账户、地址与钱包

单击顶部栏上的🚀 -> Binder在线运行此示例!

准备

本部分将准备web3对象与私钥private_key,提供后文代码所需的变量。

# 领取 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()

# 新建w3对象以便演示API的用法
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 )。

注意:手动签署交易相当繁琐。请参阅钱包部分了解如何使用钱包签名和发送交易。或者您可以参考从头构建交易了解如何正确手动签名交易。

更多文档: w3.account是一个cfx_account.Account对象,其继承自eth_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).rawTransaction.hex()}")
account address: cfxtest:aat00gxdfxun3y9a4v6azn7ew0maj9vkta4a65cdkm
account private key: 0xb4a8134094df8b7544e6787da1ee92ba94ad68e2cbbe1141a3cabc3307778e32
signed raw tx: 0xf867e301843b9aca00825208940000000000000000000000000000000000000000018064018001a0c2ac330c9617078efdc6240d7ddb3aa7bc1ef0483625ee12c1f6c1ed66a5b3cca0657695c1012f6774e9eabd679e9f1fc1a14345f13c7494da43facb5b0ca14f25

怎样创建一个LocalAccount对象

以下是创建LocalAccount对象的几种方法:

  • 通过使用 w3.account.create 生成随机密钥

  • 通过使用 w3.account.from_key 从已有密钥中创建

  • 通过使用 w3.account.from_mnemonic 从助记词创建

  • 通过使用 w3.account.decrypt 从密钥存储文件中创建

下面是使用上述 API 的示例:

# 随机生成
# 这个 API 会从操作系统中收集随机性来生成账户,参数可以提供额外的熵
generated_account = w3.account.create("extra_entropy")

# 从已有密钥中生成
generated_account = w3.account.from_key("0xb25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364")

# 从助记词中生成
# "m/44'/503'/0'/0/0" 是 Conflux 默认派生路径
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"
)

# 由keystore文件中生成
# 当然,也可以使用 `w3.account.encrypt` 来获取一个keystore 文件对应的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" 代表该地址为测试网地址
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']

钱包

我们使用钱包中间件(w3.wallet)来帮助我们签名发送交易。如果某未签名交易的from账户已添加至w3.wallet中,它将对通过w3.cfx.send_transaction发送的未签名交易进行签名。

wallet中间件的行为与web3.pyconstruct_sign_and_send_raw_middleware基本一致,但提供了更多功能。例如,我们可以使用w3.wallet.add_accountw3.wallet.add_accountsw3.wallet.pop来动态添加或删除帐户。

# wallet是 conflux_web3 的中间件,可向其中添加 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('0x0eaef189cce96acaf1228176f07ec41a352f7e6ff450bffecd85240ae3473e21'),
 'index': 0,
 'blockHash': HexBytes('0x9fbaa224b1aef6d68fa03cdf0978e2246bfce06a23e4a0ac542825aa99f980a7'),
 'epochNumber': 109112221,
 'from': 'cfxtest:aat00gxdfxun3y9a4v6azn7ew0maj9vkta4a65cdkm',
 'to': 'cfxtest:aat00gxdfxun3y9a4v6azn7ew0maj9vkta4a65cdkm',
 'gasUsed': 21000,
 'gasFee': 21000000000000 Drip,
 'contractCreated': None,
 'logs': [],
 'logsBloom': HexBytes('0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
 'stateRoot': HexBytes('0x178a81f8f52946355476db908c2ab75321e763f692f4f1cd7e1ebd268c04fa79'),
 '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是一个地址类型的变量,但可以使用LocalAccount对象进行设置。在这种情况下,该LocalAccount将同时添加到钱包中。

w3.cfx.default_account = random_account

相当于

w3.cfx.default_account = random_account.address
w3.wallet.add_account(random_account)