fix: facade TaggedArg encoding, native byte arrays, remove broken Ed25519Signer.fromMnemonic - #38
Conversation
A `Uint8Array` (or an integer array — the JSON shape other SDKs' native byte arrays serialize to) previously fell through to the envelope passthrough or was rejected, reaching the resolver raw. Canonicalize byte arrays to 0x-prefixed hex, per SDK spec §3.9 value marshalling. Covers the Hydra `init` participants/parties/head_id and Asteria create_ship pilot/ship-name shapes with regression tests (TRP `(-32005) value is not bytes`). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The type-directed encoder introduced in #36 only ran on the dynamic Invocation path: `TxBuilder.resolve` sent merged args raw, so both `Tx3Client` users and codegen-generated bindings hit resolver errors for aggregate params (`(-32005) target type not supported: List` / `value is not bytes`). - `TxBuilder` carries a `ParamMap`; `resolve()` marshals every matching arg (case-insensitive) via `encode`, pass-through for unmapped args. - `Tx3ClientBuilder` threads per-tx param maps: populated automatically from a loaded `Protocol` (new `Protocol.txParams`), or supplied by generated bindings through the new `withTxParams` setter. `Tx3ClientBuilder.fromParts` is unchanged, so existing generated clients keep compiling (their args pass through unencoded as before). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The constructor took `mnemonicToSeedSync(phrase).slice(0, 32)` as a raw ed25519 key — no CIP-1852 derivation — so its witness vkey could never hash to the payment credential of the caller-supplied Cardano address: the witness was internally valid but never satisfied the tx's required signer. A raw-key signer cannot be fixed to match: an address derived per CIP-1852 binds to a BIP32-Ed25519 extended key whose scalar plain RFC 8032 signing cannot accept. Mnemonic-based signing belongs to `CardanoSigner.fromMnemonic`, which derives m/1852'/1815'/0'/0/0 and verifies the key↔address binding at construction. The class itself stays: `Ed25519Signer.fromHex`/`new` serve genuine raw ed25519 keypairs, per SDK spec §3.5 (which requires only raw-key construction for this signer). Adds CardanoSigner tests pinning the two properties the witness needs: vkey hashes to the address payment credential, and the signature verifies under that vkey; plus rejection of a mismatched address. BREAKING CHANGE: `Ed25519Signer.fromMnemonic` is removed; use `CardanoSigner.fromMnemonic(address, phrase)` instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The generated client now embeds each transaction's params JSON schema plus the protocol's `components.schemas` table and hands them to the new `Tx3ClientBuilder.withTxParams`, so generated bindings marshal typed args into the TaggedArg wire form on resolve. Bump the standalone package's tx3-sdk floor to the release that carries the new API. Note: CI's codegen-check type-checks the rendered module against tx3-sdk@latest from npm, so it fails until the release carrying `withTxParams`/`paramsFromSchema` re-exports publishes; verified locally against the built SDK instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merging with The Order: merge → publish 0.15.0 → Note for the changelog: this carries a breaking removal — Green on this head: |
Plan
Tx3 Trellis domain plan
plans/feedback-cba-04-sdks-imports-utxoref-signer-encoding.md(domain root not yet on a forge; plan ref by path). Executed byorg/coderunder plan dispatch.Done criterion (web-sdk share):
initaggregate args now encode into theTaggedArgwire form on the facade path (previously raw →(-32005) target type not supported: List/value is not bytes) — met, pinned by unit tests.Ed25519Signer.fromMnemonicresolved per the plan's decision rule — removed (see below), snippets/e2e already useCardanoSigner.Draft because: CI's
codegen-checktype-checks the rendered.trixtemplate againsttx3-sdk@latestfrom npm; the template now calls the newwithTxParams/paramsFromSchemaAPI, so that check stays red until the release carrying this PR publishes (verified locally against the built SDK instead — see Verification). Everything else is green. Ordering: merge → release → codegen-check green → re-pointcodegen-v1beta0.What changed
fix(tii)— the bytes encoder canonicalizes native byte arrays (Uint8Array, or integer arrays — the JSON shape other SDKs' native byte arrays serialize to) to0x-prefixed hex, per SDK spec §3.9. Previously aUint8Arrayfell through to the envelope passthrough and serialized as{"0":1,...}. Regression tests cover the Hydrainitand Asteria name shapes.fix(facade)— the type-directed encoder shipped in feat(tii): type-directed argument encoding to the TaggedArg wire form #36 ran only on the dynamicInvocationpath; the facadeTxBuilder.resolve()(used byTx3Clientand every codegen-generated binding) sent args raw.TxBuildernow carries aParamMap;Tx3ClientBuilderthreads per-tx params — automatic from a loadedProtocol(newProtocol.txParams), explicit for codegen via newwithTxParams.fromPartsunchanged: existing generated clients keep compiling and behave as before.fix(signer)!— removedEd25519Signer.fromMnemonic. Plan decision rule applied: this is not a fixable derivation bug. The constructor usedmnemonicToSeedSync(phrase).slice(0, 32)as a raw ed25519 key — no CIP-1852 derivation — so its witness vkey can never hash to the payment credential of the caller-supplied Cardano address: the signature was internally valid but never satisfied the tx's required signer (the reported "witness that does not sign"). It cannot be fixed inside a raw-key signer: a CIP-1852 address binds to a BIP32-Ed25519 extended key whose scalar plain RFC 8032 signing cannot accept. The class stays — it is not redundant withCardanoSigner: spec §3.5 requires it as the generic raw-key signer, andfromHex/newserve genuine raw ed25519 keypairs. Mnemonic construction belongs toCardanoSigner.fromMnemonic, which derivesm/1852'/1815'/0'/0/0and verifies the key↔address binding at construction. Newcardano.test.tspins both witness properties (vkey↔address, signature↔vkey) plus mismatch rejection. README and e2e already used the correct constructors; no snippet changes needed. BREAKING CHANGE footer carried on the commit.fix(codegen)—.trix/client-lib/protocol.ts.hbsembeds per-tx params schemas +components.schemasand wires them throughwithTxParams; standalonepackage.jsonfloor bumped to^0.15.0.Verification
npm run test:unit: 163 passed (150 baseline + 13 new), 10 suites.npm run type-check(tsc --noEmit) andnpm run build(tsup): clean.tx3c codegenrendered the template against the transfer fixture; the module type-checks (tsc --noEmit --strict --exactOptionalPropertyTypes --module nodenext) in a fresh consumer project against this branch's built SDK.npm run lintfails repo-wide (ESLint 9 installed, no flateslint.config.js); lint is not in CI.Escalations / follow-ups
codegen-v1beta0tag sotrixusers get the new template.Ed25519Signermnemonic constructors are filed as a follow-up plan in the domain root.🤖 Generated with Claude Code