# 使用合约调用zkSync2.0跨链

By [plsdm7](https://paragraph.com/@dogsuisui) · 2022-11-27

---

由于本菜鸡实在太菜，稍微复杂的不开源合约就看不懂参数，尝试看JS又实在看不出来，所以找了一个很简单的例子做实验。就是zkSync2.0测试网的跨链桥。

[https://portal.zksync.io/bridge](https://portal.zksync.io/bridge)

要体验zksync2.0需要从Goerli把测试eth跨过去，小跨一笔。

[https://goerli.etherscan.io/tx/0xff637f90945bf7bb45f866ba9c7a0eaa7fbab05317398dd1a93856cd4b09cb3b](https://goerli.etherscan.io/tx/0xff637f90945bf7bb45f866ba9c7a0eaa7fbab05317398dd1a93856cd4b09cb3b)

decode一下发现合约不开源，但是参数能够decode出来：

0 \_l2Receiver address 0xDac752245d44f396630C84394E5dB9B5dE6614dD 1 \_l1Token address 0x0000000000000000000000000000000000000000 2 \_amount uint256 10000000000000000

第一个是接收地址，第二个不知道是啥，反正都是0，第三个是十六进制跨链金额

网上有相关的文章介绍如何从不开源合约里解析函数签名，例如：

[https://cloud.tencent.com/developer/article/1945583](https://cloud.tencent.com/developer/article/1945583)

大致思路是先根据签名去查找一下函数签名数据库，如果有匹配的就可以拿到函数名和参数。向上面 这种估计是用得太多浏览器直接帮我们解出来了。

但是作者接下来的思路是构造参数相同的不同名的函数，然后再通过修改web3py源码的方式把函数名替换为目标函数。感觉这样过于复杂了。实际上能确定每个参数的含义，直接使用16进制调用是方便的。

    from web3 import Web3, HTTPProvider
    import json
    
    address = 'your wallet address'
    rpc = 'https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161'
    private_key = 'your private key'
    
    def replace(str):
        zeroList = list("0000000000000000000000000000000000000000000000000000000000000000")
        zeroListLen = len(zeroList)
        _str = str[2:] if str.startswith('0x') else str
        strLen = len(_str)
        #听说py是左开右闭区间，所以加1
        for i in range(1, strLen + 1):
            zeroList[zeroListLen - i] = _str[strLen - i]
        return "".join(zeroList)
    
    
    def transfer_eth_on_zksync_bridge(target_address, amount, gas_price=200, gas_limit=600000):
        nonce = web3.eth.getTransactionCount(address)
    
        params = {
            'nonce': nonce,
            'to': target_address,
            'gas': gas_limit,
            'maxFeePerGas': web3.toWei(gas_price, 'gwei'),
            'maxPriorityFeePerGas': web3.toWei(5, 'gwei'),
            'from': address,
            'value': web3.toWei(amount, 'ether'),
            "chainId": web3.eth.chain_id,
            "data": "0x8340f549" + replace(address) + '0000000000000000000000000000000000000000000000000000000000000000' + replace(hex(web3.toWei(amount, 'ether')))
        }
        print(nonce)
        signed_tx = web3.eth.account.signTransaction(params, private_key=private_key)
        tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction).hex()
        receipt = web3.eth.wait_for_transaction_receipt(tx_hash, timeout=150)
        return tx_hash
    
    
    web3 = Web3(HTTPProvider(rpc))
    transfer_eth_on_zksync_bridge(web3.toChecksumAddress("0xc24215226336d22238a20a72f8e489c005b44c4a"), "0.01")
    

看到传参的的时候data部分直接使用，函数签名+参数拼接。

第三个参数表示跨链的eth数量，需要转一下16进制。

另外这里有个小坑，我之前一直不成功，是因为没注意到txn里有个value。所以参数列表要把value也加上，也就是跨链的金额，单位记得是wei不是ether。

**整体上合约调用的思路就是这样了，其实如果有ABI那就更简单了，可以使用更加直接的函数调用。有兴趣可以拿这个代码多跑几个钱包跨一下。**

最后说下wait\_for\_transaction\_receipt这个函数，它本意是等待交易完成并返回回执，但我测试了很多次发现虽然是同步阻塞的，但是拿到返回结果也不一定这个交易就在链上minted了，因为我经常返回了但是nonce 还是不变。估计是因为节点不同步等等的原因，所以如果有nonce 的问题，可能最好的办法还是循环等待一下nonce 更新。

---

*Originally published on [plsdm7](https://paragraph.com/@dogsuisui/zksync2-0)*
