From 43974d204853633b66608399795add9f4694b415 Mon Sep 17 00:00:00 2001 From: James Kim Date: Thu, 9 Jan 2025 21:54:40 -0800 Subject: [PATCH] feat: add l1 to l2 bridge --- packages/cli/src/abi/l1StandardBridgeAbi.ts | 492 +++++++++++++++++ packages/cli/src/abi/multicall3Abi.ts | 440 +++++++++++++++ .../cli/src/actions/deployCreateXCreate2.ts | 2 +- packages/cli/src/actions/verifyContract.ts | 2 +- .../cli/src/bridge-wizard/BridgeWizard.tsx | 16 +- .../cli/src/bridge-wizard/EnterAmount.tsx | 4 +- .../cli/src/bridge-wizard/EnterPrivateKey.tsx | 58 -- .../cli/src/bridge-wizard/EnterRecipient.tsx | 47 ++ .../cli/src/bridge-wizard/SelectChains.tsx | 15 +- .../cli/src/bridge-wizard/SelectNetwork.tsx | 2 +- .../src/bridge-wizard/bridgeWizardSteps.ts | 119 ----- .../src/bridge-wizard/bridgeWizardStore.ts | 27 +- packages/cli/src/commands/bridge.tsx | 500 ++++++++++++++++++ packages/cli/src/commands/bridge/index.tsx | 7 - packages/cli/src/commands/deploy/create2.tsx | 2 +- packages/cli/src/commands/index.tsx | 2 +- .../DeployCreate2Wizard.tsx | 12 - .../deploy-create2-wizard/SelectChains.tsx | 14 +- .../deploy-create2-wizard/SelectNetwork.tsx | 2 +- .../deployCreate2WizardStore.ts | 2 +- .../deploy-create2/ChooseExecutionOption.tsx | 6 +- .../deploy-create2/DeployCreate2Command.tsx | 5 +- packages/cli/src/queries/chainById.ts | 105 +--- packages/cli/src/queries/chainByIdentifier.ts | 23 +- packages/cli/src/queries/chainConfig.ts | 26 - .../queries/chainRegistryItemByIdentifier.ts | 36 -- packages/cli/src/queries/chains.ts | 95 ++++ .../queries/superchainRegistryAddresses.ts | 19 + .../queries/superchainRegistryChainList.ts | 23 + packages/cli/src/server/api.ts | 3 +- .../fetchSuperchainRegistryAddresses.ts | 27 + ...ts => fetchSuperchainRegistryChainList.ts} | 4 +- packages/cli/src/utils/superchainRegistry.ts | 86 --- packages/cli/src/validators/schemas.ts | 14 +- packages/cli/src/viemChainById.ts | 8 + 35 files changed, 1742 insertions(+), 503 deletions(-) create mode 100644 packages/cli/src/abi/l1StandardBridgeAbi.ts create mode 100644 packages/cli/src/abi/multicall3Abi.ts delete mode 100644 packages/cli/src/bridge-wizard/EnterPrivateKey.tsx create mode 100644 packages/cli/src/bridge-wizard/EnterRecipient.tsx delete mode 100644 packages/cli/src/bridge-wizard/bridgeWizardSteps.ts create mode 100644 packages/cli/src/commands/bridge.tsx delete mode 100644 packages/cli/src/commands/bridge/index.tsx delete mode 100644 packages/cli/src/queries/chainConfig.ts delete mode 100644 packages/cli/src/queries/chainRegistryItemByIdentifier.ts create mode 100644 packages/cli/src/queries/chains.ts create mode 100644 packages/cli/src/queries/superchainRegistryAddresses.ts create mode 100644 packages/cli/src/queries/superchainRegistryChainList.ts create mode 100644 packages/cli/src/superchain-registry/fetchSuperchainRegistryAddresses.ts rename packages/cli/src/superchain-registry/{fetchChainList.ts => fetchSuperchainRegistryChainList.ts} (94%) delete mode 100644 packages/cli/src/utils/superchainRegistry.ts create mode 100644 packages/cli/src/viemChainById.ts diff --git a/packages/cli/src/abi/l1StandardBridgeAbi.ts b/packages/cli/src/abi/l1StandardBridgeAbi.ts new file mode 100644 index 0000000..e3b025c --- /dev/null +++ b/packages/cli/src/abi/l1StandardBridgeAbi.ts @@ -0,0 +1,492 @@ +export const l1StandardBridgeAbi = [ + {type: 'constructor', inputs: [], stateMutability: 'nonpayable'}, + {type: 'receive', stateMutability: 'payable'}, + { + type: 'function', + name: 'MESSENGER', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'contract ICrossDomainMessenger', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'OTHER_BRIDGE', + inputs: [], + outputs: [ + {name: '', type: 'address', internalType: 'contract StandardBridge'}, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'bridgeERC20', + inputs: [ + {name: '_localToken', type: 'address', internalType: 'address'}, + {name: '_remoteToken', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'bridgeERC20To', + inputs: [ + {name: '_localToken', type: 'address', internalType: 'address'}, + {name: '_remoteToken', type: 'address', internalType: 'address'}, + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'bridgeETH', + inputs: [ + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + name: 'bridgeETHTo', + inputs: [ + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + name: 'depositERC20', + inputs: [ + {name: '_l1Token', type: 'address', internalType: 'address'}, + {name: '_l2Token', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'depositERC20To', + inputs: [ + {name: '_l1Token', type: 'address', internalType: 'address'}, + {name: '_l2Token', type: 'address', internalType: 'address'}, + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'depositETH', + inputs: [ + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + name: 'depositETHTo', + inputs: [ + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_minGasLimit', type: 'uint32', internalType: 'uint32'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + name: 'deposits', + inputs: [ + {name: '', type: 'address', internalType: 'address'}, + {name: '', type: 'address', internalType: 'address'}, + ], + outputs: [{name: '', type: 'uint256', internalType: 'uint256'}], + stateMutability: 'view', + }, + { + type: 'function', + name: 'finalizeBridgeERC20', + inputs: [ + {name: '_localToken', type: 'address', internalType: 'address'}, + {name: '_remoteToken', type: 'address', internalType: 'address'}, + {name: '_from', type: 'address', internalType: 'address'}, + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'finalizeBridgeETH', + inputs: [ + {name: '_from', type: 'address', internalType: 'address'}, + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + name: 'finalizeERC20Withdrawal', + inputs: [ + {name: '_l1Token', type: 'address', internalType: 'address'}, + {name: '_l2Token', type: 'address', internalType: 'address'}, + {name: '_from', type: 'address', internalType: 'address'}, + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'finalizeETHWithdrawal', + inputs: [ + {name: '_from', type: 'address', internalType: 'address'}, + {name: '_to', type: 'address', internalType: 'address'}, + {name: '_amount', type: 'uint256', internalType: 'uint256'}, + {name: '_extraData', type: 'bytes', internalType: 'bytes'}, + ], + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + name: 'initialize', + inputs: [ + { + name: '_messenger', + type: 'address', + internalType: 'contract ICrossDomainMessenger', + }, + { + name: '_superchainConfig', + type: 'address', + internalType: 'contract ISuperchainConfig', + }, + { + name: '_systemConfig', + type: 'address', + internalType: 'contract ISystemConfig', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + name: 'l2TokenBridge', + inputs: [], + outputs: [{name: '', type: 'address', internalType: 'address'}], + stateMutability: 'view', + }, + { + type: 'function', + name: 'messenger', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'contract ICrossDomainMessenger', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'otherBridge', + inputs: [], + outputs: [ + {name: '', type: 'address', internalType: 'contract StandardBridge'}, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'paused', + inputs: [], + outputs: [{name: '', type: 'bool', internalType: 'bool'}], + stateMutability: 'view', + }, + { + type: 'function', + name: 'superchainConfig', + inputs: [], + outputs: [ + {name: '', type: 'address', internalType: 'contract ISuperchainConfig'}, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'systemConfig', + inputs: [], + outputs: [ + {name: '', type: 'address', internalType: 'contract ISystemConfig'}, + ], + stateMutability: 'view', + }, + { + type: 'function', + name: 'version', + inputs: [], + outputs: [{name: '', type: 'string', internalType: 'string'}], + stateMutability: 'view', + }, + { + type: 'event', + name: 'ERC20BridgeFinalized', + inputs: [ + { + name: 'localToken', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'remoteToken', + type: 'address', + indexed: true, + internalType: 'address', + }, + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: false, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ERC20BridgeInitiated', + inputs: [ + { + name: 'localToken', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'remoteToken', + type: 'address', + indexed: true, + internalType: 'address', + }, + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: false, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ERC20DepositInitiated', + inputs: [ + { + name: 'l1Token', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'l2Token', + type: 'address', + indexed: true, + internalType: 'address', + }, + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: false, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ERC20WithdrawalFinalized', + inputs: [ + { + name: 'l1Token', + type: 'address', + indexed: true, + internalType: 'address', + }, + { + name: 'l2Token', + type: 'address', + indexed: true, + internalType: 'address', + }, + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: false, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ETHBridgeFinalized', + inputs: [ + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: true, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ETHBridgeInitiated', + inputs: [ + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: true, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ETHDepositInitiated', + inputs: [ + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: true, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'ETHWithdrawalFinalized', + inputs: [ + {name: 'from', type: 'address', indexed: true, internalType: 'address'}, + {name: 'to', type: 'address', indexed: true, internalType: 'address'}, + { + name: 'amount', + type: 'uint256', + indexed: false, + internalType: 'uint256', + }, + { + name: 'extraData', + type: 'bytes', + indexed: false, + internalType: 'bytes', + }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'Initialized', + inputs: [ + {name: 'version', type: 'uint8', indexed: false, internalType: 'uint8'}, + ], + anonymous: false, + }, +] as const; diff --git a/packages/cli/src/abi/multicall3Abi.ts b/packages/cli/src/abi/multicall3Abi.ts new file mode 100644 index 0000000..fdc84fc --- /dev/null +++ b/packages/cli/src/abi/multicall3Abi.ts @@ -0,0 +1,440 @@ +export const multicall3Abi = [ + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'aggregate', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + { + internalType: 'bytes[]', + name: 'returnData', + type: 'bytes[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bool', + name: 'allowFailure', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Call3[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'aggregate3', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bool', + name: 'allowFailure', + type: 'bool', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Call3Value[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'aggregate3Value', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'blockAndAggregate', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'getBasefee', + outputs: [ + { + internalType: 'uint256', + name: 'basefee', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + ], + name: 'getBlockHash', + outputs: [ + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getBlockNumber', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getChainId', + outputs: [ + { + internalType: 'uint256', + name: 'chainid', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockCoinbase', + outputs: [ + { + internalType: 'address', + name: 'coinbase', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockDifficulty', + outputs: [ + { + internalType: 'uint256', + name: 'difficulty', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockGasLimit', + outputs: [ + { + internalType: 'uint256', + name: 'gaslimit', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockTimestamp', + outputs: [ + { + internalType: 'uint256', + name: 'timestamp', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'addr', + type: 'address', + }, + ], + name: 'getEthBalance', + outputs: [ + { + internalType: 'uint256', + name: 'balance', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getLastBlockHash', + outputs: [ + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bool', + name: 'requireSuccess', + type: 'bool', + }, + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'tryAggregate', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bool', + name: 'requireSuccess', + type: 'bool', + }, + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'tryBlockAndAggregate', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct IMulticall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, +] as const; diff --git a/packages/cli/src/actions/deployCreateXCreate2.ts b/packages/cli/src/actions/deployCreateXCreate2.ts index 48f200c..aa4e65d 100644 --- a/packages/cli/src/actions/deployCreateXCreate2.ts +++ b/packages/cli/src/actions/deployCreateXCreate2.ts @@ -1,4 +1,4 @@ -import {zodSupportedNetwork} from '@/superchain-registry/fetchChainList'; +import {zodSupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; import {zodPrivateKey} from '@/validators/schemas'; import {option} from 'pastel'; diff --git a/packages/cli/src/actions/verifyContract.ts b/packages/cli/src/actions/verifyContract.ts index 4d352b0..e19c481 100644 --- a/packages/cli/src/actions/verifyContract.ts +++ b/packages/cli/src/actions/verifyContract.ts @@ -1,4 +1,4 @@ -import {zodSupportedNetwork} from '@/superchain-registry/fetchChainList'; +import {zodSupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; import {zodAddress} from '@/validators/schemas'; import {option} from 'pastel'; diff --git a/packages/cli/src/bridge-wizard/BridgeWizard.tsx b/packages/cli/src/bridge-wizard/BridgeWizard.tsx index a04c3d0..c26bc4b 100644 --- a/packages/cli/src/bridge-wizard/BridgeWizard.tsx +++ b/packages/cli/src/bridge-wizard/BridgeWizard.tsx @@ -4,9 +4,12 @@ import { useBridgeWizardStore, } from '@/bridge-wizard/bridgeWizardStore'; import {EnterAmount} from '@/bridge-wizard/EnterAmount'; +import {EnterRecipient} from '@/bridge-wizard/EnterRecipient'; import {SelectChains} from '@/bridge-wizard/SelectChains'; import {SelectNetwork} from '@/bridge-wizard/SelectNetwork'; +import BridgeEntrypoint from '@/commands/bridge'; import {useSaveWizardProgress} from '@/hooks/useSaveWizardProgress'; +import {SupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; import {Box, Text} from 'ink'; type StepStatus = 'done' | 'current' | 'upcoming'; @@ -73,11 +76,13 @@ const WizardProgressForStep = ({stepId}: {stepId: BridgeWizardStepId}) => { const WizardProgress = () => { const {steps, wizardState} = useBridgeWizardStore(); if (wizardState.stepId === 'completed') { - return ( - - Completed - - ); + const options = { + network: wizardState.network as SupportedNetwork, + chains: wizardState.chains, + amount: wizardState.amount, + recipient: wizardState.recipient, + }; + return ; } return ( @@ -109,6 +114,7 @@ export const BridgeWizard = () => { + {stepId === 'enter-recipient' && } {stepId === 'select-network' && } {stepId === 'select-chains' && } {stepId === 'enter-amount' && } diff --git a/packages/cli/src/bridge-wizard/EnterAmount.tsx b/packages/cli/src/bridge-wizard/EnterAmount.tsx index bffe643..694bab8 100644 --- a/packages/cli/src/bridge-wizard/EnterAmount.tsx +++ b/packages/cli/src/bridge-wizard/EnterAmount.tsx @@ -45,10 +45,10 @@ export const EnterAmount = () => { const {data: balance, isLoading: isLoadingBalance} = useBalance( wizardState.network, - wizardState.address, + wizardState.recipient, ); - const numChains = wizardState.chainIds.length; + const numChains = wizardState.chains.length; return ( diff --git a/packages/cli/src/bridge-wizard/EnterPrivateKey.tsx b/packages/cli/src/bridge-wizard/EnterPrivateKey.tsx deleted file mode 100644 index 3d7294c..0000000 --- a/packages/cli/src/bridge-wizard/EnterPrivateKey.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import {useBridgeWizardStore} from '@/bridge-wizard/bridgeWizardStore'; -import {Box, Text} from 'ink'; -import {TextInput} from '@inkjs/ui'; -import {privateKeyToAccount, PrivateKeyToAccountErrorType} from 'viem/accounts'; -import {useState} from 'react'; -import {Account, isHex} from 'viem'; - -export const EnterPrivateKey = () => { - const {wizardState, submitEnterPrivateKey} = useBridgeWizardStore(); - - if (wizardState.stepId !== 'enter-private-key') { - throw new Error('Invalid state'); - } - - const [errorMessage, setErrorMessage] = useState(''); - const [resetKey, setResetKey] = useState(0); - - return ( - - - Enter your private key for your account: - - { - if (!isHex(privateKey)) { - setErrorMessage('Invalid private key: must start with 0x'); - setResetKey(prev => prev + 1); - return; - } - - let account: Account; - try { - account = privateKeyToAccount(privateKey); - } catch (err) { - const error = err as PrivateKeyToAccountErrorType; - setErrorMessage( - // @ts-expect-error - `Invalid private key: ${error.shortMessage ?? error.message}`, - ); - setResetKey(prev => prev + 1); - return; - } - - submitEnterPrivateKey({ - privateKey, - address: account.address, - }); - }} - /> - {errorMessage && ( - - {errorMessage ? `❌ ${errorMessage}` : ' '} - - )} - - ); -}; diff --git a/packages/cli/src/bridge-wizard/EnterRecipient.tsx b/packages/cli/src/bridge-wizard/EnterRecipient.tsx new file mode 100644 index 0000000..8b4e710 --- /dev/null +++ b/packages/cli/src/bridge-wizard/EnterRecipient.tsx @@ -0,0 +1,47 @@ +import {Box, Text} from 'ink'; +import {TextInput} from '@inkjs/ui'; + +import {useBridgeWizardStore} from '@/bridge-wizard/bridgeWizardStore'; +import {useState} from 'react'; +import {isAddress} from 'viem'; +import {zodAddress} from '@/validators/schemas'; + +export const EnterRecipient = () => { + const {submitEnterRecipient} = useBridgeWizardStore(); + + const [errorMessage, setErrorMessage] = useState(''); + const [resetKey, setResetKey] = useState(0); + + return ( + + + Enter the recipient address: + + { + if (!isAddress(address)) { + setErrorMessage('Invalid address: must start with 0x'); + setResetKey(prev => prev + 1); + return; + } + + const result = zodAddress.safeParse(address); + + if (!result.success) { + setErrorMessage(result.error.message); + setResetKey(prev => prev + 1); + return; + } + + submitEnterRecipient({recipient: result.data}); + }} + /> + {errorMessage && ( + + {errorMessage ? `❌ ${errorMessage}` : ' '} + + )} + + ); +}; diff --git a/packages/cli/src/bridge-wizard/SelectChains.tsx b/packages/cli/src/bridge-wizard/SelectChains.tsx index 89e9e55..00dd6ca 100644 --- a/packages/cli/src/bridge-wizard/SelectChains.tsx +++ b/packages/cli/src/bridge-wizard/SelectChains.tsx @@ -1,5 +1,5 @@ import {useBridgeWizardStore} from '@/bridge-wizard/bridgeWizardStore'; -import {useChainConfig} from '@/queries/chainConfig'; +import {useSuperchainRegistryChainList} from '@/queries/superchainRegistryChainList'; import {MultiSelect, Spinner} from '@inkjs/ui'; import {Box, Text} from 'ink'; import {useState} from 'react'; @@ -15,7 +15,7 @@ export const SelectChains = () => { data: chains, isLoading: isLoadingChains, error: loadChainsError, - } = useChainConfig(); + } = useSuperchainRegistryChainList(); const [errorMessage, setErrorMessage] = useState(null); @@ -67,16 +67,15 @@ export const SelectChains = () => { .filter(chain => chain.parent.chain === wizardState.network) .map(chain => ({ label: `${chain.name} (${chain.chainId})`, - value: chain.chainId.toString(), + value: chain.identifier.split('/')[1]!, }))} - onSubmit={chainIdStrs => { - if (chainIdStrs.length === 0) { + onSubmit={chainNames => { + if (chainNames.length === 0) { setErrorMessage('You must select at least one chain'); return; } - submitSelectChains({ - chainIds: chainIdStrs.map(Number), - }); + + submitSelectChains({chains: chainNames}); }} /> {errorMessage && {errorMessage}} diff --git a/packages/cli/src/bridge-wizard/SelectNetwork.tsx b/packages/cli/src/bridge-wizard/SelectNetwork.tsx index 7453208..138d73a 100644 --- a/packages/cli/src/bridge-wizard/SelectNetwork.tsx +++ b/packages/cli/src/bridge-wizard/SelectNetwork.tsx @@ -1,5 +1,5 @@ import {useBridgeWizardStore} from '@/bridge-wizard/bridgeWizardStore'; -import {SupportedNetwork} from '@/utils/superchainRegistry'; +import {SupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; import {Select} from '@inkjs/ui'; import {Box, Text} from 'ink'; diff --git a/packages/cli/src/bridge-wizard/bridgeWizardSteps.ts b/packages/cli/src/bridge-wizard/bridgeWizardSteps.ts deleted file mode 100644 index 139b086..0000000 --- a/packages/cli/src/bridge-wizard/bridgeWizardSteps.ts +++ /dev/null @@ -1,119 +0,0 @@ -import {Address, formatEther, Hex} from 'viem'; - -type BridgeWizardStepWithPreviousState< - TStep extends string, - TPrev extends BridgeWizardStep, - TNew extends keyof BridgeWizardStateVariables, -> = Omit & { - step: TStep; -} & Pick; - -export type BridgeWizardStateVariables = { - privateKey: Hex; - address: Address; - network: string; - chainIds: number[]; - amount: bigint; -}; - -type BridgeWizardSelectNetworkStep = { - step: 'select-network'; -}; - -type BridgeWizardEnterPrivateKeyStep = BridgeWizardStepWithPreviousState< - 'enter-private-key', - BridgeWizardSelectNetworkStep, - 'network' ->; - -type BridgeWizardSelectChainsStep = BridgeWizardStepWithPreviousState< - 'select-chains', - BridgeWizardEnterPrivateKeyStep, - 'privateKey' | 'address' ->; - -type BridgeWizardEnterAmountStep = BridgeWizardStepWithPreviousState< - 'enter-amount', - BridgeWizardSelectChainsStep, - 'chainIds' ->; - -type BridgeWizardConfirmTransactionStep = BridgeWizardStepWithPreviousState< - 'confirm-transaction', - BridgeWizardEnterAmountStep, - 'amount' ->; - -export type BridgeWizardStep = - | BridgeWizardSelectNetworkStep - | BridgeWizardEnterPrivateKeyStep - | BridgeWizardSelectChainsStep - | BridgeWizardEnterAmountStep - | BridgeWizardConfirmTransactionStep; - -export const bridgeWizardStepMetadatas = [ - { - step: 'select-network', - title: 'Select network', - getSummary: (state: BridgeWizardStateVariables) => `${state.network}`, - }, - { - step: 'enter-private-key', - title: 'Connect account', - getSummary: (state: BridgeWizardStateVariables) => `${state.address}`, - }, - { - step: 'select-chains', - title: 'Select chains', - getSummary: (state: BridgeWizardStateVariables) => - `${state.chainIds.map(chainId => `${chainId}`).join(', ')}`, - }, - { - step: 'enter-amount', - title: 'Enter amount', - getSummary: (state: BridgeWizardStateVariables) => { - const perChainAmount = Number(formatEther(state.amount)).toFixed(2); - const totalAmount = Number( - formatEther(state.amount * BigInt(state.chainIds.length)), - ).toFixed(2); - return `${perChainAmount} ETH × ${state.chainIds.length} chains = ${totalAmount} ETH total`; - }, - }, - { - step: 'confirm-transaction', - title: 'Confirm transaction', - getSummary: () => '', - }, -] as const satisfies { - step: BridgeWizardStep['step']; - title: string; - getSummary: (state: BridgeWizardStateVariables) => string; -}[]; - -export const bridgeWizardStepMetadataByStep = bridgeWizardStepMetadatas.reduce( - (acc, metadata) => { - acc[metadata.step] = metadata; - return acc; - }, - {} as Record< - BridgeWizardStep['step'], - (typeof bridgeWizardStepMetadatas)[number] - >, -); - -export const indexByBridgeWizardStep = bridgeWizardStepMetadatas.reduce( - (acc, metadata, index) => { - acc[metadata.step] = index; - return acc; - }, - {} as Record, -); - -export const isAfterStep = ( - currentStep: BridgeWizardStep['step'], - targetStep: BridgeWizardStep['step'], -) => { - return ( - indexByBridgeWizardStep[currentStep] > indexByBridgeWizardStep[targetStep] - ); -}; diff --git a/packages/cli/src/bridge-wizard/bridgeWizardStore.ts b/packages/cli/src/bridge-wizard/bridgeWizardStore.ts index c9de2fb..ccdd72c 100644 --- a/packages/cli/src/bridge-wizard/bridgeWizardStore.ts +++ b/packages/cli/src/bridge-wizard/bridgeWizardStore.ts @@ -1,34 +1,33 @@ import {defineWizard, InferStepId} from '@/wizard-builder/defineWizard'; import {z} from 'zod'; import {formatEther} from 'viem'; -import {Address as ZodAddress} from 'abitype/zod'; import {createWizardStore} from '@/wizard-builder/createWizardStore'; +import {zodAddress} from '@/validators/schemas'; const bridgeWizard = defineWizard() .addStep({ - id: 'select-network', + id: 'enter-recipient', schema: z.object({ - network: z.string(), + recipient: zodAddress, }), - title: 'Select Network', - getSummary: state => `${state.network}`, + title: 'Enter Recipient', + getSummary: () => '', }) .addStep({ - id: 'enter-private-key', + id: 'select-network', schema: z.object({ - privateKey: z.string(), - address: ZodAddress, + network: z.string(), }), - title: 'Enter Private Key', - getSummary: state => `${state.address}`, + title: 'Select Network', + getSummary: state => `${state.network}`, }) .addStep({ id: 'select-chains', schema: z.object({ - chainIds: z.array(z.number()), + chains: z.array(z.string()), }), title: 'Select Chains', - getSummary: state => `${state.chainIds.join(', ')}`, + getSummary: state => `${state.chains.join(', ')}`, }) .addStep({ id: 'enter-amount', @@ -39,9 +38,9 @@ const bridgeWizard = defineWizard() getSummary: state => { const perChainAmount = Number(formatEther(state.amount)).toFixed(2); const totalAmount = Number( - formatEther(state.amount * BigInt(state.chainIds.length)), + formatEther(state.amount * BigInt(state.chains.length)), ).toFixed(2); - return `${perChainAmount} ETH × ${state.chainIds.length} chains = ${totalAmount} ETH total`; + return `${perChainAmount} ETH × ${state.chains.length} chains = ${totalAmount} ETH total`; }, }) .build(); diff --git a/packages/cli/src/commands/bridge.tsx b/packages/cli/src/commands/bridge.tsx new file mode 100644 index 0000000..523dd07 --- /dev/null +++ b/packages/cli/src/commands/bridge.tsx @@ -0,0 +1,500 @@ +import {l1StandardBridgeAbi} from '@/abi/l1StandardBridgeAbi'; +import {multicall3Abi} from '@/abi/multicall3Abi'; +import { + ChooseExecutionOption, + ExecutionOption, +} from '@/deploy-create2/ChooseExecutionOption'; +import {useMappingChainByIdentifier} from '@/queries/chainByIdentifier'; +import {useTransactionTaskStore} from '@/stores/transactionTaskStore'; +import {zodSupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; +import {createTransactionTaskId} from '@/transaction-task/transactionTask'; +import {getBlockExplorerTxHashLink} from '@/utils/blockExplorer'; +import {zodAddress, zodPrivateKey, zodValueAmount} from '@/validators/schemas'; +import {viemChainById} from '@/viemChainById'; +import {Badge, Spinner} from '@inkjs/ui'; +import {Box, Text} from 'ink'; +import {option} from 'pastel'; +import {useEffect, useState} from 'react'; +import { + Address, + Chain, + encodeFunctionData, + formatEther, + formatGwei, + Hex, + toHex, + zeroAddress, +} from 'viem'; +import {privateKeyToAccount, privateKeyToAddress} from 'viem/accounts'; +import { + useEstimateGas, + useGasPrice, + useWaitForTransactionReceipt, + useWriteContract, +} from 'wagmi'; +import {z} from 'zod'; + +const zodBridgeParams = z.object({ + network: zodSupportedNetwork.describe( + option({ + description: 'Network to bridge to', + alias: 'n', + }), + ), + chains: z + .array(z.string()) + .describe( + option({ + description: 'Chains to bridge to', + alias: 'c', + }), + ) + .min(1), + amount: zodValueAmount.describe( + option({ + description: 'Amount to bridge per chain', + alias: 'a', + }), + ), + privateKey: zodPrivateKey.optional().describe( + option({ + description: 'Signer private key', + alias: 'pk', + }), + ), + recipient: zodAddress.optional().describe( + option({ + description: 'Recipient address to bridge to', + alias: 'r', + }), + ), +}); + +export const BridgeEntrypoint = ({ + options, +}: { + options: z.infer; +}) => { + if (!options.privateKey && !options.recipient) { + console.error( + 'Either --private-key OR --recipient is required. Please provide one.', + ); + return ( + + Error: Either --private-key OR --recipient is required. Please provide + one. + + ); + } + + const {data: chainByIdentifier, isLoading: isChainByIdentifierLoading} = + useMappingChainByIdentifier(); + + if (isChainByIdentifierLoading || !chainByIdentifier) { + return ; + } + + const chains = options.chains.map( + chain => chainByIdentifier[`${options.network}/${chain}`]!, + ); + + const sourceChain = viemChainById[chains[0]!.sourceId!]!; + + // Defaults to the private key address if no recipient is provided + const recipientAddress = + options.recipient ?? privateKeyToAddress(options.privateKey!); + + return ( + + ); +}; + +const BridgeInner = ({ + sourceChain, + chains, + recipientAddress, + privateKey, + amountPerChain, +}: { + sourceChain: Chain; + chains: Chain[]; + recipientAddress: Address; + privateKey: Hex | undefined; + amountPerChain: bigint; +}) => { + const [executionOption, setExecutionOption] = + useState( + privateKey ? {type: 'privateKey', privateKey: privateKey} : null, + ); + + return ( + + + + Bridge + + + + Source Chain: {sourceChain.name} + + + Target Chains:{' '} + + {chains.map(chain => chain.name).join(', ')} + + + + Recipient: {recipientAddress} + + + Value:{' '} + + {formatEther(amountPerChain)} ETH × {chains.length} chains ={' '} + {formatEther(amountPerChain * BigInt(chains.length))} ETH total + + + + Gas: + + + + {!executionOption && ( + + + + )} + + {executionOption && ( + + )} + + + ); +}; + +const SendStatus = ({ + chains, + sourceChain, + recipientAddress, + amountPerChain, + executionOption, +}: { + chains: Chain[]; + sourceChain: Chain; + recipientAddress: Address; + amountPerChain: bigint; + executionOption: ExecutionOption; +}) => { + if (executionOption.type === 'privateKey') { + return ( + + ); + } + + if (executionOption.type === 'externalSigner') { + return ( + + ); + } + + throw new Error('Invalid execution option'); +}; + +const ExternalSignerExecution = ({ + chains, + sourceChain, + recipientAddress, + amountPerChain, +}: { + chains: Chain[]; + sourceChain: Chain; + recipientAddress: Address; + amountPerChain: bigint; +}) => { + const encodedData = encodeFunctionData( + getContractWriteParams({ + chains, + recipientAddress, + amountPerChain, + }), + ); + + const {createTask, taskEntryById} = useTransactionTaskStore(); + + const task = { + chainId: sourceChain.id, + to: '0xcA11bde05977b3631167028862bE2a173976CA11', + data: encodedData, + value: toHex(amountPerChain * BigInt(chains.length)), + } as const; + + const taskId = createTransactionTaskId(task); + + useEffect(() => { + createTask(task); + }, []); + + const transactionHash = taskEntryById[taskId]?.hash; + + const {isLoading: isReceiptLoading} = useWaitForTransactionReceipt({ + hash: transactionHash, + chainId: sourceChain.id, + }); + + if (!transactionHash) { + return ( + + + + Send the transaction at + + http://localhost:3000 + + + + ); + } + + if (isReceiptLoading && transactionHash) { + return ( + + + Transaction sent:{' '} + {getBlockExplorerTxHashLink(sourceChain, transactionHash)} + + + + ); + } + + return ( + + Bridged + + {formatEther(amountPerChain * BigInt(chains.length))} ETH successfully + bridged + + {getBlockExplorerTxHashLink(sourceChain, transactionHash)} + + ); +}; + +const PrivateKeyExecution = ({ + chains, + sourceChain, + recipientAddress, + amountPerChain, + privateKey, +}: { + chains: Chain[]; + sourceChain: Chain; + recipientAddress: Address; + amountPerChain: bigint; + privateKey: Hex; +}) => { + const { + writeContract, + isPending, + error, + data: transactionHash, + } = useWriteContract(); + + const {isLoading: isReceiptLoading} = useWaitForTransactionReceipt({ + hash: transactionHash, + chainId: sourceChain.id, + }); + + useEffect(() => { + writeContract({ + chainId: sourceChain.id, + ...getContractWriteParams({ + chains, + recipientAddress, + amountPerChain, + }), + account: privateKeyToAccount(privateKey), + }); + }, []); + + if (error) { + return Error bridging ETH: {error.message}; + } + + if (isPending || !transactionHash) { + return ; + } + + if (isReceiptLoading) { + return ( + + + Transaction sent:{' '} + {getBlockExplorerTxHashLink(sourceChain, transactionHash)} + + + + ); + } + + return ( + + Bridged + + {formatEther(amountPerChain * BigInt(chains.length))} ETH successfully + bridged + + {getBlockExplorerTxHashLink(sourceChain, transactionHash)} + + ); +}; + +const GasEstimation = ({ + sourceChain, + chains, + recipientAddress, + amountPerChain, + accountToEstimateFrom, +}: { + sourceChain: Chain; + chains: Chain[]; + recipientAddress: Address; + amountPerChain: bigint; + accountToEstimateFrom: Address; +}) => { + const contractWriteParams = getContractWriteParams({ + chains, + recipientAddress, + amountPerChain, + }); + + const encodedData = encodeFunctionData( + getContractWriteParams({ + chains, + recipientAddress, + amountPerChain, + }), + ); + + const { + data: estimatedGas, + isLoading: isEstimateGasLoading, + error: estimateGasError, + } = useEstimateGas({ + chainId: sourceChain.id, + to: '0xcA11bde05977b3631167028862bE2a173976CA11', + data: encodedData, + value: contractWriteParams.value, + account: accountToEstimateFrom, + }); + + const { + data: gasPrice, + isLoading: isGasPriceLoading, + error: gasPriceError, + } = useGasPrice({ + chainId: sourceChain.id, + }); + + if (isEstimateGasLoading || isGasPriceLoading) { + return ; + } + + if (estimateGasError || gasPriceError) { + console.error(estimateGasError, gasPriceError); + return Error estimating gas; + } + + if (estimatedGas === undefined || gasPrice === undefined) { + // Invariant: we should always have gas data + throw new Error('No gas data'); + } + + const fees = estimatedGas * gasPrice; + + return ( + + {estimatedGas.toLocaleString()} ×{' '} + {Number(formatGwei(gasPrice)).toFixed(2)} gwei ={' '} + {Number(formatEther(fees)).toFixed(5)} ETH + + ); +}; + +const getContractWriteParams = ({ + chains, + recipientAddress, + amountPerChain, +}: { + chains: Chain[]; + recipientAddress: Address; + amountPerChain: bigint; +}) => { + return { + abi: multicall3Abi, + functionName: 'aggregate3Value', + address: '0xcA11bde05977b3631167028862bE2a173976CA11', + args: [ + [ + ...chains.map(chain => { + const l1StandardBridgeAddress: Address = + // @ts-expect-error + chain.contracts?.l1StandardBridge?.[chain.sourceId!]?.address; + + if (!l1StandardBridgeAddress) { + // Invariant: we should always have a l1StandardBridge defined (see chains.ts) + throw new Error('l1StandardBridge not found'); + } + + return { + target: l1StandardBridgeAddress, + allowFailure: false, + callData: encodeFunctionData({ + abi: l1StandardBridgeAbi, + functionName: 'bridgeETHTo', + args: [recipientAddress, 1000000, toHex('')], + }), + value: amountPerChain, + }; + }), + ], + ], + value: amountPerChain * BigInt(chains.length), + } as const; +}; + +export default BridgeEntrypoint; +export const options = zodBridgeParams; diff --git a/packages/cli/src/commands/bridge/index.tsx b/packages/cli/src/commands/bridge/index.tsx deleted file mode 100644 index d11ce6d..0000000 --- a/packages/cli/src/commands/bridge/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import {BridgeWizard} from '@/bridge-wizard/BridgeWizard'; - -const Index = () => { - return ; -}; - -export default Index; diff --git a/packages/cli/src/commands/deploy/create2.tsx b/packages/cli/src/commands/deploy/create2.tsx index b74c5af..72caa6c 100644 --- a/packages/cli/src/commands/deploy/create2.tsx +++ b/packages/cli/src/commands/deploy/create2.tsx @@ -7,7 +7,7 @@ import {fromZodError} from 'zod-validation-error'; import {parseSuperConfigFromTOML} from '@/utils/config'; import {DeployCreate2Command} from '@/deploy-create2/DeployCreate2Command'; -import {SupportedNetwork} from '@/superchain-registry/fetchChainList'; +import {SupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; const zodDeployCreate2CommandEntrypointOptions = zodDeployCreateXCreate2Params .partial() diff --git a/packages/cli/src/commands/index.tsx b/packages/cli/src/commands/index.tsx index b54e996..08f01eb 100644 --- a/packages/cli/src/commands/index.tsx +++ b/packages/cli/src/commands/index.tsx @@ -13,7 +13,7 @@ import {useDeployCreate2WizardStore} from '@/deploy-create2-wizard/deployCreate2 const options = [ {label: '🚀 Deploy a contract', value: 'deploy'}, {label: '🌉 Bridge assets', value: 'bridge'}, - {label: '✅ Verify a contract', value: 'verify'}, + // {label: '✅ Verify a contract', value: 'verify'}, ]; export default function DefaultEntrypoint() { diff --git a/packages/cli/src/deploy-create2-wizard/DeployCreate2Wizard.tsx b/packages/cli/src/deploy-create2-wizard/DeployCreate2Wizard.tsx index 272e832..a97f6e8 100644 --- a/packages/cli/src/deploy-create2-wizard/DeployCreate2Wizard.tsx +++ b/packages/cli/src/deploy-create2-wizard/DeployCreate2Wizard.tsx @@ -118,17 +118,6 @@ export const DeployCreate2Wizard = () => { network: wizardState.network, }; - console.log( - Object.entries(options) - .map( - ([key, value]) => - `--${key.replace( - /[A-Z]/g, - letter => `-${letter.toLowerCase()}`, - )} ${value}`, - ) - .join(' '), - ); return ; } @@ -146,7 +135,6 @@ export const DeployCreate2Wizard = () => { {stepId === 'configure-salt' && } {stepId === 'select-network' && } {stepId === 'select-chains' && } - {/* {stepId === 'enter-private-key' && } */} ); }; diff --git a/packages/cli/src/deploy-create2-wizard/SelectChains.tsx b/packages/cli/src/deploy-create2-wizard/SelectChains.tsx index fd3f1fc..603dbaf 100644 --- a/packages/cli/src/deploy-create2-wizard/SelectChains.tsx +++ b/packages/cli/src/deploy-create2-wizard/SelectChains.tsx @@ -1,23 +1,13 @@ import {useDeployCreate2WizardStore} from '@/deploy-create2-wizard/deployCreate2WizardStore'; -import {initChainConfig} from '@/utils/superchainRegistry'; +import {useSuperchainRegistryChainList} from '@/queries/superchainRegistryChainList'; import {MultiSelect, Spinner} from '@inkjs/ui'; -import {useQuery} from '@tanstack/react-query'; import {Box, Text} from 'ink'; import {useState} from 'react'; export const SelectChains = () => { const {wizardState, submitSelectChains} = useDeployCreate2WizardStore(); - const { - data: chains, - isLoading, - error, - } = useQuery({ - queryKey: ['init-chain-config'], - queryFn: async () => { - return await initChainConfig(); - }, - }); + const {data: chains, isLoading, error} = useSuperchainRegistryChainList(); const [errorMessage, setErrorMessage] = useState(null); diff --git a/packages/cli/src/deploy-create2-wizard/SelectNetwork.tsx b/packages/cli/src/deploy-create2-wizard/SelectNetwork.tsx index defb84b..3349cbb 100644 --- a/packages/cli/src/deploy-create2-wizard/SelectNetwork.tsx +++ b/packages/cli/src/deploy-create2-wizard/SelectNetwork.tsx @@ -4,7 +4,7 @@ import {Box, Text} from 'ink'; import { SupportedNetwork, zodSupportedNetwork, -} from '@/superchain-registry/fetchChainList'; +} from '@/superchain-registry/fetchSuperchainRegistryChainList'; export const SelectNetwork = () => { const {wizardState, submitSelectNetwork} = useDeployCreate2WizardStore(); diff --git a/packages/cli/src/deploy-create2-wizard/deployCreate2WizardStore.ts b/packages/cli/src/deploy-create2-wizard/deployCreate2WizardStore.ts index f45fd75..c4578fa 100644 --- a/packages/cli/src/deploy-create2-wizard/deployCreate2WizardStore.ts +++ b/packages/cli/src/deploy-create2-wizard/deployCreate2WizardStore.ts @@ -1,4 +1,4 @@ -import {zodSupportedNetwork} from '@/superchain-registry/fetchChainList'; +import {zodSupportedNetwork} from '@/superchain-registry/fetchSuperchainRegistryChainList'; import {createWizardStore} from '@/wizard-builder/createWizardStore'; import {defineWizard, InferStepId} from '@/wizard-builder/defineWizard'; import {z} from 'zod'; diff --git a/packages/cli/src/deploy-create2/ChooseExecutionOption.tsx b/packages/cli/src/deploy-create2/ChooseExecutionOption.tsx index 88508af..a127e5f 100644 --- a/packages/cli/src/deploy-create2/ChooseExecutionOption.tsx +++ b/packages/cli/src/deploy-create2/ChooseExecutionOption.tsx @@ -17,16 +17,18 @@ export type ExecutionOption = }; export const ChooseExecutionOption = ({ + label, onSubmit, }: { + label: string; onSubmit: (option: ExecutionOption) => void; }) => { const [chosePrivateKey, setChosePrivateKey] = useState(false); return ( - 🚀 Ready to deploy! - How would you like to deploy? + {label} + How would you like to send the transaction?