0%

solidity | python 编码 abi data

使用 python 进行 abi 的编码。

这里一共说几个方式

  • 通过 abi 生成 data
  • 通过第三方工具生成 data
  • 通过原始代码生成 data

关于 abi 编码后的 input 具体是什么排列的,请参考

这里就以 pancakeswapswapExactTokensForTokensSupportingFeeOnTransferTokens 为例子。

我们将要构造

通过 abi 生成 data

这个是最正规的,也是最简单的。

请看下面的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from web3 import Web3

pancake_Router_abi = """[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
"""

pancake_Factory = Web3.toChecksumAddress("0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73")
pancake_Route = Web3.toChecksumAddress("0x10ed43c718714eb63d5aa57b78b54704e256024e")

w3 = Web3(Web3.HTTPProvider("https://bsc-mainnet.nodereal.io/v1/***"))

contract_pancake_Router = w3.eth.contract(
address=Web3.toChecksumAddress(pancake_Route), abi=pancake_Router_abi)

tx_dic = contract_pancake_Router.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens(
2654911060,
22955622102789724744,
[
Web3.toChecksumAddress("0x3019BF2a2eF8040C242C9a4c5c4BD4C81678b2A1"), # BNB
Web3.toChecksumAddress("0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"), # JULD
],
Web3.toChecksumAddress("0x0a46E71A93819f6e6E94Ea47B08998EE8dd0450D"),
1654665606
).buildTransaction(
{
'gas': 500000,
}
)
print(tx_dic.get("data"))

输出

1
0x5c11d795000000000000000000000000000000000000000000000000000000009e3eba540000000000000000000000000000000000000000000000013e92c0adaae31a4800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000a46e71a93819f6e6e94ea47b08998ee8dd0450d0000000000000000000000000000000000000000000000000000000062a0318600000000000000000000000000000000000000000000000000000000000000020000000000000000000000003019bf2a2ef8040c242c9a4c5c4bd4c81678b2a10000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d

如果只是想知道加密后的 data

可以使用

contract_pancake_Router.encodeABI()

具体用法请参考

通过第三方工具生成 data

这里用的第三方库是 eth_abi

参考博客

ps: 这里 eth_abi 使用的版本是 2.1.1 版本,最新的版本调用方式已经和这个版本相差很大了,这点要注意。

如果,我们想要和一个合约进行交互,在不知道 abi 的情况下,我们发送的方式是

1
2
3
4
5
6
7
8
9
10
11
12
13
fromAddress = Web3.toChecksumAddress(address)
nonce = w3.eth.getTransactionCount(fromAddress)
transaction = {
'from': fromAddress,
'to': toAddress,
'gas': 241838,
'gasPrice': w3.toWei('5', 'gwei'),
'nonce': nonce,
'data': "c9972e44",
'chainId': 70
}
signed_tx = w3.eth.account.signTransaction(transaction, private)
txn_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)

我们主要是构造 data

首先我们要知道 data 的构造方式

0x + 函数的前8字符 + abi 编码出的数据

所以,想要获得 data 需要

  • 函数前 8 个字符
  • abi 编码出的数据

函数前 8 个字符

安装

1
pip install pysha3

1
2
3
4
5
6
import sha3

result = sha3.keccak_256()
result.update(b"swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256)")
a = result.hexdigest()
print(a)

输出

5c11d79526ce10b4a02fad7c13a4f0c7482b8f962c004e4f4d599003116c5f92

abi 编码出的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from eth_abi import encode_abi
from web3 import Web3

code = encode_abi(['uint', 'uint256', 'address[]', 'address', 'uint256'],
[2654911060,
22955622102789724744,
[
Web3.toChecksumAddress("0x3019BF2a2eF8040C242C9a4c5c4BD4C81678b2A1"),
Web3.toChecksumAddress("0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"),
],
Web3.toChecksumAddress("0x0a46E71A93819f6e6E94Ea47B08998EE8dd0450D"),
1654665606
])
print(code.hex())

输出

1
000000000000000000000000000000000000000000000000000000009e3eba540000000000000000000000000000000000000000000000013e92c0adaae31a4800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000a46e71a93819f6e6e94ea47b08998ee8dd0450d0000000000000000000000000000000000000000000000000000000062a0318600000000000000000000000000000000000000000000000000000000000000020000000000000000000000003019bf2a2ef8040c242c9a4c5c4bd4c81678b2a10000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d

这样就能把 data 拼接起来了。

至于这个 data 如何使用,请参考

通过原始代码生成 data

通过原始代码的意思是不借助第三方库,而是仅仅凭借加密基础库进行编码。

先分析一下原来的数据都代表什么。

1
2
3
4
5
6
7
8
9
10
11
12
# 2654911060
# 000000000000000000000000000000000000000000000000000000009e3eba54
# 22955622102789724744
# 0000000000000000000000000000000000000000000000013e92c0adaae31a48
# 占位符
# 00000000000000000000000000000000000000000000000000000000000000a0
# 1654665606
# 0000000000000000000000000a46e71a93819f6e6e94ea47b08998ee8dd0450d
# 0000000000000000000000000000000000000000000000000000000062a03186
# 0000000000000000000000000000000000000000000000000000000000000002
# 0000000000000000000000003019bf2a2ef8040c242c9a4c5c4bd4c81678b2a1
# 0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d

所以,我们只需要把相应的数字加密出来,补上占位符,还有填充 address 足够的 0 就能做到了。

这里不再对 address 还有 占位符做过的说明,值得注意的是,address 全部小写。

直接上代码

1
2
3
param1 = (2654911060).to_bytes(32, byteorder='big').hex()
param2 = (22955622102789724744).to_bytes(32, byteorder='big').hex()
param3 = (1654665606).to_bytes(32, byteorder='big').hex()

上面的就能解析出对应的数据。

请我喝杯咖啡吧~