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?