Skip to content

Commit 92056a3

Browse files
NAOR YUVALNAOR YUVAL
authored andcommitted
docs: restore NFT as valid policy anchoring mechanism
NFT on XRPL is still supported for policy document anchoring (minting NFToken with policy hash URI). Only grant liveness via NFT (mint-on-issue / burn-on-revoke) was replaced by XLS-70 credentials. All 9 doc files now clearly distinguish: - NFT = policy document anchoring (supported) - XLS-70 credentials = grant liveness/revocation (new) Made-with: Cursor
1 parent d27f4c2 commit 92056a3

9 files changed

Lines changed: 49 additions & 23 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Import from `mpcp-service/sdk`.
118118
```
119119
mpcp-reference
120120
├── src
121-
│ ├── anchor/ # On-chain adapters: did:xrpl, HCS; grant liveness via XLS-70 credentials
121+
│ ├── anchor/ # On-chain adapters: did:xrpl, HCS, XRPL NFT policy anchoring, XLS-70 credential revocation
122122
│ ├── hash/ # Canonical JSON serialization and SHA-256 hashing
123123
│ ├── policy-core/ # Policy evaluation engine and types
124124
│ ├── protocol/ # Artifact types, schemas, SBA/PolicyGrant signing, Trust Bundles

docs/animation/MPCP_ANIMATION_PACK.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Narration:
6565

6666
## Scene 5 — Policy Anchoring
6767
Visual:
68-
Policy document hash flowing into a public ledger (Hedera HCS).
68+
Policy document hash flowing into a public ledger (Hedera HCS or XRPL NFT).
6969

7070
Narration:
7171
"An optional anchorRef on the PolicyGrant links it to a public ledger record — providing tamper-evident policy history for audit and dispute resolution."
@@ -113,7 +113,7 @@ Autonomous parking example
113113
Vehicle enters → policy → budget → Trust Gateway → XRPL settlement
114114

115115
Scene 5
116-
Policy document anchored to ledger (Hedera HCS)
116+
Policy document anchored to ledger (Hedera HCS or XRPL NFT)
117117

118118
Scene 6
119119
Verification replay animation

docs/implementation/dispute-verification.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const result = verifyDisputedSettlement({
1818
context: settlementVerificationContext,
1919
// Optional: ledger anchor result from policy document anchoring
2020
ledgerAnchor: {
21-
anchorRef: grant.anchorRef, // "hcs:0.0.12345:42"
21+
anchorRef: grant.anchorRef, // e.g. "hcs:0.0.12345:42" or "xrpl:nft:ABC123..."
2222
rail: "hedera-hcs",
2323
sequenceNumber: "42",
2424
topicId: "0.0.12345",

docs/implementation/intent-anchoring.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
Optional support for publishing MPCP policy documents to distributed ledgers. Provides public auditability, dispute protection, and tamper-evident policy history.
44

5-
**Hedera HCS** adapter is implemented (publish policy document to a topic). It returns an `anchorRef` that is stored on the PolicyGrant for **policy document** auditability and dispute resolution.
5+
**Hedera HCS** and **XRPL NFT** adapters support **policy document** anchoring: HCS publishes to a topic; the XRPL path encrypts (optional), stores ciphertext on IPFS, and records the policy via an NFToken whose URI points at that content (`anchorRef` = `xrpl:nft:{tokenId}` with the policy hash in the anchoring flow). Store the returned reference on the PolicyGrant for auditability and dispute resolution.
66

7-
> **Grant liveness** (revoking or invalidating a grant) is a **separate** mechanism: XRPL **XLS-70** credentials (`CredentialCreate` / `CredentialDelete`), not policy `anchorRef` on HCS.
8-
9-
> **Historical note:** An earlier **XRPL NFT** policy-anchor path (`xrpl:nft:{tokenId}`) existed in reference discussions; it is **removed / superseded** for anchoring. Use HCS for policy documents; use XLS-70 for grant state.
7+
> **Grant liveness** (revoking or invalidating a grant) is a **separate** mechanism: XRPL **XLS-70** credentials (`CredentialCreate` / `CredentialDelete`). That replaces the older **NFT mint-on-issue / burn-on-revoke** pattern for **grants**. Do not conflate XLS-70 grant credentials with **policy** `anchorRef` on HCS or XRPL NFT.
108
119
## Purpose
1210

@@ -21,33 +19,46 @@ The `anchorRef` field on a PolicyGrant identifies the on-chain location of the a
2119
| Format | Rail | Example |
2220
|--------|------|---------|
2321
| `hcs:{topicId}:{seq}` | Hedera HCS | `hcs:0.0.12345:42` |
22+
| `xrpl:nft:{tokenId}` | XRPL NFT (policy document URI) | `xrpl:nft:00080000...` |
2423

2524
## Usage
2625

2726
```typescript
28-
import { hederaHcsAnchorPolicyDocument } from "mpcp-service/anchor";
27+
import {
28+
hederaHcsAnchorPolicyDocument,
29+
xrplEncryptAndStorePolicyDocument,
30+
checkXrplNftRevocation,
31+
} from "mpcp-service/anchor";
2932

3033
const policyDoc = { version: "1.0", policyHash: "a1b2c3...", issuedAt: "2026-01-01T00:00:00Z" };
3134

3235
// Hedera HCS (requires MPCP_HCS_POLICY_TOPIC_ID, MPCP_HCS_OPERATOR_ID, MPCP_HCS_OPERATOR_KEY)
3336
const result = await hederaHcsAnchorPolicyDocument(policyDoc);
34-
// { anchorRef: "hcs:0.0.12345:42", rail: "hedera-hcs", anchoredAt: "..." }
37+
// { reference: "hcs:0.0.12345:42", rail: "hedera-hcs", anchoredAt: "..." }
38+
39+
// XRPL NFT path: encrypt + IPFS → CID for NFToken URI (`ipfs://{cid}`); mint off-chain / policy authority, then anchorRef = `xrpl:nft:{tokenId}`
40+
// const prep = await xrplEncryptAndStorePolicyDocument(policyDoc, { encryption: {...}, ipfsStore: myStore });
3541

36-
// Store the anchorRef on the PolicyGrant
42+
// Optional: verify the policy-anchor NFT still exists on XRPL (policy audit / tamper check).
43+
// This is not grant liveness — use XLS-70 credentials for that (see PolicyGrant).
44+
const nftStatus = await checkXrplNftRevocation("00080000ABCD...");
45+
// { revoked: false } if the anchor NFT still exists; { revoked: true } if burned
46+
47+
// Store the anchor reference on the PolicyGrant (maps to anchorRef on the grant)
3748
const grant = createPolicyGrant({
3849
policyHash: "a1b2c3",
3950
allowedRails: ["xrpl"],
4051
allowedAssets: [...],
4152
expiresAt: "2030-12-31T23:59:59Z",
42-
anchorRef: result.anchorRef,
53+
anchorRef: result.reference,
4354
});
4455
```
4556

4657
## PolicyAnchorResult
4758

4859
```typescript
4960
interface PolicyAnchorResult {
50-
anchorRef: string; // "hcs:{topicId}:{seq}"
61+
anchorRef: string; // "hcs:{topicId}:{seq}" | "xrpl:nft:{tokenId}" (SDK field: `reference`)
5162
rail: AnchorRail;
5263
txHash?: string; // Optional ledger record id (implementation-specific)
5364
topicId?: string; // Hedera HCS topic ID
@@ -75,6 +86,17 @@ The Hedera HCS adapter publishes policy documents to a Hedera Consensus Service
7586
- `MPCP_HCS_POLICY_TOPIC_ID` — HCS topic ID for policy anchoring
7687
- `HEDERA_NETWORK` (optional) — `testnet` or `mainnet`, default `testnet`
7788

89+
## XRPL NFT Adapter (policy document anchoring)
90+
91+
> **Scope:** This path is for **policy document anchoring** only (tamper-evident policy history on XRPL). **Grant liveness** (revocation) uses **XLS-70 Credentials** — see PolicyGrant and the XRPL profile; do not use NFToken burn as the grant revocation mechanism.
92+
93+
The reference SDK provides `xrplEncryptAndStorePolicyDocument` (in `mpcp-service/anchor`): it encrypts the policy document, uploads the ciphertext via an injected IPFS client, and returns a **CID** intended as the NFToken URI (`ipfs://{cid}`). **NFTokenMint** (and setting `anchorRef` to `xrpl:nft:{tokenId}`) is typically performed by the policy authority service, not inside the lightweight SDK.
94+
95+
**Requirements:**
96+
- Caller-supplied **IPFS store** (`PolicyDocumentIpfsStore`) — no bundled IPFS client
97+
- Encryption options when using encrypted submit mode (`PolicyAnchorEncryptionOptions`)
98+
- XRPL account with NFToken issuance rights for minting the policy anchor NFT
99+
78100
## XRPL Payment Memos
79101

80102
Every XRPL payment submitted via the Trust Gateway includes an `mpcp/grant-id` memo field. This provides a lightweight on-chain audit trail linking each payment to its PolicyGrant — even without a full policy document anchor.

docs/implementation/l1-ecosystem-evaluation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Adding a second rail is a protocol-level decision. It requires:
3939
| Identity | `did:xrpl` | On-ledger DID method; XLS-70 Credentials for grant liveness |
4040
| Offline friendliness | Strong | Trust Bundle + signature verification; no chain client needed |
4141
| Tooling | Good | `xrpl.js`, testnet faucet, well-documented |
42-
| MPCP integration | Deep | Anchor adapters, DID resolver, XLS-70 credential revocation, stablecoin profile, golden vectors |
42+
| MPCP integration | Deep | Anchor adapters, DID resolver, NFT policy anchoring, XLS-70 credential revocation, stablecoin profile, golden vectors |
4343

4444
**Assessment:** Production-ready for MPCP v1.0. No gaps.
4545

docs/implementation/verifier.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ If any check fails, verification fails with a specific reason.
2121
| SBA | Signature valid; expiresAt not passed; sessionId, policyHash match |
2222
| SBA → decision | Budget not exceeded; rail, asset, destination in allowlists |
2323
| Settlement | Amount, rail, destination, asset match SBA constraints |
24-
| anchorRef | If present on PolicyGrant, format validated (`hcs:{topicId}:{seq}`) |
24+
| anchorRef | If present on PolicyGrant, format validated (`hcs:{topicId}:{seq}` or `xrpl:nft:{tokenId}`) |
2525

2626
## Usage
2727

@@ -102,7 +102,7 @@ Settlement bundles for development and conformance testing may include `sbaPubli
102102

103103
## Dispute Verification
104104

105-
When a settlement is disputed, `verifyDisputedSettlement` runs full chain verification plus optional policy anchor verification. If the PolicyGrant has an `anchorRef` (e.g., to Hedera HCS), the anchor can be checked to confirm the policy document was published before the settlement.
105+
When a settlement is disputed, `verifyDisputedSettlement` runs full chain verification plus optional policy anchor verification. If the PolicyGrant has an `anchorRef` (e.g., to Hedera HCS or XRPL NFT), the anchor can be checked to confirm the policy document was published before the settlement.
106106

107107
See [Dispute Resolution](https://github.com/mpcp-protocol/mpcp-spec/blob/main/docs/guides/dispute-resolution.md) for the guide.
108108

docs/implementation/xrpl-stablecoin-profile.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Policies using this profile must include:
2626
- `allowedAssets`: Array of `{ kind: "IOU", currency: string, issuer: string }`
2727
- `destinationAllowlist` (in SBA): XRPL account addresses allowed as payment destinations
2828
- `maxAmountMinor`, `expiresAt` per standard MPCP
29-
- `anchorRef` (optional): on-chain policy document anchor (`hcs:{topicId}:{seq}`)
29+
- `anchorRef` (optional): on-chain policy document anchor (`hcs:{topicId}:{seq}` or `xrpl:nft:{tokenId}`)
3030

3131
## Wallet Expectations
3232

docs/reference/sdk.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const grant = createPolicyGrant({
3636
allowedAssets: [{ kind: "IOU", currency: "RLUSD", issuer: "rIssuer" }],
3737
expiresAt: "2030-12-31T23:59:59Z",
3838
// Optional: on-chain anchor reference for this policy document
39-
// anchorRef: "hcs:0.0.12345:42"
39+
// anchorRef: "hcs:0.0.12345:42" | "xrpl:nft:ABC123..."
4040
});
4141

4242
// Signed (requires MPCP_POLICY_GRANT_SIGNING_PRIVATE_KEY_PEM — returns null if not set)

docs/reference/service-api.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,19 @@ Publish a policy document to a ledger and return an `anchorRef` for use in Polic
6767

6868
```typescript
6969
// Hedera HCS (requires MPCP_HCS_POLICY_TOPIC_ID, MPCP_HCS_OPERATOR_ID, MPCP_HCS_OPERATOR_KEY)
70-
const result = await anchorPolicyDocument(policyDoc, { rail: "hedera-hcs" });
71-
// result.anchorRef: "hcs:{topicId}:{sequenceNumber}"
70+
const hcs = await anchorPolicyDocument(policyDoc, { rail: "hedera-hcs" });
71+
// hcs.anchorRef: "hcs:{topicId}:{sequenceNumber}"
72+
73+
// XRPL NFT — policy document anchoring (encrypted doc → IPFS URI on NFToken; mint completed by policy authority)
74+
const nft = await anchorPolicyDocument(policyDoc, { rail: "xrpl-nft" /* + encryption / ipfs options */ });
75+
// nft.anchorRef: "xrpl:nft:{tokenId}"
7276
```
7377

74-
Supported rail: **`hedera-hcs`** (policy document anchoring).
78+
Supported rails for **policy document** anchoring: **`hedera-hcs`**, **`xrpl-nft`**.
7579

76-
> **Removed / superseded:** The former `xrpl-nft` rail (NFTokenMint/Burn for policy anchors) is no longer supported. **Grant liveness** (whether a grant is still valid) is handled separately via **XLS-70** `CredentialCreate` / `CredentialDelete` on XRPL — not via policy `anchorRef`.
80+
> **Grant liveness** (whether a grant is still valid) is **not** defined by burning the policy anchor NFT. Use **XLS-70** `CredentialCreate` / `CredentialDelete` on XRPL for credential-based grant revocation. Policy `anchorRef` (HCS or XRPL NFT) remains the tamper-evident **policy document** anchor only.
7781
78-
The returned `anchorRef` can be stored on the PolicyGrant (`grant.anchorRef`) to provide on-chain auditability of the **policy document** (HCS).
82+
The returned `anchorRef` can be stored on the PolicyGrant (`grant.anchorRef`) to provide on-chain auditability of the **policy document**.
7983

8084
---
8185

0 commit comments

Comments
 (0)