diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000..6fd8d280bd Binary files /dev/null and b/bun.lockb differ diff --git a/src/chains/definitions/zkLocalChainL1.ts b/src/chains/definitions/zkLocalChainL1.ts new file mode 100644 index 0000000000..91feabc74e --- /dev/null +++ b/src/chains/definitions/zkLocalChainL1.ts @@ -0,0 +1,14 @@ +import { defineChain } from '../../utils/chain/defineChain.js' + +export const zkLocalChainL1 = /*#__PURE__*/ defineChain({ + id: 9, + name: 'zkSync CLI Local Hyperchain L1', + network: 'zksync-cli-local-hyperchain-l1', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: ['http://localhost:15045'], + }, + }, + testnet: true, +}) diff --git a/src/chains/definitions/zkLocalChainL2.ts b/src/chains/definitions/zkLocalChainL2.ts new file mode 100644 index 0000000000..3d9d94f142 --- /dev/null +++ b/src/chains/definitions/zkLocalChainL2.ts @@ -0,0 +1,16 @@ +import { defineChain } from '../../utils/chain/defineChain.js' +import { chainConfig } from '../../zksync/chainConfig.js' + +export const zkLocalChainL2 = /*#__PURE__*/ defineChain({ + ...chainConfig, + id: 270, + name: 'zkSync CLI Local Hyperchain', + network: 'zksync-cli-local-hyperchain', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: ['http://localhost:15100'], + }, + }, + testnet: true, +}) diff --git a/src/chains/definitions/zkLocalChainL3.ts b/src/chains/definitions/zkLocalChainL3.ts new file mode 100644 index 0000000000..6704ea6d80 --- /dev/null +++ b/src/chains/definitions/zkLocalChainL3.ts @@ -0,0 +1,16 @@ +import { defineChain } from '../../utils/chain/defineChain.js' +import { chainConfig } from '../../zksync/chainConfig.js' + +export const zkLocalChainL3 = /*#__PURE__*/ defineChain({ + ...chainConfig, + id: 272, + name: 'zkSync CLI Local Hyperchain', + network: 'zksync-cli-local-hyperchain', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: ['http://localhost:15200'], + }, + }, + testnet: true, +}) diff --git a/src/chains/definitions/zkSyncLocalNodeL1.ts b/src/chains/definitions/zkSyncLocalNodeL1.ts new file mode 100644 index 0000000000..be53536405 --- /dev/null +++ b/src/chains/definitions/zkSyncLocalNodeL1.ts @@ -0,0 +1,14 @@ +import { defineChain } from '../utils.js' + +export const zkSyncLocalNodeL1 = /*#__PURE__*/ defineChain({ + id: 9, + name: 'zkSync CLI Local Node L1', + network: 'zksync-cli-local-node', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: ['http://localhost:8545'], + }, + }, + testnet: true, +}) diff --git a/src/zksync/constants/abis.ts b/src/zksync/constants/abis.ts index 18e7ccab73..fef1fddbbe 100644 --- a/src/zksync/constants/abis.ts +++ b/src/zksync/constants/abis.ts @@ -423,39 +423,2208 @@ export const contractDeployerAbi = [ }, ] +export const l1BridgeFactoryAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'txDataHash', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'l2DepositTxHash', + type: 'bytes32', + }, + ], + name: 'BridgehubDepositFinalized', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'txDataHash', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'BridgehubDepositInitiatedSharedBridge', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'ClaimedFailedDepositSharedBridge', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'l2DepositTxHash', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'DepositInitiatedSharedBridge', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'WithdrawalFinalizedSharedBridge', + type: 'event', + }, + { + inputs: [], + name: 'bridgehub', + outputs: [ + { + internalType: 'contract IBridgehub', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_txDataHash', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: '_txHash', + type: 'bytes32', + }, + ], + name: 'bridgehubConfirmL2Transaction', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_prevMsgSender', + type: 'address', + }, + { + internalType: 'bytes', + name: '_data', + type: 'bytes', + }, + ], + name: 'bridgehubDeposit', + outputs: [ + { + components: [ + { + internalType: 'bytes32', + name: 'magicValue', + type: 'bytes32', + }, + { + internalType: 'address', + name: 'l2Contract', + type: 'address', + }, + { + internalType: 'bytes', + name: 'l2Calldata', + type: 'bytes', + }, + { + internalType: 'bytes[]', + name: 'factoryDeps', + type: 'bytes[]', + }, + { + internalType: 'bytes32', + name: 'txDataHash', + type: 'bytes32', + }, + ], + internalType: 'struct L2TransactionRequestTwoBridgesInner', + name: 'request', + type: 'tuple', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_prevMsgSender', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + ], + name: 'bridgehubDepositBaseToken', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_depositSender', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_l2TxHash', + type: 'bytes32', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, + ], + name: 'claimFailedDeposit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_l2Receiver', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_mintValue', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2TxGasLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2TxGasPerPubdataByte', + type: 'uint256', + }, + { + internalType: 'address', + name: '_refundRecipient', + type: 'address', + }, + ], + name: 'deposit', + outputs: [ + { + internalType: 'bytes32', + name: 'txHash', + type: 'bytes32', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_l2TxHash', + type: 'bytes32', + }, + ], + name: 'depositHappened', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, + { + internalType: 'bytes', + name: '_message', + type: 'bytes', + }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, + ], + name: 'finalizeWithdrawal', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + ], + name: 'isWithdrawalFinalizedShared', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + ], + name: 'l2BridgeAddress', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] + export const paymasterAbi = [ { inputs: [ { internalType: 'address', - name: '_token', + name: '_token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_minAllowance', + type: 'uint256', + }, + { + internalType: 'bytes', + name: '_innerInput', + type: 'bytes', + }, + ], + name: 'approvalBased', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bytes', + name: 'input', + type: 'bytes', + }, + ], + name: 'general', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] + +/** [ERC-20 Token Standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-20) */ +export const erc20Abi = [ + { + type: 'event', + name: 'Approval', + inputs: [ + { + indexed: true, + name: 'owner', + type: 'address', + }, + { + indexed: true, + name: 'spender', + type: 'address', + }, + { + indexed: false, + name: 'value', + type: 'uint256', + }, + ], + }, + { + type: 'event', + name: 'Transfer', + inputs: [ + { + indexed: true, + name: 'from', + type: 'address', + }, + { + indexed: true, + name: 'to', + type: 'address', + }, + { + indexed: false, + name: 'value', + type: 'uint256', + }, + ], + }, + { + type: 'function', + name: 'allowance', + stateMutability: 'view', + inputs: [ + { + name: 'owner', + type: 'address', + }, + { + name: 'spender', + type: 'address', + }, + ], + outputs: [ + { + type: 'uint256', + }, + ], + }, + { + type: 'function', + name: 'approve', + stateMutability: 'nonpayable', + inputs: [ + { + name: 'spender', + type: 'address', + }, + { + name: 'amount', + type: 'uint256', + }, + ], + outputs: [ + { + type: 'bool', + }, + ], + }, + { + type: 'function', + name: 'balanceOf', + stateMutability: 'view', + inputs: [ + { + name: 'account', + type: 'address', + }, + ], + outputs: [ + { + type: 'uint256', + }, + ], + }, + { + type: 'function', + name: 'decimals', + stateMutability: 'view', + inputs: [], + outputs: [ + { + type: 'uint8', + }, + ], + }, + { + type: 'function', + name: 'name', + stateMutability: 'view', + inputs: [], + outputs: [ + { + type: 'string', + }, + ], + }, + { + type: 'function', + name: 'symbol', + stateMutability: 'view', + inputs: [], + outputs: [ + { + type: 'string', + }, + ], + }, + { + type: 'function', + name: 'totalSupply', + stateMutability: 'view', + inputs: [], + outputs: [ + { + type: 'uint256', + }, + ], + }, + { + type: 'function', + name: 'transfer', + stateMutability: 'nonpayable', + inputs: [ + { + name: 'recipient', + type: 'address', + }, + { + name: 'amount', + type: 'uint256', + }, + ], + outputs: [ + { + type: 'bool', + }, + ], + }, + { + type: 'function', + name: 'transferFrom', + stateMutability: 'nonpayable', + inputs: [ + { + name: 'sender', + type: 'address', + }, + { + name: 'recipient', + type: 'address', + }, + { + name: 'amount', + type: 'uint256', + }, + ], + outputs: [ + { + type: 'bool', + }, + ], + }, +] as const + +export const bridgehubAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'oldAdmin', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newAdmin', + type: 'address', + }, + ], + name: 'NewAdmin', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: false, + internalType: 'address', + name: 'stateTransitionManager', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'chainGovernance', + type: 'address', + }, + ], + name: 'NewChain', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'oldPendingAdmin', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newPendingAdmin', + type: 'address', + }, + ], + name: 'NewPendingAdmin', + type: 'event', + }, + { + inputs: [], + name: 'acceptAdmin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_stateTransitionManager', + type: 'address', + }, + ], + name: 'addStateTransitionManager', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_token', + type: 'address', + }, + ], + name: 'addToken', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + ], + name: 'baseToken', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_stateTransitionManager', + type: 'address', + }, + { + internalType: 'address', + name: '_baseToken', + type: 'address', + }, + { + internalType: 'uint256', + name: '_salt', + type: 'uint256', + }, + { + internalType: 'address', + name: '_admin', + type: 'address', + }, + { + internalType: 'bytes', + name: '_initData', + type: 'bytes', + }, + ], + name: 'createNewChain', + outputs: [ + { + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + ], + name: 'getStateTransition', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_gasPrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2GasLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2GasPerPubdataByteLimit', + type: 'uint256', + }, + ], + name: 'l2TransactionBaseCost', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_l2TxHash', + type: 'bytes32', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, + { + internalType: 'enum TxStatus', + name: '_status', + type: 'uint8', + }, + ], + name: 'proveL1ToL2TransactionStatus', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_batchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_index', + type: 'uint256', + }, + { + components: [ + { + internalType: 'uint8', + name: 'l2ShardId', + type: 'uint8', + }, + { + internalType: 'bool', + name: 'isService', + type: 'bool', + }, + { + internalType: 'uint16', + name: 'txNumberInBatch', + type: 'uint16', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes32', + name: 'key', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'value', + type: 'bytes32', + }, + ], + internalType: 'struct L2Log', + name: '_log', + type: 'tuple', + }, + { + internalType: 'bytes32[]', + name: '_proof', + type: 'bytes32[]', + }, + ], + name: 'proveL2LogInclusion', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_batchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_index', + type: 'uint256', + }, + { + components: [ + { + internalType: 'uint16', + name: 'txNumberInBatch', + type: 'uint16', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + internalType: 'struct L2Message', + name: '_message', + type: 'tuple', + }, + { + internalType: 'bytes32[]', + name: '_proof', + type: 'bytes32[]', + }, + ], + name: 'proveL2MessageInclusion', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_stateTransitionManager', + type: 'address', + }, + ], + name: 'removeStateTransitionManager', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'mintValue', + type: 'uint256', + }, + { + internalType: 'address', + name: 'l2Contract', + type: 'address', + }, + { + internalType: 'uint256', + name: 'l2Value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'l2Calldata', + type: 'bytes', + }, + { + internalType: 'uint256', + name: 'l2GasLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'l2GasPerPubdataByteLimit', + type: 'uint256', + }, + { + internalType: 'bytes[]', + name: 'factoryDeps', + type: 'bytes[]', + }, + { + internalType: 'address', + name: 'refundRecipient', + type: 'address', + }, + ], + internalType: 'struct L2TransactionRequestDirect', + name: '_request', + type: 'tuple', + }, + ], + name: 'requestL2TransactionDirect', + outputs: [ + { + internalType: 'bytes32', + name: 'canonicalTxHash', + type: 'bytes32', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'mintValue', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'l2Value', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'l2GasLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'l2GasPerPubdataByteLimit', + type: 'uint256', + }, + { + internalType: 'address', + name: 'refundRecipient', + type: 'address', + }, + { + internalType: 'address', + name: 'secondBridgeAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'secondBridgeValue', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'secondBridgeCalldata', + type: 'bytes', + }, + ], + internalType: 'struct L2TransactionRequestTwoBridgesOuter', + name: '_request', + type: 'tuple', + }, + ], + name: 'requestL2TransactionTwoBridges', + outputs: [ + { + internalType: 'bytes32', + name: 'canonicalTxHash', + type: 'bytes32', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_newPendingAdmin', + type: 'address', + }, + ], + name: 'setPendingAdmin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_sharedBridge', + type: 'address', + }, + ], + name: 'setSharedBridge', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'sharedBridge', + outputs: [ + { + internalType: 'contract IL1SharedBridge', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + ], + name: 'stateTransitionManager', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_stateTransitionManager', + type: 'address', + }, + ], + name: 'stateTransitionManagerIsRegistered', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_baseToken', + type: 'address', + }, + ], + name: 'tokenIsRegistered', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] + +export const l1SharedBridgeAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'BridgehubDepositBaseTokenInitiated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'txDataHash', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'l2DepositTxHash', + type: 'bytes32', + }, + ], + name: 'BridgehubDepositFinalized', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'txDataHash', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'BridgehubDepositInitiated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'ClaimedFailedDepositSharedBridge', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'l2DepositTxHash', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'LegacyDepositInitiated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'WithdrawalFinalizedSharedBridge', + type: 'event', + }, + { + inputs: [], + name: 'BRIDGE_HUB', + outputs: [ + { + internalType: 'contract IBridgehub', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'L1_WETH_TOKEN', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_txDataHash', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: '_txHash', + type: 'bytes32', + }, + ], + name: 'bridgehubConfirmL2Transaction', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_prevMsgSender', + type: 'address', + }, + { + internalType: 'uint256', + name: '_l2Value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: '_data', + type: 'bytes', + }, + ], + name: 'bridgehubDeposit', + outputs: [ + { + components: [ + { + internalType: 'bytes32', + name: 'magicValue', + type: 'bytes32', + }, + { + internalType: 'address', + name: 'l2Contract', + type: 'address', + }, + { + internalType: 'bytes', + name: 'l2Calldata', + type: 'bytes', + }, + { + internalType: 'bytes[]', + name: 'factoryDeps', + type: 'bytes[]', + }, + { + internalType: 'bytes32', + name: 'txDataHash', + type: 'bytes32', + }, + ], + internalType: 'struct L2TransactionRequestTwoBridgesInner', + name: 'request', + type: 'tuple', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_prevMsgSender', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + ], + name: 'bridgehubDepositBaseToken', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'address', + name: '_depositSender', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_l2TxHash', + type: 'bytes32', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, + ], + name: 'claimFailedDeposit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_depositSender', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_l2TxHash', + type: 'bytes32', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, + ], + name: 'claimFailedDepositLegacyErc20Bridge', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: '_l2TxHash', + type: 'bytes32', + }, + ], + name: 'depositHappened', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_msgSender', + type: 'address', + }, + { + internalType: 'address', + name: '_l2Receiver', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2TxGasLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2TxGasPerPubdataByte', + type: 'uint256', + }, + { + internalType: 'address', + name: '_refundRecipient', type: 'address', }, + ], + name: 'depositLegacyErc20Bridge', + outputs: [ + { + internalType: 'bytes32', + name: 'txHash', + type: 'bytes32', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, { internalType: 'uint256', - name: '_minAllowance', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', type: 'uint256', }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, { internalType: 'bytes', - name: '_innerInput', + name: '_message', type: 'bytes', }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, ], - name: 'approvalBased', + name: 'finalizeWithdrawal', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + { + internalType: 'uint16', + name: '_l2TxNumberInBatch', + type: 'uint16', + }, { internalType: 'bytes', - name: 'input', + name: '_message', type: 'bytes', }, + { + internalType: 'bytes32[]', + name: '_merkleProof', + type: 'bytes32[]', + }, ], - name: 'general', + name: 'finalizeWithdrawalLegacyErc20Bridge', + outputs: [ + { + internalType: 'address', + name: 'l1Receiver', + type: 'address', + }, + { + internalType: 'address', + name: 'l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2BatchNumber', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_l2MessageIndex', + type: 'uint256', + }, + ], + name: 'isWithdrawalFinalized', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + ], + name: 'l2BridgeAddress', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'legacyBridge', + outputs: [ + { + internalType: 'contract IL1ERC20Bridge', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + ], + name: 'receiveEth', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_eraLegacyBridgeLastDepositBatch', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_eraLegacyBridgeLastDepositTxNumber', + type: 'uint256', + }, + ], + name: 'setEraLegacyBridgeLastDepositTime', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_eraPostDiamondUpgradeFirstBatch', + type: 'uint256', + }, + ], + name: 'setEraPostDiamondUpgradeFirstBatch', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_eraPostLegacyBridgeUpgradeFirstBatch', + type: 'uint256', + }, + ], + name: 'setEraPostLegacyBridgeUpgradeFirstBatch', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const + +export const l2BridgeAbi = [ + { + inputs: [ + { + internalType: 'address', + name: '_l1Sender', + type: 'address', + }, + { + internalType: 'address', + name: '_l2Receiver', + type: 'address', + }, + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + { + internalType: 'bytes', + name: '_data', + type: 'bytes', + }, + ], + name: 'finalizeDeposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'l1Bridge', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_l2Token', + type: 'address', + }, + ], + name: 'l1TokenAddress', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_l1Token', + type: 'address', + }, + ], + name: 'l2TokenAddress', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_l1Receiver', + type: 'address', + }, + { + internalType: 'address', + name: '_l2Token', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amount', + type: 'uint256', + }, + ], + name: 'withdraw', outputs: [], stateMutability: 'nonpayable', type: 'function', diff --git a/src/zksync/constants/address.ts b/src/zksync/constants/address.ts index dd8e4835aa..7996e99ac3 100644 --- a/src/zksync/constants/address.ts +++ b/src/zksync/constants/address.ts @@ -1,3 +1,5 @@ +import type { Address } from 'abitype' + export const contractDeployerAddress = '0x0000000000000000000000000000000000008006' as const @@ -9,3 +11,16 @@ export const ethAddressInContracts = export const l2BaseTokenAddress = '0x000000000000000000000000000000000000800a' as const + +export const bootloaderFormalAddress = + '0x0000000000000000000000000000000000008001' + +export const l1ToL2AliasOffset = '0x1111000000000000000000000000000000001111' + +export const l1MessengerAddress = '0x0000000000000000000000000000000000008008' + +export const paymasterAddress = + '0xa222f0c183AFA73a8Bc1AFb48D34C88c9Bf7A174' as Address + +export const approvalTokenAddress = + '0x841c43Fa5d8fFfdB9efE3358906f7578d8700Dd4' as Address diff --git a/src/zksync/constants/number.ts b/src/zksync/constants/number.ts index 8cb3972169..e36e7f3938 100644 --- a/src/zksync/constants/number.ts +++ b/src/zksync/constants/number.ts @@ -2,3 +2,14 @@ import { maxUint16 } from '../../constants/number.js' export const gasPerPubdataDefault = 50000n export const maxBytecodeSize = maxUint16 * 32n + +export const requiredL2GasPricePerPubdata = 800 + +export const requiredL1ToL2GasPerPubdataLimit = 800n + +export const l1FeeEstimationCoefNumerator = 12 +export const l1FeeEstimationCoefDenominator = 10 + +export const addressModulo = 2n ** 160n + +export const defaultPollingIntervalMs = 500 diff --git a/src/zksync/types/deposit.ts b/src/zksync/types/deposit.ts new file mode 100644 index 0000000000..7681f86eb6 --- /dev/null +++ b/src/zksync/types/deposit.ts @@ -0,0 +1,46 @@ +import type { Address } from 'abitype' +import type { Hex } from '../../types/misc.js' +import type { GetDefaultBridgeAddressesReturnType } from '../actions/getDefaultBridgeAddresses.js' +import type { ZksyncTransactionRequest } from './transaction.js' + +export type DepositTransaction = { + amount: bigint + token?: Address + to?: Address + operatorTip?: bigint + bridgeAddress?: Address + approveERC20?: boolean + approveBaseERC20?: boolean + l2GasLimit?: bigint + gasPerPubdataByte?: bigint + refundRecipient?: Address + overrides?: Overrides + approveOverrides?: Overrides + approveBaseOverrides?: Overrides + customBridgeData?: Hex +} + +export type DepositTransactionExtended = DepositTransaction & { + bridgehubContractAddress: Address + l2ChainId: bigint + eRC20DefaultBridgeData: Hex + bridgeAddresses?: GetDefaultBridgeAddressesReturnType +} + +export interface Overrides + extends Omit { + gasLimit: bigint +} + +export type DepositTypeValues = { + mintValue: bigint + l2Value: bigint + txValue: bigint +} + +export type SecondBridgeEncodeData = { + secondBridgeValue: bigint + token: Address + amount: bigint + to: Address +} diff --git a/src/zksync/types/eip1193.ts b/src/zksync/types/eip1193.ts index 628a4d5fbd..90d81e957e 100644 --- a/src/zksync/types/eip1193.ts +++ b/src/zksync/types/eip1193.ts @@ -65,7 +65,27 @@ export type RawBlockTransactions = { raw_bytes?: string }[] -export type PublicZksyncRpcSchema = [ +export type PublicZkSyncRpcSchema = [ + { + Method: 'zks_sendRawTransactionWithDetailedOutput' + Parameters: [Hash] + ReturnType: SendRawTransactionWithDetailedReturnType + }, + { + Method: 'zks_getConfirmedTokens' + Parameters: [number, number] + ReturnType: GetConfirmedTokensReturnType + }, + { + Method: 'zks_getFeeParams' + Parameters: [] + ReturnType: GetFeeParamsReturnType + }, + { + Method: 'zks_getProtocolVersion' + Parameters: [number | undefined] + ReturnType: GetProtocolVersionReturnType + }, { Method: 'zks_estimateFee' Parameters: [TransactionRequest] @@ -131,7 +151,7 @@ export type PublicZksyncRpcSchema = [ { Method: 'zks_getL1BatchDetails' Parameters: [number] - ReturnType: ZksyncBatchDetails + ReturnType: ZkSyncBatchDetails }, { Method: 'zks_getRawBlockTransactions' @@ -141,12 +161,12 @@ export type PublicZksyncRpcSchema = [ { Method: 'zks_getBlockDetails' Parameters: [number] - ReturnType: ZksyncBlockDetails + ReturnType: ZkSyncBlockDetails }, { Method: 'zks_getTransactionDetails' Parameters: [Hash] - ReturnType: ZksyncTransactionDetails + ReturnType: ZkSyncTransactionDetails }, { Method: 'zks_getBridgehubContract' diff --git a/src/zksync/types/transaction.ts b/src/zksync/types/transaction.ts index bbfe59112f..a672c5fbeb 100644 --- a/src/zksync/types/transaction.ts +++ b/src/zksync/types/transaction.ts @@ -73,6 +73,29 @@ export type ZksyncTransaction = // Transaction (RPC) +export type TransactionWithDetailedOutput = { + transactionHash: Hash + storageLogs: Array<{ + address: Address + key: string + writtenValue: string + }> + events: Array<{ + address: Address + topics: Hex[] + data: Hex + blockHash: Hash | null + blockNumber: bigint | null + l1BatchNumber: bigint | null + transactionHash: Hash + transactionIndex: bigint + logIndex: bigint | null + transactionLogIndex: bigint | null + logType: string | null + removed: boolean + }> +} + type RpcTransactionOverrides = { l1BatchNumber: Hex | null l1BatchTxIndex: Hex | null diff --git a/src/zksync/utils/bridge/applyL1ToL2Alias.test.ts b/src/zksync/utils/bridge/applyL1ToL2Alias.test.ts new file mode 100644 index 0000000000..f1d2a5c9c1 --- /dev/null +++ b/src/zksync/utils/bridge/applyL1ToL2Alias.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'vitest' +import { applyL1ToL2Alias } from './applyL1ToL2Alias.js' + +describe('applyL1ToL2Alias', () => { + it('should apply L1 to L2 alias to an address v1', () => { + const address = '0x1234567890123456789012345678901234567890' + const expectedAlias = '0x23455678901234567890123456789012345689a1' + + const result = applyL1ToL2Alias({ address }) + + expect(result).toBe(expectedAlias) + }) + + it('should apply L1 to L2 alias to an address v2', () => { + const address = '0x1111000000000000000000000000000000001111' + const expectedAlias = '0x2222000000000000000000000000000000002222' + + const result = applyL1ToL2Alias({ address }) + + expect(result).toBe(expectedAlias) + }) +}) diff --git a/src/zksync/utils/bridge/applyL1ToL2Alias.ts b/src/zksync/utils/bridge/applyL1ToL2Alias.ts new file mode 100644 index 0000000000..2aa6228c52 --- /dev/null +++ b/src/zksync/utils/bridge/applyL1ToL2Alias.ts @@ -0,0 +1,21 @@ +import type { Address } from 'abitype' +import { pad, toHex } from '../../../utils/index.js' +import { l1ToL2AliasOffset } from '../../constants/address.js' +import { addressModulo } from '../../constants/number.js' + +export type ApplyL1ToL2AliasParameters = { + address: Address +} + +export type ApplyL1ToL2AliasReturnType = Address + +export function applyL1ToL2Alias( + parameters: ApplyL1ToL2AliasParameters, +): ApplyL1ToL2AliasReturnType { + return pad( + toHex( + (BigInt(parameters.address) + BigInt(l1ToL2AliasOffset)) % addressModulo, + ), + { size: 20 }, + ) +} diff --git a/src/zksync/utils/bridge/approveL1Erc20Token.test.ts b/src/zksync/utils/bridge/approveL1Erc20Token.test.ts new file mode 100644 index 0000000000..790ff54cee --- /dev/null +++ b/src/zksync/utils/bridge/approveL1Erc20Token.test.ts @@ -0,0 +1,51 @@ +import { erc20Abi } from 'abitype/abis' +import { afterAll, expect, test, vi } from 'vitest' +import { accounts } from '../../../../test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' +import * as writeContract from '../../../actions/wallet/writeContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import type { Overrides } from '../../types/deposit.js' +import { approveErc20L1 } from './approveL1Erc20Token.js' + +const sourceAccount = accounts[0] +const token = '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55' +const account = privateKeyToAccount(sourceAccount.privateKey) + +const spy = vi + .spyOn(writeContract, 'writeContract') + .mockResolvedValue( + '0x5254a0e1d200d0900920b9bc810caf2d26814426db0719da05a1b14bc3e4032d', + ) + +afterAll(() => { + spy.mockRestore() +}) + +test('default', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await approveErc20L1(client, { + token, + amount: 222n, + sharedL1Address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + overrides: {} as Overrides, + }), + ).toBe('0x5254a0e1d200d0900920b9bc810caf2d26814426db0719da05a1b14bc3e4032d') + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: token, + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 222n], + functionName: 'approve', + chain: client.chain, + account, + }) +}) diff --git a/src/zksync/utils/bridge/approveL1Erc20Token.ts b/src/zksync/utils/bridge/approveL1Erc20Token.ts new file mode 100644 index 0000000000..669d47ac7f --- /dev/null +++ b/src/zksync/utils/bridge/approveL1Erc20Token.ts @@ -0,0 +1,55 @@ +import type { Address } from 'abitype' +import { erc20Abi } from 'abitype/abis' +import { + type WriteContractParameters, + writeContract, +} from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account, GetAccountParameter } from '../../../types/account.js' +import type { Chain, GetChainParameter } from '../../../types/chain.js' +import type { Hash } from '../../../types/misc.js' +import { parseAccount } from '../../../utils/index.js' +import type { Overrides } from '../../types/deposit.js' + +export type ApproveErc20L1Parameters< + TChain extends Chain | undefined = Chain | undefined, + TAccount extends Account | undefined = Account | undefined, + chainOverride extends Chain | undefined = Chain | undefined, +> = GetAccountParameter & + (TChain extends undefined ? {} : GetChainParameter) & { + token: Address + amount: bigint + sharedL1Address: Address + overrides: Overrides & { bridgeAddress?: Address } + } +export async function approveErc20L1< + TChain extends Chain | undefined, + TAccount extends Account | undefined, + chainOverride extends Chain | undefined = undefined, +>( + clientL1: Client, + parameters: ApproveErc20L1Parameters, +): Promise { + const { account: account_, token, amount } = parameters + + const account = account_ ? parseAccount(account_) : clientL1.account + let bridgeAddress = parameters.overrides.bridgeAddress + + if (!bridgeAddress) { + bridgeAddress = parameters.sharedL1Address + } else { + delete parameters.overrides.bridgeAddress + } + + return await writeContract(clientL1, { + account: account!, + abi: erc20Abi, + chain: clientL1.chain, + address: token, + functionName: 'approve', + args: [bridgeAddress, amount], + //TODO: Add rest of the parameters? + // gas:parameters.overrides.gas + } satisfies WriteContractParameters as any) +} diff --git a/src/zksync/utils/bridge/getAllowanceL1.test.ts b/src/zksync/utils/bridge/getAllowanceL1.test.ts new file mode 100644 index 0000000000..51f2faef36 --- /dev/null +++ b/src/zksync/utils/bridge/getAllowanceL1.test.ts @@ -0,0 +1,130 @@ +import { afterAll, expect, test, vi } from 'vitest' + +import { accounts } from '~test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' + +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { erc20Abi } from '../../constants/abis.js' + +import { createClient } from '../../../clients/createClient.js' +import { createPublicClient } from '../../../clients/createPublicClient.js' +import { createWalletClient } from '../../../clients/createWalletClient.js' +import { http } from '../../../clients/transports/http.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { getAllowanceL1 } from './getAllowanceL1.js' + +const sourceAccount = accounts[0] +const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B' +const account = privateKeyToAccount(sourceAccount.privateKey) +const spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(170n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default with account hoisting', async () => { + const client = createWalletClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getAllowanceL1(client, { + token: tokenL1, + bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'allowance', + args: [ + '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + ], + blockTag: undefined, + }) +}) + +test('args: blockTag with account hoisting', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getAllowanceL1(client, { + token: tokenL1, + bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + blockTag: 'finalized', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'allowance', + args: [ + '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + ], + blockTag: 'finalized', + }) +}) + +test('default with account provided to the method', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getAllowanceL1(client, { + token: tokenL1, + bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + account, + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'allowance', + args: [ + '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + ], + blockTag: undefined, + }) +}) + +test('args: blockTag with account provided to the method', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getAllowanceL1(client, { + token: tokenL1, + bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + account, + blockTag: 'finalized', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'allowance', + args: [ + '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', + ], + blockTag: 'finalized', + }) +}) diff --git a/src/zksync/utils/bridge/getAllowanceL1.ts b/src/zksync/utils/bridge/getAllowanceL1.ts new file mode 100644 index 0000000000..4ce1bab967 --- /dev/null +++ b/src/zksync/utils/bridge/getAllowanceL1.ts @@ -0,0 +1,48 @@ +import type { Address } from '../../../accounts/index.js' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { AccountNotFoundError } from '../../../errors/account.js' +import type { BaseError } from '../../../errors/base.js' +import type { Account, GetAccountParameter } from '../../../types/account.js' +import type { BlockTag } from '../../../types/block.js' +import type { Chain } from '../../../types/chain.js' +import { parseAccount } from '../../../utils/index.js' +import { erc20Abi } from '../../constants/abis.js' + +export type AllowanceL1Parameters< + TAccount extends Account | undefined = Account | undefined, +> = GetAccountParameter & { + token: Address + bridgeAddress: Address + blockTag?: BlockTag +} + +export type getAllowanceL1ReturnType = bigint + +export type getAllowanceL1L1ErrorType = AccountNotFoundError | BaseError + +export async function getAllowanceL1< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: AllowanceL1Parameters, +): Promise { + const { + token, + bridgeAddress, + blockTag, + account: account_, + } = parameters as AllowanceL1Parameters + + const account = account_ ? parseAccount(account_) : client.account + + return await readContract(client, { + abi: erc20Abi, + address: token, + functionName: 'allowance', + args: [account!.address, bridgeAddress], + blockTag: blockTag, + }) +} diff --git a/src/zksync/utils/bridge/getBalanceL1.test.ts b/src/zksync/utils/bridge/getBalanceL1.test.ts new file mode 100644 index 0000000000..672706dc02 --- /dev/null +++ b/src/zksync/utils/bridge/getBalanceL1.test.ts @@ -0,0 +1,163 @@ +import { afterAll, expect, test, vi } from 'vitest' + +import { accounts } from '~test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' + +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { createPublicClient } from '../../../clients/createPublicClient.js' +import { http } from '../../../clients/transports/http.js' +import { erc20Abi } from '../../constants/abis.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { getBalanceL1 } from './getBalanceL1.js' + +const sourceAccount = accounts[0] +const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B' +const account = privateKeyToAccount(sourceAccount.privateKey) +const spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(170n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default with account hoisting and token', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + token: tokenL1, + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: undefined, + }) +}) + +test('args: blockTag with account hoisting and token', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + token: tokenL1, + blockTag: 'finalized', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: 'finalized', + }) +}) + +test('default with account provided to the method and token', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + token: tokenL1, + account, + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: undefined, + }) +}) + +test('args: blockTag with account provided to the method and token', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + token: tokenL1, + account, + blockTag: 'finalized', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: 'finalized', + }) +}) + +test('default with account hoisting', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect(await getBalanceL1(client, {})).toBeGreaterThanOrEqual(0n) +}) + +test('args: blockTag with account hoisting', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + blockTag: 'finalized', + }), + ).toBeGreaterThanOrEqual(0n) +}) + +test('default with account provided to the method', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + account, + }), + ).toBeGreaterThanOrEqual(0n) +}) + +test('args: blockTag with account provided to the method', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBalanceL1(client, { + account, + blockTag: 'finalized', + }), + ).toBeGreaterThanOrEqual(0n) +}) diff --git a/src/zksync/utils/bridge/getBalanceL1.ts b/src/zksync/utils/bridge/getBalanceL1.ts new file mode 100644 index 0000000000..32c9a0aaa3 --- /dev/null +++ b/src/zksync/utils/bridge/getBalanceL1.ts @@ -0,0 +1,63 @@ +import type { Address } from '../../../accounts/index.js' +import { getBalance } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { AccountNotFoundError } from '../../../errors/account.js' +import type { BaseError } from '../../../errors/base.js' +import type { Account, GetAccountParameter } from '../../../types/account.js' +import type { BlockTag } from '../../../types/block.js' +import type { Chain } from '../../../types/chain.js' +import type { IsUndefined } from '../../../types/utils.js' +import { parseAccount } from '../../../utils/index.js' +import { legacyEthAddress } from '../../constants/address.js' +import { isEth } from '../../utils/isEth.js' +import { + type BalanceOfTokenL1Parameters, + getBalanceOfTokenL1, +} from './getBalanceOfTokenL1.js' + +export type BalanceL1Parameters< + TAccount extends Account | undefined = Account | undefined, + TToken extends Address | undefined = Address | undefined, + TRequired extends boolean = false, +> = GetAccountParameter & + (IsUndefined extends true + ? TRequired extends false + ? { token?: TToken | Address } + : { token: TToken | Address } + : { token?: TToken | Address }) & { + blockTag?: BlockTag | undefined + } + +export type BalanceL1ReturnType = bigint + +export type BalanceL1ErrorType = AccountNotFoundError | BaseError + +export async function getBalanceL1< + TChain extends Chain | undefined, + TAccount extends Account | undefined, + TToken extends Address | undefined = Address | undefined, +>( + client: Client, + parameters: BalanceL1Parameters, +): Promise { + const { + token: token_, + blockTag, + account: account_, + } = parameters as BalanceL1Parameters + + const account = account_ ? parseAccount(account_) : client.account + const token = token_ ?? legacyEthAddress + + if (isEth(token)) { + return await getBalance(client, { + address: account!.address, + blockTag: blockTag, + }) + } + + return await getBalanceOfTokenL1(client, { + ...(parameters as BalanceOfTokenL1Parameters), + }) +} diff --git a/src/zksync/utils/bridge/getBalanceOfTokenL1.test.ts b/src/zksync/utils/bridge/getBalanceOfTokenL1.test.ts new file mode 100644 index 0000000000..bb1e83202c --- /dev/null +++ b/src/zksync/utils/bridge/getBalanceOfTokenL1.test.ts @@ -0,0 +1,170 @@ +import { afterAll, expect, test, vi } from 'vitest' + +import { accounts } from '~test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' + +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { erc20Abi } from '../../../constants/abis.js' +import { http, createClient, createPublicClient } from '../../../index.js' +import { + ethAddressInContracts, + l2BaseTokenAddress, + legacyEthAddress, +} from '../../constants/address.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { getBalanceOfTokenL1 } from './getBalanceOfTokenL1.js' + +const sourceAccount = accounts[0] +const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B' +const account = privateKeyToAccount(sourceAccount.privateKey) +const spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(170n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default with account hoisting', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getBalanceOfTokenL1(client, { + token: tokenL1, + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: undefined, + }) +}) + +test('args: blockTag with account hoisting', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getBalanceOfTokenL1(client, { + token: tokenL1, + blockTag: 'finalized', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: 'finalized', + }) +}) + +test('default with account provided to the method', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBalanceOfTokenL1(client, { + token: tokenL1, + account, + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: undefined, + }) +}) + +test('args: blockTag with account provided to the method', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBalanceOfTokenL1(client, { + token: tokenL1, + account, + blockTag: 'finalized', + }), + ).toBe(170n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'balanceOf', + args: ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'], + blockTag: 'finalized', + }) +}) + +test('provided token is ETH', async () => { + const client = createPublicClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + await expect(() => + getBalanceOfTokenL1(client, { + token: ethAddressInContracts, + account, + blockTag: 'finalized', + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + ` + [TokenIsEthError: Token is an ETH token. + + ETH token cannot be retrieved. + + Version: viem@x.y.z] + `, + ) + + await expect(() => + getBalanceOfTokenL1(client, { + token: legacyEthAddress, + account, + blockTag: 'finalized', + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + ` + [TokenIsEthError: Token is an ETH token. + + ETH token cannot be retrived. + + Version: viem@1.0.2] + `, + ) + + await expect(() => + getBalanceOfTokenL1(client, { + token: l2BaseTokenAddress, + account, + blockTag: 'finalized', + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + ` + [TokenIsEthError: Token is an ETH token. + + ETH token cannot be retrived. + + Version: viem@1.0.2] + `, + ) +}) diff --git a/src/zksync/utils/bridge/getBalanceOfTokenL1.ts b/src/zksync/utils/bridge/getBalanceOfTokenL1.ts new file mode 100644 index 0000000000..6a72077e1b --- /dev/null +++ b/src/zksync/utils/bridge/getBalanceOfTokenL1.ts @@ -0,0 +1,55 @@ +import type { Address } from '../../../accounts/index.js' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { AccountNotFoundError } from '../../../errors/account.js' +import type { BaseError } from '../../../errors/base.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { parseAccount } from '../../../utils/index.js' +import { erc20Abi } from '../../constants/abis.js' +import { TokenIsEthError } from '../../errors/token-is-eth.js' +import { isEth } from '../../utils/isEth.js' +import type { BalanceL1Parameters } from './getBalanceL1.js' + +export type BalanceOfTokenL1Parameters< + TAccount extends Account | undefined = Account | undefined, + TToken extends Address | undefined = Address | undefined, + TRequired extends boolean = true, +> = BalanceL1Parameters + +export type BalanceOfTokenL1ReturnType = bigint + +export type BalanceOfTokenL1ErrorType = + | AccountNotFoundError + | BaseError + | TokenIsEthError + +export async function getBalanceOfTokenL1< + TChain extends Chain | undefined, + TAccount extends Account | undefined, + TToken extends Address | undefined = Address | undefined, +>( + client: Client, + parameters: BalanceOfTokenL1Parameters, +): Promise { + const { + token, + blockTag, + account: account_, + } = parameters as BalanceOfTokenL1Parameters + + if (isEth(token!)) { + throw new TokenIsEthError() + } + + const account = account_ ? parseAccount(account_) : client.account + + return await readContract(client, { + abi: erc20Abi, + address: token!, + functionName: 'balanceOf', + args: [account!.address], + blockTag: blockTag, + }) +} diff --git a/src/zksync/utils/bridge/getBaseToken.test.ts b/src/zksync/utils/bridge/getBaseToken.test.ts new file mode 100644 index 0000000000..96c2347622 --- /dev/null +++ b/src/zksync/utils/bridge/getBaseToken.test.ts @@ -0,0 +1,39 @@ +import { afterAll, expect, test, vi } from 'vitest' +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { bridgehubAbi } from '../../constants/abis.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { getBaseToken } from './getBaseToken.js' + +const bridgehubContractAddress = '0x05b30BE4e32E6dD6eEe2171E0746e987BeCc9b36' + +let spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getBaseToken(client, { + bridgehubContractAddress, + l2ChainId: BigInt(client.chain.id), + }), + ).toBe(100n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: bridgehubAbi, + address: bridgehubContractAddress, + args: [BigInt(client.chain.id)], + functionName: 'baseToken', + }) +}) diff --git a/src/zksync/utils/bridge/getBaseToken.ts b/src/zksync/utils/bridge/getBaseToken.ts new file mode 100644 index 0000000000..0af9efdda3 --- /dev/null +++ b/src/zksync/utils/bridge/getBaseToken.ts @@ -0,0 +1,27 @@ +import type { Address } from 'abitype' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { bridgehubAbi } from '../../constants/abis.js' + +export type GetBaseTokenParameters = { + bridgehubContractAddress: Address + l2ChainId: bigint +} + +export async function getBaseToken< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + clientL1: Client, + parameters: GetBaseTokenParameters, +): Promise
{ + return (await readContract(clientL1, { + abi: bridgehubAbi, + functionName: 'baseToken', + args: [parameters.l2ChainId], + address: parameters.bridgehubContractAddress, + })) as Address +} diff --git a/src/zksync/utils/bridge/getConfirmedTokens.test.ts b/src/zksync/utils/bridge/getConfirmedTokens.test.ts new file mode 100644 index 0000000000..8c96e8724d --- /dev/null +++ b/src/zksync/utils/bridge/getConfirmedTokens.test.ts @@ -0,0 +1,29 @@ +import { expect, test } from 'vitest' +import { mockClientPublicActionsL2 } from '../../../../test/src/zksync.js' +import { zkLocalChainL2 } from '../../../chains/definitions/zkLocalChainL2.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { getConfirmedTokens } from './getConfirmedTokens.js' + +const clientL2 = createClient({ + chain: zkLocalChainL2, + transport: http(), +}) + +mockClientPublicActionsL2(clientL2) + +test('default', async () => { + const confirmedTokens = await getConfirmedTokens(clientL2) + + expect(confirmedTokens).toMatchInlineSnapshot(` + [ + { + "decimals": 18, + "l1Address": "0x0000000000000000000000000000000000000000", + "l2Address": "0x0000000000000000000000000000000000000000", + "name": "Ether", + "symbol": "ETH", + }, + ] + `) +}) diff --git a/src/zksync/utils/bridge/getConfirmedTokens.ts b/src/zksync/utils/bridge/getConfirmedTokens.ts new file mode 100644 index 0000000000..e0ab33732e --- /dev/null +++ b/src/zksync/utils/bridge/getConfirmedTokens.ts @@ -0,0 +1,32 @@ +import type { Address } from 'abitype' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import type { PublicZkSyncRpcSchema } from '../../types/eip1193.js' + +export type Token = { + l1Address: Address + l2Address: Address + name: string + symbol: string + decimals: number +} + +export type GetConfirmedTokensReturnType = Token[] + +export async function getConfirmedTokens< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, +): Promise { + const start = 0 + const limit = 255 + + const tokens: Token[] = await client.request({ + method: 'zks_getConfirmedTokens', + params: [start, limit], + }) + return tokens +} diff --git a/src/zksync/utils/bridge/getErc20ContractValue.test.ts b/src/zksync/utils/bridge/getErc20ContractValue.test.ts new file mode 100644 index 0000000000..0cd9386abc --- /dev/null +++ b/src/zksync/utils/bridge/getErc20ContractValue.test.ts @@ -0,0 +1,107 @@ +import { erc20Abi } from 'abitype/abis' +import { afterAll, expect, test, vi } from 'vitest' +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { getErc20ContractValue } from './getErc20ContractValue.js' + +const tokenL1 = '0x53844F9577C2334e541Aec7Df7174ECe5dF1fCf0' +let spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default with decimals', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(18) + + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getErc20ContractValue(client, { + functionName: 'decimals', + l1TokenAddress: tokenL1, + }), + ).toBe(18) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'decimals', + args: [], + }) +}) + +test('default with name', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue('Test') + + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getErc20ContractValue(client, { + functionName: 'name', + l1TokenAddress: tokenL1, + }), + ).toBe('Test') + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'name', + args: [], + }) +}) + +test('default with symbol', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue('T') + + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getErc20ContractValue(client, { + functionName: 'symbol', + l1TokenAddress: tokenL1, + }), + ).toBe('T') + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'symbol', + args: [], + }) +}) + +test('default with total supply', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100000000n) + + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getErc20ContractValue(client, { + functionName: 'totalSupply', + l1TokenAddress: tokenL1, + }), + ).toBe(100000000n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: erc20Abi, + address: tokenL1, + functionName: 'totalSupply', + args: [], + }) +}) diff --git a/src/zksync/utils/bridge/getErc20ContractValue.ts b/src/zksync/utils/bridge/getErc20ContractValue.ts new file mode 100644 index 0000000000..697805597a --- /dev/null +++ b/src/zksync/utils/bridge/getErc20ContractValue.ts @@ -0,0 +1,27 @@ +import type { Address } from 'abitype' +import { erc20Abi } from 'abitype/abis' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' + +export type GetErc20ContractValueParameters = { + l1TokenAddress: Address + functionName: 'name' | 'symbol' | 'totalSupply' | 'decimals' +} + +export async function getErc20ContractValue< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: GetErc20ContractValueParameters, +): Promise { + return (await readContract(client, { + abi: erc20Abi, + functionName: parameters.functionName, + address: parameters.l1TokenAddress, + args: [], + })) as string +} diff --git a/src/zksync/utils/bridge/getFeeParameters.test.ts b/src/zksync/utils/bridge/getFeeParameters.test.ts new file mode 100644 index 0000000000..b54f2735b5 --- /dev/null +++ b/src/zksync/utils/bridge/getFeeParameters.test.ts @@ -0,0 +1,17 @@ +import { expect, test } from 'vitest' +import { zkLocalChainL2 } from '../../../chains/definitions/zkLocalChainL2.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { getFeeParams } from './getFeeParameters.js' + +const clientL2 = createClient({ + chain: zkLocalChainL2, + transport: http(), +}) + +// mockClientPublicActionsL2(clientL2) + +test('default', async () => { + const feeParams = await getFeeParams(clientL2) + expect(feeParams).toBeDefined() +}) diff --git a/src/zksync/utils/bridge/getFeeParameters.ts b/src/zksync/utils/bridge/getFeeParameters.ts new file mode 100644 index 0000000000..289dbc94bc --- /dev/null +++ b/src/zksync/utils/bridge/getFeeParameters.ts @@ -0,0 +1,33 @@ +import type { Chain } from '~viem/types/chain.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { PublicZkSyncRpcSchema } from '../../types/eip1193.js' + +export type GetFeeParamsReturnType = { + V2: { + config: { + minimal_l2_gas_price: bigint + compute_overhead_part: bigint + pubdata_overhead_part: bigint + batch_overhead_l1_gas: bigint + max_gas_per_batch: bigint + max_pubdata_per_batch: bigint + } + l1_gas_price: bigint + l1_pubdata_price: bigint + } +} + +export async function getFeeParams< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, +): Promise { + const result = await client.request({ + method: 'zks_getFeeParams', + params: [], + }) + return result +} diff --git a/src/zksync/utils/bridge/getL2BridgeAddress.test.ts b/src/zksync/utils/bridge/getL2BridgeAddress.test.ts new file mode 100644 index 0000000000..05c07bb99b --- /dev/null +++ b/src/zksync/utils/bridge/getL2BridgeAddress.test.ts @@ -0,0 +1,41 @@ +import { afterAll, expect, test, vi } from 'vitest' +import { accounts } from '../../../../test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { l1BridgeFactoryAbi } from '../../constants/abis.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { getL2BridgeAddress } from './getL2BridgeAddress.js' + +const sourceAccount = accounts[0] +const bridgehubAddress = '0xA5b795d453CA0FBD599EC28Dd88d020E06048619' + +const account = privateKeyToAccount(sourceAccount.privateKey) +let spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + expect( + await getL2BridgeAddress(client, { bridgeAddress: bridgehubAddress }), + ).toBe(100n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: l1BridgeFactoryAbi, + address: bridgehubAddress, + args: [BigInt(client.chain.id)], + functionName: 'l2BridgeAddress', + }) +}) diff --git a/src/zksync/utils/bridge/getL2BridgeAddress.ts b/src/zksync/utils/bridge/getL2BridgeAddress.ts new file mode 100644 index 0000000000..58d57b343d --- /dev/null +++ b/src/zksync/utils/bridge/getL2BridgeAddress.ts @@ -0,0 +1,26 @@ +import type { Address } from 'abitype' +import type { Chain } from '~viem/types/chain.js' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import { l1BridgeFactoryAbi } from '../../constants/abis.js' + +export type GetL2BridgeAddressParameters = { + bridgeAddress: Address +} + +export async function getL2BridgeAddress< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: GetL2BridgeAddressParameters, +): Promise
{ + return (await readContract(client, { + abi: l1BridgeFactoryAbi, + functionName: 'l2BridgeAddress', + address: parameters.bridgeAddress, + args: [BigInt(client.chain!.id)], + })) as Address +} diff --git a/src/zksync/utils/bridge/getL2TransactionBaseCost.test.ts b/src/zksync/utils/bridge/getL2TransactionBaseCost.test.ts new file mode 100644 index 0000000000..bf7792815d --- /dev/null +++ b/src/zksync/utils/bridge/getL2TransactionBaseCost.test.ts @@ -0,0 +1,51 @@ +import { afterAll, expect, test, vi } from 'vitest' +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { bridgehubAbi } from '../../constants/abis.js' +import { requiredL2GasPricePerPubdata } from '../../constants/number.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import type { Overrides } from '../../types/deposit.js' +import { getL2TransactionBaseCost } from './getL2TransactionBaseCost.js' + +const bridgehubContractAddress = '0x05b30BE4e32E6dD6eEe2171E0746e987BeCc9b36' +const depositL2GasLimit = 10000000n +const gasPriceForEstimation = 100000000000n + +let spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + +afterAll(() => { + spy.mockRestore() +}) + +test('default', async () => { + spy = vi.spyOn(readContract, 'readContract').mockResolvedValue(100n) + + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await getL2TransactionBaseCost(client, { + overrides: { maxFeePerGas: gasPriceForEstimation } as Overrides, + l2GasLimit: depositL2GasLimit, + gasPerPubdataByte: BigInt(requiredL2GasPricePerPubdata), + bridgehubContractAddress, + l2ChainId: BigInt(client.chain.id), + }), + ).toBe(100n) + + expect(spy).toHaveBeenCalledWith(client, { + abi: bridgehubAbi, + address: bridgehubContractAddress, + args: [ + BigInt(client.chain.id), + gasPriceForEstimation, + depositL2GasLimit, + BigInt(requiredL2GasPricePerPubdata), + ], + functionName: 'l2TransactionBaseCost', + }) +}) diff --git a/src/zksync/utils/bridge/getL2TransactionBaseCost.ts b/src/zksync/utils/bridge/getL2TransactionBaseCost.ts new file mode 100644 index 0000000000..d15e4a4740 --- /dev/null +++ b/src/zksync/utils/bridge/getL2TransactionBaseCost.ts @@ -0,0 +1,36 @@ +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { bridgehubAbi } from '../../constants/abis.js' +import type { DepositTransactionExtended } from '../../types/deposit.js' + +export type GetL2TransactionBaseCostParameters = Pick< + DepositTransactionExtended, + | 'gasPerPubdataByte' + | 'l2GasLimit' + | 'bridgehubContractAddress' + | 'l2ChainId' + | 'overrides' +> + +export async function getL2TransactionBaseCost< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: GetL2TransactionBaseCostParameters, +): Promise { + return (await readContract(client, { + abi: bridgehubAbi, + functionName: 'l2TransactionBaseCost', + address: parameters.bridgehubContractAddress, + args: [ + parameters.l2ChainId, + parameters.overrides?.maxFeePerGas || parameters.overrides?.gasPrice, + parameters.l2GasLimit, + parameters.gasPerPubdataByte, + ], + })) as bigint +} diff --git a/src/zksync/utils/bridge/getProtocolVersion.test.ts b/src/zksync/utils/bridge/getProtocolVersion.test.ts new file mode 100644 index 0000000000..c012e29a17 --- /dev/null +++ b/src/zksync/utils/bridge/getProtocolVersion.test.ts @@ -0,0 +1,36 @@ +import { expect, test } from 'vitest' +import { mockClientPublicActionsL2 } from '../../../../test/src/zksync.js' +import { zkLocalChainL2 } from '../../../chains/definitions/zkLocalChainL2.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { getProtocolVersion } from './getProtocolVersion.js' + +const clientL2 = createClient({ + chain: zkLocalChainL2, + transport: http(), +}) + +mockClientPublicActionsL2(clientL2) + +test('default', async () => { + const protocolVersion = await getProtocolVersion(clientL2, {}) + expect(protocolVersion).toMatchInlineSnapshot(` + { + "base_system_contracts": { + "bootloader": "0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e", + "default_aa": "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32", + }, + "l2_system_upgrade_tx_hash": "0x0b198075f23eba8137d7c071e5b9e594a4acabb85dfbd59b4b5dd326a54671ed", + "timestamp": 0, + "verification_keys_hashes": { + "params": { + "recursion_circuits_set_vks_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursion_leaf_level_vk_hash": "0x435202d277dd06ef3c64ddd99fda043fc27c2bd8b7c66882966840202c27f4f6", + "recursion_node_level_vk_hash": "0xf520cd5b37e74e19fdb369c8d676a04dce8a19457497ac6686d2bb95d94109c8", + }, + "recursion_scheduler_level_vk_hash": "0x1d485be42d712856dfe85b3cf7823f020fa5f83cb41c83f9da307fdc2089beee", + }, + "version_id": 24, + } + `) +}) diff --git a/src/zksync/utils/bridge/getProtocolVersion.ts b/src/zksync/utils/bridge/getProtocolVersion.ts new file mode 100644 index 0000000000..cca8e89be1 --- /dev/null +++ b/src/zksync/utils/bridge/getProtocolVersion.ts @@ -0,0 +1,43 @@ +import type { Address } from 'abitype' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import type { Hash } from '../../../types/misc.js' +import type { PublicZkSyncRpcSchema } from '../../types/eip1193.js' + +export type GetProtocolVersionParameters = { + id?: number +} + +export type GetProtocolVersionReturnType = { + version_id: number + timestamp: number + verification_keys_hashes: { + params: { + recursion_node_level_vk_hash: Hash + recursion_leaf_level_vk_hash: Hash + recursion_circuits_set_vks_hash: Hash + } + recursion_scheduler_level_vk_hash: Hash + } + base_system_contracts: { + bootloader: Hash + default_aa: Address + } + l2_system_upgrade_tx_hash: Hash | null +} + +export async function getProtocolVersion< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: GetProtocolVersionParameters, +): Promise { + const result = await client.request({ + method: 'zks_getProtocolVersion', + params: [parameters?.id], + }) + return result +} diff --git a/src/zksync/utils/bridge/isAddressEqualLite.test.ts b/src/zksync/utils/bridge/isAddressEqualLite.test.ts new file mode 100644 index 0000000000..ded70c0d22 --- /dev/null +++ b/src/zksync/utils/bridge/isAddressEqualLite.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, test } from 'vitest' +import { isAddressEqual } from '../../../utils/index.js' + +test('checksums address', () => { + expect( + isAddressEqual( + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', + '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', + ), + ).toBeTruthy() + expect( + isAddressEqual( + '0xa0cf798816d4b9b9866b5330eea46a18382f251e', + '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', + ), + ).toBeTruthy() + expect( + isAddressEqual( + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', + ), + ).toBeTruthy() + expect( + isAddressEqual( + '0xa0cf798816d4b9b9866b5330eea46a18382f251e', + '0xA0Cf798816D4b9b9866b5330EEa46a18382f251f', + ), + ).toBeFalsy() +}) + +describe('errors', () => { + test('invalid address', () => { + expect(() => + isAddressEqual( + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678az', + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', + ), + ).toThrowErrorMatchingInlineSnapshot(` + [InvalidAddressError: Address "0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678az" is invalid. + + - Address must be a hex value of 20 bytes (40 hex characters). + - Address must match its checksum counterpart. + + Version: viem@1.0.2] + `) + expect(() => + isAddressEqual( + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', + '0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678aff', + ), + ).toThrowErrorMatchingInlineSnapshot(` + [InvalidAddressError: Address "0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678aff" is invalid. + + - Address must be a hex value of 20 bytes (40 hex characters). + - Address must match its checksum counterpart. + + Version: viem@1.0.2] + `) + }) +}) diff --git a/src/zksync/utils/bridge/isAddressEqualLite.ts b/src/zksync/utils/bridge/isAddressEqualLite.ts new file mode 100644 index 0000000000..d20a82dfb5 --- /dev/null +++ b/src/zksync/utils/bridge/isAddressEqualLite.ts @@ -0,0 +1,11 @@ +import type { Address } from 'abitype' + +import type { InvalidAddressErrorType } from '../../../errors/address.js' +import type { ErrorType } from '../../../errors/utils.js' + +export type IsAddressEqualReturnType = boolean +export type IsAddressEqualErrorType = InvalidAddressErrorType | ErrorType + +export function isAddressEqualLite(a: Address, b: Address) { + return a.toLowerCase() === b.toLowerCase() +} diff --git a/src/zksync/utils/bridge/isEth.test.ts b/src/zksync/utils/bridge/isEth.test.ts new file mode 100644 index 0000000000..3e9e5496fa --- /dev/null +++ b/src/zksync/utils/bridge/isEth.test.ts @@ -0,0 +1,13 @@ +import { expect, test } from 'vitest' +import { isEth } from './isEth.js' + +test('true', () => { + expect(isEth('0x0000000000000000000000000000000000000000')).toBeTruthy() + expect(isEth('0x000000000000000000000000000000000000800a')).toBeTruthy() + expect(isEth('0x0000000000000000000000000000000000000001')).toBeTruthy() +}) + +test('false', () => { + expect(isEth('0x0000000000000000000000000000000000000002')).toBeFalsy() + expect(isEth('0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f')).toBeFalsy() +}) diff --git a/src/zksync/utils/bridge/isEth.ts b/src/zksync/utils/bridge/isEth.ts new file mode 100644 index 0000000000..fcaa8105fe --- /dev/null +++ b/src/zksync/utils/bridge/isEth.ts @@ -0,0 +1,20 @@ +import type { Address } from '../../../accounts/index.js' +import { + ethAddressInContracts, + l2BaseTokenAddress, + legacyEthAddress, +} from '../../constants/address.js' + +export function isEth(token: Address) { + return ( + token.localeCompare(legacyEthAddress, undefined, { + sensitivity: 'accent', + }) === 0 || + token.localeCompare(l2BaseTokenAddress, undefined, { + sensitivity: 'accent', + }) === 0 || + token.localeCompare(ethAddressInContracts, undefined, { + sensitivity: 'accent', + }) === 0 + ) +} diff --git a/src/zksync/utils/bridge/isEthBasedChain.test.ts b/src/zksync/utils/bridge/isEthBasedChain.test.ts new file mode 100644 index 0000000000..6cb3afbee4 --- /dev/null +++ b/src/zksync/utils/bridge/isEthBasedChain.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from 'vitest' +import { + mockClientPublicActionsL2, + zksyncClientLocalNodeWithAccount, +} from '../../../../test/src/zksync.js' +import { getIsEthBasedChain } from './isEthBasedChain.js' + +const client = { ...zksyncClientLocalNodeWithAccount } + +mockClientPublicActionsL2(client) + +test('default', async () => { + const isEthBased = await getIsEthBasedChain(client) + expect(isEthBased).toEqual(false) +}) diff --git a/src/zksync/utils/bridge/isEthBasedChain.ts b/src/zksync/utils/bridge/isEthBasedChain.ts new file mode 100644 index 0000000000..7d4194d827 --- /dev/null +++ b/src/zksync/utils/bridge/isEthBasedChain.ts @@ -0,0 +1,19 @@ +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { getBaseTokenL1Address } from '../../actions/getBaseTokenL1Address.js' +import { ethAddressInContracts } from '../../constants/address.js' +import { isAddressEqualLite } from './isAddressEqualLite.js' + +export type GetIsEthBasedChainReturnType = boolean + +export async function getIsEthBasedChain< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + clientL2: Client, +): Promise { + const baseTokenL1Address = await getBaseTokenL1Address(clientL2) + return isAddressEqualLite(baseTokenL1Address, ethAddressInContracts) +} diff --git a/src/zksync/utils/bridge/isWithdrawalFinalized.ts b/src/zksync/utils/bridge/isWithdrawalFinalized.ts new file mode 100644 index 0000000000..6f471d2eb2 --- /dev/null +++ b/src/zksync/utils/bridge/isWithdrawalFinalized.ts @@ -0,0 +1,33 @@ +import type { Address } from 'abitype' +import type { Chain } from '~viem/types/chain.js' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import { l1SharedBridgeAbi } from '../../constants/abis.js' +import type { ZksyncLog } from '../../types/log.js' +import type { MessageProof } from '../../types/proof.js' + +export type IsWithdrawalFinalizedParameters = { + l2ChainId: bigint + log: ZksyncLog + sharedBridgeAddress: Address + proof: MessageProof +} +export type IsWithdrawalFinalizedReturnType = boolean + +export async function isWithdrawalFinalized( + clientL1: Client, + parameters: IsWithdrawalFinalizedParameters, +): Promise { + return (await readContract(clientL1, { + abi: l1SharedBridgeAbi, + functionName: 'isWithdrawalFinalized', + address: parameters.sharedBridgeAddress, + args: [ + parameters.l2ChainId, + parameters.log.l1BatchNumber!, + BigInt(parameters.proof.id!), + ], + })) as boolean +} diff --git a/src/zksync/utils/bridge/l1Bridge.test.ts b/src/zksync/utils/bridge/l1Bridge.test.ts new file mode 100644 index 0000000000..02c599b652 --- /dev/null +++ b/src/zksync/utils/bridge/l1Bridge.test.ts @@ -0,0 +1,25 @@ +import { afterAll, expect, test, vi } from 'vitest' +import { + mockAddress, + mockClientPublicActionsL2, + zkSyncClientLocalNodeWithAccountL1, +} from '~test/src/zksync.js' +import * as readContract from '../../../actions/public/readContract.js' +import { l1Bridge } from './l1Bridge.js' + +const client = { ...zkSyncClientLocalNodeWithAccountL1 } + +mockClientPublicActionsL2(client) + +const spy = vi + .spyOn(readContract, 'readContract') + .mockResolvedValue(mockAddress) + +afterAll(() => { + spy.mockRestore() +}) + +test('getBaseCostFromFeeData', async () => { + const address = await l1Bridge(client, { l2BridgeAddress: mockAddress }) + expect(address).equal(mockAddress) +}) diff --git a/src/zksync/utils/bridge/l1Bridge.ts b/src/zksync/utils/bridge/l1Bridge.ts new file mode 100644 index 0000000000..0f2c33ee51 --- /dev/null +++ b/src/zksync/utils/bridge/l1Bridge.ts @@ -0,0 +1,26 @@ +import type { Address } from 'abitype' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { l2BridgeAbi } from '../../constants/abis.js' + +export type l1BridgeParameters = { + l2BridgeAddress: Address +} + +export async function l1Bridge< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + clientL1: Client, + parameters: l1BridgeParameters, +): Promise
{ + return (await readContract(clientL1, { + abi: l2BridgeAbi, + functionName: 'l1Bridge', + args: [], + address: parameters.l2BridgeAddress, + })) as Address +} diff --git a/src/zksync/utils/bridge/l2TokenAddress.test.ts b/src/zksync/utils/bridge/l2TokenAddress.test.ts new file mode 100644 index 0000000000..5fa0a181dd --- /dev/null +++ b/src/zksync/utils/bridge/l2TokenAddress.test.ts @@ -0,0 +1,30 @@ +import type { Address } from 'abitype' +import { afterAll, expect, test, vi } from 'vitest' +import { + mockAddress, + mockAddresses, + mockClientPublicActionsL2, + zkSyncClientLocalNodeWithAccountL1, +} from '../../../../test/src/zksync.js' +import * as readContract from '../../../actions/public/readContract.js' +import { l2TokenAddress } from './l2TokenAddress.js' + +const clientL1 = { ...zkSyncClientLocalNodeWithAccountL1 } + +mockClientPublicActionsL2(clientL1) + +const spy = vi + .spyOn(readContract, 'readContract') + .mockResolvedValue(mockAddress) + +afterAll(() => { + spy.mockRestore() +}) + +test('default', async () => { + const address = await l2TokenAddress(clientL1, { + token: mockAddress, + sharedL2: mockAddresses.l1SharedDefaultBridge as Address, + }) + expect(address).toEqual(mockAddress) +}) diff --git a/src/zksync/utils/bridge/l2TokenAddress.ts b/src/zksync/utils/bridge/l2TokenAddress.ts new file mode 100644 index 0000000000..9971bffbba --- /dev/null +++ b/src/zksync/utils/bridge/l2TokenAddress.ts @@ -0,0 +1,29 @@ +import type { Address } from 'abitype' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { l2BridgeAbi } from '../../constants/abis.js' + +export type GetL2TokenAddressParameters = { + token: Address + sharedL2: Address +} + +export type GetL2TokenAddressReturnType = Address + +export async function l2TokenAddress< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + clientL2: Client, + parameters: GetL2TokenAddressParameters, +): Promise { + return (await readContract(clientL2, { + abi: l2BridgeAbi, + functionName: 'l2TokenAddress', + address: parameters.sharedL2, + args: [parameters.token], + })) as Address +} diff --git a/src/zksync/utils/bridge/requestL2TransactionDirect.test.ts b/src/zksync/utils/bridge/requestL2TransactionDirect.test.ts new file mode 100644 index 0000000000..ad826b03f8 --- /dev/null +++ b/src/zksync/utils/bridge/requestL2TransactionDirect.test.ts @@ -0,0 +1,75 @@ +import { afterAll, expect, test, vi } from 'vitest' + +import { accounts } from '~test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' + +import { parseUnits } from 'ethers' +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { bridgehubAbi } from '../../constants/abis.js' +import { requiredL2GasPricePerPubdata } from '../../constants/number.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { + type L2TransactionRequestDirectParameters, + requestL2TransactionDirect, +} from './requestL2TransactionDirect.js' + +const sourceAccount = accounts[0] +const account = privateKeyToAccount(sourceAccount.privateKey) +const mockedResolvedValue = + '0x5254a0e1d200d0900920b9bc810caf2d26814426db0719da05a1b14bc3e4032d' +const spy = vi + .spyOn(readContract, 'readContract') + .mockResolvedValue(mockedResolvedValue) + +afterAll(() => { + spy.mockRestore() +}) + +test('default with account hoisting and token', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + const accountAddress = account.address + + const parameters: L2TransactionRequestDirectParameters = { + bridgehubContractAddress: '0x8E5937cE49C72264a2318163Aa96F9F973A83192', + mintValue: parseUnits('800', 18), + l2Contract: accountAddress, + l2Value: 1n, + l2Calldata: '0x', + l2GasLimit: 10000000n, + l2GasPerPubdataByteLimit: BigInt(requiredL2GasPricePerPubdata), + factoryDeps: [], + refundRecipient: accountAddress, + l2ChainId: BigInt(client.chain.id), + } + + expect(await requestL2TransactionDirect(client, parameters)).toBe( + mockedResolvedValue, + ) + + expect(spy).toHaveBeenCalledWith(client, { + abi: bridgehubAbi, + address: parameters.bridgehubContractAddress, + functionName: 'requestL2TransactionDirect', + args: [ + { + chainId: BigInt(client.chain.id), + factoryDeps: parameters.factoryDeps, + l2Calldata: parameters.l2Calldata, + l2Contract: parameters.l2Contract, + l2GasLimit: parameters.l2GasLimit, + l2GasPerPubdataByteLimit: parameters.l2GasPerPubdataByteLimit, + l2Value: parameters.l2Value, + mintValue: parameters.mintValue, + refundRecipient: parameters.refundRecipient, + }, + ], + }) +}) diff --git a/src/zksync/utils/bridge/requestL2TransactionDirect.ts b/src/zksync/utils/bridge/requestL2TransactionDirect.ts new file mode 100644 index 0000000000..574f5f62dd --- /dev/null +++ b/src/zksync/utils/bridge/requestL2TransactionDirect.ts @@ -0,0 +1,48 @@ +import type { Address } from 'abitype' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import type { Hash, Hex } from '../../../types/misc.js' +import { bridgehubAbi } from '../../constants/abis.js' + +export type L2TransactionRequestDirectParameters = { + mintValue: bigint + l2Contract: Address + l2Value: bigint + l2Calldata: Hex + l2GasLimit: bigint + l2GasPerPubdataByteLimit: bigint + factoryDeps: Hex[] + refundRecipient: Address + bridgehubContractAddress: Address + l2ChainId: bigint +} + +export async function requestL2TransactionDirect< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: L2TransactionRequestDirectParameters, +): Promise { + return (await readContract(client, { + abi: bridgehubAbi, + functionName: 'requestL2TransactionDirect', + address: parameters.bridgehubContractAddress, + args: [ + { + chainId: parameters.l2ChainId, + mintValue: parameters.mintValue, + l2Contract: parameters.l2Contract, + l2Value: parameters.l2Value, + l2Calldata: parameters.l2Calldata, + l2GasLimit: parameters.l2GasLimit, + l2GasPerPubdataByteLimit: parameters.l2GasPerPubdataByteLimit, + factoryDeps: parameters.factoryDeps, + refundRecipient: parameters.refundRecipient, + }, + ], + })) as Hash +} diff --git a/src/zksync/utils/bridge/requestL2TransactionTwoBridges.test.ts b/src/zksync/utils/bridge/requestL2TransactionTwoBridges.test.ts new file mode 100644 index 0000000000..b66f3e54bb --- /dev/null +++ b/src/zksync/utils/bridge/requestL2TransactionTwoBridges.test.ts @@ -0,0 +1,75 @@ +import { afterAll, expect, test, vi } from 'vitest' + +import { accounts } from '~test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' + +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { parseUnits } from '../../../utils/index.js' +import { bridgehubAbi } from '../../constants/abis.js' +import { requiredL2GasPricePerPubdata } from '../../constants/number.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { + type L2TransactionRequestTwoBridgesParameters, + requestL2TransactionTwoBridges, +} from './requestL2TransactionTwoBridges.js' + +const sourceAccount = accounts[0] +const account = privateKeyToAccount(sourceAccount.privateKey) +const mockedResolvedValue = + '0x5254a0e1d200d0900920b9bc810caf2d26814426db0719da05a1b14bc3e4032d' +const spy = vi + .spyOn(readContract, 'readContract') + .mockResolvedValue(mockedResolvedValue) + +afterAll(() => { + spy.mockRestore() +}) + +test('default with account hoisting and token', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + account, + }).extend(publicActionsL1()) + + const accountAddress = account.address + + const parameters: L2TransactionRequestTwoBridgesParameters = { + bridgehubContractAddress: '0x8E5937cE49C72264a2318163Aa96F9F973A83192', + mintValue: parseUnits('800', 18), + l2Value: 1n, + l2GasLimit: 10000000n, + l2GasPerPubdataByteLimit: BigInt(requiredL2GasPricePerPubdata), + refundRecipient: accountAddress, + secondBridgeAddress: accountAddress, + secondBridgeValue: 0n, + secondBridgeCalldata: '0x', + l2ChainId: BigInt(client.chain.id), + } + + expect(await requestL2TransactionTwoBridges(client, parameters)).toBe( + mockedResolvedValue, + ) + + expect(spy).toHaveBeenCalledWith(client, { + abi: bridgehubAbi, + address: parameters.bridgehubContractAddress, + functionName: 'requestL2TransactionTwoBridges', + args: [ + { + chainId: BigInt(client.chain.id), + l2GasLimit: parameters.l2GasLimit, + l2GasPerPubdataByteLimit: parameters.l2GasPerPubdataByteLimit, + l2Value: parameters.l2Value, + mintValue: parameters.mintValue, + refundRecipient: parameters.refundRecipient, + secondBridgeAddress: accountAddress, + secondBridgeValue: 0n, + secondBridgeCalldata: '0x', + }, + ], + }) +}) diff --git a/src/zksync/utils/bridge/requestL2TransactionTwoBridges.ts b/src/zksync/utils/bridge/requestL2TransactionTwoBridges.ts new file mode 100644 index 0000000000..de01190a8b --- /dev/null +++ b/src/zksync/utils/bridge/requestL2TransactionTwoBridges.ts @@ -0,0 +1,48 @@ +import type { Address } from 'abitype' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import type { Hash, Hex } from '../../../types/misc.js' +import { bridgehubAbi } from '../../constants/abis.js' + +export type L2TransactionRequestTwoBridgesParameters = { + mintValue: bigint + l2Value: bigint + l2GasLimit: bigint + l2GasPerPubdataByteLimit: bigint + refundRecipient: Address + secondBridgeAddress: Address + secondBridgeValue: bigint + secondBridgeCalldata: Hex + bridgehubContractAddress: Address + l2ChainId: bigint +} + +export async function requestL2TransactionTwoBridges< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: L2TransactionRequestTwoBridgesParameters, +): Promise { + return (await readContract(client, { + abi: bridgehubAbi, + functionName: 'requestL2TransactionTwoBridges', + address: parameters.bridgehubContractAddress, + args: [ + { + chainId: parameters.l2ChainId, + mintValue: parameters.mintValue, + l2Value: parameters.l2Value, + l2GasLimit: parameters.l2GasLimit, + l2GasPerPubdataByteLimit: parameters.l2GasPerPubdataByteLimit, + refundRecipient: parameters.refundRecipient, + secondBridgeAddress: parameters.secondBridgeAddress, + secondBridgeValue: parameters.secondBridgeValue, + secondBridgeCalldata: parameters.secondBridgeCalldata, + }, + ], + })) as Hash +} diff --git a/src/zksync/utils/bridge/sendRawTransactionWithDetailedOutput.test.ts b/src/zksync/utils/bridge/sendRawTransactionWithDetailedOutput.test.ts new file mode 100644 index 0000000000..e716c23285 --- /dev/null +++ b/src/zksync/utils/bridge/sendRawTransactionWithDetailedOutput.test.ts @@ -0,0 +1,31 @@ +import { expect, test } from 'vitest' +import { mockClientPublicActionsL2 } from '../../../../test/src/zksync.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' +import { signTransaction } from '../../../actions/index.js' +import { zkLocalChainL2 } from '../../../chains/definitions/zkLocalChainL2.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { sendRawTransactionWithDetailedOutput } from './sendRawTransactionWithDetailedOutput.js' + +const account = privateKeyToAccount( + '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110', +) + +const clientL2 = createClient({ + chain: zkLocalChainL2, + transport: http(), + account, +}) + +mockClientPublicActionsL2(clientL2) + +test('default', async () => { + const output = await sendRawTransactionWithDetailedOutput(clientL2, { + serializedTransaction: await signTransaction(clientL2, { + to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', + value: 1n, + maxFeePerGas: 15000000n, + }), + }) + expect(output).toBeDefined() +}) diff --git a/src/zksync/utils/bridge/sendRawTransactionWithDetailedOutput.ts b/src/zksync/utils/bridge/sendRawTransactionWithDetailedOutput.ts new file mode 100644 index 0000000000..b01bf6ae98 --- /dev/null +++ b/src/zksync/utils/bridge/sendRawTransactionWithDetailedOutput.ts @@ -0,0 +1,28 @@ +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import type { Hex } from '../../../types/misc.js' +import type { PublicZkSyncRpcSchema } from '../../types/eip1193.js' +import type { TransactionWithDetailedOutput } from '../../types/transaction.js' + +export type SendRawTransactionWithDetailedOutputParameters = { + serializedTransaction: Hex +} + +export type SendRawTransactionWithDetailedReturnType = + TransactionWithDetailedOutput + +export async function sendRawTransactionWithDetailedOutput< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: SendRawTransactionWithDetailedOutputParameters, +): Promise { + const tokens = await client.request({ + method: 'zks_sendRawTransactionWithDetailedOutput', + params: [parameters.serializedTransaction], + }) + return tokens +} diff --git a/src/zksync/utils/bridge/sharedBridge.test.ts b/src/zksync/utils/bridge/sharedBridge.test.ts new file mode 100644 index 0000000000..a3b39e1216 --- /dev/null +++ b/src/zksync/utils/bridge/sharedBridge.test.ts @@ -0,0 +1,36 @@ +import { afterAll, expect, test, vi } from 'vitest' +import * as readContract from '../../../actions/public/readContract.js' +import { sepolia } from '../../../chains/index.js' +import { createClient } from '../../../clients/createClient.js' +import { http } from '../../../clients/transports/http.js' +import { bridgehubAbi } from '../../constants/abis.js' +import { publicActionsL1 } from '../../decorators/publicL1.js' +import { sharedBridge } from './sharedBridge.js' + +const spy = vi + .spyOn(readContract, 'readContract') + .mockResolvedValue('0xA5b795d453CA0FBD599EC28Dd88d020E06048619') + +afterAll(() => { + spy.mockRestore() +}) + +test('default', async () => { + const client = createClient({ + chain: sepolia, + transport: http(), + }).extend(publicActionsL1()) + + expect( + await sharedBridge(client, { + bridgehubContractAddress: '0x8E5937cE49C72264a2318163Aa96F9F973A83192', + }), + ).toBe('0xA5b795d453CA0FBD599EC28Dd88d020E06048619') + + expect(spy).toHaveBeenCalledWith(client, { + abi: bridgehubAbi, + address: '0x8E5937cE49C72264a2318163Aa96F9F973A83192', + args: [], + functionName: 'sharedBridge', + }) +}) diff --git a/src/zksync/utils/bridge/sharedBridge.ts b/src/zksync/utils/bridge/sharedBridge.ts new file mode 100644 index 0000000000..c503a41d0d --- /dev/null +++ b/src/zksync/utils/bridge/sharedBridge.ts @@ -0,0 +1,26 @@ +import type { Address } from 'abitype' +import { readContract } from '../../../actions/index.js' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { bridgehubAbi } from '../../constants/abis.js' + +export type SharedBridgeParameters = { + bridgehubContractAddress: Address +} + +export async function sharedBridge< + TChain extends Chain | undefined, + TAccount extends Account | undefined, +>( + client: Client, + parameters: SharedBridgeParameters, +): Promise
{ + return (await readContract(client, { + abi: bridgehubAbi, + functionName: 'sharedBridge', + args: [], + address: parameters.bridgehubContractAddress, + })) as Address +} diff --git a/test/src/zksync.ts b/test/src/zksync.ts index 54f5220a8d..d3675323a3 100644 --- a/test/src/zksync.ts +++ b/test/src/zksync.ts @@ -1,3 +1,4 @@ +import { zkSyncLocalNodeL1 } from '~viem/chains/definitions/zkSyncLocalNodeL1.js' import { zksyncLocalNode } from '~viem/chains/index.js' import { createClient } from '~viem/clients/createClient.js' import { http } from '~viem/index.js' @@ -14,6 +15,12 @@ export const zksyncClientLocalNodeWithAccount = createClient({ transport: http(), }) +export const zkSyncClientLocalNodeWithAccountL1 = createClient({ + account: accounts[0].address, + chain: zkSyncLocalNodeL1, + transport: http(), +}) + export function getZksyncMockProvider( request: ({ method, diff --git a/test/src/zksyncPublicActionsL2MockData.ts b/test/src/zksyncPublicActionsL2MockData.ts new file mode 100644 index 0000000000..8170567f55 --- /dev/null +++ b/test/src/zksyncPublicActionsL2MockData.ts @@ -0,0 +1,546 @@ +import type { Address } from 'abitype' +import type { FeeValues, TransactionReceipt } from '~viem/index.js' +import type { + CreateWithdrawSpecificationReturnType, + ZkSyncTransactionDetails, +} from '~viem/zksync/index.js' +import type { + ZkSyncBatchDetails, + ZkSyncBlockDetails, +} from '~viem/zksync/types/block.js' +import type { MessageProof } from '~viem/zksync/types/proof.js' +import type { GetL1BatchBlockRangeReturnParameters } from '../../src/zksync/actions/getL1BatchBlockRange.js' +import type { RawBlockTransactions } from '../../src/zksync/actions/getRawBlockTransaction.js' +import { mockFeeValues } from './zksync.js' + +export const mockedL1BatchNumber = '0x2012' + +export const mockAccountBalances = { + '0x0000000000000000000000000000000000000000': '1000000000000000000', + '0x0000000000000000000000000000000000000001': '2000000000000000000', + '0x0000000000000000000000000000000000000002': '3500000000000000000', +} + +export const mockWithdrawSpecification: CreateWithdrawSpecificationReturnType = + { + amount: 1n, + baseTokenAddress: '0x0000000000000000000000000000000000000000', + bridgeAddresses: { + erc20L1: '0xbe270c78209cfda84310230aaa82e18936310b2e', + sharedL1: '0x648afeaf09a3db988ac41b786001235bbdbc7640', + sharedL2: '0xfd61c893b903fa133908ce83dfef67c4c2350dd8', + }, + from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', + isBaseToken: false, + isEthBasedChain: false, + token: '0x0000000000000000000000000000000000000001', + } + +export const mockBaseTokenL1Address: Address = + '0x0000000000000000000000000000000000000000' + +export const mockBlockDetails: ZkSyncBlockDetails = { + number: 0, + timestamp: 1713435780, + l1BatchNumber: 0, + l1TxCount: 2, + l2TxCount: 3, + status: 'verified', + baseSystemContractsHashes: { + bootloader: + '0x010008bb22aea1e22373cb8d807b15c67eedd65523e9cba4cc556adfa504f7b8', + default_aa: + '0x010008bb22aea1e22373cb8d807b15c67eedd65523e9cba4cc556adfa504f7b8', + }, + operatorAddress: '0xde03a0b5963f75f1c8485b355ff6d30f3093bde7', + protocolVersion: 'Version19', +} + +export const mockAddress: Address = '0x173999892363ba18c9dc60f8c57152fc914bce89' + +export const mockAddresses = { + l1SharedDefaultBridge: '0x648afeaf09a3db988ac41b786001235bbdbc7640', + l2SharedDefaultBridge: '0xfd61c893b903fa133908ce83dfef67c4c2350dd8', + l1Erc20DefaultBridge: '0xbe270c78209cfda84310230aaa82e18936310b2e', + l2Erc20DefaultBridge: '0xfc073319977e314f251eae6ae6be76b0b3baeecf', + l1WethBridge: '0x5e6d086f5ec079adff4fb3774cdf3e8d6a34f7e9', + l2WethBridge: '0x5e6d086f5ec079adff4fb3774cdf3e8d6a34f7e9', +} + +export const mockRange: GetL1BatchBlockRangeReturnParameters = [0, 5] + +export const mockL1TxReceipt: TransactionReceipt = { + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + cumulativeGasUsed: 270252n, + gasUsed: 270252n, + effectiveGasPrice: 1500000001n, + from: '0x36615cf349d7f6344891b1e7ca7c72883f5dc049', + to: '0x6ee1e6a16d5c93de0cc8ce803682082440f7c568', + contractAddress: null, + logs: [ + { + topics: [ + '0x249bc8a55d0c4a0034b9aaa6be739bec2d4466e5d859bec9566a8553c405c838', + '0x000000000000000000000000000000000000000000000000000000000000010e', + '0x00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc049', + ], + address: '0xdbedff7f37db0e03a77330b191a9873ca9ab2ddb', + data: '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000ae3c1ca171c0', + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + logIndex: 0, + removed: false, + }, + { + topics: [ + '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925', + '0x00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc049', + '0x000000000000000000000000dbedff7f37db0e03a77330b191a9873ca9ab2ddb', + ], + address: '0x70a0f165d6f8054d0d0cf8dfd4dd2005f0af6b55', + data: '0x0000000000000000000000000000000000000000000000000000000000000000', + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + logIndex: 1, + removed: false, + }, + { + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc049', + '0x000000000000000000000000dbedff7f37db0e03a77330b191a9873ca9ab2ddb', + ], + address: '0x70a0f165d6f8054d0d0cf8dfd4dd2005f0af6b55', + data: '0x0000000000000000000000000000000000000000000000000000000000000005', + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + logIndex: 2, + removed: false, + }, + { + topics: [ + '0x8768405a01370685449c74c293804d6c9cc216d170acdbdba50b33ed4144447f', + '0x000000000000000000000000000000000000000000000000000000000000010e', + '0x2fbe05f2f4ebbb3302086c04c246c103b8084282ce6fc1d47fa7cffdeced76ec', + '0x00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc049', + ], + address: '0xdbedff7f37db0e03a77330b191a9873ca9ab2ddb', + data: '0x00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000070a0f165d6f8054d0d0cf8dfd4dd2005f0af6b550000000000000000000000000000000000000000000000000000000000000005', + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + logIndex: 3, + removed: false, + }, + { + topics: [ + '0x4531cd5795773d7101c17bdeb9f5ab7f47d7056017506f937083be5d6e77a382', + ], + address: '0x38969c7b1a39893c176d37bd9b61225d62b7e851', + data: '0x00000000000000000000000000000000000000000000000000000000000000141414b49119ba22f4df715d78a22e8aa94f9d4fefe694fd19a43ca90bc69c6187000000000000000000000000000000000000000000000000000000006650e13700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000000ff000000000000000000000000ecfeff7f37db0e03a77330b191a9873ca9ab3eec000000000000000000000000b0f696622f7415b0415970ecd184bedd39ce50cc00000000000000000000000000000000000000000000000000000000000627700000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000001004ccb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae3c1ca171c000000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000054000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000264cfe7af7c00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000070a0f165d6f8054d0d0cf8dfd4dd2005f0af6b55000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000344414900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034441490000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + logIndex: 4, + removed: false, + }, + { + topics: [ + '0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df', + '0x000000000000000000000000000000000000000000000000000000000000010e', + '0x2fbe05f2f4ebbb3302086c04c246c103b8084282ce6fc1d47fa7cffdeced76ec', + '0x7247734d64e672d477960855e6ffe36e95c967565dc14de07c3085ad5f596f85', + ], + address: '0xdbedff7f37db0e03a77330b191a9873ca9ab2ddb', + data: '0x', + blockHash: + '0x871ad780b836badec33d32c63a367b773ee2a0ed1efcf61c2ecf46bcf6f8b2b7', + blockNumber: 4948n, + transactionHash: + '0x22b242bb10a49333e5a1a18cca1128718a56e412cad7441eb3d1b658902b2926', + transactionIndex: 0, + logIndex: 5, + removed: false, + }, + ], + logsBloom: + '0x00000004800000000000000000000020000000000000010000000000000000000000000000000000001000100001000080000000082000080000000000200000000000020000000440000088000000000000000000000000000000080000200000200004000000000400000110000000000800000000000000040010000000000000000000000000000000000200000000000000100000000004000000000000020000000000000000000000000000000040000000000000000020000000000000000002000000000000000000000000000000000000000000000000000100000110000000000000000010000000000080020010000000000000000040000000', + status: 'success', + type: 'eip1559', +} + +export const mockDetails: ZkSyncBatchDetails = { + number: 0, + timestamp: 0, + l1TxCount: 0, + l2TxCount: 0, + l1BatchNumber: 0, + status: 'verified', + l1GasPrice: 0, + l2FairGasPrice: 0, + baseSystemContractsHashes: { + bootloader: + '0x010008bb22aea1e22373cb8d807b15c67eedd65523e9cba4cc556adfa504f7b8', + default_aa: + '0x01000563a7f32f1d97b4697f3bc996132433314b9b17351a7f7cd6073f618569', + }, +} + +export const mockChainId = '0x9' + +export const mockProofValues: MessageProof = { + id: 112, + proof: [ + '0x3d999d6a5bacdc5c8c01ad0917c1dca03c632fc486ac623a8857804374b0d1b1', + '0xc3d03eebfd83049991ea3d3e358b6712e7aa2e2e63dc2d4b438987cec28ac8d0', + '0xe3697c7f33c31a9b0f0aeb8542287d0d21e8c4cf82163d0c44c7a98aa11aa111', + '0x199cc5812543ddceeddd0fc82807646a4899444240db2c0d2f20c3cceb5f51fa', + '0xe4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db89', + '0x1798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef2272', + '0x66d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770d', + '0xb04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396c', + '0xac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db', + '0x124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470f', + '0xc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13f', + ], + root: '0x443ddd5b010069db588a5f21e9145f94a93dd8109c72cc70d79281f1c19db2c8', +} + +export const mockL2Tx = { + hash: '0x822ab5fa87c51c7c19744098820ad3851aeeb48a36912fd59a4098e561b9ad29', + nonce: 0, + blockHash: + '0xfd17f1b4ab9411eb4078de799b03b6d60d10979bb25c0082fc88b3c05054f123', + blockNumber: 24n, + transactionIndex: 0, + from: '0xecfeff7f37db0e03a77330b191a9873ca9ab3eec', + to: '0xb0f696622f7415b0415970ecd184bedd39ce50cc', + value: 0n, + gasPrice: 268750000n, + gas: 403312n, + input: + '0xcfe7af7c00000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000036615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000070a0f165d6f8054d0d0cf8dfd4dd2005f0af6b55000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034441490000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003444149000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012', + type: 'priority', + maxFeePerGas: 268750000n, + maxPriorityFeePerGas: 0n, + chainId: 270, + maxFeePerBlobGas: undefined, + typeHex: '0xff', + v: undefined, + yParity: undefined, + l1BatchNumber: null, + l1BatchTxIndex: null, +} + +export const mockMainContractAddress = + '0x38969c7b1a39893c176d37bd9b61225d62b7e851' + +export const mockRawBlockTransaction: RawBlockTransactions = [ + { + common_data: { + L1: { + sender: '0xde03a0b5963f75f1c8485b355ff6d30f3093bde7', + serialId: 0, + deadlineBlock: 0, + layer2TipFee: '0x0', + fullFee: '0x0', + maxFeePerGas: '0x1dcd6500', + gasLimit: '0x44aa200', + gasPerPubdataLimit: '0x320', + opProcessingType: 'Common', + priorityQueueType: 'Deque', + ethHash: + '0x0000000000000000000000000000000000000000000000000000000000000000', + ethBlock: 125, + canonicalTxHash: + '0x9376f805ccd40186a73672a4d0db064060956e70c4ae486ab205291986439343', + toMint: '0x7fe5cf2bea0000', + refundRecipient: '0xde03a0b5963f75f1c8485b355ff6d30f3093bde7', + }, + L2: { + nonce: 0, + fee: { + gas_limit: '0x2803d', + gas_per_pubdata_limit: '0x42', + max_fee_per_gas: '0xee6b280', + max_priority_fee_per_gas: '0x0', + }, + initiatorAddress: '0x000000000000000000000000000000000000800b', + signature: new Uint8Array(), + transactionType: 'ProtocolUpgrade', + input: { + hash: '0x', + data: new Uint8Array(), + }, + paymasterParams: { + paymaster: '0x0a67078A35745947A37A552174aFe724D8180c25', + paymasterInput: new Uint8Array(), + }, + }, + }, + execute: { + calldata: + '0xef0e2ff4000000000000000000000000000000000000000000000000000000000000010e', + contractAddress: '0x000000000000000000000000000000000000800b', + factoryDeps: '0x', + value: BigInt(0), + }, + received_timestamp_ms: 1713436617435, + raw_bytes: '', + }, +] + +export const mockTestnetPaymasterAddress = + '0x0a67078A35745947A37A552174aFe724D8180c25' + +export const mockTransactionDetails: ZkSyncTransactionDetails = { + isL1Originated: true, + status: 'validated', + fee: 10n, + gasPerPubdata: 50000n, + initiatorAddress: '0x000000000000000000000000000000000000800b', + receivedAt: new Date(1713436617435), +} + +export const mockedGasEstimation = 123456789n +export const mockTransactionReceipt = { + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchTxIndex: 0n, + l1BatchNumber: 4n, + from: '0x36615cf349d7f6344891b1e7ca7c72883f5dc049', + to: '0x000000000000000000000000000000000000800a', + cumulativeGasUsed: 0n, + gasUsed: 220407n, + contractAddress: null, + logs: [ + { + address: '0x000000000000000000000000000000000000800a', + topics: [Array], + data: '0x00000000000000000000000000000000000000000000000000001cad2d9a3200', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 0, + transactionLogIndex: 0, + logType: null, + removed: false, + }, + { + address: '0x000000000000000000000000000000000000800a', + topics: [Array], + data: '0x000000000000000000000000000000000000000000000000000004c78799b300', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 1, + transactionLogIndex: 1, + logType: null, + removed: false, + }, + { + address: '0x000000000000000000000000000000000000800a', + topics: [Array], + data: '0x0000000000000000000000000000000000000000000000000000000000000001', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 2, + transactionLogIndex: 2, + logType: null, + removed: false, + }, + { + address: '0x0000000000000000000000000000000000008008', + topics: [Array], + data: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008008000000000000000000000000000000000000000000000000000000000000800a45dd73c9e5194b7eb37037beda4171fe761e85d4149a083acd48061ef1ea14ae', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 3, + transactionLogIndex: 3, + logType: null, + removed: false, + }, + { + address: '0x0000000000000000000000000000000000008008', + topics: [Array], + data: '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000386c0960f936615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000000000000000000000000000000000000000000010000000000000000', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 4, + transactionLogIndex: 4, + logType: null, + removed: false, + }, + { + address: '0x000000000000000000000000000000000000800a', + topics: [Array], + data: '0x0000000000000000000000000000000000000000000000000000000000000001', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 5, + transactionLogIndex: 5, + logType: null, + removed: false, + }, + { + address: '0x000000000000000000000000000000000000800a', + topics: [Array], + data: '0x000000000000000000000000000000000000000000000000000003d9e5e86800', + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + blockNumber: 7n, + l1BatchNumber: 4n, + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + transactionIndex: 0, + logIndex: 6, + transactionLogIndex: 6, + logType: null, + removed: false, + }, + ], + l2ToL1Logs: [ + { + blockNumber: + 78796022661380546701551694676929027283217048048233045390905312619491818049270n, + blockHash: + '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + l1BatchNumber: 4n, + transactionIndex: 0n, + shardId: 0n, + isService: true, + sender: '0x0000000000000000000000000000000000008008', + key: '0x000000000000000000000000000000000000000000000000000000000000800a', + value: + '0x45dd73c9e5194b7eb37037beda4171fe761e85d4149a083acd48061ef1ea14ae', + transactionHash: + '0xd6f3a9ddeb34ed805b1d04c75e95651cc8ebe4ce7d6f8d1e86191417fe578bae', + logIndex: 0n, + }, + ], + status: 'success', + root: '0xae34f7e70d90342688299d2db834c28863ddfd27e66f01be4c5dcd61dcf18ef6', + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + type: 'eip1559', + effectiveGasPrice: 100000000n, +} + +export const mockBlock = { + hash: '0xd2c6b75ab85605c61ca2de0cd7c670a53a6ccea6cf18e69701762d0c82754a10', + parentHash: + '0xe09bea35398b1fe0ba6bec1533ed3406e3c014c4f5a6a095475caa0a6a3e17bc', + sha3Uncles: + '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + miner: '0x0000000000000000000000000000000000000000', + stateRoot: + '0x0000000000000000000000000000000000000000000000000000000000000000', + transactionsRoot: + '0x0000000000000000000000000000000000000000000000000000000000000000', + receiptsRoot: + '0x0000000000000000000000000000000000000000000000000000000000000000', + number: 14n, + l1BatchNumber: 7n, + gasUsed: 0n, + gasLimit: 1125899906842624n, + baseFeePerGas: 100000000n, + extraData: '0x', + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + timestamp: 1717510530n, + l1BatchTimestamp: 1717510529n, + difficulty: 0n, + totalDifficulty: 0n, + sealFields: [], + uncles: [], + transactions: [], + size: 0n, + mixHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + nonce: '0x0000000000000000', + blobGasUsed: undefined, + excessBlobGas: undefined, +} +export const mockRequestReturnData = async (method: string) => { + if (method === 'eth_getTransactionReceipt') return mockTransactionReceipt + if (method === 'eth_getBlockByHash') return mockBlock + if (method === 'eth_getBlockByNumber') return mockBlock + if (method === 'zks_L1ChainId') return mockChainId + if (method === 'zks_estimateFee') return mockFeeValues + if (method === 'zks_getAllAccountBalances') return mockAccountBalances + if (method === 'zks_getBaseTokenL1Address') return mockBaseTokenL1Address + if (method === 'zks_getBlockDetails') return mockBlockDetails + if (method === 'zks_getBridgehubContract') return mockAddress + if (method === 'zks_getBridgeContracts') return mockAddresses + if (method === 'zks_getL1BatchBlockRange') return mockRange + if (method === 'zks_getL1BatchDetails') return mockDetails + if (method === 'zks_getL2ToL1LogProof') return mockProofValues + if (method === 'zks_getMainContract') return mockMainContractAddress + if (method === 'zks_getRawBlockTransactions') return mockRawBlockTransaction + if (method === 'zks_getTestnetPaymaster') return mockTestnetPaymasterAddress + if (method === 'zks_getTransactionDetails') return mockTransactionDetails + if (method === 'zks_L1BatchNumber') return mockedL1BatchNumber + if (method === 'zks_estimateGasL1ToL2') return mockedGasEstimation + if (method === 'eth_gasPrice') return 1n + return undefined +} + +export function mockClientPublicActionsL2(client) { + client.request = async ({ method }) => { + return mockRequestReturnData(method) + } +}