Summary
The Token Standard mint/burn ExtraArgs / ChoiceContext map is hand-written three times, all untyped/string-keyed, and the copies must stay byte-identical. CIP-112 (Token Standard V2) will add a parallel set of V2-namespaced keys (dual-version support), roughly doubling each copy.
Consolidate now, as a V1-only refactor (no V2 dependency), so the key set + context types are defined once per language and adding the V2 keys later is a one-place change.
Prep, not the V2 migration itself. Safe to land before the Token Standard V2 API freeze (Splice 0.6.11, ~Jul 2 2026). Tracked in the CIP-112 cBTC scoping doc §9.3 (shared-builder note) and §5.5 (pre-Jul-2 prep).
Current state — the three copies
| Copy |
Location |
How it builds the context |
| Rust |
cbtc-lib/src/mint_redeem/redeem.rs:419 |
serde_json::Map + json! literals — untyped serde_json::Value, keys + AV_* tags as string literals |
| TS app |
DLC-link/cbtc-mint-burn → app/src/functions/token-standard.ts:70 (createExtraArgsForMintBurn) |
hand-declared AnyValue / ChoiceContext / ExtraArgs interfaces + the same keys |
| IT helper |
DLC-link/dlc-attestor-stack → it/src/canton/helpers/token-standard.ts |
third copy; the TS app's header comment says it "matches" this one |
All three emit the same keys — utility.digitalasset.com/instrument-configuration, /issuer-credentials (plus optional /app-reward-configuration, /featured-app-right), and splice.lfdecentralizedtrust.org/reason — off the contracts returned by GET /cbtc/v1/token-standard-contracts.
Contrast: the transfer/accept path does not hand-build context — transfer.rs / accept.rs fetch typed choice_context_data from the registry. Only the burn-mint path assembles the map locally. (The Daml side is unaffected: cBTC's choices forward extraArgs opaquely into BurnMintFactory_BurnMint, so DLC-link/canton needs no change.)
Why now
- Drift risk: three untyped copies kept in sync by hand; a mistyped reverse-DNS key or wrong
AnyValue tag fails only at exercise time, on-ledger.
- V2 doubles it: dual-version means emitting V2-namespaced keys alongside the V1 keys in every copy.
- Unblocked: pure V1 refactor, no V2 package dependency — can land before the Jul 2 API freeze and shrinks the eventual V2 diff to one place per language.
Proposed scope
- Rust (
cbtc-lib): replace the json! context literals in redeem.rs with the codegen'd typed common::*::ExtraArgs types already used by transfer.rs / accept.rs; centralize the burn-mint key set as named constants/types in one module.
- TS: merge the two TS copies —
cbtc-mint-burn app + the dlc-attestor-stack IT helper — into a single shared module (one set of AnyValue / ChoiceContext / ExtraArgs types + one keyed builder). Decide where it lives (published TS package vs. single-source-of-truth file).
- Define the context key set once per language as named constants.
Rust and TS can't share one function — "shared" here means one schema / source of truth per language, not one binary.
Out of scope
- Any V2 keys/interfaces (added once the V2 APIs freeze, ~Jul 2 2026).
- The transfer/accept path (already typed + registry-fetched).
- The Daml code in
DLC-link/canton (receives extraArgs opaquely; no change).
Acceptance criteria
Cross-repo
DLC-link/cbtc-mint-burn — TS app copy (sub-task / PR there).
DLC-link/dlc-attestor-stack — IT helper copy + the integration tests that gate the refactor.
References
Summary
The Token Standard mint/burn
ExtraArgs/ChoiceContextmap is hand-written three times, all untyped/string-keyed, and the copies must stay byte-identical. CIP-112 (Token Standard V2) will add a parallel set of V2-namespaced keys (dual-version support), roughly doubling each copy.Consolidate now, as a V1-only refactor (no V2 dependency), so the key set + context types are defined once per language and adding the V2 keys later is a one-place change.
Current state — the three copies
cbtc-lib/src/mint_redeem/redeem.rs:419serde_json::Map+json!literals — untypedserde_json::Value, keys +AV_*tags as string literalsDLC-link/cbtc-mint-burn→app/src/functions/token-standard.ts:70(createExtraArgsForMintBurn)AnyValue/ChoiceContext/ExtraArgsinterfaces + the same keysDLC-link/dlc-attestor-stack→it/src/canton/helpers/token-standard.tsAll three emit the same keys —
utility.digitalasset.com/instrument-configuration,/issuer-credentials(plus optional/app-reward-configuration,/featured-app-right), andsplice.lfdecentralizedtrust.org/reason— off the contracts returned byGET /cbtc/v1/token-standard-contracts.Contrast: the transfer/accept path does not hand-build context —
transfer.rs/accept.rsfetch typedchoice_context_datafrom the registry. Only the burn-mint path assembles the map locally. (The Daml side is unaffected: cBTC's choices forwardextraArgsopaquely intoBurnMintFactory_BurnMint, soDLC-link/cantonneeds no change.)Why now
AnyValuetag fails only at exercise time, on-ledger.Proposed scope
cbtc-lib): replace thejson!context literals inredeem.rswith the codegen'd typedcommon::*::ExtraArgstypes already used bytransfer.rs/accept.rs; centralize the burn-mint key set as named constants/types in one module.cbtc-mint-burnapp + thedlc-attestor-stackIT helper — into a single shared module (one set ofAnyValue/ChoiceContext/ExtraArgstypes + one keyed builder). Decide where it lives (published TS package vs. single-source-of-truth file).Out of scope
DLC-link/canton(receivesextraArgsopaquely; no change).Acceptance criteria
redeem.rsuses the typedExtraArgstypes — nojson!context literals.utility.digitalasset.com/*+reasonkeys are defined once per language (named constants), not inlined.CBTCWithdrawAccount_Withdraw), and the cancel-withdraw mint-back; existing integration tests pass.Cross-repo
DLC-link/cbtc-mint-burn— TS app copy (sub-task / PR there).DLC-link/dlc-attestor-stack— IT helper copy + the integration tests that gate the refactor.References