Skip to content

Example script

This is the script I have used to build and test this module. It works. Trust me :)

import dotenv
from eth_account.messages import encode_defunct
from web3 import Web3

from web3_google_hsm.accounts.gcp_kms_account import GCPKmsAccount
from web3_google_hsm.types.ethereum_types import Signature, Transaction
from rich.console import Console

console = Console()
dotenv.load_dotenv()

w3 = Web3(Web3.HTTPProvider("http://localhost:8545"))
account = GCPKmsAccount()

console.print(f"GCP KMS Account address: {account.address}")

# 1. Test Message Signing and Verification
message = "Hello Ethereum!"
message_hash = encode_defunct(text=message)

# Sign the message
signed_message = account.sign_message(message)
console.print("\nSigned message details:")
console.print(f"R: {signed_message.r.hex()}")
console.print(f"S: {signed_message.s.hex()}")
console.print(f"V: {signed_message.v}")
console.print(f"Full signature: {signed_message.to_hex()}")

# Verify the signature using web3.py
recovered_address = w3.eth.account.recover_message(
    message_hash, vrs=(signed_message.v, signed_message.r, signed_message.s)
)
console.print("\nSignature verification:")
console.print(f"Original address: {account.address}")
console.print(f"Recovered address: {recovered_address}")
console.print(f"Signature valid: {recovered_address.lower() == account.address.lower()}")

# 2. Test Transaction Signing and Sending
console.print("\nTesting transaction signing...")

# First, fund the account from a test account (using Anvil's default funded account)
funded_account = w3.eth.account.from_key("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")

# Send some ETH to our GCP KMS account
fund_tx = {
    "from": funded_account.address,
    "to": account.address,
    "value": w3.to_wei(0.1, "ether"),
    "gas": 21000,
    "gasPrice": w3.eth.gas_price,
    "nonce": w3.eth.get_transaction_count(funded_account.address),
    "chainId": w3.eth.chain_id,
}

# Send funding transaction
signed_fund_tx = w3.eth.account.sign_transaction(fund_tx, funded_account.key)
fund_tx_hash = w3.eth.send_raw_transaction(signed_fund_tx.raw_transaction)
fund_receipt = w3.eth.wait_for_transaction_receipt(fund_tx_hash)
console.print(f"Funded account with 0.1 ETH. TX hash: {fund_receipt['transactionHash'].hex()}")

# Now create and sign a transaction from our GCP KMS account
tx = {
    "from": funded_account.address,
    "chain_id": w3.eth.chain_id,
    "nonce": w3.eth.get_transaction_count(account.address),
    "value": w3.to_wei(0.000001, "ether"),
    "data": "0x00",
    "to": "0xa5D3241A1591061F2a4bB69CA0215F66520E67cf",
    "type": 0,
    "gas_limit": 1000000,
    "gas_price": 300000000000,
}

# Sign the transaction
signed_tx = account.sign_transaction(Transaction.from_dict(tx))
console.print(f"{signed_tx=}")

if signed_tx:
    console.print(signed_tx)
    # Send the transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx)
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    console.print("\nTransaction successful!")
    console.print(f"Transaction hash: {receipt['transactionHash'].hex()}")
    console.print(f"From: {receipt['from']}")
    console.print(f"To: {receipt['to']}")
    console.print(f"Gas used: {receipt['gasUsed']}")

    # Verify the transaction signature
    tx_data = w3.eth.get_transaction(tx_hash)
    # Get the raw transaction data
    raw_tx = signed_tx
    recovered_address = w3.eth.account.recover_transaction(raw_tx)
    console.print("\nTransaction signature verification:")
    console.print(f"Original address: {account.address}")
    console.print(f"Recovered address: {recovered_address}")
    console.print(f"Signature valid: {recovered_address.lower() == account.address.lower()}")
else:
    console.print("Failed to sign transaction")