Skip to content

URN 1.1: chain identity without coin type, optional wallet domain#1

Merged
x88 merged 1 commit into
masterfrom
feat/urn-1.1-chain-identity
Jul 4, 2026
Merged

URN 1.1: chain identity without coin type, optional wallet domain#1
x88 merged 1 commit into
masterfrom
feat/urn-1.1-chain-identity

Conversation

@x88

@x88 x88 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Version 1.1.0 — a behavioral mirror of the go-mhda 1.1 grammar rework. The URN stays bit-for-bit compatible between both implementations.

What changes

  • Chain identity is (nt, ci). chain::str() / chain::key() emit nt:<network>:ci:<chain_id>; operator== compares the identity only; the constructor is chain(network_type, chain_id). The SLIP-44 coin type becomes optional metadata (std::optional<coin_type> via coin() / set_coin() / clear_coin()), parsed from any position and emitted after ci in decimal — never part of the key.
  • Strict chain::from_key. A chain key must be the canonical identity string. ct in a key (the pre-1.1 format) throws the dedicated error_code::coin_type_in_chain_key; any other residue — known non-identity components, unknown tokens, reordering, non-canonical case — throws error_code::invalid_chain_key. chain::from_nss stays lenient for extraction from full NSS forms.
  • Wallet domain. Optional, independent, free-form wt (client type: web3, metamask, tonconnect, …) and wi (wallet instance id: UUID, HD root fingerprint, …), emitted last in the canonical order, orthogonal to validation.
  • Network value renames to the accepted lowercase names (bitcoin, tron, avalanche, solana, xrpl, stellar, aptos, cardano, algorand); evm, cosmos, near, sui, ton unchanged; no aliases.
  • Coin registry: atom fixed to 118 per SLIP-44 (168 is Helleniccoin), 34 modern entries added, list reordered ascending.
  • Parser hardening (in lockstep with the reference): printable-ASCII value enforcement with ASCII-only trimming; strict ct numeric grammar (decimal / 0x hex only); validated free-form setters and constructor params — a value able to smuggle :, ?, # or whitespace into the NSS throws the new error_code::invalid_value.

Versioning note: the previous release shipped as tag v1.0.0 while its in-tree markers still read 0.1.0; this release restores consistency (CMake project version, changelog and README all say 1.1.0).

Testing

  • 139 test cases, 100% green in a fresh build under -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wsign-conversion -Werror, and again under -fsanitize=address,undefined,leak with halt_on_error=1 — zero diagnostics.
  • New suites mirror the Go reference: wallet domain, strict chain keys, and the hardening pack (duplicates, canonical-only keys, setter injection attempts, ct spellings, non-ASCII rejection, case preservation, registry spot checks).
  • Differential parity against the Go reference: identical accept/reject decisions and byte-identical canonical output across a hand-crafted tricky corpus, ~50k random mutations and a targeted ct-value fuzz; the hash reference vectors were recomputed for the new canonical strings.
  • SPEC.md is normatively identical to the Go one (the C++ preface and naming notes aside).

… domain

The chain identity is now the (nt, ci) pair, mirroring the go-mhda
reference: chain::str()/key() serialize nt:<network>:ci:<chain_id> only,
equality compares network and chain id, and the constructor drops the
coin-type argument. The SLIP-44 coin type becomes optional metadata on
chain (coin() -> std::optional, set_coin/clear_coin); the ct component is
accepted anywhere on input, re-emitted in decimal right after ci, and an
empty set_coin_type clears it.

chain::from_key is canonical-only: the accepted input must be the exact
nt:<network>:ci:<chain_id> rendering, with surrounding ASCII whitespace
trimmed and tolerated. A key carrying ct (the pre-1.1 key format) fails
with the new error_code::coin_type_in_chain_key so legacy keys fail
loudly instead of being silently reinterpreted; any other known
component, unknown tokens, reordering or non-canonical spelling fails
with the new error_code::invalid_chain_key. error_code::missing_coin_type
is removed; ct is never required. chain::from_nss stays lenient.

Harden parsing and mutation against malformed values:
- ct parses as plain decimal or 0x/0X-prefixed hex only; 0o/0b prefixes,
  digit-group underscores, signs and a bare 0x are rejected, and a
  leading zero stays decimal (060 == 60, never octal).
- Every NSS value must be printable ASCII (0x21-0x7E) after ASCII-only
  trimming; control bytes, interior whitespace and non-ASCII bytes
  (including Unicode spaces) are rejected instead of silently normalised.
- The free-form setters (set_address_prefix/suffix, set_wallet_type/id)
  and the address constructor params reject NSS-corrupting values (':',
  '?', '#', anything outside printable ASCII) with the new
  error_code::invalid_value; an empty value still resets the field.

New optional wallet domain on address: free-form wt (wallet type) and wi
(wallet instance id) components, each independently optional, emitted
last in the canonical NSS and orthogonal to strict validation.

Network-type values are renamed to the commonly accepted network names
(bitcoin, avalanche, tron, solana, xrpl, stellar, aptos, cardano,
algorand) with no aliases for the old short forms; constant identifiers
are unchanged. The coin registry fixes ATOM to 118 (168 belongs to
Helleniccoin), adds 34 SLIP-44 entries and is reordered ascending.

Version 1.1.0. SPEC.md and README are brought in lockstep with the Go
reference; tests mirror the Go fixtures (wallet-domain suite, strict
chain-key suite, optional-ct semantics, post-review hardening suite,
recomputed hash vectors) — 139 cases, green under ASan/UBSan/LSan and
the full warning set, with byte-for-byte parity against the Go
implementation on the shared corpus.
@x88
x88 force-pushed the feat/urn-1.1-chain-identity branch from 898725d to 3d0219b Compare July 4, 2026 10:01
@x88
x88 merged commit 75a15da into master Jul 4, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant