使用 web3.py 高效转账 ERC20 代币的完整指南

·

1. 准备工作:合约地址、ABI 与私钥配置

要进行 ERC20 代币转账,首先需要三样东西:节点 RPC 地址、ERC20 合约地址,以及一份精简的 ABI。以示例中的 Hoo Smart Chain 为例——HTTP 端点为 https://http-mainnet.hoosmartchain.com
本示范所用的两个代币分别映射到两个 ERC20 合约地址

只保留 balanceOftransfer 两个函数,能显著减小 ABI 体积,降低代码复杂度,也能减少内存占用。

2. 项目结构与依赖

安装命令:

pip install web3==6.* xlrd==2.*

3. 读取 Excel—批量导入地址与私钥

Excel 格式保持简单:
| 一栏:钱包地址 | 一栏:明文私钥 |

借助 defaultdict,可以把地址映射到私钥,实现“一键扫全部私钥”的批处理:

from collections import defaultdict
import xlrd

def init_address():
    data = defaultdict(str)
    xls = xlrd.open_workbook("3000_2.xlsx")
    sheet = xls.sheets()[0]
    for row_idx in range(sheet.nrows):
        addr = sheet.cell_value(row_idx, 0).strip()
        priv = sheet.cell_value(row_idx, 1).strip()
        data[addr] = priv
    return data
小提示
Excel 中会出现空格或科学计数法问题,务必 .strip() 并在数据源头统一格式。

4. 查询余额——实时校验代币余额

web3.pycontract.functions.balanceOf().call() 查询完全离线,不产生费用。将其换算成 以太单位 方便人类阅读:

def get_ixt(address):
    addr = Web3.toChecksumAddress(address)
    return w3.fromWei(iXT_CONTRACT.functions.balanceOf(addr).call(), 'ether')

def get_iusdt(address):
    addr = Web3.toChecksumAddress(address)
    return w3.fromWei(iUSDT_CONTRACT.functions.balanceOf(addr).call(), 'ether')

调用失败的大多是 地址未校验toChecksumAddress() 是小写地址转 EIP-55 格式的关键步骤。

5. 签名与广播交易——三步完成转账

  1. 构造交易字典
  2. 本地签名
  3. 广播到节点

示例函数仅转账整张 iUSDT 余额:

def send_iusdt(from_addr, priv_key):
    to_addr = Web3.toChecksumAddress('0xE8e069C47A45050DBA9D566CEfFA7bc7D453F0c5')
    amount_wei = w3.toWei(get_iusdt(from_addr), 'ether')
    if amount_wei == 0:
        return  # 余额 0 不可转账

    nonce = w3.eth.getTransactionCount(from_addr)
    tx = iUSDT_CONTRACT.functions.transfer(
        to_addr, amount_wei
    ).buildTransaction({
        'gas': 241838,
        'gasPrice': w3.toWei('1', 'gwei'),
        'nonce': nonce,
    })

    signed = w3.eth.account.signTransaction(tx, priv_key)
    tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction)
    print(f'已广播:{Web3.toHex(tx_hash)}')

gas 设置为 24 万以上略高,能应付多数 ERC20 合约;节点拥堵时可提升 gasprice 到 5 gwei。

6. 批处理脚本实践

把上述模块拼成 if __name__ == '__main__': 块,即可一次扫完所有私钥:

if __name__ == '__main__':
    wallets = init_address()
    for addr, priv in wallets.items():
        send_iusdt(addr, priv)
        time.sleep(0.3)  # 稍微降速,防止节点限频

7. 安全与自动化进阶

👉 查看完整示例源码,一键运行无坑

8. 常见问题(FAQ)

Q1:为什么报错 Could not decode contract function call

Q2:转账卡在 pending?

Q3:批量转账如何保障私钥不泄露?

Q4:能否一次转账多笔地址节省 gas?

Q5:USDT 汇率与手续费怎么算?

👉 更多效率工具的详细使用手册