go-mhda v1.1.0
URN grammar 1.1: the chain identity drops the coin type, and the URN gains an
optional wallet domain. This is a format-changing release — strings produced
by 1.0.0 do not round-trip unchanged (see Migration below).
Breaking changes
- Chain identity is the
(nt, ci)pair.Chain.String()/Chain.Key()
now returnnt:<network>:ci:<chain_id>. The chain key remains a strict
prefix of every canonical NSS.NewChaintakes two arguments:
NewChain(networkType, chainId). ctis no longer required — or part of the identity. The SLIP-44 coin
type is optional metadata: parsed from any position, emitted afterciin
decimal, never included inKey()/String(). For HD addresses the coin
already lives in the derivation path; the standalone component exists as an
annotation for consumers that need the registry value without parsing a
path. New accessors:Chain.CoinType(),Chain.HasCoinType(),
Chain.SetCoinType(),Chain.ClearCoinType().ErrMissingCoinTypeis
gone.ChainFromKeyis strict. A chain key must be the canonical identity
string, byte for byte. A key carryingct(the pre-1.1 format) fails with
the dedicatedErrCoinTypeInChainKey; any other residue — non-identity
components, unknown tokens, reordering, non-canonical case — fails with
ErrInvalidChainKey.ChainFromNSSstays lenient for extracting the chain
from a full address NSS.- Network type values renamed to the commonly accepted network names,
lowercase:bitcoin,tron,avalanche,solana,xrpl,stellar,
aptos,cardano,algorand. Unchanged:evm,cosmos,near,sui,
ton. There are no aliases — the old short names are rejected. ParseURNRxremoved. The regex variant silently truncated
case-preserving values, applied last-wins to duplicate components and
dropped components past its match cap — behaviours the canonical parser
rejects loudly. One grammar, one parser.NewAddressvalidates its optional params. They ride the same setters
as parsed input and panic on an invalid value (matching the
NewDerivationPathprecedent). The parse entry points never panic.ATOMis 118. The previous constant (168) belongs to Helleniccoin in
the SLIP-44 registry; 118 also matches the coin level of CIP-11 paths.
New
- Wallet domain. Two optional, independent, free-form components bind an
address to a wallet context:wt— the client or protocol the address is
exposed through (web3,metamask,tonconnect, …), andwi— a wallet
instance identifier (a UUID, an HD root key fingerprint, …). They are
emitted last in the canonical order
nt:ci[:ct][:dt][:dp][:aa][:af][:ap][:as][:wt][:wi], participate in the
serialised NSS and its hashes when set, and are orthogonal to validation.
AccessorsWalletType()/WalletId()are part of theMHDAinterface. - Coin type registry extended with 34 modern SLIP-44 registrations (DOT,
KSM, FIL, EGLD, FLOW, HBAR, ICP, XTZ, KAS, MINA, CSPR, STRK, SEI, INJ,
OSMO, RUNE, XCH, CKB, STX, ZIL, VET, EOS, LUNA, BCH, ETC, BERA, HYPE,
MOVE, MON and others), all verified against the registry.
Parser hardening
- NSS values are enforced to printable ASCII (0x21–0x7E): control bytes,
whitespace of any kind and non-ASCII bytes are rejected. Trimming is
ASCII-only — a Unicode space is malformed input, never decoration to strip. - Free-form values (
ci,ap,as,wt,wi) are case-preserving and
round-trip verbatim; enum values normalise to lowercase. - The free-form setters reject values that would corrupt the serialised NSS:
:(component injection on re-parse),?/#(RFC 8141 truncation),
whitespace and non-ASCII. New sentinel:ErrInvalidValue. ctaccepts its two documented spellings only — plain decimal and
0x-prefixed hex. Legacy octal,0o/0bprefixes and digit-group
underscores are rejected.
Migration
- Regenerate persisted chain keys and URNs; there is no compatibility layer
by design. Old keys fail loudly inChainFromKey(ErrCoinTypeInChainKey),
and the renamed network values make pre-1.1 strings with short names fail
at the network check. - Full address NSS forms that carry
ctstill parse (it is valid optional
metadata) and re-serialise withctin the canonical position afterci.
Testing
go test, go vet, gofmt clean. The golden corpus was rewritten for the
1.1 grammar and extended with wallet-domain, strict chain-key and hardening
suites; the fuzzers run clean with refreshed seeds. SPEC.md is updated in
lockstep. The C++ port (censync/mhda 1.1.0) mirrors this release bit for bit,
verified by a differential harness over ~50k inputs.