由于本菜鸡实在太菜,稍微复杂的不开源合约就看不懂参数,尝试看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 更新。
