---
# System prepended metadata

title: Bridge Parameters

---

# 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
    )
```
所需的参数均可以通过以上获取到。
