Skip to content

Commit 7db7386

Browse files
naoryNAOR YUVALclaude
authored
feat(PR30): XRPL escrow budget fields in PolicyGrantLike (#48)
* feat(PR30): add budgetMinor, budgetEscrowRef, authorizedGateway, offlineMaxSinglePayment to PolicyGrantLike XRPL-escrow budget enforcement requires these PA-signed fields in the PolicyGrant so the Trust Gateway can enforce ceilings from a tamper-proof source rather than trusting agent-reported values. - PolicyGrantLike: budgetMinor, budgetCurrency, budgetEscrowRef, authorizedGateway, offlineMaxSinglePayment, offlineMaxSinglePaymentCurrency - policyGrantForVerificationSchema: Zod validators for all six fields (numeric strings validated via regex) - createPolicyGrant / CreatePolicyGrantInput: factory and input type updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: review corrections — JSDoc consistency and rail-agnostic wording - types.ts: authorizedGateway — remove XRPL-specific "address" wording, use rail-agnostic description - types.ts: offlineMaxSinglePayment — "(drops)" → "minor units" (rail-agnostic) - types.ts: budgetEscrowRef example — add lockId to eth example for consistency with spec - createPolicyGrant.ts: add missing JSDoc for authorizedGateway, offlineMaxSinglePayment, offlineMaxSinglePaymentCurrency (other new fields had docs, these three did not) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: NAOR YUVAL <naoryuval@NAORs-MacBook-Air.local> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e6ad583 commit 7db7386

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

src/protocol/schema/verifySchemas.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export const policyGrantForVerificationSchema = z
2525
revocationEndpoint: z.string().url().optional(),
2626
allowedPurposes: z.array(z.string()).optional(),
2727
anchorRef: z.string().optional(),
28+
budgetMinor: z.string().regex(/^\d+$/).optional(),
29+
budgetCurrency: z.string().optional(),
30+
budgetEscrowRef: z.string().optional(),
31+
authorizedGateway: z.string().optional(),
32+
offlineMaxSinglePayment: z.string().regex(/^\d+$/).optional(),
33+
offlineMaxSinglePaymentCurrency: z.string().optional(),
2834
})
2935
.refine((g) => g.expiresAt != null || g.expiresAtISO != null, {
3036
message: "policy_grant_missing_expiry",

src/sdk/createPolicyGrant.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ export interface CreatePolicyGrantInput {
1212
revocationEndpoint?: string;
1313
allowedPurposes?: string[];
1414
anchorRef?: string;
15+
/** Total authorized spend in minor units (e.g. drops for XRP). Signed by the PA. */
16+
budgetMinor?: string;
17+
/** Currency code for budgetMinor (e.g. "XRP"). Required when budgetMinor is set. */
18+
budgetCurrency?: string;
19+
/** On-chain escrow locking budgetMinor. Format: "xrpl:escrow:{account}:{sequence}". Signed by the PA. */
20+
budgetEscrowRef?: string;
21+
/** Address of the only gateway authorized to spend against this grant's escrow. Rail-specific format. PA-signed. */
22+
authorizedGateway?: string;
23+
/** PA-signed per-transaction cap for offline merchant acceptance, in minor units (see offlineMaxSinglePaymentCurrency). */
24+
offlineMaxSinglePayment?: string;
25+
/** Currency code for offlineMaxSinglePayment (e.g. "XRP"). */
26+
offlineMaxSinglePaymentCurrency?: string;
1527
}
1628

1729
/**
@@ -30,5 +42,11 @@ export function createPolicyGrant(input: CreatePolicyGrantInput): PolicyGrantLik
3042
...(input.revocationEndpoint ? { revocationEndpoint: input.revocationEndpoint } : {}),
3143
...(input.allowedPurposes ? { allowedPurposes: input.allowedPurposes } : {}),
3244
...(input.anchorRef ? { anchorRef: input.anchorRef } : {}),
45+
...(input.budgetMinor ? { budgetMinor: input.budgetMinor } : {}),
46+
...(input.budgetCurrency ? { budgetCurrency: input.budgetCurrency } : {}),
47+
...(input.budgetEscrowRef ? { budgetEscrowRef: input.budgetEscrowRef } : {}),
48+
...(input.authorizedGateway ? { authorizedGateway: input.authorizedGateway } : {}),
49+
...(input.offlineMaxSinglePayment ? { offlineMaxSinglePayment: input.offlineMaxSinglePayment } : {}),
50+
...(input.offlineMaxSinglePaymentCurrency ? { offlineMaxSinglePaymentCurrency: input.offlineMaxSinglePaymentCurrency } : {}),
3351
};
3452
}

src/verifier/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@ export interface PolicyGrantLike {
1616
revocationEndpoint?: string;
1717
allowedPurposes?: string[];
1818
anchorRef?: string; // "hcs:{topicId}:{seq}" | "xrpl:nft:{tokenId}"
19+
/** Total authorized spend for this grant in minor units (e.g. drops for XRP). PA-signed. */
20+
budgetMinor?: string;
21+
/** Currency code for budgetMinor (e.g. "XRP"). Required when budgetMinor is set. */
22+
budgetCurrency?: string;
23+
/**
24+
* On-chain budget escrow reference — proof that budgetMinor is locked on-chain.
25+
* Format is rail-specific:
26+
* XRPL: "xrpl:escrow:{account}:{sequence}"
27+
* (future) "eth:timelock:{contract}:{lockId}"
28+
* Included in the PA signature, making the escrow commitment tamper-evident.
29+
*/
30+
budgetEscrowRef?: string;
31+
/** Address of the only gateway authorized to spend against this grant's escrow. Rail-specific format. PA-signed. */
32+
authorizedGateway?: string;
33+
/** PA-signed per-transaction cap for offline merchant acceptance, in minor units (see offlineMaxSinglePaymentCurrency). */
34+
offlineMaxSinglePayment?: string;
35+
/** Currency for offlineMaxSinglePayment (e.g. "XRP"). */
36+
offlineMaxSinglePaymentCurrency?: string;
1937
}
2038

2139
/** Shared verification result for all verifiers. Use with CLI and callers. */

0 commit comments

Comments
 (0)