Account, Address and Wallet
Contents
Account, Address and Wallet¶
Run this example online by clicking 🚀
-> Binder
on the top bar!
Preparation¶
This part prepares the web3
instance and key private_key
to use in the following part of this documentation.
# 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()
Account and Address¶
In web3, typically, owning an account means knowing a secret, or private key. Although private key should be kept secret, address can be revealed. Address is a string one-way derived from the private key, and identifies an account. Different blockchain might adopt different approach to derive an address, e.g. bitcoin and ethereum use different methods to generate account addresses .In Conflux, addresses are encoded in base32 format defined by CIP-37.
LocalAccount
Object¶
w3.account
is a factory which is used to produce LocalAccount
objects (e.g. random_account
). which can be used to sign transactions.
NOTE: it is quite tedious to manually sign a transaction. Refer to wallet part to see how to sign and send a transaction by using wallet. Or you can refer to construct_transaction_from_scratch to see how to manually sign transactions correctly.
More documents:
w3.account
is acfx_account.Account
object inherited frometh_account.Account
, and most of its apis are consistent with 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:aak610kbgm17u1knr11xjs4b9cgehft3uy07v7w3dy
account private key: 0xdd8fd18afdcebd8801f9c6a04812ac6e8f5ab31d9c50de51eda0581291b61d61
signed raw tx: 0xf867e301843b9aca00825208940000000000000000000000000000000000000000018064018001a0541786f46b98237f85b5d26bb0844fc6a5596c5856c217f257abbcf2a156f9f1a02f07e5ca33b4b0d235b39b8e116f792a76e1121a74e15b4cb5f8e4f6f1bc52ce
How to Create a LocalAccount
object¶
There are several ways to create a LocalAccount
object.
from random by using
w3.account.create
from existed key by using
w3.account.from_key
from mnemonic by using
w3.account.from_mnemonic
from keystore by using
w3.account.decrypt
Here are the examples of how to use the above APIs:
# 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 Addresses¶
In Conflux, addresses are encoded in base32 format following CIP-37. You can infer which network the address belongs to simply from the address literal.
# "cfxtest" marks an address in testnet
assert random_account.address.startswith("cfxtest:")
The addresses returned by SDK are all wrapped by class Base32Address
. The class provides convenient methods to operate base32 addresses, but you can also use Base32Address
object as trivial python str
object.
Refer to Base32Address documentation for more information.
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¶
We use a wallet
middleware to help us sign and send transactions. w3.wallet
will sign the unsigned transaction sent via w3.cfx.send_transaction
if the transaction is from
an account in w3.wallet
.
wallet
middleware follows the behaviour ofweb3.py
’sconstruct_sign_and_send_raw_middleware
, but provides more feature. For example, we can usew3.wallet.add_account
,w3.wallet.add_accounts
,w3.wallet.pop
to add or remove accounts dynamically.
# 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': []})
use w3.cfx.default_account
to add account to wallet¶
If w3.cfx.default_account
is set, from
field of the sent transaction will be set to w3.cfx.default_account
if empty.
w3.cfx.default_account
is a Base32Address
, but can be set using a LocalAccount
object. In this case, the provided LocalAccount
object will be added to the wallet at the same time.
w3.cfx.default_account = random_account
is equivalent to
w3.cfx.default_account = random_account.address
w3.wallet.add_account(random_account)