Chain table
Source of truth: crates/core/src/chains.rs. Known-answer vectors come from scripts/kat-chains.py, an independent base58check that uses only hashlib,β¦
Source of truth: crates/core/src/chains.rs. Known-answer vectors come from scripts/kat-chains.py, an independent base58check that uses only hashlib, and are checked in the kat_long_tail test. tx-build builds chains whose Sign is Standard or ForkId (bch/bsv/btg; tx-sign signs those with SIGHASH_ALL|FORKID, see below); it refuses PosTime only for pot (ppc/nvc/clam/rdd have a dedicated pos-ntime builder/signer, crates/tx/src/pos.rs; blk is Standard) and Unknown (qrk, plus the non-UTXO chains, which have their own signers). No coin other than BTC has been signed and accepted on a real network.
Supported (verified)
| name | ticker | SLIP-44 | p2pkh | p2sh | hrp | wif | checksum | decimals | forkid | tx format | sweep build | sources |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| btc | BTC | 0 | 00 | 05 | bc | 128 | sha256d | 8 | β | legacy | yes | esplora blockstream.info |
| ltc | LTC | 2 | 30 | 32 | ltc | 176 | sha256d | 8 | β | legacy | yes | esplora litecoinspace.org |
| doge | DOGE | 3 | 1e | 16 | β | 158 | sha256d | 8 | β | legacy | yes | none |
| eth | ETH | 60 | β | β | β | β | β | 18 | β | evm | no | none |
| tron | TRX | 195 | β | β | β | β | β | 6 | β | account | no | none |
| xrp | XRP | 144 | β | β | β | β | β | 6 | β | account | no | none |
| sol | SOL | 501 | β | β | β | β | β | 9 | β | account | no | none |
| atom | ATOM | 118 | β | β | cosmos | β | β | 6 | β | account | no | none |
| algo | ALGO | 283 | β | β | β | β | β | 6 | β | account | no | none |
| ada | ADA | 1815 | β | β | β | β | β | 6 | β | account | no | none |
| ton | TON | 607 | β | β | β | β | β | 9 | β | account | no | none |
| dot | DOT | 354 | β | β | β | β | β | 10 | β | account | no | none |
| xlm | XLM | 148 | β | β | β | β | β | 7 | β | account | no | none |
| aptos | APT | 637 | β | β | β | β | β | 8 | β | account | no | none |
| sui | SUI | 784 | β | β | β | β | β | 9 | β | account | no | none |
| near | NEAR | 397 | β | β | β | β | β | 24 | β | account | no | none |
| xtz | XTZ | 1729 | β | β | β | β | β | 6 | β | account | no | none |
| egld | EGLD | 508 | β | β | β | β | β | 18 | β | account | no | none |
| qtum | QTUM | 2301 | 3a | 32 | qc | 128 | sha256d | 8 | β | legacy | yes | qtuminfo qtum.info |
| ftc | FTC | 8 | 0e | 05 | fc | 142 | sha256d | 8 | β | legacy | yes | none |
| nmc | NMC | 7 | 34 | 0d | nc | 180 | sha256d | 8 | β | legacy | yes | none |
| dash | DASH | 5 | 4c | 10 | β | 204 | sha256d | 8 | β | legacy | yes | blockbook blockbook.dash.zelcore.io; insight insight.dash.org |
| vtc | VTC | 28 | 47 | 05 | vtc | 128 | sha256d | 8 | β | legacy | yes | blockbook blockbook.vtc.zelcore.io |
| dgb | DGB | 20 | 1e | 3f | dgb | 128 | sha256d | 8 | β | legacy | yes | blockbook blockbook.dgb.zelcore.io |
| via | VIA | 14 | 47 | 21 | via | 199 | sha256d | 8 | β | legacy | yes | blockbook blockbook.viacoin.org |
| mona | MONA | 22 | 32 | 37 | mona | 176 | sha256d | 8 | β | legacy | yes | insight mona.insight.monaco-ex.org |
| rvn | RVN | 175 | 3c | 7a | β | 128 | sha256d | 8 | β | legacy | yes | blockbook blockbook.rvn.zelcore.io; blockbook blockbook.ravencoin.org |
| xpm | XPM | 24 | 17 | 53 | β | 151 | sha256d | 8 | β | legacy | yes | cryptoid chainz.cryptoid.info |
| trc | TRC | 83 | 00 | 05 | β | 128 | sha256d | 8 | β | legacy | yes | none |
| mec | MEC | 217 | 32 | 05 | mec | 178 | sha256d | 8 | β | legacy | yes | none |
| aur | AUR | 85 | 17 | 05 | β | 176 | sha256d | 8 | β | legacy | yes | cryptoid chainz.cryptoid.info |
| bch | BCH | 145 | 00 | 05 | β | 128 | sha256d | 8 | 0 | forkid | yes | none |
| bsv | BSV | 236 | 00 | 05 | β | 128 | sha256d | 8 | 0 | forkid | yes | woc whatsonchain.com |
| btg | BTG | 156 | 26 | 17 | btg | 128 | sha256d | 8 | 79 | forkid | yes | none |
| ppc | PPC | 6 | 37 | 75 | pc | 183 | sha256d | 6 | β | pos-ntime | yes | blockbook blockbook.peercoin.net |
| nvc | NVC | 50 | 08 | 14 | β | 136 | sha256d | 6 | β | pos-ntime | yes | cryptoid chainz.cryptoid.info |
| clam | CLAM | 23 | 89 | 0d | β | 133 | sha256d | 8 | β | pos-ntime | yes | cryptoid chainz.cryptoid.info |
| blk | BLK | 10 | 19 | 55 | β | 153 | sha256d | 8 | β | legacy | yes | cryptoid chainz.cryptoid.info |
| rdd | RDD | 4 | 3d | 05 | rdd | 189 | sha256d | 8 | β | pos-ntime | yes | blockbook blockbook.reddcoin.com |
| pot | POT | 81 | 37 | 6e | β | 183 | sha256d | 8 | β | pos-ntime | no | cryptoid chainz.cryptoid.info |
| qrk | QRK | 82 | 3a | 09 | β | 186 | sha256d | 5 | β | legacy | yes | cryptoid chainz.cryptoid.info |
| zec | ZEC | 133 | 1cb8 | 1cbd | β | 128 | sha256d | 8 | β | zcash-v5 | yes (transparent P2PKH) | none |
| grs | GRS | 17 | 24 | 05 | grs | 128 | groestl512d | 8 | β | legacy-sha256 | yes | none listed |
| strd | STRD | 118 | β | β | stride | β | β | 6 | β | account | no | none |
| axl | AXL | 118 | β | β | axelar | β | β | 6 | β | account | no | none |
| cre | CRE | 118 | β | β | cre | β | β | 6 | β | account | no | none |
| kuji | KUJI | 118 | β | β | kujira | β | β | 6 | β | account | no | none |
| cmdx | CMDX | 118 | β | β | comdex | β | β | 6 | β | account | no | none |
| ntrn | NTRN | 118 | β | β | neutron | β | β | 6 | β | account | no | none |
| somm | SOMM | 118 | β | β | somm | β | β | 6 | β | account | no | none |
| fet | FET | 118 | β | β | fetch | β | β | 6 | β | account | no | none |
| mars | MARS | 118 | β | β | mars | β | β | 6 | β | account | no | none |
| umee | UMEE | 118 | β | β | umee | β | β | 6 | β | account | no | none |
| noble | USDC | 118 | β | β | noble | β | β | 6 | β | account | no | none |
| sei | SEI | 118 | β | β | sei | β | β | 6 | β | account | no | none |
| tia | TIA | 118 | β | β | celestia | β | β | 6 | β | account | no | none |
| coreum | CORE | 990 | β | β | core | β | β | 6 | β | account | no | none |
| qsr | QSR | 118 | β | β | quasar | β | β | 6 | β | account | no | none |
| xprt | XPRT | 118 | β | β | persistence | β | β | 6 | β | account | no | none |
| akt | AKT | 118 | β | β | akash | β | β | 6 | β | account | no | none |
| kava | KAVA | 459 | β | β | kava | β | β | 6 | β | account | no | none |
| blz | BLZ | 483 | β | β | bluzelle | β | β | 6 | β | account | no | none |
| band | BAND | 494 | β | β | band | β | β | 6 | β | account | no | none |
| cro | CRO | 394 | β | β | cro | β | β | 8 | β | account | no | none |
| bld | BLD | 564 | β | β | agoric | β | β | 6 | β | account | no | none |
| dydx | DYDX | 118 | β | β | dydx | β | β | 18 | β | account | no | none |
| rune | RUNE | 931 | β | β | thor | β | β | 8 | β | account | no | none |
| inj | INJ | 60 | β | β | inj | β | β | 18 | β | account | no | none |
| evmos | EVMOS | 60 | β | β | evmos | β | β | 18 | β | account | no | none |
| canto | CANTO | 60 | β | β | canto | β | β | 18 | β | account | no | none |
| zeta | ZETA | 60 | β | β | zeta | β | β | 18 | β | account | no | none |
Fee-warning limits (verify-tx / wasm verifyTx, chainParams().fee_warn)
high_fee fires above fee base units, high_fee_rate above rate base units per vbyte. Default 1,000,000 / 500 (Bitcoin-tuned). A per-coin row is 20 x the measured median fee rate x a 1,000 vB sweep (rate limit 20 x median), never below the default. Measured 2026-10-24 from recent mainnet blocks (non-coinbase txs, fee = inputs - outputs); scripts in the commit message basis strings.
Since 2026-10-25: (1) the fee limit is per started 1,000 vB of the tx (FeeWarn::fee_for(vsize) = fee x ceil(vsize/1000)), so a 147-input VTC sweep (~21,800 vB) is checked against 22 x 2,000,000, not 2,000,000; (2) the hard fee-rate cap in every sweep builder (buildUnsignedSweep*, legacy, pos-ntime and zec) is per coin, FeeWarn::rate_cap() = max(2,000, 4 x rate limit): btc/default 2,000, xpm 8,000,000 (measured median 100,312 sat/B is now buildable). Break: the pos-ntime and zec builders previously allowed up to 100,000 sat/B; they now get their row's cap (2,000 unless the row has a measured limit). (unmeasured)
Default fee cap (signing, no --max-fee; 3ec1d1a). Every signing route (tx-sign, tx-verify, envelope, wasm verifyTx) refuses fee_above_cap above max(100,000 sat, the chain's rate limit from this table x the tx's vsize), even with warnings waived; an explicit max_fee replaces it. The verdict reports fee_cap {chain, cap, source}. Measured by crates/tx/tests/fee_cap_chains.rs: SwapChan's corpus of 35 legitimate sweeps all pass (the old flat 100,000-sat cap refused 9 of 35); on each of the 27 buildable chains a fee 1 unit over the cap is refused and 10x the cap passes only with an explicit max_fee. BTC: a 1-input tx paying 240,000 sat is refused.
| chain | fee limit | rate limit | measured median | sample |
|---|---|---|---|---|
| dgb | 10,000,000 | 10,000 | 512 sat/vB | 60 txs, blocks 24444779-24445073, blockbook.dgb.zelcore.io (unmeasured) |
| rvn | 20,000,000 | 20,000 | 1004 sat/vB | 60 txs, blocks 4596227-4596275, blockbook.rvn.zelcore.io (unmeasured) |
| qtum | 14,000,000 | 14,000 | 700 sat/vB | 100 txs, blocks 6253698-6255768, qtum.info (unmeasured) |
| xpm | 2,000,000,000 | 2,000,000 | 100,312 sat/B | 30 txs, blocks 7064002-7064118, chainz.cryptoid.info (raw rebuilt from explorer JSON, sha256d = txid, exact size) (unmeasured) |
| vtc | 2,000,000 | 2,000 | 101 sat/vB | 60 txs, blocks 2703728-2703858, blockbook.vtc.zelcore.io (unmeasured) |
| doge | 1,200,000,000 | 1,200,000 | 60,463 sat/B (p10 2,418, p90 523,560) | 100 txs, blocks 6429664-6429671, blockbook.doge.zelcore.io, sha256d-checked. Policy minimum 1,000 sat/B (RECOMMENDED_MIN_TX_FEE 0.01 DOGE/kB) is far below what wallets pay (unmeasured) |
| ftc | 40,000,000 | 40,000 | 2,000 sat/vB (p10 600) | 100 txs (21 segwit), blocks 6407004-6408299, blockbook.feathercoin.com (unmeasured) |
| mona | 2,000,000 | 2,000 | 2.54 sat/vB; p75 and p90 = 100 | 100 txs, blocks 4142748-4143093, mona.insight.monaco-ex.org, exact vsize (witness stripped), 100/100 txids checked. Bimodal: ~2.5 (relay-minimum wallets) and 100 (Monacoin Core DEFAULT_TRANSACTION_MINFEE 100,000/kB); the limit is 20 x the 100 mode (unmeasured) |
| aur | 2,000,000 | 2,000 | 102.8 sat/B | 30 txs, blocks 5913204-5913347, chainz.cryptoid.info (raw rebuilt, sha256d = txid, exact size) (unmeasured) |
MONA rate (SwapChan uses 220): the chain data says 2.5 sat/vB is the median and 100 sat/vB the common wallet default; no sampled tx paid 220 (max 349, one outlier). 2.5 is right as "what the chain accepts" (node relayfee 0.001 MONA/kB = 1 sat/B); 100 matches Monacoin Core's default minimum tx fee. 220 is not supported by the data: it overpays ~2x the wallet default and ~90x the median. Suggest 100 (wallet-compatible) or a floor of 3. (unmeasured)
Measured and left at the default: dash (3.9 sat/B, 60 txs, blockbook.dash.zelcore.io), trc (re-measured 2026-10-25: median 20.0 sat/B, p10 1.32, p90 20.1, 100 txs in 2,743 blocks 3325168-3327910, insight.terracoin.io, txid-checked 100/100; replaces the earlier 14-tx 14.8 figure), ppc (blockbook reports fee 0 for most txs; fees are burned), via (4 txs in 400 blocks, all fee 0). Also measured: wdc 5.4 sat/B (4 txs, block 11881187; default kept). Not measured (default applies): every other row, including nmc, mec, nvc, clam, blk, pot, qrk, grs, bch, bsv, btg, ltc. (unmeasured)
RDD (not measured): source found, rddblockexplorer.com (blockbook). Nearly every tx is a PoSV stake (outputs > inputs); a scan of ~9,000 blocks (6002715-6011409) found only 32 fee-paying txs, and the run was stopped before fees were computed. RDD keeps the default limits (now size-scaled); its own row still needs measuring.
ZEC vs ZIP-317 (2026-10-25): 200 txs, blocks 3529835-3529915, blockbook.zec.zelcore.io. Ratio fee / ZIP-317 conventional fee (5,000 x max(2, transparent inputs, transparent outputs)): median 1.48, p10 1.00, 73/199 exactly 1.00, 1 below 1. The upper tail (p90 ~125,000x) is not real overpayment: blockbook cannot see shielded value, so for shielding/unshielding txs inputs - outputs is not the fee; only transparent-only txs are meaningful there, and the ZIP-317 figure is a lower bound when shielded actions exist. Rate median 49.7 sat/B (ZIP-317 minimum on a 1-in-1-out tx). Default limits kept. Immature coinbase: the ZEC explorer SwapChan uses (blockbook.zec.zelcore.io) lists immature coinbase outputs as spendable UTXOs (reported by SwapChan; not re-measured here); consensus requires 100 confirmations (COINBASE_MATURITY). Consumers must drop UTXOs with coinbase: true and confirmations < 100 before buildUnsignedSweep; blocktools cannot tell from {txid,vout,amount,address} alone. (unmeasured)
Unverified (never returned as supported)
| name | ticker | SLIP-44 | p2pkh | p2sh | hrp | wif | checksum | decimals | forkid | tx format | sweep build | sources |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wdc | WDC | 0 | 49 | 05 | β | 201 | sha256d | 8 | β | legacy | no | cryptoid chainz.cryptoid.info |
| anc | ANC | 0 | 17 | 0f | β | 151 | sha256d | 8 | β | legacy | no | none |
| bcc | BCC | 0 | 12 | 55 | β | 146 | sha256d | 8 | β | pos-ntime | no | none |
Zcash Sapling: zec-sapling CLI (ZIP-32, m/32'/133'/i', zs1 default address, optional 0600 viewing-key file; --unified adds the ZIP-316 u1 orchard+sapling+p2pkh address and t1). No spend/scan.
Zcash transparent is listed by wasm listChains/supportedChains (scope transparent) since 2026-10-25. Evidence: ZIP-243/244 official vectors, 7 mainnet txs (txid + signature), 21 mainnet script->address pairs from api.blockchair.com (crates/tx/tests/data/zec_addresses.txt). Untested: BIP44 m/44'/133' derivation, xpubs, broadcast, v6.
WDC: tx format confirmed Bitcoin-legacy on 4 mainnet txs (block 11881187): txid = sha256d, 357 P2PKH signatures verify under the legacy sighash, and every input address re-derives under p2pkh 73 (crates/tx/tests/wdc.rs). Still verified: false: no SLIP-44 coin type, so no derivation path can be checked. QRK (2026-10-25): tx format Bitcoin-legacy, found via chainz api.dws?q=lasttxs (block-by-block scanning saw only coinbase): 10/10 recent non-coinbase txs rebuild to their txid under sha256d, but only with values x 1e5, i.e. QRK has 5 decimals (COIN = 100000; the table said 8, now fixed: decimals 5). crates/tx/tests/qrk.rs: 2 txs (blocks 13906691, 13907052; 8 and 170 inputs), 10 P2PKH signatures verify under the legacy sighash and re-derive to the chainz input addresses under p2pkh 58; 168 P2PK inputs are not checked (pubkey lives in the prevout). Row now Standard, so buildUnsignedSweep supports qrk. Untested: a built QRK sweep broadcast on mainnet; QRK fee rates (default limits apply).
Account payments (2026-10-25)
xlm, algo, atom, ton, ada and dot have payment/sweep builders in acct-tx (see recipes/chain-polkadot.md, chain-cardano.md, chain-ton.md, chain-stellar.md, chain-algorand.md, chain-cosmos.md). The table's
sweep build column is the wasm/UTXO builder only and stays no for them.
Groestlcoin extended keys and taproot (2026-10-25)
GRS xpub/tpub strings use the Groestl-512 checksum and are accepted only with --chain grs (vectors: Groestlcoin/eclair commit f52fbf9, 4 tpub pairs); classify reports them as xpub. GRS rows include p2tr (grs1pβ¦, BIP341 vector); spending GRS taproot inputs is refused. Untested: real Electrum-GRS mainnet xpub, any mainnet grs1p.
Monero (2026-10-25)
Scan and sweep: host tool xmr-wallet over a loopback monero-wallet-rpc. 2026-10-25 stagenet run (Mac, official monero v0.18.5.4 binaries, SHA-256 checked against the published hashes.txt): faucet 0.5 XMR seen by xmr-wallet scan (unlocked 500000000000 at height 2236134); xmr-wallet sweep --relay planned amount 499969620000 + fee 30380000 = unlocked, relayed tx bb300227e8e6c418fe7d825ac432d79abc2d4b943d99e053eabfba3c8197a96d (mined in stagenet block 2236135, checked on a public stagenet node); a view-only scan of the destination wallet shows that amount incoming (pool). The TTY confirm was answered by an expect script standing in for a human. Untested: mainnet, Polyseed/13-word/non-English seeds, subaddresses.
Solana public data (2026-10-25)
wasm/lib sol: PDA/ATA, on-curve, Anchor discriminator, legacy+v0 tx decode, ed25519 signature check, solVerifyTx policy. No Solana builder yet (planned: acct-tx style, solders vectors).
- 2026-10-26: BCH CashAddr destinations in the CLIs:
tx-build --to,tx-verify --expect-toandtx-sign --expect-toacceptbitcoincash:qβ¦/pβ¦, bare and upper-case forms (mainnet prefix, 20-byte hash). Measured (Linux only):crates/core/tests/cashaddr_script.rs(2 tests; CashAddr spec table, the CashAddr maps to the same script as its legacy address; bad checksum, mixed case,bchtestrefused) andscripts/e2e.d/cashaddr-tx.sh(tx-build bytes identical to the legacy--to, verify refuses a different destination, tx-sign passes). Untested: other CashAddr hash sizes (refused), eCash prefix onxec. - 2026-10-25: BCH CashAddr accepted by
addressToScript('bch', β¦)and converted bycashAddrToLegacy/legacyToCashAddr. - 2026-10-25: EVM transfer builder for any chain id (
buildEvmTransfer); UTXO selection (selectUtxos). - 2026-10-25: EVM recovery/sweep verifier (SwapChan parity, raw tx entry points).
- 2026-10-25: Solana v1 transactions (SIMD-0385) decode + verify; XRP X-address kind
xaddressin detectAddressInfo. - 2026-10-25:
buildPsbtWithMemooutput order[to, change, OP_RETURN](THORChain), optional memo, selected-input fee fix. - 2026-10-25: Tron txID + raw_data decode (
tronDecodeTx); BTC-family PSBT with OP_RETURN memo (buildPsbtWithMemo).
Fork-id signing (BCH, BSV, BTG)
tx-sign signs bch/bsv/btg PSBTs from tx-build with the replay-protected fork-id sighash: the BIP143 digest layout for every input type (P2PKH included), committed with the 32-bit type 0x41 | forkid << 8 (BCH/BSV forkid 0 -> 0x41; BTG forkid 79 -> 0x4f41), signature byte 0x41. Never the BTC sighash. Signed: P2PKH (compressed and uncompressed) and P2PK on all three; P2WPKH on BTG only (the only one with an hrp). Refused: any other script (forkid_script_unsupported), any input without a proving prev_tx (legacy_input_amount_unproven), P2WPKH on bch/bsv.
Measured (Linux only): forkid_sighash matches all 495 SIGHASH_FORKID rows of Bitcoin ABC's src/test/data/sighash.json (crates/tx/tests/forkid.rs; vendored verbatim as crates/tx/tests/vectors/abc-sighash.json); the signatures in BCH mainnet tx 96ee2000β¦bbb4, BSV mainnet tx 8f95d11fβ¦508c (block 972,739) and Trust Wallet Core's BTG P2WPKH vector verify under it and do not verify under the BTC sighash (or, for BTG, fork id 0); tx-sign's signer reproduces Trust Wallet Core's BCH and BTG signed txs byte for byte (forkid_bch_btg_byte_exact); scripts/e2e.d/forkid.sh builds, tty-signs, decodes and re-verifies a sweep on each chain and checks each signature with an independent pure-Python ECDSA verifier. Untested: broadcast or acceptance on any of the three networks, BCH CashAddr destinations in tx-build, BCH Schnorr signatures, multi-input fork-id txs against a real node.
Every non-segwit input needs prev_tx: P2PKH on every chain including the fork-id chains BCH/BSV/BTG (their sighash commits the amount, but every check keys on the script type and the fork-id signer requires the proof too), GRS and PoS-nTime. Only zec is exempt (ZIP-243/244 amounts via zec_prevouts).
- 2026-10-25:
buildPsbtWithMemodefaults to non-RBF (0xffffffff); optional trailingrbfarg.
EVM: Trust Wallet Core signer vectors
crates/tx/tests/vectors/twc-evm.json vendors the 13 signed transactions of Trust Wallet Core's rust/tw_evm/tests/signer.rs (commit adf80f8, Apache-2.0; public test keys): 7 legacy EIP-155 (native, ERC-20 transfer and approve, ERC-20 transfer as a generic contract call, ERC-721 and ERC-1155 transfer, a contract creation on chain id 1) and 6 EIP-1559 (native on chain id 3, ERC-20 transfer, transfer with an access list, approve, ERC-721, ERC-1155).
Measured (Linux only): every one parses, recovers to the address of its key, round-trips, and re-signs byte for byte from its unsigned form with evm::Tx::sign (crates/tx/tests/twc_evm.rs, 7 legacy + 6 EIP-1559); a changed nonce stops it recovering to the signer. scripts/e2e.d/twc-evm.sh runs the legacy native and the EIP-1559 ERC-20 vectors through the real tx-sign CLI (code typed on a pty) and gets Trust Wallet Core's bytes; ERC-1155 safeTransferFrom is refused as unknown_contract_call and ERC-721 transferFrom as token_call_not_transfer, before any key is read.
Refused (no vector here): EIP-2930 type 1 (eip2930_unsupported), EIP-4844 type 3 (eip4844_unsupported), EIP-7702 type 4 (eip7702_unsupported), and Trust Wallet Core's ERC-4337 / Barz user operations. Untested: broadcast on any network, NFT-aware decoding (ERC-721/1155 are shown only as raw or transferFrom calldata), chain ids outside the vectors.
Message signing: Trust Wallet Core message-signer vectors
msg-sign and msg-verify port Trust Wallet Core's EthMessageSigner (rust/tw_evm/tests/message_signer.rs) and BitcoinMessageSigner (tests/chains/Bitcoin/MessageSignerTests.cpp), commit adf80f8, public test keys. Code: crates/tx/src/message.rs. The chain is detected from the address: 0x + 40 hex is Ethereum, a base58 P2PKH address starting with 1 is Bitcoin; --chain must agree.
- Ethereum: EIP-191
personal_sign, keccak256("\x19Ethereum Signed Message:\n" + decimal length + message). The signature is r||s||v, with v = 27/28 (legacy, the default), 0/1 (raw, Immutable X) or 35 + 2N + rec (eip155:N). - Bitcoin: Bitcoin Core
signmessage, sha256d(varstr("Bitcoin Signed Message:\n") + varstr(message)), base64 of header||r||s with header 27 + rec (+4 for a compressed key). msg-sign picks compressed or uncompressed from whichever P2PKH address the key matches.
Measured (Linux only): crates/tx/tests/twc_message.rs (2 tests). It signs TWC's 4 Ethereum vectors byte for byte (legacy "Foo", legacy_hex as bytes, eip155 chain 0, Immutable X) and recovers each to its key's address. It signs TWC's 3 Bitcoin vectors byte for byte (compressed "test signature" and "another text", uncompressed "test signature"), recovers all 6 of TWC's Bitcoin verify vectors (one of them, 1B8Qea.., is high-s and is accepted on verify as Bitcoin Core does), matches both messageToHash values, and covers TWC's negatives: wrong address, signature too short, segwit address. scripts/e2e.d/twc-message.sh runs the real CLIs (code typed on a pty), gets TWC's signatures for 2 Bitcoin and 3 Ethereum cases, and checks every refusal below plus the wrong-code abort; a mismatched verify exits 1 with signer_mismatch.
Refused by msg-sign, before any key is read: a bare 32-byte hash (blind_hash_message; TWC signs its legacy_hex vector this way, and msg-verify checks it with --hex, but blocktools will not sign a hash it cannot show); hex or typed-data input (only_text_messages_signed); a message that decodes as a transaction or PSBT (message_looks_like_transaction); non-UTF-8, empty or oversized messages; segwit and taproot addresses (address_not_p2pkh; BIP137 segwit headers 35-42 and BIP322 are unsupported); other chains' message prefixes (message_prefix_unproven_for_chain, e.g. ltc, doge); EIP-712 (blocktools only verifies it, with typed-data-verify). A key that does not match --address gives address_does_not_match_key. Untested: testnet addresses, wallets other than TWC (no vectors from MetaMask, Electrum or Bitcoin Core were run here), and long messages (the multi-byte varint length prefix has no vector).
Cosmos SDK: Trust Wallet Core MsgSend vectors
acct-tx --chain atom builds, signs and decodes Cosmos SDK MsgSend (/cosmos.bank.v1beta1.MsgSend, SIGN_MODE_DIRECT, secp256k1 pubkey). Code: crates/acct/src/atom.rs. The chain is detected from the bech32 hrp of --from (and of the TxRaw on decode); --to must use the same hrp. The hrp picks the base denom and the default --chain-id; a different chain id or denom is a warning, not an error, so testnets still decode.
| hrp | chain | default chain id | denom | TWC vector (adf80f8) |
|---|---|---|---|---|
| cosmos | Cosmos Hub | cosmoshub-4 | uatom | tests/chains/Cosmos/SignerTests.cpp SignTxProtobuf (gaia-13003) |
| osmo | Osmosis | osmosis-1 | uosmo | Osmosis/SignerTests.cpp SignTransfer_81B4 |
| juno | Juno | juno-1 | ujuno | Juno/TWAnySignerTests.cpp Sign |
| stars | Stargaze | stargaze-1 | ustars | Stargaze/TWAnySignerTests.cpp Sign |
| secret | Secret | secret-4 | uscrt | Secret/SignerTests.cpp Sign |
| terra | Terra 2 | phoenix-1 | uluna | TerraV2/SignerTests.cpp SignSendTx |
| cro | Crypto.org | crypto-org-chain-mainnet-1 | basecro | CryptoOrg/TWAnySignerTests.cpp SignTx_Proto_BCB213 |
Measured (Linux only): crates/acct/tests/twc_cosmos.rs (33 tests; 20 address-only hrps signed against vectors from tools/twc-vectors/gen_cosmos23.rs). Evmos has no published TWC signer vector: its vector was generated by running wallet-core adf80f8's own Rust signer on fixed inputs with a TWC public test key (tools/twc-vectors/, manual workflow twc-vectors.yml on Battleaxe; inputs and run id in the test). Injective (2 vectors: NativeInjective/SignerTests.cpp, TransactionCompilerTests.cpp) and ZetaChain (rust/tw_tests/tests/chains/zetachain/zetachain_sign.rs, athens testnet) sign with ethsecp256k1: keccak256(SignDoc), Injective's AuthInfo carries the 65-byte uncompressed key under /injective.crypto.v1beta1.ethsecp256k1.PubKey, ZetaChain the 33-byte key under /ethermint.crypto.v1.ethsecp256k1.PubKey; a fee with no coin (ZetaChain's vector) round-trips. For each chain it decodes TWC's tx_bytes, verifies the signature, checks the detected chain, re-signs with TWC's public test key and requires the TxRaw to match byte for byte. One test feeds TWC's IBC transfer, MsgVote, Terra CosmWasm and Stargaze CW721 vectors to the decoder and requires each to be refused. scripts/e2e.d/twc-cosmos.sh rebuilds the Osmosis vector from its inputs with the real CLI (keys --hrp osmo, build, sign with the code typed on a pty) and gets TWC's tx_bytes exactly, then checks the refusals below.
Refused: any other hrp (cosmos_hrp_without_vector), which includes Canto (TWC adf80f8 signs Canto as plain Cosmos with a /cosmos.crypto.secp256k1.PubKey and sha256, which does not match its ethsecp256k1 address); a --to on another hrp (wrong network); every message other than MsgSend (IBC, staking, governance, CosmWasm, NFTs); amino-JSON signing (TWC's Crypto.org amino and SignTxJson vectors are not ported); fee and amount in different denoms. Untested: TWC's SignDirect_0a90010a vector (a pre-built body passed through; its auth info carries no pubkey, which the decoder refuses), broadcast, multi-coin amounts, Terra Classic (same terra hrp; columbus-5 gets the chain-id warning but has no vector here), and signing on the 23 address-only Cosmos rows below.
Cosmos SDK address rows (TWC address vectors, no signing)
strd, axl, cre, kuji, cmdx, ntrn, somm, fet, mars, umee, noble, sei, tia, coreum, qsr, xprt, akt, kava, blz, band, bld, dydx and rune (THORChain), plus cro: derive (m/44'/coin'/0'/0/i), validate and auto-detect from the bech32 hrp. Hrp and coin type from TWC adf80f8 registry.json. Measured (Linux only): crates/blocktools/tests/twc_cosmos_addr.rs (4 tests) derives TWC's tests/common/CoinAddressDerivationTests.cpp address for the public 0x46Γ32 dummy key on all 24, checks the coin type and decimals and that detect returns exactly that chain, and replays 19 pubkey-to-address vectors from tests/chains/Cosmos/<Chain>/TWAnyAddressTests.cpp. acct-tx refuses to sign on these hrps (cosmos_hrp_without_vector) except cro, because TWC has no MsgSend vector for them. Untested: balance lookup, any transaction on these chains.
Ethermint (ethsecp256k1) address rows: inj, evmos, canto, zeta
Injective, Evmos, Canto and ZetaChain native addresses: path m/44'/60'/0'/0/i (the same key as the EVM address), address = bech32(hrp, keccak256(uncompressed pubkey)[12..]), i.e. the EVM address bytes under the chain's hrp. Derive, validate and auto-detect from the hrp; address only. Hrp, path and 18 decimals from TWC adf80f8 registry.json. Measured (Linux only): twc_ethermint_address in crates/blocktools/tests/twc_cosmos_addr.rs derives TWC's CoinAddressDerivationTests.cpp address for the 0x46Γ32 key on all 4, replays the pubkey-to-address vector from tests/chains/Cosmos/Native{Injective,Evmos,Canto}/TWAnyAddressTests.cpp and rust/tw_tests/tests/chains/zetachain/zetachain_address.rs, and checks detect returns exactly that chain. acct-tx signs MsgSend on inj, zeta and evmos (TWC signer vectors; Evmos TWC-signer-generated, see above) and refuses canto (cosmos_hrp_without_vector). Untested: broadcast on any of them (no Evmos tx has been accepted by a node), balance lookup, any Canto transaction.
Chain quirks and their known-answer vectors (2026-10-25)
Every way a chain departs from plain Bitcoin is listed here with at least one independent
known-answer test (KAT): a vector from another implementation, a spec, or real chain data, never
only our own output. crates/tx/tests/quirks.rs parses this table and fails if a row has no KAT,
names a test that does not exist, or lacks a source, and if a chain with a quirk in code
(pos::layout, the zec path, single-SHA-256 GRS digests) has no row. Add the vector with the quirk.
| quirk | chains | KAT (tests file::fn) | vector source |
|---|---|---|---|
| groestl-single-sha256-bip143 | grs | grs.rs::bip143_single_sha256_vectors | groestlcoinjs-lib test/fixtures/transaction.json hashForWitnessV0 (data/grs_witness_v0.txt) |
| groestl-single-sha256-legacy | grs | grs.rs::mainnet_signatures_verify_under_single_sha256 | Groestlcoin mainnet txs, api.blockchair.com raw/transaction (data/grs_mainnet.txt) |
| pos-ntime-after-version | ppc nvc clam | pos.rs::mainnet_txids_and_signatures | PPC raw hex from Blockbook; NVC/CLAM from chainz.cryptoid.info JSON, txid-checked (data/pos_mainnet.txt) |
| pos-ntime-after-locktime | rdd | pos.rs::mainnet_txids_and_signatures | RDD mainnet raw hex from Blockbook (data/pos_mainnet.txt) |
| pos-nvc-json-serialize | nvc | nvc_json.rs::mainnet_json_reserializes_to_txid | api.novaco.in gettransaction JSON, coinstake + regular + PoS coinbase, txid-checked (data/nvc_*.json) |
| blk-bitcoin-layout | blk | pos.rs::blackcoin_is_bitcoin_layout | Blackcoin mainnet txs (data/pos_mainnet.txt blk rows) |
| zcash-v5-zip244 | zec | zcash.rs::zip244_vectors | zcash-test-vectors zip_0244.json (data/zec_zip244.txt) |
| zcash-v4-zip243 | zec | zcash.rs::zip243_vectors | zcash-test-vectors zip_0243.json (data/zec_zip243.txt) |
| zcash-envelope-mainnet | zec | zcash.rs::mainnet_txs | zec mainnet txs, api.blockchair.com raw/transaction (data/zec_mainnet.txt) |
| zcash-blake2b-personal | zec | zcash.rs::blake2b_matches_hashlib | Python hashlib.blake2b with person= |
| p2sh-wrapped-segwit | btc ltc | sign.rs::bip143_p2sh_p2wpkh_byte_exact | BIP143 P2SH-P2WPKH example |
| p2sh-bare-amount-uncommitted | btc ltc | sign.rs::bare_p2sh_is_not_amount_committed | BIP143 vs legacy sighash definitions (amount in BIP143 preimage only) |
| evm-eip155-chain-id | eth bsc polygon avax | kat.rs::eip155_example | EIP-155 spec example |
| qrk-5-decimals-legacy | qrk | qrk.rs::qrk_mainnet_txs_are_bitcoin_legacy | chainz.cryptoid.info tx.raw.dws, txid-checked (data/qrk_mainnet.txt) |
| qtum-legacy | qtum | qtum.rs::qtum_mainnet_txs_are_bitcoin_legacy | qtum.info api raw-tx (data/qtum_mainnet.txt) |
| wdc-legacy | wdc | wdc.rs::wdc_mainnet_txs_are_bitcoin_legacy | chainz.cryptoid.info tx.raw.dws (data/wdc_mainnet.txt) |
The registry as data
chain-table prints the CHAINS table above as JSON (one object per chain; --array for a single
array; chain-table btc for one row): name, ticker, SLIP-44 coin_type, curve, encoding with
its version bytes / hrp / SS58 prefix, native_seed, sign (UTXO sighash scheme; account_family
means the chain is signed by its own tool, e.g. acct-tx / xrp-tx), buildable (tx-build signs it),
verified and the parameter source. The wasm build exports the same array as chainTable().
Trust Wallet Core UTXO forks: PIVX, Syscoin, Firo (address + WIF only)
Rows pivx, sys, firo carry each coin's own chainparams prefixes (PIVX 30/13/WIF 212; Syscoin 63/5/WIF 128, bech32 hrp sys; Firo 82/7/WIF 210). Signing is Unknown: build/sign refuse them; no transaction has been tested on any of these chains.
Measured (Linux only): scripts/e2e.d/twc-utxo.sh gives Trust Wallet Core's published addresses (tests/chains, commit adf80f8) for Syscoin p2pkh and p2wpkh and Firo p2pkh from TWC's public test keys; the KAT table covers all three. Untested: PIVX against an outside vector from a private key (TWC only has a pubkey/mnemonic case), Syscoin's other address types.
Exchange and staking addresses (validate and detect only; no output script is built, so tx-build/verify-tx cannot pay them): Firo EXX... (version 01 b9 bb), PIVX EXM... (01 b9 a2) and PIVX cold-staking S... (version 63), from each coin's src/chainparams.cpp. A PIVX S... address is also a valid Syscoin p2pkh (both use version 63), so detect lists both. Measured (Linux only): crates/blocktools/tests/exchange_addr.rs (3 tests) accepts the Firo wiki's published transparent/EXX pair ("Information for Exchanges", same key), rejects a one-character change and Firo testnet EXT, and accepts PIVX EXM/S addresses built from that hash160 by an independent hashlib base58check. Untested: the PIVX addresses against an address PIVX itself published (none found), sending to any of these address types.
Kusama and Polymesh (SS58 prefixes 2 and 12, address only)
Rows ksm (SLIP-44 434) and polyx (595) use the same substrate key as dot (subkey mini-secret, sr25519) and only change the SS58 prefix. Signing is Unknown; no transaction is built or signed. Trust Wallet Core derives these chains with ed25519 SLIP-10 keys (m/44'/434'/0'/0'/0'), so a TWC wallet's Kusama/Polymesh address is not what these rows give from the same phrase; that is the ed25519 port, not done here.
Measured (Linux only): crates/secrets/tests/dot.rs encodes TWC's published Kusama and Polymesh public keys to TWC's addresses (tests/chains/Kusama, Polymesh, commit adf80f8) and validates them; scripts/e2e.d/twc-substrate.sh checks the CLI rows (its expected Kusama address was computed independently in Python from subkey's published key), and that redact drops a Kusama address on a line labeled another chain. Untested: Polkadot.js/Talisman wallets on these prefixes, balances (no RPC row).
Aptos, Sui, NEAR, Tezos, MultiversX (ed25519 SLIP-0010, address only, 2026-10-26)
Rows aptos (SLIP-44 637, m/44'/637'/i'/0'/0', address 0x+sha3-256(pubβ0x00)), sui (784, m/44'/784'/i'/0'/0', 0x+blake2b-256(0x00βpub)) near (397, m/44'/397'/i', implicit account = hex(pub)), xtz (1729, m/44'/1729'/i'/0', tz1 = base58check(06a19fβblake2b-160(pub)); tz2/tz3/KT1 validate) and egld (508, m/44'/508'/0'/0'/i', bech32 erd). The secret is the 32-byte ed25519 seed as hex. Signing is Unknown; no transaction is built or signed. A 64-hex address is shape-ambiguous, so detect lists every chain it fits (0x+64 hex: aptos and sui; bare 64 hex: sui and near).
Measured (Linux only): crates/blocktools/tests/twc_ed25519.rs (5 tests) replays Trust Wallet Core adf80f8 public vectors: CoinAddressDerivationTests.cpp dummy key 0x46Γ32 β TWC's Aptos/Sui/NEAR/Tezos/MultiversX addresses; Tezos and MultiversX AddressTests.cpp key β address and valid/invalid lists; TWHDWalletTests.cpp DeriveTezos public key and DeriveMultiversX key and address at the registry paths; Aptos AddressTests.cpp private/public key β address and its valid/invalid lists; Sui sui_address.rs valid/invalid lists; HDWalletTests.cpp AptosKey and NearKey (public test phrases) β TWC's private keys and NEAR address at the registry paths. Untested: NEAR named accounts (alice.near, refused), Tezos tz2/tz3 key derivation (secp256k1/P-256; validate only), Aptos multi-ed25519 and Sui secp256k1/secp256r1 schemes, any wallet app other than TWC, balances (no RPC row).