diff --git a/typescript/infra/scripts/funding/fund-keys-from-deployer.ts b/typescript/infra/scripts/funding/fund-keys-from-deployer.ts index d3ad82da0e..06185ea1fd 100644 --- a/typescript/infra/scripts/funding/fund-keys-from-deployer.ts +++ b/typescript/infra/scripts/funding/fund-keys-from-deployer.ts @@ -12,7 +12,7 @@ import { MultiProvider, RpcConsensusType, } from '@hyperlane-xyz/sdk'; -import { error, log, warn } from '@hyperlane-xyz/utils'; +import { Address, error, log, warn } from '@hyperlane-xyz/utils'; import { Contexts } from '../../config/contexts'; import { parseKeyIdentifier } from '../../src/agents/agent'; @@ -33,6 +33,21 @@ import { } from '../../src/utils/utils'; import { getAgentConfig, getArgs, getEnvironmentConfig } from '../utils'; +import * as L1ETHGateway from './utils/L1ETHGateway.json'; +import * as L1MessageQueue from './utils/L1MessageQueue.json'; +import * as L1ScrollMessenger from './utils/L1ScrollMessenger.json'; +import * as PolygonZkEVMBridge from './utils/PolygonZkEVMBridge.json'; + +const nativeBridges = { + scrollsepolia: { + l1ETHGateway: '0x8A54A2347Da2562917304141ab67324615e9866d', + l1Messenger: '0x50c7d3e7f7c656493D1D76aaa1a836CedfCBB16A', + }, + polygonzkevmtestnet: { + l1EVMBridge: '0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7', + }, +}; + type L2Chain = | Chains.optimism | Chains.optimismgoerli @@ -49,6 +64,7 @@ const L2Chains: ChainName[] = [ Chains.arbitrumgoerli, Chains.scrollsepolia, Chains.basegoerli, + Chains.polygonzkevmtestnet, ]; const L2ToL1: ChainMap = { @@ -58,7 +74,7 @@ const L2ToL1: ChainMap = { arbitrum: 'ethereum', scrollsepolia: 'sepolia', basegoerli: 'goerli', - polygonzktestnet: 'goerli', + polygonzkevmtestnet: 'goerli', }; // Missing types declaration for bufio @@ -118,7 +134,7 @@ const desiredBalancePerChain: ChainMap = { gnosis: '0.1', basegoerli: '0.05', scrollsepolia: '0.05', - polygonzkevmtestnet: '0.01', + polygonzkevmtestnet: '0.3', // unused test1: '0', @@ -626,10 +642,14 @@ class ContextFunder { ), }); let tx; - if (l2Chain.includes('optimism')) { + if (l2Chain.includes('optimism') || l2Chain.includes('base')) { tx = await this.bridgeToOptimism(l2Chain, amount, to); } else if (l2Chain.includes('arbitrum')) { tx = await this.bridgeToArbitrum(l2Chain, amount); + } else if (l2Chain.includes('scroll')) { + tx = await this.bridgeToScroll(l2Chain, amount, to); + } else if (l2Chain.includes('zkevm')) { + tx = await this.bridgeToPolygonCDK(l2Chain, amount, to); } else { throw new Error(`${l2Chain} is not an L2`); } @@ -667,6 +687,69 @@ class ContextFunder { }); } + private async bridgeToScroll( + l2Chain: L2Chain, + amount: BigNumber, + to: Address, + ) { + const l1Chain = L2ToL1[l2Chain]; + const l1ChainSigner = this.multiProvider.getSigner(l1Chain); + const l1EthGateway = new ethers.Contract( + nativeBridges.scrollsepolia.l1ETHGateway, + L1ETHGateway.abi, + l1ChainSigner, + ); + const l1ScrollMessenger = new ethers.Contract( + nativeBridges.scrollsepolia.l1Messenger, + L1ScrollMessenger.abi, + l1ChainSigner, + ); + const l2GasLimit = BigNumber.from('200000'); // l2 gas amount for the transfer and an empty callback calls + const l1MessageQueueAddress = await l1ScrollMessenger.messageQueue(); + const l1MessageQueue = new ethers.Contract( + l1MessageQueueAddress, + L1MessageQueue.abi, + l1ChainSigner, + ); + const gasQuote = await l1MessageQueue.estimateCrossDomainMessageFee( + l2GasLimit, + ); + const totalAmount = amount.add(gasQuote); + return l1EthGateway['depositETH(address,uint256,uint256)']( + to, + amount, + l2GasLimit, + { + value: totalAmount, + }, + ); + } + + private async bridgeToPolygonCDK( + l2Chain: L2Chain, + amount: BigNumber, + to: Address, + ) { + const l1Chain = L2ToL1[l2Chain]; + const l1ChainSigner = this.multiProvider.getSigner(l1Chain); + const polygonZkEVMbridge = new ethers.Contract( + nativeBridges.polygonzkevmtestnet.l1EVMBridge, + PolygonZkEVMBridge.abi, + l1ChainSigner, + ); + return polygonZkEVMbridge.bridgeAsset( + 1, // 0 is mainnet, 1 is l2 + to, + amount, + ethers.constants.AddressZero, + true, + [], + { + value: amount, + }, + ); + } + private async updateWalletBalanceGauge(chain: ChainName) { const funderAddress = await this.multiProvider.getSignerAddress(chain); walletBalanceGauge diff --git a/typescript/infra/scripts/funding/utils/L1ETHGateway.json b/typescript/infra/scripts/funding/utils/L1ETHGateway.json new file mode 100644 index 0000000000..1622a94581 --- /dev/null +++ b/typescript/infra/scripts/funding/utils/L1ETHGateway.json @@ -0,0 +1,45 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_gasLimit", + "type": "uint256" + } + ], + "name": "depositETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_gasLimit", + "type": "uint256" + } + ], + "name": "depositETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ] +} diff --git a/typescript/infra/scripts/funding/utils/L1MessageQueue.json b/typescript/infra/scripts/funding/utils/L1MessageQueue.json new file mode 100644 index 0000000000..040883a47a --- /dev/null +++ b/typescript/infra/scripts/funding/utils/L1MessageQueue.json @@ -0,0 +1,23 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasLimit", + "type": "uint256" + } + ], + "name": "estimateCrossDomainMessageFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/typescript/infra/scripts/funding/utils/L1ScrollMessenger.json b/typescript/infra/scripts/funding/utils/L1ScrollMessenger.json new file mode 100644 index 0000000000..efe556a193 --- /dev/null +++ b/typescript/infra/scripts/funding/utils/L1ScrollMessenger.json @@ -0,0 +1,17 @@ +{ + "abi": [ + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/typescript/infra/scripts/funding/utils/PolygonZkEVMBridge.json b/typescript/infra/scripts/funding/utils/PolygonZkEVMBridge.json new file mode 100644 index 0000000000..54a868c3fb --- /dev/null +++ b/typescript/infra/scripts/funding/utils/PolygonZkEVMBridge.json @@ -0,0 +1,42 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "uint32", + "name": "destinationNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "destinationAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "bool", + "name": "forceUpdateGlobalExitRoot", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "permitData", + "type": "bytes" + } + ], + "name": "bridgeAsset", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ] +}