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() and sign_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

address

Get the Ethereum address associated with the HSM key.

Methods summary

__init__([config, credentials])

Initialize HSM wallet with Google Cloud KMS configuration and credentials.

allocate_nonce()

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_main_address()

Get the main Ethereum address for this wallet.

get_native_currency_balance(web3)

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_transaction_with_new_nonce(tx)

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

Parameters
property address: eth_typing.evm.HexAddress

Get the Ethereum address associated with the HSM key.

get_main_address()[source]

Get the main Ethereum address for this wallet.

Return type

eth_typing.evm.HexAddress

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

int

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

eth_defi.hotwallet.SignedTransactionWithNonce

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
  • func (web3.contract.contract.ContractFunction) –

  • tx_params (Optional[dict]) –

  • web3 (Optional[web3.main.Web3]) –

Return type

eth_defi.hotwallet.SignedTransactionWithNonce

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

decimal.Decimal

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
  • func (web3.contract.contract.ContractFunction) –

  • args (Any) –

  • kwargs (Any) –

Return type

eth_defi.hotwallet.SignedTransactionWithNonce

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
  • web3 (web3.main.Web3) –

  • config (Optional[web3_google_hsm.config.BaseConfig]) –

  • credentials (Optional[dict]) –

  • eth_amount (int) –

Return type

eth_defi.gcloud_hsm_wallet.GCloudHSMWallet

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 and chainId fields of tx.

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

Parameters
  • web3 (web3.main.Web3) –

  • tx (dict) –

Return type

dict