CIP-PR-283: Canton Access and Privacy Standard
CIP-?: Canton Access and Privacy Standard
Abstract
This CIP defines a set of Daml interfaces, the Canton Access and Privacy Standard (CAPS), for publishing, distributing and verifying oracle data on Canton. Under CAPS a data set is published in numbered rounds whose price-free records are visible to the feed's readers; the data travels in capsules that each distributor scopes to its own clients; and a consumer proves two things on its own participant, with no informee but itself: that a capsule's content is what the oracle's nodes signed, and that it is the content fixed in the round of its number. The party that publishes the data is a stakeholder of nothing a consumer touches, so it learns who holds a license and nothing about consumption.
The standard is oracle-agnostic: an oracle joins it by providing one
contract, a verifier for its own signing scheme. It builds on the
Canton Data Standard:
every capsule implements PublishedDataPoint, so an
application written against that standard reads a CAPS capsule unchanged.
A reference implementation, with verifiers for RedStone payloads and for the
Data Standard's signed envelope, accompanies the proposal.
Motivation
Price-dependent workflows on Canton have no standard source of a canonical, auditable price. CIP-0056 defines asset issuance and settlement but contains no valuation clause, so every price-dependent lifecycle event in a token workflow takes its reference from outside the standard. The FINOS CDM implementation demonstrated on Canton models margin and collateral workflows, but its event types (Valuation, MarginCallIssuance, Reset) take a price input as a given. The Collateral Subcommittee's work on haircut schedules and margin thresholds depends on deterministic price feeds in the same way. Each of these needs the same thing: a price that every party to a transaction can establish is the one the oracle fixed at a given time, without trusting the others, and that an auditor can trace back to a signed attestation. The network already runs on price feeds without such a record: the reference price of Canton Coin is ingested and voted by each Super Validator off-ledger (CIP-0079, CIP-0092), and several Super Validators have committed to bringing market and oracle data onto Canton (CIP-0061, CIP-0063, CIP-0065). A shared standard lets an application consume any of these feeds through one code path and lets their providers compete on data rather than on integration.
The two oracle models in use on other networks each fail one institutional requirement. A pull oracle, where the submitting party fetches a signed price certificate off-chain and includes it in its transaction, provides no canonical fixing: two counterparties to one settlement may hold two valid certificates with different timestamps or aggregations, and nothing at the protocol level says which governs. Traditional market infrastructure resolves this with fixing conventions, such as the 4pm WM/Reuters rates or ISDA fallback frameworks; the pull model has no equivalent, which is why its adoption has stayed with latency-sensitive trading rather than with lending, collateral and structured products, where a single agreed reference price is required for margin, liquidation and valuation. A push oracle, where the oracle writes a single on-ledger price contract, gives the fixing but, on Canton, leaks consumption: reading a contract in a transaction is an event disclosed to its stakeholders, so an oracle that is a stakeholder of the price contract observes which participants use which data, when and how often. Consumption patterns reveal positions, hedging and transaction timing, which institutions cannot accept as a side effect of a price lookup.
Canton's model makes it possible to have the push model's fixing without its leak, provided the design keeps the oracle's contracts off every path a consumer's transaction takes. A party is informed of a transaction when it is a stakeholder of a contract the transaction creates or archives, or a signatory or actor of a contract it fetches or exercises. A verification that fetches the oracle's contract informs the oracle; a distribution that archives a shared contract informs every observer of it. Data providers add a third requirement: the right to distribute and redistribute data is licensed, and a provider must be able to see who holds a license and to revoke it, without seeing what the licensee does with the data. Each oracle on Canton today solves this in its own templates, with its own notion of a round and its own verification path, so an application that consumes two feeds codes against two models, and the guarantees it gets differ in ways that are hard to compare.
The workflows this is meant to serve: the net asset value of a tokenized fund published at dealing cut-offs, where transfer agents, custodians and wealth platforms each see the valuation relevant to their holdings and none can infer another's assets under management; fair-value assessments for secondary transfers of private company shares, where each transaction sees the valuation and no participant observes other trades; structured notes on a basket of private fund NAVs, where investors receive views scoped to their tranche; and corporate actions fixed once by consensus of several verifiers and consumed down a custody chain, each custodian deriving the entitlement relevant to the positions it holds.
The Canton Data Standard,
published by Kaiko, fixes how a data point is read: the
PublishedDataPoint interface and the AnyValue type. It does
not say how a consumer establishes that a data point is canonical, how
data is licensed and redistributed, or what a distribution reveals. CAPS
fills that gap above the Data Standard, without changing it: it fixes what
a consumer checks, what a publication produces, what a license may do and
what a distribution must not reveal, and leaves everything vendor-specific
to one interface, the verifier.
A standard rather than a product because an interface package on Canton cannot be smart-contract-upgraded: whatever interface consumers code against is fixed for the life of its version. Fixing it once, in the open, lets wallets, dApps and settlement contracts verify any conforming feed through one code path, lets data providers compete on data and price rather than on integration, and gives the network a shared definition of a verified feed.
Specification
The normative text of this section is restated in full, with the data
types and the reference implementation's choices, in the specification of
the reference repository (see Reference implementation). The
interface source, package caps-api-core-v1, is the authority where the
two differ.
The words MUST, SHOULD and MAY are used as in RFC 2119.
1. Overview
A data set (a feed) is identified by a DataDefinition contract, whose
view names the canonical Verifier instance for the feed. Publication
happens in rounds: each round is a Round contract holding a round
number, a fixing time and a commitment to the data, never the data itself.
The chain of rounds is driven by one live RoundHead contract per data
set, consumed and re-created on every publication, which is what makes
round numbers unique. The data of a round is published as a capsule, a
Capsule contract carrying the data point, the oracle's signed payload and
the license under which it was created. Licenses are License
contracts: the root license belongs to the publishing party, and every
sublicense to the licensee it was created for. A license owner distributes
by deriving a new capsule, with the same content, for its own clients. A
license may name a LicenseDelegate, the extension point through which a
deployment adds behaviour such as accounting.
In the terms of the original proposal: the feed producer contract is the
DataDefinition together with its canonical Verifier and the
RoundHead; the root capsule is the root Capsule of a round, with the
Round as its price-free record; derived capsules are capsules created
through License_Distribute; the credentialed verifier that mints the root
is the publisher exercising RoundHead_CreateRound; and the licensing
terms live in License contracts rather than in the feed producer.
The standard refers to parties by role. One party may hold several roles.
| Role | What it does |
|---|---|
| Operator | Publishes the data set: owns the root license and is the distributor of every root capsule. |
| Publisher | Submits a publication. The operator always may; an implementation may admit others. |
| Readers | The parties entitled to see that a round exists and to check capsules against it. |
| Distributor | The owner of a license, who signs the capsules created under it. |
| Licensee | A party a license entitles to create a sublicense from it. On the root license, also the audience of every root capsule. |
| Client | A party a capsule is distributed to. |
| Consumer | A client that verifies a capsule before acting on it. |
| Auditors | In the reference implementation, parties that co-sign the definition, the head and the rounds, so that the operator cannot archive them, fork the chain or mint a round alone; they may pause publication. Not named by the interfaces. |
The privacy goal is stated in terms of these roles: the operator learns who holds a license and who publishes rounds; it does not learn who consumes, or how much any distributor distributes.
2. The interface package
caps-api-core-v1 is a Daml package targeting Daml-LF 2.1, built with
--explicit-serializable=yes, that depends on the
Canton Data Standard
packages canton-data-standard-utils-v1 (for AnyValue) and
canton-data-standard-datapoint-v1 (for PublishedDataPoint), version
0.2.0. It defines
seven interfaces and the shared types below, and no executable code: every
choice body is a single call of an interface method.
data CapsuleContent = CapsuleContent with
dataPoint : PublishedDataPointView -- distributor, publishedAt, values...
payload : AnyValue -- the oracle's signed data, opaque
license : ContractId License
type RejectionReason = Text
data VerificationResult = Verified with dataHash : Text
| Rejected [RejectionReason]
data CheckResult = Passed | Failed [RejectionReason]
data CapsuleSource = ById (ContractId Capsule) | ByView CapsuleView
data CreateRoundResult = CreateRoundResult with
head : ContractId RoundHead
round : ContractId Round
capsule : ContractId Capsule
3. The interfaces
3.1 DataDefinition
The identity and trust anchor of a data set; its contract id is what every round, capsule and license points at.
data DataDefinitionView = DataDefinitionView with
dataId : Text -- a human-readable name, not unique
verifier : ContractId Verifier -- the canonical verifier instance
No choices. An implementation MUST keep a definition's view constant for its life: a change of verifier or of data set is a new definition. A definition SHOULD be visible to the readers. Who signs it and how it is created is left open.
3.2 Verifier
The oracle's verification rules as a contract, and the only vendor-specific piece of a deployment. Its view is empty; its parameters (keys, quorum, freshness window) are template fields, known to whoever creates an instance. It answers three questions through non-consuming choices whose only controller is the asking party, each taking views, never contract ids:
nonconsuming choice Verifier_Verify : VerificationResult
with actor : Party; capsule : CapsuleView
nonconsuming choice Verifier_VerifyRound : CheckResult
with actor : Party; capsule : CapsuleView; round : RoundView
nonconsuming choice Verifier_VerifyFreshness : CheckResult
with actor : Party; capsule : CapsuleView; asOf : Time
Verifier_Verify (authenticity) returns Verified dataHash when the
content is authentic by the verifier's rules, typically that payload
carries a sufficient set of valid oracle signatures and that dataPoint is
the correct aggregate of it; dataHash is the verifier's commitment to the
content. Verifier_VerifyRound (canonicality) passes when the round
belongs to the capsule's definition, has its round number and fixing time,
and has as dataHash this verifier's commitment to the content.
Verifier_VerifyFreshness passes when the fixing time is acceptable at
asOf by the oracle's window.
Requirements:
- A verifier MUST NOT abort on a bad capsule; it reports.
- Each verdict MUST be a function of the choice's arguments and the verifier's own fields only: not of ledger time, the calling party or any other contract. A verifier MUST NOT fetch or exercise another contract.
- The commitment MUST be stable across instances with the same parameters,
and MUST depend only on the fields of
CapsuleContentthat a distribution copies unchanged:publishedAt,schemaVersion,values,metadataandpayload; never onlicenseor ondistributor. - Two instances with the same template and parameters MUST give the same verdicts, which is what lets a consumer verify against an instance of its own.
The signing scheme, the aggregation, the encoding of payload, the
commitment function and the freshness window are the implementation's.
3.3 RoundHead
The head of a data set's round chain and its publishing endpoint. One live contract per definition.
data RoundHeadView = RoundHeadView with
definition : ContractId DataDefinition
round : ContractId Round -- the latest round; a pointer, may be retired
roundNumber : Int -- the latest round's number
isPaused : Bool
choice RoundHead_CreateRound : CreateRoundResult -- consuming
with actor : Party; content : CapsuleContent
An implementation of RoundHead_CreateRound MUST: consume the head, so
that two concurrent publications are a double spend and the loser creates
nothing; give the new round the previous number plus one and
content.dataPoint.publishedAt as its timestamp; fail unless that fixing
time is strictly greater than the previous round's; obtain the verdict of
Verifier_Verify from the definition's canonical verifier for the new
capsule's view, fail on Rejected, and record the returned dataHash in
the round; obtain the verdict of Verifier_VerifyFreshness with ledger
time as asOf and fail on Failed; fail while isPaused; create the root
capsule with content unchanged, signed by the operator, with the operator
as distributor; and fail unless content.license is a license of this
definition owned by the operator. The authority to sign the round and the
root capsule MUST flow from the head, not from the caller, so that
publication is open to any party the implementation admits. The head
carries the latest round's number and fixing time itself, so a
publication depends on no round's existence and retiring one never stops
the chain. Who signs the head and the rounds, how publication is paused
and who observes the root capsule are left open.
3.4 Round
The immutable, price-free record of one fixing. A consumer reads it from
its own participant and passes the view to Verifier_VerifyRound; it is
never fetched inside a consumer's transaction.
data RoundView = RoundView with
definition : ContractId DataDefinition
roundNumber : Int
timestamp : Time -- the fixing time
dataHash : Text -- the verifier's commitment to the root capsule
choice Round_Archive : () -- consuming
with actor : Party
A round MUST be created only by RoundHead_CreateRound, except round 0,
the genesis round, which the bootstrap of a definition creates with an
empty commitment and no capsule. A round's view MUST NOT change. Rounds
MUST be visible to the readers and MUST NOT carry the data. A round MUST
be archived only by Round_Archive, whose authority flows from the round
and which MUST refuse any actor the implementation does not admit; the
reference implementation admits the operator alone. A round SHOULD outlive
every capsule of its number; when it may go is an archiver's rule, not the
standard's.
3.5 License
A right to distribute capsules and to sublicense. One interface for every level of the chain.
data LicenseView = LicenseView with
definition : ContractId DataDefinition
owner : Party -- the signatory; the only distributor
licensees : [Party] -- entitled to sublicense from it
delegate : Optional (ContractId LicenseDelegate)
nonconsuming choice License_Distribute : ContractId Capsule
with source : CapsuleSource; clients : [Party]
controller (view this).owner
nonconsuming choice License_CreateSublicense : ContractId License
with actor : Party; licenseType : AnyValue; licensees : [Party]
controller actor
License_Distribute MUST copy the source capsule's definition, round
number and content unchanged, except for content.license, which becomes
this license, and distributor, which becomes the owner; MUST fail when
the source belongs to another definition; MUST make clients observers of
the new capsule and SHOULD make nobody else, since every added observer
learns the audience, which the delegate exists to avoid; and MUST NOT
verify the source's authenticity, which is the consumer's check.
License_CreateSublicense MUST fail unless actor is one of the license's
licensees; the child,
signed by actor alone, MUST have the same definition. A license that
names a delegate MUST exercise LicenseDelegate_OnDistribute in every
distribution, after creating the capsule, and MUST give every sublicense
the delegate LicenseDelegate_Subdelegate returns. A license's licensees
MUST be fixed for its life. An implementation SHOULD provide a way for the
licensor to retire a license. The encoding of licenseType, expiry,
revocation and what a distribution costs are left open.
3.6 Capsule
The unit of distribution. Capsule requires the Data Standard's
PublishedDataPoint, so any consumer of that standard reads it unchanged.
data CapsuleView = CapsuleView with
definition : ContractId DataDefinition
roundNumber : Int
content : CapsuleContent
No choices of its own. PublishedDataPoint_Fetch is inherited from the
Data Standard; a consumer that reads a capsule through it informs the
distributor, so a CAPS consumer reads the view from its own participant
instead (section 4). The signatory MUST be content.dataPoint.distributor.
content.dataPoint MUST equal the view the contract exposes through
PublishedDataPoint. The observers MUST be the audience the capsule was
distributed to: for a root capsule, the audience the implementation
defines, which MUST include the root license's licensees (the reference
adds the auditors); for a distributed capsule, the clients of
License_Distribute, and nobody else unless the implementation chooses to
widen it (3.5). A capsule MUST NOT be modified; retention is the
distributor's.
3.7 LicenseDelegate
What a license does on a distribution beyond creating the capsule.
Optional: a license names one, or None. Its view is empty.
nonconsuming choice LicenseDelegate_OnDistribute : ()
with distributor : Party; license : ContractId License; roundNumber : Int
capsule : Optional (ContractId Capsule); clients : Optional [Party]
context : Optional AnyValue
controller distributor
nonconsuming choice LicenseDelegate_Subdelegate
: Optional (ContractId LicenseDelegate)
with licensor : Party; actor : Party
licenseType : AnyValue; licensees : [Party]
controller licensor, actor
LicenseDelegate_OnDistribute is exercised by the license in the same
transaction as the distribution, so a distribution through the license
cannot happen without it. LicenseDelegate_Subdelegate returns the
delegate a sublicense names, with the authority of both owners, which
License_CreateSublicense carries. Who signs a delegate decides who learns
of distributions: a delegate signed by the distributor informs nobody new;
one signed by an accountant informs the accountant and makes its
participant a confirming party of every distribution; one signed by the
operator defeats the privacy goal. The licensees of every license that
names a delegate MUST observe the delegate.
4. Privacy rules
Canton informs a party of a transaction node when the party is a stakeholder of a contract the node creates or archives, a signatory or actor of a contract the node fetches or exercises, or an observer of a contract a consuming exercise archives. The rules follow.
- Verification takes views, never contract ids. A fetch would inform the capsule's distributor and the round's signatories that the consumer used the capsule and when.
- A consumer verifies against its own verifier instance. Exercising the canonical instance would inform its signatory of every verification. The consumer creates an instance from the same template with the same parameters and itself as signatory; by 3.2 the verdicts are the same.
- A consumer reads its round from its own participant. As an observer it has the view without any transaction.
- Distribution by view is private; by id is not.
ByViewpasses the source as data and informs the owner and the new capsule's clients only, plus the delegate's informees if the license names one.ByIdfetches the source and informs its signatory of the time of this distribution. - Nothing on the consumption path touches a contract the operator signs. The operator is informed of a round's existence, which it created, and of nothing downstream.
- Disclosure informs the recipient only. A publisher that is not a reader can be shown the contracts a publication touches; a client can be shown the license a capsule names. Neither creates a ledger event.
A party acting as operator MUST NOT also act as a client's verifier owner or, where an extension adds the role, as an accountant, or it learns through those roles what the rules keep from the operator.
5. The consumer's procedure
A consumer accepts a capsule only after:
- Authenticity.
Verifier_Verifyon its own verifier instance with the capsule's view MUST returnVerified. - Canonicality.
Verifier_VerifyRoundwith the capsule's view and the view of the round of the capsule's number for the capsule's definition, read from the consumer's own participant, MUST returnPassed. A consumer that is not a reader cannot perform this check and SHOULD NOT accept the capsule. - Freshness.
Verifier_VerifyFreshnesswith the time the consumer cares about MUST returnPassed, or the consumer applies a policy of its own topublishedAt. - License. The capsule's
definitionMUST be the definition the consumer pinned, andcontent.licenseSHOULD resolve to a license the consumer sees, or is shown, whoseowneris the capsule's distributor and whose definition is the capsule's. - Chain. The round's signatories, as the Ledger API reports them,
SHOULD be the signatories of the definition the consumer pinned. In the
reference implementation both are the operator and the auditors, and the
auditors' authority over a round exists only inside
RoundHead_CreateRound, so such a round came from the chain.
A consumer that uses a capsule in a transaction with other parties performs checks 1 to 3 inside that transaction: every informee's participant re-executes them, so counterparties need not trust the consumer's reading.
6. The publisher's procedure
A publication is one exercise of RoundHead_CreateRound on the current
head. Every contract the transaction uses MUST be visible to the
submitter's participant, whatever authority the choice carries; in the
reference implementation these are the head, the canonical verifier and
the root license, so publication is open to whoever sees all three, by
observation or by explicit disclosure. A publisher that
loses the race on the head gets a failed submission, nothing is created,
and it retries on the new head.
7. Conformance
- A deployment conforms when it runs, for each data set, one
DataDefinition, oneVerifierthe definition points to, a chain ofRoundHeadandRoundcontracts, andLicenseandCapsulecontracts, all satisfying section 3. It MAY add contracts, choices and fields beyond the interfaces. - A verifier conforms when its template implements
Verifierunder 3.2. - A consumer conforms when it accepts a capsule only after the checks
of section 5. A consumer written against
PublishedDataPointalone reads a capsule but does not conform.
8. What the standard does not promise
- A capsule can be created directly. A template signed by its
distributor alone can always be created outside any license.
Verifier_Verifyrejects fabricated content; nothing rejects a genuine capsule that skipped the license. The only structural remedy, a co-signatory of the capsule, would see the capsule's audience. - License provenance is policed, not proven. Whether a license was issued through the chain is visible to the parties the implementation makes observers of it, and known to the licensor it names; it is not provable to a consumer from the interface alone.
- The operator learns who publishes and who holds licenses. What it does not learn is consumption.
9. Versioning
An interface package cannot be smart-contract-upgraded. A change to any
view, type or choice signature of caps-api-core-v1 is a new package,
caps-api-core-v2, which a deployment adopts by implementing both during
the transition, as the Token Standard did between CIP-0056 and CIP-0112.
Implementation packages, verifiers among them, MAY be
upgraded in place under Daml's smart-contract upgrade rules, which is where
the executable code lives for that reason.
Rationale
Interfaces, not templates. Oracles differ in signing schemes,
aggregation and payload encodings, and will keep differing. Everything
vendor-specific is behind Verifier; everything a consumer, a wallet or a
settlement contract needs to know is in the views and the choices. A
deployment may replace any template of the reference implementation and
remain conforming. The price is that the interface package is frozen for
its version; the executable code is kept out of it so that it can be
upgraded.
Views, never contract ids, on the verification path. This is the single rule from which the privacy guarantee follows. A verifier that fetched the capsule or the round would inform their signatories, which include the operator, of every verification. Passing the views as data costs the consumer nothing: it is an observer of both and already holds them. The same reasoning gives distribution by view as the private option, and the rule that a distribution informs its clients and, by default, nobody else is the principle the Token Standard V2 (CIP-0112) states for settlement choices: the set of informees only ever decreases along the chain.
A consumer's own verifier instance. The canonical instance a definition names is the reference the consumer copies its parameters from, not the contract it exercises. Requiring verdicts to be a pure function of arguments and parameters is what makes the copy equivalent, and it also makes every verdict reproducible by any party later, which is what lets the checks run inside a multi-party settlement.
A commitment in the round, not the data. Readers of the rounds learn that a fixing happened and when, and can check any capsule against it, without receiving the data. The round is the canonical anchor every reader shares; the data goes only where it is licensed to go. The requirement that the commitment cover exactly what a distribution copies unchanged is what makes a redistributed capsule verify against the same round as the root.
Lineage to the fixing, not to the path. Every capsule is anchored to the round of its number: a consumer proves that the content is the one fixed in that round, whatever chain of distributions brought it, and the chain itself is not observable from the capsule. A reference to the parent capsule would add nothing to the proof, since the round already binds the content, and following it would inform the parent's signatory. What an auditor traces is the fixing: the round, its commitment, and the signed payload every copy carries verbatim.
Attenuation is structural where the ledger can make it so, policed elsewhere. That a child cannot assert rights its parent does not hold is enforced by the ledger at the points where a choice is involved: a sublicense can be created only by a party the parent entitles, a license's licensees are fixed for its life, the root capsule's audience is the root license's licensees, and a license that names a delegate calls it in the same transaction as every distribution. What the ledger cannot enforce is that a capsule or a license was created through a choice at all: a template signed by one party is always directly creatable by that party. The standard says so (section 8) and gives the operator and the licensor the means to see and revoke rather than promise a guarantee the visibility model does not allow.
The head as a mutex. Consuming one contract per publication is the cheapest way Canton offers to make round numbers unique: concurrent publications on one head are a double spend, and the loser retries on the new head. This is the contention pattern Splice adopted for its own automation (CIP-0064), where every Super Validator may submit the same action and the ledger picks one. The standard does not rely on contract keys: the interface package stays on Daml-LF 2.1, which the Data Standard and Splice target, and a key lookup on the consumption path would inform the key's maintainers; an implementation on a later LF version may use keys for its own purposes. A k-of-n approval of every publication is likewise left to deployments that need it: the authority to publish flows from the head, so a propose-and-accept workflow around it is an implementation choice, paid for in publication latency.
Who signs the head and the rounds. On Canton every guarantee of the form "the operator cannot do X alone" is somebody's signature, and every signatory's participant is a confirming party of every transaction that touches the contract. Confirmation is validation, not consent: a participant cannot refuse a valid transaction, only be unavailable. The standard therefore leaves the signatories open and the reference implementation chooses co-signature by every auditor: the ledger excludes a fork of the chain, at the cost that an auditor's outage stops publication, which multi-hosting the auditors' parties addresses in topology. The alternatives are documented with the reference implementation: auditors as observers who acknowledge rather than co-sign, with a consumer-side check (a fork becomes detectable rather than excluded); a subset of co-signers with pause thresholds; and a governance party in a decentralized namespace with a k-of-n confirmation threshold. None changes the interfaces, which is the point: the consumer's chain check (section 5, check 5) is what adapts.
Checking signatories outside the verifier. A verifier sees views, and a view can carry any field its creator writes; signatories are facts of the ledger, visible in the Ledger API events. The chain check belongs to the consumer's application for that reason.
Provenance of licenses is policed, not proven. A license template signed by its owner alone can always be created directly, as can a capsule. The structural remedy, a second signatory of every capsule, would see every capsule's audience and defeat the privacy goal. The standard therefore leaves who observes or co-signs a license to the implementation: the reference makes the operator and the licensor observers, so that a license created outside the chain is visible to them the moment it exists and either may revoke it; a deployment may add accountants or other observers, or co-sign licenses, and detect a forged one on the ledger, at the cost of making those parties confirming parties of every distribution. What no variant can do is prove provenance to a consumer from the interface alone, and section 8 says so rather than promising what the ledger cannot deliver.
Building on the Canton Data Standard. A capsule is a
PublishedDataPoint, and payloads and license types use AnyValue, so
consumers of the Data Standard read CAPS feeds unchanged and the two
standards do not compete. CAPS does not extend PublishedDataPoint itself
because canonicality and licensing need contracts of their own (the round,
the head, the license), not more fields on the data point.
Delegates as the extension point. Accounting, metering and quotas vary by deployment and by jurisdiction; the standard fixes only that a license calls its delegate in the same transaction as the distribution, so that whatever a deployment records cannot be skipped by a distributor that uses the license. Who signs the delegate is the deployment's choice, with the trade-off between privacy and confirmation stated in 3.7. The reference repository ships an accounting delegate as an example; it is not part of the standard.
Community feedback. To be summarized after the cip-discuss thread.
Backwards compatibility
The proposal adds new interfaces and changes nothing that exists. Contracts
of oracles already deployed on Canton are unaffected; an oracle adopts CAPS
by deploying a conforming set of contracts alongside its existing ones and
a verifier for its scheme. Applications written against the Canton Data
Standard's PublishedDataPoint read CAPS capsules without change, and gain
the checks of section 5 when they adopt the Capsule and Verifier
interfaces. A CIP-0056 asset registry, or any settlement contract, consumes
a capsule through an ordinary contract read within the existing
stakeholder model, and may run checks 1 to 3 inside its own transaction so
that every informee's participant re-executes them; no new ledger
primitive is involved, and a wallet or dApp reaches the contracts through
the dApp API (CIP-0103) as it reaches any other. An oracle's off-chain
signing is
unchanged: the RedStone verifier consumes the payloads RedStone's nodes
already sign, and the Data Standard verifier the envelope that standard
defines. Later versions of the standard are new interface packages
(section 9), adopted by implementing both during a transition.
Reference implementation
The reference implementation is at https://github.com/redstone-finance/canton-access-privacy-standard-public; the tag this proposal refers to: TODO.
The repository contains the interface package caps-api-core-v1, a
reference implementation caps-core generic over the oracle (templates for
the definition and its bootstrap proposal, the head, the round, the license
and the capsule), two verifiers (caps-verifier-redstone for payloads
signed by RedStone oracle nodes, verified by the RedStone Daml SDK, and
caps-verifier-datastandard for data signed in the Canton Data Standard's
own envelope, verified by its codecs), an extended set of license kinds and
an accounting delegate as examples of extensions, archivers for capsules
and for rounds that apply one retention rule, and a Daml Script test suite
covering bootstrap, publication and its rejections, the race on the head,
pause, distribution by view and by id, sublicensing, revocation, round
retirement and every visibility claim of section 4. The
documentation includes the full specification, the data model, consumer
and implementer guides, the governance variants and the threat model.
Interface package hash at the tag: TODO.
The work is funded by the Development Fund (CIP-0082, governed by CIP-0100) under a grant whose first milestone includes this proposal. Code is licensed under Apache-2.0 (see License-Code).
Copyright
This CIP is licensed under CC0-1.0. The reference implementation is licensed under Apache-2.0.
Changelog
- 2026-10-23: initial draft.