# Bridge Parameters 08-11: Update L2 status for the front-end: ``` const { L1TransactionReceipt } = require('@arbitrum/sdk') const receipt = await l1Provider.getTransactionReceipt(txnHash) const l1Receipt = new L1TransactionReceipt(receipt) const message = await l1Receipt.getL1ToL2Message(l2Wallet) const status = (await message.waitForStatus()).status if (status === 4) { console.log(`L2 retryable txn is already executed 🥳 ${message.l2TxHash}`) return } else { console.log( `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` ) } ``` 其中status的状态如下: ``` /** * The retryable ticket has yet to be created */ NOT_YET_CREATED = 1, /** * An attempt was made to create the retryable ticket, but it failed. * This could be due to not enough submission cost being paid by the L1 transaction */ CREATION_FAILED = 2, /** * The retryable ticket has been created but has not been redeemed. This could be due to the * auto redeem failing, or if the params (max l2 gas price) * (max l2 gas) = 0 then no auto * redeem tx is ever issued. An auto redeem is also never issued for ETH deposits. * A manual redeem is now required. */ FUNDS_DEPOSITED_ON_L2 = 3, /** * The retryable ticket has been redeemed (either by auto, or manually) and the * l2 transaction has been executed */ REDEEMED = 4, /** * The message has either expired or has been canceled. It can no longer be redeemed. */ EXPIRED = 5 ``` 08-01:Update bridge parameters calculation 安装新的依赖包: ``` npm install @arbitrum/sdk ``` 运行以下程序: ``` import { L1ToL2MessageGasEstimator } from "@arbitrum/sdk-nitro" const { BigNumber, providers, utils } = require('ethers') const l1GatewayABI = [ { inputs: [ { internalType: 'address', name: 'l1Token', type: 'address', }, { internalType: 'address', name: 'from', type: 'address', }, { internalType: 'address', name: 'to', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, { internalType: 'bytes', name: 'data', type: 'bytes', }, ], name: 'getOutboundCalldata', outputs: [ { internalType: 'bytes', name: 'outboundCalldata', type: 'bytes', }, ], stateMutability: 'pure', type: 'function', }, ] async function main() { const l1Provider_1 = new providers.JsonRpcProvider( 'https://rinkeby.infura.io/v3/5b56b37c7e9844f7b58373cac2fafa1d' ) const l2Provider_1 = new providers.JsonRpcProvider( 'https://rinkeby.arbitrum.io/rpc' ) const gasEstimator = new L1ToL2MessageGasEstimator(l2Provider_1) const l1USXAddress = '0x2D76117C2C85c2E9C9FBF08199C9Be59af887526' const l1GatewayAddress = '0x6729B1425DF1750e14CEb171919c346f58014913' const from = '0xbA32Bc6396152025608a37005D80E0346aB4740b' const to = '0xbA32Bc6396152025608a37005D80E0346aB4740b' const baseFee = (await l1Provider_1.getBlock('latest')).baseFeePerGas const estimateGasCallValue = BigNumber.from('0') const tokenGasOverrides = { gasLimit: { min: BigNumber.from(275000) }, } const depositAmount = utils.parseEther('3') const l1Gateway = new ethers.Contract( l1GatewayAddress, l1GatewayABI, l1Provider_1 ) const abiCoder = new ethers.utils.AbiCoder() const data = abiCoder.encode( ['uint256', 'bytes'], [estimates.maxSubmissionFee, '0x'] ) const depositCalldata = await l1Gateway.getOutboundCalldata( l1USXAddress, from, to, depositAmount, '0x' ) console.log('depositCalldata', depositCalldata) const estimates = await gasEstimator.estimateAll( l1GatewayAddress, to, depositCalldata, estimateGasCallValue, baseFee, from, from, l1Provider_1, tokenGasOverrides ) console.log('\n 1. max gas: ', estimates.gasLimit.toString()) console.log('\n 2. gas price bid: ', estimates.maxFeePerGas.toString()) console.log('\n 3. data: ', data) console.log('\n 4. eth value: ', estimates.totalL2GasCosts.toString()) } ``` ## Overview: USX: ETH -> Arbitrum/Optimism: dForce bridge ETH -> BNB: cBridge Arbitrum/Optimism/BNB -> ETH: cBridge DF: ETH -> Arbitrum/Optimism: L2 bridge ETH -> BNB: cBridge Arbitrum/Optimism/BNB -> ETH: cBridge ## Ethereum -> Arbitrum: ### USX(使用dForce的bridge): Rinkeby L1 USX Address: `0x2D76117C2C85c2E9C9FBF08199C9Be59af887526` (可以调用[allocateTo](https://rinkeby.etherscan.io/address/0x2D76117C2C85c2E9C9FBF08199C9Be59af887526#writeContract) 获得) 查询余额为:balanceOf(account_address) (decimals 为18) Rinkeby L1 USX Bridge: `0x9f94c5136A80B994AD53acfeF5e3F27609D221a8` Rinkeby L1 USX Approval: `0x9f94c5136A80B994AD53acfeF5e3F27609D221a8` Arbitrum-Test L2 USX Address: `0x53876c224Ef395428c97b368236Eb7132400c4B3` Arbitrum-Test L2 USX Bridge: `0x1e572B08e311C229FF8cfAaB0142e36474c3640D` Arbitrum-Test L2 Provider: ``` var Web3 = require('web3'); l2_provider = new Web3(new Web3.providers.HttpProvider('https://rinkeby.arbitrum.io/rpc')); ``` Mainnet L1 USX Address: `0x0a5E677a6A24b2F1A2Bf4F3bFfC443231d2fDEc8` 查询余额为:balanceOf(account_address) (decimals 为18) Mainnet L1 USX Bridge: `0x870ac6a76A30742800609F205c741E86Db9b71a2` Mainnet L1 USX Approval: `0x870ac6a76A30742800609F205c741E86Db9b71a2` Arbitrum-Mainnet L2 USX Address: `0x641441c631e2F909700d2f41FD87F0aA6A6b4EDb` Arbitrum-Mainnet L2 USX Bridge: `0x1C4d5eCFBf2AF57251f20a524D0f0c1b4f6ED1C9` Arbitrum-Mainnet L2 Provider: ``` var Web3 = require('web3'); l2_provider = new Web3(new Web3.providers.HttpProvider('https://arb1.arbitrum.io/rpc')); ``` 跨链发交易之前先检查授权额度:allowance(user_address, L1_USX_Approval) 如果上面的授权额度值小于想要跨链的USX的数量,调用 USX.approve(L1_USX_Approval, MAX) MAX = web3.utils.toTwosComplement('-1') 此项检查通过后,获得用户想要跨链的USX的数量:depositAmount 调用: L1_USX_Bridge.methods.outboundTransfer(L1_USX, user_address, depositAmount, max_gas, gas_price_bid, data).send({value: eth_value}) 其中,`const gas_price_bid = await l2_provider.eth.getGasPrice();` max_gas: ``` const l1_bridge = new web3.eth.Contract(bridge_abi, bridge_address); const deposit_calldata = await l1_bridge.methods.getOutboundCalldata(l1_usx_address, from, to, depositAmount, '0x'); const max_submission_price = await getMaxSubmissionPrice(l2_provider, deposit_calldata); const max_gas = await getMaxGas( l2_provider, l1_usx_bridge, l2_usx_bridge, from, max_submission_price, gas_price_bid, deposit_calldata, ); ``` **所需方法和ABI在此处:[arbitrum_helpers](https://gist.github.com/Skyge/563854ef619bba23e2554af0d3a8bcf0#file-arbitrum_helpers-js)** data: ``` const data = web3.eth.abi.encodeParameters(['uint256','bytes'], [max_submission_price, '0x']); ``` eth_value: ``` const eth_value = await max_submission_price.add(gas_price_bid.mul(max_gas)) ``` 交易确定后,从交易中获得event,找到`InboxMessageDelivered`, 第一个参数为需要的 MessagesSequenceNum,通过这个数字来计算L2的交易hash,L2 hash: ``` const request_id = await calculateL2TransactionHash(MessagesSequenceNum); const L2_hash = await calculateL2RetryableTransactionHash(request_id); ``` L2 交易的确定大概是10分钟。 trigger on Arbitrum testnet: [0xb0A5C5136A80b994ad53acfEf5e3F27609D232b9](https://testnet.arbiscan.io/address/0xb0A5C5136A80b994ad53acfEf5e3F27609D232b9) trigger on Arbitrum Mainnet: [0x981bc6a76a30742800609f205c741e86db9b82b3](https://arbiscan.io/address/0x981bc6a76a30742800609f205c741e86db9b82b3) ### DF Mainnet L1 DF Address: `0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0` 查询余额为:balanceOf(account_address) (decimals 为18) Mainnet L1 DF Router(Bridge): `0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef` Mainnet L1 DF Approval: `0xcEe284F754E854890e311e3280b767F80797180d` Arbitrum-Mainnet L2 DF Address: `0xaE6aab43C4f3E0cea4Ab83752C278f8dEbabA689` Arbitrum-Mainnet L2 Provider: ``` var Web3 = require('web3'); l2_provider = new Web3(new Web3.providers.HttpProvider('https://arb1.arbitrum.io/rpc')); ``` 其余的方法同USX ## Arbitrum -> Ethereum: ### USX(使用celer的bridge): Arbitrum-Test L2 cBridge: 0xFFe5f3dDdA62A9c5b0339AcD3632a99266dabe4e Mainnet cBridge: 0x5427FEFA711Eff984124bFBB1AB6fbf5E3DA1820 BNB cBridge: 0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF BNB DF: 0x4A9A2b2b04549C3927dd2c9668A5eF3fCA473623 BNB USX:0xB5102CeE1528Ce2C760893034A4603663495fD72 Arbitrum cBridge: 0x1619DE6B6B20eD217a58d00f37B9d47C7663feca Optimism cBridge: 0x9D39Fc627A6d9d9F8C831c16995b209548cc3401 Polygon cBridge: 0x88DCDC47D2f83a99CF0000FDF667A468bB958a78 **所需的ABI在此处: [cbridge_json](https://gist.github.com/Skyge/563854ef619bba23e2554af0d3a8bcf0#file-cbridge-json)** 前提,查看 `USX.allowance(caller_address, cBridge_address)`, 如果返回值allowance小于跨链token的数量,先`USX.approve(cBridge_address, amount)` 转移token的方法:`cBridge.methods.send(_receiver, _token, _amount, _dstChainId, _timestamp, _maxSlippage)` 其中,`_receiver`: 默认是调用者地址 `_token`: L2 转移token的地址(USX/DF) `_amount`: L2 转移token的数量 `_dstChainId`: 目标跨链的chain id, 例如从Arbitrum -> ETH, 则目标链为ETH,获得chain id,可根据目标链的 `web3.eth.getChainId()` 或者 ``` mainnet: 1 rinkeby: 4 Görli: 5 optimism: 10 kovan: 42 BNB(BSC): 56 optimism kovan: 69 BNB(BSC) Test: 97 Polygon: 137 Arbitrum: 42161 Polygon Test(Mumbai): 80001 Arbitrum Rinkeby: 421611 ``` `_timestamp`: 取当前时间戳 `_maxSlippage`: 取下面结果的 `max_slippage` ,直接填入就可以 ``` 通过请求API: https://cbridge-prod2.celer.network/v2/estimateAmt?src_chain_id=42161&dst_chain_id=56&token_symbol=DF&amt=1000000000000000000&usr_addr=0xa0183E85b199Cb4437200B9E87809d38b6Ed325f&slippage_tolerance=3000 src_chain_id:调用链的chain ID dst_chain_id:目标链的chain ID token_symbol:USX/DF(只能是大写) amt:转移的token数量(带decimals,USX和DF的decimals都是18) usr_addr:调用者地址 slippage_tolerance:用户前端选用的滑点,例子:3000,代表0.3% 返回结果示例: { "err": null, "eq_value_token_amt": "1000000000000000000", "bridge_rate": 1, "perc_fee": "0", "base_fee": "14182106305582652666", "slippage_tolerance": 3000, "max_slippage": 1000000, "estimated_receive_amt": "-13182106305582652666", // 预计跨链得到的数量 "drop_gas_amt": "2000000000000000" } ``` **说明:** 首先判断error是否为空,可能出现 `insufficient funds`等问题, 如果不为空,对于拿到的结果 `perc_fee` 和 `base_fee` 是跨链的费用(会扣除的DF/USX的数量),两者需相加,注意的是两者都是18位的,DF,USX 的decimals 都是18,默认就可以了。 total fee 是上述两个值相加。 `estimated_receive_amt` 是展示给用户预计接收的数量。当该数值为负数时表示,跨链的数量无法支付跨链的费用。 `estimated_receive_amt` = 跨链数量 - perc_fee - base_fee *此API不要频繁请求,只在发交易时请求* **cBridge查询跨链结果:** 首先计算出 transactionId, ``` // result = 0xfbb252266bf72bd50c20cce12911fc3dcb42af5d47ffe33d8e60491932fb5c6a web3.utils.soliditySha3( {type: 'address', value: '0xdad9d86885d217b92a47370e1e785897dd09a4f3'}, /// User's wallet address {type: 'address', value: '0xdad9d86885d217b92a47370e1e785897dd09a4f3'}, /// User's wallet address {type: 'address', value: '0x7d43aabc515c356145049227cee54b608342c0ad'}, /// ETH / ERC20 token address {type: 'uint256', value: '10000000000'}, /// Send amount in String {type: 'uint64', value: '5'}, /// Destination chain id {type: 'uint64', value: '1638862397751'}, /// timestamp {type: 'uint64', value: '4002'}) /// Source chain id ``` 所以transaction_id = "fbb252266bf72bd50c20cce12911fc3dcb42af5d47ffe33d8e60491932fb5c6a", 请求: ``` var myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); var raw = JSON.stringify({ "transfer_id": "fbb252266bf72bd50c20cce12911fc3dcb42af5d47ffe33d8e60491932fb5c6a" }); var requestOptions = { method: 'POST', headers: myHeaders, body: raw, redirect: 'follow' }; fetch("https://cbridge-prod2.celer.network/v2/getTransferStatus", requestOptions) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error)); ``` 结果: ![](https://hackmd.io/_uploads/ry3thJqM9.png) ### Refund 当上述查询结果为 **TRANSFER_TO_BE_REFUNDED**, 即返回结果代码为6, 则跨链交易失败,需要用户手动取出自己的资产。流程如下: - https://cbridge-docs.celer.network/developer/cbridge-pool-based-transfer-xliquidity/transfer-refund ## Ethereum -> Optimism: ### USX(使用dForce的bridge): **Kovan:** L1 USX: 0xF76eAd4da04BbeB97d29F83e2Ec3a621d0FB3c6e L1 messenger: 0x4361d0F75A0186C05f971c566dC6bEa5957483fD L1 USX bridge: 0x40E862341b2416345F02c41Ac70df08525150dC7 L2 USX: 0xab7020476D814C52629ff2e4cebC7A8cdC04F18E 首先调用USX的allowance方法查询用户是否授过足够的额度,方法为`USX.allowance(User_Address, l1_usx_bridge)` 如果该结果的allowance是0或者小于欲转移token的数量,调用approve进行授权。 进行授权方法:`USX.approve(l1_usx_bridge, -1)` token跨链调用的方法为 `l1_usx_bridge.depositERC20()`: ``` depositERC20( address _l1Token, // L1 USX 地址 address _l2Token, // L2 USX 地址 uint256 _amount, // 转移token的数量 uint32 _l2Gas, // 1000000 写死该数值 bytes calldata _data // "0x" ) ``` 所需合约的ABI在此处:[L1 optimism USX bridge](https://gist.github.com/Skyge/563854ef619bba23e2554af0d3a8bcf0#file-l1_optimism_bridge-json) 跨链交易发送成功后,先获取该交易hash, 然后通过以下方法查询L2结果: 首先安装辅助package: `npm install @eth-optimism/core-utils ethers` ``` const ethers = require('ethers') const { Watcher } = require('@eth-optimism/core-utils') // 替换成metamask有效的链接 const l1RpcProvider = new ethers.providers.JsonRpcProvider('https://eth-kovan.alchemyapi.io/v2/xxx') // 替换成metamask有效的链接 const l2RpcProvider = new ethers.providers.JsonRpcProvider('https://opt-kovan.g.alchemy.com/v2/xxx') const watcher = new Watcher({ l1: { provider: l1RpcProvider, messengerAddress: "0x4361d0F75A0186C05f971c566dC6bEa5957483fD" // (Op-Kovan) // messengerAddress: "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1" // (Op-Mainnet) }, l2: { provider: l2RpcProvider, messengerAddress: "0x4200000000000000000000000000000000000007" //(Op-Kovan) // messengerAddress: "0x4200000000000000000000000000000000000007" //(Op-mainnet 同 Op-kovan) } }) const [ msgHash1 ] = await watcher.getMessageHashesFromL1Tx(transaction_hash) const receipt = await watcher.getL2TransactionReceipt(msgHash1, true) console.log("receipt hash", receipt.transactionHash) ``` Mainnet: L1 USX: 0x0a5e677a6a24b2f1a2bf4f3bffc443231d2fdec8 L1 messenger: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 L1 USX bridge: 0xC5b1EC605738eF73a4EFc562274c1c0b6609cF59 L2 USX: 0xbfD291DA8A403DAAF7e5E9DC1ec0aCEaCd4848B9 L1 DF: 0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0 L1 DF bridge: 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1 L2 DF: 0x9e5AAC1Ba1a2e6aEd6b32689DFcF62A509Ca96f3 ~~L2 DF bridge: 0x4200000000000000000000000000000000000010~~ ## Ethereum -> Polygon:(无测试网) ### USX(使用c-bridge): Polygon USX: 0xCf66EB3D546F0415b368d98A95EAF56DeD7aA752 使用方法同USX 使用cBridge 从 Arbitrum 到 Ethereum. ### DF(使用官方Bridge) L1 DF: 0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0 L1 approve: 0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf L1 bridge: 0xA0c68C638235ee32657e8f720a23ceC1bFc77C77 Polygon DF: 0x08C15FA26E519A78a666D19CE5C646D55047e0a3 同上,首先检查allowance 是否足够。 跨链调用方法为 ``` L1_bridge.depositFor( address user, // 用户地址 address rootToken, // df 地址 bytes calldata depositData // 10进制的存款数量转换为16进制,例如:0x0000000000000000000000000000000000000000000000056bc75e2d63100000 ) ``` 事件查询方法: ``` const WebSocket = require("ws"); const Web3 = require("web3"); // For Mumbai const ws = new WebSocket("wss://ws-mumbai.matic.today/"); // For Polygon mainnet: wss://ws-mainnet.matic.network/ const web3 = new Web3(); const abiCoder = web3.eth.abi; async function checkDepositStatus( userAccount, rootToken, depositAmount, childChainManagerProxy ) { return new Promise((resolve, reject) => { ws.on("open", () => { ws.send( `{"id": 1, "method": "eth_subscribe", "params": ["newDeposits", {"Contract": "${childChainManagerProxy}"}]}` ); ws.on("message", (msg) => { const parsedMsg = JSON.parse(msg); if ( parsedMsg && parsedMsg.params && parsedMsg.params.result && parsedMsg.params.result.Data ) { const fullData = parsedMsg.params.result.Data; const { 0: syncType, 1: syncData } = abiCoder.decodeParameters( ["bytes32", "bytes"], fullData ); // check if sync is of deposit type (keccak256("DEPOSIT")) const depositType = "0x87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f821"; if (syncType.toLowerCase() === depositType.toLowerCase()) { const { 0: userAddress, 1: rootTokenAddress, 2: depositData, } = abiCoder.decodeParameters( ["address", "address", "bytes"], syncData ); // depositData can be further decoded to get amount, tokenId etc. based on token type // For ERC20 tokens const { 0: amount } = abiCoder.decodeParameters( ["uint256"], depositData ); if ( userAddress.toLowerCase() === userAccount.toLowerCase() && rootToken.toLowerCase() === rootTokenAddress.toLowerCase() && depositAmount === amount ) { resolve(true); } } } }); ws.on("error", () => { reject(false); }); ws.on("close", () => { reject(false); }); }); }); } // Param1 - user address // Param2 - contract address on main chain // Param3 - amount deposited on main chain // Param4 - child chain manager proxy address (0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa for mainnet) checkDepositStatus( "0xFd71Dc9721d9ddCF0480A582927c3dCd42f3064C", "0x47195A03fC3Fc2881D084e8Dc03bD19BE8474E46", "1000000000000000000", "0xb5505a6d998549090530911180f38aC5130101c6" ) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); ``` ## cBridge Test cBridge test 网络体验:https://dev-cbridge-v2.netlify.app/#/transfer 所连接的测试网为Görli,添加该网络可前往:https://chainlist.org/ 先选择Testnets, 然后搜索该网络,连接钱包,添加即可。 前往此处获得测试币:https://faucet.paradigm.xyz/ Görli weth 地址为: 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6 BNB test weth: 0xE0dfD58A528085912a03C4d093905707FC4EDac7 支持 weth 在 Görli, BNB test, 这两个网络之间相互跨链 cBridge Testnet Endpoint The testnet endpoint is: https://cbridge-v2-test.celer.network/ ## Ethereum -> Arbitrum: ### DF(使用Arbitrum的bridge): 具体方法同之前的usx 从 [ethereum 到 arbitrum 的跨链](https://hackmd.io/5QvObfeMRme4ZJC6DuJYQg?view#Ethereum--gt-Arbitrum) Ethereum DF: 0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0 Ethereum l1 erc20 gateway(approval): 0xa3A7B6F88361F48403514059F1F16C8E78d60EeC Ethereum l1 gateway router: 0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef Arbitrum DF: 0xaE6aab43C4f3E0cea4Ab83752C278f8dEbabA689 Arbitrum l2 gateway: 0x5288c571Fd7aD117beA99bF60FE0846C4E84F933 Arbitrum l2 destination: 0xb4B8B6F88361F48403514059f1f16C8E78d61FFD Rinkeby l1 erc20 gateway(approval): 0x91169Dbb45e6804743F94609De50D511C437572E Rinkeby l1 gateway router: 0x70C143928eCfFaf9F5b406f7f4fC28Dc43d68380 Arbitrum Test l2 gateway: 0x9413AD42910c1eA60c737dB5f58d1C504498a3cD Arbitrum Test l2 destination: 0x81D243928eCFFAf9f5B406F7f4fC28Dc43D69491 getMaxGas( l2_provider, l1_erc20_gateway, // <<<---- l2_destination, // <<<---- ## 在 Ethereum 上 claim DF 安装所需要的package: `npm install @arbitrum/sdk ethers` 首先拿到 `txnHash`, 它是 L2 触发跨链的交易哈希,拿到交易哈希后,解析event 合约: https://arbiscan.io/address/0x5288c571fd7ad117bea99bf60fe0846c4e84f933#readProxyContract 解析topics为 `0x5baaa87db386365b5c161be377bc3d8e317e8d98d71a3ca7ed7d555340c8f767` 的 event,拿到最后一个topic的数值,记为 `batchNum`,例如 这笔交易: https://arbiscan.io/tx/0x742b611b4e5741d4c5ffd2f85d8463b703ff74a3ac20dce71d564b1305e72a25#eventlog ,topics 为`0x5baaa87db386365b5c161be377bc3d8e317e8d98d71a3ca7ed7d555340c8f767`的最后一个数值为:`0x00000000000000000000000000000000000000000000000000000000000018eb` 然后运行以下程序,得到所需的`poolInfo`, helper.js ``` const { providers, Wallet } = require('ethers') const { L2TransactionReceipt, getL2Network, L2ToL1MessageStatus, } = require('@arbitrum/sdk') // Set up: instantiate L1 wallet connected to provider const walletPrivateKey = "0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709" // Ethereum-Arbitrum // const l1Provider = new providers.JsonRpcProvider(xxxx) // const l2Provider = new providers.JsonRpcProvider("https://arb1.arbitrum.io/rpc") // Rinkeby-Arbitrum_Test const l1Provider = new providers.JsonRpcProvider(xxxx) const l2Provider = new providers.JsonRpcProvider("https://rinkeby.arbitrum.io/rpc") const l1Wallet = new Wallet(walletPrivateKey, l1Provider) // First, let's find the Arbitrum txn from the txn hash provided const receipt = await l2Provider.getTransactionReceipt(txnHash) const l2Receipt = new L2TransactionReceipt(receipt) // Note that in principle, a single transaction could trigger any number of outgoing messages; the common case will be there's only one. // For the sake of this script, we assume there's only one / just grad the first one. const messages = await l2Receipt.getL2ToL1Messages(l1Wallet, l2Provider) const l2ToL1Msg = messages[0] // Check if already executed // if ((await l2ToL1Msg.status(l2Provider)) == L2ToL1MessageStatus.EXECUTED) { // return // } // Now fetch the proof info we'll need in order to execute, or check execution const proofInfo = await l2ToL1Msg.getOutboxProof(l2Provider) ``` 以上 `proofInfo` 返回结构为: ``` { proof: string[]; path: BigNumber; l2Sender: string; l1Dest: string; l2Block: BigNumber; l1Block: BigNumber; timestamp: BigNumber; amount: BigNumber; calldataForL1: string; } ``` 所以 调用的方法为: ``` claimFunds( uint256 batchNum, bytes32[] calldata proof, uint256 index, address l2Sender, address destAddr, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 amount, bytes calldata calldataForL1 ) ``` 所需的参数均可以通过以上获取到。