Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Secp256k1Wallet

Holds a 32-byte secp256k1 secret plus the Dango account address it controls. The only Wallet-protocol implementation that ships in tree.

Setup

from dango.utils.signing import Secp256k1Wallet
from dango.utils.types import Addr
 
wallet = Secp256k1Wallet.random(Addr("0x..."))

Constructor

Secp256k1Wallet(secret: bytes, address: Addr) -> None

secretbytes. Must be exactly 32 bytes with value in [1, n-1] for the secp256k1 curve order n. Raises ValueError on zero, on values >= n, or on wrong length.

addressAddr. The Dango account address this wallet signs for. Decoupled from the key — the same secret can sign for multiple Dango accounts.

Class methods

MethodDescription
random(address) -> Secp256k1WalletGenerate a CSPRNG-sourced wallet
from_bytes(secret, address) -> Secp256k1WalletWrap an explicit 32-byte secret
from_mnemonic(mnemonic, address, *, coin_type=60) -> Secp256k1WalletBIP-39 mnemonic + BIP-44 path m/44'/{coin_type}'/0'/0/0
from_eth_account(account, address) -> Secp256k1WalletRe-use a LocalAccount's secret (key_tag=Secp256k1, NOT EIP-712)
from eth_account import Account
 
from dango.utils.signing import Secp256k1Wallet
from dango.utils.types import Addr
 
addr = Addr("0x...")
 
w1 = Secp256k1Wallet.random(addr)
w2 = Secp256k1Wallet.from_bytes(bytes.fromhex("aa" * 32), addr)
w3 = Secp256k1Wallet.from_mnemonic("test test test test test test test test test test test junk", addr)
w4 = Secp256k1Wallet.from_eth_account(Account.from_key("0x..."), addr)

Properties

address -> Addr — the Dango account address supplied at construction.

secret_bytes -> bytes — the raw 32-byte secret. Sensitive — never log or persist in plaintext.

public_key_compressed -> bytes — 33-byte compressed pubkey (1-byte parity + 32-byte x).

key -> Key — wire-shape {"secp256k1": "<base64 of compressed pubkey>"}.

key_hash -> Hash256SHA-256(compressed_pubkey) as uppercase hex. The on-chain identifier the contract uses to look up the pubkey.

Methods

sign

def sign(self, sign_doc: SignDoc) -> Signature

Produces a secp256k1 signature over SHA-256(canonical_json(sign_doc)). Returns the 64-byte r||s in the {"secp256k1": "<base64>"} envelope. The trailing recovery byte from eth_keys is stripped — Dango verifies via the pubkey resolved from key_hash.

from dango.utils.signing import Secp256k1Wallet
from dango.utils.types import Addr, SignDoc
 
wallet = Secp256k1Wallet.random(Addr("0x..."))
sig = wallet.sign(SignDoc(sender=Addr("0x..."), gas_limit=1_000_000, messages=[], data={...}))

Notes

  • BIP-39 mnemonics use coin type 60 (Ethereum) by default — pass coin_type= to derive at a different path. The library uses eth-account's unaudited HD wallet path, matching the Rust SDK's BIP-32 derivation.
  • from_eth_account signs with KeyType=Secp256k1. The Dango account address you pass is independent from the wallet's derived EVM address and is the user's responsibility to provide.
  • The wallet satisfies the @runtime_checkable Wallet protocol — isinstance(wallet, Wallet) returns True.

See also