账户、地址和钱包#
点击顶部栏的 🚀 -> Binder 在线运行此示例!
准备工作#
本部分准备了在后续文档中使用的 web3 实例和密钥 private_key。
# claim 1000 CFX
from pprint import pprint
from conflux_web3 import Web3
w3_ = Web3(Web3.HTTPProvider("https://test.confluxrpc.com"))
acct = w3_.account.create()
w3_.cfx.default_account = acct
faucet = w3_.cfx.contract(name="Faucet")
tx_receipt = faucet.functions.claimCfx().transact().executed()
# we use a new w3 object for the following part
w3 = Web3(Web3.HTTPProvider("https://test.confluxrpc.com"))
private_key: str = acct.key.hex()
账户和地址#
在web3中,拥有一个账户通常意味着知道一个密钥,或者说私钥。虽然私钥应该保密,但是地址可以公开。地址是从私钥单向派生出的字符串,用于标识一个账户。不同的区块链可能采用不同的方法来派生地址,例如比特币和以太坊使用不同的方法来生成账户地址。在Conflux中,地址使用CIP-37定义的base32格式进行编码。
LocalAccount 对象#
w3.account 是一个工厂,用于生成 LocalAccount 对象(例如 random_account),这些对象可以用来签名交易。
注意:手动签名交易是一个繁琐的过程。请参考 wallet 部分了解如何使用钱包来签名和发送交易。或者您可以参考 construct_transaction_from_scratch 来了解如何正确地手动签名交易。
更多文档:
w3.account是一个继承自eth_account.Account的cfx_account.Account对象,其大部分API与 eth_account 保持一致。
random_account = w3.account.from_key(private_key)
print(f"account address: {random_account.address}")
print(f"account private key: {private_key}")
transaction = {
'to': w3.address.zero_address(),
'nonce': 1,
'value': 1,
'gas': 21000,
'gasPrice': 10**9,
'storageLimit': 0,
'epochHeight': 100,
'chainId': 1
}
print(f"signed raw tx: {random_account.sign_transaction(transaction).raw_transaction.hex()}")
account address: cfxtest:aak610kbgm17u1knr11xjs4b9cgehft3uy07v7w3dy
account private key: 0xdd8fd18afdcebd8801f9c6a04812ac6e8f5ab31d9c50de51eda0581291b61d61
signed raw tx: 0xf867e301843b9aca00825208940000000000000000000000000000000000000000018064018001a0541786f46b98237f85b5d26bb0844fc6a5596c5856c217f257abbcf2a156f9f1a02f07e5ca33b4b0d235b39b8e116f792a76e1121a74e15b4cb5f8e4f6f1bc52ce
如何创建 LocalAccount 对象#
创建 LocalAccount 对象有以下几种方式:
使用
w3.account.create随机创建使用
w3.account.from_key从已有私钥创建使用
w3.account.from_mnemonic从助记词创建使用
w3.account.decrypt从密钥库文件创建
以下是这些API的使用示例:
# from random
# this api will collect randomness from operating system to generate the account,
# the parameter could provide extra entropy
generated_account = w3.account.create("extra_entropy")
# from existed key
generated_account = w3.account.from_key("0xb25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364")
# from mnemonic
# "m/44'/503'/0'/0/0" is the default Conflux derive path
generated_account = w3.account.from_mnemonic(
"health embark april buyer eternal leopard want before nominee head thing tackle",
passphrase="",
account_path="m/44'/503'/0'/0/0"
)
# from keystore
# and of course, you can use `w3.account.encrypt` to get a keystore file json
keystore = {
"version": 3,
"id": "db029583-f1bd-41cc-aeb5-b2ed5b33227b",
"address": "1cad0b19bb29d4674531d6f115237e16afce377c",
"crypto": {
"ciphertext": "3198706577b0880234ecbb5233012a8ca0495bf2cfa2e45121b4f09434187aba",
"cipherparams": {"iv": "a9a1f9565fd9831e669e8a9a0ec68818"},
"cipher": "aes-128-ctr",
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"salt": "3ce2d51bed702f2f31545be66fa73d1467d24686059776430df9508407b74231",
"n": 8192,
"r": 8,
"p": 1,
},
"mac": "cf73832f328f3d5d1e0ec7b0f9c220facf951e8bba86c9f26e706d2df1e34890",
}
}
generated_account = w3.account.decrypt(keystore, password="password")
Conflux 地址#
在 Conflux 中,地址按照 CIP-37 规范使用 base32 格式进行编码。通过地址字面值,你可以直接判断该地址属于哪个网络。
# "cfxtest" marks an address in testnet
assert random_account.address.startswith("cfxtest:")
SDK 返回的地址都被封装为 Base32Address 类。该类提供了便捷的方法来操作 base32 地址,同时 Base32Address 对象也可以像普通的 Python str 对象一样使用。
更多信息请参考 Base32Address 文档。
addr = random_account.address
print(f"the type of addr: {type(addr)}")
# a Base32Address object is also a `str`
assert isinstance(addr, str)
# encode a base32 address from hex address and network_id
# it is also supported to use `w3.address("cfxtest:aatp533cg7d0agbd87kz48nj1mpnkca8be1rz695j4")`
address = w3.address("0x1ecde7223747601823f7535d7968ba98b4881e09", network_id=1)
print(address)
pprint([
address.address_type,
address.network_id,
address.hex_address,
address.verbose_address,
address.abbr,
address.mapped_evm_space_address,
])
the type of addr: <class 'cfx_address.address.Base32Address'>
cfxtest:aatp533cg7d0agbd87kz48nj1mpnkca8be1rz695j4
['user',
1,
'0x1ECdE7223747601823f7535d7968Ba98b4881E09',
'CFXTEST:TYPE.USER:AATP533CG7D0AGBD87KZ48NJ1MPNKCA8BE1RZ695J4',
'cfxtest:aat...95j4',
'0x349f086998cF4a0C5a00b853a0E93239D81A97f6']
钱包#
我们使用 wallet 中间件来帮助签名和发送交易。当通过 w3.cfx.send_transaction 发送未签名交易时,如果交易的 from 地址是 w3.wallet 中的账户,w3.wallet 将会为该交易进行签名。
wallet中间件的行为与web3.py的SignAndSendRawMiddleware类似,但提供了更多功能。例如,我们可以使用w3.wallet.add_account、w3.wallet.add_accounts、w3.wallet.pop来动态添加或移除账户。
# wallet serves as a middleware for conflux_web3 and contains a collection of LocalAccount
assert w3.wallet is w3.middleware_onion["wallet"]
w3.wallet.add_account(random_account)
assert random_account.address in w3.wallet
w3.cfx.send_transaction({
"from": random_account.address,
"to": random_account.address,
"value": 10**18
}).executed()
AttributeDict({'transactionHash': HexBytes('0x563c8e1d944d4e688b619808ddd9e92178881ebfe64f3da7c027922e54ef3d55'),
'index': 0,
'blockHash': HexBytes('0x4e46fe16028137953f5eca7f34ef63e18f323809eadab3137c497764d7cf39de'),
'epochNumber': 109112027,
'from': 'cfxtest:aak610kbgm17u1knr11xjs4b9cgehft3uy07v7w3dy',
'to': 'cfxtest:aak610kbgm17u1knr11xjs4b9cgehft3uy07v7w3dy',
'gasUsed': 21000,
'gasFee': 21000000000000 Drip,
'contractCreated': None,
'logs': [],
'logsBloom': HexBytes('0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
'stateRoot': HexBytes('0x50b523a7e94e9cc3a699c8d2db5402d5f146cddb8e552f6fe8ce697ee26a9bd7'),
'outcomeStatus': 0,
'txExecErrorMsg': None,
'gasCoveredBySponsor': False,
'storageCoveredBySponsor': False,
'storageCollateralized': 0,
'storageReleased': []})
使用 w3.cfx.default_account 向钱包添加账户#
如果设置了 w3.cfx.default_account,当发送交易时如果没有指定 from 字段,该字段将被设置为 w3.cfx.default_account。
w3.cfx.default_account 是一个 Base32Address 类型,但可以使用 LocalAccount 对象来设置。在这种情况下,提供的 LocalAccount 对象会同时被添加到钱包中。
w3.cfx.default_account = random_account
等价于
w3.cfx.default_account = random_account.address
w3.wallet.add_account(random_account)