使用合约调用zkSync2.0跨链

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

https://portal.zksync.io/bridge

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

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

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

但是作者接下来的思路是构造参数相同的不同名的函数,然后再通过修改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 更新。