Skip to content

add TransactionPrototype type and CST encoder/decoder - #837

Open
lisicky wants to merge 1 commit into
mainfrom
feat/tx-prototype
Open

add TransactionPrototype type and CST encoder/decoder#837
lisicky wants to merge 1 commit into
mainfrom
feat/tx-prototype

Conversation

@lisicky

@lisicky lisicky commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

What

TransactionPrototype — a universal layer representing a raw transaction that is already in a
serialization-friendly state, plus converters between it and CBOR.

This is groundwork for the new tx builder. The intended shape is: the builder does its work
(coin selection, witness collection, fee calculation) and at the end assembles a
TransactionPrototype, which is what it hands to the serializer. The prototype itself holds no
builder logic — every value in it is already decided.

Why it lives in mesh-common

mesh-core-cst and mesh-core-csl are two backends behind one IMeshTxSerializer. Both need
the same shape, so the type cannot live in either of them. The file has no runtime imports, so
this adds no dependency edge.

Contents

  • mesh-common — the types. Typed against the Conway CDDL
    (IntersectMBO/cardano-ledger, eras/conway/impl/cddl/data/conway.cddl), not against any
    backend's own field widths.
  • mesh-core-cst/tx-prototype-to-cbor — prototype → Transaction.
  • mesh-core-cst/tx-prototype-from-cborTransaction → prototype. Exists mainly so the
    encoder can be round-trip tested; decode(encode(x)) === x catches silent field drops that
    per-field assertions miss.
  • mesh-core-csl/tx-prototypeserializeTxPrototype via js_tx_prototype_to_hex.

135 tests. bigint is used (not number | bigint) for every field whose CDDL range exceeds
Number.MAX_SAFE_INTEGER, so a plain numeric literal is a compile error rather than a silent
precision loss.

Two CDDL points

Plutus scripts are split per version. transaction_witness_set keys 3/6/7 and
auxiliary_data_map keys 2/3/4 are separate fields because a script's language version is not
recoverable from its bytes — the map key is what records it. A single version-less list cannot
round-trip a V2/V3 script.

transactionPrototypeToHex takes a taggedSets option. CDDL accepts both #6.258-tagged
sets and plain arrays, but the choice is transaction-wide and changes the tx hash.
@cardano-sdk/core decides it from a module-global read at serialization time (default false,
flipped to true as a side effect of constructing a CardanoSDKSerializer). The option pins
that global for the duration of the call and restores it, so output neither depends on nor leaks
ambient state.

Unrelated fix included

utils/certificate.ts — shared with the v1 MeshTxBuilder — handled
StakeVoteRegistrationAndDelegation by emitting newStakeVoteDelegationCert (CDDL certificate
10) instead of newStakeVoteRegistrationDelegationCert (13). The two produced identical
CBOR and the deposit was dropped, while getTotalDeposit() still charged it: the balance assumed
a deposit the certificate never declared, and the stake credential was never registered.

There is no public builder method that reaches this today, so exposure is low. Not covered by any
test on the v1 path — the new tests exercise it through certificatePrototypeToCardano.

Known limitations

  • prefer_alonzo_format and PlutusListPrototype.definite_encoding are not honoured —
    @cardano-sdk/core exposes no control for either. Documented at their declarations.
  • The decoder does not invert PARAMETER_CHANGE_ACTION; it throws rather than return a
    half-correct protocol-parameter update.
  • transaction_output has two legal encodings (Alonzo array / Babbage map) and the type does not
    express the choice — CST derives it from content. Stable for anything encoded here; only
    byte-exact re-encoding of a third-party transaction is affected.
  • Pre-Conway shapes (update, genesis-key and MIR certificates, PPU d/extra_entropy/
    protocol_version) are absent from the type by design.

A backend-agnostic representation of a fully-resolved Cardano transaction,
typed against the Conway CDDL, plus converters in both directions:

- mesh-common: the TransactionPrototype types
- mesh-core-cst: prototype <-> Transaction (decoder enables round-trip tests)
- mesh-core-csl: serializeTxPrototype via js_tx_prototype_to_hex

Also fixes a pre-existing bug in utils/certificate.ts, shared with the v1
builder: StakeVoteRegistrationAndDelegation emitted CDDL certificate 10
instead of 13, dropping the deposit that getTotalDeposit() still charged.
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