CIP-0188? | Token-Owned Addresses - #1200
Conversation
Defines Token-Owned Addresses (TOA): a deterministic Cardano enterprise script address derived from (toa_version, policy_id, asset_name) applied to a canonical Plutus V3 validator. A TOA is spendable by any transaction that consumes exactly one unit of the controlling NFT as input, produces exactly one unit as output, and does not mint or burn that asset class in the same transaction. Authorisation is purely NFT-presence-based — no signer, wallet identity, or external ownership registry required. The standard is an off-chain interoperability CIP requiring no ledger changes; conformance is defined by the compiled validator artifact, the canonical parameter encoding, the address-derivation procedure, validator rules, and the normative test vectors. Reference implementation, compiled un-applied Plutus V3 validator artifact (476 bytes, template hash 129181a5...96dc0), and six normative address-derivation test vectors published externally at en7angled/toa tag 0.1.0. Demo frontend exercising address derivation, deposit, spend, and NFT carry-through hosted at toa.e7d.tech (mainnet and Preview).
There was a problem hiding this comment.
Thanks @mariusgeorgescu for submitting a progressive & well defined proposal with apparently great commercial potential: marking ready for Triage (preliminary technical assessment only: enough to confirm CIP candidacy) for the next meeting (https://hackmd.io/@cip-editors/135) which you & other proposal advocates are welcome to attend.
Also thanks for your rigour in cross-referencing the foundational CIPs in your OP & elaborating the "prior art" through the CIP itself: not all CIP authors do this, it saves editors a lot of work, and provides an excellent starting point in tagging potential reviewers.
Since it appears your method has already been demonstrated as workable, I think the next important step would be to verify that the great amount of implementation detail in your document would still leave the Cardano community with a standard that can be implemented by enterprises other than your own:
- Rather than just a "take it or leave it" stage ("independent implementation" pending in your Acceptance Criteria) we should now exercise due diligence to confirm that all of the detail in the Specification (and methods to demonstrate compliance) is both:
- necessary for mutual interoperability;
- mutually agreeable by reviewers as "best practice" rather than an arbitrary choice of your own reference implementation.
- TL;DR the reviewing community should agree that this is not overspecified. (Maybe you have already explained this & we just need to highlight those demonstrations.)
Though operatively about Tokens I'm not categorising this yet because it has the scope of other Tools CIPs before it: to discuss below & also likely settle at the upcoming CIP meeting. Tagging, in the meantime, roughly by stakeholder category:
- gating tokens, scripts & permissions, security considerations: @colll78 @fallen-icarus
- NFT architectures, royalties & wallet support: @gitmachtl @SamDelaney @thaddeusdiamond @realdecimalist @Crypto2099
- general ecosystem capabilities: @gufmar @ptrdsh @Quantumplation
- general efficiency (from Plutus & Ledger (though no Ledger updates required)): @lehins @WhatisRT @zliu41
- Motivation/Rationale: capital first word after colon - Acceptance Criteria: regroup; rephrase to not depend on checkbox rendering - Implementation Plan: drop implicit editor-signoff step Co-authored-by: Robert Phair <rphair@cosd.com>
Addresses @rphair's review comment by leading the related-work comparison with CIP-0113, clarifying the derivation-model distinction with TOA, and adding CIP-0113 to References.
Moves JSON envelope example and per-vector field semantics out of the CIP body into en7angled/toa@0.1.1:test-vectors/README.md, identified by blake2b-256 content hash. Conformance gates (a)/(b) split and Coverage MUSTs stay inline. Bumps all reference-repo links from 0.1.0 to 0.1.1. UPLC and test-vector JSON content unchanged from 0.1.0 (verified by hash). Addresses @rphair review comment on PR thread cardano-foundation#4.
Motivation: under the previous apply_params-based derivation, the TOA address could not be derived on-chain (Plutus V3 exposes no primitive for apply_params + ledger serialisation), and off-chain implementations in TypeScript, Rust, Python, etc. had to depend on Plutus tooling. R removes both obstacles: it is implementable on-chain using only standard Plutus V3 builtins (appendByteString, consByteString, lengthOfByteString, serialiseData, blake2b_224) and off-chain in any language with bytestring concatenation and blake2b-224. The semantic identity of TOA v1 remains anchored in the same compiled validator artifact -- the byte-level constants are extracted from it -- but conformance is now expressed in a form that is verifiable uniformly on-chain and off-chain. Replaces the apply_params-based derivation procedure with the byte-level function R, executable on-chain via standard Plutus V3 builtins and implementable off-chain in any language with bytestring concatenation and blake2b-224. The compiled UPLC artifact and template hash become audit references; FLAT_PREFIX_TOA_V1 (528 B), FLAT_SUFFIX_TOA_V1 (1 B), the CBOR bytestring-header encoder, and the canonical PlutusData CBOR parameter encoder become the normative derivation inputs, pinned at en7angled/toa@0.2.0 with blake2b-256 content hashes. The reference recipe wraps params_cbor in a single-chunk chunked-bytestring frame (1-byte length prefix + paramCbor + 0x00 terminator), matching the flat-encoded UPLC layout the validator expects when applied via a Constant Data UPLC term (cardano-api applyArguments semantics). Implements cerinta sections 3.1, 3.2, 3.3, 3.8.
Adds:
- Rationale entry "Why is the canonical address derivation specified
at the byte level (R) rather than via apply_params?" — explains why
on-chain executability + non-Haskell implementability justify the
byte-level specification, and documents the empirical precondition
(byte-aligned decomposition of the applied flat-encoded script).
- Open Question cardano-foundation#6 "Stability of FLAT_PREFIX_TOA_V1 and
FLAT_SUFFIX_TOA_V1" — frames byte-aligned decomposition as a
property of the compiled artifact, not of the Plinth source;
recompilation requires a new toa_version.
- Acceptance Criteria items for canonical R implementation and for
toa-verify-reconstruction passing on every artifact release.
Also adjusts the high-level Specification intro to be neutral about
which procedure produces the applied script bytes (R reconstructs
them rather than calling apply_params).
Implements cerinta sections 3.5, 3.6, 3.7.
Keeps the conformance-vs-documentation cut agreed in PR review discussion r3293465306 (cardano-foundation#1200 (comment)): conformance gates stay inline in the CIP; schema documentation lives in en7angled/toa@0.2.0:test-vectors/README.md (referenced by content hash). Changes inline in the CIP: - Clarifies that per-vector fields `params_cbor_hex`, `applied_script_cbor_hex`, `applied_script_bytes`, and `flat_body_length` are diagnostic aids; conformance for category (a) is determined by `expected_script_hash`, `expected_address_mainnet`, `expected_address_testnet`. - Adds the CBOR-threshold rationale paragraph: lengths 23 and 24 bracket the single-byte vs length-prefixed CBOR bytestring header transition, and lengths 31 and 32 cover the upper boundary of the permitted asset_name domain. - Adds two coverage MUST bullets: single-policy_id-change vector pairs and single-asset_name-change vector pairs, useful for isolating which region of R depends on which input. The schema documentation for the new `flat_body_length` field is in en7angled/toa@0.2.0:test-vectors/README.md, already content-hashed in the preceding paragraph. Implements cerinta section 3.4 under the conformance-vs-documentation cut.
Removes paragraphs and sections that are non-normative noise under the
R-canonical derivation:
- The "TextEnvelope encoding mistakes" warning in Address Derivation:
irrelevant under R, which never goes through cardano-cli text
envelopes — implementers compute applied bytes directly from
bytestring concatenation, not from a serialised wrapper.
- The Tx3 paragraph in Public API and Transaction Shapes and the
"Generated bindings (supplementary)" subsection: Tx3 was a
non-normative reference file that was never published; the mentions
added noise without normative or informative value.
- The "L2 Interoperability" subsection: a disclaimer paragraph noting
cross-ledger semantics are out of scope; the Versioning section
already establishes scope.
Condenses two redundancies:
- The repeated MUST NOT in Datum and Redeemer Schema becomes a single
cross-reference to Definitions — TOA deposit, which already
establishes the normative rule.
- "What lives where" no longer restates content-hashing strategy
already covered in Mandatory Normative Artifacts; the two bullets
naming the CIP folder contents are preserved.
Updates two orphan references left behind: the "outside Tx3" sentence
in Address derivation helper, and the "any toa.tx3 file" mention in
Reference Artifacts — Normative components.
Net: 22 deletions, 5 insertions; 611 → 593 lines.
|
Update — TOA addresses can now be derived on-chain The address-derivation procedure has been restructured into a byte-level function R (4 new commits). Core benefit: TOA addresses are now derivable on-chain by other validators. Plutus V3 exposes no primitive that applies parameters to an unapplied script and serialises the result, so under Technical cost. TOA v1's validator was recompiled to accept R is content-hashed at en7angled/toa@0.2.0; Reading order: |
|
thanks @mariusgeorgescu — it seems like at least the change TOA addresses are now derivable on-chain by other validators supports the premise I mentioned in #1200 (review) that a CIP more generally usable by third parties will be more acceptable as a "standard" ... I'll bring this up at the the CIP meeting today (in about 45 minutes). |
|
Very cool CIP, and a great use-case of onchain parameter validation. Perhaps you will find our Aiken Design Patterns library useful for this, specifically the parameter validation module which exposes high-level abstractions for performing onchain parameter validation: example uses: |
There was a problem hiding this comment.
@mariusgeorgescu as you've observed, the CIP meeting today has declared this a candidate: please rename the containing directory to CIP-0188 and update the "rendered latest document" link in your OP accordingly. 🎉
We had a longer than usual Triage for this one because of concerns (introduced by @perturbing) that this data structure for each token-owned address would provide standardisation for an "entity" on the Cardano chain which all wallets would then be compelled to recognise and process in user wallets: a query-intensive operation whose expense and development difficulty might not be worth the benefits gained from it.
However @colll78 made a number of arguments that presented technical usefulness even under these conditions, including:
- Other Cardano contributors, without this CIP presented roughly as conceived, would eventually submit their own CIPs — or worse, continue without standardisation — to achieve same purpose (of saying "this address is owned by this NFT: which can serve as a witness instead of a conventional signature").
- ... Therefore it would make sense to continue with this spec to have a common definition: rather than the chaos that would ensue if each data structure developed for this purpose had a mutually incompatible surface. This is the same rationale behind pursuing CIP-0113 - Programmable Tokens.
- The off-chain development that this would entail is not strictly a part of the CIP (therefore also confirming the category as
Tokensrather the the possibility ofToolsraised above) and therefore it shouldn't be inadmissible because of the degree of complexity or expense that might lurk there. - ... We adopted a similar rationale when accepting the Beacon Tokens CIP: i.e. even though the primary use case of such tokens — signaling for conditional transactions (again, my own words) — has not been broadly accepted.
We should be able to continue this CIP's review with expectations set as above: assuming I've described these correctly. I've already tagged those who I hope are a representative set of experts across the applicability of this CIP & believe we should consider suitability as @perturbing & @colll78 have defined it above before merging.
Therefore please anyone else that was at the CIP meeting today correct my non-expert language in defining the issues & assessment above: @PapaGoose @Cerkoryn @fallen-icarus @nemo83 @Ryun1
|
|
||
| **Within the Aiken / Plutus design-patterns ecosystem:** | ||
|
|
||
| - The [`parameter-validation`](https://github.com/Anastasia-Labs/aiken-design-patterns/blob/main/lib/aiken-design-patterns/parameter-validation.ak) module of Anastasia Labs' [aiken-design-patterns](https://github.com/Anastasia-Labs/aiken-design-patterns) library captures, in a more general form, the byte-level technique TOA's R uses to reconstruct a parameterised script's hash without invoking `apply_params` at runtime — splicing precomputed prefix and suffix bytes around the parameter region and hashing the result with `blake2b_224`. Example usage of the library is at [`validators/examples/parameter-validation.ak`](https://github.com/Anastasia-Labs/aiken-design-patterns/blob/main/validators/examples/parameter-validation.ak). TOA's R is conceptually a specific instance of the same pattern, specialised to a single composite parameter and pinned to a single canonical artifact. The encoding choices differ: the library hashes each parameter to a constant 28-byte footprint (`blake2b_224(serialise(param))`) so that arbitrary parameter types — and, in particular, multiple interleaved parameters — share a uniform on-chain layout; TOA embeds the raw `serialiseData` output of a single composite parameter `Constr 0 [toa_version, policy_id, asset_name]`, variable in length, framed by a fixed 1-byte suffix. The two encodings reflect different design goals — generality across parameter shapes versus a specialised single-parameter form — not a quality judgement. See *Why raw parameter embedding rather than hashing parameters?* in *Rationale — Design Decisions* for the specific reasons TOA chose the latter. |
There was a problem hiding this comment.
Good feedback, I will make sure we add variants of the library functions which provide direct argument support such that when the caller is certain that the argument they are parameterizing the contract with is byte aligned already (as is the case for Constr BuiltinData) then no hashing is required, likewise if the argument is a currency symbol, script hash or other hashed already hashed or byte aligned parameter.
There was a problem hiding this comment.
Thanks @colll78 — I noticed you actually built this the very next day: 2eb280f9 on develop (parameter-validation/advanced.ak, variable-length Data params). That's essentially CIP-0188's R, generalised to any prefix.
If/when it lands on main: feeding advanced.apply_param the pinned FLAT_PREFIX_TOA_V1 and Constr(0, [toa_version, policy_id, asset_name]) should reproduce every expected_script_hash in the six vectors at en7angled/toa@0.2.1 — a free byte-for-byte test target. Happy to reference the module from the CIP once it's released.
There was a problem hiding this comment.
@keyan-m What's the progress on that? Can we merge into main?
There was a problem hiding this comment.
@colll78 @mariusgeorgescu this is now merged and included in v1.8.0
|
Independent clean-room verification of R · erratum fix in diagnostic vector fields ( Three related updates, just pushed to this branch and released as reference-repo tag 1. R verified implementable from the CIP text aloneTo test the overspecification concern from the less-demanding direction, I wrote a clean-room Python implementation of R from the CIP text only — ~40 lines of core logic, standard library only ( The exercise surfaced exactly two places where I had to reach outside the CIP text: the CBOR encoding of the integer field (the CIP specified To be clear about what this is not: Path-to-Active steps 7–8 require verification by independent external parties, and category-(b) validator-scenario vectors remain outstanding. This exercise claims neither — it only demonstrates that the byte-level spec is complete enough to implement in any language without Plutus dependencies. 2. Erratum:
|
…end security analysis Overspecification pass (conformance = R + Validator Rules + test vectors): - Policy classification becomes a RECOMMENDED vocabulary; per-TOA assignment is SHOULD; the single remaining MUST is the safety outcome (never present a TOA as safely controlled by a unique NFT without verified policy closure). - UI wording and display obligations lowered to SHOULD; min-UTxO no longer restated as a wallet obligation; obligations addressed to the frozen validator artifact rephrased as properties. - Wallet Behaviour states the minimal 'TOA-aware' bar explicitly. - Acceptance Criteria rewritten as conditions-at-activation (checkbox syntax dropped); status tracking consolidated in Implementation Plan. Test-vector erratum (reference repo 0.2.1): params_cbor_hex was emitted definite-length in 0.2.0 vectors and flat_body_length was off by one in all six; script hashes, addresses and applied bytes unchanged; normative binaries byte-identical. Pins bumped: toa-v1.json blake2b-256 03ebfb99..., tag URLs 0.2.0 -> 0.2.1. Precision: n = 531 + len(params_cbor) in [567, 600]; integer smallest-form bytes inline; serialiseData empty-Constr exception noted; BIP-173 cited for bech32 (checksum constant 1); aiken-design-patterns links pinned to v1.7.0; Validator Rules list indentation fixed; phantom 'R-canonic' term unified. Security analysis: control cycles and nested TOAs (self-deposit as the 1-cycle); multi-TOA composition without double-satisfaction; consumer contracts deriving TOA addresses on-chain; CIP-0068 label-100 control caveat; non-spending purpose behaviour (trace T3); corresponding category-(b) coverage entries added as outstanding.
cb277a2 to
9d809ee
Compare
rphair
left a comment
There was a problem hiding this comment.
@mariusgeorgescu (and/or @colll78) please ping the editors in a comment here when the work in progress appears to stabilise — particularly, anything that would be documented in the CIP — so we can put this through final review.
…cross-check of vectors Anastasia Labs released the raw-embedding parameter-application form (parameter-validation/advanced.apply_param) in v1.8.0. Related Work now describes it as the same construction as R generalised to any flat prefix, and records that, called with FLAT_PREFIX_TOA_V1 and Constr 0 [toa_version, policy_id, asset_name], it reproduces all six published address-derivation vectors byte-for-byte (Aiken 1.1.23; harness pinned in the reference repository). Implementation Plan step 5 notes the independently authored implementation; links bumped v1.7.0 -> v1.8.0.
45871b5 to
8821694
Compare
|
Thanks @rphair (cc @Ryun1) — pinging as requested: the document has stabilised and I'd like to request final review. The one substantive change since my last comment is the v1.8.0 reference. Anastasia Labs released the same byte-level construction as R in aiken-design-patterns v1.8.0 ( The remaining Path-to-Active items (validator-scenario vectors, ports, integrations) are tracked in the Implementation Plan; completing them will only bump pins and status markers, not the normative content. CI validation is green on the current head. |
There was a problem hiding this comment.
that's great @mariusgeorgescu and I will readily approve this myself & mark Last Check for the next CIP meeting after your consideration of the change below: as you say, with Path to Active issues being independent of the normative content.
@colll78 we have tagged this around the ecosystem already in #1200 (review) and you are the only one who's shown a productive interest. It looks like implementations have already been facilitated by the work you began in #1200 (comment) with compatibility verified in #1200 (comment).
- Whatever assurance you can give us that this CIP is ready to merge will be helpful in
Last Checkmaybe as soon as Tuesday: https://hackmd.io/@cip-editors/142
@mariusgeorgescu the CIP editors don't have the need or the ability to audit this — so this would not be a deeply technical review — though I can appreciate (and will note in the meeting review) that:
- audit is expected beginning with the next item on the Implementation Plan
- data structure has been provided to facilitate audit (i.e. exposing intermediate levels of data).
@Crypto2099 I've also seen you RSVP for this next meeting so I thought you might also be interested in a look at this beforehand & please tag anyone else you'd like to notify that the review is actively proceeding.
rphair
left a comment
There was a problem hiding this comment.
p.s. in my last review I meant to suggest using a link when referring to a commonly quoted part of your spec (used 8 times in your document, but only these 2 are forward references & therefore more of a courtesy to the reader):
…atus markers - Implementation Plan closing line per rphair's suggestion: editors verify completion and apply the Active tag; steps 7-9 remain ecosystem-owned. - Forward references to Mandatory Normative Artifacts become anchor links (Canonical Parameter Encoding, Address Derivation). - Done/outstanding status markers in Implementation Plan bolded for scannability (keeping the no-tickbox format).
775c6cc to
f1765d6
Compare
rphair
left a comment
There was a problem hiding this comment.
great work @mariusgeorgescu ⭐ and I look forward to hearing what the other editors think (cc @Ryun1 @perturbing) — and if @colll78 has any last words — around Last Check tomorrow: https://hackmd.io/@cip-editors/142
Ryun1
left a comment
There was a problem hiding this comment.
LGTM
thanks for the contribution @mariusgeorgescu
Summary
Token-Owned Addresses (TOA) define a deterministic Cardano enterprise script address for a controlling asset class
(policy_id, asset_name). The address is the hash of a canonical Plutus V3 validator applied to(toa_version, policy_id, asset_name), spendable by any transaction that consumes exactly one unit of the controlling NFT as input, produces exactly one unit as output, and does not mint or burn that asset class in the same transaction.This is an off-chain interoperability CIP — no ledger changes are required. Conformance is determined by the compiled un-applied validator artifact, the canonical parameter encoding (CDDL), the address-derivation procedure, validator rules, and normative test vectors.
Status:
Proposed.Related work
Reference implementation and demo
Published at en7angled/toa@0.1.0:
129181a58ca3716aada61244d3d4210bff5a7235f709189af2596dc0, artifact blake2b-2567f78c5524a00852eb51ee760f86a3f0cce4535b446e0c03d6cdc35eb6de0092b).toa_versionisolation.Demo: toa.e7d.tech — runs the reference frontend against Cardano Preview and mainnet, exercising address derivation, deposit, spend, and NFT carry-through end-to-end.
Path to Active
7 of 9 acceptance criteria are satisfied by the reference implementation. Outstanding work is community-owned:
Note on Discussions
The
Discussions:field will be updated to this PR URL in a follow-up commit on the same branch immediately after this PR is opened, per CIP-0001 convention.(rendered latest document)