title: 6. 部署合约 tags: web3py provider wallet contract create frontend web Ethers极简入门: 6. 部署合约 WTF Academy社群: 官网 wtf.academy | WTF Solidity教程 | discord | 微信群申请 这一讲,我们将介绍 中的合约部署过程,并以部署一个合约为例帮助大家理解本节内容。我们将介绍 中的合约工厂 类型,并利用它部署合约。 部署智能合约 在以太坊上,智能合约的部署是一种特殊的交易:将编译智能合约得到的字节码发送到0地址。如果这个合约的构造函数有参数的话,需要利用 将参数编码为字节码,然后附在在合约字节码的尾部一起发送。
title: 6. 部署合约 tags: - web3py - provider - wallet - contract - create - frontend - web
WTF Academy社群: 官网 wtf.academy | WTF Solidity教程 | discord | 微信群申请
这一讲,我们将介绍web3.py中的合约部署过程,并以部署一个合约为例帮助大家理解本节内容。我们将介绍we3py中的合约工厂ContractFactory类型,并利用它部署合约。
在以太坊上,智能合约的部署是一种特殊的交易:将编译智能合约得到的字节码发送到0地址。如果这个合约的构造函数有参数的话,需要利用abi.encode将参数编码为字节码,然后附在在合约字节码的尾部一起发送。对于ABI编码的介绍见WTF Solidity极简教程第27讲 ABI编码。
web3py拥有合约工厂ContractFactory类型,方便开发者部署合约。你可以利用合约abi,编译得到的字节码bytecode来创建合约工厂实例,为部署合约做准备。
#构造合约工厂 contract_factory = w3.eth.contract(abi=abi, bytecode=bytecode)
注意:其中w3为我们提前定义的provider,如果合约的构造函数有参数,那么在abi中必须包含构造函数。
在创建好合约工厂实例之后,可以调用它的constructor函数并传入合约构造函数的参数args来构建部署交易信息:
# 部署合约 tx_hash = contract_factory.constructor(args).transact() # 等待交易完成 tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) #打印合约地址 contract_address = tx_receipt['contractAddress']
ERC20标准代币合约的介绍见WTF Solidity极简教程第31讲 ERC20。
创建provider和wallet变量。
from eth_account import Account from web3 import Web3, contract # 连利用infura提供的节点连接到以太坊测试网 infura_url = "https://goerli.infura.io/v3/22b26b228b004ccc9325066db8b5c468" w3 = Web3(Web3.HTTPProvider(infura_url)) # 创建钱包对象 private_key = "e08ca922fedbc3d37fa677f1d8f7e8fcbe42d031186bcbbc763d20cbdac81f9d" wallet = Account.from_key(private_key)
准备ERC20合约的字节码和ABI。因为ERC20的构造函数含有参数,因此我们必须把它包含在ABI中。合约的abi可以直接在remix编译界面电机abi按钮复制,字节码可以从remix的编译面板中点击Bytecode按钮,把它复制下来,其中"object"字段对应的数据就是字节码。如果部署在链上的合约,你可以在etherscan的Contract页面的Contract Creation Code中找到。
# ERC20的合约abi abi = [{"inputs": [{"internalType": "string","name": "name_","type": "string"}, {"internalType": "string","name": "symbol_","type": "string"}], "stateMutability": "nonpayable","type": "constructor"}, {"anonymous": False,"inputs": [{"indexed": True,"internalType": "address","name": "owner","type": "address"},{"indexed": True,"internalType": "address","name": "spender","type": "address"},{"indexed": False,"internalType": "uint256","name": "value","type": "uint256"}],"name": "Approval","type": "event"},{"anonymous": False,"inputs": [{"indexed": True,"internalType": "address","name": "from","type": "address"},{"indexed": True,"internalType": "address","name": "to","type": "address"},{"indexed": False,"internalType": "uint256","name": "value","type": "uint256"}],"name": "Transfer","type": "event"},{"inputs": [{"internalType": "address","name": "","type": "address"},{"internalType": "address","name": "","type": "address"}],"name": "allowance","outputs": [{"internalType": "uint256","name": "","type": "uint256"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "address","name": "spender","type": "address"},{"internalType": "uint256","name": "amount","type": "uint256"}],"name": "approve","outputs": [{"internalType": "bool","name": "","type": "bool"}],"stateMutability": "nonpayable","type": "function"},{"inputs": [{"internalType": "address","name": "","type": "address"}],"name": "balanceOf","outputs": [{"internalType": "uint256","name": "","type": "uint256"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "uint256","name": "amount","type": "uint256"}],"name": "burn","outputs": [],"stateMutability": "nonpayable","type": "function"},{"inputs": [],"name": "decimals","outputs": [{"internalType": "uint8","name": "","type": "uint8"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "uint256","name": "amount","type": "uint256"}],"name": "mint","outputs": [],"stateMutability": "nonpayable","type": "function"},{"inputs": [],"name": "name","outputs": [{"internalType": "string","name": "","type": "string"}],"stateMutability": "view","type": "function"},{"inputs": [],"name": "symbol","outputs": [{"internalType": "string","name": "","type": "string"}],"stateMutability": "view","type": "function"},{"inputs": [],"name": "totalSupply","outputs": [{"internalType": "uint256","name": "","type": "uint256"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "address","name": "recipient","type": "address"},{"internalType": "uint256","name": "amount","type": "uint256"}],"name": "transfer","outputs": [{"internalType": "bool","name": "","type": "bool"}],"stateMutability": "nonpayable","type": "function"},{"inputs": [{"internalType": "address","name": "sender","type": "address"},{"internalType": "address","name": "recipient","type": "address"},{"internalType": "uint256","name": "amount","type": "uint256"}],"name": "transferFrom","outputs": [{"internalType": "bool","name": "","type": "bool"}],"stateMutability": "nonpayable","type": "function"}] # 合约ABI # 填入合约字节码,在remix中,你可以在两个地方找到Bytecode # 1. 编译面板的Bytecode按钮 #2. 文件面板artifact文件夹下与合约同名的json文件中 # 里面"bytecode"属性下的"object"字段对应的数据就是Bytecode。 bytecode = '60806040526012600560006101000a81548160ff021916908360ff1602179055503480156200002d57600080fd5b506040516200111b3803806200111b8339818101604052810190620000539190620001af565b81600390805190602001906200006b9291906200008d565b508060049080519060200190620000849291906200008d565b50505062000392565b8280546200009b90620002b7565b90600052602060002090601f016020900481019282620000bf57600085556200010b565b82601f10620000da57805160ff19168380011785556200010b565b828001600101855582156200010b579182015b828111156200010a578251825591602001919060010190620000ed565b5b5090506200011a91906200011e565b5090565b5b80821115620001395760008160009055506001016200011f565b5090565b6000620001546200014e846200024b565b62000222565b9050828152602081018484840111156200016d57600080fd5b6200017a84828562000281565b509392505050565b600082601f8301126200019457600080fd5b8151620001a68482602086016200013d565b91505092915050565b60008060408385031215620001c357600080fd5b600083015167ffffffffffffffff811115620001de57600080fd5b620001ec8582860162000182565b925050602083015167ffffffffffffffff8111156200020a57600080fd5b620002188582860162000182565b9150509250929050565b60006200022e62000241565b90506200023c8282620002ed565b919050565b6000604051905090565b600067ffffffffffffffff82111562000269576200026862000352565b5b620002748262000381565b9050602081019050919050565b60005b83811015620002a157808201518184015260208101905062000284565b83811115620002b1576000848401525b50505050565b60006002820490506001821680620002d057607f821691505b60208210811415620002e757620002e662000323565b5b50919050565b620002f88262000381565b810181811067ffffffffffffffff821117156200031a576200031962000352565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b610d7980620003a26000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c806342966c681161007157806342966c681461016857806370a082311461018457806395d89b41146101b4578063a0712d68146101d2578063a9059cbb146101ee578063dd62ed3e1461021e576100a9565b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100fc57806323b872dd1461011a578063313ce5671461014a575b600080fd5b6100b661024e565b6040516100c39190610aee565b60405180910390f35b6100e660048036038101906100e19190610a08565b6102dc565b6040516100f39190610ad3565b60405180910390f35b6101046103ce565b6040516101119190610b10565b60405180910390f35b610134600480360381019061012f91906109b9565b6103d4565b6040516101419190610ad3565b60405180910390f35b610152610583565b60405161015f9190610b2b565b60405180910390f35b610182600480360381019061017d9190610a44565b610596565b005b61019e60048036038101906101999190610954565b61066d565b6040516101ab9190610b10565b60405180910390f35b6101bc610685565b6040516101c99190610aee565b60405180910390f35b6101ec60048036038101906101e79190610a44565b610713565b005b61020860048036038101906102039190610a08565b6107ea565b6040516102159190610ad3565b60405180910390f35b6102386004803603810190610233919061097d565b610905565b6040516102459190610b10565b60405180910390f35b6003805461025b90610c74565b80601f016020809104026020016040519081016040528092919081815260200182805461028790610c74565b80156102d45780601f106102a9576101008083540402835291602001916102d4565b820191906000526020600020905b8154815290600101906020018083116102b757829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516103bc9190610b10565b60405180910390a36001905092915050565b60025481565b600081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546104629190610bb8565b92505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546104b79190610bb8565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461050c9190610b62565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516105709190610b10565b60405180910390a3600190509392505050565b600560009054906101000a900460ff1681565b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546105e49190610bb8565b9250508190555080600260008282546105fd9190610bb8565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516106629190610b10565b60405180910390a350565b60006020528060005260406000206000915090505481565b6004805461069290610c74565b80601f01602080910402602001604051908101604052809291908181526020018280546106be90610c74565b801561070b5780601f106106e05761010080835404028352916020019161070b565b820191906000526020600020905b8154815290600101906020018083116106ee57829003601f168201915b505050505081565b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107619190610b62565b92505081905550806002600082825461077a9190610b62565b925050819055503373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516107df9190610b10565b60405180910390a350565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461083a9190610bb8565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461088f9190610b62565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516108f39190610b10565b60405180910390a36001905092915050565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008135905061093981610d15565b92915050565b60008135905061094e81610d2c565b92915050565b60006020828403121561096657600080fd5b60006109748482850161092a565b91505092915050565b6000806040838503121561099057600080fd5b600061099e8582860161092a565b92505060206109af8582860161092a565b9150509250929050565b6000806000606084860312156109ce57600080fd5b60006109dc8682870161092a565b93505060206109ed8682870161092a565b92505060406109fe8682870161093f565b9150509250925092565b60008060408385031215610a1b57600080fd5b6000610a298582860161092a565b9250506020610a3a8582860161093f565b9150509250929050565b600060208284031215610a5657600080fd5b6000610a648482850161093f565b91505092915050565b610a7681610bfe565b82525050565b6000610a8782610b46565b610a918185610b51565b9350610aa1818560208601610c41565b610aaa81610d04565b840191505092915050565b610abe81610c2a565b82525050565b610acd81610c34565b82525050565b6000602082019050610ae86000830184610a6d565b92915050565b60006020820190508181036000830152610b088184610a7c565b905092915050565b6000602082019050610b256000830184610ab5565b92915050565b6000602082019050610b406000830184610ac4565b92915050565b600081519050919050565b600082825260208201905092915050565b6000610b6d82610c2a565b9150610b7883610c2a565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610bad57610bac610ca6565b5b828201905092915050565b6000610bc382610c2a565b9150610bce83610c2a565b925082821015610be157610be0610ca6565b5b828203905092915050565b6000610bf782610c0a565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015610c5f578082015181840152602081019050610c44565b83811115610c6e576000848401525b50505050565b60006002820490506001821680610c8c57607f821691505b60208210811415610ca057610c9f610cd5565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b610d1e81610bec565b8114610d2957600080fd5b50565b610d3581610c2a565b8114610d4057600080fd5b5056fea264697066735822122054793defcdde024a27f6e3fee0a20e3752f26b010918f9abf6225be94424006864736f6c63430008040033'


创建合约工厂ContractFactory实例。
# 创建合约工厂 contract_factory = w3.eth.contract(abi=abi, bytecode=bytecode)
调用工厂合约的construct()函数并填入构造函数的参数(代币名称和代号),部署ERC20代币合约并获得合约实例。在build_transaction中构建参数:
from:表示交易发送方的以太坊地址。这是用于支付交易费用的账户。nonce:表示发送方账户的交易计数器。它确保每个交易都具有唯一的标识符,并按照顺序执行。gas:表示交易所能消耗的最大燃气数量。gasPrice:表示以太坊网络中每单位燃气的价格。# 部署合约 tx_hash = contract_factory.constructor("WTF Token", "WTF").build_transaction({ 'from': wallet.address, 'nonce': w3.eth.get_transaction_count(wallet.address), 'gas': 2000000, 'gasPrice': w3.to_wei('50', 'gwei') }) signed_tx = wallet.signTransaction(tx_hash) tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) # 获取部署的合约地址 contract_address = tx_receipt.contractAddress print("合约部署成功,合约地址为:", contract_address)

在合约上链后,调用name()和symbol()函数打印代币名称和代号,然后调用mint()函数给自己铸造10,000枚代币。
# 调用合约的name()和symbol()函数打印代币名称和代号 token_name = contract_instance.functions.name().call() token_symbol = contract_instance.functions.symbol().call() print("代币名称:", token_name) print("代币代号:", token_symbol) # 将整数10000转换为uint256类型 amount = 10000 # 调用mint()函数给自己铸造10,000枚代币 tx_hash = contract_instance.functions.mint(amount).build_transaction({ 'from': wallet.address, 'nonce': w3.eth.get_transaction_count(wallet.address), 'gas': 2000000, 'gasPrice': w3.to_wei('50', 'gwei') }) signed_tx = wallet.signTransaction(tx_hash) tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print("铸造代币成功") # 查询铸造后账户的WTF代币余额 balance = contract_instance.functions.balanceOf(wallet.address).call() print("WTF代币余额:", balance)

调用transfer()函数,给Vitalik转账1,000枚代币。
# 调用transfer()函数,给Vitalik转账1000代币 tx_hash = contract_instance.functions.transfer("vitalik.eth", 1000).build_transaction({ 'from': wallet.address, 'nonce': w3.eth.get_transaction_count(wallet.address), 'gas': 2000000, 'gasPrice': w3.to_wei('50', 'gwei') }) signed_tx = wallet.signTransaction(tx_hash) tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print("等待交易上链") # 查询Vitalik钱包中的代币余额 vitalik_balance = contract_instance.functions.balanceOf("vitalik.eth").call() print(f"Vitalik钱包中的代币余额: {vitalik_balance}")

这一讲我们介绍了web3.py中的合约工厂ContractFactory类型,利用它部署了一个ERC20代币合约,并给Vitalik转账了1,000枚代币。