GCloudHSMWallet
Documentation for eth_defi.gcloud_hsm_wallet.GCloudHSMWallet Python class.
- class GCloudHSMWallet[source]
HSM-backed wallet for secure transaction signing, on Google Cloud.
An HSM wallet uses a Google Cloud KMS key for secure key management and transaction signing, providing enhanced security compared to plaintext private keys
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
Configuration can be provided either through environment variables or explicitly in the constructor
Unlike
HotWallet
, this implementation does not expose private keys as they are securely stored in Cloud HSM. All signing operations are performed remotely in the HSM.Example using environment variables:
# Assumes required environment variables are set: # GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_REGION, KEY_RING, # KEY_NAME, GCP_CREDENTIALS_STRING from web3 import Web3 from eth_defi.trace import assert_transaction_success_with_explanation web3 = Web3(Web3.HTTPProvider('http://localhost:8545')) wallet = HSMWallet() # Uses env vars for configuration wallet.sync_nonce(web3) # Send a simple ETH transfer tx = { "to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "from": wallet.address, "value": web3.to_wei(0.1, "ether"), "gas": 21000, "gasPrice": web3.eth.gas_price, "chainId": web3.eth.chain_id, "data": "0x", } signed_tx = wallet.sign_transaction_with_new_nonce(tx) tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction) assert_transaction_success_with_explanation(web3, tx_hash)
Example with explicit configuration:
from web3_google_hsm.config import BaseConfig import json config = BaseConfig( project_id='my-project', location_id='us-east1', key_ring_id='eth-keys', key_id='signing-key' ) credentials = json.loads(os.environ["GCP_CREDENTIALS_STRING"]) wallet = HSMWallet(config=config, credentials=credentials) wallet.sync_nonce(web3)
- Required environment variables if no config/credentials provided:
GOOGLE_CLOUD_PROJECT: GCP project ID
GOOGLE_CLOUD_REGION: GCP region (e.g., us-east1)
KEY_RING: Name of the key ring in Cloud KMS
KEY_NAME: Name of the key in the key ring
GCP_CREDENTIALS_STRING: Service account credentials as JSON string
Note
This class is not thread safe. If multiple threads try to sign transactions at the same time, nonce tracking may be lost.
Attributes summary
Get the Ethereum address associated with the HSM key.
Methods summary
__init__
([config, credentials])Initialize HSM wallet with Google Cloud KMS configuration and credentials.
Get the next available nonce for transaction signing.
create_for_testing
(web3[, config, ...])Creates a new HSM wallet for testing and seeds it with ETH.
fill_in_gas_price
(web3, tx)Fill in gas price fields for a transaction.
Get the main Ethereum address for this wallet.
Get the native currency balance (ETH, BNB, MATIC) of the wallet.
sign_bound_call_with_new_nonce
(func[, ...])Signs a bound Web3 Contract call.
Sign a transaction using HSM and allocate a new nonce.
sync_nonce
(web3)Initialize the current nonce from on-chain data.
transact_with_contract
(func, *args, **kwargs)Call a contract function using HSM signing.
- __init__(config=None, credentials=None)[source]
Initialize HSM wallet with Google Cloud KMS configuration and credentials.
The wallet can be initialized either with explicit configuration via BaseConfig and credentials, or using environment variables. If neither is provided, it will attempt to load both configuration and credentials from environment variables.
- Args:
config: Optional BaseConfig instance containing GCP project details and key information credentials: Optional dictionary containing GCP service account credentials
- property address: eth_typing.evm.HexAddress
Get the Ethereum address associated with the HSM key.
- sync_nonce(web3)[source]
Initialize the current nonce from on-chain data.
- Args:
web3: Web3 instance connected to an Ethereum node
- Parameters
web3 (web3.main.Web3) –
- Return type
None
- allocate_nonce()[source]
Get the next available nonce for transaction signing.
Ethereum tx nonces are a counter. Each time this method is called, it returns the current nonce value and increments the counter.
- Returns:
int: Next available nonce
- Raises:
AssertionError: If nonce hasn’t been synced yet
- Return type
- sign_transaction_with_new_nonce(tx)[source]
Sign a transaction using HSM and allocate a new nonce.
Example:
web3 = Web3(Web3.HTTPProvider('http://localhost:8545')) wallet = HSMWallet() # Using env vars wallet.sync_nonce(web3) signed_tx = wallet.sign_transaction_with_new_nonce({ "to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "from": wallet.address, "value": web3.to_wei(0.1, "ether"), "gas": 21000, "gasPrice": web3.eth.gas_price, "chainId": web3.eth.chain_id, "data": "0x", }) tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
- Args:
- tx: Ethereum transaction data as a dict
This is modified in-place to include nonce
- Returns:
SignedTransactionWithNonce containing the signed transaction and metadata
- Raises:
Exception: If transaction signing fails in the HSM
- Parameters
tx (dict) –
- Return type
- sign_bound_call_with_new_nonce(func, tx_params=None, web3=None, fill_gas_price=False)[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)
- Args:
func: Web3 contract function that has its arguments bound tx_params: Transaction parameters like gas web3: Optional Web3 instance for gas estimation fill_gas_price: Whether to fill gas price automatically
- Returns:
SignedTransactionWithNonce containing the signed contract call
- Parameters
- Return type
- get_native_currency_balance(web3)[source]
Get the native currency balance (ETH, BNB, MATIC) of the wallet.
Useful to check if you have enough cryptocurrency for gas fees.
- Args:
web3: Web3 instance
- Returns:
Current balance in ether units as Decimal
- Parameters
web3 (web3.main.Web3) –
- Return type
- transact_with_contract(func, *args, **kwargs)[source]
Call a contract function using HSM signing.
Construct a tx payload ready for web3.eth.send_raw_transaction, signed using the HSM key
Remember to call
sync_nonce()
before calling this method
Example:
# Approve USDC deposit to a vault contract deposit_amount = 500 * 10**6 # 500 USDC signed_tx = wallet.transact_with_contract( usdc.contract.functions.approve, Web3.to_checksum_address(vault.rebalance_address), deposit_amount ) tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction) assert_transaction_success_with_explanation(web3, tx_hash)
Chain ID management:
# Example with specific chain ID for cross-chain deployment signed_tx = wallet.transact_with_contract( contract.functions.initialize, owner_address, chainId=137 # Polygon mainnet )
- Args:
func: Contract function to call *args: Arguments to pass to the contract function **kwargs: Additional arguments including transaction overrides
- Returns:
Signed transaction ready for broadcasting
- Raises:
ValueError: If contract function is not properly initialized Exception: If transaction signing fails
- Parameters
- Return type
- static create_for_testing(web3, config=None, credentials=None, eth_amount=99)[source]
Creates a new HSM wallet for testing and seeds it with ETH.
This is a test helper that: 1. Creates a new HSM wallet 2. Gets ETH from the first test account 3. Initializes the nonce
Example:
# For local testing with environment variables web3 = Web3(Web3.HTTPProvider('http://localhost:8545')) wallet = HSMWallet.create_for_testing(web3) # For testing with specific config and credentials config = BaseConfig(...) credentials = json.loads(os.environ["GCP_CREDENTIALS_STRING"]) wallet = HSMWallet.create_for_testing(web3, config, credentials)
- Args:
web3: Web3 instance connected to a test node config: Optional HSM configuration credentials: Optional GCP credentials dictionary eth_amount: Amount of ETH to seed the wallet with (default: 99)
- Returns:
Initialized and funded HSM wallet ready for testing
- Parameters
- Return type
- static fill_in_gas_price(web3, tx)[source]
Fill in gas price fields for a transaction.
Estimates raw transaction gas usage
Uses web3 methods to get the gas value fields
Supports different backends (legacy, EIP-1559)
Queries values from the node
Note
Mutates
tx
in place.Note
Before calling this method, you need to set
gas
andchainId
fields oftx
.Example:
# Send small amount of ETH using HSM wallet tx_data = { "chainId": web3.eth.chain_id, "from": wallet.address, "to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "value": Web3.to_wei(Decimal("0.1"), "ether"), "gas": 21000, } # Fill in optimal gas values wallet.fill_in_gas_price(web3, tx_data) signed_tx = wallet.sign_transaction_with_new_nonce(tx_data) # Broadcast the transaction tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
- Args:
web3: Web3 instance tx: Transaction dictionary to update with gas values
- Returns:
Updated transaction dictionary with gas fields