hdwallet

package module
v0.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 55 Imported by: 0

README

hd-wallet

Go Reference Go Report Card CI

A Trust Wallet–compatible, security-focused hierarchical-deterministic (HD) wallet library for Go.

Generate a BIP-39 mnemonic (or import one) and derive receive addresses for 100 networks using the same derivation paths and address formats Trust Wallet uses by default — so seeds are interchangeable between the two. Beyond derivation it adds EVM tooling (RLP, ABI, EIP-191, EIP-712), protobuf transaction signing for many families (EVM, Tron, XRP, Cosmos, Solana, Bitcoin/UTXO, Stellar, Algorand, Aptos, TON, Polkadot — no broadcast), secure private-key import/export, and address validation/parsing.

35 chains are explicitly not supported by this library (no address derivation, no validation, nothing). See Unsupported chains.

🤖 Using an LLM / AI coding assistant? Point it at llms.txt — a self-contained context file summarizing the project scope, full API surface, workflows, and troubleshooting notes.

Sensitive material (the mnemonic and derived seed) is never held as a plain Go string or a long-lived byte slice. It lives in encrypted, page-locked memguard enclaves and is decrypted only for the microseconds of a single derivation.


Why this library

  • 🔐 Secrets isolated in RAM. Encrypted enclaves, memory locked against swap (mlock/VirtualLock), guard pages, and automatic wiping. No mnemonic-as-string, no exported secret fields. Private-key import/export goes through the same memguard pattern — there is still no raw key getter.
  • Provably Trust Wallet–compatible. Every address encoder is tested against Trust Wallet Core's own vectors; key derivation is tested against the SLIP-0010 specification; transaction signers reproduce Trust Wallet Core's AnySigner vectors byte-for-byte. See Verification.
  • 🌐 100 networks across 2 curves. secp256k1 (Bitcoin-style, 50+ EVM chains, ~30 Cosmos chains, XRP, Tron) and ed25519 (Solana, Stellar, Algorand, Aptos, TON, Polkadot).
  • ✍️ Signing at every level. Raw ECDSA/EdDSA signing for every network, EVM message signing (EIP-191/EIP-712), and full protobuf transaction signing (EVM, Tron, XRP, Cosmos, Solana, Bitcoin/UTXO, Stellar, Algorand, Aptos, TON, Polkadot) that returns broadcast-ready raw transactions. Derived keys are wiped after each use.
  • 🧩 Extensible. Add a network with a single registry row.
  • 📦 Focused dependency surface. btcd (secp256k1/bech32/base58), go-bip39, x/crypto, memguard, protobuf.

Install

go get github.com/ranjbar-dev/hd-wallet
import hdwallet "github.com/ranjbar-dev/hd-wallet"

Requires Go 1.23+.


Quick start

package main

import (
	"fmt"
	"log"

	"github.com/awnumar/memguard"
	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

func main() {
	defer memguard.Purge() // wipe all protected memory on exit

	// Create a wallet with a fresh 12-word mnemonic...
	w, err := hdwallet.NewHDWallet()
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy() // wipe this wallet's secrets when done

	// ...or import one:
	// w, _ := hdwallet.FromMnemonic("abandon abandon ... about")

	// Chains are a typed enum (hdwallet.Chain) — use the exported constants
	// for compile-time checking and autocomplete.
	btc, _ := w.Address(hdwallet.BTC)
	eth, _ := w.Address(hdwallet.ETH)
	sol, _ := w.Address(hdwallet.SOL)
	fmt.Println(btc, eth, sol)

	all, _ := w.AllAddresses() // map[hdwallet.Chain]string for every network
	fmt.Println(all[hdwallet.ATOM])
}
Reading the mnemonic safely

The mnemonic is never exposed as a field. Read it only when needed, through a buffer that is wiped immediately afterwards:

err := w.WithMnemonic(func(mnemonic []byte) error {
	fmt.Printf("%s\n", mnemonic) // do not let the slice escape this function
	return nil
})
Multiple addresses per chain

Address returns the first receive address; AddressIndex derives any index by replacing the final element of the chain's path (preserving its hardened flag):

a0, _ := w.AddressIndex(hdwallet.BTC, 0) // bc1q...306fyu (same as w.Address(hdwallet.BTC))
a1, _ := w.AddressIndex(hdwallet.BTC, 1) // bc1q...rkf9g — second receive address
sol1, _ := w.AddressIndex(hdwallet.SOL, 1) // account-based chains vary the hardened element
Bitcoin address types

Address/AddressIndex return the chain default (native SegWit, BIP-84 for BTC/LTC). BitcoinAddress derives any of the four standard formats at its standard BIP path (arguments are account, change, index):

legacy,  _ := w.BitcoinAddress(hdwallet.BTC, hdwallet.P2PKH, 0, 0, 0)      // 1…   (BIP-44)
nested,  _ := w.BitcoinAddress(hdwallet.BTC, hdwallet.P2SHP2WPKH, 0, 0, 0) // 3…   (BIP-49)
native,  _ := w.BitcoinAddress(hdwallet.BTC, hdwallet.P2WPKH, 0, 0, 0)     // bc1q… (BIP-84)
taproot, _ := w.BitcoinAddress(hdwallet.BTC, hdwallet.P2TR, 0, 0, 0)       // bc1p… (BIP-86)

Available for BTC and LTC; verified against the official BIP-44/49/84/86 test vectors. ValidateAddress/ParseAddress accept all four formats.

Error handling

The package exports sentinel errors for use with errors.Is: ErrInvalidMnemonic, ErrUnsupportedCoin, and ErrDestroyed.

if _, err := w.Address("NOPE"); errors.Is(err, hdwallet.ErrUnsupportedCoin) {
	// unknown chain
}
Signing (raw)

Sign/SignIndex produce a signature with the derived private key for any supported chain. The key is wiped immediately after signing and never leaves the package — there is no way to extract a private key.

There is one inherent rule, driven by the cryptography:

  • The ECDSA chain (secp256k1 — BTC, ETH, ATOM, …): pass the 32-byte digest your chain signs. Pre-hash the message yourself with the chain's hash (keccak256 for Ethereum/Tron, double-SHA256 for Bitcoin, SHA-256 for Cosmos, …).
  • ed25519 chains (SOL, XLM, ALGO, APTOS): pass the message; the EdDSA scheme hashes internally.
digest := sha256.Sum256(txBytes)         // chain-specific pre-hash for ECDSA
sig, _ := w.Sign(hdwallet.BTC, digest[:])

sig.Bytes()        // 64-byte R||S (ECDSA) or 64-byte ed25519 signature  → Cosmos, Solana
sig.Recoverable()  // 65-byte R||S||V (secp256k1 only)                   → Ethereum/EVM, Tron
sig.DER()          // ASN.1 DER (ECDSA)                                  → Bitcoin family

pub, _ := w.PublicKey(hdwallet.BTC)
ok := hdwallet.Verify(hdwallet.Secp256k1, pub, digest[:], sig)

SignIndex(chain, index, data) and PublicKeyIndex(chain, index) work with non-zero address indices. ECDSA inputs that are not 32 bytes return ErrInvalidDigest.

This is the low-level primitive. For Ethereum message signing and full transaction building, use the higher-level APIs below.

Transaction signing (protobuf, no broadcast)

SignTransaction builds, serializes, and signs a broadcast-ready raw transaction from a protobuf SigningInput, mirroring Trust Wallet Core's AnySigner. It returns the signed bytes/hex — it does not broadcast.

Coverage note: address derivation/validation spans all 100 networks, but transaction building covers only the families in the table below. For any other chain you can derive and validate addresses but must assemble and sign the transaction yourself (use the raw Sign/SignIndex primitive on the chain's sighash). You also supply chain state — fees/gas, nonce/sequence, recent blockhash, UTXOs — in the SigningInput; this library does no network I/O.

Verified against authoritative signing vectors for:

Family Coverage
EVM legacy (EIP-155) + EIP-2930 (access list) + EIP-1559 + EIP-4844 (type-3 blob tx: max_fee_per_blob_gas + blob_versioned_hashes) + EIP-7702 (type-4 set-code tx: authorization_list), native + ERC-20 + arbitrary contract call + contract creation (deploy). Select the format with tx_mode (exported hdwallet.EthTxModeLegacy/EthTxModeEIP2930/EthTxModeEIP1559/EthTxModeEIP4844/EthTxModeEIP7702). Structured token intents via proto oneofs: ERC-20 approve (ERC20Approve), ERC-721 transfer (ERC721Transfer), ERC-1155 transfer (ERC1155Transfer) — each tested with Legacy + EIP-1559 TWC-vector-pinned tests. ERC-4337 account abstraction: UserOperation v0.6 (EthTxModeUserOp = 5, SigningInput.user_operation field 14) and v0.7 (EthTxModeUserOpV07 = 6, SigningInput.user_operation_v0_7 field 15, packed uint128 accountGasLimits/gasFees). Smart-wallet batch intents: SCWalletExecute (single call, field 7) and SCWalletBatch (batched calls, field 8) for three wallet types — SC_SIMPLE_ACCOUNT (execute/executeBatch(address[],uint256[],bytes[])), BIZ_4337 (executeBatch(address[],bytes[])), and BIZ (executeBatch(address[],uint256[],bytes[])). All registered EVM chains.
Tron TRX transfer (TransferContract) + TRC-10 transfer (TransferAssetContract) + TRC-20 transfer + generic TriggerSmartContract (arbitrary call with call_value/data/call_token_value/token_id) + legacy Stake 1.0 FreezeBalanceContract/UnfreezeBalanceContract + UnfreezeAssetContract + WithdrawBalanceContract + VoteAssetContract; raw_json mode signs a node/DApp-provided pre-built transaction (raw_data_hex + txID guard) for wallet-connect flows
XRP Payment
Cosmos bank MsgSend, staking MsgDelegate/MsgUndelegate, MsgWithdrawDelegatorReward, multi-message (protobuf direct mode). All standard secp256k1 Cosmos chains, plus EVMOS and INJ (ethermint eth_secp256k1: keccak256 SignDoc + chain-specific pubkey type URL — INJ uses an uncompressed key).
Cosmos multisig LegacyAminoMultisig m-of-n bank MsgSend (CosmosMultisigAddress/SignCosmosMultisigPartial/CombineCosmosMultisig), LEGACY_AMINO_JSON sign docs. Standard secp256k1 Cosmos chains only (Ethermint chains rejected). Pinned byte-for-byte to a cosmos-sdk-generated vector.
Solana system transfer + SPL token transfer (TransferChecked) + Token-2022 transfers (token_program_id selects the Token-2022 program) + versioned v0 messages (v0_msg) + associated-token-account flows (CreateTokenAccount, CreateAndTransferToken — the ATA is always derived internally via SolanaTokenAccountAddress, guarding against a mismatched caller-supplied token address) + durable nonces (nonce_account prepends AdvanceNonceAccount on transfer/token-transfer/create-and-transfer; plus CreateNonceAccount/WithdrawNonceAccount/AdvanceNonceAccount lifecycle)
Bitcoin / UTXO BTC/LTC spends across all four single-key input types — legacy P2PKH, nested P2SH-P2WPKH (BIP-49), native P2WPKH (BIP-143), and Taproot key-path (BIP-341 / BIP-340 Schnorr); outputs to any address type; SIGHASH ALL/NONE/SINGLE/ANYONECANPAY (legacy + BIP-143); multiple recipients, OP_RETURN data output, opt-in RBF (BIP-125) + nLockTime/nSequence; deterministic coin-selection with configurable input selectors, fee-per-vByte, dust handling, send-all/use-all, and change. PlanBitcoinTx/EstimateBitcoinFee preview the plan without signing. The same engine signs the UTXO altcoins (DOGE/DASH/BCH/ZEC and DGB/SYS/VIA/STRAX/QTUM/RVN/FIRO/MONA/PIVX). Verified against btcd and the BIP-143 spec vector.
Bitcoin PSBT BIP-174 (v0) and BIP-370 (v2) build / sign / finalize / extract over the same inputs (BuildPSBT/SignPSBT/FinalizePSBT/ExtractPSBTTx and the …PSBTV2 variants). The v0 path is byte-identical to the direct signer.
Bitcoin multisig P2SH and P2WSH m-of-n (BIP-67 sorted keys), partial-sign + finalize via BIP-174 PSBT (BuildMultisigPSBT/SignMultisigPSBT/FinalizeMultisigPSBT/ExtractMultisigTx). Pinned to btcd.
Bitcoin Ordinals / BRC-20 Taproot script-path primitives (BuildInscriptionScript, control-block builder) plus a two-phase BRC-20 transfer flow (BuildBRC20CommitSignBRC20Reveal). Babylon BTC-staking output builders (tx_bitcoin_babylon.go) are also included.
Stellar (XLM) Payment + CreateAccount (TransactionV0 XDR envelope), plus Memo support (MEMO_TEXT/MEMO_ID/MEMO_HASH). Pinned to the Trust Wallet Core Stellar vector.
Algorand (ALGO) Payment (canonical msgpack, "TX"-prefixed ed25519) plus ASA transfers (axfer) and opt-in (0-amount self-axfer). Pinned to the TWC Algorand vector.
Aptos (APTOS) Entry-function transfer (BCS + APTOS::RawTransaction prehash), plus a structured Transfer convenience input synthesized into aptos_account::transfer. Pinned to the TWC Aptos vector.
TON Native transfer (wallet v4r2), deploy-on-first-send (seqno==0), UTF-8 comments, and TEP-74 jetton transfers. Pinned to the TWC test_ton_sign_transfer_ordinary vector.
Polkadot (DOT) Balances.transfer_keep_alive (native DOT) and Assets.transfer_keep_alive (Asset Hub tokens, e.g. USDT = 1984 / USDC = 1337) as SCALE-encoded v4 extrinsics with mortal/immortal eras, MultiAddress or raw AccountId encoding, and overridable call indices. Pinned to the TWC SignTransfer_9fd062 vector.
import ethpb "github.com/ranjbar-dev/hd-wallet/txproto/ethereum"

out, _ := w.SignTransaction(hdwallet.ETH, 0, &ethpb.SigningInput{ /* … */ })

Bitcoin spending covers all four standard single-key input types (P2PKH, P2SH-P2WPKH, P2WPKH, Taproot key-path) plus P2SH/P2WSH multisig via PSBT.

What you must provide (no network I/O)

SignTransaction never calls the network. The caller supplies all chain state as fields on the SigningInput proto before signing. providers.go exports five small interfaces that formalise this contract; doc.go contains the full per-family matrix mapping each SigningInput field to its data source:

Interface Used for Chain state
NonceProvider EVM, XRP, Cosmos sender nonce / account sequence
UTXOProvider Bitcoin-family unspent outputs (txid, vout, amount, scriptPubKey)
FeeOracle EVM, Bitcoin, XRP, Tron gas price / sat-per-vbyte / drops
RecentBlockhashProvider Solana latest confirmed blockhash
Broadcaster all families post-signing submission sink

None of these interfaces are called inside the package — they exist purely for typing and documentation. Wire them as thin wrappers around your node RPC or indexer client, call each one before building the SigningInput, then pass the results in. See example_providers_test.go for a minimal wiring example and doc.go for the field-by-field mapping.

Ethereum message signing (EIP-191 / EIP-712)
sig, _ := w.SignMessage(hdwallet.ETH, 0, []byte("Hello, world!"))   // EIP-191 personal_sign
addr, _ := hdwallet.RecoverEthereumAddress([]byte("Hello, world!"), sig)

sig2, _ := w.SignTypedData(hdwallet.ETH, 0, typedDataJSON)           // EIP-712

Plus standalone EVM tooling: EncodeRLP/DecodeRLP, ABIEncode/ABIDecode, ABIFunctionSelector, EthereumPersonalMessageHash, EIP712Hash.

JSON-ABI contract-call decoding

Parse a contract's JSON ABI and decode raw calldata into typed named parameters:

abi, err := hdwallet.ParseContractABI(jsonABI)    // parse ABI array → selector-keyed map
name, params, err := hdwallet.DecodeContractCall(abi, calldata) // decode 4-byte selector + args
// name = "approve", params = [{Name:"spender" Value:"0x…"}, {Name:"amount" Value:"1000000"}]
sig := hdwallet.GetFunctionSignature(abi["approve"]) // "approve(address,uint256)"

Implemented in eth_contractcall.go; no new dependencies (reuses the existing ABIDecode primitive).

Bitcoin, Solana, Cosmos & Tron message signing

Non-EVM message signing, each following the chain's canonical standard:

// Bitcoin "signmessage" standard → base64; verifies against a legacy P2PKH address.
// Pinned byte-for-byte to Trust Wallet Core BitcoinMessageSigner vectors.
sig, _  := w.SignBitcoinMessage(hdwallet.BTC, 0, []byte("test signature"))
ok      := hdwallet.VerifyBitcoinMessage("19cAJn4Ms8jodBBGtroBNNpCZiHAWGAq7X", []byte("test signature"), sig)

// Solana off-chain message (raw ed25519) → base58.
// Pinned to Trust Wallet Core SolanaMessageSigner vector.
ssig, _ := w.SignSolanaMessage(hdwallet.SOL, 0, []byte("Hello world"))
sok     := hdwallet.VerifySolanaMessage(addr, []byte("Hello world"), ssig)

// Cosmos ADR-36 arbitrary-message signing → base64 (65-byte recoverable secp256k1).
// Follows the CosmJS / Keplr makeADR36AminoSignDoc + serializeSignDoc pipeline;
// ecrecover is used for verification (no separate public key needed).
signer, _ := w.Address(hdwallet.ATOM)
csig, _ := w.SignCosmosADR36(hdwallet.ATOM, 0, signer, []byte("arbitrary cosmos data"))
cok     := hdwallet.VerifyCosmosADR36(signer, []byte("arbitrary cosmos data"), csig)

// Tron TIP-191 message signing → "0x…" hex (65-byte R‖S‖V, V ∈ {27,28}).
// Matches TronWeb trx.signMessageV2; uses keccak256("\x19TRON Signed Message:\n32" ‖ keccak256(msg)).
tsig, _ := w.SignTronMessage(hdwallet.TRX, 0, []byte("Hello World"))
tok     := hdwallet.VerifyTronMessage(tronAddr, []byte("Hello World"), tsig)
Chain-neutral raw message signing

For advanced use cases, SignRawMessage / VerifyRawMessage route through the correct curve for any registered chain without a chain-specific envelope:

// secp256k1 chains: pass the 32-byte digest you pre-hashed.
digest := hdwallet.Keccak256([]byte("raw data"))
sig, _ := w.SignRawMessage(hdwallet.ETH, 0, digest)
pub, _ := w.PublicKey(hdwallet.ETH)
ok, _ := hdwallet.VerifyRawMessage(hdwallet.ETH, pub, digest, sig)

// ed25519 chains: pass the raw message; EdDSA hashes internally.
sig, _ = w.SignRawMessage(hdwallet.SOL, 0, []byte("any length"))
Amount formatting

Convert between human-readable amounts and base units using each chain's native decimals (from the registry) — or explicit decimals for tokens (ERC-20/SPL/TRC-20, whose decimals are token-specific and supplied by you). All big.Int / decimal-string math, no float:

d, _ := hdwallet.NativeDecimals(hdwallet.ETH)            // 18
s   := hdwallet.FormatAmount(hdwallet.ETH, weiBigInt)    // "1.5"
wei, _ := hdwallet.ParseAmount(hdwallet.ETH, "1.5")      // *big.Int

// Token amounts: pass the token's own decimals.
usdc := hdwallet.FormatUnits(rawBigInt, 6)               // "12.34"
raw, _ := hdwallet.ParseUnits("12.34", 6)

Native decimals come from CoinInfo(chain).Decimals; token decimals are the client's responsibility (token lists are out of scope).

Chain-constraint helpers

Pre-flight informational sanity floors — not fund-critical signing data, no network I/O — so a caller can warn before broadcasting a transfer that would leave an account/UTXO below the network's floor:

min, ok := hdwallet.MinimumBalance(hdwallet.XRP)     // 1_000_000 drops (base reserve)
dust, ok := hdwallet.DustThreshold(hdwallet.BTC)     // 546 sats (standard relay dust)
fee, ok := hdwallet.ActivationCost(hdwallet.TRX)     // 1_100_000 sun (new-account fee)

MinimumBalance covers XRP/XLM/SOL (ongoing reserve/rent floor); DustThreshold covers every UTXO chain (reuses the signer's own dust constant); ActivationCost covers TRX (a one-off account-creation fee, distinct from an ongoing reserve). ok is false for chains with no such constraint.

Address validation & parsing
ok  := hdwallet.IsValidAddress(hdwallet.ETH, "0x…")     // bool
err := hdwallet.ValidateAddress(hdwallet.BTC, "bc1q…")  // descriptive error
payload, _ := hdwallet.ParseAddress(hdwallet.ETH, "0x…")
addr, _ := hdwallet.AddressFromPublicKey(hdwallet.ETH, pubKey) // external key → address
Importing / exporting a raw private key (securely)

A wallet can be built from a single private key, and the leaf key can be exported — always through the same memguard pattern as the mnemonic (no raw []byte getter; the key is wiped when your callback returns):

w, _ := hdwallet.FromPrivateKeyBytes(keyBytes, hdwallet.Secp256k1) // wipes keyBytes
// or FromPrivateKeyBuffer(*memguard.LockedBuffer, curve) — zero-copy, strongest

_ = w.WithPrivateKey(hdwallet.ETH, 0, func(priv []byte) error {     // wiped on return
    // use priv; do not let it escape
    return nil
})
buf, _ := w.PrivateKey(hdwallet.ETH, 0)                             // caller Destroys
defer buf.Destroy()

Passing a mnemonic in securely

The golden rule: never let the mnemonic become a Go string in your code — strings are immutable and can never be wiped from memory. Choose the entry point that matches how securely you can hold the secret:

Entry point Security When
FromMnemonicBuffer(*memguard.LockedBuffer) 🟢 Strongest Mnemonic stays in page-locked, encrypted memory end-to-end; sealed zero-copy into the wallet.
FromMnemonicBytes([]byte) 🟡 Good You have a mutable []byte; it is wiped inside the call.
FromMnemonic(string) 🔴 Weakest Convenience only; the string cannot be wiped. Avoid for real funds.
Most secure: hand off a memguard buffer (zero-copy)

The wallet takes ownership of the buffer and destroys it — there is no extra unprotected copy anywhere in your process.

import (
	"os"

	"github.com/awnumar/memguard"
	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

func loadWallet() (*hdwallet.HDWallet, error) {
	defer memguard.Purge()

	// Read one line straight into locked, encrypted memory — never a string.
	buf, err := memguard.NewBufferFromReaderUntil(os.Stdin, '\n')
	if err != nil {
		return nil, err
	}
	// Ownership transfers to the wallet; buf is destroyed for you.
	return hdwallet.FromMnemonicBuffer(buf)
}

From a secrets manager / KMS that returns raw bytes:

raw := fetchFromVault()                    // []byte from your secret store
buf := memguard.NewBufferFromBytes(raw)    // copies into protected memory, wipes raw
w, err := hdwallet.FromMnemonicBuffer(buf) // takes ownership of buf
Good: a mutable byte slice
raw, _ := os.ReadFile("mnemonic.txt") // []byte, never a string
mn := bytes.TrimSpace(raw)
w, err := hdwallet.FromMnemonicBytes(mn) // mn is zeroed inside the call
for i := range raw {                     // wipe any trimmed remainder
	raw[i] = 0
}

Avoid os.Getenv for the mnemonic: environment variables are already immutable strings and cannot be wiped.

Residual exposure: the underlying tyler-smith/go-bip39 API only accepts string, so the library makes a single short-lived string copy for validation and seed derivation. It is GC-bounded, and every durable copy of the mnemonic and seed is sealed in a memguard enclave.


Supported networks

100 networks across 2 curves. SupportedCoins() returns the live, authoritative list; CoinInfo(chain) gives each coin's curve and path. Every chain below is verified against a Trust Wallet Core address vector.

secp256k1 (94)
Group Chains Path
Bitcoin-family / UTXO BTC, LTC, DOGE, BCH, DASH, ZEC, DGB, SYS, VIA, QTUM, RVN, FIRO, MONA, PIVX, STRAX per-chain (e.g. m/84'/0'/0'/0/0)
Ethereum / EVM (same key & address) ETH, BNB, MATIC, AVAX, ARB, OP, FTM, BASE, CRO, GNO, CELO, ETC, RBTC, KAIA, AURORA, GLMR, MOVR, BOBA, METIS, OPBNB, POLZKEVM, MANTA, ZKSYNC, LINEA, SCROLL, MANTLE, BLAST, RONIN, HECO, OKT, KCS, WAN, POA, CLO, GO, TT, VET, IOTX, THETA, NEON, MERLIN, LIGHT, SONIC, ZENEON, EVMOS, INJ, ZETAEVM m/44'/60'/0'/0/0
Tron TRX m/44'/195'/0'/0/0
XRP Ledger XRP m/44'/144'/0'/0/0
Cosmos SDK (bech32, per-chain HRP) ATOM, OSMO, JUNO, TIA, LUNA, KAVA, SCRT, BAND, RUNE, STARS, AXL, STRD, BLD, CRE, KUJI, CMDX, NTRN, SOMM, FET, MARS, UMEE, COREUM, QSR, XPRT, AKT, NOBLE, SEI, DYDX, BLZ, CRYPTOORG m/44'/118'/0'/0/0 (some differ)
ed25519 (6)
Chain Network Path
SOL Solana m/44'/501'/0'
XLM Stellar m/44'/148'/0'
ALGO Algorand m/44'/283'/0'/0'/0'
APTOS Aptos m/44'/637'/0'/0'/0'
TON TON m/44'/607'/0'
DOT Polkadot m/44'/354'/0'/0'/0'

All paths derive receive address index 0 and an empty BIP-39 passphrase (Trust Wallet's default).

Unsupported chains

This library does not support the following 35 chains at all — no address derivation, no validation, no registry rows, nothing:

ADA (Cardano), AE (Aeternity), BCD (Bitcoin Diamond), BTG (Bitcoin Gold), CANTO (Canto), CKB (Nervos), EGLD (MultiversX), EOS (EOS), FIL (Filecoin), FIO (FIO), FLUX (Flux), GRS (Groestlcoin), HBAR (Hedera), ICX (ICON), IOST (IOST), KIN (Kin), KMD (Komodo), KSM (Kusama), NEAR (NEAR), NEBL (Neblio), NEO (NEO), ONE (Harmony), ONT (Ontology), ROSE (Oasis), STRK (StarkNet), SUI (Sui), WAVES (Waves), WAX (WAX), XEC (eCash), XNO (Nano), XTZ (Tezos), XVG (Verge), ZEN (Horizen), ZETA (ZetaChain, Cosmos-side), ZIL (Zilliqa).

Note: ZETAEVM (ZetaChain's EVM side) and ZEC/BCH remain fully supported — only the Cosmos-side ZETA row and the non-standard-sighash UTXO chains above were removed.

A PR re-adding any of these must follow the same rule as every other chain in this registry: no fund-critical address or signature ships without an authoritative Trust Wallet Core (or equivalent) test vector.

Contributions with test vectors welcome.


Verification

"Trust Wallet–compatible" is proven, not asserted. The test suite layers three independent sources of truth:

  1. Encoders (encoders_test.go) — every address encoder is run against the exact addresses Trust Wallet Core's CoinAddressDerivationTests produces for a fixed key, isolating address-format correctness.
  2. Derivation (slip10_test.go) — ed25519 derivation is checked against the official SLIP-0010 specification test vectors.
  3. End-to-end (hdwallet_test.go) — full mnemonic→seed→derive→encode against the BIP-84 spec (BTC), the canonical ETH vector, and Trust Wallet Core's HDWalletTests Cosmos secp256k1 mnemonic vector.
go test -race -cover ./...

Always verify before sending funds. Import your mnemonic into Trust Wallet and confirm the address for any chain you intend to use with real value.


API

Function / method Purpose
NewHDWallet() (*HDWallet, error) New wallet with a fresh 12-word mnemonic.
NewHDWalletWithWordCount(words int) (*HDWallet, error) New wallet with a 12/15/18/21/24-word mnemonic. Also NewHDWalletWithEntropy(bits).
FromMnemonic(string) (*HDWallet, error) Import from a mnemonic string (least secure).
FromMnemonicBytes([]byte) (*HDWallet, error) Import from a byte slice (wiped on use).
FromMnemonicBuffer(*memguard.LockedBuffer) (*HDWallet, error) Import from a memguard buffer (most secure; zero-copy).
FromMnemonicWithPassphrase([]byte, []byte) (*HDWallet, error) Import with a BIP-39 passphrase (the "25th word").
FromMnemonicBufferWithPassphrase(buf, pass *memguard.LockedBuffer) (*HDWallet, error) Passphrase import, both secrets in memguard buffers.
GenerateMnemonic() (string, error) Generate a mnemonic without building a wallet. Also GenerateMnemonicWithWordCount(words).
(*HDWallet) Address(chain Chain) (string, error) First receive address for one network.
(*HDWallet) AddressIndex(chain Chain, index uint32) (string, error) Nth address/account for one network.
(*HDWallet) AddressPath(chain Chain, path string) (string, error) Address at an arbitrary absolute BIP-32 path. Also SignPath/PublicKeyPath/WithPrivateKeyPath/PrivateKeyPath.
(*HDWallet) AddressAt(chain Chain, account, change, index uint32) (string, error) Address by BIP-44 account/change/index. Also SignAt/PublicKeyAt.
(*HDWallet) AllAddresses() (map[Chain]string, error) Addresses for all networks. Also AllAddressesAt(index) for any index.
(*HDWallet) Sign(chain Chain, data []byte) (*Signature, error) Sign a digest (ECDSA) / message (ed25519) at index 0.
(*HDWallet) SignIndex(chain Chain, index uint32, data []byte) (*Signature, error) Sign with the key at a given index.
(*HDWallet) PublicKey(chain Chain) ([]byte, error) Public key at index 0.
(*HDWallet) PublicKeyIndex(chain Chain, index uint32) ([]byte, error) Public key at a given index.
Verify(curve Curve, pub, data []byte, sig *Signature) bool Verify a signature.
(*HDWallet) WithMnemonic(func([]byte) error) error Use the mnemonic, auto-wiped.
(*HDWallet) Mnemonic() (*memguard.LockedBuffer, error) Mnemonic buffer (caller Destroys).
(*HDWallet) Destroy() Wipe the wallet's secrets.
SupportedCoins() []Chain Sorted list of chains.
CoinInfo(chain Chain) (Coin, bool) Registry entry for a chain.

Private-key import / export (same memguard discipline as the mnemonic):

Function / method Purpose
FromPrivateKeyBytes([]byte, Curve) (*HDWallet, error) Key-only wallet from a byte slice (wiped on use). Any 32-byte-scalar curve.
FromPrivateKeyBuffer(*memguard.LockedBuffer, Curve) (*HDWallet, error) Key-only wallet from a memguard buffer (zero-copy).
(*HDWallet) WithPrivateKey(chain, index, func([]byte) error) error Use the leaf private key, auto-wiped.
(*HDWallet) PrivateKey(chain, index) (*memguard.LockedBuffer, error) Leaf key buffer (caller Destroys).
FromWIF([]byte) (*HDWallet, error) · (*HDWallet) WithWIF / WIF Import/export a Bitcoin WIF (secp256k1).
(*HDWallet) AccountXPub(chain, account) (string, error) · WithAccountXPrv Export account-level BIP-32 extended keys (secp256k1).
WatchOnlyFromXPub(xpub string, chain) (*WatchWallet, error) Watch-only address derivation from an xpub — no seed.

Transaction & Ethereum message signing:

Function / method Purpose
(*HDWallet) SignTransaction(chain, index, proto.Message) (proto.Message, error) Build+sign a raw tx (EVM/Tron/XRP/Cosmos/Solana/Bitcoin-UTXO/Stellar/Algorand/Aptos/TON/Polkadot; no broadcast).
BroadcastPayload(chain, proto.Message) (string, error) Convert a SignTransaction output to the exact string each chain's RPC endpoint expects: "0x"+hex for EVM, bare hex for Bitcoin/UTXO, base64 for Solana and Cosmos, a TronGrid JSON object for Tron, uppercase hex for XRP, "0x"+hex for Polkadot (author_submitExtrinsic).
TransactionID(proto.Message) (string, error) Extract the canonical transaction id from any SignTransaction output, normalised to lower-case hex (or base58 for Solana). Polkadot's is Substrate's extrinsic hash, BLAKE2b-256(Encoded).
DecodePolkadotTx(raw []byte, network byte) (*PolkadotTxFields, error) Decode a signed Polkadot v4 extrinsic back into display fields (signer/dest SS58, era, nonce, tip, call, value, asset id) — the reverse of SignTransaction(DOT, …).
(*HDWallet) SignMessage(chain, index, []byte) ([]byte, error) EIP-191 personal_sign → 65-byte r‖s‖v.
(*HDWallet) SignTypedData(chain, index, []byte) ([]byte, error) EIP-712 typed-data signature.
(*HDWallet) SignBitcoinMessage(chain, index, []byte) (string, error) Bitcoin signmessage → base64. With VerifyBitcoinMessage.
(*HDWallet) SignSolanaMessage(chain, index, []byte) (string, error) Solana off-chain message → base58. With VerifySolanaMessage.
(*HDWallet) SignCosmosADR36(chain, index, signer, []byte) (string, error) Cosmos ADR-36 arbitrary-message → base64 (65-byte recoverable). With VerifyCosmosADR36.
(*HDWallet) SignTronMessage(chain, index, []byte) (string, error) Tron TIP-191 message → 0x… hex (V ∈ {27,28}). With VerifyTronMessage.
(*HDWallet) SignRawMessage(chain, index, []byte) (*Signature, error) Chain-neutral: ECDSA 32-byte digest or ed25519 raw message. With VerifyRawMessage.
RecoverEthereumAddress([]byte, []byte) (string, error) · VerifyEthereumMessage / …TypedData Recover/verify EIP-191/712 signers.
EncodeRLP/DecodeRLP · ABIEncode/ABIDecode · ABIFunctionSelector · EIP712Hash Standalone EVM encoding utilities.
ParseContractABI(jsonABI string) (ContractABIMap, error) · DecodeContractCall(abi, calldata) · GetFunctionSignature(fn) JSON-ABI-driven contract-call decoding: parse a JSON ABI array into a selector-keyed map, then decode raw calldata into a function name and typed named parameters.

Chain-constraint helpers (informational, no network I/O):

Function Purpose
MinimumBalance(chain) (*big.Int, bool) Minimum on-chain reserve/rent floor (XRP/XLM/SOL/DOT — DOT is the relay-chain existential deposit; Asset Hub's differs).
DustThreshold(chain) (*big.Int, bool) Standard-relay dust limit in sats (every UTXO chain).
ActivationCost(chain) (*big.Int, bool) One-off account-activation fee (TRX).

Address validation / parsing (AnyAddress-style):

Function Purpose
IsValidAddress(chain, addr) bool · ValidateAddress(chain, addr) error Validate an address for a network.
ParseAddress(chain, addr) ([]byte, error) Decode an address to its payload.
AddressFromPublicKey(chain, pub) (string, error) Derive an address from an external public key.

Mnemonic entry-screen helpers (pure functions, no secrets):

Function Purpose
WordlistPrefix(prefix string) []string Up to 8 BIP-39 English words starting with prefix — for autocomplete.
IsValidWord(word string) bool Reports whether a word is in the BIP-39 English wordlist.
SuggestFinalWords(words []string) ([]string, error) Given the first 11/14/17/20/23 words, returns all valid final words (128 completions for a 12-word mnemonic).
MnemonicStrength(mnemonic string) (bits, words int, err error) Validates a mnemonic and reports its entropy size and word count.
ValidateMnemonic(string) error · ValidateMnemonicBytes([]byte) error Validate without building a wallet.

Chain is a typed string enum; the package exports a constant for every supported network (hdwallet.BTC, hdwallet.ETH, hdwallet.SOL, …). Pass these constants instead of raw strings for compile-time safety. Chain also has String() string and IsValid() bool helpers.


Adding a network

Append one row to the registry in registry.go:

"FOO": {"Foochain", "FOO", Secp256k1, "m/44'/9999'/0'/0/0", encodeFoo},

Provide an Encode func(pub []byte) (string, error) for the address format (the compressed key for secp256k1, the raw 32-byte key for ed25519), and add a test vector. EVM chains can reuse encodeETH; Cosmos chains can reuse cosmosEncoder("<hrp>").


Demo CLI

go run ./cmd/hdwallet                       # fresh wallet, prints addresses
go run ./cmd/hdwallet -mnemonic "abandon ... about"
go run ./cmd/hdwallet -show-mnemonic        # demo only; printing defeats isolation

Security

  • Secrets are stored in memguard enclaves (encrypted at rest in RAM, pages locked against swap, guarded with canaries, auto-wiped).
  • Private keys derived during an operation are zeroed immediately after the address is computed.
  • Call w.Destroy() per wallet and defer memguard.Purge() at program exit.
  • Caveat: FromMnemonic(string) and GenerateMnemonic() string involve a Go string that cannot be wiped (a limitation of the BIP-39 API). Prefer FromMnemonicBytes and WithMnemonic for the strongest guarantees.

Found a vulnerability? Please open a private security advisory rather than a public issue.

Concurrency

*HDWallet is safe for concurrent use: all read methods (Address, Sign, PublicKey, AllAddresses, SignTransaction, …) take a shared sync.RWMutex read-lock and may run in parallel across goroutines; Destroy() takes the exclusive write-lock. Each call opens its own short-lived decrypted buffer from the memguard enclave and wipes it on return, so concurrent callers never share mutable key material. Don't call Destroy() concurrently with in-flight calls on the same wallet — it invalidates the secret out from under them.


Publishing & releasing

Releases are fully automated. Every push to main that passes the test and security gates is tagged and published by CI (.github/workflows/ci.yml):

  1. CI runs build, tests (-race), govulncheck, and gosec.
  2. A new semver tag is created and pushed.
  3. The Go module proxy is warmed (proxy.golang.org), which publishes the version and triggers pkg.go.dev indexing.
  4. A GitHub Release with auto-generated notes is created.

Control the version bump from the commit message:

Marker in commit message Result
[major] x+1.0.0
[minor] x.y+1.0
(none) x.y.z+1 (patch)
[skip release] no release for that push

The first release is v0.1.0. Requires the repo to be public and the default GITHUB_TOKEN to have write access (Settings → Actions → General → Workflow permissions → "Read and write permissions"). If tag protection rules block the bot, supply a Personal Access Token instead.

To release manually instead, just push a tag (git tag v1.2.3 && git push origin v1.2.3).


License

MIT © Amir Ranjbar

Disclaimer

This software is provided "as is", without warranty of any kind. You are responsible for safeguarding your own keys and funds. Always test with small amounts first and verify addresses against a reference wallet.

Documentation

Overview

Package hdwallet is a Trust Wallet–compatible hierarchical-deterministic (HD) wallet library for Go. It derives addresses and signs transactions for 99 networks across two elliptic curves (secp256k1 and ed25519), with secrets sealed in memguard enclaves so private keys are never exposed to the caller. See the package README's "Unsupported chains" section for networks this library deliberately does not support.

What you must supply (the network seam)

HDWallet.SignTransaction builds, signs, and serializes a broadcast-ready raw transaction from a protobuf SigningInput. It performs NO network I/O. The caller is responsible for fetching all chain state before calling SignTransaction and setting it on the relevant SigningInput fields.

The table below is the authoritative per-family reference: for each signing family it lists the SigningInput fields that carry chain state, the data source, and the provider interface (from providers.go) that formalises the contract. "Local" means the value is derived locally (from the wallet or known chain constants) without a network call.

## EVM — ethereum.SigningInput (ETH, BNB, MATIC, AVAX, …)

Field                    Source                          Provider
────────────────────────────────────────────────────────────────────
chain_id                 Known chain constant            Local
nonce                    eth_getTransactionCount         NonceProvider
gas_limit                eth_estimateGas / EthGasLimit   Local (helper)
gas_price (legacy)       eth_gasPrice                    FeeOracle
max_fee_per_gas (1559)   eth_feeHistory / baseFee        FeeOracle
max_inclusion_fee_per_gas eth_feeHistory                 FeeOracle
to_address               Caller knows                    —
transaction payload      Caller knows                    —

tx_mode selects the serialization format: EthTxModeLegacy (0), EthTxModeEIP2930 (1), or EthTxModeEIP1559 (2).

## Tron — tron.SigningInput (TRX, TRC-20)

Field                          Source                      Provider
────────────────────────────────────────────────────────────────────
transaction.block_header       getNowBlock / getBlockByNum —
  .number                      block.block_header.raw.number
  .timestamp                   block.block_header.raw.timestamp
  .tx_trie_root                block.block_header.raw.txTrieRoot
  .parent_hash                 block.block_header.raw.parentHash
  .witness_address             block.block_header.raw.witnessAddress
  .version                     block.block_header.raw.version
transaction.expiration         timestamp + expiry window   Local (defaults +10 h)
transaction.timestamp          Current time                Local (defaults now)
transaction.fee_limit          Caller decision (TRC-20)    FeeOracle
contract payload               Caller knows                —

ref_block_bytes and ref_block_hash are derived from block_header by the library; callers do not set them directly.

## XRP — ripple.SigningInput (XRP, issued currencies)

Field                Source                              Provider
────────────────────────────────────────────────────────────────────
sequence             account_info → Sequence             NonceProvider
last_ledger_sequence Current ledger index + safety margin —
fee                  fee command → base_fee (drops)      FeeOracle
account              Derived from wallet (Address/ParseAddress) Local
flags                Caller sets (e.g. tfFullyCanonicalSig)   —
payment / trust_set / offer fields   Caller knows        —

## Cosmos — cosmos.SigningInput (ATOM, OSMO, JUNO, EVMOS, INJ, …)

Field                Source                              Provider
────────────────────────────────────────────────────────────────────
account_number       /cosmos/auth/v1beta1/accounts/{addr} → account_number   NonceProvider (first call)
sequence             /cosmos/auth/v1beta1/accounts/{addr} → sequence         NonceProvider (second call)
chain_id             Known chain constant                Local
fee.gas              CosmosGasLimit(in) helper           Local (helper)
fee.amount / denom   CosmosMinFee(gas, price, denom)     Local (helper)
memo                 Caller                              —
messages / send      Caller knows                        —

Both account_number and sequence come from the same REST endpoint; fetch once and assign both fields. CosmosMinGasPrices maps well-known chains to their minimum gas price if you do not have a live oracle.

Cosmos Ethermint chains (EVMOS, INJ) use keccak256(SignDoc) instead of sha256 and a chain-specific pubkey type URL in AuthInfo; both are handled automatically by the SignTransaction dispatcher.

## Solana — solana.SigningInput (SOL, SPL tokens)

Field                Source                              Provider
────────────────────────────────────────────────────────────────────
recent_blockhash     getLatestBlockhash → value.blockhash RecentBlockhashProvider
transfer / token_transfer fields   Caller knows          —

The transaction fee on Solana is 5 000 lamports per signature and is deducted from the fee-payer's account automatically; it does not appear in SigningInput.

## Bitcoin-family — bitcoin.SigningInput (BTC, LTC, DOGE, BCH, ZEC, DASH, …)

Field                Source                              Provider
────────────────────────────────────────────────────────────────────
utxo (repeated)      Electrum / esplora / listunspent    UTXOProvider
  .out_point_hash    32-byte txid, internal byte order   UTXOProvider
  .out_point_index   vout                                UTXOProvider
  .amount            Value in satoshis                   UTXOProvider
  .script            scriptPubKey of the UTXO            UTXOProvider
byte_fee             estimatesmartfee / fee API (sat/vb) FeeOracle
to_address           Caller knows                        —
change_address       Caller knows (typically from wallet) Local
amount               Caller knows                        —
use_max_amount       Caller decision (send-all)          —

## Polkadot — polkadot.SigningInput (DOT, Asset Hub assets)

Field                Source                              Provider
────────────────────────────────────────────────────────────────────
nonce                system_accountNextIndex             NonceProvider
spec_version         state_getRuntimeVersion → specVersion        SubstrateContextProvider
transaction_version  state_getRuntimeVersion → transactionVersion SubstrateContextProvider
genesis_hash         chain_getBlockHash(0)               SubstrateContextProvider
block_hash + era     Recent finalized block (mortality)  SubstrateContextProvider
tip                  Caller decision (usually 0)         —
balance_transfer / asset_transfer fields   Caller knows  —

Omit era (and block_hash) for an immortal extrinsic. The transaction fee is weight-based and deducted automatically; it does not appear in SigningInput.

Broadcasting

SignTransaction returns a signed SigningOutput. The library never submits to the network. Pass SigningOutput.Encoded (binary) to Broadcaster.Broadcast, or use SigningOutput.EncodedHex / TxBytes for chain endpoints that expect hex or base64.

Security model

The mnemonic and derived seed are sealed in memguard enclaves — encrypted in RAM, page-locked against swap, automatically wiped on HDWallet.Destroy. The derived private key is materialised once per signing call inside the package and wiped on return; it is never returned to the caller. All signing inputs and outputs are plain structs with no secret material.

Deposit-address topology (watch-only limits)

Secp256k1 chains (BTC, ETH, ATOM, …) support seedless deposit-address generation via WatchOnlyFromXPub: an extended public key (xpub) is sufficient to derive all addresses, enabling a fully offline watch-only wallet on a key-less machine.

Ed25519 chains (SOL, XLM, ALGO, APTOS, TON, DOT) use SLIP-0010 hardened-only derivation — no public-key derivation path exists in the standard. As a result, the machine minting deposit addresses must hold the seed. To isolate signing from address generation, use an isolated signer service: the seed wallet opens the seed once per bulk address operation ([AddressRange], [AllAddressesAt]) and exposes a stateless interface for address queries and signing requests, never returning the seed or intermediate keys.

Package hdwallet is a Trust Wallet-compatible hierarchical-deterministic wallet for Go.

It generates a BIP-39 mnemonic (or imports one) and derives receive addresses for many networks using the same derivation paths and address formats Trust Wallet uses by default, so seeds are interchangeable between the two.

Secrets (the mnemonic and the derived seed) are never held as plain Go strings or long-lived byte slices. They are stored in encrypted, page-locked memguard enclaves and decrypted only for the duration of a single derivation. Always call (*HDWallet).Destroy when finished, and consider memguard.Purge on program exit.

Index

Examples

Constants

View Source
const (
	SigHashAll          uint32 = 0x01
	SigHashNone         uint32 = 0x02
	SigHashSingle       uint32 = 0x03
	SigHashAnyoneCanPay uint32 = 0x80
)

SigHashAll, SigHashNone, SigHashSingle and SigHashAnyoneCanPay are the standard Bitcoin SIGHASH flag bits used in SigningInput.HashType. A complete hash_type value is formed by OR-ing one base type (bits 0–4) with optional modifier bits: bit 7 (0x80) = AnyoneCanPay, bit 6 (0x40) = FORKID (BCH).

Common combinations:

0x01  SIGHASH_ALL                  — default; all inputs, all outputs
0x41  SIGHASH_ALL|FORKID           — BCH default
0x02  SIGHASH_NONE                 — no outputs committed
0x03  SIGHASH_SINGLE               — only input's paired output committed
0x81  SIGHASH_ALL|ANYONECANPAY     — only signing input; all outputs
0x83  SIGHASH_SINGLE|ANYONECANPAY  — only signing input; paired output
View Source
const (
	EthTxModeLegacy    uint32 = 0 // EIP-155 legacy
	EthTxModeEIP2930   uint32 = 1 // type-1 access-list
	EthTxModeEIP1559   uint32 = 2 // type-2 fee market
	EthTxModeEIP4844   uint32 = 3 // type-3 blob tx (EIP-4844)
	EthTxModeEIP7702   uint32 = 4 // type-4 set-code tx (EIP-7702)
	EthTxModeUserOp    uint32 = 5 // ERC-4337 v0.6 UserOperation
	EthTxModeUserOpV07 uint32 = 6 // ERC-4337 v0.7 UserOperation
)

EVM transaction modes, selecting the serialization format produced by SignTransaction for an EVM chain. They are the values of ethereum.SigningInput.tx_mode; use them instead of bare integers.

View Source
const (
	SolanaTokenProgramClassic uint32 = 0
	SolanaTokenProgram2022    uint32 = 1
)

SolanaTokenProgramClassic and SolanaTokenProgram2022 select which SPL token program a TransferChecked/CreateAndTransferToken instruction targets, via the SigningInput's token_program_id field.

View Source
const (
	// TONModePayFeesSeparately pays transfer fees separately from the message
	// value (send-mode bit 0).
	TONModePayFeesSeparately uint32 = 1
	// TONModeIgnoreActionPhaseErrors ignores errors during the action phase
	// (send-mode bit 1).
	TONModeIgnoreActionPhaseErrors uint32 = 2
)

TON send-mode flags (the `mode` byte on each wallet message). The default transfer mode is 3 = PAY_FEES_SEPARATELY | IGNORE_ACTION_PHASE_ERRORS.

View Source
const BTCSequenceRBF uint32 = 0xFFFFFFFD

BTCSequenceRBF is the BIP-125 opt-in sequence number. Set an input's OutPointSequence to this value to signal that the spending transaction may be replaced by fee (RBF). Any UTXO whose OutPointSequence is explicitly set to 0xFFFFFFFD will carry that sequence through to the signed transaction.

Variables

View Source
var (
	// ErrNegativeAmount is returned by ParseAmount and ParseUnits when the input
	// string represents a negative value. Wallet amounts are non-negative by
	// definition, so negative inputs are rejected rather than silently accepted.
	ErrNegativeAmount = errors.New("hdwallet: amount must not be negative")

	// ErrInvalidAmount is returned by ParseAmount and ParseUnits when the input
	// string is not a valid unsigned decimal number. Triggers include an empty
	// string, multiple decimal points, non-numeric characters, or more fractional
	// digits than the declared precision (extra precision is rejected rather than
	// silently truncated — a wrong value means permanently lost funds).
	ErrInvalidAmount = errors.New("hdwallet: invalid amount string")
)

Sentinel errors for amount parsing.

View Source
var (
	// ErrABIType is returned for an unrecognized or unsupported ABI type string.
	ErrABIType = errors.New("hdwallet: unsupported ABI type")
	// ErrABIValue is returned when a Go value does not match its ABI type.
	ErrABIValue = errors.New("hdwallet: ABI value does not match type")
	// ErrABIDecode is returned when ABI-encoded input is malformed.
	ErrABIDecode = errors.New("hdwallet: malformed ABI encoding")
)

ABI-related errors.

View Source
var (
	// ErrRLPCanonical is returned when a decoded item is not in canonical form
	// (e.g. a leading zero in a length prefix, or a single byte < 0x80 wrapped in
	// a string header). Ethereum requires canonical RLP.
	ErrRLPCanonical = errors.New("hdwallet: non-canonical RLP encoding")
	// ErrRLPTruncated is returned when the input ends before a declared length.
	ErrRLPTruncated = errors.New("hdwallet: truncated RLP input")
	// ErrRLPTrailing is returned by DecodeRLP when bytes remain after one item.
	ErrRLPTrailing = errors.New("hdwallet: trailing bytes after RLP item")
)

RLP-related errors.

View Source
var (
	// ErrInvalidMnemonic is returned when a mnemonic fails BIP-39 validation.
	ErrInvalidMnemonic = errors.New("hdwallet: invalid mnemonic")
	// ErrUnsupportedCoin is returned for a chain not in the registry.
	ErrUnsupportedCoin = errors.New("hdwallet: unsupported coin")
	// ErrDestroyed is returned by operations on a wallet whose secrets were wiped.
	ErrDestroyed = errors.New("hdwallet: wallet has been destroyed")
	// ErrInvalidDigest is returned when an ECDSA signing input is not 32 bytes.
	ErrInvalidDigest = errors.New("hdwallet: digest must be 32 bytes")
	// ErrInvalidPrivateKey is returned when an imported private key has the wrong
	// length or is otherwise invalid for its curve.
	ErrInvalidPrivateKey = errors.New("hdwallet: invalid private key")
	// ErrUnsupportedCurve is returned when a curve is not one of the supported
	// elliptic curves.
	ErrUnsupportedCurve = errors.New("hdwallet: unsupported curve")
	// ErrCurveMismatch is returned when an operation targets a coin whose curve
	// differs from the curve of a key-only wallet's imported private key.
	ErrCurveMismatch = errors.New("hdwallet: coin curve does not match imported key curve")
	// ErrKeyOnlyWallet is returned by mnemonic/seed-only operations (Mnemonic,
	// WithMnemonic, AllAddresses) on a wallet imported from a raw private key.
	ErrKeyOnlyWallet = errors.New("hdwallet: operation not available on a private-key-only wallet")
	// ErrKeyOnlyIndex is returned when a non-zero address/sign index is requested
	// on a key-only wallet, which has a single leaf key and no HD path.
	ErrKeyOnlyIndex = errors.New("hdwallet: private-key-only wallet supports only index 0")
	// ErrPathArity is returned by the structured account/change/index helpers
	// (AddressAt, SignAt, PublicKeyAt) when a coin's path template is not a
	// 5-element BIP-44/BIP-84 path; use the AddressPath/SignPath primitives instead.
	ErrPathArity = errors.New("hdwallet: coin path is not a 5-element BIP-44/84 path; use the *Path methods")
	// ErrExtKeyUnsupportedCurve is returned by the extended-key (xprv/xpub) and
	// watch-only APIs for a non-secp256k1 coin: BIP-32 extended keys and public
	// (non-hardened) child derivation apply only to secp256k1; the SLIP-0010
	// ed25519/nist256p1 schemes support hardened derivation only.
	ErrExtKeyUnsupportedCurve = errors.New("hdwallet: extended keys / watch-only require a secp256k1 coin")
	// ErrInvalidWordCount is returned when a requested mnemonic length is not a
	// valid BIP-39 word count (12, 15, 18, 21, or 24) or entropy size in bits
	// (128, 160, 192, 224, or 256).
	ErrInvalidWordCount = errors.New("hdwallet: invalid mnemonic word count")
)

Exported sentinel errors. Consumers can match them with errors.Is; errors that add context (e.g. the offending chain) wrap these with %w.

View Source
var (
	// ErrTxUnsupported is returned when SignTransaction is asked to sign for a
	// chain whose family has no transaction builder.
	ErrTxUnsupported = errors.New("hdwallet: transaction signing not supported for coin")
	// ErrTxInput is returned when the SigningInput proto type does not match the
	// family selected by chain, or a required field is missing/invalid.
	ErrTxInput = errors.New("hdwallet: invalid transaction signing input")
)

Transaction-signing errors.

View Source
var CosmosMinGasPrices = map[Chain]struct {
	Price float64
	Denom string
}{
	ATOM: {0.005, "uatom"},
	OSMO: {0.0025, "uosmo"},
	JUNO: {0.001, "ujuno"},
	KAVA: {0.001, "ukava"},
}

CosmosMinGasPrices maps well-known Cosmos chains to their minimum gas price.

View Source
var (
	// ErrEIP712 is returned for malformed typed data or unsupported types.
	ErrEIP712 = errors.New("hdwallet: invalid EIP-712 typed data")
)

EIP-712-related errors.

View Source
var (
	// ErrEthSignature is returned when an Ethereum signature is malformed.
	ErrEthSignature = errors.New("hdwallet: invalid ethereum signature")
)

Ethereum message errors.

View Source
var ErrInvalidAddress = errors.New("hdwallet: invalid address")

ErrInvalidAddress is the base sentinel for all address-validation failures. Specific reasons (bad checksum, wrong prefix, wrong length, …) wrap it with %w, so errors.Is(err, ErrInvalidAddress) matches any validation failure while the message still describes the precise cause.

View Source
var ErrInvalidWIF = errors.New("hdwallet: invalid WIF private key")

ErrInvalidWIF is returned for a malformed WIF string or a WIF export requested for a non-secp256k1 coin.

View Source
var ErrNoTxID = errors.New("hdwallet: signing output has no transaction id")

ErrNoTxID is returned by TransactionID when a SigningOutput carries no transaction id (an empty id field) or when the argument is not one of the eight recognised per-family *…SigningOutput types (including a nil proto.Message).

View Source
var ErrNotRecoverable = errors.New("hdwallet: coin curve does not support recoverable signatures")

ErrNotRecoverable is returned by SignBitcoinMessage when the coin's curve is not secp256k1 (only secp256k1 produces a recoverable signature).

View Source
var ErrTxDecode = errors.New("hdwallet: malformed transaction bytes")

ErrTxDecode is returned when raw transaction bytes are malformed, truncated or otherwise not a transaction this decoder understands. The decoder never panics and never reads past the input.

Functions

func ABIEncode added in v0.2.2

func ABIEncode(name string, args []ABIValue) ([]byte, error)

ABIEncode encodes a function call: selector(name,types...) || head/tail(args). The signature is formed from name and the argument types, so name must be the bare function name (e.g. "transfer"), not the full signature.

func ABIEncodeParams added in v0.2.2

func ABIEncodeParams(values []ABIValue) ([]byte, error)

ABIEncodeParams encodes a tuple of values (no selector) using the head/tail layout. This is the encoding used for the arguments of a call and for nested tuples/arrays.

func ABIFunctionSelector added in v0.2.2

func ABIFunctionSelector(name string, types []string) []byte

ABIFunctionSelector returns the 4-byte selector for a function signature built from name and the given argument types (the canonical forms are used).

func ActivationCost added in v0.14.0

func ActivationCost(chain Chain) (*big.Int, bool)

ActivationCost returns the one-off cost charged when first funding a previously unseen account (e.g. TRX's account-creation fee). This is distinct from an ongoing reserve requirement: XLM/XRP's reserve is not a one-off fee consumed on activation but a floor the balance must stay above indefinitely, so it is modeled under MinimumBalance instead — not here.

func AddressFromPayload added in v0.10.0

func AddressFromPayload(chain Chain, payload []byte) (string, error)

AddressFromPayload derives an address for chain from a raw address payload. For EVM/secp256k1 chains: payload is the 20-byte keccak address. For Bitcoin P2PKH: payload is the 20-byte hash160 (always encodes as P2PKH). For ed25519 chains: payload is the 32-byte public key. Returns ErrUnsupportedCoin if the chain is not in the validator registry (or payload re-encoding is not implemented), or ErrInvalidAddress if the payload length does not match the expected format.

func AddressFromPublicKey added in v0.2.2

func AddressFromPublicKey(chain Chain, pub []byte) (string, error)

AddressFromPublicKey derives the address for chain directly from an external public key, reusing the registry's encoder (read-only). pub must be the curve's expected public-key form: a 33-byte compressed key for secp256k1/nist256p1, or a 32-byte key for ed25519. An unknown chain returns ErrUnsupportedCoin; a malformed key is reported by the underlying encoder.

func BroadcastPayload added in v0.11.0

func BroadcastPayload(chain Chain, out proto.Message) (string, error)

BroadcastPayload returns the RPC-ready string for submitting a signed transaction produced by (*HDWallet).SignTransaction, hiding the per-family differences in encoding and field naming behind a single accessor.

chain selects the expected output type; if the concrete type of out does not correspond to chain's transaction family, ErrTxInput is returned.

The returned value, by family:

  • EVM (ETH/BNB/MATIC/… and all evmTxChains) "0x"-prefixed lowercase hex of the signed RLP (eth_sendRawTransaction).

  • Bitcoin/UTXO (BTC/LTC/DOGE/DASH/BCH/ZEC/… and all utxoTxChains) Lowercase hex of the signed wire-format tx (sendrawtransaction / sendrawtx).

  • Solana (SOL) Standard (padded) base64 of the signed transaction bytes, suitable for sendTransaction with encoding="base64".

  • Cosmos (ATOM/OSMO/… and all cosmosTxChains; also ethermint EVMOS/INJ) Standard base64 of the TxRaw broadcast bytes (the tx_bytes field of a cosmos.tx.v1beta1.BroadcastTxRequest).

  • Tron (TRX) JSON object accepted by TronGrid POST /wallet/broadcasttransaction: {"txID":"<hex>","raw_data_hex":"<hex>","signature":["<hex>"]}.

  • XRP/Ripple (XRP) Uppercase hex of the signed transaction (the tx_blob parameter of the rippled submit command).

  • Polkadot (DOT) "0x"-prefixed lowercase hex of the signed extrinsic, the exact form accepted by the author_submitExtrinsic RPC method.

Pure formatting over existing output fields — no re-signing, no network I/O. A nil or unrecognised out type returns ErrTxInput.

func BuildBRC20TransferBody added in v0.12.3

func BuildBRC20TransferBody(ticker, amount string) []byte

BuildBRC20TransferBody returns the canonical BRC-20 transfer JSON body. Field order is fund-critical (indexers are order-sensitive); we use fmt.Sprintf rather than json.Marshal to guarantee the exact field sequence.

func BuildBabylonOpReturn added in v0.12.3

func BuildBabylonOpReturn(stakerXonly []byte, finalityProviderXonly []byte, stakingTime uint16) []byte

BuildBabylonOpReturn builds the OP_RETURN identifier output used by the Babylon protocol to tag a staking transaction on-chain.

Format (after OP_RETURN):

"bbn\x01" (4 bytes magic + version byte 0x01)
+ version byte 0x00
+ stakerXonly (32 bytes)
+ finalityProviderXonly (32 bytes, or 32 zero bytes if nil)
+ stakingTime as 2-byte little-endian uint16

stakerXonly must be a 32-byte x-only public key. finalityProviderXonly must be a 32-byte x-only key, or nil (32 zero bytes used). Returns the full script: 0x6a (OP_RETURN) + minimal data push of the tag.

func BuildBabylonStakingOutput added in v0.12.3

func BuildBabylonStakingOutput(stakerKey []byte, covenantKeys [][]byte, covenantQuorum int, stakingTime uint16) (scriptPubKey []byte, err error)

BuildBabylonStakingOutput computes the P2TR scriptPubKey for a Babylon staking output. It assembles a tap-tree with a timelock leaf, an unbonding leaf, and a slashing leaf, rooted under the BIP-341 NUMS unspendable internal key.

  • stakerKey: 33-byte compressed or 32-byte x-only public key of the staker.
  • covenantKeys: one or more 33-byte compressed or 32-byte x-only covenant keys.
  • covenantQuorum: the m in the m-of-n covenant multisig (1 ≤ quorum ≤ len(covenantKeys)).
  • stakingTime: the CSV lockup period in blocks (uint16).

Returns the 34-byte P2TR scriptPubKey: OP_1 <32-byte output xonly>.

func BuildBabylonTimelockLeaf added in v0.12.3

func BuildBabylonTimelockLeaf(stakerXonly []byte, stakingTime uint16) []byte

BuildBabylonTimelockLeaf builds the tapscript leaf for the Babylon timelock spending path:

<staker_xonly> OP_CHECKSIGVERIFY <staking_time_LE2> OP_CSV OP_DROP OP_TRUE

stakingTime is encoded as a 2-byte little-endian uint16 (Bitcoin script number for OP_CSV). stakerXonly must be a 32-byte x-only public key.

func BuildInscriptionScript added in v0.12.3

func BuildInscriptionScript(xonlyPubkey []byte, contentType string, body []byte) ([]byte, error)

BuildInscriptionScript builds the tapscript leaf for an Ordinals inscription.

Layout:

<32-byte xonly pubkey> OP_CHECKSIG   // key-spend guard
OP_FALSE OP_IF                        // envelope open  (OP_0 = 0x00, OP_IF = 0x63)
  push("ord")                         // protocol tag
  OP_1 push(<contentType bytes>)      // content-type field
  OP_0 push(<body chunk>)             // body chunks, ≤520 bytes each
  [OP_0 push(<next chunk>) …]
OP_ENDIF                              // envelope close

xonlyPubkey must be exactly 32 bytes; returns ErrTxInput otherwise.

func BuildMultisigPSBT added in v0.11.0

func BuildMultisigPSBT(chain Chain, in *txbtc.SigningInput, redeemScript []byte) ([]byte, error)

BuildMultisigPSBT constructs an unsigned BIP-174 PSBT for spending a multisig UTXO. redeemScript is the m-of-n script produced by BuildMultisigRedeemScript (for P2SH it is also the redeemScript; for P2WSH it becomes the witnessScript). The type (P2SH or P2WSH) is inferred from each UTXO's scriptPubKey in in.

Coin selection uses the same planBitcoinTx logic as the single-key path. Fee estimation is approximate — it assumes P2SH/P2WSH per-type overhead and does not model the extra witness bytes of multisig scripts; callers should add headroom if byte-exact fees matter.

Only chains in btcAddrParams (BTC, LTC, and the native-SegWit altcoins) are accepted. Legacy P2PKH inputs in in.Utxo are rejected (same reason as the single-key PSBT path: no full prev-tx in the proto).

func BuildMultisigRedeemScript added in v0.11.0

func BuildMultisigRedeemScript(m int, pubkeys [][]byte) ([]byte, error)

BuildMultisigRedeemScript returns an OP_m <pubkeys> OP_n OP_CHECKMULTISIG script with the pubkeys sorted lexicographically (BIP-67). It is used both as the redeemScript for P2SH and as the witnessScript for P2WSH.

Constraints: 1 ≤ m ≤ n ≤ 16; every pubkey must be a 33-byte compressed point.

func BuildPSBT added in v0.6.0

func BuildPSBT(chain Chain, in *txbtc.SigningInput) ([]byte, error)

BuildPSBT builds an unsigned PSBT (BIP-174) for chain from in, returning the serialized packet. Coin selection (planBitcoinTx) chooses which UTXOs become inputs and computes the recipient/change outputs exactly as the direct signer would, so a subsequent SignPSBT/FinalizePSBT/ExtractPSBTTx produces the same transaction. Supported input types: P2WPKH, P2SH-P2WPKH, P2TR, and legacy P2PKH (via a synthetic NonWitnessUtxo using multisigFakePrevTx).

func BuildPSBTV2 added in v0.10.0

func BuildPSBTV2(chain Chain, in *txbtc.SigningInput) ([]byte, error)

BuildPSBTV2 constructs an unsigned BIP-370 PSBT for chain from in. Coin selection runs the same planBitcoinTx as the direct signer. Only segwit input types (P2WPKH, P2SH-P2WPKH, P2TR) are accepted; P2PKH returns ErrTxInput because the proto does not carry the full previous transaction.

func CPFPFee added in v0.10.0

func CPFPFee(parentFeeAlreadyPaid, parentVsize, childVsize int64, targetSatPerVbyte float64) int64

CPFPFee returns the fee a child tx must pay so that the parent+child package confirms at targetSatPerVbyte sat/vbyte. parentFeeAlreadyPaid is the fee the parent tx already included (satoshis); parentVsize and childVsize are virtual sizes in vbytes (use EstimateTxVsize). Returns 0 if the parent alone already meets or exceeds the target rate.

func CREATE2Address added in v0.10.0

func CREATE2Address(deployer []byte, salt [32]byte, initCode []byte) []byte

CREATE2Address computes the address a CREATE2 deployment will land at.

deployer — address calling CREATE2 (20 bytes)
salt     — 32-byte salt
initCode — contract init bytecode

Formula: keccak256(0xff ‖ deployer ‖ salt ‖ keccak256(initCode))[12:]

func ChecksumEthAddress added in v0.10.0

func ChecksumEthAddress(addr string) (string, error)

ChecksumEthAddress returns the EIP-55 mixed-case checksum of an Ethereum address. Input may be with or without "0x"/"0X" prefix, any case. Returns ErrInvalidAddress if the input is not a valid 20-byte hex address.

func CoinDecimals added in v0.10.0

func CoinDecimals(chain Chain) int

CoinDecimals returns the number of decimal places for the base unit of chain. Returns 0 if chain is not registered.

func CoinFamily added in v0.10.0

func CoinFamily(chain Chain) string

CoinFamily returns a string identifying the chain family for routing purposes. Values: "evm", "cosmos", "bitcoin-utxo", "solana", "tron", "ripple", "stellar", "polkadot", or "unknown".

func CombineCosmosMultisig added in v0.14.0

func CombineCosmosMultisig(threshold int, pubkeys [][]byte, in *txcosmos.SigningInput, sigs map[int][]byte) (*txcosmos.SigningOutput, error)

CombineCosmosMultisig assembles the broadcastable TxRaw from at least `threshold` partial signatures, keyed by index into pubkeys (the same ordered list used for CosmosMultisigAddress). Every partial is VERIFIED against its public key before combining (fund-critical guard). Pure function: no wallet, no secrets.

func CosmosGasLimit added in v0.10.0

func CosmosGasLimit(in *cosmos.SigningInput) uint64

CosmosGasLimit returns a conservative gas limit for the given Cosmos signing input. It sums per-message estimates; returns 80000 if no messages are present.

func CosmosMinFee added in v0.10.0

func CosmosMinFee(gasLimit uint64, minGasPrice float64, denom string) string

CosmosMinFee returns the minimum fee string (e.g. "5000uatom") for the given gas limit and minimum gas price in the chain's smallest denom unit.

func CosmosMultisigAddress added in v0.14.0

func CosmosMultisigAddress(hrp string, threshold int, pubkeys [][]byte) (string, error)

CosmosMultisigAddress returns the bech32 address of an m-of-n LegacyAminoMultisig account under hrp (e.g. "cosmos"). Key ORDER matters: the same ordered key list must be used for partial-signature indices and CombineCosmosMultisig. Pure function, no secrets.

func DecryptWIF added in v0.10.0

func DecryptWIF(encrypted string, passphrase []byte, fn func(wif []byte)) error

DecryptWIF decrypts a BIP-38 '6P…' encrypted key with passphrase. fn receives the WIF-encoded private key bytes; the slice is wiped before DecryptWIF returns. Returns ErrInvalidWIF if the passphrase is wrong.

func DustThreshold added in v0.14.0

func DustThreshold(chain Chain) (*big.Int, bool)

DustThreshold returns the standard-relay dust limit for UTXO chains (sats), reusing tx_bitcoin.go's btcDustThreshold — the same constant the signer itself uses to decide whether a change output is worth creating.

func EIP712Hash added in v0.2.2

func EIP712Hash(typedDataJSON []byte) ([]byte, error)

EIP712Hash parses MetaMask-shape typed-data JSON and returns the 32-byte keccak256 digest to sign (the 0x1901-prefixed hash).

func ERC20ApproveCalldata added in v0.10.0

func ERC20ApproveCalldata(spender []byte, amount *big.Int) []byte

ERC20ApproveCalldata builds approve(spender, amount) calldata.

func ERC20PermitCalldata added in v0.10.0

func ERC20PermitCalldata(owner, spender []byte, value, deadline *big.Int, v uint8, r, s [32]byte) []byte

ERC20PermitCalldata builds permit(owner, spender, value, deadline, v, r, s) calldata for EIP-2612.

func ERC20TransferLog added in v0.10.0

func ERC20TransferLog(log *EthLog) (from, to string, amount *big.Int, err error)

ERC20TransferLog decodes a standard ERC-20 Transfer(address,address,uint256) event log. Topics[1]=from (indexed), Topics[2]=to (indexed), Data=amount. Returns ErrTxDecode if the log does not match the Transfer event signature.

func ERC721ApproveCalldata added in v0.10.0

func ERC721ApproveCalldata(to []byte, tokenID *big.Int) []byte

ERC721ApproveCalldata builds approve(to, tokenId) calldata.

func ERC721SafeTransferCalldata added in v0.10.0

func ERC721SafeTransferCalldata(from, to []byte, tokenID *big.Int) []byte

ERC721SafeTransferCalldata builds safeTransferFrom(from, to, tokenId) calldata.

func ERC721SafeTransferWithDataCalldata added in v0.10.0

func ERC721SafeTransferWithDataCalldata(from, to []byte, tokenID *big.Int, data []byte) []byte

ERC721SafeTransferWithDataCalldata builds safeTransferFrom(from, to, tokenId, data) calldata.

func ERC721SetApprovalForAllCalldata added in v0.10.0

func ERC721SetApprovalForAllCalldata(operator []byte, approved bool) []byte

ERC721SetApprovalForAllCalldata builds setApprovalForAll(operator, approved) calldata.

func ERC721TransferCalldata added in v0.10.0

func ERC721TransferCalldata(from, to []byte, tokenID *big.Int) []byte

ERC721TransferCalldata builds transferFrom(from, to, tokenId) calldata.

func ERC721TransferLog added in v0.10.0

func ERC721TransferLog(log *EthLog) (from, to string, tokenID *big.Int, err error)

ERC721TransferLog decodes a standard ERC-721 Transfer(address,address,uint256) event log. Topics[1]=from, Topics[2]=to, Topics[3]=tokenId (all indexed). Returns ErrTxDecode if the log does not match the Transfer event signature.

func ERC1155SafeBatchTransferCalldata added in v0.10.0

func ERC1155SafeBatchTransferCalldata(from, to []byte, ids, amounts []*big.Int, data []byte) []byte

ERC1155SafeBatchTransferCalldata builds safeBatchTransferFrom(from, to, ids, amounts, data) calldata.

func ERC1155SafeTransferCalldata added in v0.10.0

func ERC1155SafeTransferCalldata(from, to []byte, id, amount *big.Int, data []byte) []byte

ERC1155SafeTransferCalldata builds safeTransferFrom(from, to, id, amount, data) calldata.

func ERC1155SetApprovalForAllCalldata added in v0.10.0

func ERC1155SetApprovalForAllCalldata(operator []byte, approved bool) []byte

ERC1155SetApprovalForAllCalldata builds setApprovalForAll(operator, approved) calldata.

func EncodeRLP added in v0.2.2

func EncodeRLP(item RLPItem) []byte

EncodeRLP encodes an RLP tree to its canonical byte serialization.

func EstimateBitcoinFee added in v0.6.0

func EstimateBitcoinFee(inputs []BitcoinInputKind, outputs []BitcoinOutputKind, satPerVbyte int64) int64

EstimateBitcoinFee returns the estimated fee (satoshis) for a transaction of the given input/output kinds at satPerVbyte sat/vbyte. It is fee-planning guidance, not a consensus value: fee = EstimateTxVsize * satPerVbyte.

func EstimateTxVsize added in v0.6.0

func EstimateTxVsize(inputs []BitcoinInputKind, outputs []BitcoinOutputKind) int64

EstimateTxVsize returns an approximate virtual size (vbytes) for a transaction spending the given input kinds to the given output kinds. It is a coarse estimate for fee planning only (not consensus-exact): per-type constants are measured against btcd's blockchain/txsizes, with a fixed overhead for the version, locktime, the input/output counts and the amortised SegWit marker/flag when any input carries a witness.

ponytail: coarse per-type constants, good enough for fee math; refine if fee-rate accuracy ever matters.

func EthGasLimit added in v0.10.0

func EthGasLimit(in *ethereum.SigningInput) uint64

EthGasLimit returns a conservative gas limit estimate for the given signing input. Native transfers return exactly 21000. Known selectors return the table value. Contract deploys and generic calls use calldata cost + headroom.

func EthereumPersonalMessageHash added in v0.2.2

func EthereumPersonalMessageHash(message []byte) []byte

EthereumPersonalMessageHash returns the 32-byte keccak256 digest that EIP-191 personal_sign signs for the given message. len(message) is rendered as its decimal ASCII representation, per the standard.

func ExtractMultisigTx added in v0.11.0

func ExtractMultisigTx(psbtBytes []byte) ([]byte, error)

ExtractMultisigTx finalizes (if needed) a signed multisig PSBT and returns the network-serialized signed transaction ready for broadcast.

func ExtractPSBTTx added in v0.6.0

func ExtractPSBTTx(psbtBytes []byte) ([]byte, error)

ExtractPSBTTx finalizes (if needed) and extracts the network-serialized signed transaction from a signed PSBT.

func ExtractPSBTV2Tx added in v0.10.0

func ExtractPSBTV2Tx(psbtBytes []byte) ([]byte, error)

ExtractPSBTV2Tx finalizes (if needed) and extracts the network-serialized signed transaction from a BIP-370 PSBT.

func FinalizeMultisigPSBT added in v0.11.0

func FinalizeMultisigPSBT(psbtBytes []byte) ([]byte, error)

FinalizeMultisigPSBT runs the BIP-174 finalizer over a signed multisig PSBT and returns the finalized packet bytes. The finalizer assembles:

  • P2SH: OP_FALSE <ordered-sigs...> <redeemScript> as the scriptSig
  • P2WSH: <nil> <ordered-sigs...> <witnessScript> as the witness stack

btcd's finalizer orders signatures by the position of the corresponding pubkey in the redeemScript/witnessScript (required for multisig validation). It returns an error if fewer than m signatures are present.

func FinalizePSBT added in v0.6.0

func FinalizePSBT(psbtBytes []byte) ([]byte, error)

FinalizePSBT runs the BIP-174 Finalizer over a fully signed packet and returns the finalized serialized PSBT.

func FinalizePSBTV2 added in v0.10.0

func FinalizePSBTV2(psbtBytes []byte) ([]byte, error)

FinalizePSBTV2 runs the BIP-370 finalizer over a signed packet: it moves partial signatures into the final scriptSig / witness fields.

func FormatAmount added in v0.11.0

func FormatAmount(chain Chain, raw *big.Int) (string, error)

FormatAmount converts a raw integer amount (in the coin's native smallest unit) to a human-readable decimal string using the decimal count registered for chain. It returns ErrUnsupportedCoin for an unknown chain.

This is the native-coin helper. For ERC-20, SPL, or TRC-20 tokens whose decimal count comes from the token contract, use FormatUnits directly.

Examples:

FormatAmount(BTC, big.NewInt(100_000_000)) // "1"   (1 BTC = 1e8 satoshis)
FormatAmount(ETH, big.NewInt(1_500_000_000_000_000_000)) // "1.5"

func FormatUnits added in v0.11.0

func FormatUnits(raw *big.Int, decimals uint8) string

FormatUnits converts a raw integer amount to a human-readable decimal string with the given decimal precision. It is the coin-agnostic primitive used by FormatAmount, and is the correct helper for ERC-20, SPL, and TRC-20 tokens where the decimal count is provided by the token contract's metadata rather than the native coin registry.

Trailing fractional zeros are stripped ("1.500" → "1.5"). A nil raw is treated as zero. Negative raw values are formatted with a leading "-".

Examples (decimals=18):

FormatUnits(big.NewInt(0), 18)                              // "0"
FormatUnits(big.NewInt(1_000_000_000_000_000_000), 18)      // "1"
FormatUnits(big.NewInt(1_500_000_000_000_000_000), 18)      // "1.5"
FormatUnits(big.NewInt(1), 18)                              // "0.000000000000000001"

func GenerateMnemonic

func GenerateMnemonic() (string, error)

GenerateMnemonic returns a fresh 12-word BIP-39 mnemonic as a Go string.

Security note: Go strings are GC-managed and cannot be reliably wiped from memory. For security-sensitive applications (hardware wallets, HSMs) prefer GenerateMnemonicBuffer, which returns the phrase in a page-locked enclave that is wiped on Destroy. If you use this function, call FromMnemonicBytes immediately and discard the string rather than storing it.

func GenerateMnemonicBuffer added in v0.10.0

func GenerateMnemonicBuffer() (*memguard.LockedBuffer, error)

GenerateMnemonicBuffer returns a fresh 12-word BIP-39 mnemonic in a page-locked, encrypted-at-rest memguard buffer. The caller must call Destroy on the returned buffer when finished. This is the secure alternative to GenerateMnemonic for applications where the phrase must not linger on the Go heap.

func GenerateMnemonicBufferWithWordCount added in v0.10.0

func GenerateMnemonicBufferWithWordCount(words int) (*memguard.LockedBuffer, error)

GenerateMnemonicBufferWithWordCount returns a fresh BIP-39 mnemonic of the given length (12, 15, 18, 21, or 24 words) in a page-locked memguard buffer. An unsupported word count returns ErrInvalidWordCount.

func GenerateMnemonicWithWordCount added in v0.3.1

func GenerateMnemonicWithWordCount(words int) (string, error)

GenerateMnemonicWithWordCount returns a fresh BIP-39 mnemonic of the given length in words (12, 15, 18, 21, or 24) as a string. Like GenerateMnemonic, the returned string cannot be securely wiped; prefer NewHDWalletWithWordCount for sensitive use. An unsupported word count returns an error wrapping ErrInvalidWordCount.

func GetFunctionSignature added in v0.12.5

func GetFunctionSignature(fn ContractABIFunction) string

GetFunctionSignature returns the canonical signature string for a function, e.g. "transfer(address,uint256)".

func IsCosmosSDK added in v0.10.0

func IsCosmosSDK(chain Chain) bool

IsCosmosSDK returns true if chain uses the Cosmos SDK signing path.

func IsEVM added in v0.10.0

func IsEVM(chain Chain) bool

IsEVM returns true if chain is an EVM-compatible chain (Ethereum, BNB, Polygon, etc.)

func IsUTXO added in v0.10.0

func IsUTXO(chain Chain) bool

IsUTXO returns true if chain uses Bitcoin-style UTXO transaction model.

func IsValidAddress added in v0.2.2

func IsValidAddress(chain Chain, addr string) bool

IsValidAddress reports whether addr is a syntactically and checksum-valid address for the given network. It is a convenience wrapper over ValidateAddress.

func IsValidWord added in v0.11.0

func IsValidWord(word string) bool

IsValidWord reports whether word is present in the BIP-39 English wordlist.

func MinimumBalance added in v0.14.0

func MinimumBalance(chain Chain) (*big.Int, bool)

MinimumBalance returns the minimum native balance (in base units) an account must retain to exist on-chain, and whether the chain has such a constraint. Values are protocol parameters as of 2026-07-04 (sources in the package-level var comments above) and can change by governance — treat as sanity floors, not consensus data.

func MnemonicStrength added in v0.11.0

func MnemonicStrength(mnemonic string) (bits int, words int, err error)

MnemonicStrength validates mnemonic and returns its entropy size in bits and word count. It is intended for a "strength indicator" on a wallet-import screen, e.g. "128 bits · 12 words". Surrounding whitespace is trimmed before validation, exactly as the wallet constructors do.

Returns ErrInvalidMnemonic for an invalid phrase (wrong word count, unknown words, or bad checksum).

func MultisigP2SHAddress added in v0.11.0

func MultisigP2SHAddress(chain Chain, redeemScript []byte) (string, error)

MultisigP2SHAddress returns the P2SH address for redeemScript on chain. Only chains in btcAddrParams (BTC, LTC, DGB, SYS, VIA, STRAX) are supported.

func MultisigP2WSHAddress added in v0.11.0

func MultisigP2WSHAddress(chain Chain, witnessScript []byte) (string, error)

MultisigP2WSHAddress returns the native-SegWit P2WSH bech32 address for witnessScript on chain (the same script as the redeemScript — just the name changes to match BIP-141 terminology). Only chains in btcAddrParams are supported.

func NativeDecimals added in v0.11.0

func NativeDecimals(chain Chain) (uint8, bool)

NativeDecimals returns the number of fractional digits in the coin's native base unit (e.g. 8 for BTC/satoshis, 18 for ETH/wei, 6 for ATOM/uatom).

The second return value reports whether chain is a registered coin; an unregistered chain returns (0, false). This is a thin convenience wrapper over CoinInfo for callers that only need the decimal count.

func NormalizeXPub added in v0.10.0

func NormalizeXPub(extKey string) (string, error)

NormalizeXPub converts a ypub/zpub (or their testnet equivalents) to standard xpub format so it can be passed to WatchOnlyFromXPub. xpub/tpub inputs are returned unchanged. Returns an error for unrecognized prefixes.

func ParseAddress added in v0.2.2

func ParseAddress(chain Chain, addr string) ([]byte, error)

ParseAddress decodes addr for chain, verifies its checksum, and returns the decoded payload — e.g. the 20-byte hash160 for Bitcoin/Cosmos/Tron, the 32-byte public key for Solana/Stellar/SS58, or the 20/32-byte account identifier for EVM/Sui/Aptos. An unknown chain returns ErrUnsupportedCoin; an invalid address returns an error wrapping ErrInvalidAddress.

func ParseAmount added in v0.11.0

func ParseAmount(chain Chain, human string) (*big.Int, error)

ParseAmount parses a human-readable unsigned decimal string into its raw integer representation using the decimal count registered for chain. Returns ErrUnsupportedCoin for an unknown chain, ErrNegativeAmount for a negative input, and ErrInvalidAmount for a malformed string.

This is the native-coin helper. For ERC-20, SPL, or TRC-20 tokens whose decimal count comes from the token contract, use ParseUnits directly.

Examples:

ParseAmount(BTC, "0.5")  // big.Int: 50_000_000
ParseAmount(ETH, "1.5")  // big.Int: 1_500_000_000_000_000_000

func ParseUnits added in v0.11.0

func ParseUnits(human string, decimals uint8) (*big.Int, error)

ParseUnits parses a human-readable unsigned decimal string into its raw integer representation with the given decimal precision. It is the coin-agnostic primitive used by ParseAmount, and is the correct helper for ERC-20, SPL, and TRC-20 tokens where the decimal count is provided by the token contract's metadata.

Parsing rules:

  • Negative values are rejected with ErrNegativeAmount.
  • The fractional part must not exceed decimals digits; extra precision is rejected with ErrInvalidAmount (no silent truncation — a wrong value means lost funds).
  • Non-numeric characters and multiple decimal points return ErrInvalidAmount.
  • A leading dot (e.g. ".5") is accepted and treated as "0.5".

Examples (decimals=18):

ParseUnits("1",   18) // 1_000_000_000_000_000_000
ParseUnits("1.5", 18) // 1_500_000_000_000_000_000
ParseUnits("0",   18) // 0

func RecoverEthereumAddress added in v0.2.2

func RecoverEthereumAddress(message, sig []byte) (string, error)

RecoverEthereumAddress recovers the EIP-55 checksummed Ethereum address that produced sig over message under EIP-191 personal_sign. It is a convenience for callers that want the signer's address rather than a boolean match.

func SolanaComputeBudgetInstructions added in v0.10.0

func SolanaComputeBudgetInstructions(units uint32, priorityMicroLamportsPerCU uint64) [][]byte

SolanaComputeBudgetInstructions returns the serialized ComputeBudget program instructions to prepend: SetComputeUnitLimit (always) and SetComputeUnitPrice (only when priorityMicroLamportsPerCU > 0). Encoding: discriminator byte + little-endian value (no Borsh library needed).

func SolanaComputeUnits added in v0.10.0

func SolanaComputeUnits(in *solana.SigningInput) uint32

SolanaComputeUnits returns a conservative compute unit estimate for the input.

func SolanaTokenAccountAddress added in v0.14.0

func SolanaTokenAccountAddress(walletAddress, mintAddress string) (string, error)

SolanaTokenAccountAddress returns the SPL associated token account (ATA) — the canonical token account address — for a wallet address and token mint, both base58. It is a pure offline derivation: no wallet, no secrets, no network. Use it to compute deposit token accounts and withdrawal destinations for SPL tokens.

This derives against the classic SPL Token program; for a Token-2022 (Token Extensions) mint use SolanaTokenAccountAddressWithProgram.

func SolanaTokenAccountAddressWithProgram added in v0.14.0

func SolanaTokenAccountAddressWithProgram(walletAddress, mintAddress, tokenProgramID string) (string, error)

SolanaTokenAccountAddressWithProgram is SolanaTokenAccountAddress with an explicit token-program id (base58), so the ATA can be derived for the classic SPL Token program or the Token-2022 (Token Extensions) program — the seeds are [wallet, tokenProgramID, mint], and the token-program id enters the PDA derivation directly. Pure offline derivation: no wallet, no secrets, no network.

func SuggestFinalWords added in v0.11.0

func SuggestFinalWords(words []string) ([]string, error)

SuggestFinalWords takes a slice of 11, 14, 17, 20, or 23 valid BIP-39 words (the first N–1 words of a mnemonic) and returns every word from the English wordlist that, when appended, yields a valid BIP-39 checksum. Results are in wordlist (alphabetical) order.

Expected result counts per prefix length:

11 words → 12-word / 128-bit mnemonic → 128 valid completions
14 words → 15-word / 160-bit mnemonic →  64 valid completions
17 words → 18-word / 192-bit mnemonic →  32 valid completions
20 words → 21-word / 224-bit mnemonic →  16 valid completions
23 words → 24-word / 256-bit mnemonic →   8 valid completions

The function returns an error if the prefix length is not one of the values above, or if any word in words is not in the BIP-39 English wordlist.

func TransactionID added in v0.9.0

func TransactionID(out proto.Message) (string, error)

TransactionID returns one canonical transaction id for any SigningOutput produced by (*HDWallet).SignTransaction, hiding the per-family differences in field name, byte order and text encoding behind a single accessor so callers need not special-case each chain.

out must be one of the eight per-family SigningOutput messages. The id source, by family, is:

  • Bitcoin (and the UTXO altcoins BTC/LTC/DOGE/DASH/BCH/ZEC) — the conventional "txid" reverse(sha256d(tx without witnesses)); from the bytes field TransactionId.
  • Tron — sha256(raw_data); from the bytes field Id.
  • Ethereum / EVM — keccak256(signed RLP); from the string field TxId, which the signer stores as "0x"+hex.
  • Cosmos — sha256(TxRaw broadcast bytes); from the string field TxId, which the signer stores as upper-case hex.
  • Ripple / XRP — sha512Half(signed tx) (SHA-512(tx)[:32]); from the string field TxId, which the signer stores as upper-case hex.
  • Polkadot — BLAKE2b-256(Encoded), Substrate's standard extrinsic hash (matches the on-chain/Subscan "extrinsic hash"); computed from the bytes field Encoded.

For these five hash-based families the result is normalised to LOWER-CASE hex with NO "0x" prefix, irrespective of how the underlying field stores it. The two byte-typed ids (Bitcoin TransactionId, Tron Id) are already in display (big-endian) order and are hex-encoded as-is — no reversal is applied here.

Solana is the deliberate exception: its transaction id is NOT a hash but the base58-encoded fee-payer signature (Solana identifies a transaction by its first signature). It is returned exactly as the signer produced it — base58, unchanged — and must not be interpreted as hex.

An empty id, or any message that is not one of the eight recognised SigningOutput types (including a nil proto.Message), returns ErrNoTxID. The helper reads only the public output and touches no secret material.

func TronBandwidth added in v0.10.0

func TronBandwidth(_ *tron.SigningInput) int64

TronBandwidth returns the estimated bandwidth for a Tron signing input. All transactions consume at least 268 bandwidth units.

func TronEnergy added in v0.10.0

func TronEnergy(in *tron.SigningInput) int64

TronEnergy returns the estimated energy for a Tron signing input. Returns 0 for non-contract transactions; 65000 for TRC-20 transfers; 100000 for generic smart contract calls.

func UserOperationHash added in v0.10.0

func UserOperationHash(op *UserOperation, entryPoint []byte, chainID *big.Int) []byte

UserOperationHash computes the ERC-4337 v0.6 userOp hash (the value to sign).

Inner hash: keccak256(abi.encode(sender, nonce, keccak256(initCode), keccak256(callData), callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas, keccak256(paymasterAndData)))

Outer hash: keccak256(abi.encode(innerHash, entryPoint, chainID))

func ValidateAddress added in v0.2.2

func ValidateAddress(chain Chain, addr string) error

ValidateAddress returns nil if addr is a valid address for chain, or a descriptive error wrapping ErrInvalidAddress (bad checksum, wrong prefix, wrong length, …) or ErrUnsupportedCoin for an unknown chain.

func ValidateMnemonic added in v0.9.0

func ValidateMnemonic(mnemonic string) error

ValidateMnemonic reports whether mnemonic is a valid BIP-39 seed phrase. It returns nil if the phrase is valid and ErrInvalidMnemonic otherwise, applying the same wordlist, word-count, and checksum checks FromMnemonic does — but without constructing a wallet or retaining the phrase, so an import UI can validate user input before building anything. Surrounding whitespace is trimmed first, exactly as the constructors do.

func ValidateMnemonicBytes added in v0.9.0

func ValidateMnemonicBytes(mnemonic []byte) error

ValidateMnemonicBytes is ValidateMnemonic for a mnemonic held in a byte slice, mirroring the FromMnemonic/FromMnemonicBytes string/bytes pairing. Unlike the constructors it neither wipes nor modifies the slice: this is a read-only validity check, not a wallet entry point.

func ValidateSigningInput added in v0.10.0

func ValidateSigningInput(chain Chain, input proto.Message) error

ValidateSigningInput performs a quick sanity check on the signing input for chain. Returns ErrTxInput with a descriptive message if a required field appears missing. This does NOT validate chain-level correctness (nonce sequence, balance) — only that structurally required proto fields are non-zero.

func Verify added in v0.2.0

func Verify(curve Curve, pub, data []byte, sig *Signature) bool

Verify reports whether sig is a valid signature of data by the public key pub on the given curve. For ECDSA curves data is the 32-byte digest that was signed; for ed25519 it is the message.

func VerifyBitcoinMessage added in v0.3.1

func VerifyBitcoinMessage(address string, message []byte, sigBase64 string) bool

VerifyBitcoinMessage reports whether sigBase64 is a valid Bitcoin signed-message signature of message by the key behind a legacy P2PKH (base58check, "1"-prefix) address. It recovers the public key from the compact signature and checks its legacy address equals address.

func VerifyCosmosADR36 added in v0.11.0

func VerifyCosmosADR36(signer string, data []byte, sigBase64 string) bool

VerifyCosmosADR36 reports whether sigBase64 is a valid ADR-36 signature of data by the key behind the bech32 signer address. sigBase64 must be a base64-encoded 65-byte R‖S‖V signature (V ∈ {0,1}) as returned by SignCosmosADR36. It recovers the public key from the signature and checks that its bech32 Cosmos address (same HRP as signer) equals signer.

func VerifyEthereumMessage added in v0.2.2

func VerifyEthereumMessage(addressOrPubKey string, message, sig []byte) bool

VerifyEthereumMessage reports whether sig (65-byte r||s||v, v in {27,28} or {0,1}) is a valid EIP-191 personal_sign signature of message by the signer identified by addressOrPubKey. addressOrPubKey may be a 0x-hex Ethereum address (20 bytes), or a hex/raw secp256k1 public key (33-byte compressed or 65-byte uncompressed). It ecrecovers the signer and compares.

func VerifyEthereumTypedData added in v0.2.2

func VerifyEthereumTypedData(addressOrPubKey string, typedDataJSON, sig []byte) bool

VerifyEthereumTypedData is the EIP-712 counterpart of VerifyEthereumMessage.

func VerifyRawMessage added in v0.11.0

func VerifyRawMessage(chain Chain, pub, message []byte, sig *Signature) (bool, error)

VerifyRawMessage reports whether sig is a valid raw signature of message by the public key pub for the coin chain. It is the Chain-keyed counterpart to SignRawMessage and wraps VerifySignature.

As with SignRawMessage, message is the 32-byte digest for ECDSA chains and the raw message for ed25519 chains. An unknown chain returns a wrapped ErrUnsupportedCoin; a non-32-byte input for an ECDSA chain returns a wrapped ErrInvalidDigest. It needs no secret and is a free function.

func VerifySignature added in v0.8.0

func VerifySignature(chain Chain, pub, data []byte, sig *Signature) (bool, error)

VerifySignature reports whether sig is a valid signature of data by the public key pub for the coin chain. It is the Chain-keyed counterpart to Sign: the curve is resolved from the registry rather than supplied directly.

As with Sign/SignIndex, data is the 32-byte digest for ECDSA chains (secp256k1) and the raw message for ed25519 chains. A non-32-byte input for an ECDSA chain returns a wrapped ErrInvalidDigest, mirroring SignIndex; an unknown chain returns a wrapped ErrUnsupportedCoin.

It needs no secret and so is a free function, not a wallet method.

func VerifySolanaMessage added in v0.3.1

func VerifySolanaMessage(address string, message []byte, sigBase58 string) bool

VerifySolanaMessage reports whether sigBase58 is a valid Solana off-chain message signature for message under the given base58 account address (which is itself the 32-byte ed25519 public key).

func VerifyTronMessage added in v0.11.0

func VerifyTronMessage(tronAddr string, message []byte, sigHex string) bool

VerifyTronMessage reports whether sigHex is a valid Tron TIP-191 signature of message by the key behind tronAddr. sigHex is the hex-encoded 65-byte signature (with or without the "0x" prefix) where the last byte V ∈ {27, 28}.

It recovers the secp256k1 public key from the signature and derives the Tron address (keccak256(uncompressed[1:])[12:], version 0x41, base58check) to compare against tronAddr.

func WordlistPrefix added in v0.11.0

func WordlistPrefix(prefix string) []string

WordlistPrefix returns up to [wordlistMaxResults] BIP-39 English words that begin with prefix, in alphabetical (wordlist) order. It is designed for wallet-entry autocomplete: call it on every keystroke and display the results as suggestions.

An empty prefix returns the first [wordlistMaxResults] words of the wordlist. A prefix with no matches returns a nil slice.

Types

type ABIValue added in v0.2.2

type ABIValue struct {
	Type  string
	Value any
}

ABIValue is one ABI argument: Type is the canonical type string (e.g. "uint256", "address", "bytes", "uint256[]", "(address,uint256)") and Value is the Go value:

address, bytesN, bytes, string -> []byte
uint*/int*                     -> *big.Int
bool                           -> bool
arrays, tuples                 -> []ABIValue (elements/fields)

func ABIDecode added in v0.2.2

func ABIDecode(types []string, input []byte) (selector []byte, values []ABIValue, err error)

ABIDecode decodes input that begins with a 4-byte selector followed by the arguments encoded for the given types. The returned selector is the leading 4 bytes (not verified against any signature).

func ABIDecodeParams added in v0.2.2

func ABIDecodeParams(types []string, data []byte) ([]ABIValue, error)

ABIDecodeParams decodes the head/tail-encoded data for the given tuple of types into ABIValues. data must be the argument region (no selector).

func DecodeEthLog added in v0.10.0

func DecodeEthLog(log *EthLog, abiTypes []string) ([]ABIValue, error)

DecodeEthLog decodes the non-indexed ABI parameters from an Ethereum event log. abiTypes is the list of Solidity types for the non-indexed params (e.g. ["uint256", "address"]). Returns the decoded values using ABIDecodeParams.

type AddressResult added in v0.10.0

type AddressResult struct {
	Address string
	Err     error
}

AddressResult is the result of deriving one coin address.

type BitcoinAddressKind added in v0.10.0

type BitcoinAddressKind int

BitcoinAddressKind describes the script type of a Bitcoin-family address.

const (
	BitcoinAddressKindUnknown    BitcoinAddressKind = iota // address type could not be determined
	BitcoinAddressKindP2PKH                                // 1… (base58check, version 0x00 for BTC)
	BitcoinAddressKindP2SHP2WPKH                           // 3… (base58check, version 0x05 for BTC)
	BitcoinAddressKindP2WPKH                               // bc1q… (bech32, witness v0, 20-byte program)
	BitcoinAddressKindP2TR                                 // bc1p… (bech32m, witness v1, 32-byte program)
)

BitcoinAddressKindUnknown is the zero value returned when the address format is not recognised for the given chain.

func DetectBitcoinAddressKind added in v0.10.0

func DetectBitcoinAddressKind(chain Chain, addr string) BitcoinAddressKind

DetectBitcoinAddressKind returns the address type for a Bitcoin-family address, using the coin's version bytes and bech32 HRP from btcAddrParams. Returns BitcoinAddressKindUnknown if the format is not recognised for that chain (including chains not in btcAddrParams).

type BitcoinAddressType added in v0.5.0

type BitcoinAddressType int

BitcoinAddressType selects which standard Bitcoin script/address format BitcoinAddress produces. Each maps to a BIP "purpose" derivation path.

const (
	// P2PKH is a legacy pay-to-public-key-hash address (base58check, "1..."),
	// derived under BIP-44 (m/44').
	P2PKH BitcoinAddressType = iota
	// P2SHP2WPKH is a nested SegWit pay-to-witness-public-key-hash wrapped in
	// pay-to-script-hash (base58check, "3..."), derived under BIP-49 (m/49').
	P2SHP2WPKH
	// P2WPKH is a native SegWit v0 address (bech32, "bc1q..."), derived under
	// BIP-84 (m/84'). This is the registry default for BTC/LTC.
	P2WPKH
	// P2TR is a Taproot v1 key-path address (bech32m, "bc1p..."), derived under
	// BIP-86 (m/86').
	P2TR
)

func (BitcoinAddressType) String added in v0.5.0

func (t BitcoinAddressType) String() string

String returns a short human-readable name for the address type.

type BitcoinInputKind added in v0.6.0

type BitcoinInputKind int

BitcoinInputKind identifies the script type of an input being spent, for the fee/size estimator (EstimateTxVsize / EstimateBitcoinFee).

const (
	// InputP2PKH is a legacy pay-to-pubkey-hash input (no witness).
	InputP2PKH BitcoinInputKind = iota
	// InputP2SHP2WPKH is a nested SegWit (BIP-49) P2SH-P2WPKH input.
	InputP2SHP2WPKH
	// InputP2WPKH is a native SegWit v0 P2WPKH input.
	InputP2WPKH
	// InputP2TR is a Taproot key-path P2TR input.
	InputP2TR
)

type BitcoinOutputKind added in v0.6.0

type BitcoinOutputKind int

BitcoinOutputKind identifies the script type of an output, for the fee/size estimator.

const (
	// OutputP2PKH is a legacy pay-to-pubkey-hash output (25-byte script).
	OutputP2PKH BitcoinOutputKind = iota
	// OutputP2SH is a pay-to-script-hash output (23-byte script).
	OutputP2SH
	// OutputP2WPKH is a native SegWit v0 P2WPKH output (22-byte script).
	OutputP2WPKH
	// OutputP2TR is a Taproot P2TR output (34-byte script).
	OutputP2TR
)

type BitcoinTxPlan added in v0.12.3

type BitcoinTxPlan struct {
	// Amount is the value of in.Amount (satoshis to send to the primary recipient).
	Amount int64
	// AvailableAmount is the sum of ALL UTXOs supplied in the SigningInput,
	// regardless of how many were selected.
	AvailableAmount int64
	// Fee is the estimated fee in satoshis (identical to SigningOutput.Fee).
	Fee int64
	// Change is the change output value in satoshis, or 0 when sub-threshold
	// dust is folded into the fee.
	Change int64
	// SelectedUTXO is the subset of UTXOs chosen by coin selection
	// (identical to SigningOutput.UsedUtxo).
	SelectedUTXO []*txbtc.UsedUTXO
	// VsizeEstimate is the estimated virtual size (vbytes) of the transaction.
	VsizeEstimate int64
}

BitcoinTxPlan is the result of a no-sign transaction planning step returned by PlanBitcoinTx. It carries all information needed to show the user what a subsequent SignTransaction call will do, without requiring a wallet or seed.

func PlanBitcoinTx added in v0.12.3

func PlanBitcoinTx(chain Chain, in *txbtc.SigningInput) (*BitcoinTxPlan, error)

PlanBitcoinTx performs the coin-selection and fee-estimation steps for a Bitcoin transaction without signing or accessing any key material. The returned BitcoinTxPlan describes the selected UTXOs, fee, and change for the given SigningInput using the same logic as SignTransaction.

PlanBitcoinTx is a pure function over the proto — it requires no wallet or seed and can be called before a signing session is available.

type Broadcaster added in v0.11.0

type Broadcaster interface {
	Broadcast(chain Chain, rawTx []byte) (txID string, err error)
}

Broadcaster is a client-implemented sink that submits a signed, serialized raw transaction to the network. The library produces signed bytes in SigningOutput.Encoded and never broadcasts itself.

chain identifies the target chain. rawTx is the value of SigningOutput.Encoded (binary) — use the corresponding _hex or TxBytes field if the endpoint expects hex or base64. Returns the transaction identifier (hash/txid) as reported by the node, or an error if submission fails.

type BtcTxFields added in v0.6.0

type BtcTxFields struct {
	Version    int32
	Vin        []BtcVin
	Vout       []BtcVout
	LockTime   uint32
	HasWitness bool
}

BtcTxFields holds the decoded, display-ready fields of a Bitcoin-family transaction.

func DecodeBitcoinTx added in v0.6.0

func DecodeBitcoinTx(chain Chain, raw []byte) (*BtcTxFields, error)

DecodeBitcoinTx decodes a raw Bitcoin-family transaction (signed or unsigned) for chain, whose btcAddrParams select the HRP / version bytes used to render output addresses. Malformed or truncated input returns ErrTxDecode; the function never panics and never reads past `raw`.

type BtcVin added in v0.6.0

type BtcVin struct {
	TxID     string // 32-byte prev txid, big-endian hex (explorer order)
	Vout     uint32
	Sequence uint32
}

BtcVin is one decoded transaction input. TxID is rendered big-endian (the display/explorer order, reversed from the internal little-endian wire order).

type BtcVout added in v0.6.0

type BtcVout struct {
	Value     int64  // satoshis
	ScriptHex string // scriptPubKey, hex
	Address   string // rendered address, empty if nonstandard
	Type      string // "p2pkh" / "p2sh" / "p2wpkh" / "p2tr" / "nonstandard"
}

BtcVout is one decoded transaction output. Address is the rendered destination for a recognised standard script (empty with Type "nonstandard" otherwise).

type Chain added in v0.14.0

type Chain string

Chain is a typed network identifier used to look up a registry entry. Use the exported constants below (hdwallet.BTC, hdwallet.ETH, …) when calling methods such as (*HDWallet).Address and AddressIndex; the typed enum gives compile-time checking and editor autocomplete instead of bare strings.

const (
	// secp256k1 — Bitcoin-style UTXO chains.
	BTC  Chain = "BTC"
	LTC  Chain = "LTC"
	DOGE Chain = "DOGE"
	BCH  Chain = "BCH"
	DASH Chain = "DASH"
	ZEC  Chain = "ZEC"

	// secp256k1 — additional UTXO chains.
	DGB   Chain = "DGB"   // DigiByte (segwit)
	SYS   Chain = "SYS"   // Syscoin (segwit)
	VIA   Chain = "VIA"   // Viacoin (segwit)
	QTUM  Chain = "QTUM"  // Qtum (base58check P2PKH)
	RVN   Chain = "RVN"   // Ravencoin (base58check P2PKH)
	FIRO  Chain = "FIRO"  // Firo (base58check P2PKH)
	MONA  Chain = "MONA"  // MonaCoin (base58check P2PKH)
	PIVX  Chain = "PIVX"  // PIVX (base58check P2PKH)
	STRAX Chain = "STRAX" // Stratis (segwit)

	// secp256k1 — account-based / keccak.
	ETH Chain = "ETH"
	TRX Chain = "TRX"
	XRP Chain = "XRP"

	// secp256k1 — EVM chains (same key & address format as Ethereum).
	BNB   Chain = "BNB"
	MATIC Chain = "MATIC"
	AVAX  Chain = "AVAX"
	ARB   Chain = "ARB"
	OP    Chain = "OP"
	FTM   Chain = "FTM"
	BASE  Chain = "BASE"
	CRO   Chain = "CRO"
	GNO   Chain = "GNO"
	CELO  Chain = "CELO"

	// secp256k1 — additional EVM chains (Ethereum address format, EIP-55).
	ETC      Chain = "ETC"
	RONIN    Chain = "RONIN"
	ZKSYNC   Chain = "ZKSYNC"
	LINEA    Chain = "LINEA"
	SCROLL   Chain = "SCROLL"
	MANTLE   Chain = "MANTLE"
	BLAST    Chain = "BLAST"
	KAIA     Chain = "KAIA"
	AURORA   Chain = "AURORA"
	GLMR     Chain = "GLMR"
	MOVR     Chain = "MOVR"
	BOBA     Chain = "BOBA"
	METIS    Chain = "METIS"
	OPBNB    Chain = "OPBNB"
	POLZKEVM Chain = "POLZKEVM"
	MANTA    Chain = "MANTA"
	RBTC     Chain = "RBTC"
	HECO     Chain = "HECO"
	OKT      Chain = "OKT"
	KCS      Chain = "KCS"
	WAN      Chain = "WAN"
	POA      Chain = "POA"
	CLO      Chain = "CLO"
	GO       Chain = "GO"
	TT       Chain = "TT"
	VET      Chain = "VET"
	IOTX     Chain = "IOTX"
	THETA    Chain = "THETA"
	NEON     Chain = "NEON"
	MERLIN   Chain = "MERLIN"
	LIGHT    Chain = "LIGHT"
	SONIC    Chain = "SONIC"
	ZENEON   Chain = "ZENEON"
	ZETAEVM  Chain = "ZETAEVM"

	// secp256k1 — Cosmos SDK chains.
	ATOM Chain = "ATOM"
	OSMO Chain = "OSMO"
	JUNO Chain = "JUNO"
	TIA  Chain = "TIA"

	// secp256k1 — additional Cosmos SDK chains (hash160 bech32, per-chain HRP).
	LUNA      Chain = "LUNA"
	KAVA      Chain = "KAVA"
	SCRT      Chain = "SCRT"
	BAND      Chain = "BAND"
	RUNE      Chain = "RUNE"
	STARS     Chain = "STARS"
	AXL       Chain = "AXL"
	STRD      Chain = "STRD"
	BLD       Chain = "BLD"
	CRE       Chain = "CRE"
	KUJI      Chain = "KUJI"
	CMDX      Chain = "CMDX"
	NTRN      Chain = "NTRN"
	SOMM      Chain = "SOMM"
	FET       Chain = "FET"
	MARS      Chain = "MARS"
	UMEE      Chain = "UMEE"
	COREUM    Chain = "COREUM"
	QSR       Chain = "QSR"
	XPRT      Chain = "XPRT"
	AKT       Chain = "AKT"
	NOBLE     Chain = "NOBLE"
	SEI       Chain = "SEI"
	DYDX      Chain = "DYDX"
	BLZ       Chain = "BLZ"
	CRYPTOORG Chain = "CRYPTOORG"

	// secp256k1 — Cosmos chains with EVM-style keys (keccak address, bech32).
	EVMOS Chain = "EVMOS"
	INJ   Chain = "INJ"

	// ed25519 (SLIP-0010).
	SOL   Chain = "SOL"
	XLM   Chain = "XLM"
	ALGO  Chain = "ALGO"
	APTOS Chain = "APTOS"
	TON   Chain = "TON"
	DOT   Chain = "DOT"
)

Supported network chains. These mirror the registry below and match Trust Wallet's tickers.

func DetectChains added in v0.14.0

func DetectChains(addr string) []Chain

DetectChains returns all registered chains whose address validator accepts addr. The result is sorted alphabetically. Returns nil if no match is found. This is O(n) over all registered coins — do not call in hot loops.

func SupportedCoins

func SupportedCoins() []Chain

SupportedCoins lists the registered coin chains in sorted order.

func SupportedTxCoins added in v0.10.0

func SupportedTxCoins() []Chain

SupportedTxCoins returns chains for which SignTransaction is implemented, sorted alphabetically.

func (Chain) IsValid added in v0.14.0

func (s Chain) IsValid() bool

IsValid reports whether the chain is a registered network.

func (Chain) String added in v0.14.0

func (s Chain) String() string

String implements fmt.Stringer.

type Coin

type Coin struct {
	Name     string
	Chain    Chain
	Curve    Curve
	Path     string
	Encode   func(pub []byte) (string, error)
	Decimals uint8
	ChainID  uint64
}

Coin describes a supported network: its curve, BIP-32 derivation path, and the function that turns a derived public key into an address string. Adding a network is a single entry in the registry below.

Decimals is the number of fractional digits in the chain's native unit (e.g. 8 for Bitcoin satoshis, 18 for Ethereum wei, 6 for Cosmos uatom) and is used to format on-chain balances. ChainID is the EIP-155 numeric chain id used to build EVM transactions; it is non-zero only for EVM chains (the evmTxChains set in tx_families.go) and 0 for every non-EVM coin. Both mirror the Trust Wallet Core coins registry. The SLIP-44 coin type is NOT stored — it is derived from Path via the SLIP44 method below.

func CoinInfo

func CoinInfo(chain Chain) (Coin, bool)

CoinInfo returns the static registry entry for a chain.

func (Coin) SLIP44 added in v0.6.0

func (c Coin) SLIP44() uint32

SLIP44 returns the SLIP-44 coin type for the coin, derived from the second element of its BIP-32 Path (e.g. "m/44'/60'/0'/0/0" → 60). The hardened flag is stripped. It is computed from Path rather than stored separately so the two can never drift; a malformed path returns 0.

type ContractABIFunction added in v0.12.5

type ContractABIFunction struct {
	Name   string
	Inputs []ContractABIParam
}

ContractABIFunction is a parsed ABI function entry.

type ContractABIMap added in v0.12.5

type ContractABIMap map[[4]byte]ContractABIFunction

ContractABIMap is a selector-indexed ABI returned by ParseContractABI. The key is the 4-byte function selector.

func ParseContractABI added in v0.12.5

func ParseContractABI(jsonABI []byte) (ContractABIMap, error)

ParseContractABI parses a JSON ABI array (the format returned by solc) and returns a map from 4-byte selector to function definition. Non-function entries (events, errors, constructor, fallback) are silently ignored.

type ContractABIParam added in v0.12.5

type ContractABIParam struct {
	Name string
	Type string
}

ContractABIParam is one named parameter in an ABI function.

type ContractCallParam added in v0.12.5

type ContractCallParam struct {
	Name  string
	Type  string
	Value any
}

ContractCallParam is one decoded parameter: name, type, and decoded value. Value holds the same Go types as ABIValue.Value.

func DecodeContractCall added in v0.12.5

func DecodeContractCall(abiMap ContractABIMap, calldata []byte) (string, []ContractCallParam, error)

DecodeContractCall decodes ABI calldata using the parsed ABI map. Returns the matched function name, the decoded named parameters, and any error. Returns ErrABIDecode if calldata is shorter than 4 bytes or the selector is not found.

type CosmosCoin added in v0.8.0

type CosmosCoin struct {
	Denom  string
	Amount string
}

CosmosCoin is one decoded { denom, amount } coin (amount is a decimal string, the on-wire Cosmos representation).

type CosmosMessage added in v0.8.0

type CosmosMessage struct {
	TypeURL string

	// MsgSend.
	FromAddress string
	ToAddress   string

	// MsgDelegate / MsgUndelegate / MsgWithdrawDelegatorReward.
	DelegatorAddress string
	ValidatorAddress string

	// Amount: MsgSend carries a repeated coin set; MsgDelegate / MsgUndelegate
	// carry a single coin (one element). MsgWithdrawReward carries none.
	Amount []CosmosCoin
}

CosmosMessage is one decoded transaction message. TypeURL is always set; the remaining fields are populated according to the message type (only the relevant subset is non-empty).

type CosmosTxFields added in v0.8.0

type CosmosTxFields struct {
	Messages   []CosmosMessage
	Memo       string
	FeeAmount  []CosmosCoin
	GasLimit   uint64
	Sequence   uint64
	Signatures [][]byte
}

CosmosTxFields holds the decoded, display-ready fields of a Cosmos transaction.

func DecodeCosmosTx added in v0.8.0

func DecodeCosmosTx(raw []byte) (*CosmosTxFields, error)

DecodeCosmosTx decodes a raw (broadcast) Cosmos TxRaw blob into its display fields. Malformed or truncated input returns ErrTxDecode; the function never panics.

type Curve

type Curve int

Curve identifies the elliptic curve a coin derives keys on. Each curve has a distinct derivation scheme (BIP-32 for secp256k1, SLIP-0010 for the others).

const (
	// Secp256k1 covers Bitcoin-style, Ethereum/EVM, Cosmos, XRP and Tron.
	Secp256k1 Curve = iota
	// Ed25519 covers Solana, Stellar, Algorand, Aptos, TON and Polkadot.
	Ed25519
)

func (Curve) String

func (c Curve) String() string

String returns the SLIP-0010/BIP-32 name of the curve for diagnostics. The strings for the Trust Wallet Core curves match TWCurve.h exactly.

type ERC20Call added in v0.6.0

type ERC20Call struct {
	Method    string   // "transfer" or "approve"
	Recipient string   // "0x"-prefixed 20-byte address (the `to`/`spender`)
	Amount    *big.Int // the uint256 amount
}

ERC20Call is a decoded ERC-20 method call recognised in the transaction's calldata (transfer or approve). It is nil on EthTxFields unless the calldata's 4-byte selector and shape match one of those methods.

type EthAccessTuple added in v0.6.0

type EthAccessTuple struct {
	Address     string   // "0x"-prefixed 20-byte address
	StorageKeys [][]byte // each 32 bytes
}

EthAccessTuple is one decoded EIP-2930 access-list entry: the accessed address (0x-hex) and the 32-byte storage keys accessed under it.

type EthAuthorizationTuple added in v0.11.0

type EthAuthorizationTuple struct {
	ChainID *big.Int // authorization's chain scope (0 = any chain)
	Address string   // delegation target, "0x"-prefixed 20-byte address
	Nonce   uint64   // EOA nonce at the time of signing
	YParity uint8    // 0 or 1
	R       *big.Int
	S       *big.Int
}

EthAuthorizationTuple is one decoded EIP-7702 authorization-list entry. The authorization was signed off-band by an EOA delegating its code to Address. YParity is 0 or 1 (the bare recovery id of the auth signature).

type EthLog added in v0.10.0

type EthLog struct {
	Address string   // contract address ("0x"-hex)
	Topics  []string // hex-encoded 32-byte topics: [eventSig, indexedParam…]
	Data    []byte   // ABI-encoded non-indexed parameters
}

EthLog represents one Ethereum event log entry as returned by eth_getLogs or a transaction receipt. Topics is a slice of hex-encoded 32-byte values (with or without "0x" prefix); Data holds the non-indexed ABI-encoded parameters.

type EthTxFields added in v0.6.0

type EthTxFields struct {
	Type     EthTxType
	ChainID  *big.Int
	Nonce    *big.Int
	GasPrice *big.Int // legacy + 2930

	MaxPriorityFeePerGas *big.Int // 1559 + 4844 + 7702
	MaxFeePerGas         *big.Int // 1559 + 4844 + 7702

	GasLimit *big.Int
	To       string // "0x"-hex; empty = contract creation
	Value    *big.Int
	Data     []byte

	AccessList []EthAccessTuple // 2930 + 1559 + 4844 + 7702

	// EIP-4844 fields (only set for EthTxEIP4844).
	MaxFeePerBlobGas    *big.Int // max_fee_per_blob_gas
	BlobVersionedHashes [][]byte // each 32 bytes; fixed-width (not quantity-stripped)

	// EIP-7702 fields (only set for EthTxEIP7702).
	AuthorizationList []EthAuthorizationTuple

	// Signature scalars (present in a signed tx). YParity is the bare recovery id
	// (0/1) for typed txs; for legacy it is the raw v as a *big.Int.
	V *big.Int
	R *big.Int
	S *big.Int

	// ERC20 is set when Data decodes to a recognised ERC-20 transfer/approve call.
	ERC20 *ERC20Call
}

EthTxFields holds the decoded, display-ready fields of an EVM transaction. Numeric quantities are *big.Int (nil means absent/zero); To is a "0x"-prefixed hex address, empty for contract creation. The fields populated depend on Type: MaxPriorityFeePerGas/MaxFeePerGas/AccessList are EIP-1559/2930 only, GasPrice is legacy/2930 only, ChainID is decoded for all (derived from v via EIP-155 for a legacy tx whose v >= 35; nil for a legacy tx with the pre-155 v of 27/28).

func DecodeEthereumTx added in v0.6.0

func DecodeEthereumTx(raw []byte) (*EthTxFields, error)

DecodeEthereumTx decodes a raw EVM transaction (signed or unsigned) into its display fields. It branches on the first byte:

0x01 => EIP-2930 access-list (type 1)
0x02 => EIP-1559 fee-market (type 2)
0x03 => EIP-4844 blob (type 3)
0x04 => EIP-7702 set-code (type 4)
>= 0xc0 (RLP list prefix) => legacy EIP-155

Malformed or truncated input returns ErrTxDecode; the function never panics.

type EthTxType added in v0.6.0

type EthTxType int

EthTxType identifies the EVM transaction envelope a raw blob decoded as.

const (
	// EthTxLegacy is a pre-EIP-2718 legacy (EIP-155) transaction: a bare RLP
	// list with no type-byte envelope.
	EthTxLegacy EthTxType = iota
	// EthTxEIP2930 is a type-1 (0x01) access-list transaction.
	EthTxEIP2930
	// EthTxEIP1559 is a type-2 (0x02) fee-market transaction.
	EthTxEIP1559
	// EthTxEIP4844 is a type-3 (0x03) blob transaction (EIP-4844).
	EthTxEIP4844
	// EthTxEIP7702 is a type-4 (0x04) set-code transaction (EIP-7702).
	EthTxEIP7702
)

func (EthTxType) String added in v0.6.0

func (t EthTxType) String() string

String returns a short human-readable name for the transaction type.

type FeeOracle added in v0.11.0

type FeeOracle interface {
	FeeRate(chain Chain) (uint64, error)
}

FeeOracle returns a fee recommendation for the given chain. The returned value maps to SigningInput fields as follows:

  • EVM chains: gas_price (wei, legacy) or max_fee_per_gas (wei, EIP-1559). Obtain from eth_gasPrice or eth_feeHistory. Pair with EthGasLimit to compute gas_limit.
  • Bitcoin-family: byte_fee (satoshis per virtual byte). Obtain from estimatesmartfee or a fee-estimation API. CPFPFee and EstimateTxVsize are available for CPFP bump calculations.
  • XRP Ledger: fee (drops). Obtain from the fee command.
  • Tron TRC-20: fee_limit (sun). Caller sets a conservative cap.

For Cosmos chains, use CosmosGasLimit and CosmosMinFee with the chain's minimum gas price from CosmosMinGasPrices instead of calling FeeOracle.

type HDWallet

type HDWallet struct {
	// contains filtered or unexported fields
}

HDWallet is an HD wallet derived from a BIP-39 mnemonic. Its sensitive material is protected in memory; see the package documentation. All methods are safe for concurrent use.

func FromMnemonic

func FromMnemonic(mnemonic string) (*HDWallet, error)

FromMnemonic builds a wallet from an existing 12/24-word mnemonic string.

Prefer FromMnemonicBytes where possible: a Go string cannot be wiped from memory, so any mnemonic held as a string lingers until garbage-collected.

func FromMnemonicBuffer

func FromMnemonicBuffer(buf *memguard.LockedBuffer) (*HDWallet, error)

FromMnemonicBuffer builds a wallet from a mnemonic held in a memguard LockedBuffer. This is the most secure entry point: the mnemonic stays in page-locked, encrypted-at-rest memory from your code all the way into the wallet's sealed enclave, with no intermediate plaintext copy on the Go heap.

The wallet takes ownership of buf and destroys it; do not use buf afterwards. Surrounding whitespace in the buffer is trimmed before use.

It uses the empty BIP-39 passphrase (Trust Wallet's default). For a passphrase-protected wallet, use FromMnemonicBufferWithPassphrase.

Example

ExampleFromMnemonicBuffer shows the most secure way to import a mnemonic: the phrase lives in a page-locked, encrypted memguard buffer and is handed to the wallet without an intermediate plaintext copy. The wallet takes ownership of the buffer and destroys it.

package main

import (
	"fmt"
	"log"

	"github.com/awnumar/memguard"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

// exampleMnemonic is the standard BIP-39 test vector mnemonic. Never hard-code a
// real mnemonic in source; this one holds no funds and is used only for docs.
const exampleMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

func main() {
	// In real code, read the mnemonic straight into protected memory (for
	// example with memguard.NewBufferFromReaderUntil over stdin).
	buf := memguard.NewBufferFromBytes([]byte(exampleMnemonic))

	w, err := hdwallet.FromMnemonicBuffer(buf)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy()

	addr, _ := w.Address(hdwallet.BTC)
	fmt.Println(addr)
}
Output:
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu

func FromMnemonicBufferWithPassphrase added in v0.3.0

func FromMnemonicBufferWithPassphrase(buf, passphrase *memguard.LockedBuffer) (*HDWallet, error)

FromMnemonicBufferWithPassphrase is the most secure passphrase entry point: both the mnemonic and the BIP-39 passphrase are supplied in page-locked, encrypted-at-rest memguard buffers and used without an intermediate plaintext heap copy (aside from the unavoidable transient BIP-39 string conversion).

The wallet takes ownership of both buffers and destroys them; do not use either afterwards. passphrase may be nil for the empty passphrase. Surrounding whitespace in the mnemonic buffer is trimmed; the passphrase is used verbatim.

func FromMnemonicBytes

func FromMnemonicBytes(mnemonic []byte) (*HDWallet, error)

FromMnemonicBytes builds a wallet from a mnemonic held in a byte slice. The slice is wiped before the function returns; callers must not reuse it.

It uses the empty BIP-39 passphrase (Trust Wallet's default). For a passphrase-protected ("hidden") wallet, use FromMnemonicWithPassphrase.

func FromMnemonicWithPassphrase added in v0.3.0

func FromMnemonicWithPassphrase(mnemonic, passphrase []byte) (*HDWallet, error)

FromMnemonicWithPassphrase builds a wallet from a mnemonic and an optional BIP-39 passphrase (the "25th word"), both held in byte slices. A different passphrase derives a completely different set of addresses from the same mnemonic; the empty passphrase (nil or empty slice) matches FromMnemonicBytes and Trust Wallet's default.

Both slices are wiped before the function returns; callers must not reuse them. Like the mnemonic, the passphrase is briefly converted to a Go string internally for BIP-39 seed derivation (see the package secret-handling notes).

func FromPrivateKeyBuffer added in v0.2.2

func FromPrivateKeyBuffer(buf *memguard.LockedBuffer, curve Curve) (*HDWallet, error)

FromPrivateKeyBuffer builds a key-only wallet from a raw private key held in a memguard LockedBuffer. This is the most secure key-import entry point: the key stays in page-locked, encrypted-at-rest memory from your code all the way into the wallet's sealed enclave, with no intermediate plaintext copy on the Go heap (mirrors FromMnemonicBuffer).

The wallet takes ownership of buf and destroys it; do not use buf afterwards. See FromPrivateKeyBytes for the semantics of a key-only wallet.

func FromPrivateKeyBytes added in v0.2.2

func FromPrivateKeyBytes(priv []byte, curve Curve) (*HDWallet, error)

FromPrivateKeyBytes builds a key-only wallet from a raw private key held in a byte slice. The slice is wiped before this function returns; callers must not reuse it (mirrors FromMnemonicBytes).

curve identifies the elliptic curve the key belongs to (Secp256k1, Ed25519, or Nist256p1). The resulting wallet can derive addresses, public keys, sign, and export the key for any registered coin whose curve matches; mismatched-curve coins return ErrCurveMismatch. A key-only wallet has no HD path — the imported key is the leaf — so only index 0 is valid and there is no mnemonic to read (Mnemonic/WithMnemonic/AllAddresses return ErrKeyOnlyWallet).

The key must be exactly 32 bytes and non-zero, or ErrInvalidPrivateKey is returned.

func FromWIF added in v0.3.0

func FromWIF(wif []byte) (*HDWallet, error)

FromWIF builds a key-only secp256k1 wallet from a Bitcoin WIF private key held in a byte slice. The slice is wiped before returning; callers must not reuse it. Both compressed and uncompressed mainnet (0x80) WIF are accepted, and the imported key may then be used with any secp256k1 coin.

Like the mnemonic path, the WIF is briefly converted to a Go string internally for base58 decoding (it cannot be wiped and is GC-bounded).

func NewHDWallet

func NewHDWallet() (*HDWallet, error)

NewHDWallet creates a wallet with a fresh 12-word (128-bit) mnemonic. It is a convenience wrapper over NewHDWalletWithWordCount(12).

Example

ExampleNewHDWallet creates a wallet with a fresh, random mnemonic and derives an address. Output is omitted because the mnemonic (and therefore the address) is random on every run.

package main

import (
	"fmt"
	"log"
	"strings"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

func main() {
	w, err := hdwallet.NewHDWallet()
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy() // wipe the wallet's secrets when finished

	addr, err := w.Address(hdwallet.ETH)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(strings.HasPrefix(addr, "0x"))
}
Output:
true

func NewHDWalletWithEntropy added in v0.3.1

func NewHDWalletWithEntropy(bits int) (*HDWallet, error)

NewHDWalletWithEntropy creates a wallet with a fresh mnemonic generated from bits of BIP-39 entropy. bits must be one of 128, 160, 192, 224, or 256 (yielding 12, 15, 18, 21, or 24 words); any other value returns an error wrapping ErrInvalidWordCount.

func NewHDWalletWithWordCount added in v0.3.1

func NewHDWalletWithWordCount(words int) (*HDWallet, error)

NewHDWalletWithWordCount creates a wallet with a fresh mnemonic of the given length in words. words must be one of 12, 15, 18, 21, or 24; any other value returns an error wrapping ErrInvalidWordCount.

func (*HDWallet) AccountEd25519PubKey added in v0.10.0

func (w *HDWallet) AccountEd25519PubKey(chain Chain, account uint32) (pubKey, chainCode []byte, err error)

AccountEd25519PubKey returns the SLIP-0010 ed25519 public key (32 bytes) and chain code (32 bytes) at the account level (m/purpose'/coin'/account') for chain.

SLIP-0010 ed25519 does not support public child key derivation — all path elements must be hardened and no WatchWallet equivalent exists. This method exports the account-level public key for external signing or identity use; child address derivation still requires the full seed. chain must be an Ed25519 coin.

func (*HDWallet) AccountXPub added in v0.3.0

func (w *HDWallet) AccountXPub(chain Chain, account uint32) (string, error)

AccountXPub returns the BIP-32 extended PUBLIC key (xpub) for chain's account at the given index — i.e. the neutered key at m/purpose'/coin'/account'. It is public and safe to share; feed it to WatchOnlyFromXPub to derive addresses without the seed. chain must be a secp256k1 coin.

func (*HDWallet) Address

func (w *HDWallet) Address(chain Chain) (string, error)

Address returns the first receive address (index 0) for a coin chain, e.g. "BTC", "ETH", "SOL", "ATOM". Use SupportedCoins to list every chain.

Privacy note: calling Address repeatedly returns the same address. For privacy-sensitive applications (receiving from multiple sources) use [AddressIndex] with incrementing indices or [AddressRange] for gap-limit discovery.

It is exactly equivalent to AddressIndex(chain, 0).

Example

ExampleHDWallet_Address derives the first receive address for several chains from a fixed mnemonic, producing deterministic, Trust Wallet-compatible addresses.

package main

import (
	"fmt"
	"log"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

// exampleMnemonic is the standard BIP-39 test vector mnemonic. Never hard-code a
// real mnemonic in source; this one holds no funds and is used only for docs.
const exampleMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

func main() {
	w, err := hdwallet.FromMnemonic(exampleMnemonic)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy()

	btc, _ := w.Address(hdwallet.BTC)
	eth, _ := w.Address(hdwallet.ETH)
	fmt.Println(btc)
	fmt.Println(eth)
}
Output:
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu
0x9858EfFD232B4033E47d90003D41EC34EcaEda94

func (*HDWallet) AddressAt added in v0.3.0

func (w *HDWallet) AddressAt(chain Chain, account, change, index uint32) (string, error)

AddressAt returns the address for chain at the given BIP-44 account, change branch, and address index, building the path "m/purpose'/coin'/account'/change/ index" from the coin's template. It requires a standard 5-element path; coins whose template has a different shape (e.g. SOL's "m/44'/501'/0'") return ErrPathArity — use AddressPath for those.

func (*HDWallet) AddressIndex

func (w *HDWallet) AddressIndex(chain Chain, index uint32) (string, error)

AddressIndex returns the address for a coin chain derived with the final element of the coin's BIP-32 path replaced by index, preserving that element's hardened flag (a trailing "'").

For BIP-44/BIP-84 chains whose path ends in "/0/0" (change/address_index), this varies the non-hardened receive address index — e.g. for BTC (m/84'/0'/0'/0/0), index 1 derives m/84'/0'/0'/0/1. For account-based chains whose path ends in a hardened element such as "/0'" (e.g. SOL, m/44'/501'/0'), this varies that final hardened element — index 1 derives m/44'/501'/1'.

index must be below 2^31 (0x80000000); a larger value returns an error, as does an unknown chain (wrapping ErrUnsupportedCoin) or a destroyed wallet.

Example

ExampleHDWallet_AddressIndex derives multiple receive addresses for the same chain by varying the final path index.

package main

import (
	"fmt"
	"log"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

// exampleMnemonic is the standard BIP-39 test vector mnemonic. Never hard-code a
// real mnemonic in source; this one holds no funds and is used only for docs.
const exampleMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

func main() {
	w, err := hdwallet.FromMnemonic(exampleMnemonic)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy()

	first, _ := w.AddressIndex(hdwallet.BTC, 0)
	second, _ := w.AddressIndex(hdwallet.BTC, 1)
	fmt.Println(first)
	fmt.Println(second)
}
Output:
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu
bc1qnjg0jd8228aq7egyzacy8cys3knf9xvrerkf9g

func (*HDWallet) AddressPath added in v0.3.0

func (w *HDWallet) AddressPath(chain Chain, path string) (string, error)

AddressPath returns the address for chain derived at the given absolute BIP-32 path (e.g. "m/44'/60'/1'/0/5"). The path's curve scheme is the coin's; only the child indices are taken from path. An invalid path or unknown chain returns an error; a key-only wallet returns ErrKeyOnlyWallet.

func (*HDWallet) AddressRange added in v0.8.0

func (w *HDWallet) AddressRange(chain Chain, start, count uint32) ([]string, error)

AddressRange derives count consecutive addresses for a single coin chain starting at index start, varying the final element of the coin's BIP-32 path (preserving its hardened flag) exactly as AddressIndex does. The returned slice is in ascending index order: element i is the address at start+i. A count of 0 returns an empty, non-nil slice.

The seed enclave is opened exactly once and every address is derived inside that single decryption window. start+count must not exceed 2^31 (0x80000000); a larger range returns an out-of-range error, as does an unknown chain (wrapping ErrUnsupportedCoin). It is only available on seed-based wallets; a key-only wallet (imported from a single private key) returns ErrKeyOnlyWallet.

func (*HDWallet) AllAddressResults added in v0.10.0

func (w *HDWallet) AllAddressResults(index uint32) map[Chain]AddressResult

AllAddressResults derives all coins at index and returns per-coin results. Does not stop on error — all coins are attempted.

func (*HDWallet) AllAddresses

func (w *HDWallet) AllAddresses() (map[Chain]string, error)

AllAddresses derives the first address (index 0) for every supported coin. It is exactly equivalent to AllAddressesAt(0).

func (*HDWallet) AllAddressesAt added in v0.3.1

func (w *HDWallet) AllAddressesAt(index uint32) (map[Chain]string, error)

AllAddressesAt derives the address at the given index for every supported coin, varying the final element of each coin's BIP-32 path (preserving its hardened flag) exactly as AddressIndex does. The seed enclave is opened exactly once and every coin is derived inside that single decryption window.

index must be below 2^31 (0x80000000); a larger value returns an error. It is only available on seed-based wallets; a key-only wallet (imported from a single private key) has no seed to enumerate over and returns ErrKeyOnlyWallet.

func (*HDWallet) AllAddressesAtCtx added in v0.10.0

func (w *HDWallet) AllAddressesAtCtx(ctx context.Context, index uint32) (map[Chain]string, error)

AllAddressesAtCtx is like AllAddressesAt but respects cancellation. Returns partial results and ctx.Err() if cancelled.

func (*HDWallet) AllAddressesCtx added in v0.10.0

func (w *HDWallet) AllAddressesCtx(ctx context.Context) (map[Chain]string, error)

AllAddressesCtx is like AllAddresses but respects the context's cancellation. Returns partial results and ctx.Err() if cancelled.

func (*HDWallet) BIP85Entropy added in v0.10.0

func (w *HDWallet) BIP85Entropy(appPath string, index uint32, length int, fn func([]byte)) error

BIP85Entropy derives entropy bytes via BIP-85 (non-EC-multiply mode only).

appPath is the application-specific suffix after m/83696968', without a leading or trailing slash. Common values:

"39'/0'/12'"  →  first 16 bytes → 12-word BIP-39 English mnemonic
"39'/0'/24'"  →  first 32 bytes → 24-word BIP-39 English mnemonic
"32'"         →  first 32 bytes → raw 256-bit entropy

index is the BIP-85 child index (hardened automatically). length is the number of entropy bytes (1–64) passed to fn; fn is called with the slice and it is wiped before BIP85Entropy returns.

func (*HDWallet) BIP85Mnemonic added in v0.10.0

func (w *HDWallet) BIP85Mnemonic(wordCount int, index uint32, fn func([]byte)) error

BIP85Mnemonic derives a child BIP-39 mnemonic at the given index via BIP-85.

wordCount must be 12, 18, or 24. fn receives the space-separated mnemonic as a byte slice; the slice is wiped before BIP85Mnemonic returns.

func (*HDWallet) BitcoinAddress added in v0.5.0

func (w *HDWallet) BitcoinAddress(chain Chain, t BitcoinAddressType, account, change, index uint32) (string, error)

BitcoinAddress returns the address for chain in the given Bitcoin address type, derived at the type's standard BIP path "m/purpose'/coinType'/account'/change/index" (purpose = 44/49/84/86 for P2PKH/P2SHP2WPKH/P2WPKH/P2TR; coinType taken from the coin's registry path).

It is available for chains in btcAddrParams (BTC, LTC); any other chain returns ErrUnsupportedCoin. account/change/index must each be below 2^31. Like the other derivation methods it is seed-only and the leaf key is wiped after use; a key-only wallet returns ErrKeyOnlyWallet.

func (*HDWallet) BuildBRC20Commit added in v0.12.3

func (w *HDWallet) BuildBRC20Commit(chain Chain, index uint32, ticker, amount string,
	in *txbtc.SigningInput) (commitTxHex string, reveal *InscriptionCommit, err error)

BuildBRC20Commit builds and signs the commit transaction for a BRC-20 transfer inscription, returning the signed raw-tx hex and an InscriptionCommit that carries all data needed for the subsequent reveal.

The commit output pays to a P2TR address whose taproot output key is derived from the wallet key (internal key) tweaked by the merkle root of a single-leaf script tree containing the inscription envelope.

in.ToAddress is overwritten with the derived commit address before signing; the caller should treat the SigningInput as consumed after this call.

func (*HDWallet) Destroy

func (w *HDWallet) Destroy()

Destroy wipes the wallet's secret material from memory. After Destroy returns, all methods that require secret material return ErrDestroyed. Safe to call multiple times; subsequent calls are no-ops.

Destroy does not wait for in-flight Sign or Address operations to complete. If concurrent goroutines may be using the wallet, callers must coordinate shutdown before calling Destroy.

func (*HDWallet) EncryptWIF added in v0.10.0

func (w *HDWallet) EncryptWIF(chain Chain, index uint32, passphrase []byte) (string, error)

EncryptWIF encrypts the private key for chain at index using BIP-38 non-EC-multiply mode and returns the '6P…' base58check-encoded ciphertext. chain must be a secp256k1 coin. The address hash is computed from the Bitcoin P2PKH representation of the key (BIP-38 is inherently Bitcoin-format).

func (*HDWallet) Mnemonic

func (w *HDWallet) Mnemonic() (*memguard.LockedBuffer, error)

Mnemonic returns the wallet's mnemonic in a page-locked buffer. This is a lower-level accessor: the caller MUST call Destroy on the returned buffer when finished with it, or the decrypted phrase lingers in memory. Prefer WithMnemonic, which wipes the decrypted copy automatically when its callback returns.

func (*HDWallet) PrivateKey added in v0.2.2

func (w *HDWallet) PrivateKey(chain Chain, index uint32) (*memguard.LockedBuffer, error)

PrivateKey returns the raw leaf private key for chain at the given address index in a page-locked, encrypted-at-rest memguard buffer. This is a lower-level accessor: the caller MUST call Destroy on the returned buffer when finished, or the decrypted key lingers in memory. Prefer WithPrivateKey, which wipes the key automatically when its callback returns (mirrors Mnemonic).

The returned buffer holds a copy taken inside the wallet's protected derivation window; the wallet's own working copy is wiped before this returns. See WithPrivateKey for the seed/key-only semantics and the key encoding.

func (*HDWallet) PrivateKeyPath added in v0.3.0

func (w *HDWallet) PrivateKeyPath(chain Chain, path string) (*memguard.LockedBuffer, error)

PrivateKeyPath returns the raw leaf private key for chain derived at the given absolute BIP-32 path in a page-locked memguard buffer; the caller MUST Destroy it (mirrors PrivateKey). Prefer WithPrivateKeyPath, which wipes automatically.

func (*HDWallet) PublicKey added in v0.2.0

func (w *HDWallet) PublicKey(chain Chain) ([]byte, error)

PublicKey returns the public key for chain at address index 0. See PublicKeyIndex.

func (*HDWallet) PublicKeyAt added in v0.3.0

func (w *HDWallet) PublicKeyAt(chain Chain, account, change, index uint32) ([]byte, error)

PublicKeyAt is the account/change/index counterpart of PublicKeyPath.

func (*HDWallet) PublicKeyIndex added in v0.2.0

func (w *HDWallet) PublicKeyIndex(chain Chain, index uint32) ([]byte, error)

PublicKeyIndex returns the public key derived for chain at the given address index: the 33-byte compressed key for secp256k1/nist256p1, or the 32-byte key for ed25519. Signing callers need this to build or verify transactions.

func (*HDWallet) PublicKeyPath added in v0.3.0

func (w *HDWallet) PublicKeyPath(chain Chain, path string) ([]byte, error)

PublicKeyPath returns the public key for chain derived at the given absolute BIP-32 path: the 33-byte compressed key for secp256k1/nist256p1, or the 32-byte key for ed25519-family curves.

func (*HDWallet) Sign added in v0.2.0

func (w *HDWallet) Sign(chain Chain, data []byte) (*Signature, error)

Sign signs data with the key for chain at address index 0. See SignIndex.

Example

ExampleHDWallet_Sign signs a digest and verifies it with the derived public key. For ECDSA chains (BTC/ETH/…) pass the 32-byte digest your chain hashes; for ed25519 chains pass the message itself.

package main

import (
	"crypto/sha256"
	"fmt"
	"log"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

// exampleMnemonic is the standard BIP-39 test vector mnemonic. Never hard-code a
// real mnemonic in source; this one holds no funds and is used only for docs.
const exampleMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

func main() {
	w, err := hdwallet.FromMnemonic(exampleMnemonic)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy()

	digest := sha256.Sum256([]byte("transaction bytes to sign"))
	sig, err := w.Sign(hdwallet.BTC, digest[:])
	if err != nil {
		log.Fatal(err)
	}

	pub, _ := w.PublicKey(hdwallet.BTC)
	fmt.Println(hdwallet.Verify(hdwallet.Secp256k1, pub, digest[:], sig))
}
Output:
true

func (*HDWallet) SignAt added in v0.3.0

func (w *HDWallet) SignAt(chain Chain, account, change, index uint32, data []byte) (*Signature, error)

SignAt is the account/change/index counterpart of SignPath.

func (*HDWallet) SignBRC20Reveal added in v0.12.3

func (w *HDWallet) SignBRC20Reveal(chain Chain, index uint32, reveal *InscriptionCommit,
	commitTxID []byte, commitVout uint32, commitAmount int64,
	toAddress string, feeRate int64) (revealTxHex string, err error)

SignBRC20Reveal builds and signs the reveal transaction for a BRC-20 transfer inscription.

The reveal spends the commit output (identified by commitTxID:commitVout) via a tapscript script-path spend, pushing the Ordinals witness stack [sig, leafScript, controlBlock] so that the inscription is revealed on-chain.

revealFee = feeRate * 200 (fixed 200-vbyte estimate). The net output value (commitAmount − revealFee) must exceed btcDustThreshold.

func (*HDWallet) SignBitcoinMessage added in v0.3.1

func (w *HDWallet) SignBitcoinMessage(chain Chain, index uint32, message []byte) (string, error)

SignBitcoinMessage signs message under the Bitcoin signed-message standard with the key derived for chain at the given address index, returning the base64 compact signature. chain must be a secp256k1 coin (e.g. BTC, LTC); the derived private key is wiped immediately after signing and never leaves the package.

The signature commits only to the message and key, so it is independent of the address format; this library derives compressed keys, so the header byte marks the key compressed (verifiers recover the compressed key / its legacy address).

func (*HDWallet) SignCosmosADR36 added in v0.11.0

func (w *HDWallet) SignCosmosADR36(chain Chain, index uint32, signer string, data []byte) (string, error)

SignCosmosADR36 signs data with the key for chain at the given address index using the Cosmos ADR-36 arbitrary-message signing standard. signer must be the bech32 address corresponding to that key (e.g. obtained via w.AddressIndex(chain, index) or w.Address(chain) for index 0).

It returns a base64-encoded 65-byte recoverable secp256k1 signature (R‖S‖V, V ∈ {0,1}) over sha256(amino_json). chain must be a secp256k1 coin (e.g. ATOM, OSMO); other curves return ErrNotRecoverable. The derived private key is wiped immediately after signing and never leaves the package.

func (*HDWallet) SignCosmosMultisigPartial added in v0.14.0

func (w *HDWallet) SignCosmosMultisigPartial(chain Chain, index uint32, in *txcosmos.SigningInput) ([]byte, error)

SignCosmosMultisigPartial produces this wallet's partial signature (64-byte r‖s over sha256 of the amino-JSON sign doc) for a multisig MsgSend. in.Send.FromAddress must be the MULTISIG address and in.AccountNumber / in.Sequence the multisig account's values. chain must be a standard (non-Ethermint) Cosmos chain. The derived key is wiped after signing.

func (*HDWallet) SignERC20Permit added in v0.10.0

func (w *HDWallet) SignERC20Permit(
	chain Chain,
	index uint32,
	chainID *big.Int,
	tokenAddr []byte,
	tokenName string,
	spender []byte,
	value, nonce, deadline *big.Int,
) (v uint8, r, s [32]byte, err error)

SignERC20Permit signs an EIP-2612 permit for tokenAddr on chainID. tokenName is the token contract's name() used in the EIP-712 domain separator. The owner is derived from the wallet's key at chain/index. Returns (v, r, s) ready for ERC20PermitCalldata.

func (*HDWallet) SignIndex added in v0.2.0

func (w *HDWallet) SignIndex(chain Chain, index uint32, data []byte) (*Signature, error)

SignIndex signs data with the private key derived for chain at the given address index and returns the signature.

For the ECDSA chain (secp256k1 — e.g. BTC, ETH, ATOM) data must be the 32-byte digest the chain signs; pre-hash the message with the chain's hash function (keccak256 for Ethereum/Tron, double-SHA256 for Bitcoin, SHA-256 for Cosmos, …). For ed25519 chains (e.g. SOL, XLM, ALGO) data is the message itself; the EdDSA scheme hashes internally.

The derived private key is wiped immediately after signing and never leaves the package.

func (*HDWallet) SignMessage added in v0.2.2

func (w *HDWallet) SignMessage(chain Chain, index uint32, message []byte) ([]byte, error)

SignMessage signs message with EIP-191 personal_sign using the key for chain at the given address index, returning a 65-byte r||s||v signature (v = 27/28). chain must be a secp256k1/EVM coin (e.g. ETH); other curves return an error.

func (*HDWallet) SignMultisigPSBT added in v0.11.0

func (w *HDWallet) SignMultisigPSBT(chain Chain, index uint32, psbtBytes []byte) ([]byte, error)

SignMultisigPSBT signs every multisig input in psbtBytes that is controlled by the (chain, index) key and attaches the partial signature. If an input does not contain this wallet's pubkey in its redeemScript/witnessScript the input is silently skipped (another co-signer owns it). The updated PSBT is returned.

The leaf private key is derived under the package's wiped-on-return discipline; no raw key bytes leave the package.

func (*HDWallet) SignPSBT added in v0.6.0

func (w *HDWallet) SignPSBT(chain Chain, index uint32, psbtBytes []byte) ([]byte, error)

SignPSBT parses psbtBytes, signs every input controlled by the (chain,index) key, attaches the signatures, and returns the updated serialized PSBT. The leaf key is derived under the package's seed discipline and wiped on return.

func (*HDWallet) SignPSBTV2 added in v0.10.0

func (w *HDWallet) SignPSBTV2(chain Chain, index uint32, psbtBytes []byte) ([]byte, error)

SignPSBTV2 parses psbtBytes, signs every input controlled by the (chain,index) key and returns the updated BIP-370 PSBT. The leaf key is derived under the package's wiped-on-return discipline.

func (*HDWallet) SignPath added in v0.3.0

func (w *HDWallet) SignPath(chain Chain, path string, data []byte) (*Signature, error)

SignPath signs data with the key for chain derived at the given absolute BIP-32 path. The ECDSA-vs-ed25519 input rule is identical to SignIndex (ECDSA curves want the 32-byte digest; ed25519 wants the message).

func (*HDWallet) SignRawMessage added in v0.11.0

func (w *HDWallet) SignRawMessage(chain Chain, index uint32, message []byte) (*Signature, error)

SignRawMessage is the chain-neutral signing primitive. It routes to the correct curve for the given chain and returns the raw Signature.

For the ECDSA chain (secp256k1 — e.g. ETH, BTC, ATOM) message must be the 32-byte digest the caller has pre-hashed with the chain's own hash function (keccak256 for Ethereum/Tron, double-SHA256 for Bitcoin, SHA-256 for Cosmos, …). A non-32-byte input returns a wrapped ErrInvalidDigest.

For ed25519 chains (SOL, XLM, ALGO, …) message is the raw payload; the EdDSA scheme hashes internally, so any length is accepted.

This is the low-level primitive. For chain-specific standards with magic envelope prefixes use SignBitcoinMessage, SignSolanaMessage, SignCosmosADR36, or SignTronMessage instead. The derived private key is wiped immediately after signing and never leaves the package.

func (*HDWallet) SignSolanaMessage added in v0.3.1

func (w *HDWallet) SignSolanaMessage(chain Chain, index uint32, message []byte) (string, error)

SignSolanaMessage signs message with the ed25519 key derived for chain at the given address index and returns the base58-encoded 64-byte signature.

chain must be a Solana / ed25519 coin (e.g. SOL). The derived private key is wiped immediately after signing and never leaves the package.

func (*HDWallet) SignTransaction added in v0.2.2

func (w *HDWallet) SignTransaction(chain Chain, index uint32, input proto.Message) (proto.Message, error)

SignTransaction signs a transaction for chain using the key derived at the given address index and returns a per-chain protobuf SigningOutput.

input must be the SigningInput proto for chain's family (e.g. *ethereum.SigningInput for ETH/EVM, *tron.SigningInput for TRX, …). The returned proto.Message is the matching SigningOutput, holding the signed serialized raw-transaction bytes plus a hex/base58/base64 convenience form. No network calls are made.

The derived private key is wiped immediately after signing and never leaves the package. An unknown chain returns ErrTxUnsupported; a wrong input type returns ErrTxInput.

func (*HDWallet) SignTronMessage added in v0.11.0

func (w *HDWallet) SignTronMessage(chain Chain, index uint32, message []byte) (string, error)

SignTronMessage signs message under the Tron TIP-191 standard with the key derived for chain at the given address index.

chain must be a secp256k1 coin (e.g. TRX); other curves return ErrNotRecoverable. The derived private key is wiped immediately after signing and never leaves the package.

The returned signature is a hex-encoded 65-byte string "0x{R‖S‖V}" where V ∈ {27, 28}, matching the format TronWeb trx.signMessageV2 produces.

func (*HDWallet) SignTypedData added in v0.2.2

func (w *HDWallet) SignTypedData(chain Chain, index uint32, typedDataJSON []byte) ([]byte, error)

SignTypedData signs the EIP-712 digest of MetaMask-shape typed-data JSON using the key for chain at the given address index, returning a 65-byte r||s||v signature (v = 27/28).

func (*HDWallet) SignUserOperation added in v0.10.0

func (w *HDWallet) SignUserOperation(
	chain Chain,
	index uint32,
	op *UserOperation,
	entryPoint []byte,
	chainID *big.Int,
) ([]byte, error)

SignUserOperation signs op via EIP-191 personal_sign over its hash, sets op.Signature, and returns the 65-byte r‖s‖v recoverable signature.

func (*HDWallet) WIF added in v0.3.0

func (w *HDWallet) WIF(chain Chain, index uint32) (*memguard.LockedBuffer, error)

WIF returns the leaf key for chain at the given address index as a Bitcoin mainnet compressed WIF in a page-locked memguard buffer; the caller MUST Destroy it. Prefer WithWIF, which wipes automatically.

func (*HDWallet) WithAccountXPrv added in v0.3.0

func (w *HDWallet) WithAccountXPrv(chain Chain, account uint32, fn func(xprv []byte) error) error

WithAccountXPrv runs fn with the BIP-32 extended PRIVATE key (xprv) string for chain's account, then wipes the byte slice (mirrors WithPrivateKey/WithWIF). The xprv is a full secret — anyone holding it can derive every key under the account. The slice passed to fn must not escape fn. chain must be secp256k1.

func (*HDWallet) WithMnemonic

func (w *HDWallet) WithMnemonic(fn func(mnemonic []byte) error) error

WithMnemonic runs fn with the plaintext mnemonic bytes and wipes the decrypted copy as soon as fn returns. The slice passed to fn must not escape fn.

Example

ExampleHDWallet_WithMnemonic shows the safe pattern for reading the mnemonic back: the decrypted copy is wiped automatically when the callback returns, and the slice must not escape it.

package main

import (
	"fmt"
	"log"
	"strings"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
)

// exampleMnemonic is the standard BIP-39 test vector mnemonic. Never hard-code a
// real mnemonic in source; this one holds no funds and is used only for docs.
const exampleMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

func main() {
	w, err := hdwallet.FromMnemonic(exampleMnemonic)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Destroy()

	err = w.WithMnemonic(func(mnemonic []byte) error {
		fmt.Println(len(strings.Fields(string(mnemonic))), "words")
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
}
Output:
12 words

func (*HDWallet) WithPrivateKey added in v0.2.2

func (w *HDWallet) WithPrivateKey(chain Chain, index uint32, fn func(priv []byte) error) error

WithPrivateKey runs fn with the raw leaf private key for chain at the given address index and wipes the key as soon as fn returns. This is the safe export primitive — the key never escapes into a value the caller must remember to clear (mirrors WithMnemonic). The slice passed to fn must not escape fn.

It works for both wallet modes: seed wallets derive the key for chain/index; key-only wallets return their imported key (curve must match chain's curve, and index must be 0). The key is the 32-byte scalar/seed for the coin's curve.

For ECDSA chains this is the signing scalar; for ed25519 it is the 32-byte seed (not the 64-byte expanded key).

func (*HDWallet) WithPrivateKeyPath added in v0.3.0

func (w *HDWallet) WithPrivateKeyPath(chain Chain, path string, fn func(priv []byte) error) error

WithPrivateKeyPath runs fn with the raw leaf private key for chain derived at the given absolute BIP-32 path and wipes the key as soon as fn returns (mirrors WithPrivateKey). The slice passed to fn must not escape fn.

func (*HDWallet) WithWIF added in v0.3.0

func (w *HDWallet) WithWIF(chain Chain, index uint32, fn func(wif []byte) error) error

WithWIF runs fn with the leaf private key for chain at the given address index encoded as a Bitcoin mainnet compressed WIF, then wipes the WIF bytes (mirrors WithPrivateKey). chain must be a secp256k1 coin. The slice passed to fn must not escape fn.

type InscriptionCommit added in v0.12.3

type InscriptionCommit struct {
	// CommitAddress is the bech32m P2TR address to which the commit tx sends funds.
	CommitAddress string
	// CommitScript is the 34-byte P2TR scriptPubKey (OP_1 <32-byte xonly output key>)
	// of the commit output — needed as the prevout scriptPubKey when signing the reveal.
	CommitScript []byte
	// LeafScript is the full inscription tapscript leaf built by BuildInscriptionScript.
	LeafScript []byte
	// ControlBlock is the BIP-341 control block for the script-path reveal spend.
	ControlBlock []byte
	// InternalKey is the 33-byte compressed public key of the wallet key used as the
	// internal taproot key.
	InternalKey []byte
}

InscriptionCommit carries all the data a caller needs to build and broadcast the reveal transaction after the commit has confirmed.

type NonceProvider added in v0.11.0

type NonceProvider interface {
	Nonce(address string) (uint64, error)
}

NonceProvider returns the next outbound nonce (or sequence number) for the given account address. Callers supply the returned value as:

  • SigningInput.nonce — EVM chains (ETH, BNB, MATIC, …): the sender's transaction count, as returned by eth_getTransactionCount with the "pending" tag.
  • SigningInput.sequence — XRP Ledger: the account's Sequence field from the account_info command. Cosmos SDK: the account's sequence from GET /cosmos/auth/v1beta1/accounts/{address}.

Note: Cosmos signing also requires account_number (a separate field on the same endpoint response). Call the endpoint once, extract both values, and set them independently on the SigningInput.

Example

ExampleNonceProvider demonstrates how a caller wires a hdwallet.NonceProvider into an EVM [ethpb.SigningInput] before calling hdwallet.HDWallet.SignTransaction. In production, Nonce calls eth_getTransactionCount("pending") on an Ethereum node; the fake provider here returns a fixed value so the example is deterministic.

package main

import (
	"fmt"
	"math/big"

	hdwallet "github.com/ranjbar-dev/hd-wallet"
	ethpb "github.com/ranjbar-dev/hd-wallet/txproto/ethereum"
)

// staticNonceProvider is a trivial [hdwallet.NonceProvider] used in examples
// and tests. A production implementation calls eth_getTransactionCount (EVM),
// account_info (XRP), or /cosmos/auth/v1beta1/accounts (Cosmos).
type staticNonceProvider struct{ n uint64 }

func (p *staticNonceProvider) Nonce(_ string) (uint64, error) { return p.n, nil }

// ExampleNonceProvider demonstrates how a caller wires a [hdwallet.NonceProvider]
// into an EVM [ethpb.SigningInput] before calling [hdwallet.HDWallet.SignTransaction].
// In production, Nonce calls eth_getTransactionCount("pending") on an Ethereum
// node; the fake provider here returns a fixed value so the example is deterministic.
func main() {
	// 1. Obtain chain state from your provider implementations.
	var nonces hdwallet.NonceProvider = &staticNonceProvider{n: 9}

	// 2. Derive the sender address from the wallet (not shown; see ExampleHDWallet_Address).
	senderAddr := "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"

	nonce, err := nonces.Nonce(senderAddr)
	if err != nil {
		return
	}

	// 3. Build the SigningInput. All chain-state fields come from the providers;
	//    chain constants (chain_id) and transfer details are set directly.
	in := &ethpb.SigningInput{
		ChainId:  big.NewInt(1).Bytes(), // Ethereum mainnet
		Nonce:    big.NewInt(0).SetUint64(nonce).Bytes(),
		GasLimit: big.NewInt(21000).Bytes(),
		GasPrice: big.NewInt(20_000_000_000).Bytes(), // 20 gwei
		TxMode:   0,                                  // hdwallet.EthTxModeLegacy
		// ... set ToAddress, Transaction, etc.
	}

	// 4. Confirm the nonce is set correctly before passing to SignTransaction.
	fmt.Println(new(big.Int).SetBytes(in.Nonce).Uint64())
}
Output:
9

type PolkadotTxFields added in v0.16.0

type PolkadotTxFields struct {
	SignerPubKey    []byte // 32-byte public key
	SignerAddress   string // SS58, rendered with the caller-supplied network prefix
	MultiAddress    bool   // encoding detected for signer/dest: MultiAddress::Id (true) vs raw AccountId (false)
	SignatureScheme string // "ed25519" | "sr25519" | "ecdsa" (from the MultiSignature discriminant)
	Signature       []byte

	Immortal bool
	Period   uint64 // quantized mortal-era period; 0 when Immortal
	Phase    uint64 // quantized mortal-era phase; 0 when Immortal

	Nonce uint64
	Tip   *big.Int

	ModuleIndex byte
	MethodIndex byte

	ToAddress string // SS58 of the transfer destination
	Value     *big.Int
	AssetID   *uint32 // non-nil only for an Assets-pallet-shaped call
}

PolkadotTxFields holds the decoded, display-ready fields of a signed Polkadot v4 extrinsic.

func DecodePolkadotTx added in v0.16.0

func DecodePolkadotTx(raw []byte, network byte) (*PolkadotTxFields, error)

DecodePolkadotTx decodes a signed Polkadot v4 extrinsic (the Encoded bytes signPolkadotTx produces) into its display fields. network is the SS58 address prefix used to render SignerAddress/ToAddress (0 for the Polkadot relay chain and Asset Hub) — display-only, not re-derived from the bytes, so the caller must know which network signed the extrinsic. Malformed, truncated, or unrecognised-call input returns ErrTxDecode; never panics.

type RLPItem added in v0.2.2

type RLPItem struct {
	IsList bool
	Str    []byte
	List   []RLPItem
}

RLPItem is a node in an RLP tree: exactly one of Str (a byte string, a leaf) or List (an ordered list of items) is meaningful. IsList selects which. The zero value is the empty string item (encodes to 0x80).

func DecodeRLP added in v0.2.2

func DecodeRLP(data []byte) (RLPItem, error)

DecodeRLP decodes a single, complete RLP item. It is strict: the entire input must be exactly one canonical item with no trailing bytes.

func RLPList added in v0.2.2

func RLPList(items ...RLPItem) RLPItem

RLPList builds a list RLPItem from the given child items.

func RLPString added in v0.2.2

func RLPString(b []byte) RLPItem

RLPString builds a leaf RLPItem holding the given bytes.

type RecentBlockhashProvider added in v0.11.0

type RecentBlockhashProvider interface {
	RecentBlockhash() (string, error)
}

RecentBlockhashProvider returns the latest confirmed blockhash for a Solana cluster. Callers supply the returned base58-encoded string as SigningInput.recent_blockhash for SOL transactions.

A production implementation calls the getLatestBlockhash JSON-RPC method and returns result.value.blockhash.

type Signature added in v0.2.0

type Signature struct {
	Curve      Curve
	R, S       []byte // ECDSA signature scalars (nil for ed25519)
	RecoveryID byte   // secp256k1 public-key recovery id (0 or 1)
	// contains filtered or unexported fields
}

Signature is the result of signing with a derived key.

For the ECDSA curve (secp256k1), R and S are the signature scalars and the value is available as a 64-byte R||S string, an ASN.1 DER encoding, and a 65-byte recoverable form. For ed25519, R and S are nil and the 64-byte signature is available via Bytes.

func (*Signature) Bytes added in v0.2.0

func (s *Signature) Bytes() []byte

Bytes returns the 64-byte signature: R||S for ECDSA curves, or the raw 64-byte signature for ed25519. Cosmos and Solana use this form.

func (*Signature) DER added in v0.2.0

func (s *Signature) DER() []byte

DER returns the ASN.1 DER encoding (SEQUENCE of two INTEGERs) used by Bitcoin-family chains. It is valid for ECDSA curves; for ed25519 it returns nil.

func (*Signature) Recoverable added in v0.2.0

func (s *Signature) Recoverable() []byte

Recoverable returns the 65-byte [R||S||V] signature, where V is the recovery id (0 or 1), used by Ethereum/EVM chains and Tron. Callers add the chain's V offset (e.g. 27, or 35+2*chainID for EIP-155) as needed. It is only valid for secp256k1; for other curves it returns nil.

type SolanaDecodedInstruction added in v0.10.0

type SolanaDecodedInstruction struct {
	Kind      SolanaInstructionKind
	ProgramID string // base58 program address

	// SystemTransfer fields:
	FromAccount   string // base58 sender account
	ToAccount     string // base58 recipient account
	LamportAmount uint64

	// SPLTransfer / SPLTransferChecked fields:
	SourceToken string // source token account (base58)
	DestToken   string // destination token account (base58)
	TokenMint   string // mint address (TransferChecked only, base58)
	TokenAmount uint64
	Decimals    uint8 // TransferChecked only

	// ComputeBudget fields:
	ComputeUnits  uint32 // SetComputeUnitLimit
	MicroLamports uint64 // SetComputeUnitPrice

	// Raw fallback — always set, useful for Unknown instructions:
	RawData     []byte
	RawAccounts []string // base58 account keys referenced by this instruction
}

SolanaDecodedInstruction is a decoded Solana instruction with typed fields. Only the fields relevant to the instruction Kind are populated; all others are zero. RawData/RawAccounts are always populated for Unknown instructions and as supplemental raw access for known ones.

type SolanaInstructionKind added in v0.10.0

type SolanaInstructionKind int

SolanaInstructionKind identifies a decoded instruction type.

const (
	SolanaInstructionUnknown               SolanaInstructionKind = iota
	SolanaInstructionSystemTransfer                              // system: Transfer
	SolanaInstructionSPLTransfer                                 // spl-token: Transfer
	SolanaInstructionSPLTransferChecked                          // spl-token: TransferChecked
	SolanaInstructionComputeBudgetSetLimit                       // compute-budget: SetComputeUnitLimit
	SolanaInstructionComputeBudgetSetPrice                       // compute-budget: SetComputeUnitPrice
)

SolanaInstructionUnknown is the zero value returned for instructions that are not one of the recognised/decoded types.

type SolanaTxFields added in v0.8.0

type SolanaTxFields struct {
	// Version is -1 for a legacy (non-versioned) message, or the message
	// version (0 for the only version this library compiles/decodes lookups
	// for) when the message carries the 0x80-prefixed versioned-message
	// marker.
	Version               int
	Signatures            [][]byte
	NumRequiredSignatures byte
	NumReadonlySigned     byte
	NumReadonlyUnsigned   byte
	AccountKeys           []string // base58
	RecentBlockhash       string   // base58
	Instructions          []SolanaDecodedInstruction
	// AddressTableLookups is the count of address-table lookups trailing a
	// versioned (v0+) message; always 0 for a legacy message. This library
	// never SIGNS a message with populated lookups, but a decode may
	// encounter one built by someone else, so each lookup entry is parsed
	// (and discarded beyond the count) to stay in sync with the byte stream.
	AddressTableLookups int
}

SolanaTxFields holds the decoded, display-ready fields of a Solana transaction.

func DecodeSolanaTx added in v0.8.0

func DecodeSolanaTx(raw []byte) (*SolanaTxFields, error)

DecodeSolanaTx decodes a raw signed Solana (legacy) transaction into its display fields. Malformed or truncated input returns ErrTxDecode; the function never panics and never reads past `raw`.

type SubstrateContextProvider added in v0.15.0

type SubstrateContextProvider interface {
	RuntimeVersion(chain Chain) (specVersion, transactionVersion uint32, err error)
	GenesisHash(chain Chain) ([]byte, error)
	MortalityCheckpoint(chain Chain) (blockNumber uint64, blockHash []byte, err error)
}

SubstrateContextProvider supplies the chain/runtime context a mortal Substrate extrinsic (DOT) needs beyond the account nonce (which comes from NonceProvider / the system_accountNextIndex RPC). Callers map the returned values onto polkadot.SigningInput as follows:

  • RuntimeVersion → spec_version and transaction_version, from the state_getRuntimeVersion RPC (fields specVersion / transactionVersion). Both enter the signing preimage, so a stale value invalidates the signature at the node — refresh around runtime upgrades.
  • GenesisHash → genesis_hash, from chain_getBlockHash(0). Constant per chain; safe to cache forever.
  • MortalityCheckpoint → block_hash and Era.block_number, from a recent finalized block (chain_getFinalizedHead + chain_getHeader). Pick Era.period (e.g. 64) for the validity window. For an immortal extrinsic omit Era and leave block_hash unset (genesis is used).

type TronContract added in v0.8.0

type TronContract struct {
	Type     int32  // 1=Transfer, 2=TransferAsset, 3=VoteAsset, 4=VoteWitness, 11=FreezeBalance, 12=UnfreezeBalance, 13=WithdrawBalance, 14=UnfreezeAsset, 31=TriggerSmartContract, 54=FreezeV2, 55=UnfreezeV2, 56=WithdrawExpireUnfreeze, 57=DelegateResource, 58=UndelegateResource
	TypeName string // human-readable contract type name, "" if unknown
	TypeURL  string // the google.protobuf.Any type_url

	OwnerAddress string // base58check "T..." address

	// TransferContract / TransferAssetContract.
	ToAddress string // base58check "T..." address
	Amount    int64

	// TransferAssetContract.
	AssetName string // TRC-10 asset ID, e.g. "1000001"

	// TriggerSmartContract.
	ContractAddress string // base58check "T..." address
	Data            []byte // raw call data (e.g. TRC-20 transfer calldata)
	CallValue       int64  // TRX (SUN) sent with the call; 0 if absent
	CallTokenValue  int64  // TRC-10 amount sent with the call; 0 if absent
	TokenID         int64  // TRC-10 token id; 0 if absent

	// FreezeBalanceV2Contract / UnfreezeBalanceV2Contract / FreezeBalanceContract.
	FrozenBalance   int64
	FrozenDuration  int64 // days (FreezeBalanceContract only)
	UnfreezeBalance int64
	Resource        int32 // 0=BANDWIDTH, 1=ENERGY

	// DelegateResourceContract / UndelegateResourceContract.
	Balance         int64
	ReceiverAddress string // base58check "T..." address
	Lock            bool

	// VoteWitnessContract.
	Votes []TronVote

	// VoteAssetContract.
	VoteAddresses []string // base58check "T..." addresses
	Support       bool
	Count         int32
}

TronContract is one decoded contract entry. Type is the Tron ContractType enum value; the populated fields depend on it.

type TronTxFields added in v0.8.0

type TronTxFields struct {
	RefBlockBytes []byte
	RefBlockHash  []byte
	Expiration    int64
	Timestamp     int64
	FeeLimit      int64 // 0 when absent
	Memo          []byte
	Contracts     []TronContract
}

TronTxFields holds the decoded, display-ready fields of a Tron transaction's raw_data.

func DecodeTronTx added in v0.8.0

func DecodeTronTx(raw []byte) (*TronTxFields, error)

DecodeTronTx decodes a raw_data protobuf blob into its display fields. Malformed or truncated input returns ErrTxDecode; the function never panics.

type TronVote added in v0.10.0

type TronVote struct {
	VoteAddress string // base58check "T..." Super Representative address
	VoteCount   int64
}

TronVote is one vote in a VoteWitnessContract.

type UTXOProvider added in v0.11.0

type UTXOProvider interface {
	UTXOs(address string) ([]*txbtc.UnspentTransaction, error)
}

UTXOProvider returns the set of unspent transaction outputs for the given address. Callers supply the returned slice as SigningInput.utxo for Bitcoin-family chains (BTC, LTC, DOGE, BCH, ZEC, DASH, and other registered UTXO altcoins in utxoTxChains).

A production implementation queries an Electrum server, a block explorer REST API (Blockstream esplora, mempool.space), or a full-node listunspent RPC, then constructs one UnspentTransaction per output with out_point_hash (32-byte txid, internal byte order), out_point_index (vout), amount (satoshis), and script (scriptPubKey of the output being spent).

type UserOperation added in v0.10.0

type UserOperation struct {
	Sender               []byte // 20-byte address
	Nonce                *big.Int
	InitCode             []byte
	CallData             []byte
	CallGasLimit         *big.Int
	VerificationGasLimit *big.Int
	PreVerificationGas   *big.Int
	MaxFeePerGas         *big.Int
	MaxPriorityFeePerGas *big.Int
	PaymasterAndData     []byte
	Signature            []byte
}

UserOperation is the ERC-4337 v0.6 struct submitted to the EntryPoint.

type WatchWallet added in v0.3.0

type WatchWallet struct {
	// contains filtered or unexported fields
}

WatchWallet derives receive/change addresses for a single account from its extended PUBLIC key (xpub) — no seed, no private keys, no signing. It is the watch-only counterpart of HDWallet for secp256k1 coins.

func WatchOnlyFromXPub added in v0.3.0

func WatchOnlyFromXPub(xpub string, chain Chain) (*WatchWallet, error)

WatchOnlyFromXPub builds a watch-only wallet for chain from an account-level extended key string. Both xpub and xprv strings are accepted; an xprv is immediately neutered so the WatchWallet never holds private material. chain must be a secp256k1 coin whose address format matches the xpub's chain.

func (*WatchWallet) Address added in v0.3.0

func (ww *WatchWallet) Address(change, index uint32) (string, error)

Address returns the address at the account's change/index branch (e.g. change=0, index=5 -> .../0/5). Both must be non-hardened (< 2^31); public derivation cannot produce hardened children.

func (*WatchWallet) PublicKey added in v0.3.0

func (ww *WatchWallet) PublicKey(change, index uint32) ([]byte, error)

PublicKey returns the 33-byte compressed public key at the change/index branch.

type XPubVersion added in v0.10.0

type XPubVersion int

XPubVersion describes the address type implied by an extended public key prefix.

const (
	XPubVersionUnknown    XPubVersion = iota // prefix did not match a known xpub version
	XPubVersionLegacy                        // xpub/tpub — BIP-44 P2PKH
	XPubVersionP2SHP2WPKH                    // ypub/upub — BIP-49 P2SH-P2WPKH
	XPubVersionP2WPKH                        // zpub/vpub — BIP-84 native SegWit
)

XPubVersionUnknown is the zero value returned when the extended-key prefix is not recognised as any of the known BIP-32 version bytes.

func DetectXPubVersion added in v0.10.0

func DetectXPubVersion(extKey string) XPubVersion

DetectXPubVersion returns the address type implied by the extended key prefix. Returns XPubVersionUnknown for unrecognized or malformed inputs.

type XrpTxFields added in v0.8.0

type XrpTxFields struct {
	TransactionType uint16
	TransactionName string
	Account         string // "r..." address
	Sequence        uint32
	Flags           uint32
	Fee             uint64 // drops
	SigningPubKey   []byte
	TxnSignature    []byte

	LastLedgerSequence *uint32
	DestinationTag     *uint32

	// Payment / EscrowCreate
	Destination string
	Amount      uint64 // drops (Payment, EscrowCreate)

	// TrustSet
	LimitAmountCurrency string
	LimitAmountIssuer   string
	LimitAmountValue    string

	// OfferCreate
	TakerPaysCurrency string
	TakerPaysIssuer   string
	TakerPaysValue    string
	TakerGetsCurrency string
	TakerGetsIssuer   string
	TakerGetsValue    string

	// OfferCreate / OfferCancel / EscrowFinish
	OfferSequence uint32

	// EscrowCreate / EscrowFinish
	Condition   []byte
	CancelAfter *uint32
	FinishAfter *uint32

	// EscrowFinish
	Owner       string
	Fulfillment []byte

	// AccountSet
	SetFlag      *uint32
	ClearFlag    *uint32
	Domain       []byte
	TransferRate *uint32
	TickSize     *uint32
}

XrpTxFields holds the decoded, display-ready fields of an XRP transaction. Pointer fields are nil when the field was absent on the wire.

func DecodeRippleTx added in v0.8.0

func DecodeRippleTx(raw []byte) (*XrpTxFields, error)

DecodeRippleTx decodes a serialized XRP transaction into its display fields. Malformed or truncated input returns ErrTxDecode; never panics.

Directories

Path Synopsis
cmd
hdwallet command
Command hdwallet is a small demo CLI for the hd-wallet library: it generates a fresh BIP-39 mnemonic (or imports one) and prints the receive address for every supported network.
Command hdwallet is a small demo CLI for the hd-wallet library: it generates a fresh BIP-39 mnemonic (or imports one) and prints the receive address for every supported network.
txproto
ton

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL