python与以太坊智能合约交互
先说一下为啥选择python,因为简单。之前用swift(iOS)实现了和以太坊交互,太恶心了。。。
python需要用到一个库web3.py。
文档:https://web3py.readthedocs.io/en/stable/
github:https://github.com/ethereum/web3.py
需要做一个轮询脚本
之前写了基于DYDX闪电贷在Cofix和Uniswap之间套利,只要解释了套利合约中的逻辑以及怎么调用其中涉及到的各个合约(cofix,weth,dydx,uniswap)。套利机会很少,不能人在盯着,需要配一套可以自动查询并且发送交易的程序。
思路
graph LR
A[套利脚本] -- 生成 --> B((触发套利合约的交易))
B((触发套利合约的交易))--查询是否有套利空间-->C[以太坊]
脚本需要实现的是一直在查询是否有套利机会,如果有就发起交易。
上代码
https://github.com/MLY0813/FlashSwapForCofixAndUni/tree/main/FlashSwapForCofixAndUni
https://github.com/MLY0813/SwapCofixAndUni/tree/main/CofixAndUni
1.配置
SETTING = {
"ROPSTEN_URL": "XXX",
"MAINNET_URL": "XXX",
"CONTRACT_ADDRESS": "XXX",
"WALLET_PRIVATEKEY": "XXX",
"WALLET_ADDRESS": "XXX",
"ETH_SPAN": [1800, 2100, 2400, 2700, 3000, 3300, 3600, 3900]
}
- ROPSTEN_URL:以太坊测试网的节点地址
- MAINNET_URL:以太坊主网的节点地址
- CONTRACT_ADDRESS:套利合约的地址
- WALLET_PRIVATEKEY:执行套利交易的钱包私钥(需要私钥签名交易)
- WALLET_ADDRESS:执行套利交易的钱包地址
- ETH_SPAN:套利所使用的资金规模,暂定以300ETH为跨度
2.交易必备的方法和对象
w3节点对象
w3 = Web3(Web3.HTTPProvider(SETTING["MAINNET_URL"]))
发送交易方法封装
def sendTransation(tx_dic):
nonce = w3.eth.getTransactionCount(SETTING["WALLET_ADDRESS"])
tx_dic["nonce"] = nonce
tx_dic['gasPrice'] = w3.eth.gasPrice
sign_tx = w3.eth.account.signTransaction(tx_dic, private_key=SETTING["WALLET_PRIVATEKEY"])
return w3.eth.sendRawTransaction(sign_tx.rawTransaction)
def sendTransationWithMoreGas(tx_dic, gwei):
nonce = w3.eth.getTransactionCount(SETTING["WALLET_ADDRESS"])
tx_dic["nonce"] = nonce
tx_dic['gasPrice'] = w3.eth.gasPrice + w3.toWei(gwei, 'gwei')
sign_tx = w3.eth.account.signTransaction(tx_dic, private_key=SETTING["WALLET_PRIVATEKEY"])
return w3.eth.sendRawTransaction(sign_tx.rawTransaction)
sendTransation和sendTransationWithMoreGas的区别在于前者使用的是默认gasprice(均价),后者是在均价的基础上按需求增加。
swapContract.py
主要包含套利合约的ABI,拼接调用initiateFlashLoan方法的交易。“initiateFlashLoan”是触发套利合约套利的方法。
def initiateFlashLoan(ethAmount):
tx_dix = contractObj.functions.initiateFlashLoan(ethAmount).buildTransaction({
'from': SETTING["WALLET_ADDRESS"],
'gas': 1200000
})
return tx_dix
main.py
在主函数中主要实现了轮询的方法,这里用到了以太坊的机制“预估gas”。套利合约需要检测有没有套利空间,cofix和uniswap都有很复杂的交易计算,没必要在脚本中完全模拟出双方的交易计算从而判断有没有套利空间是否需要发交易。estimateGas可以预估出套利交易的gas消耗(不准,仅供参考)。我们实际想要知道的是是否有套利空间,因为在套利合约中已经判断了资金量不能少。所以可以假设estimateGas正常返回数据代表此刻有套利空间,如果异常代表没有套利空间。
在代码中使用try,捕捉异常来判断发起交易的时机。
for num in SETTING["ETH_SPAN"]:
now = int(time.time())
timeArray = time.localtime(now)
tx_dic = initiateFlashLoan(w3.toWei(num, "ether"))
try:
tx_dic_gas = w3.eth.estimateGas(tx_dic)
except ValueError:
print("unlucky", time.strftime("%Y--%m--%d %H:%M:%S", timeArray))
else:
print("success")
sendTransationWithMoreGas(tx_dic, "2")
time.sleep(20)