Skip to content

#115 Migrate minting from caller-supplied token ids to networkId + salt#119

Merged
b3y0urs3lf merged 13 commits into
mainfrom
issue-115
Jun 4, 2026
Merged

#115 Migrate minting from caller-supplied token ids to networkId + salt#119
b3y0urs3lf merged 13 commits into
mainfrom
issue-115

Conversation

@martti007

Copy link
Copy Markdown
Collaborator

No description provided.

@martti007 martti007 requested review from MastaP and removed request for MastaP May 22, 2026 11:44
@martti007 martti007 changed the title #115 Migrate minting from caller-supplied token ids to networkId + salt DRAFT: #115 Migrate minting from caller-supplied token ids to networkId + salt May 22, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces comprehensive JSDoc documentation across the codebase and refactors token identification. A new NetworkId type and TokenSalt class are introduced, and TokenId is now derived from these values rather than being generated independently. The MintTransaction and TokenSplit logic have been updated to support this derivation. Feedback includes a request to add getLatestBlockNumber to the IAggregatorClient interface for consistency, a suggestion to check for duplicate salts in token splits to prevent ID collisions, and a recommendation to increment the MintTransaction version due to changes in its CBOR serialization format.

Comment thread src/api/AggregatorClient.ts
Comment thread src/payment/TokenSplit.ts Outdated
Comment thread src/transaction/MintTransaction.ts
@martti007 martti007 changed the title DRAFT: #115 Migrate minting from caller-supplied token ids to networkId + salt #115 Migrate minting from caller-supplied token ids to networkId + salt May 22, 2026
@martti007 martti007 requested a review from MastaP May 22, 2026 13:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates token minting away from caller-supplied TokenIds to a deterministic TokenId = H(networkId, salt) scheme, introducing NetworkId and TokenSalt and plumbing them through minting, splitting, certification, and verification flows.

Changes:

  • Update MintTransaction to carry networkId + salt and derive tokenId from them; introduce NetworkId and TokenSalt.
  • Refactor token splitting API to accept SplitTokenRequest inputs and output SplitToken objects (instead of caller-provided token IDs), adding duplicate-derived-id detection.
  • Update verification rules, tests/examples, and documentation to reflect the new network-scoped minting flow and improve JSDoc across the SDK.

Reviewed changes

Copilot reviewed 138 out of 139 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/utils/UnicityCertificateFixture.ts Update unicity seal creation to use NetworkId.
tests/utils/TokenUtils.ts Adapt mint helper to new mint API (networkId + salt).
tests/utils/RootTrustBaseFixture.ts Use NetworkId when building root trust base JSON.
tests/unit/api/StateIdTest.ts Update mint construction and expected vectors for new ID derivation.
tests/unit/api/InclusionProofTest.ts Update mint construction to new mint API.
tests/unit/api/CertificationDataTest.ts Update mint construction and expected vectors for new ID derivation.
tests/functional/payment/SplitBuilderTest.ts Refactor split flow tests to SplitTokenRequest/SplitToken.
tests/examples/transfer/ExampleTest.ts Update mint example to include NetworkId.
tests/examples/split/ExampleTest.ts Update split example to SplitTokenRequest/SplitToken and NetworkId.
tests/examples/mint/ExampleTest.ts Update mint example to include NetworkId.
tests/e2e/ShardAggregatorClient.ts Rename/getter reshuffle around latest block height method naming.
src/verification/VerificationResult.ts Improve documentation for verification result formatting/tracing.
src/verification/VerificationError.ts Remove redundant constructor doc block.
src/verification/IVerificationContext.ts Add marker-interface documentation.
src/util/TypedArrayUtils.ts Add API documentation for typed-array equality/compare helpers.
src/util/InclusionProofUtils.ts Add documentation around polling/sleep error behavior.
src/util/HexConverter.ts Document 0x-prefix handling and output formatting.
src/util/BitString.ts Add detailed docs for bit/byte order helpers.
src/util/BigintConverter.ts Add big-endian conversion documentation.
src/unicity-id/UnicityIdToken.ts Add docs for unicity-id token wrapper API.
src/unicity-id/UnicityIdMintTransaction.ts Add docs for unicity-id mint transaction API.
src/unicity-id/UnicityId.ts Add docs for unicity-id encoding and token-id derivation.
src/unicity-id/CertifiedUnicityIdMintTransaction.ts Add docs for certified unicity-id transaction wrapper.
src/transaction/verification/rule/ShardIdMatchesStateIdRule.ts Add docs describing shard/state-id prefix verification.
src/transaction/verification/rule/InclusionProofVerificationRule.ts Add docs for inclusion proof verification entrypoint.
src/transaction/verification/rule/CertifiedUnicityIdMintTransactionVerificationRule.ts Improve docs for certified unicity-id verification rule.
src/transaction/verification/rule/CertifiedTransferTransactionVerificationRule.ts Add docs for certified transfer verification rule.
src/transaction/verification/rule/CertifiedMintTransactionVerificationRule.ts Enforce mint-network == trust-base network during verification.
src/transaction/verification/MintJustificationVerifierService.ts Add docs for justification verifier registry/dispatch.
src/transaction/verification/IMintJustificationVerifier.ts Add docs for mint justification verifier interface.
src/transaction/TransferTransaction.ts Add docs and clarify getters/serialization behaviors.
src/transaction/TokenType.ts Add docs and clarify serialization/string forms.
src/transaction/TokenSalt.ts Introduce TokenSalt (32-byte) value object.
src/transaction/TokenId.ts Replace random generation with fromSalt(networkId, salt) derivation.
src/transaction/Token.ts Add docs; no functional changes beyond updated types.
src/transaction/MintTransactionState.ts Fix/standardize return-type docs.
src/transaction/MintTransaction.ts Add networkId + salt to CBOR and derive token id from them.
src/transaction/ITransaction.ts Expand interface docs for hashing/CBOR methods.
src/transaction/CertifiedTransferTransaction.ts Add docs for certified transfer wrapper.
src/transaction/CertifiedMintTransaction.ts Expose networkId/salt on certified mint wrapper; add docs.
src/StateTransitionClient.ts Improve facade documentation.
src/smt/sum/SparseMerkleSumTreePathStep.ts Add JSON/CBOR/docs for sum-tree path steps.
src/smt/sum/SparseMerkleSumTreePath.ts Add JSON/CBOR/docs for sum-tree paths.
src/smt/sum/PendingNodeBranch.ts Document sum-tree pending node finalization.
src/smt/sum/PendingLeafBranch.ts Document sum-tree pending leaf finalization.
src/smt/sum/FinalizedNodeBranch.ts Document sum-tree finalized node behavior.
src/smt/sum/FinalizedLeafBranch.ts Document sum-tree finalized leaf behavior.
src/smt/radix/SparseMerkleTreeRootNode.ts Add docs for has method.
src/smt/radix/SparseMerkleTree.ts Add docs for leaf insertion API.
src/smt/radix/PendingNodeBranch.ts Add docs for radix pending node branch.
src/smt/radix/PendingLeafBranch.ts Add docs for radix pending leaf branch.
src/smt/radix/FinalizedNodeBranch.ts Add docs for radix finalized node branch.
src/smt/radix/FinalizedLeafBranch.ts Add docs for radix finalized leaf branch.
src/smt/plain/SparseMerkleTreePathStep.ts Add docs for plain SMT path steps.
src/smt/plain/SparseMerkleTreePath.ts Add docs for plain SMT paths.
src/smt/plain/PendingNodeBranch.ts Add docs for plain SMT pending node branch.
src/smt/plain/PendingLeafBranch.ts Add docs for plain SMT pending leaf branch.
src/smt/plain/FinalizedNodeBranch.ts Add docs for plain SMT finalized node branch.
src/smt/plain/FinalizedLeafBranch.ts Add docs for plain SMT finalized leaf branch.
src/smt/PathVerificationResult.ts Add docs for path verification result.
src/smt/LeafOutOfBoundsError.ts Add docs for SMT leaf out-of-bounds error.
src/smt/LeafInBranchError.ts Add docs for SMT leaf-in-branch error.
src/serialization/cbor/MajorType.ts Document CBOR major type constants.
src/serialization/cbor/ICborSerializable.ts Document CBOR-serializable marker interface.
src/serialization/cbor/CborSerializer.ts Add extensive docs for canonical CBOR encoding helpers.
src/serialization/cbor/CborReader.ts Add docs; tighten typing around major-type parsing.
src/serialization/cbor/CborMapEntry.ts Document canonical CBOR map entry storage semantics.
src/serialization/cbor/CborMap.ts Document canonical CBOR map ordering/uniqueness behavior.
src/serialization/cbor/CborError.ts Add docs for CBOR error type.
src/serialization/cbor/CborDeserializer.ts Add docs for canonical CBOR decoding helpers.
src/predicate/verification/PredicateVerifierService.ts Document verifier registry and dispatch semantics.
src/predicate/verification/IPredicateVerifier.ts Document predicate verifier interface.
src/predicate/PredicateEngine.ts Document predicate engine enumeration.
src/predicate/IUnlockScript.ts Document unlock script interface.
src/predicate/IPredicate.ts Document predicate interface encoding expectations.
src/predicate/EncodedPredicate.ts Document encoded predicate wire form and equality.
src/predicate/builtin/verification/UnicityIdPredicateVerifier.ts Document unicity-id predicate verification behavior.
src/predicate/builtin/verification/SignaturePredicateVerifier.ts Document signature predicate verification behavior.
src/predicate/builtin/verification/IBuiltInPredicateVerifier.ts Document built-in predicate verifier interface.
src/predicate/builtin/UnicityIdPredicateUnlockScript.ts Document unicity-id unlock script structure and creation.
src/predicate/builtin/UnicityIdPredicate.ts Document unicity-id predicate encoding/decoding.
src/predicate/builtin/SignaturePredicateUnlockScript.ts Document signature unlock script encoding/creation.
src/predicate/builtin/SignaturePredicate.ts Document signature predicate creation/decoding.
src/predicate/builtin/IBuiltInPredicate.ts Document built-in predicate marker interface.
src/predicate/builtin/DefaultBuiltInPredicateVerifier.ts Document built-in verifier registry.
src/predicate/builtin/BurnPredicate.ts Document burn predicate semantics.
src/predicate/builtin/BuiltInPredicateType.ts Document built-in predicate type ids.
src/payment/TokenSplit.ts Refactor split API to requests/outputs; derive token IDs via salt+network.
src/payment/SplitTokenRequest.ts Introduce split-output request type with salt/type defaults.
src/payment/SplitToken.ts Introduce realized split output (network/recipient/type/salt/assets/proofs).
src/payment/SplitMintJustificationVerifier.ts Add network-id consistency check for split mints.
src/payment/SplitMintJustification.ts Document split mint justification and validate non-empty proofs.
src/payment/SplitAssetProof.ts Add docs for per-asset split inclusion proof.
src/payment/IPaymentData.ts Document payment payload interface.
src/payment/error/TokenAssetValueMismatchError.ts Add docs for value mismatch error.
src/payment/error/TokenAssetMissingError.ts Add docs for missing asset error.
src/payment/error/TokenAssetCountMismatchError.ts Add docs for asset count mismatch error.
src/payment/error/DuplicateSplitTokenIdError.ts Add explicit error for derived token-id collisions in splits.
src/payment/asset/PaymentAssetCollection.ts Add docs and clarify behaviors (lookup/size/toArray/toCBOR).
src/payment/asset/AssetId.ts Add docs and clarify serialization/string behavior.
src/payment/asset/Asset.ts Add docs for asset encoding/decoding.
src/InvalidJsonStructureError.ts Add docs for JSON shape mismatch error.
src/crypto/secp256k1/SigningService.ts Expand docs and clarify sign/verify semantics.
src/crypto/secp256k1/Signature.ts Add docs and clarify CBOR/JSON/encode/decode.
src/crypto/MintSigningService.ts Clarify deterministic mint key derivation docs.
src/crypto/ISigningService.ts Document signing service interface and type parameter.
src/crypto/ISignature.ts Replace inline comment with proper interface docs.
src/crypto/hash/UnsupportedHashAlgorithmError.ts Add docs for unsupported algorithm error.
src/crypto/hash/SubtleCryptoDataHasher.ts Clean up docs; mark methods as @inheritDoc.
src/crypto/hash/NodeDataHasher.ts Document Node-backed hasher and @inheritDoc methods.
src/crypto/hash/IDataHasherFactory.ts Document hasher factory interface.
src/crypto/hash/IDataHasher.ts Document streaming hasher interface.
src/crypto/hash/HashAlgorithm.ts Document algorithm registry and lookup.
src/crypto/hash/DataHasherFactory.ts Document generic hasher factory.
src/crypto/hash/DataHasher.ts Document noble-backed hasher; @inheritDoc methods.
src/crypto/hash/DataHash.ts Document imprint semantics and add docs for methods.
src/api/StateId.ts Improve docs for state-id derivation/encoding.
src/api/NetworkId.ts Introduce typed network identifier with validation and registry.
src/api/InclusionProofResponse.ts Add docs for CBOR serialization.
src/api/InclusionProof.ts Add docs for version getter.
src/api/InclusionCertificate.ts Add docs for create/decode/verify APIs.
src/api/IAggregatorClient.ts Update docs to reflect state-id based inclusion proof querying.
src/api/CertificationResponse.ts Remove STATE_ID_EXISTS and add response JSON shape docs.
src/api/CertificationRequest.ts Add docs for version getter.
src/api/CertificationData.ts Add docs for version and constructors.
src/api/bft/verification/UnicityCertificateVerification.ts Add trust-base vs seal network-id check; improve docs.
src/api/bft/verification/rule/UnicitySealQuorumSignaturesVerificationRule.ts Add docs for quorum signature verification rule.
src/api/bft/verification/rule/UnicitySealHashMatchesWithRootHashRule.ts Add docs for seal/root-hash verification rule.
src/api/bft/UnicityTreeCertificate.ts Add docs for version getter.
src/api/bft/UnicitySeal.ts Change seal networkId type to NetworkId and update CBOR encode/decode.
src/api/bft/UnicityCertificate.ts Add docs for getters and JSON decoding.
src/api/bft/ShardTreeCertificate.ts Add docs for version getter.
src/api/bft/ShardId.ts Add extensive docs for shard-id encoding/prefix checks.
src/api/bft/RootTrustBase.ts Change networkId type to NetworkId and update JSON parsing/toString.
src/api/bft/InputRecord.ts Add docs for version getter.
src/api/AggregatorClient.ts Add getLatestBlockNumber and move inclusion proof method; improve docs.
README.md Update quick-start and testing guidance for examples/e2e and network ids.
package.json Bump dependencies/devDependencies and add test:examples script usage.
Comments suppressed due to low confidence (1)

src/transaction/MintTransaction.ts:30

  • MintTransaction and UnicityIdMintTransaction both declare CBOR_TAG = 39041n, which makes their CBOR encodings ambiguous and allows decoding the wrong transaction type without any tag mismatch. Please assign distinct CBOR tags for distinct transaction types (and update the corresponding toCBOR/fromCBOR implementations and any dependent code/tests).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 29 to 134
private static readonly VERSION = 1n;

private constructor(
public readonly sourceStateHash: MintTransactionState,
public readonly lockScript: EncodedPredicate,
public readonly networkId: NetworkId,
public readonly recipient: EncodedPredicate,
public readonly tokenId: TokenId,
public readonly salt: TokenSalt,
public readonly tokenType: TokenType,
public readonly tokenId: TokenId,
private readonly _justification: Uint8Array | null,
private readonly _data: Uint8Array | null,
) {}

/**
* @returns {Uint8Array|null} Copy of the data payload, or `null` if absent.
*/
public get data(): Uint8Array | null {
return this._data ? new Uint8Array(this._data) : null;
}

/**
* @returns {Uint8Array|null} Copy of the mint justification bytes, or `null` if absent.
*/
public get justification(): Uint8Array | null {
return this._justification ? new Uint8Array(this._justification) : null;
}

/**
* @returns {Uint8Array} State mask used when computing the resulting state hash.
*/
public get stateMask(): Uint8Array {
return new Uint8Array(this.tokenId.bytes);
}

/**
* @returns {bigint} Wire-format version of this transaction.
*/
public get version(): bigint {
return MintTransaction.VERSION;
}

/**
* Create a MintTransaction for a fresh token.
*
* @param {NetworkId} networkId Network identifier.
* @param {IPredicate} recipient Predicate that will lock the minted state.
* @param {Uint8Array|null} data Optional data payload.
* @param {TokenType} tokenType Token type being minted.
* @param {TokenSalt} salt Mint-transaction salt; defaults to a random 32-byte salt.
* @param {Uint8Array|null} justification Optional mint justification bytes.
* @returns {Promise<MintTransaction>} New mint transaction.
*/
public static async create(
networkId: NetworkId,
recipient: IPredicate,
tokenId: TokenId,
tokenType: TokenType,
justification: Uint8Array | null = null,
data: Uint8Array | null = null,
tokenType: TokenType = TokenType.generate(),
salt: TokenSalt = TokenSalt.generate(),
justification: Uint8Array | null = null,
): Promise<MintTransaction> {
justification = justification ? new Uint8Array(justification) : null;
data = data ? new Uint8Array(data) : null;

const tokenId = await TokenId.fromSalt(networkId, salt);
const signingService = await MintSigningService.create(tokenId);
return new MintTransaction(
await MintTransactionState.create(tokenId),
EncodedPredicate.fromPredicate(SignaturePredicate.fromSigningService(signingService)),
networkId,
EncodedPredicate.fromPredicate(recipient),
tokenId,
salt,
tokenType,
tokenId,
justification,
data,
);
}

/**
* Create MintTransaction from CBOR bytes.
*
* @param {Uint8Array} bytes CBOR bytes.
* @returns {Promise<MintTransaction>} Decoded transaction.
* @throws {CborError} On wrong tag or unsupported version.
*/
public static fromCBOR(bytes: Uint8Array): Promise<MintTransaction> {
const tag = CborDeserializer.decodeTag(bytes);
if (tag.tag !== MintTransaction.CBOR_TAG) {
throw new CborError(`Invalid CBOR tag for MintTransaction: ${tag.tag}`);
}

const data = CborDeserializer.decodeArray(tag.data, 6);
const data = CborDeserializer.decodeArray(tag.data, 7);
const version = CborDeserializer.decodeUnsignedInteger(data[0]);
if (version !== MintTransaction.VERSION) {
throw new CborError(`Unsupported MintTransaction version: ${version}`);
}

return MintTransaction.create(
EncodedPredicate.fromCBOR(data[1]),
TokenId.fromCBOR(data[2]),
TokenType.fromCBOR(data[3]),
CborDeserializer.decodeNullable(data[4], CborDeserializer.decodeByteString),
NetworkId.fromId(CborDeserializer.decodeUnsignedInteger(data[1])),
EncodedPredicate.fromCBOR(data[2]),
CborDeserializer.decodeNullable(data[6], CborDeserializer.decodeByteString),
TokenType.fromCBOR(data[4]),
TokenSalt.fromCBOR(data[3]),
CborDeserializer.decodeNullable(data[5], CborDeserializer.decodeByteString),
);
Comment thread src/unicity-id/UnicityIdMintTransaction.ts
Comment thread src/api/NetworkId.ts Outdated
@martti007 martti007 requested a review from MastaP May 28, 2026 11:50
MastaP
MastaP previously approved these changes May 28, 2026
@b3y0urs3lf b3y0urs3lf merged commit a57c080 into main Jun 4, 2026
1 check passed
@b3y0urs3lf b3y0urs3lf deleted the issue-115 branch June 4, 2026 09:40
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
…nt, …) + SplitTokenRequest API

PR #119 (sdk-js#115 + sdk-js#116) replaces the caller-supplied tokenId with
networkId+salt derivation, reorders MintTransaction.create(), removes STATE_ID_EXISTS
from CertificationStatus, and replaces the [TokenId, PaymentAssetCollection][] split
input with SplitTokenRequest[]. This ports the BDD test infrastructure to the new APIs:

- TestSetup mintTokenToRecipient / mintTokenWithAssets / runMixedChain: now pass
  setup.trustBase.networkId + recipient; defaults for salt/tokenType.
- TestSetup splitToken / splitTokenToOwner / attemptUnauthorizedSplit: build a
  SplitTokenRequest[] internally; the mint loop reads networkId/recipient/tokenType/
  salt/assets/proofs from each SplitToken in splitResult.tokens.
- Step files (addressing, canonical-certification-request, cbor-envelope,
  certification-request-determinism, certification-status, id-boundaries,
  mint-transaction-fields, minting, mixed-addressing, split-boundaries,
  split-combinations, split-edge-cases, split, transaction-data): updated to the new
  signature; TokenSalt/NetworkId imports added where needed.
- transfer-edge-cases + tree-owner-actions: the tolerant-re-spend branch that checked
  for STATE_ID_EXISTS is removed (the enum value no longer exists in PR #119); the
  proof-time TRANSACTION_HASH_MISMATCH path is now the only enforcement layer.
- ShardLoadRunner / ShardLoadTypes: tokenIdBytes → saltBytes (the seed now feeds
  TokenSalt.fromBytes rather than the removed TokenId constructor).
- AggregatorClientTest: NetworkId.LOCAL + default salt/tokenType.
- World.ts: mintTokenSalt added (certification-status uses it to reproduce the same
  derived tokenId across two mints with different tokenTypes).
- src/api/InclusionCertificate.ts: minor prettier-only formatting from lint:fix.

build:check ✔, lint ✔.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
…tion

PR #119 made the aggregator surface re-spend rejections as a JSON-RPC error rather
than a {status: ...} CertificationResponse, so submitCertificationRequest now throws
('Invalid JSON structure' from CertificationResponse.fromJSON) instead of returning
SUCCESS. The tolerant double-spend assertion was only handling SUCCESS+proof-time
TRANSACTION_HASH_MISMATCH; extend it to also accept submit-side rejection.

Affected:
- tree-owner-actions.steps.ts (the 8 token-4level Outline rows) — catch in the
  duplicate-transfer When step; the Then accepts a null status as 'rejected at submit'.
- transfer-edge-cases.steps.ts (stale-token scenario) — same.
- World.ts: respendSubmitError field for capture; certificationStatus now nullable.

Restores the 9 token-4level/transfer-edge re-spend scenarios that regressed after
the merge; the proof-time path is still asserted when the aggregator accepts the
submit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
Three test-side fallouts from PR #119 (NetworkId + salt minting):

* SplitMintJustificationVerifier.verify now reads transaction.networkId.
  The mockCert helper in split-mint-justification.steps.ts was synthesizing
  a partial CertifiedMintTransaction without networkId, crashing 4 mutation
  scenarios with TypeError. Forward base.networkId into the mock.
* wrong-trust-base.steps.ts hard-coded networkId: 0 in its synthetic JSON.
  NetworkId.fromId now rejects 0 (out of 16-bit unsigned range). Use 2,
  which differs from the live LOCAL=3 trust base — same intent, valid id.
* cbor-envelope-tags.feature pinned MintTransaction arity at 6. #119 bumped
  the wire format to 7 elements (networkId + salt). Update the table row.

Also includes updated trust-base.json fixtures for tests/{e2e,functional}
matching the running bft-2sh aggregator at localhost:8080.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
Adds three new feature files covering high-value gaps from the post-#119
coverage audit, plus a tagged repro for a real bug surfaced by adversarial
review of src/payment/SplitMintJustification.ts.

* mint-canonicalization.feature (6 scenarios) — pins MintTransaction CBOR
  byte-stability (encode→decode→re-encode == orig) and two-build determinism
  (two independent create() calls with identical logical inputs produce
  byte-identical CBOR and the same derived tokenId). Both properties are
  load-bearing for the stateId / CertificationData chain after #115.

* mint-wire-mutation.feature (4 scenarios) — adversarial harness: rebuild
  a real MintTransaction CBOR with networkId={0,65536} or salt={31,33} bytes
  and assert the decoder rejects each with the documented error fragment.
  Confirms the new NetworkId/TokenSalt guards fire on the decode path, not
  just the constructor path.

* split-mint-empty-proofs.feature (@known-bug, 2 scenarios) — captures
  B3#1 finding (pre-existing): SplitMintJustification.fromCBOR at
  SplitMintJustification.ts:58 calls `new SplitMintJustification(...)`
  directly, bypassing the proofs.length>0 invariant enforced by create()
  at line 36. A crafted CBOR payload with zero proofs decodes cleanly.
  The bug scenario fails by design with an actionable message; tag
  @known-bug lets the regression filter skip it until fromCBOR is routed
  through create() or duplicates the non-empty check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
Adds 5 new feature files and extends 1 existing, covering the bulk of the
remaining post-#119 coverage gaps from the audit.

Hermetic (all pass, no aggregator):
* network-id-edge-cases.feature (5 scenarios) — pins NetworkId.fromId
  singleton identity for MAINNET/TESTNET/LOCAL, asserts custom-id
  fromId(42) returns fresh-but-equal instances, and verifies a
  RootTrustBase JSON round-trip preserves equality.
* token-salt-edge-cases.feature (3 scenarios) — mutation safety of
  TokenSalt.fromBytes (input-buffer mutation does not leak) and
  TokenSalt.toBytes (returned slice mutation does not leak), plus
  TokenSalt.generate uniqueness over 100 calls.
* mint-slot-pinning.feature (6 scenarios) — asymmetric per-field
  inputs (networkId=7, salt=0xAA·32, tokenType=0xBB·32, justification=0xCC,
  data=0xDD) round-tripped through CBOR. Each scenario asserts one slot
  decoded to its expected distinguishable value so any encoder/decoder
  slot-swap regression is observable (constructor arg order differs from
  wire-slot order in MintTransaction; this pins both).

Live (real aggregator at localhost:8080):
* mint-respend-tolerance.feature (1 scenario) — second mint at the same
  derived stateId with different `data` collides; tolerated either as a
  submit-side JSON-RPC error OR proof-time TRANSACTION_HASH_MISMATCH (the
  same shape as the transfer re-spend tolerance).
* split-mint-justification-verifier.feature (1 new mutation row,
  Examples table) — "swapping the mint networkId to a different network"
  triggers SplitMintJustificationVerifier.ts:62 cross-network check.
  Extends the existing mutation harness; mockCert helper now forwards
  a networkId override.

Deferred (skeleton + intent documented):
* deferred-coverage.feature (@deferred, 2 placeholders) — captures the
  two scenarios that need invasive fixture work:
  - #7: aggregator-side rejection of arity-6 MintTransaction sent over
    the JSON-RPC seam (extension of RawCertificationSubmitter).
  - #8: UnicitySealNetworkMatchesTrustBaseRule isolated FAIL, requires
    CBOR-level tampering of the inclusion proof's unicityCertificate
    to swap seal.networkId without mutating genesis.networkId.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
…vel tampering

Closes gap #8 from the post-#119 coverage audit. The existing
network-id-consistency.feature swaps the trust-base's networkId, which
trips MintNetworkMatchesTrustBaseRule first and short-circuits before
the seal rule is even checked. To observe the seal rule's FAIL in
isolation we needed a CertifiedMintTransaction where:
  - genesis.networkId matches the trust-base (mint rule passes)
  - inclusionProof.unicityCertificate.unicitySeal.networkId differs

seal-network-rule-isolation.feature constructs that shape by CBOR-
tampering the real seal's networkId byte (arity-8 tag 39005 array,
slot [1]) inside a real mint's inclusion proof, then re-packaging via
UnicitySeal.fromCBOR / new UnicityCertificate / new InclusionProof.
The seal's signatures no longer verify after the swap — but per PR
#119 the seal rule fires BEFORE signature verification, so the test
observes the seal-rule FAIL specifically (not a signature failure).

The mock CertifiedMintTransaction forwards just the methods/fields
the verification rule actually reads (calculateTransactionHash,
sourceStateHash, lockScript, networkId, tokenId, recipient, tokenType,
data, justification, inclusionProof). Verifies via
CertifiedMintTransactionVerificationRule.verify directly so we can
walk the result tree and assert MintNetworkMatchesTrustBaseRule=OK
sibling-to UnicitySealNetworkMatchesTrustBaseRule=FAIL.

Also updates deferred-coverage.feature: #7 (arity-6 mint over the wire)
turned out non-testable — CertificationData.toCBOR carries only the
mint's transactionHash, not the mint bytes themselves, so there is no
aggregator-side arity check to test. The arity guard is entirely
SDK-side and is already covered by cbor-envelope-tags.feature +
mint-wire-mutation.feature. Documented in deferred-coverage.feature
as a paper trail.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
…@known-bug

PR #119 commit 1dbc4a0 (Martti, 2026-06-04) routes
SplitMintJustification.fromCBOR through SplitMintJustification.create:

    - return new SplitMintJustification(
    + return SplitMintJustification.create(
        await Token.fromCBOR(data[0]),
        CborDeserializer.decodeArray(data[1]).map(p => SplitAssetProof.fromCBOR(p)),
      );

The create() invariant (proofs.length > 0) is now enforced at the decode
path too. Our adversarial repro scenario (commit 075a4b9) now passes —
empty-proofs CBOR is rejected with "proofs cannot be empty.".

Drop the @known-bug feature tag; rename the scenario from
"the bug" to "regression guard for 1dbc4a0"; tighten the Then step
to assert the specific error fragment instead of just "any error".
The hermetic positive control scenario is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
b3y0urs3lf pushed a commit that referenced this pull request Jun 11, 2026
…ion guard for e635578)

PR #119 commit e635578 (Martti, 2026-06-04) removed a stray `}` from
the OK branch of UnicitySealQuorumSignaturesVerificationRule.verifySignature:

    - return new VerificationResult(`SignatureVerificationRule[${nodeId}]}`, OK);
    + return new VerificationResult(`SignatureVerificationRule[${nodeId}]`, OK);

Pre-existing bug (introduced in 3e3a7fe "Draft version of sdk 2.0").
Surfaced by this session's adversarial review (B2#1) and reported to
the SDK dev via Discord.

Note on test shape: Token.verify discards UnicityCertificateVerification's
result subtree on OK (InclusionProofVerificationRule:117 returns OK with
no child results), so the per-node `SignatureVerificationRule[<nodeId>]`
names don't surface through the public Token.verify path. The regression
guard instead invokes UnicitySealQuorumSignaturesVerificationRule.verify
directly on a real mint's seal and walks its per-node children:
  - Asserts every child name matches /^SignatureVerificationRule\[[^\]]+]$/
  - Asserts no child name ends with `}`

Live (real aggregator) — needs a passing mint that produces a signed
seal with quorum-passing signatures.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

[TGE] Enforce network-id consistency during verification [TGE] Migrate minting from caller-supplied token ids to networkId + salt

4 participants