HotWallet
Documentation for eth_defi.hotwallet.HotWallet Python class.
- class HotWallet[source]
Hot wallet for signing transactions effectively.
A hot wallet maintains an plain text private key of an Ethereum address in the process memory using
eth_account.signers.local.LocalAccount
and nonce counter.It is able to sign transactions, including batches, using manual nonce management. See
sync_nonce()
,allocate_nonce()
andsign_transaction_with_new_nonce()
.Signed transactions carry extra debug information with them in
SignedTransactionWithNonce
To use this class with the existing web3.py Contract.functions.myFunc().transact() you can add the private key as the local signing middleware. However you should try to use
sign_bound_call_with_new_nonce()
instead when possible. See alsoeth_defi.middleware.construct_sign_and_send_raw_middleware_anvil()
when working with Anvil.Example:
from eth_account import Account from web3.middleware import construct_sign_and_send_raw_middleware from eth_defi.trace import assert_transaction_success_with_explanation from eth_defi.hotwallet import HotWallet account = Account.create() # Move 1/2 of ETH from the first test account to ours test_account_1 = web3.eth.accounts[0] stash = web3.eth.get_balance(test_account_1) tx_hash = web3.eth.send_transaction({"from": test_account_1, "to": account.address, "value": stash // 2}) assert_transaction_success_with_explanation(web3, tx_hash) # Attach local private key to the web3.py middleware machinery web3.middleware_onion.add(construct_sign_and_send_raw_middleware(account)) # Create a hot wallet instance hot_wallet = HotWallet(account) hot_wallet.sync_nonce(web3) # Use web3.py signing (NOTE: does not correctly increment nonce) # so you need to call hot_wallet.sync_nonce() after the tx has been confirmed tx_hash = usdc.functions.transfer( some_address, 500 * 10**6, ).transact({"from": hot_wallet.address}) assert_transaction_success_with_explanation(web3, tx_hash) hot_wallet.sync_nonce(web3) # Sync nonce again, as the manual management is off
Note
This class is not thread safe. If multiple threads try to sign transactions at the same time, nonce tracking may be lost.
See also how to create private keys from command line.
Attributes summary
Ethereum address of the wallet.
The private key as plain text.
Methods summary
__init__
(account)Create a hot wallet from a local account.
Get the next free available nonce to be used with a transaction.
create_for_testing
(web3[, test_account_n, ...])Creates a new hot wallet and seeds it with ETH from one of well-known test accounts.
fill_in_gas_price
(web3, tx)Fills in the gas value fields for a transaction.
from_private_key
(key)Create a hot wallet from a private key that is passed in as a hex string.
Get the balance of the native currency (ETH, BNB, MATIC) of the wallet.
sign_bound_call_with_new_nonce
(func[, tx_params])Signs a bound Web3 Contract call.
Signs a transaction and allocates a nonce for it.
sync_nonce
(web3)Initialise the current nonce from the on-chain data.
- __init__(account)[source]
Create a hot wallet from a local account.
- Parameters
account (eth_account.signers.local.LocalAccount) –
- property address: eth_typing.evm.HexAddress
Ethereum address of the wallet.
- property private_key: hexbytes.main.HexBytes
The private key as plain text.
- sync_nonce(web3)[source]
Initialise the current nonce from the on-chain data.
- Parameters
web3 (web3.main.Web3) –
- allocate_nonce()[source]
Get the next free available nonce to be used with a transaction.
Ethereum tx nonces are a counter.
Increase the nonce counter
- Return type
- sign_transaction_with_new_nonce(tx)[source]
Signs a transaction and allocates a nonce for it.
Example:
web3 = Web3(mev_blocker_provider) wallet = HotWallet.create_for_testing(web3) # Send some ETH to zero address from # the hot wallet signed_tx = wallet.sign_transaction_with_new_nonce({ "from": wallet.address, "to": ZERO_ADDRESS, "value": 1, "gas": 100_000, "gasPrice": web3.eth.gas_price, }) tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
- Parameters
tx (dict) – Ethereum transaction data as a dict. This is modified in-place to include nonce.
- Returns
A transaction payload and nonce with used to generate this transaction.
- Return type
- sign_bound_call_with_new_nonce(func, tx_params=None)[source]
Signs a bound Web3 Contract call.
Example:
bound_func = busd_token.functions.transfer(user_2, 50*10**18) # Transfer 50 BUDF signed_tx = hot_wallet.sign_bound_call_with_new_nonce(bound_func) web3.eth.send_raw_transaction(signed_tx.rawTransaction)
With manual gas estimation:
approve_call = usdc.contract.functions.approve(quickswap.router.address, raw_amount) gas_estimation = estimate_gas_fees(web3) tx_gas_parameters = apply_gas({"gas": 100_000}, gas_estimation) # approve should not take more than 100k gas signed_tx = hot_wallet.sign_bound_call_with_new_nonce(approve_call, tx_gas_parameters)
See also
- Parameters
- Return type
- get_native_currency_balance(web3)[source]
Get the balance of the native currency (ETH, BNB, MATIC) of the wallet.
Useful to check if you have enough cryptocurrency for the gas fees.
- Parameters
web3 (web3.main.Web3) –
- Return type
- static fill_in_gas_price(web3, tx)[source]
Fills in the gas value fields for a transaction.
Estimates raw transaction gas usage
Uses web3 methods to get the gas value fields for the dict
web3 offers different backends for this
likely queries the values from the node
- static from_private_key(key)[source]
Create a hot wallet from a private key that is passed in as a hex string.
Add the key to web3 signing chain.
Example:
# Generated with openssl rand -hex 32 wallet = HotWallet.from_private_key("0x54c137e27d2930f7b3433249c5f07b37ddcfea70871c0a4ef9e0f65655faf957")
- Parameters
key (str) – 0x prefixed hex string
- Returns
Ready to go hot wallet account
- Return type
- static create_for_testing(web3, test_account_n=0, eth_amount=10)[source]
Creates a new hot wallet and seeds it with ETH from one of well-known test accounts.
Shortcut method for unit testing.
Example:
web3 = Web3(test_provider) wallet = HotWallet.create_for_testing(web3) signed_tx = wallet.sign_transaction_with_new_nonce( { "from": wallet.address, "to": ZERO_ADDRESS, "value": 1, "gas": 100_000, "gasPrice": web3.eth.gas_price, } ) tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction) assert_transaction_success_with_explanation(web3, tx_hash)
- Parameters
web3 (web3.main.Web3) –
- Return type