@agenticprimitives/payments 0.0.0-alpha.4 → 0.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entitlement/index.d.ts +92 -0
- package/dist/entitlement/index.d.ts.map +1 -0
- package/dist/entitlement/index.js +93 -0
- package/dist/entitlement/index.js.map +1 -0
- package/dist/entitlement/voucher.d.ts +78 -0
- package/dist/entitlement/voucher.d.ts.map +1 -0
- package/dist/entitlement/voucher.js +102 -0
- package/dist/entitlement/voucher.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/mandate-sign.d.ts +173 -0
- package/dist/mandate-sign.d.ts.map +1 -0
- package/dist/mandate-sign.js +147 -0
- package/dist/mandate-sign.js.map +1 -0
- package/dist/mandate.d.ts +33 -0
- package/dist/mandate.d.ts.map +1 -0
- package/dist/mandate.js +40 -0
- package/dist/mandate.js.map +1 -0
- package/dist/ops.d.ts +55 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +66 -0
- package/dist/ops.js.map +1 -0
- package/dist/rails/escrow.d.ts +143 -0
- package/dist/rails/escrow.d.ts.map +1 -0
- package/dist/rails/escrow.js +90 -0
- package/dist/rails/escrow.js.map +1 -0
- package/dist/rails/invoice.d.ts +65 -0
- package/dist/rails/invoice.d.ts.map +1 -0
- package/dist/rails/invoice.js +57 -0
- package/dist/rails/invoice.js.map +1 -0
- package/dist/rails/recurring.d.ts +56 -0
- package/dist/rails/recurring.d.ts.map +1 -0
- package/dist/rails/recurring.js +58 -0
- package/dist/rails/recurring.js.map +1 -0
- package/dist/rails/wallet.d.ts +16 -0
- package/dist/rails/wallet.d.ts.map +1 -0
- package/dist/rails/wallet.js +20 -0
- package/dist/rails/wallet.js.map +1 -0
- package/dist/rails/x402/executor.d.ts +17 -1
- package/dist/rails/x402/executor.d.ts.map +1 -1
- package/dist/rails/x402/executor.js +24 -2
- package/dist/rails/x402/executor.js.map +1 -1
- package/dist/receipt.d.ts +36 -0
- package/dist/receipt.d.ts.map +1 -0
- package/dist/receipt.js +50 -0
- package/dist/receipt.js.map +1 -0
- package/dist/refund.d.ts +29 -0
- package/dist/refund.d.ts.map +1 -0
- package/dist/refund.js +19 -0
- package/dist/refund.js.map +1 -0
- package/dist/split.d.ts +27 -0
- package/dist/split.d.ts.map +1 -0
- package/dist/split.js +33 -0
- package/dist/split.js.map +1 -0
- package/dist/transfer.d.ts +51 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transfer.js +54 -0
- package/dist/transfer.js.map +1 -0
- package/package.json +6 -5
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escrow rail (spec 243 §5.5, over PaymentEscrow.sol) — hold-and-capture for an order.
|
|
3
|
+
*
|
|
4
|
+
* Powers the deliver-then-pay flow: payer deposits a hold keyed by `orderHash` → provider
|
|
5
|
+
* fulfils → `release` captures to the payee (and the app mints the entitlement, pay-AFTER-
|
|
6
|
+
* fulfillment) → on failure/expiry `refund`/`reclaim` returns the funds. Builders emit the
|
|
7
|
+
* `{to: escrow, value, data}` calls an SA executes; deposit needs a prior `approve`
|
|
8
|
+
* (`buildErc20Approve`). App reads hold state via `getHold` (readContract), not log scans.
|
|
9
|
+
*/
|
|
10
|
+
import { type Address } from 'viem';
|
|
11
|
+
import type { TransferPlan } from '../transfer.js';
|
|
12
|
+
import type { Hex32 } from '../index.js';
|
|
13
|
+
/** Mirrors PaymentEscrow.Status. */
|
|
14
|
+
export declare enum EscrowStatus {
|
|
15
|
+
None = 0,
|
|
16
|
+
Held = 1,
|
|
17
|
+
Captured = 2,
|
|
18
|
+
Refunded = 3,
|
|
19
|
+
Reclaimed = 4
|
|
20
|
+
}
|
|
21
|
+
export declare const ESCROW_ABI: readonly [{
|
|
22
|
+
readonly type: "function";
|
|
23
|
+
readonly name: "deposit";
|
|
24
|
+
readonly stateMutability: "nonpayable";
|
|
25
|
+
readonly inputs: readonly [{
|
|
26
|
+
readonly name: "orderHash";
|
|
27
|
+
readonly type: "bytes32";
|
|
28
|
+
}, {
|
|
29
|
+
readonly name: "asset";
|
|
30
|
+
readonly type: "address";
|
|
31
|
+
}, {
|
|
32
|
+
readonly name: "amount";
|
|
33
|
+
readonly type: "uint256";
|
|
34
|
+
}, {
|
|
35
|
+
readonly name: "payee";
|
|
36
|
+
readonly type: "address";
|
|
37
|
+
}, {
|
|
38
|
+
readonly name: "refundTo";
|
|
39
|
+
readonly type: "address";
|
|
40
|
+
}, {
|
|
41
|
+
readonly name: "releaser";
|
|
42
|
+
readonly type: "address";
|
|
43
|
+
}, {
|
|
44
|
+
readonly name: "expiry";
|
|
45
|
+
readonly type: "uint64";
|
|
46
|
+
}];
|
|
47
|
+
readonly outputs: readonly [];
|
|
48
|
+
}, {
|
|
49
|
+
readonly type: "function";
|
|
50
|
+
readonly name: "release";
|
|
51
|
+
readonly stateMutability: "nonpayable";
|
|
52
|
+
readonly inputs: readonly [{
|
|
53
|
+
readonly name: "orderHash";
|
|
54
|
+
readonly type: "bytes32";
|
|
55
|
+
}];
|
|
56
|
+
readonly outputs: readonly [];
|
|
57
|
+
}, {
|
|
58
|
+
readonly type: "function";
|
|
59
|
+
readonly name: "refund";
|
|
60
|
+
readonly stateMutability: "nonpayable";
|
|
61
|
+
readonly inputs: readonly [{
|
|
62
|
+
readonly name: "orderHash";
|
|
63
|
+
readonly type: "bytes32";
|
|
64
|
+
}];
|
|
65
|
+
readonly outputs: readonly [];
|
|
66
|
+
}, {
|
|
67
|
+
readonly type: "function";
|
|
68
|
+
readonly name: "reclaim";
|
|
69
|
+
readonly stateMutability: "nonpayable";
|
|
70
|
+
readonly inputs: readonly [{
|
|
71
|
+
readonly name: "orderHash";
|
|
72
|
+
readonly type: "bytes32";
|
|
73
|
+
}];
|
|
74
|
+
readonly outputs: readonly [];
|
|
75
|
+
}, {
|
|
76
|
+
readonly type: "function";
|
|
77
|
+
readonly name: "getHold";
|
|
78
|
+
readonly stateMutability: "view";
|
|
79
|
+
readonly inputs: readonly [{
|
|
80
|
+
readonly name: "orderHash";
|
|
81
|
+
readonly type: "bytes32";
|
|
82
|
+
}];
|
|
83
|
+
readonly outputs: readonly [{
|
|
84
|
+
readonly type: "tuple";
|
|
85
|
+
readonly components: readonly [{
|
|
86
|
+
readonly name: "payer";
|
|
87
|
+
readonly type: "address";
|
|
88
|
+
}, {
|
|
89
|
+
readonly name: "asset";
|
|
90
|
+
readonly type: "address";
|
|
91
|
+
}, {
|
|
92
|
+
readonly name: "amount";
|
|
93
|
+
readonly type: "uint256";
|
|
94
|
+
}, {
|
|
95
|
+
readonly name: "payee";
|
|
96
|
+
readonly type: "address";
|
|
97
|
+
}, {
|
|
98
|
+
readonly name: "refundTo";
|
|
99
|
+
readonly type: "address";
|
|
100
|
+
}, {
|
|
101
|
+
readonly name: "releaser";
|
|
102
|
+
readonly type: "address";
|
|
103
|
+
}, {
|
|
104
|
+
readonly name: "expiry";
|
|
105
|
+
readonly type: "uint64";
|
|
106
|
+
}, {
|
|
107
|
+
readonly name: "status";
|
|
108
|
+
readonly type: "uint8";
|
|
109
|
+
}];
|
|
110
|
+
}];
|
|
111
|
+
}, {
|
|
112
|
+
readonly type: "function";
|
|
113
|
+
readonly name: "statusOf";
|
|
114
|
+
readonly stateMutability: "view";
|
|
115
|
+
readonly inputs: readonly [{
|
|
116
|
+
readonly name: "orderHash";
|
|
117
|
+
readonly type: "bytes32";
|
|
118
|
+
}];
|
|
119
|
+
readonly outputs: readonly [{
|
|
120
|
+
readonly type: "uint8";
|
|
121
|
+
}];
|
|
122
|
+
}];
|
|
123
|
+
export interface EscrowDepositInput {
|
|
124
|
+
escrow: Address;
|
|
125
|
+
orderHash: Hex32;
|
|
126
|
+
asset: Address;
|
|
127
|
+
amount: bigint;
|
|
128
|
+
payee: Address;
|
|
129
|
+
/** where refund/reclaim returns; defaults on-chain to the payer (msg.sender) when zero */
|
|
130
|
+
refundTo?: Address;
|
|
131
|
+
/** extra address allowed to release besides the payee; 0 = payee-only */
|
|
132
|
+
releaser?: Address;
|
|
133
|
+
expiry: number;
|
|
134
|
+
}
|
|
135
|
+
/** The deposit call (the payer SA must `approve` the escrow for `asset` first). */
|
|
136
|
+
export declare function buildEscrowDeposit(input: EscrowDepositInput): TransferPlan;
|
|
137
|
+
/** Capture the hold to the payee (payee or configured releaser executes). */
|
|
138
|
+
export declare function buildEscrowRelease(escrow: Address, orderHash: Hex32): TransferPlan;
|
|
139
|
+
/** Payee-consented refund to the payer, before capture. */
|
|
140
|
+
export declare function buildEscrowRefund(escrow: Address, orderHash: Hex32): TransferPlan;
|
|
141
|
+
/** Payer reclaims after expiry (never released). */
|
|
142
|
+
export declare function buildEscrowReclaim(escrow: Address, orderHash: Hex32): TransferPlan;
|
|
143
|
+
//# sourceMappingURL=escrow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escrow.d.ts","sourceRoot":"","sources":["../../src/rails/escrow.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAsB,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,oCAAoC;AACpC,oBAAY,YAAY;IACtB,IAAI,IAAI;IACR,IAAI,IAAI;IACR,QAAQ,IAAI;IACZ,QAAQ,IAAI;IACZ,SAAS,IAAI;CACd;AAED,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyCb,CAAC;AAEX,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,YAAY,CAU1E;AAMD,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,GAAG,YAAY,CAElF;AACD,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,GAAG,YAAY,CAEjF;AACD,oDAAoD;AACpD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,GAAG,YAAY,CAElF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escrow rail (spec 243 §5.5, over PaymentEscrow.sol) — hold-and-capture for an order.
|
|
3
|
+
*
|
|
4
|
+
* Powers the deliver-then-pay flow: payer deposits a hold keyed by `orderHash` → provider
|
|
5
|
+
* fulfils → `release` captures to the payee (and the app mints the entitlement, pay-AFTER-
|
|
6
|
+
* fulfillment) → on failure/expiry `refund`/`reclaim` returns the funds. Builders emit the
|
|
7
|
+
* `{to: escrow, value, data}` calls an SA executes; deposit needs a prior `approve`
|
|
8
|
+
* (`buildErc20Approve`). App reads hold state via `getHold` (readContract), not log scans.
|
|
9
|
+
*/
|
|
10
|
+
import { encodeFunctionData } from 'viem';
|
|
11
|
+
/** Mirrors PaymentEscrow.Status. */
|
|
12
|
+
export var EscrowStatus;
|
|
13
|
+
(function (EscrowStatus) {
|
|
14
|
+
EscrowStatus[EscrowStatus["None"] = 0] = "None";
|
|
15
|
+
EscrowStatus[EscrowStatus["Held"] = 1] = "Held";
|
|
16
|
+
EscrowStatus[EscrowStatus["Captured"] = 2] = "Captured";
|
|
17
|
+
EscrowStatus[EscrowStatus["Refunded"] = 3] = "Refunded";
|
|
18
|
+
EscrowStatus[EscrowStatus["Reclaimed"] = 4] = "Reclaimed";
|
|
19
|
+
})(EscrowStatus || (EscrowStatus = {}));
|
|
20
|
+
export const ESCROW_ABI = [
|
|
21
|
+
{
|
|
22
|
+
type: 'function',
|
|
23
|
+
name: 'deposit',
|
|
24
|
+
stateMutability: 'nonpayable',
|
|
25
|
+
inputs: [
|
|
26
|
+
{ name: 'orderHash', type: 'bytes32' },
|
|
27
|
+
{ name: 'asset', type: 'address' },
|
|
28
|
+
{ name: 'amount', type: 'uint256' },
|
|
29
|
+
{ name: 'payee', type: 'address' },
|
|
30
|
+
{ name: 'refundTo', type: 'address' },
|
|
31
|
+
{ name: 'releaser', type: 'address' },
|
|
32
|
+
{ name: 'expiry', type: 'uint64' },
|
|
33
|
+
],
|
|
34
|
+
outputs: [],
|
|
35
|
+
},
|
|
36
|
+
{ type: 'function', name: 'release', stateMutability: 'nonpayable', inputs: [{ name: 'orderHash', type: 'bytes32' }], outputs: [] },
|
|
37
|
+
{ type: 'function', name: 'refund', stateMutability: 'nonpayable', inputs: [{ name: 'orderHash', type: 'bytes32' }], outputs: [] },
|
|
38
|
+
{ type: 'function', name: 'reclaim', stateMutability: 'nonpayable', inputs: [{ name: 'orderHash', type: 'bytes32' }], outputs: [] },
|
|
39
|
+
{
|
|
40
|
+
type: 'function',
|
|
41
|
+
name: 'getHold',
|
|
42
|
+
stateMutability: 'view',
|
|
43
|
+
inputs: [{ name: 'orderHash', type: 'bytes32' }],
|
|
44
|
+
outputs: [
|
|
45
|
+
{
|
|
46
|
+
type: 'tuple',
|
|
47
|
+
components: [
|
|
48
|
+
{ name: 'payer', type: 'address' },
|
|
49
|
+
{ name: 'asset', type: 'address' },
|
|
50
|
+
{ name: 'amount', type: 'uint256' },
|
|
51
|
+
{ name: 'payee', type: 'address' },
|
|
52
|
+
{ name: 'refundTo', type: 'address' },
|
|
53
|
+
{ name: 'releaser', type: 'address' },
|
|
54
|
+
{ name: 'expiry', type: 'uint64' },
|
|
55
|
+
{ name: 'status', type: 'uint8' },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{ type: 'function', name: 'statusOf', stateMutability: 'view', inputs: [{ name: 'orderHash', type: 'bytes32' }], outputs: [{ type: 'uint8' }] },
|
|
61
|
+
];
|
|
62
|
+
const ZERO = '0x0000000000000000000000000000000000000000';
|
|
63
|
+
/** The deposit call (the payer SA must `approve` the escrow for `asset` first). */
|
|
64
|
+
export function buildEscrowDeposit(input) {
|
|
65
|
+
return {
|
|
66
|
+
to: input.escrow,
|
|
67
|
+
value: 0n,
|
|
68
|
+
data: encodeFunctionData({
|
|
69
|
+
abi: ESCROW_ABI,
|
|
70
|
+
functionName: 'deposit',
|
|
71
|
+
args: [input.orderHash, input.asset, input.amount, input.payee, input.refundTo ?? ZERO, input.releaser ?? ZERO, BigInt(input.expiry)],
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function call(escrow, fn, orderHash) {
|
|
76
|
+
return { to: escrow, value: 0n, data: encodeFunctionData({ abi: ESCROW_ABI, functionName: fn, args: [orderHash] }) };
|
|
77
|
+
}
|
|
78
|
+
/** Capture the hold to the payee (payee or configured releaser executes). */
|
|
79
|
+
export function buildEscrowRelease(escrow, orderHash) {
|
|
80
|
+
return call(escrow, 'release', orderHash);
|
|
81
|
+
}
|
|
82
|
+
/** Payee-consented refund to the payer, before capture. */
|
|
83
|
+
export function buildEscrowRefund(escrow, orderHash) {
|
|
84
|
+
return call(escrow, 'refund', orderHash);
|
|
85
|
+
}
|
|
86
|
+
/** Payer reclaims after expiry (never released). */
|
|
87
|
+
export function buildEscrowReclaim(escrow, orderHash) {
|
|
88
|
+
return call(escrow, 'reclaim', orderHash);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=escrow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escrow.js","sourceRoot":"","sources":["../../src/rails/escrow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invoice rail (spec 243 §5.5, new) — request-for-payment (Request-Network pattern).
|
|
3
|
+
*
|
|
4
|
+
* A push artifact: the issuer publishes an `Invoice` (line items + total + payee + due);
|
|
5
|
+
* the payer reviews and pays it via the wallet rail, deriving a closed mandate bound to
|
|
6
|
+
* `invoiceId`/`orderHash`. The receipt links invoice ↔ settlement; "is this invoice paid?"
|
|
7
|
+
* resolves from receipts, never `eth_getLogs` (ADR-0012). No protocol dependency.
|
|
8
|
+
*/
|
|
9
|
+
import { type Address } from 'viem';
|
|
10
|
+
import type { TransferPlan } from '../transfer.js';
|
|
11
|
+
import type { PaymentMandate, AssetRef, Hex32 } from '../index.js';
|
|
12
|
+
export interface InvoiceLineItem {
|
|
13
|
+
description: string;
|
|
14
|
+
amount: bigint;
|
|
15
|
+
}
|
|
16
|
+
export interface Invoice {
|
|
17
|
+
invoiceId: Hex32;
|
|
18
|
+
issuer: Address;
|
|
19
|
+
/** treasury that receives payment — MAY differ from the issuer */
|
|
20
|
+
payTo: Address;
|
|
21
|
+
lineItems: InvoiceLineItem[];
|
|
22
|
+
amount: bigint;
|
|
23
|
+
asset: AssetRef;
|
|
24
|
+
chain: number;
|
|
25
|
+
/** due time (unix seconds) — becomes the mandate's expiry at pay time */
|
|
26
|
+
dueAt: number;
|
|
27
|
+
/** hash of the memo body (body lives in a vault — privacy §6) */
|
|
28
|
+
memoHash: Hex32;
|
|
29
|
+
/** optional ExchangeOrder linkage (273/274); defaults to `invoiceId` at pay time */
|
|
30
|
+
orderHash?: Hex32;
|
|
31
|
+
}
|
|
32
|
+
export interface InvoiceInput {
|
|
33
|
+
issuer: Address;
|
|
34
|
+
payTo: Address;
|
|
35
|
+
lineItems: InvoiceLineItem[];
|
|
36
|
+
asset: AssetRef;
|
|
37
|
+
chain: number;
|
|
38
|
+
dueAt: number;
|
|
39
|
+
nonce: bigint;
|
|
40
|
+
memo?: string;
|
|
41
|
+
orderHash?: Hex32;
|
|
42
|
+
}
|
|
43
|
+
export declare function computeInvoiceId(args: {
|
|
44
|
+
issuer: Address;
|
|
45
|
+
payTo: Address;
|
|
46
|
+
amount: bigint;
|
|
47
|
+
asset: Address;
|
|
48
|
+
chain: number;
|
|
49
|
+
nonce: bigint;
|
|
50
|
+
}): Hex32;
|
|
51
|
+
/** Build an invoice; `amount` = sum of line items. */
|
|
52
|
+
export declare function buildInvoice(input: InvoiceInput): Invoice;
|
|
53
|
+
/**
|
|
54
|
+
* Pay an invoice via the wallet rail. Derives a closed mandate bound to the invoice
|
|
55
|
+
* (`orderHash = invoice.orderHash ?? invoiceId`) + the transfer plan. Sign the returned
|
|
56
|
+
* mandate with `signPaymentMandate`, then submit `plan`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function payInvoice(invoice: Invoice, payer: Address, opts: {
|
|
59
|
+
nonce: bigint;
|
|
60
|
+
validFrom?: number;
|
|
61
|
+
}): {
|
|
62
|
+
mandate: PaymentMandate;
|
|
63
|
+
plan: TransferPlan;
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=invoice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoice.d.ts","sourceRoot":"","sources":["../../src/rails/invoice.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAA2C,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAG7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAInE,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,QAAQ,EAAE,KAAK,CAAC;IAChB,oFAAoF;IACpF,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAO/I;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAezD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAiBzJ"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invoice rail (spec 243 §5.5, new) — request-for-payment (Request-Network pattern).
|
|
3
|
+
*
|
|
4
|
+
* A push artifact: the issuer publishes an `Invoice` (line items + total + payee + due);
|
|
5
|
+
* the payer reviews and pays it via the wallet rail, deriving a closed mandate bound to
|
|
6
|
+
* `invoiceId`/`orderHash`. The receipt links invoice ↔ settlement; "is this invoice paid?"
|
|
7
|
+
* resolves from receipts, never `eth_getLogs` (ADR-0012). No protocol dependency.
|
|
8
|
+
*/
|
|
9
|
+
import { keccak256, encodeAbiParameters, toBytes } from 'viem';
|
|
10
|
+
import { buildClosedMandate } from '../mandate.js';
|
|
11
|
+
import { buildWalletTransferPlan } from './wallet.js';
|
|
12
|
+
const ZERO32 = ('0x' + '00'.repeat(32));
|
|
13
|
+
export function computeInvoiceId(args) {
|
|
14
|
+
return keccak256(encodeAbiParameters([{ type: 'address' }, { type: 'address' }, { type: 'uint256' }, { type: 'address' }, { type: 'uint256' }, { type: 'uint256' }], [args.issuer, args.payTo, args.amount, args.asset, BigInt(args.chain), args.nonce]));
|
|
15
|
+
}
|
|
16
|
+
/** Build an invoice; `amount` = sum of line items. */
|
|
17
|
+
export function buildInvoice(input) {
|
|
18
|
+
const amount = input.lineItems.reduce((s, li) => s + li.amount, 0n);
|
|
19
|
+
if (amount <= 0n)
|
|
20
|
+
throw new Error('[invoice] amount must be > 0');
|
|
21
|
+
return {
|
|
22
|
+
invoiceId: computeInvoiceId({ issuer: input.issuer, payTo: input.payTo, amount, asset: input.asset.id, chain: input.chain, nonce: input.nonce }),
|
|
23
|
+
issuer: input.issuer,
|
|
24
|
+
payTo: input.payTo,
|
|
25
|
+
lineItems: input.lineItems,
|
|
26
|
+
amount,
|
|
27
|
+
asset: input.asset,
|
|
28
|
+
chain: input.chain,
|
|
29
|
+
dueAt: input.dueAt,
|
|
30
|
+
memoHash: input.memo ? keccak256(toBytes(input.memo)) : ZERO32,
|
|
31
|
+
orderHash: input.orderHash,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pay an invoice via the wallet rail. Derives a closed mandate bound to the invoice
|
|
36
|
+
* (`orderHash = invoice.orderHash ?? invoiceId`) + the transfer plan. Sign the returned
|
|
37
|
+
* mandate with `signPaymentMandate`, then submit `plan`.
|
|
38
|
+
*/
|
|
39
|
+
export function payInvoice(invoice, payer, opts) {
|
|
40
|
+
const orderHash = invoice.orderHash ?? invoice.invoiceId;
|
|
41
|
+
const mandate = buildClosedMandate({
|
|
42
|
+
rail: 'wallet',
|
|
43
|
+
payer,
|
|
44
|
+
payee: invoice.payTo,
|
|
45
|
+
asset: invoice.asset,
|
|
46
|
+
amount: invoice.amount,
|
|
47
|
+
chain: invoice.chain,
|
|
48
|
+
nonce: opts.nonce,
|
|
49
|
+
validFrom: opts.validFrom,
|
|
50
|
+
expiresAt: invoice.dueAt,
|
|
51
|
+
orderHash,
|
|
52
|
+
legId: invoice.invoiceId,
|
|
53
|
+
reasonHash: invoice.memoHash,
|
|
54
|
+
});
|
|
55
|
+
return { mandate, plan: buildWalletTransferPlan(mandate) };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=invoice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoice.js","sourceRoot":"","sources":["../../src/rails/invoice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recurring profile (spec 243 §5.5 / PMT-10) — NOT a rail, a mandate pattern.
|
|
3
|
+
*
|
|
4
|
+
* The payer authorizes ONCE (an open payment delegation whose caveats carry the per-charge
|
|
5
|
+
* cap + the frequency window + the aggregate cap); each period derives a CLOSED per-charge
|
|
6
|
+
* mandate settled via the wallet rail. The `PaymentEnforcer`'s on-chain frequency window +
|
|
7
|
+
* aggregate cap do the real enforcement — `recurringCaveatParams` returns the values the app
|
|
8
|
+
* feeds to `delegation.buildPaymentMandateCaveats` (payments doesn't runtime-import delegation).
|
|
9
|
+
*/
|
|
10
|
+
import type { Address } from '@agenticprimitives/types';
|
|
11
|
+
import type { TransferPlan } from '../transfer.js';
|
|
12
|
+
import type { PaymentMandate, AssetRef, Hex32 } from '../index.js';
|
|
13
|
+
export interface RecurringInput {
|
|
14
|
+
payer: Address;
|
|
15
|
+
payee: Address;
|
|
16
|
+
asset: AssetRef;
|
|
17
|
+
chain: number;
|
|
18
|
+
amountPerPeriod: bigint;
|
|
19
|
+
windowSeconds: number;
|
|
20
|
+
/** total spend ceiling across all periods (aggregate cap) */
|
|
21
|
+
totalCap: bigint;
|
|
22
|
+
validFrom: number;
|
|
23
|
+
validUntil: number;
|
|
24
|
+
/** base nonce; period N's charge uses `startNonce + N` */
|
|
25
|
+
startNonce: bigint;
|
|
26
|
+
}
|
|
27
|
+
export interface RecurringTemplate extends RecurringInput {
|
|
28
|
+
templateId: Hex32;
|
|
29
|
+
/** number of periods the totalCap covers at amountPerPeriod */
|
|
30
|
+
periods: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function buildRecurringTemplate(input: RecurringInput): RecurringTemplate;
|
|
33
|
+
export interface RecurringCaveatParams {
|
|
34
|
+
maxAmountPerCharge: bigint;
|
|
35
|
+
maxAggregate: bigint;
|
|
36
|
+
maxRedemptionsPerWindow: number;
|
|
37
|
+
windowSeconds: number;
|
|
38
|
+
validUntil: number;
|
|
39
|
+
}
|
|
40
|
+
/** The values the app feeds to `delegation.buildPaymentMandateCaveats` for the one-time authorization. */
|
|
41
|
+
export declare function recurringCaveatParams(t: RecurringTemplate): RecurringCaveatParams;
|
|
42
|
+
/** The time window in which period N may be charged (the enforcer rejects an early re-charge). */
|
|
43
|
+
export declare function periodWindow(t: RecurringTemplate, period: number): {
|
|
44
|
+
start: number;
|
|
45
|
+
end: number;
|
|
46
|
+
};
|
|
47
|
+
/** Derive the closed per-charge mandate + transfer plan for period N. Sign the mandate, then settle. */
|
|
48
|
+
export declare function deriveScheduledCharge(t: RecurringTemplate, period: number): {
|
|
49
|
+
mandate: PaymentMandate;
|
|
50
|
+
plan: TransferPlan;
|
|
51
|
+
window: {
|
|
52
|
+
start: number;
|
|
53
|
+
end: number;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=recurring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurring.d.ts","sourceRoot":"","sources":["../../src/rails/recurring.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAIxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,UAAU,EAAE,KAAK,CAAC;IAClB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,CAW/E;AAED,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,iBAAiB,GAAG,qBAAqB,CAQjF;AAED,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAGjG;AAED,wGAAwG;AACxG,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAiBnK"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recurring profile (spec 243 §5.5 / PMT-10) — NOT a rail, a mandate pattern.
|
|
3
|
+
*
|
|
4
|
+
* The payer authorizes ONCE (an open payment delegation whose caveats carry the per-charge
|
|
5
|
+
* cap + the frequency window + the aggregate cap); each period derives a CLOSED per-charge
|
|
6
|
+
* mandate settled via the wallet rail. The `PaymentEnforcer`'s on-chain frequency window +
|
|
7
|
+
* aggregate cap do the real enforcement — `recurringCaveatParams` returns the values the app
|
|
8
|
+
* feeds to `delegation.buildPaymentMandateCaveats` (payments doesn't runtime-import delegation).
|
|
9
|
+
*/
|
|
10
|
+
import { keccak256, encodeAbiParameters } from 'viem';
|
|
11
|
+
import { buildClosedMandate } from '../mandate.js';
|
|
12
|
+
import { buildWalletTransferPlan } from './wallet.js';
|
|
13
|
+
export function buildRecurringTemplate(input) {
|
|
14
|
+
if (input.amountPerPeriod <= 0n)
|
|
15
|
+
throw new Error('[recurring] amountPerPeriod must be > 0');
|
|
16
|
+
if (input.totalCap < input.amountPerPeriod)
|
|
17
|
+
throw new Error('[recurring] totalCap must be >= amountPerPeriod');
|
|
18
|
+
if (input.windowSeconds <= 0)
|
|
19
|
+
throw new Error('[recurring] windowSeconds must be > 0');
|
|
20
|
+
const templateId = keccak256(encodeAbiParameters([{ type: 'address' }, { type: 'address' }, { type: 'uint256' }, { type: 'uint256' }, { type: 'uint256' }], [input.payer, input.payee, input.amountPerPeriod, BigInt(input.windowSeconds), input.startNonce]));
|
|
21
|
+
return { ...input, templateId, periods: Number(input.totalCap / input.amountPerPeriod) };
|
|
22
|
+
}
|
|
23
|
+
/** The values the app feeds to `delegation.buildPaymentMandateCaveats` for the one-time authorization. */
|
|
24
|
+
export function recurringCaveatParams(t) {
|
|
25
|
+
return {
|
|
26
|
+
maxAmountPerCharge: t.amountPerPeriod,
|
|
27
|
+
maxAggregate: t.totalCap,
|
|
28
|
+
maxRedemptionsPerWindow: 1, // one charge per window
|
|
29
|
+
windowSeconds: t.windowSeconds,
|
|
30
|
+
validUntil: t.validUntil,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** The time window in which period N may be charged (the enforcer rejects an early re-charge). */
|
|
34
|
+
export function periodWindow(t, period) {
|
|
35
|
+
const start = t.validFrom + period * t.windowSeconds;
|
|
36
|
+
return { start, end: start + t.windowSeconds };
|
|
37
|
+
}
|
|
38
|
+
/** Derive the closed per-charge mandate + transfer plan for period N. Sign the mandate, then settle. */
|
|
39
|
+
export function deriveScheduledCharge(t, period) {
|
|
40
|
+
if (period < 0 || period >= t.periods)
|
|
41
|
+
throw new Error(`[recurring] period out of range [0, ${t.periods})`);
|
|
42
|
+
const window = periodWindow(t, period);
|
|
43
|
+
const mandate = buildClosedMandate({
|
|
44
|
+
rail: 'wallet',
|
|
45
|
+
payer: t.payer,
|
|
46
|
+
payee: t.payee,
|
|
47
|
+
asset: t.asset,
|
|
48
|
+
amount: t.amountPerPeriod,
|
|
49
|
+
chain: t.chain,
|
|
50
|
+
nonce: t.startNonce + BigInt(period),
|
|
51
|
+
validFrom: window.start,
|
|
52
|
+
expiresAt: window.end,
|
|
53
|
+
orderHash: t.templateId,
|
|
54
|
+
legId: ('0x' + period.toString(16).padStart(64, '0')),
|
|
55
|
+
});
|
|
56
|
+
return { mandate, plan: buildWalletTransferPlan(mandate), window };
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=recurring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurring.js","sourceRoot":"","sources":["../../src/rails/recurring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet rail (spec 243 §5.3/§5.5) — direct SA→SA transfer of a CLOSED mandate.
|
|
3
|
+
*
|
|
4
|
+
* Plain "checkout" pay: no budget delegation, no 402 round-trip. The payer SA executes a
|
|
5
|
+
* single ERC-20 transfer to the payee. Nullifier + receipt are identical to x402 (EXC-D3
|
|
6
|
+
* evidence symmetry). Ports the smart-agent `PledgeRegistry` cryptographic-rail pattern.
|
|
7
|
+
*/
|
|
8
|
+
import { type ClosedMandateInput } from '../mandate.js';
|
|
9
|
+
import { type TransferPlan } from '../transfer.js';
|
|
10
|
+
import type { PaymentMandate } from '../index.js';
|
|
11
|
+
export declare const WALLET_RAIL: "wallet";
|
|
12
|
+
/** Build an unsigned closed wallet-rail mandate (sign with `signPaymentMandate`). */
|
|
13
|
+
export declare function buildWalletMandate(input: Omit<ClosedMandateInput, 'rail'>): PaymentMandate;
|
|
14
|
+
/** The settlement plan for a closed wallet mandate: a direct transfer payer → payee. */
|
|
15
|
+
export declare function buildWalletTransferPlan(mandate: PaymentMandate): TransferPlan;
|
|
16
|
+
//# sourceMappingURL=wallet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../../src/rails/wallet.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,eAAO,MAAM,WAAW,EAAG,QAAiB,CAAC;AAE7C,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,GAAG,cAAc,CAE1F;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CAE7E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet rail (spec 243 §5.3/§5.5) — direct SA→SA transfer of a CLOSED mandate.
|
|
3
|
+
*
|
|
4
|
+
* Plain "checkout" pay: no budget delegation, no 402 round-trip. The payer SA executes a
|
|
5
|
+
* single ERC-20 transfer to the payee. Nullifier + receipt are identical to x402 (EXC-D3
|
|
6
|
+
* evidence symmetry). Ports the smart-agent `PledgeRegistry` cryptographic-rail pattern.
|
|
7
|
+
*/
|
|
8
|
+
import { mandateAmount } from '../mandate-sign.js';
|
|
9
|
+
import { buildClosedMandate } from '../mandate.js';
|
|
10
|
+
import { buildErc20Transfer } from '../transfer.js';
|
|
11
|
+
export const WALLET_RAIL = 'wallet';
|
|
12
|
+
/** Build an unsigned closed wallet-rail mandate (sign with `signPaymentMandate`). */
|
|
13
|
+
export function buildWalletMandate(input) {
|
|
14
|
+
return buildClosedMandate({ ...input, rail: 'wallet' });
|
|
15
|
+
}
|
|
16
|
+
/** The settlement plan for a closed wallet mandate: a direct transfer payer → payee. */
|
|
17
|
+
export function buildWalletTransferPlan(mandate) {
|
|
18
|
+
return buildErc20Transfer(mandate.amountPolicy.asset.id, mandate.payee, mandateAmount(mandate));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet.js","sourceRoot":"","sources":["../../src/rails/wallet.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAA2B,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAqB,MAAM,gBAAgB,CAAC;AAGvE,MAAM,CAAC,MAAM,WAAW,GAAG,QAAiB,CAAC;AAE7C,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,KAAuC;IACxE,OAAO,kBAAkB,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,uBAAuB,CAAC,OAAuB;IAC7D,OAAO,kBAAkB,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,EAAa,EAAE,OAAO,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7G,CAAC"}
|
|
@@ -68,6 +68,22 @@ export interface X402RailDeps {
|
|
|
68
68
|
}) => Promise<{
|
|
69
69
|
settlementHash: Hex32;
|
|
70
70
|
}>;
|
|
71
|
+
/** PAY-RAIL-6 — dry-run the redemption (eth_call / estimateGas) BEFORE the nonce is burned, so a
|
|
72
|
+
* reverting or griefing settlement is rejected without consuming the one-shot mandate. Injected by
|
|
73
|
+
* the app; omit to skip simulation. Returns ok + optional gas estimate. */
|
|
74
|
+
simulate?: (plan: {
|
|
75
|
+
to: Address;
|
|
76
|
+
value: bigint;
|
|
77
|
+
data: Hex;
|
|
78
|
+
}) => Promise<{
|
|
79
|
+
ok: boolean;
|
|
80
|
+
reason?: string;
|
|
81
|
+
gas?: bigint;
|
|
82
|
+
}>;
|
|
83
|
+
/** Anti-griefing: reject a settlement whose simulated gas exceeds this cap. */
|
|
84
|
+
maxGasPerSettlement?: bigint;
|
|
85
|
+
/** Anti-griefing: abort `submitRedemption` if it doesn't resolve within this many ms (settlement timeout). */
|
|
86
|
+
settlementTimeoutMs?: number;
|
|
71
87
|
now?: () => number;
|
|
72
88
|
}
|
|
73
89
|
export type SettleResult = {
|
|
@@ -79,7 +95,7 @@ export type SettleResult = {
|
|
|
79
95
|
ok: false;
|
|
80
96
|
reason: string;
|
|
81
97
|
};
|
|
82
|
-
/** The staged x402 rail. `settle` runs verify → revoke → reserve(nullifier) →
|
|
98
|
+
/** The staged x402 rail. `settle` runs verify → revoke → reserve(nullifier) → simulate → submit →
|
|
83
99
|
* receipt; a safe retry of an already-settled request returns the original receipt (idempotent). */
|
|
84
100
|
export declare function createX402Rail(deps: X402RailDeps): {
|
|
85
101
|
rail: "x402";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/rails/x402/executor.ts"],"names":[],"mappings":"AAMA,OAAO,EAA6D,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AACzG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAA4D,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/G,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,qBAAqB,EAAkB,MAAM,kBAAkB,CAAC;AAE9E,0GAA0G;AAC1G,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,YAAY,EAAE,KAAK,CAAC;CACrB;AAmDD,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,KAAK,CAAC;CACrB,GAAG,KAAK,CAgBR;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAwBpD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,KAAK,CAAC;CACrB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAwC5C;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,qBAAqB,CAAC;IAClC;yDACqD;IACrD,SAAS,EAAE,CAAC,cAAc,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD;+DAC2D;IAC3D,gBAAgB,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,KAAK,OAAO,CAAC;QAAE,cAAc,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAC1G,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAC1E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/rails/x402/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -146,7 +146,13 @@ export function buildRedemptionCalldata(args) {
|
|
|
146
146
|
});
|
|
147
147
|
return { to: args.delegationManager, value: 0n, data };
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
function withTimeout(p, ms) {
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const t = setTimeout(() => reject(new Error(`settlement timed out after ${ms}ms`)), ms);
|
|
152
|
+
p.then((v) => { clearTimeout(t); resolve(v); }, (e) => { clearTimeout(t); reject(e); });
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/** The staged x402 rail. `settle` runs verify → revoke → reserve(nullifier) → simulate → submit →
|
|
150
156
|
* receipt; a safe retry of an already-settled request returns the original receipt (idempotent). */
|
|
151
157
|
export function createX402Rail(deps) {
|
|
152
158
|
const now = deps.now ?? (() => Math.floor(Date.now() / 1000));
|
|
@@ -183,9 +189,25 @@ export function createX402Rail(deps) {
|
|
|
183
189
|
asset: deps.asset,
|
|
184
190
|
resourceHash: quote.resourceHash,
|
|
185
191
|
});
|
|
192
|
+
// PAY-RAIL-6 — simulate before burning the nonce: a reverting or over-gas settlement is
|
|
193
|
+
// rejected as RETRYABLE so the one-shot mandate survives for a corrected resubmit.
|
|
194
|
+
if (deps.simulate) {
|
|
195
|
+
const sim = await deps.simulate(plan);
|
|
196
|
+
if (!sim.ok) {
|
|
197
|
+
await deps.nonceStore.markFailed(nullifier, true);
|
|
198
|
+
return { ok: false, reason: `simulation reverted${sim.reason ? `: ${sim.reason}` : ''}` };
|
|
199
|
+
}
|
|
200
|
+
if (deps.maxGasPerSettlement !== undefined && sim.gas !== undefined && sim.gas > deps.maxGasPerSettlement) {
|
|
201
|
+
await deps.nonceStore.markFailed(nullifier, true);
|
|
202
|
+
return { ok: false, reason: `settlement gas ${sim.gas} exceeds cap ${deps.maxGasPerSettlement}` };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
186
205
|
await deps.nonceStore.markSettling(nullifier);
|
|
187
206
|
try {
|
|
188
|
-
const
|
|
207
|
+
const submit = deps.submitRedemption(plan);
|
|
208
|
+
const { settlementHash } = deps.settlementTimeoutMs
|
|
209
|
+
? await withTimeout(submit, deps.settlementTimeoutMs)
|
|
210
|
+
: await submit;
|
|
189
211
|
const receipt = { settlementHash, mandateId: mandate.mandateId };
|
|
190
212
|
await deps.nonceStore.markSettled(nullifier, receipt);
|
|
191
213
|
return { ok: true, settlementHash, mandateId: mandate.mandateId, idempotent: false };
|