@x402r/evm 0.0.2 → 0.0.3
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/README.md +20 -16
- package/dist/cjs/escrow/client/index.cjs +227 -0
- package/dist/cjs/escrow/client/index.cjs.map +1 -0
- package/dist/cjs/escrow/client/index.d.cts +23 -0
- package/dist/cjs/escrow/client/index.d.ts +23 -0
- package/dist/cjs/escrow/client/index.js +223 -0
- package/dist/cjs/escrow/client/index.js.map +1 -0
- package/dist/cjs/escrow/facilitator/index.cjs +359 -0
- package/dist/cjs/escrow/facilitator/index.cjs.map +1 -0
- package/dist/cjs/escrow/facilitator/index.d.cts +53 -0
- package/dist/{escrow → cjs/escrow}/facilitator/index.d.ts +17 -13
- package/dist/cjs/escrow/facilitator/index.js +358 -0
- package/dist/cjs/escrow/facilitator/index.js.map +1 -0
- package/dist/cjs/escrow/server/index.cjs +222 -0
- package/dist/cjs/escrow/server/index.cjs.map +1 -0
- package/dist/cjs/escrow/server/index.d.cts +78 -0
- package/dist/{escrow → cjs/escrow}/server/index.d.ts +15 -9
- package/dist/cjs/escrow/server/index.js +217 -0
- package/dist/cjs/escrow/server/index.js.map +1 -0
- package/dist/{shared/types.d.ts → cjs/escrow/types/index.d.ts} +7 -6
- package/dist/cjs/escrow/types/index.js +40 -0
- package/dist/cjs/escrow/types/index.js.map +1 -0
- package/dist/cjs/index.cjs +215 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +22 -0
- package/dist/cjs/index.d.ts +54 -0
- package/dist/cjs/index.js +223 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/scheme-CNrmuyp3.d.ts +22 -0
- package/dist/esm/chunk-DLIBGHEY.mjs +85 -0
- package/dist/esm/chunk-DLIBGHEY.mjs.map +1 -0
- package/dist/esm/chunk-IYUU7AJZ.mjs +187 -0
- package/dist/esm/chunk-IYUU7AJZ.mjs.map +1 -0
- package/dist/esm/chunk-JBHVAJN3.mjs +13 -0
- package/dist/esm/chunk-JBHVAJN3.mjs.map +1 -0
- package/dist/esm/chunk-NSSMTXJJ.mjs +8 -0
- package/dist/esm/chunk-NSSMTXJJ.mjs.map +1 -0
- package/dist/esm/escrow/client/index.d.mts +23 -0
- package/dist/esm/escrow/client/index.mjs +20 -0
- package/dist/esm/escrow/client/index.mjs.map +1 -0
- package/dist/esm/escrow/facilitator/index.d.mts +53 -0
- package/dist/esm/escrow/facilitator/index.mjs +230 -0
- package/dist/esm/escrow/facilitator/index.mjs.map +1 -0
- package/dist/esm/escrow/server/index.d.mts +78 -0
- package/dist/esm/escrow/server/index.mjs +191 -0
- package/dist/esm/escrow/server/index.mjs.map +1 -0
- package/dist/esm/index.d.mts +54 -0
- package/dist/esm/index.mjs +15 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/scheme-CNrmuyp3.d.mts +22 -0
- package/package.json +42 -16
- package/src/escrow/client/index.ts +3 -161
- package/src/escrow/client/register.ts +33 -0
- package/src/escrow/client/scheme.ts +107 -0
- package/src/escrow/facilitator/index.ts +3 -388
- package/src/escrow/facilitator/register.ts +33 -0
- package/src/escrow/facilitator/scheme.ts +289 -0
- package/src/escrow/index.ts +3 -0
- package/src/escrow/server/index.ts +3 -261
- package/src/escrow/server/register.ts +34 -0
- package/src/escrow/server/scheme.ts +226 -0
- package/src/escrow/shared/constants.ts +65 -0
- package/src/escrow/shared/nonce.ts +175 -0
- package/src/escrow/shared/types.ts +69 -0
- package/src/escrow/shared/utils.ts +16 -0
- package/dist/escrow/client/index.d.ts +0 -40
- package/dist/escrow/client/index.d.ts.map +0 -1
- package/dist/escrow/client/index.js +0 -104
- package/dist/escrow/client/index.js.map +0 -1
- package/dist/escrow/facilitator/index.d.ts.map +0 -1
- package/dist/escrow/facilitator/index.js +0 -300
- package/dist/escrow/facilitator/index.js.map +0 -1
- package/dist/escrow/server/index.d.ts.map +0 -1
- package/dist/escrow/server/index.js +0 -214
- package/dist/escrow/server/index.js.map +0 -1
- package/dist/shared/constants.d.ts +0 -112
- package/dist/shared/constants.d.ts.map +0 -1
- package/dist/shared/constants.js +0 -51
- package/dist/shared/constants.js.map +0 -1
- package/dist/shared/nonce.d.ts +0 -41
- package/dist/shared/nonce.d.ts.map +0 -1
- package/dist/shared/nonce.js +0 -154
- package/dist/shared/nonce.js.map +0 -1
- package/dist/shared/types.d.ts.map +0 -1
- package/dist/shared/types.js +0 -21
- package/dist/shared/types.js.map +0 -1
- package/src/shared/constants.ts +0 -58
- package/src/shared/nonce.ts +0 -203
- package/src/shared/types.ts +0 -69
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
21
|
+
|
|
22
|
+
// src/escrow/facilitator/index.ts
|
|
23
|
+
var facilitator_exports = {};
|
|
24
|
+
__export(facilitator_exports, {
|
|
25
|
+
EscrowFacilitatorScheme: () => EscrowFacilitatorScheme,
|
|
26
|
+
registerEscrowEvmScheme: () => registerEscrowEvmScheme
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(facilitator_exports);
|
|
29
|
+
|
|
30
|
+
// src/escrow/facilitator/scheme.ts
|
|
31
|
+
var import_viem2 = require("viem");
|
|
32
|
+
|
|
33
|
+
// src/escrow/shared/constants.ts
|
|
34
|
+
var PAYMENT_INFO_COMPONENTS = [
|
|
35
|
+
{ name: "operator", type: "address" },
|
|
36
|
+
{ name: "payer", type: "address" },
|
|
37
|
+
{ name: "receiver", type: "address" },
|
|
38
|
+
{ name: "token", type: "address" },
|
|
39
|
+
{ name: "maxAmount", type: "uint120" },
|
|
40
|
+
{ name: "preApprovalExpiry", type: "uint48" },
|
|
41
|
+
{ name: "authorizationExpiry", type: "uint48" },
|
|
42
|
+
{ name: "refundExpiry", type: "uint48" },
|
|
43
|
+
{ name: "minFeeBps", type: "uint16" },
|
|
44
|
+
{ name: "maxFeeBps", type: "uint16" },
|
|
45
|
+
{ name: "feeReceiver", type: "address" },
|
|
46
|
+
{ name: "salt", type: "uint256" }
|
|
47
|
+
];
|
|
48
|
+
var OPERATOR_ABI = [
|
|
49
|
+
{
|
|
50
|
+
name: "authorize",
|
|
51
|
+
type: "function",
|
|
52
|
+
stateMutability: "nonpayable",
|
|
53
|
+
inputs: [
|
|
54
|
+
{
|
|
55
|
+
name: "paymentInfo",
|
|
56
|
+
type: "tuple",
|
|
57
|
+
components: PAYMENT_INFO_COMPONENTS
|
|
58
|
+
},
|
|
59
|
+
{ name: "amount", type: "uint256" },
|
|
60
|
+
{ name: "tokenCollector", type: "address" },
|
|
61
|
+
{ name: "collectorData", type: "bytes" }
|
|
62
|
+
],
|
|
63
|
+
outputs: []
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
var RECEIVE_AUTHORIZATION_TYPES = {
|
|
67
|
+
ReceiveWithAuthorization: [
|
|
68
|
+
{ name: "from", type: "address" },
|
|
69
|
+
{ name: "to", type: "address" },
|
|
70
|
+
{ name: "value", type: "uint256" },
|
|
71
|
+
{ name: "validAfter", type: "uint256" },
|
|
72
|
+
{ name: "validBefore", type: "uint256" },
|
|
73
|
+
{ name: "nonce", type: "bytes32" }
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
var ERC20_BALANCE_OF_ABI = [
|
|
77
|
+
{
|
|
78
|
+
name: "balanceOf",
|
|
79
|
+
type: "function",
|
|
80
|
+
stateMutability: "view",
|
|
81
|
+
inputs: [{ name: "account", type: "address" }],
|
|
82
|
+
outputs: [{ name: "balance", type: "uint256" }]
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
// src/escrow/shared/nonce.ts
|
|
87
|
+
var import_viem = require("viem");
|
|
88
|
+
var PAYMENT_INFO_TYPEHASH = (0, import_viem.keccak256)(
|
|
89
|
+
new TextEncoder().encode(
|
|
90
|
+
"PaymentInfo(address operator,address payer,address receiver,address token,uint120 maxAmount,uint48 preApprovalExpiry,uint48 authorizationExpiry,uint48 refundExpiry,uint16 minFeeBps,uint16 maxFeeBps,address feeReceiver,uint256 salt)"
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
async function verifyERC3009Signature(signer, authorization, signature, extra, tokenAddress) {
|
|
94
|
+
const domain = {
|
|
95
|
+
name: extra.name,
|
|
96
|
+
version: extra.version,
|
|
97
|
+
chainId: extra.chainId,
|
|
98
|
+
verifyingContract: (0, import_viem.getAddress)(tokenAddress)
|
|
99
|
+
};
|
|
100
|
+
const message = {
|
|
101
|
+
from: (0, import_viem.getAddress)(authorization.from),
|
|
102
|
+
to: (0, import_viem.getAddress)(authorization.to),
|
|
103
|
+
value: BigInt(authorization.value),
|
|
104
|
+
validAfter: BigInt(authorization.validAfter),
|
|
105
|
+
validBefore: BigInt(authorization.validBefore),
|
|
106
|
+
nonce: authorization.nonce
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
return await signer.verifyTypedData({
|
|
110
|
+
address: (0, import_viem.getAddress)(authorization.from),
|
|
111
|
+
domain,
|
|
112
|
+
types: RECEIVE_AUTHORIZATION_TYPES,
|
|
113
|
+
primaryType: "ReceiveWithAuthorization",
|
|
114
|
+
message,
|
|
115
|
+
signature
|
|
116
|
+
});
|
|
117
|
+
} catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/escrow/shared/types.ts
|
|
123
|
+
function isEscrowPayload(value) {
|
|
124
|
+
return typeof value === "object" && value !== null && "authorization" in value && "signature" in value && "paymentInfo" in value;
|
|
125
|
+
}
|
|
126
|
+
function isEscrowExtra(value) {
|
|
127
|
+
return typeof value === "object" && value !== null && "escrowAddress" in value && "operatorAddress" in value && "tokenCollector" in value;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/escrow/shared/utils.ts
|
|
131
|
+
function parseChainId(network) {
|
|
132
|
+
const parts = network.split(":");
|
|
133
|
+
if (parts.length !== 2 || parts[0] !== "eip155") {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Invalid network format: ${network}. Expected 'eip155:<chainId>'`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
const chainId = parseInt(parts[1], 10);
|
|
139
|
+
if (isNaN(chainId)) {
|
|
140
|
+
throw new Error(`Invalid chainId in network: ${network}`);
|
|
141
|
+
}
|
|
142
|
+
return chainId;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/escrow/facilitator/scheme.ts
|
|
146
|
+
var EscrowFacilitatorScheme = class {
|
|
147
|
+
constructor(signer) {
|
|
148
|
+
this.signer = signer;
|
|
149
|
+
__publicField(this, "scheme", "escrow");
|
|
150
|
+
__publicField(this, "caipFamily", "eip155:*");
|
|
151
|
+
}
|
|
152
|
+
getSigners(_network) {
|
|
153
|
+
return [...this.signer.getAddresses()];
|
|
154
|
+
}
|
|
155
|
+
// C4: name/version now come from server's parsePrice() via AssetAmount.extra.
|
|
156
|
+
// The facilitator should not hardcode token-specific metadata.
|
|
157
|
+
getExtra(_network) {
|
|
158
|
+
return void 0;
|
|
159
|
+
}
|
|
160
|
+
async verify(payload, requirements, _context) {
|
|
161
|
+
if (!isEscrowPayload(payload.payload)) {
|
|
162
|
+
return {
|
|
163
|
+
isValid: false,
|
|
164
|
+
invalidReason: "invalid_payload_format"
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const escrowPayload = payload.payload;
|
|
168
|
+
const payer = escrowPayload.authorization.from;
|
|
169
|
+
if (requirements.scheme !== "escrow") {
|
|
170
|
+
return {
|
|
171
|
+
isValid: false,
|
|
172
|
+
invalidReason: "unsupported_scheme",
|
|
173
|
+
payer
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const networkParts = requirements.network.split(":");
|
|
177
|
+
if (networkParts.length !== 2 || networkParts[0] !== "eip155") {
|
|
178
|
+
return {
|
|
179
|
+
isValid: false,
|
|
180
|
+
invalidReason: "invalid_network",
|
|
181
|
+
payer
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (!isEscrowExtra(requirements.extra)) {
|
|
185
|
+
return {
|
|
186
|
+
isValid: false,
|
|
187
|
+
invalidReason: "invalid_escrow_extra",
|
|
188
|
+
payer
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const extra = requirements.extra;
|
|
192
|
+
const chainId = parseChainId(requirements.network);
|
|
193
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
194
|
+
const validBefore = Number(escrowPayload.authorization.validBefore);
|
|
195
|
+
const validAfter = Number(escrowPayload.authorization.validAfter);
|
|
196
|
+
if (validBefore <= now + 6) {
|
|
197
|
+
return {
|
|
198
|
+
isValid: false,
|
|
199
|
+
invalidReason: "authorization_expired",
|
|
200
|
+
payer
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (validAfter > now) {
|
|
204
|
+
return {
|
|
205
|
+
isValid: false,
|
|
206
|
+
invalidReason: "authorization_not_yet_valid",
|
|
207
|
+
payer
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const { signature: signatureForVerify } = (0, import_viem2.parseErc6492Signature)(escrowPayload.signature);
|
|
211
|
+
const isValidSignature = await verifyERC3009Signature(
|
|
212
|
+
this.signer,
|
|
213
|
+
escrowPayload.authorization,
|
|
214
|
+
signatureForVerify,
|
|
215
|
+
{ ...extra, chainId },
|
|
216
|
+
requirements.asset
|
|
217
|
+
);
|
|
218
|
+
if (!isValidSignature) {
|
|
219
|
+
return {
|
|
220
|
+
isValid: false,
|
|
221
|
+
invalidReason: "invalid_escrow_signature",
|
|
222
|
+
payer
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (BigInt(escrowPayload.authorization.value) < BigInt(requirements.amount)) {
|
|
226
|
+
return {
|
|
227
|
+
isValid: false,
|
|
228
|
+
invalidReason: "insufficient_amount",
|
|
229
|
+
payer
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (escrowPayload.paymentInfo.token.toLowerCase() !== requirements.asset.toLowerCase()) {
|
|
233
|
+
return {
|
|
234
|
+
isValid: false,
|
|
235
|
+
invalidReason: "token_mismatch",
|
|
236
|
+
payer
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (escrowPayload.paymentInfo.receiver.toLowerCase() !== requirements.payTo.toLowerCase()) {
|
|
240
|
+
return {
|
|
241
|
+
isValid: false,
|
|
242
|
+
invalidReason: "receiver_mismatch",
|
|
243
|
+
payer
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const balance = await this.signer.readContract({
|
|
248
|
+
address: requirements.asset,
|
|
249
|
+
abi: ERC20_BALANCE_OF_ABI,
|
|
250
|
+
functionName: "balanceOf",
|
|
251
|
+
args: [payer]
|
|
252
|
+
});
|
|
253
|
+
if (BigInt(balance) < BigInt(requirements.amount)) {
|
|
254
|
+
return {
|
|
255
|
+
isValid: false,
|
|
256
|
+
invalidReason: "insufficient_balance",
|
|
257
|
+
payer
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
isValid: true,
|
|
264
|
+
payer
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
async settle(payload, requirements, _context) {
|
|
268
|
+
const verification = await this.verify(payload, requirements);
|
|
269
|
+
if (!verification.isValid) {
|
|
270
|
+
return {
|
|
271
|
+
success: false,
|
|
272
|
+
errorReason: verification.invalidReason ?? "verification_failed",
|
|
273
|
+
transaction: "",
|
|
274
|
+
network: requirements.network,
|
|
275
|
+
payer: verification.payer
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const escrowPayload = payload.payload;
|
|
279
|
+
const extra = requirements.extra;
|
|
280
|
+
const { authorizeAddress, operatorAddress, tokenCollector } = extra;
|
|
281
|
+
const paymentInfo = {
|
|
282
|
+
operator: escrowPayload.paymentInfo.operator,
|
|
283
|
+
payer: escrowPayload.authorization.from,
|
|
284
|
+
receiver: escrowPayload.paymentInfo.receiver,
|
|
285
|
+
token: escrowPayload.paymentInfo.token,
|
|
286
|
+
maxAmount: BigInt(escrowPayload.paymentInfo.maxAmount),
|
|
287
|
+
preApprovalExpiry: escrowPayload.paymentInfo.preApprovalExpiry,
|
|
288
|
+
authorizationExpiry: escrowPayload.paymentInfo.authorizationExpiry,
|
|
289
|
+
refundExpiry: escrowPayload.paymentInfo.refundExpiry,
|
|
290
|
+
minFeeBps: escrowPayload.paymentInfo.minFeeBps,
|
|
291
|
+
maxFeeBps: escrowPayload.paymentInfo.maxFeeBps,
|
|
292
|
+
feeReceiver: escrowPayload.paymentInfo.feeReceiver,
|
|
293
|
+
salt: BigInt(escrowPayload.paymentInfo.salt)
|
|
294
|
+
};
|
|
295
|
+
const collectorData = escrowPayload.signature;
|
|
296
|
+
const target = authorizeAddress ?? operatorAddress;
|
|
297
|
+
try {
|
|
298
|
+
const txHash = await this.signer.writeContract({
|
|
299
|
+
address: target,
|
|
300
|
+
abi: OPERATOR_ABI,
|
|
301
|
+
functionName: "authorize",
|
|
302
|
+
args: [
|
|
303
|
+
paymentInfo,
|
|
304
|
+
BigInt(escrowPayload.authorization.value),
|
|
305
|
+
tokenCollector,
|
|
306
|
+
collectorData
|
|
307
|
+
]
|
|
308
|
+
});
|
|
309
|
+
const receiptPromise = this.signer.waitForTransactionReceipt({
|
|
310
|
+
hash: txHash
|
|
311
|
+
});
|
|
312
|
+
const timeoutPromise = new Promise(
|
|
313
|
+
(_, reject) => setTimeout(
|
|
314
|
+
() => reject(new Error("Transaction receipt timeout after 60s")),
|
|
315
|
+
6e4
|
|
316
|
+
)
|
|
317
|
+
);
|
|
318
|
+
const receipt = await Promise.race([receiptPromise, timeoutPromise]);
|
|
319
|
+
if (receipt.status !== "success") {
|
|
320
|
+
return {
|
|
321
|
+
success: false,
|
|
322
|
+
errorReason: "transaction_reverted",
|
|
323
|
+
transaction: txHash,
|
|
324
|
+
network: requirements.network,
|
|
325
|
+
payer: escrowPayload.authorization.from
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
success: true,
|
|
330
|
+
transaction: txHash,
|
|
331
|
+
network: requirements.network,
|
|
332
|
+
payer: escrowPayload.authorization.from
|
|
333
|
+
};
|
|
334
|
+
} catch (error) {
|
|
335
|
+
return {
|
|
336
|
+
success: false,
|
|
337
|
+
errorReason: error instanceof Error ? error.message : "Settlement failed",
|
|
338
|
+
transaction: "",
|
|
339
|
+
network: requirements.network,
|
|
340
|
+
payer: escrowPayload.authorization.from
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// src/escrow/facilitator/register.ts
|
|
347
|
+
function registerEscrowEvmScheme(facilitator, config) {
|
|
348
|
+
facilitator.register(
|
|
349
|
+
config.networks,
|
|
350
|
+
new EscrowFacilitatorScheme(config.signer)
|
|
351
|
+
);
|
|
352
|
+
return facilitator;
|
|
353
|
+
}
|
|
354
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
355
|
+
0 && (module.exports = {
|
|
356
|
+
EscrowFacilitatorScheme,
|
|
357
|
+
registerEscrowEvmScheme
|
|
358
|
+
});
|
|
359
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/escrow/facilitator/index.ts","../../../../src/escrow/facilitator/scheme.ts","../../../../src/escrow/shared/constants.ts","../../../../src/escrow/shared/nonce.ts","../../../../src/escrow/shared/types.ts","../../../../src/escrow/shared/utils.ts","../../../../src/escrow/facilitator/register.ts"],"sourcesContent":["export { EscrowFacilitatorScheme } from \"./scheme\";\nexport { registerEscrowEvmScheme } from \"./register\";\nexport type { EvmFacilitatorConfig } from \"./register\";\n","/**\n * Escrow Scheme - Facilitator\n * Handles verification and settlement of escrow payments.\n *\n * Implements x402's SchemeNetworkFacilitator interface so the escrow scheme\n * is a drop-in for the x402 facilitator, just like ExactEvmScheme.\n */\n\nimport type {\n FacilitatorContext,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport type { FacilitatorEvmSigner } from \"@x402/evm\";\nimport { parseErc6492Signature } from \"viem\";\nimport {\n OPERATOR_ABI,\n ERC20_BALANCE_OF_ABI,\n} from \"../shared/constants\";\nimport { verifyERC3009Signature } from \"../shared/nonce\";\nimport {\n isEscrowPayload,\n isEscrowExtra,\n} from \"../shared/types\";\nimport type { EscrowExtra, EscrowPayload } from \"../shared/types\";\nimport { parseChainId } from \"../shared/utils\";\n\n/**\n * Escrow Facilitator Scheme - implements x402's SchemeNetworkFacilitator\n *\n * The facilitator is operator-agnostic: it does not store operator/escrow/tokenCollector\n * config. Those values are set by the merchant via `refundable()` and arrive in\n * `requirements.extra` at verify/settle time.\n */\nexport class EscrowFacilitatorScheme implements SchemeNetworkFacilitator {\n readonly scheme = \"escrow\";\n readonly caipFamily = \"eip155:*\";\n\n constructor(private signer: FacilitatorEvmSigner) {}\n\n getSigners(_network: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n // C4: name/version now come from server's parsePrice() via AssetAmount.extra.\n // The facilitator should not hardcode token-specific metadata.\n getExtra(_network: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n _context?: FacilitatorContext,\n ): Promise<VerifyResponse> {\n // M5: Type guard instead of double cast\n if (!isEscrowPayload(payload.payload)) {\n return {\n isValid: false,\n invalidReason: \"invalid_payload_format\",\n };\n }\n const escrowPayload = payload.payload as EscrowPayload;\n const payer = escrowPayload.authorization.from;\n\n // Validate scheme\n if (requirements.scheme !== \"escrow\") {\n return {\n isValid: false,\n invalidReason: \"unsupported_scheme\",\n payer,\n };\n }\n\n // Validate network format\n const networkParts = requirements.network.split(\":\");\n if (networkParts.length !== 2 || networkParts[0] !== \"eip155\") {\n return {\n isValid: false,\n invalidReason: \"invalid_network\",\n payer,\n };\n }\n\n // M5: Type guard for extra\n if (!isEscrowExtra(requirements.extra)) {\n return {\n isValid: false,\n invalidReason: \"invalid_escrow_extra\",\n payer,\n };\n }\n const extra = requirements.extra as EscrowExtra;\n const chainId = parseChainId(requirements.network);\n\n // Time window validation\n const now = Math.floor(Date.now() / 1000);\n const validBefore = Number(escrowPayload.authorization.validBefore);\n const validAfter = Number(escrowPayload.authorization.validAfter);\n\n if (validBefore <= now + 6) {\n return {\n isValid: false,\n invalidReason: \"authorization_expired\",\n payer,\n };\n }\n\n if (validAfter > now) {\n return {\n isValid: false,\n invalidReason: \"authorization_not_yet_valid\",\n payer,\n };\n }\n\n // Extract inner signature for verification if EIP-6492 wrapped.\n // The contract's ERC6492SignatureHandler handles deployment; the facilitator\n // only needs the inner ECDSA signature for ecrecover verification.\n const { signature: signatureForVerify } = parseErc6492Signature(escrowPayload.signature);\n\n // Verify ERC-3009 signature\n const isValidSignature = await verifyERC3009Signature(\n this.signer,\n escrowPayload.authorization,\n signatureForVerify,\n { ...extra, chainId },\n requirements.asset as `0x${string}`,\n );\n\n if (!isValidSignature) {\n return {\n isValid: false,\n invalidReason: \"invalid_escrow_signature\",\n payer,\n };\n }\n\n // Verify amount meets requirements\n if (\n BigInt(escrowPayload.authorization.value) <\n BigInt(requirements.amount)\n ) {\n return {\n isValid: false,\n invalidReason: \"insufficient_amount\",\n payer,\n };\n }\n\n // Verify token matches\n if (\n escrowPayload.paymentInfo.token.toLowerCase() !==\n requirements.asset.toLowerCase()\n ) {\n return {\n isValid: false,\n invalidReason: \"token_mismatch\",\n payer,\n };\n }\n\n // Verify receiver matches\n if (\n escrowPayload.paymentInfo.receiver.toLowerCase() !==\n requirements.payTo.toLowerCase()\n ) {\n return {\n isValid: false,\n invalidReason: \"receiver_mismatch\",\n payer,\n };\n }\n\n // H4: Balance check — verify payer has sufficient token balance\n try {\n const balance = await this.signer.readContract({\n address: requirements.asset as `0x${string}`,\n abi: ERC20_BALANCE_OF_ABI,\n functionName: \"balanceOf\",\n args: [payer],\n });\n\n if (BigInt(balance as string) < BigInt(requirements.amount)) {\n return {\n isValid: false,\n invalidReason: \"insufficient_balance\",\n payer,\n };\n }\n } catch {\n // If balance check fails (e.g., non-standard token), skip it.\n // The on-chain transaction will fail anyway if balance is insufficient.\n }\n\n return {\n isValid: true,\n payer,\n };\n }\n\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n _context?: FacilitatorContext,\n ): Promise<SettleResponse> {\n // H2: Re-verify before settling to catch expired/invalid payloads\n const verification = await this.verify(payload, requirements);\n if (!verification.isValid) {\n return {\n success: false,\n errorReason: verification.invalidReason ?? \"verification_failed\",\n transaction: \"\",\n network: requirements.network,\n payer: verification.payer,\n };\n }\n\n const escrowPayload = payload.payload as unknown as EscrowPayload;\n const extra = requirements.extra as unknown as EscrowExtra;\n const { authorizeAddress, operatorAddress, tokenCollector } = extra;\n\n const paymentInfo = {\n operator: escrowPayload.paymentInfo.operator,\n payer: escrowPayload.authorization.from,\n receiver: escrowPayload.paymentInfo.receiver,\n token: escrowPayload.paymentInfo.token,\n maxAmount: BigInt(escrowPayload.paymentInfo.maxAmount),\n preApprovalExpiry: escrowPayload.paymentInfo.preApprovalExpiry,\n authorizationExpiry: escrowPayload.paymentInfo.authorizationExpiry,\n refundExpiry: escrowPayload.paymentInfo.refundExpiry,\n minFeeBps: escrowPayload.paymentInfo.minFeeBps,\n maxFeeBps: escrowPayload.paymentInfo.maxFeeBps,\n feeReceiver: escrowPayload.paymentInfo.feeReceiver,\n salt: BigInt(escrowPayload.paymentInfo.salt),\n };\n\n // Pass raw signature — ERC3009PaymentCollector/ERC6492SignatureHandler\n // handles EIP-6492 unwrapping and wallet deployment on-chain\n const collectorData = escrowPayload.signature;\n\n const target = authorizeAddress ?? operatorAddress;\n\n try {\n const txHash = await this.signer.writeContract({\n address: target,\n abi: OPERATOR_ABI,\n functionName: \"authorize\",\n args: [\n paymentInfo,\n BigInt(escrowPayload.authorization.value),\n tokenCollector,\n collectorData,\n ],\n });\n\n // Wait for transaction confirmation with 60s timeout to avoid hanging on stuck txs\n const receiptPromise = this.signer.waitForTransactionReceipt({\n hash: txHash,\n });\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"Transaction receipt timeout after 60s\")),\n 60_000,\n ),\n );\n const receipt = await Promise.race([receiptPromise, timeoutPromise]);\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: \"transaction_reverted\",\n transaction: txHash,\n network: requirements.network,\n payer: escrowPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: txHash,\n network: requirements.network,\n payer: escrowPayload.authorization.from,\n };\n } catch (error) {\n return {\n success: false,\n errorReason:\n error instanceof Error ? error.message : \"Settlement failed\",\n transaction: \"\",\n network: requirements.network,\n payer: escrowPayload.authorization.from,\n };\n }\n }\n}\n","export const ZERO_ADDRESS =\n \"0x0000000000000000000000000000000000000000\" as const;\nexport const MAX_UINT48 = 281474976710655;\nexport const MAX_UINT32 = 4294967295;\n\n// PaymentInfo struct for AuthCaptureEscrow (matches commerce-payments contract)\nexport const PAYMENT_INFO_COMPONENTS = [\n { name: \"operator\", type: \"address\" },\n { name: \"payer\", type: \"address\" },\n { name: \"receiver\", type: \"address\" },\n { name: \"token\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint120\" },\n { name: \"preApprovalExpiry\", type: \"uint48\" },\n { name: \"authorizationExpiry\", type: \"uint48\" },\n { name: \"refundExpiry\", type: \"uint48\" },\n { name: \"minFeeBps\", type: \"uint16\" },\n { name: \"maxFeeBps\", type: \"uint16\" },\n { name: \"feeReceiver\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n] as const;\n\nexport const OPERATOR_ABI = [\n {\n name: \"authorize\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [\n {\n name: \"paymentInfo\",\n type: \"tuple\",\n components: PAYMENT_INFO_COMPONENTS,\n },\n { name: \"amount\", type: \"uint256\" },\n { name: \"tokenCollector\", type: \"address\" },\n { name: \"collectorData\", type: \"bytes\" },\n ],\n outputs: [],\n },\n] as const;\n\n// ERC-3009 TransferWithAuthorization type hash\nexport const TRANSFER_WITH_AUTHORIZATION_TYPEHASH =\n \"0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267\" as const;\n\n// ERC-3009 ReceiveWithAuthorization EIP-712 types\nexport const RECEIVE_AUTHORIZATION_TYPES = {\n ReceiveWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n// ERC-20 balanceOf ABI for balance checks\nexport const ERC20_BALANCE_OF_ABI = [\n {\n name: \"balanceOf\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"account\", type: \"address\" }],\n outputs: [{ name: \"balance\", type: \"uint256\" }],\n },\n] as const;\n","/**\n * Nonce computation and ERC-3009 signing utilities\n * Adapted from @agentokratia/x402-escrow (MIT)\n */\n\nimport { encodeAbiParameters, getAddress, keccak256, toHex } from \"viem\";\nimport type { ClientEvmSigner } from \"@x402/evm\";\nimport { ZERO_ADDRESS, PAYMENT_INFO_COMPONENTS, RECEIVE_AUTHORIZATION_TYPES } from \"./constants\";\nimport type { EscrowExtra, EscrowPayload } from \"./types\";\n\n/**\n * PaymentInfo typehash - must match AuthCaptureEscrow.PAYMENT_INFO_TYPEHASH\n */\nconst PAYMENT_INFO_TYPEHASH = keccak256(\n new TextEncoder().encode(\n \"PaymentInfo(address operator,address payer,address receiver,address token,uint120 maxAmount,uint48 preApprovalExpiry,uint48 authorizationExpiry,uint48 refundExpiry,uint16 minFeeBps,uint16 maxFeeBps,address feeReceiver,uint256 salt)\",\n ),\n);\n\n/**\n * Compute escrow nonce for ERC-3009 authorization\n * Must match AuthCaptureEscrow.getHash() with payer=address(0)\n */\nexport function computeEscrowNonce(\n chainId: number,\n escrowAddress: `0x${string}`,\n paymentInfo: EscrowPayload[\"paymentInfo\"],\n): `0x${string}` {\n // Step 1: Encode paymentInfo with payer=0 (payer-agnostic)\n const paymentInfoEncoded = encodeAbiParameters(\n [\n { name: \"typehash\", type: \"bytes32\" },\n { name: \"operator\", type: \"address\" },\n { name: \"payer\", type: \"address\" },\n { name: \"receiver\", type: \"address\" },\n { name: \"token\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint120\" },\n { name: \"preApprovalExpiry\", type: \"uint48\" },\n { name: \"authorizationExpiry\", type: \"uint48\" },\n { name: \"refundExpiry\", type: \"uint48\" },\n { name: \"minFeeBps\", type: \"uint16\" },\n { name: \"maxFeeBps\", type: \"uint16\" },\n { name: \"feeReceiver\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n [\n PAYMENT_INFO_TYPEHASH,\n paymentInfo.operator,\n ZERO_ADDRESS, // payer-agnostic\n paymentInfo.receiver,\n paymentInfo.token,\n BigInt(paymentInfo.maxAmount),\n paymentInfo.preApprovalExpiry,\n paymentInfo.authorizationExpiry,\n paymentInfo.refundExpiry,\n paymentInfo.minFeeBps,\n paymentInfo.maxFeeBps,\n paymentInfo.feeReceiver,\n BigInt(paymentInfo.salt),\n ],\n );\n const paymentInfoHash = keccak256(paymentInfoEncoded);\n\n // Step 2: Encode (chainId, escrow, paymentInfoHash) and hash\n const outerEncoded = encodeAbiParameters(\n [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"escrow\", type: \"address\" },\n { name: \"paymentInfoHash\", type: \"bytes32\" },\n ],\n [BigInt(chainId), escrowAddress, paymentInfoHash],\n );\n\n return keccak256(outerEncoded);\n}\n\n/**\n * Sign ERC-3009 ReceiveWithAuthorization\n * Note: receiveWithAuthorization uses a different primary type than transferWithAuthorization\n */\nexport async function signERC3009(\n signer: ClientEvmSigner,\n authorization: EscrowPayload[\"authorization\"],\n extra: EscrowExtra,\n tokenAddress: `0x${string}`,\n chainId: number,\n): Promise<`0x${string}`> {\n // EIP-712 domain - name must match the token's EIP-712 domain\n // (e.g., \"USDC\" for Base USDC, not \"USD Coin\")\n const domain = {\n name: extra.name,\n version: extra.version,\n chainId,\n verifyingContract: getAddress(tokenAddress),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return signer.signTypedData({\n domain,\n types: RECEIVE_AUTHORIZATION_TYPES,\n primaryType: \"ReceiveWithAuthorization\",\n message,\n });\n}\n\n/**\n * Verify ERC-3009 signature (facilitator-side)\n * @param signer - The signer with verifyTypedData method\n * @param authorization - ERC-3009 authorization data\n * @param signature - The signature to verify\n * @param extra - Extra configuration including chainId\n * @param tokenAddress - The token contract address (verifyingContract for EIP-712)\n */\nexport async function verifyERC3009Signature(\n signer: {\n verifyTypedData: (args: {\n address: `0x${string}`;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n signature: `0x${string}`;\n }) => Promise<boolean>;\n },\n authorization: EscrowPayload[\"authorization\"],\n signature: `0x${string}`,\n extra: EscrowExtra & { chainId: number },\n tokenAddress: `0x${string}`,\n): Promise<boolean> {\n const domain = {\n name: extra.name,\n version: extra.version,\n chainId: extra.chainId,\n verifyingContract: getAddress(tokenAddress),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n try {\n return await signer.verifyTypedData({\n address: getAddress(authorization.from),\n domain,\n types: RECEIVE_AUTHORIZATION_TYPES,\n primaryType: \"ReceiveWithAuthorization\",\n message,\n signature,\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Generate random salt for paymentInfo\n */\nexport function generateSalt(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return toHex(bytes);\n}\n","/**\n * Type guard for EscrowPayload\n */\nexport function isEscrowPayload(value: unknown): value is EscrowPayload {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"authorization\" in value &&\n \"signature\" in value &&\n \"paymentInfo\" in value\n );\n}\n\n/**\n * Type guard for EscrowExtra\n */\nexport function isEscrowExtra(value: unknown): value is EscrowExtra {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"escrowAddress\" in value &&\n \"operatorAddress\" in value &&\n \"tokenCollector\" in value\n );\n}\n\n// EscrowExtra - fields in PaymentRequirements.extra\nexport interface EscrowExtra {\n escrowAddress: `0x${string}`;\n operatorAddress: `0x${string}`;\n tokenCollector: `0x${string}`;\n authorizeAddress?: `0x${string}`;\n minDeposit?: string;\n maxDeposit?: string;\n preApprovalExpirySeconds?: number;\n authorizationExpirySeconds?: number;\n refundExpirySeconds?: number;\n minFeeBps?: number;\n maxFeeBps?: number;\n feeReceiver?: `0x${string}`;\n name: string; // EIP-712 domain name (e.g., \"USDC\" for Base USDC)\n version: string; // EIP-712 domain version (e.g., \"2\" for USDC)\n}\n\n// EscrowPayload - the payload field in PaymentPayload\nexport interface EscrowPayload {\n authorization: {\n from: `0x${string}`;\n to: `0x${string}`;\n value: string;\n validAfter: string;\n validBefore: string;\n nonce: `0x${string}`;\n };\n signature: `0x${string}`;\n paymentInfo: {\n operator: `0x${string}`;\n receiver: `0x${string}`;\n token: `0x${string}`;\n maxAmount: string;\n preApprovalExpiry: number;\n authorizationExpiry: number;\n refundExpiry: number;\n minFeeBps: number;\n maxFeeBps: number;\n feeReceiver: `0x${string}`;\n salt: `0x${string}`;\n };\n}\n","/**\n * Parse chainId from CAIP-2 network identifier\n * @param network - CAIP-2 network identifier (e.g., 'eip155:84532')\n * @returns The chain ID as a number\n */\nexport function parseChainId(network: string): number {\n const parts = network.split(\":\");\n if (parts.length !== 2 || parts[0] !== \"eip155\") {\n throw new Error(\n `Invalid network format: ${network}. Expected 'eip155:<chainId>'`,\n );\n }\n const chainId = parseInt(parts[1], 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid chainId in network: ${network}`);\n }\n return chainId;\n}\n","import type { Network } from \"@x402/core/types\";\nimport type { FacilitatorEvmSigner } from \"@x402/evm\";\nimport { x402Facilitator } from \"@x402/core/facilitator\";\nimport { EscrowFacilitatorScheme } from \"./scheme\";\n\nexport interface EvmFacilitatorConfig {\n signer: FacilitatorEvmSigner;\n networks: Network | Network[];\n}\n\n/**\n * Register escrow scheme with x402Facilitator\n *\n * The facilitator is operator-agnostic — it supports any operator. Operator,\n * escrow, and tokenCollector addresses are provided per-request by the merchant\n * via `refundable()` and arrive in `requirements.extra`.\n *\n * @example\n * ```typescript\n * const facilitator = new x402Facilitator();\n * registerEscrowEvmScheme(facilitator, {\n * signer: evmSigner,\n * networks: \"eip155:84532\",\n * });\n * ```\n */\nexport function registerEscrowEvmScheme(\n facilitator: x402Facilitator,\n config: EvmFacilitatorConfig,\n): x402Facilitator {\n facilitator.register(\n config.networks,\n new EscrowFacilitatorScheme(config.signer),\n );\n return facilitator;\n}\n"],"mappings":"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","names":["import_viem"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, FacilitatorContext, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
|
|
2
|
+
import { FacilitatorEvmSigner } from '@x402/evm';
|
|
3
|
+
import { x402Facilitator } from '@x402/core/facilitator';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Escrow Scheme - Facilitator
|
|
7
|
+
* Handles verification and settlement of escrow payments.
|
|
8
|
+
*
|
|
9
|
+
* Implements x402's SchemeNetworkFacilitator interface so the escrow scheme
|
|
10
|
+
* is a drop-in for the x402 facilitator, just like ExactEvmScheme.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Escrow Facilitator Scheme - implements x402's SchemeNetworkFacilitator
|
|
15
|
+
*
|
|
16
|
+
* The facilitator is operator-agnostic: it does not store operator/escrow/tokenCollector
|
|
17
|
+
* config. Those values are set by the merchant via `refundable()` and arrive in
|
|
18
|
+
* `requirements.extra` at verify/settle time.
|
|
19
|
+
*/
|
|
20
|
+
declare class EscrowFacilitatorScheme implements SchemeNetworkFacilitator {
|
|
21
|
+
private signer;
|
|
22
|
+
readonly scheme = "escrow";
|
|
23
|
+
readonly caipFamily = "eip155:*";
|
|
24
|
+
constructor(signer: FacilitatorEvmSigner);
|
|
25
|
+
getSigners(_network: string): string[];
|
|
26
|
+
getExtra(_network: string): Record<string, unknown> | undefined;
|
|
27
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements, _context?: FacilitatorContext): Promise<VerifyResponse>;
|
|
28
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements, _context?: FacilitatorContext): Promise<SettleResponse>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface EvmFacilitatorConfig {
|
|
32
|
+
signer: FacilitatorEvmSigner;
|
|
33
|
+
networks: Network | Network[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Register escrow scheme with x402Facilitator
|
|
37
|
+
*
|
|
38
|
+
* The facilitator is operator-agnostic — it supports any operator. Operator,
|
|
39
|
+
* escrow, and tokenCollector addresses are provided per-request by the merchant
|
|
40
|
+
* via `refundable()` and arrive in `requirements.extra`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const facilitator = new x402Facilitator();
|
|
45
|
+
* registerEscrowEvmScheme(facilitator, {
|
|
46
|
+
* signer: evmSigner,
|
|
47
|
+
* networks: "eip155:84532",
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function registerEscrowEvmScheme(facilitator: x402Facilitator, config: EvmFacilitatorConfig): x402Facilitator;
|
|
52
|
+
|
|
53
|
+
export { EscrowFacilitatorScheme, type EvmFacilitatorConfig, registerEscrowEvmScheme };
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, FacilitatorContext, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
|
|
2
|
+
import { FacilitatorEvmSigner } from '@x402/evm';
|
|
3
|
+
import { x402Facilitator } from '@x402/core/facilitator';
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* Escrow Scheme - Facilitator
|
|
3
7
|
* Handles verification and settlement of escrow payments.
|
|
@@ -5,9 +9,7 @@
|
|
|
5
9
|
* Implements x402's SchemeNetworkFacilitator interface so the escrow scheme
|
|
6
10
|
* is a drop-in for the x402 facilitator, just like ExactEvmScheme.
|
|
7
11
|
*/
|
|
8
|
-
|
|
9
|
-
import type { FacilitatorEvmSigner } from "@x402/evm";
|
|
10
|
-
import { x402Facilitator } from "@x402/core/facilitator";
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Escrow Facilitator Scheme - implements x402's SchemeNetworkFacilitator
|
|
13
15
|
*
|
|
@@ -15,15 +17,20 @@ import { x402Facilitator } from "@x402/core/facilitator";
|
|
|
15
17
|
* config. Those values are set by the merchant via `refundable()` and arrive in
|
|
16
18
|
* `requirements.extra` at verify/settle time.
|
|
17
19
|
*/
|
|
18
|
-
|
|
20
|
+
declare class EscrowFacilitatorScheme implements SchemeNetworkFacilitator {
|
|
19
21
|
private signer;
|
|
20
22
|
readonly scheme = "escrow";
|
|
21
23
|
readonly caipFamily = "eip155:*";
|
|
22
24
|
constructor(signer: FacilitatorEvmSigner);
|
|
23
25
|
getSigners(_network: string): string[];
|
|
24
26
|
getExtra(_network: string): Record<string, unknown> | undefined;
|
|
25
|
-
verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
|
|
26
|
-
settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
|
|
27
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements, _context?: FacilitatorContext): Promise<VerifyResponse>;
|
|
28
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements, _context?: FacilitatorContext): Promise<SettleResponse>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface EvmFacilitatorConfig {
|
|
32
|
+
signer: FacilitatorEvmSigner;
|
|
33
|
+
networks: Network | Network[];
|
|
27
34
|
}
|
|
28
35
|
/**
|
|
29
36
|
* Register escrow scheme with x402Facilitator
|
|
@@ -35,15 +42,12 @@ export declare class EscrowFacilitatorScheme implements SchemeNetworkFacilitator
|
|
|
35
42
|
* @example
|
|
36
43
|
* ```typescript
|
|
37
44
|
* const facilitator = new x402Facilitator();
|
|
38
|
-
*
|
|
45
|
+
* registerEscrowEvmScheme(facilitator, {
|
|
39
46
|
* signer: evmSigner,
|
|
40
47
|
* networks: "eip155:84532",
|
|
41
48
|
* });
|
|
42
49
|
* ```
|
|
43
50
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}): x402Facilitator;
|
|
48
|
-
export type { EscrowExtra, EscrowPayload } from "../../shared/types.js";
|
|
49
|
-
//# sourceMappingURL=index.d.ts.map
|
|
51
|
+
declare function registerEscrowEvmScheme(facilitator: x402Facilitator, config: EvmFacilitatorConfig): x402Facilitator;
|
|
52
|
+
|
|
53
|
+
export { EscrowFacilitatorScheme, type EvmFacilitatorConfig, registerEscrowEvmScheme };
|