Files
wasm/packages/quantus-codec/Cargo.toml
rob thijssen 09a96b64bf feat: render account ids as SS58 when a prefix is set
A decoded call named its recipient as 32 bytes of hex. That is a correct
description of the value and the one form nobody reads — and the only moment in
a wallet where reading the recipient matters is the screen asking somebody to
approve sending them money.

`set_ss58_format` turns it on. Off by default, and deliberately: the prefix is a
property of the chain a caller is talking to rather than of the metadata, so
inferring one would put a plausible, wrong address in front of that same person.

Account types are found by their **registry path**, not by length. A block hash
is also 32 bytes, and rendering one as an address would be a lie a reader cannot
catch — there is a test that `System::BlockHash` stays hex with a prefix set.
`scale_value` carries each value's type id as its context, so the check is on
what the runtime declared.

The vector is crystal_bob on Heisenberg, taken from the chain rather than
computed here, which also pins the two-byte prefix form — 189 needs it, and
getting it wrong yields an address that looks right and belongs to nobody.

Refs #3, quantus/extension#6

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 15:26:11 +03:00

64 lines
3.0 KiB
TOML

# Metadata-driven SCALE encode/decode for the Quantus chain, compiled to WASM.
#
# A separate crate from `quantus-crypto` for the same reason that one is separate
# from `wasm-crypto`: different dependency graphs, built independently. They ship
# as sibling packages and the extension uses both — this one decides *what bytes*
# get signed, that one signs them.
#
# Why this exists at all rather than `@polkadot/api`: quantus/api#1. In short,
# polkadot-js cannot decode a Quantus block (it reads the extrinsic preamble byte
# as a version when the top two bits are a type tag), it refuses fixed arrays
# longer than 2048 (ML-DSA signatures are 5261 and 7219 bytes), and — the part
# that matters after those are patched — it *guesses* that signed extensions it
# does not recognise contribute nothing to the signed payload. On a chain whose
# encoding has already changed between runtimes, a guess like that produces a
# valid signature over the wrong bytes, which arrives as `BadProof` and looks
# exactly like a wrong key. See quantus/wasm#3.
[package]
authors = ["Quantus Network Developers <hello@quantus.com>"]
description = "Metadata-driven SCALE codec for the Quantus chain, as WASM bindings."
edition = "2021"
license = "Apache-2.0"
name = "quantus_codec"
publish = false
repository = "https://git.lair.cafe/quantus/wasm"
resolver = "2"
version = "0.0.0"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
# Versions match blackbeard.observer's, which is the other consumer decoding this
# chain against its own metadata and the reference implementation for this crate.
frame-metadata = { version = "23", default-features = false, features = ["current", "decode"] }
parity-scale-codec = { version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false }
scale-value = { version = "0.18", default-features = false }
# Only for `IgnoreVisitor`. `scale_value` sizes a sequence's Vec from the length
# prefix *before* decoding an item, so a blob that disagrees with the registry can
# ask for an allocation of any size and abort the process — there is no Err to
# catch. Pinned to the version `scale-value` itself resolves so both see one
# registry. blackbeard.observer took a 76 GiB allocation to find this.
scale-decode = { version = "0.16", default-features = false }
serde_json = "1"
wasm-bindgen = "0.2"
# Storage keys. Substrate hashes a pallet prefix and an item name with twox128
# and each map key with whatever hasher the metadata declares for it.
blake2 = { version = "0.10", default-features = false }
twox-hash = { version = "2", default-features = false, features = ["xxhash64"] }
# SS58. An account id rendered as 32 bytes of hex is a correct description of the
# value and unreadable to the person being asked to approve it.
bs58 = { version = "0.5", default-features = false, features = ["alloc"] }
[profile.release]
codegen-units = 1
debug = false
debug-assertions = false
incremental = false
lto = true
opt-level = "z"
panic = "abort"
rpath = false