Python实现以太坊ERC20代币转账全指南

在区块链应用开发中,与以太坊生态的交互是常见需求,尤其是ERC20代币的转账操作,ERC20是以太坊上最主流的代币标准,稳定币(如USDT)、治理代币(如UNI)等都基于它实现,本文将详细介绍如何使用Python语言,结合web3.py库,实现ERC20代币的转账功能,涵盖环境准备、代码实现、错误处理及注意事项。

环境准备:开发工具与依赖安装

在开始编码前,需确保开发环境满足以下要求:

安装Python

推荐使用Python 3.8及以上版本,可通过官网或包管理器安装。

安装web3.py库

web3.py是与以太坊节点交互的核心Python库,提供了调用智能合约、发送交易等功能,通过pip安装:

pip install web3

准备以太坊节点

与以太坊网络交互需要连接到以太坊节点,常见方式有:

  • Infura:公共节点服务(需注册获取项目ID),适合测试和开发。
  • Alchemy:另一类公共节点服务,提供稳定接口。
  • 本地节点:运行Geth或OpenEthereum客户端,适合本地调试。

本文以Infura为例,需在Infura官网创建项目,获取HTTPS节点地址(格式:https://mainnet.infura.io/v3/YOUR_PROJECT_ID)。

准备钱包与私钥

ERC20代币转账需要以太坊账户,需提前准备:

  • 钱包地址:接收代币的目标地址。
  • 发送方私钥:用于签名交易(注意:私钥需妥善保管,切勿泄露)。
  • ETH余额:发送方地址需有足够ETH支付矿工费(Gas),因为ERC20转账本质是以太坊上的合约调用交易。

ERC20代币转账核心原理

ERC20代币的转账并非直接转移代币,而是通过调用代币合约的transfer函数实现的,代币合约需遵循ERC20标准,定义了transfer函数的接口:

function transfer(address recipient, uint256 amount) external returns (bool);

参数说明:

  • recipient:接收代币的地址。
  • amount:转账代币数量(注意:ERC20代币通常有18位小数,需按实际精度处理)。

调用transfer函数时,需向以太坊网络发送一笔交易,交易中包含:

  • 接收方地址(代币合约地址)。
  • 调用的函数名(transfer)。
  • 函数参数(接收地址和转账数量)。
  • 发送方签名(由私钥生成)。

Python实现ERC20代币转账

初始化Web3连接

使用Web3.py连接到以太坊节点:

from web3 import Web3
# 初始化Web3实例
infura_url = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
w3 = Web3(Web3.HTTPProvider(infura_url))
# 检查连接是否成功
print(f"连接状态: {w3.is_connected()}")

定义代币合约ABI与地址

ERC20合约的ABI(Application Binary Interface)定义了函数接口,transfer函数的ABI片段如下:

erc20_abi = [
    {
        "constant": False,
        "inputs": [
            {"name": "_to", "type": "address"},
            {"name": "_value", "type": "uint256"}
        ],
        "name": "transfer",
        "outputs": [{"name": "", "type": "bool"}],
        "type": "function"
    }
]

代币地址需提前确认,例如USDT(主网)地址为0xdAC17F958D2ee523a2206206994597C13D831ec7

加载合约实例

使用合约地址和ABI加载合约实例:

token_address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"  # USDT地址
contract = w3.eth.contract(address=token_address, abi=erc20_abi)

构建转账交易

调用transfer函数前,需构建交易数据,核心步骤包括:

  • 确定转账数量:ERC20代币通常有18位小数,需将实际数量乘以10^18转换为合约中的整数,例如转账100 USDT,数量为100 * 10**18
  • 获取Nonce:发送方账户的交易计数器,用于防止重放攻击。
  • 估算Gas:计算交易所需的Gas限制(Gas Limit)和Gas价格(Gas Price)。
# 发送方配置
sender_private_key = "YOUR_PRIVATE_KEY"  # 替换为发送方私钥
sender_address = "0xYourSenderAddress"    # 替换为发送方地址
# 接收方配置
receiver_address = "0xYourReceiverAddress"  # 替换为接收方地址
# 转账数量(假设代币精度为18位,转账100个代币)
amount = 100 * 10**18
# 获取Nonce
nonce = w3.eth.get_transaction_count(sender_address)
# 估算Gas
try:
    gas_estimate = contract.functions.transfer(receiver_address, amount).estimate_gas({'from': sender_address})
    print(f"预估Gas: {gas_estimate}")
except Exception as e:
    print(f"Gas估算失败: {e}")
    gas_estimate = 300000  # 手动设置默认Gas Limit(ERC20转账通常约6万Gas)
# 设置Gas Price(根据网络情况调整,单位:Gwei)
gas_price = w3.to_wei(20, 'gwei')  # 20 Gwei
# 构建交易
transaction = contract.functions.transfer(receiver_address, amount).build_transaction({
    'from': sender_address,
    'nonce': nonce,
    'gas': gas_estimate,
    'gasPrice': gas_price,
})

签名并发送交易

使用发送方私钥对交易进行签名,然后发送到以太坊网络:

# 签名交易
signed_txn = w3.eth.account.sign_transaction(transaction, sender_private_key)
# 发送交易
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
print(f"交易哈希: {w3.to_hex(tx_hash)}")
# 等待交易上链
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"交易回执: {receipt}")

完整代码示例

将上述步骤整合为完整代码:

from web3 import Web3
def transfer_erc20():
    # 初始化Web3
    infura_url = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
    w3 = Web3(Web3.HTTPProvider(infura_url))
    if not w3.is_connected():
        print("连接以太坊节点失败")
        return
    # 代币配置(USDT)
    token_address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"
    erc20_abi = [
        {
            "constant": False,
            "inputs": [{"name": "_to", "type": "address"}, {"name": "_value", "type": "uint256"}],
            "name": "transfer",
            "outputs": [{"name": "", "type": "bool"}],
            "type": "function"
        }
    ]
    contract = w3.eth.contract(address=token_address, abi=erc20_abi)
    # 账户配置
    sender_private_key = "YOUR_PRIVATE_KEY"
    sender_address = "0xYourSenderAddress"
    receiver_address = "0xYourReceiverAddress"
    # 转账数量(100 USDT,精度18位)
    amount = 100 * 10**18
    try:
        # 获取Nonce
        nonce = w3.eth.get_transaction_count(sender_address)
        # 估算Gas
        gas_estimate = contract.functions.transfer(receiver_address, amount).estimate_gas({'from': sender_address})
        gas_price = w3.to_wei(20, 'gwei')  # 20 Gwei
        # 构建交易
        transaction = contract.functions.transfer(receiver_address, amount).build_transaction({
            'from': sender_address,
            'nonce': nonce,
   
随机配图
'gas': gas_estimate, 'gasPrice': gas_price, }) # 签名并发送 signed_txn = w3.eth.account.sign_transaction(transaction, sender_private_key) tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) print(f"交易哈希: {w3.to_hex(tx_hash)}") # 等待

本文由用户投稿上传,若侵权请提供版权资料并联系删除!