@bankofai/x402-evm 1.0.0-beta.0
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 +172 -0
- package/dist/cjs/auth-capture/client/index.d.ts +44 -0
- package/dist/cjs/auth-capture/client/index.js +298 -0
- package/dist/cjs/auth-capture/client/index.js.map +1 -0
- package/dist/cjs/batch-settlement/client/file-storage.d.ts +47 -0
- package/dist/cjs/batch-settlement/client/file-storage.js +116 -0
- package/dist/cjs/batch-settlement/client/file-storage.js.map +1 -0
- package/dist/cjs/batch-settlement/client/index.d.ts +111 -0
- package/dist/cjs/batch-settlement/client/index.js +1565 -0
- package/dist/cjs/batch-settlement/client/index.js.map +1 -0
- package/dist/cjs/batch-settlement/facilitator/index.d.ts +72 -0
- package/dist/cjs/batch-settlement/facilitator/index.js +2102 -0
- package/dist/cjs/batch-settlement/facilitator/index.js.map +1 -0
- package/dist/cjs/batch-settlement/server/file-storage.d.ts +53 -0
- package/dist/cjs/batch-settlement/server/file-storage.js +181 -0
- package/dist/cjs/batch-settlement/server/file-storage.js.map +1 -0
- package/dist/cjs/batch-settlement/server/index.d.ts +491 -0
- package/dist/cjs/batch-settlement/server/index.js +1978 -0
- package/dist/cjs/batch-settlement/server/index.js.map +1 -0
- package/dist/cjs/batch-settlement/server/redis-storage.d.ts +87 -0
- package/dist/cjs/batch-settlement/server/redis-storage.js +181 -0
- package/dist/cjs/batch-settlement/server/redis-storage.js.map +1 -0
- package/dist/cjs/client/agent-wallet.d.ts +69 -0
- package/dist/cjs/client/agent-wallet.js +84 -0
- package/dist/cjs/client/agent-wallet.js.map +1 -0
- package/dist/cjs/exact/client/index.d.ts +63 -0
- package/dist/cjs/exact/client/index.js +739 -0
- package/dist/cjs/exact/client/index.js.map +1 -0
- package/dist/cjs/exact/facilitator/index.d.ts +141 -0
- package/dist/cjs/exact/facilitator/index.js +1989 -0
- package/dist/cjs/exact/facilitator/index.js.map +1 -0
- package/dist/cjs/exact/server/index.d.ts +118 -0
- package/dist/cjs/exact/server/index.js +326 -0
- package/dist/cjs/exact/server/index.js.map +1 -0
- package/dist/cjs/exact/v1/client/index.d.ts +38 -0
- package/dist/cjs/exact/v1/client/index.js +193 -0
- package/dist/cjs/exact/v1/client/index.js.map +1 -0
- package/dist/cjs/exact/v1/facilitator/index.d.ts +84 -0
- package/dist/cjs/exact/v1/facilitator/index.js +739 -0
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -0
- package/dist/cjs/facilitator/agent-wallet.d.ts +109 -0
- package/dist/cjs/facilitator/agent-wallet.js +105 -0
- package/dist/cjs/facilitator/agent-wallet.js.map +1 -0
- package/dist/cjs/index.d.ts +338 -0
- package/dist/cjs/index.js +2860 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/permit2-DK5A8alk.d.ts +729 -0
- package/dist/cjs/permit2-DhJRUcgY.d.ts +729 -0
- package/dist/cjs/rpc-DULZzRne.d.ts +13 -0
- package/dist/cjs/scheme-7ehldYoO.d.ts +307 -0
- package/dist/cjs/scheme-BjBJzHF7.d.ts +307 -0
- package/dist/cjs/scheme-DWgpkDgz.d.ts +47 -0
- package/dist/cjs/signer-BFelv8DL.d.ts +170 -0
- package/dist/cjs/storage-6W5MO46W.d.ts +50 -0
- package/dist/cjs/storage-CHNote8s.d.ts +81 -0
- package/dist/cjs/storage-DjCv5IPh.d.ts +81 -0
- package/dist/cjs/types-CKd3Xoi1.d.ts +180 -0
- package/dist/cjs/types-DIt9uAUy.d.ts +180 -0
- package/dist/cjs/upto/client/index.d.ts +34 -0
- package/dist/cjs/upto/client/index.js +509 -0
- package/dist/cjs/upto/client/index.js.map +1 -0
- package/dist/cjs/upto/facilitator/index.d.ts +54 -0
- package/dist/cjs/upto/facilitator/index.js +1313 -0
- package/dist/cjs/upto/facilitator/index.js.map +1 -0
- package/dist/cjs/upto/server/index.d.ts +69 -0
- package/dist/cjs/upto/server/index.js +296 -0
- package/dist/cjs/upto/server/index.js.map +1 -0
- package/dist/cjs/v1/index.d.ts +40 -0
- package/dist/cjs/v1/index.js +199 -0
- package/dist/cjs/v1/index.js.map +1 -0
- package/dist/esm/auth-capture/client/index.d.mts +44 -0
- package/dist/esm/auth-capture/client/index.mjs +8 -0
- package/dist/esm/auth-capture/client/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/client/file-storage.d.mts +47 -0
- package/dist/esm/batch-settlement/client/file-storage.mjs +63 -0
- package/dist/esm/batch-settlement/client/file-storage.mjs.map +1 -0
- package/dist/esm/batch-settlement/client/index.d.mts +111 -0
- package/dist/esm/batch-settlement/client/index.mjs +58 -0
- package/dist/esm/batch-settlement/client/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/facilitator/index.d.mts +72 -0
- package/dist/esm/batch-settlement/facilitator/index.mjs +1252 -0
- package/dist/esm/batch-settlement/facilitator/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/file-storage.d.mts +53 -0
- package/dist/esm/batch-settlement/server/file-storage.mjs +128 -0
- package/dist/esm/batch-settlement/server/file-storage.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/index.d.mts +491 -0
- package/dist/esm/batch-settlement/server/index.mjs +1640 -0
- package/dist/esm/batch-settlement/server/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/redis-storage.d.mts +87 -0
- package/dist/esm/batch-settlement/server/redis-storage.mjs +156 -0
- package/dist/esm/batch-settlement/server/redis-storage.mjs.map +1 -0
- package/dist/esm/chunk-2EUQTNJO.mjs +38 -0
- package/dist/esm/chunk-2EUQTNJO.mjs.map +1 -0
- package/dist/esm/chunk-3WZF6722.mjs +36 -0
- package/dist/esm/chunk-3WZF6722.mjs.map +1 -0
- package/dist/esm/chunk-E4Z7PNXC.mjs +275 -0
- package/dist/esm/chunk-E4Z7PNXC.mjs.map +1 -0
- package/dist/esm/chunk-GQVMVP4N.mjs +911 -0
- package/dist/esm/chunk-GQVMVP4N.mjs.map +1 -0
- package/dist/esm/chunk-H2EYJIZL.mjs +489 -0
- package/dist/esm/chunk-H2EYJIZL.mjs.map +1 -0
- package/dist/esm/chunk-H3KPLYGI.mjs +152 -0
- package/dist/esm/chunk-H3KPLYGI.mjs.map +1 -0
- package/dist/esm/chunk-HYABYUBD.mjs +432 -0
- package/dist/esm/chunk-HYABYUBD.mjs.map +1 -0
- package/dist/esm/chunk-I2DVUHM5.mjs +123 -0
- package/dist/esm/chunk-I2DVUHM5.mjs.map +1 -0
- package/dist/esm/chunk-JK7SLLF7.mjs +34 -0
- package/dist/esm/chunk-JK7SLLF7.mjs.map +1 -0
- package/dist/esm/chunk-JNT7C46S.mjs +352 -0
- package/dist/esm/chunk-JNT7C46S.mjs.map +1 -0
- package/dist/esm/chunk-MACPBXCT.mjs +415 -0
- package/dist/esm/chunk-MACPBXCT.mjs.map +1 -0
- package/dist/esm/chunk-P3QOX3QZ.mjs +113 -0
- package/dist/esm/chunk-P3QOX3QZ.mjs.map +1 -0
- package/dist/esm/chunk-QVATVA3J.mjs +47 -0
- package/dist/esm/chunk-QVATVA3J.mjs.map +1 -0
- package/dist/esm/chunk-SHJFA25H.mjs +159 -0
- package/dist/esm/chunk-SHJFA25H.mjs.map +1 -0
- package/dist/esm/chunk-TW7Z65AO.mjs +34 -0
- package/dist/esm/chunk-TW7Z65AO.mjs.map +1 -0
- package/dist/esm/chunk-U4HCGTLU.mjs +35 -0
- package/dist/esm/chunk-U4HCGTLU.mjs.map +1 -0
- package/dist/esm/chunk-VS3RYAYE.mjs +80 -0
- package/dist/esm/chunk-VS3RYAYE.mjs.map +1 -0
- package/dist/esm/chunk-W6ON4LG2.mjs +39 -0
- package/dist/esm/chunk-W6ON4LG2.mjs.map +1 -0
- package/dist/esm/chunk-XG2JLZVJ.mjs +627 -0
- package/dist/esm/chunk-XG2JLZVJ.mjs.map +1 -0
- package/dist/esm/chunk-ZCJRY5LQ.mjs +162 -0
- package/dist/esm/chunk-ZCJRY5LQ.mjs.map +1 -0
- package/dist/esm/client/agent-wallet.d.mts +69 -0
- package/dist/esm/client/agent-wallet.mjs +36 -0
- package/dist/esm/client/agent-wallet.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +63 -0
- package/dist/esm/exact/client/index.mjs +25 -0
- package/dist/esm/exact/client/index.mjs.map +1 -0
- package/dist/esm/exact/facilitator/index.d.mts +141 -0
- package/dist/esm/exact/facilitator/index.mjs +694 -0
- package/dist/esm/exact/facilitator/index.mjs.map +1 -0
- package/dist/esm/exact/server/index.d.mts +118 -0
- package/dist/esm/exact/server/index.mjs +153 -0
- package/dist/esm/exact/server/index.mjs.map +1 -0
- package/dist/esm/exact/v1/client/index.d.mts +38 -0
- package/dist/esm/exact/v1/client/index.mjs +12 -0
- package/dist/esm/exact/v1/client/index.mjs.map +1 -0
- package/dist/esm/exact/v1/facilitator/index.d.mts +84 -0
- package/dist/esm/exact/v1/facilitator/index.mjs +12 -0
- package/dist/esm/exact/v1/facilitator/index.mjs.map +1 -0
- package/dist/esm/facilitator/agent-wallet.d.mts +109 -0
- package/dist/esm/facilitator/agent-wallet.mjs +74 -0
- package/dist/esm/facilitator/agent-wallet.mjs.map +1 -0
- package/dist/esm/index.d.mts +338 -0
- package/dist/esm/index.mjs +144 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/permit2-DhJRUcgY.d.mts +729 -0
- package/dist/esm/rpc-DULZzRne.d.mts +13 -0
- package/dist/esm/scheme-CkNhpXrG.d.mts +307 -0
- package/dist/esm/scheme-D8ZbykGV.d.mts +47 -0
- package/dist/esm/signer-BFelv8DL.d.mts +170 -0
- package/dist/esm/storage-6W5MO46W.d.mts +50 -0
- package/dist/esm/storage-BEzTEiUr.d.mts +81 -0
- package/dist/esm/types-DIt9uAUy.d.mts +180 -0
- package/dist/esm/upto/client/index.d.mts +34 -0
- package/dist/esm/upto/client/index.mjs +22 -0
- package/dist/esm/upto/client/index.mjs.map +1 -0
- package/dist/esm/upto/facilitator/index.d.mts +54 -0
- package/dist/esm/upto/facilitator/index.mjs +507 -0
- package/dist/esm/upto/facilitator/index.mjs.map +1 -0
- package/dist/esm/upto/server/index.d.mts +69 -0
- package/dist/esm/upto/server/index.mjs +124 -0
- package/dist/esm/upto/server/index.mjs.map +1 -0
- package/dist/esm/v1/index.d.mts +40 -0
- package/dist/esm/v1/index.mjs +18 -0
- package/dist/esm/v1/index.mjs.map +1 -0
- package/package.json +250 -0
|
@@ -0,0 +1,2860 @@
|
|
|
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 __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
AUTH_CAPTURE_ESCROW_ADDRESS: () => AUTH_CAPTURE_ESCROW_ADDRESS,
|
|
24
|
+
AUTH_CAPTURE_SCHEME: () => AUTH_CAPTURE_SCHEME,
|
|
25
|
+
AuthCaptureEvmScheme: () => AuthCaptureEvmScheme,
|
|
26
|
+
BATCH_SETTLEMENT_ADDRESS: () => BATCH_SETTLEMENT_ADDRESS,
|
|
27
|
+
BATCH_SETTLEMENT_DOMAIN: () => BATCH_SETTLEMENT_DOMAIN,
|
|
28
|
+
BATCH_SETTLEMENT_SCHEME: () => BATCH_SETTLEMENT_SCHEME,
|
|
29
|
+
BUILDER_CODE_KEY: () => BUILDER_CODE_KEY,
|
|
30
|
+
BatchSettlementEvmScheme: () => BatchSettlementEvmScheme,
|
|
31
|
+
DEFAULT_STABLECOINS: () => DEFAULT_STABLECOINS,
|
|
32
|
+
EIP3009_TOKEN_COLLECTOR_ADDRESS: () => EIP3009_TOKEN_COLLECTOR_ADDRESS,
|
|
33
|
+
ERC3009_DEPOSIT_COLLECTOR_ADDRESS: () => ERC3009_DEPOSIT_COLLECTOR_ADDRESS,
|
|
34
|
+
ExactEvmScheme: () => ExactEvmScheme,
|
|
35
|
+
PERMIT2_ADDRESS: () => PERMIT2_ADDRESS,
|
|
36
|
+
PERMIT2_TOKEN_COLLECTOR_ADDRESS: () => PERMIT2_TOKEN_COLLECTOR_ADDRESS,
|
|
37
|
+
UptoEvmScheme: () => UptoEvmScheme,
|
|
38
|
+
appendDataSuffix: () => appendDataSuffix,
|
|
39
|
+
authorizationTypes: () => authorizationTypes,
|
|
40
|
+
claimBatchTypes: () => claimBatchTypes,
|
|
41
|
+
createPermit2ApprovalTx: () => createPermit2ApprovalTx,
|
|
42
|
+
eip3009ABI: () => eip3009ABI,
|
|
43
|
+
erc20AllowanceAbi: () => erc20AllowanceAbi,
|
|
44
|
+
getDefaultAsset: () => getDefaultAsset,
|
|
45
|
+
getPermit2AllowanceReadParams: () => getPermit2AllowanceReadParams,
|
|
46
|
+
isAuthCaptureExtra: () => isAuthCaptureExtra,
|
|
47
|
+
isAuthCapturePayload: () => isAuthCapturePayload,
|
|
48
|
+
isBatchSettlementClaimPayload: () => isBatchSettlementClaimPayload,
|
|
49
|
+
isBatchSettlementDepositPayload: () => isBatchSettlementDepositPayload,
|
|
50
|
+
isBatchSettlementEnrichedRefundPayload: () => isBatchSettlementEnrichedRefundPayload,
|
|
51
|
+
isBatchSettlementRefundPayload: () => isBatchSettlementRefundPayload,
|
|
52
|
+
isBatchSettlementSettlePayload: () => isBatchSettlementSettlePayload,
|
|
53
|
+
isBatchSettlementVoucherPayload: () => isBatchSettlementVoucherPayload,
|
|
54
|
+
isEIP3009Payload: () => isEIP3009Payload,
|
|
55
|
+
isPermit2Payload: () => isPermit2Payload,
|
|
56
|
+
isUptoPermit2Payload: () => isUptoPermit2Payload,
|
|
57
|
+
permit2WitnessTypes: () => permit2WitnessTypes,
|
|
58
|
+
refundTypes: () => refundTypes,
|
|
59
|
+
resolveDataSuffix: () => resolveDataSuffix,
|
|
60
|
+
toClientEvmSigner: () => toClientEvmSigner,
|
|
61
|
+
toFacilitatorEvmSigner: () => toFacilitatorEvmSigner,
|
|
62
|
+
uptoPermit2WitnessTypes: () => uptoPermit2WitnessTypes,
|
|
63
|
+
voucherTypes: () => voucherTypes,
|
|
64
|
+
x402ExactPermit2ProxyABI: () => x402ExactPermit2ProxyABI,
|
|
65
|
+
x402ExactPermit2ProxyAddress: () => x402ExactPermit2ProxyAddress,
|
|
66
|
+
x402UptoPermit2ProxyABI: () => x402UptoPermit2ProxyABI,
|
|
67
|
+
x402UptoPermit2ProxyAddress: () => x402UptoPermit2ProxyAddress
|
|
68
|
+
});
|
|
69
|
+
module.exports = __toCommonJS(src_exports);
|
|
70
|
+
|
|
71
|
+
// src/exact/client/eip3009.ts
|
|
72
|
+
var import_viem2 = require("viem");
|
|
73
|
+
|
|
74
|
+
// src/constants.ts
|
|
75
|
+
var authorizationTypes = {
|
|
76
|
+
TransferWithAuthorization: [
|
|
77
|
+
{ name: "from", type: "address" },
|
|
78
|
+
{ name: "to", type: "address" },
|
|
79
|
+
{ name: "value", type: "uint256" },
|
|
80
|
+
{ name: "validAfter", type: "uint256" },
|
|
81
|
+
{ name: "validBefore", type: "uint256" },
|
|
82
|
+
{ name: "nonce", type: "bytes32" }
|
|
83
|
+
]
|
|
84
|
+
};
|
|
85
|
+
var permit2WitnessTypes = {
|
|
86
|
+
PermitWitnessTransferFrom: [
|
|
87
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
88
|
+
{ name: "spender", type: "address" },
|
|
89
|
+
{ name: "nonce", type: "uint256" },
|
|
90
|
+
{ name: "deadline", type: "uint256" },
|
|
91
|
+
{ name: "witness", type: "Witness" }
|
|
92
|
+
],
|
|
93
|
+
TokenPermissions: [
|
|
94
|
+
{ name: "token", type: "address" },
|
|
95
|
+
{ name: "amount", type: "uint256" }
|
|
96
|
+
],
|
|
97
|
+
Witness: [
|
|
98
|
+
{ name: "to", type: "address" },
|
|
99
|
+
{ name: "validAfter", type: "uint256" }
|
|
100
|
+
]
|
|
101
|
+
};
|
|
102
|
+
var uptoPermit2WitnessTypes = {
|
|
103
|
+
PermitWitnessTransferFrom: [
|
|
104
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
105
|
+
{ name: "spender", type: "address" },
|
|
106
|
+
{ name: "nonce", type: "uint256" },
|
|
107
|
+
{ name: "deadline", type: "uint256" },
|
|
108
|
+
{ name: "witness", type: "Witness" }
|
|
109
|
+
],
|
|
110
|
+
TokenPermissions: [
|
|
111
|
+
{ name: "token", type: "address" },
|
|
112
|
+
{ name: "amount", type: "uint256" }
|
|
113
|
+
],
|
|
114
|
+
Witness: [
|
|
115
|
+
{ name: "to", type: "address" },
|
|
116
|
+
{ name: "facilitator", type: "address" },
|
|
117
|
+
{ name: "validAfter", type: "uint256" }
|
|
118
|
+
]
|
|
119
|
+
};
|
|
120
|
+
var eip3009ABI = [
|
|
121
|
+
{
|
|
122
|
+
inputs: [
|
|
123
|
+
{ name: "from", type: "address" },
|
|
124
|
+
{ name: "to", type: "address" },
|
|
125
|
+
{ name: "value", type: "uint256" },
|
|
126
|
+
{ name: "validAfter", type: "uint256" },
|
|
127
|
+
{ name: "validBefore", type: "uint256" },
|
|
128
|
+
{ name: "nonce", type: "bytes32" },
|
|
129
|
+
{ name: "v", type: "uint8" },
|
|
130
|
+
{ name: "r", type: "bytes32" },
|
|
131
|
+
{ name: "s", type: "bytes32" }
|
|
132
|
+
],
|
|
133
|
+
name: "transferWithAuthorization",
|
|
134
|
+
outputs: [],
|
|
135
|
+
stateMutability: "nonpayable",
|
|
136
|
+
type: "function"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
inputs: [
|
|
140
|
+
{ name: "from", type: "address" },
|
|
141
|
+
{ name: "to", type: "address" },
|
|
142
|
+
{ name: "value", type: "uint256" },
|
|
143
|
+
{ name: "validAfter", type: "uint256" },
|
|
144
|
+
{ name: "validBefore", type: "uint256" },
|
|
145
|
+
{ name: "nonce", type: "bytes32" },
|
|
146
|
+
{ name: "signature", type: "bytes" }
|
|
147
|
+
],
|
|
148
|
+
name: "transferWithAuthorization",
|
|
149
|
+
outputs: [],
|
|
150
|
+
stateMutability: "nonpayable",
|
|
151
|
+
type: "function"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
inputs: [{ name: "account", type: "address" }],
|
|
155
|
+
name: "balanceOf",
|
|
156
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
157
|
+
stateMutability: "view",
|
|
158
|
+
type: "function"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
inputs: [],
|
|
162
|
+
name: "version",
|
|
163
|
+
outputs: [{ name: "", type: "string" }],
|
|
164
|
+
stateMutability: "view",
|
|
165
|
+
type: "function"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
inputs: [],
|
|
169
|
+
name: "name",
|
|
170
|
+
outputs: [{ name: "", type: "string" }],
|
|
171
|
+
stateMutability: "view",
|
|
172
|
+
type: "function"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
inputs: [
|
|
176
|
+
{ name: "authorizer", type: "address" },
|
|
177
|
+
{ name: "nonce", type: "bytes32" }
|
|
178
|
+
],
|
|
179
|
+
name: "authorizationState",
|
|
180
|
+
outputs: [{ name: "", type: "bool" }],
|
|
181
|
+
stateMutability: "view",
|
|
182
|
+
type: "function"
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
var eip2612PermitTypes = {
|
|
186
|
+
Permit: [
|
|
187
|
+
{ name: "owner", type: "address" },
|
|
188
|
+
{ name: "spender", type: "address" },
|
|
189
|
+
{ name: "value", type: "uint256" },
|
|
190
|
+
{ name: "nonce", type: "uint256" },
|
|
191
|
+
{ name: "deadline", type: "uint256" }
|
|
192
|
+
]
|
|
193
|
+
};
|
|
194
|
+
var eip2612NoncesAbi = [
|
|
195
|
+
{
|
|
196
|
+
type: "function",
|
|
197
|
+
name: "nonces",
|
|
198
|
+
inputs: [{ name: "owner", type: "address" }],
|
|
199
|
+
outputs: [{ type: "uint256" }],
|
|
200
|
+
stateMutability: "view"
|
|
201
|
+
}
|
|
202
|
+
];
|
|
203
|
+
var erc20ApproveAbi = [
|
|
204
|
+
{
|
|
205
|
+
type: "function",
|
|
206
|
+
name: "approve",
|
|
207
|
+
inputs: [
|
|
208
|
+
{ name: "spender", type: "address" },
|
|
209
|
+
{ name: "amount", type: "uint256" }
|
|
210
|
+
],
|
|
211
|
+
outputs: [{ type: "bool" }],
|
|
212
|
+
stateMutability: "nonpayable"
|
|
213
|
+
}
|
|
214
|
+
];
|
|
215
|
+
var erc20AllowanceAbi = [
|
|
216
|
+
{
|
|
217
|
+
type: "function",
|
|
218
|
+
name: "allowance",
|
|
219
|
+
inputs: [
|
|
220
|
+
{ name: "owner", type: "address" },
|
|
221
|
+
{ name: "spender", type: "address" }
|
|
222
|
+
],
|
|
223
|
+
outputs: [{ type: "uint256" }],
|
|
224
|
+
stateMutability: "view"
|
|
225
|
+
}
|
|
226
|
+
];
|
|
227
|
+
var ERC20_APPROVE_GAS_LIMIT = 70000n;
|
|
228
|
+
var DEFAULT_MAX_FEE_PER_GAS = 1000000000n;
|
|
229
|
+
var DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100000000n;
|
|
230
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
231
|
+
var x402ExactPermit2ProxyAddress = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
|
|
232
|
+
var x402UptoPermit2ProxyAddress = "0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002";
|
|
233
|
+
var permit2WitnessABIComponents = [
|
|
234
|
+
{ name: "to", type: "address", internalType: "address" },
|
|
235
|
+
{ name: "validAfter", type: "uint256", internalType: "uint256" }
|
|
236
|
+
];
|
|
237
|
+
var uptoPermit2WitnessABIComponents = [
|
|
238
|
+
{ name: "to", type: "address", internalType: "address" },
|
|
239
|
+
{ name: "facilitator", type: "address", internalType: "address" },
|
|
240
|
+
{ name: "validAfter", type: "uint256", internalType: "uint256" }
|
|
241
|
+
];
|
|
242
|
+
var x402UptoPermit2ProxyABI = [
|
|
243
|
+
{
|
|
244
|
+
type: "function",
|
|
245
|
+
name: "PERMIT2",
|
|
246
|
+
inputs: [],
|
|
247
|
+
outputs: [{ name: "", type: "address", internalType: "contract ISignatureTransfer" }],
|
|
248
|
+
stateMutability: "view"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
type: "function",
|
|
252
|
+
name: "WITNESS_TYPEHASH",
|
|
253
|
+
inputs: [],
|
|
254
|
+
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
|
|
255
|
+
stateMutability: "view"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
type: "function",
|
|
259
|
+
name: "WITNESS_TYPE_STRING",
|
|
260
|
+
inputs: [],
|
|
261
|
+
outputs: [{ name: "", type: "string", internalType: "string" }],
|
|
262
|
+
stateMutability: "view"
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
type: "function",
|
|
266
|
+
name: "settle",
|
|
267
|
+
inputs: [
|
|
268
|
+
{
|
|
269
|
+
name: "permit",
|
|
270
|
+
type: "tuple",
|
|
271
|
+
internalType: "struct ISignatureTransfer.PermitTransferFrom",
|
|
272
|
+
components: [
|
|
273
|
+
{
|
|
274
|
+
name: "permitted",
|
|
275
|
+
type: "tuple",
|
|
276
|
+
internalType: "struct ISignatureTransfer.TokenPermissions",
|
|
277
|
+
components: [
|
|
278
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
279
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{ name: "nonce", type: "uint256", internalType: "uint256" },
|
|
283
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" }
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
{ name: "amount", type: "uint256", internalType: "uint256" },
|
|
287
|
+
{ name: "owner", type: "address", internalType: "address" },
|
|
288
|
+
{
|
|
289
|
+
name: "witness",
|
|
290
|
+
type: "tuple",
|
|
291
|
+
internalType: "struct x402UptoPermit2Proxy.Witness",
|
|
292
|
+
components: uptoPermit2WitnessABIComponents
|
|
293
|
+
},
|
|
294
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
295
|
+
],
|
|
296
|
+
outputs: [],
|
|
297
|
+
stateMutability: "nonpayable"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
type: "function",
|
|
301
|
+
name: "settleWithPermit",
|
|
302
|
+
inputs: [
|
|
303
|
+
{
|
|
304
|
+
name: "permit2612",
|
|
305
|
+
type: "tuple",
|
|
306
|
+
internalType: "struct x402UptoPermit2Proxy.EIP2612Permit",
|
|
307
|
+
components: [
|
|
308
|
+
{ name: "value", type: "uint256", internalType: "uint256" },
|
|
309
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" },
|
|
310
|
+
{ name: "r", type: "bytes32", internalType: "bytes32" },
|
|
311
|
+
{ name: "s", type: "bytes32", internalType: "bytes32" },
|
|
312
|
+
{ name: "v", type: "uint8", internalType: "uint8" }
|
|
313
|
+
]
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: "permit",
|
|
317
|
+
type: "tuple",
|
|
318
|
+
internalType: "struct ISignatureTransfer.PermitTransferFrom",
|
|
319
|
+
components: [
|
|
320
|
+
{
|
|
321
|
+
name: "permitted",
|
|
322
|
+
type: "tuple",
|
|
323
|
+
internalType: "struct ISignatureTransfer.TokenPermissions",
|
|
324
|
+
components: [
|
|
325
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
326
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
327
|
+
]
|
|
328
|
+
},
|
|
329
|
+
{ name: "nonce", type: "uint256", internalType: "uint256" },
|
|
330
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" }
|
|
331
|
+
]
|
|
332
|
+
},
|
|
333
|
+
{ name: "amount", type: "uint256", internalType: "uint256" },
|
|
334
|
+
{ name: "owner", type: "address", internalType: "address" },
|
|
335
|
+
{
|
|
336
|
+
name: "witness",
|
|
337
|
+
type: "tuple",
|
|
338
|
+
internalType: "struct x402UptoPermit2Proxy.Witness",
|
|
339
|
+
components: uptoPermit2WitnessABIComponents
|
|
340
|
+
},
|
|
341
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
342
|
+
],
|
|
343
|
+
outputs: [],
|
|
344
|
+
stateMutability: "nonpayable"
|
|
345
|
+
},
|
|
346
|
+
{ type: "event", name: "Settled", inputs: [], anonymous: false },
|
|
347
|
+
{ type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
|
|
348
|
+
{ type: "error", name: "AmountExceedsPermitted", inputs: [] },
|
|
349
|
+
{ type: "error", name: "InvalidDestination", inputs: [] },
|
|
350
|
+
{ type: "error", name: "InvalidOwner", inputs: [] },
|
|
351
|
+
{ type: "error", name: "InvalidPermit2Address", inputs: [] },
|
|
352
|
+
{ type: "error", name: "PaymentTooEarly", inputs: [] },
|
|
353
|
+
{ type: "error", name: "Permit2612AmountMismatch", inputs: [] },
|
|
354
|
+
{ type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] },
|
|
355
|
+
{ type: "error", name: "UnauthorizedFacilitator", inputs: [] }
|
|
356
|
+
];
|
|
357
|
+
var x402ExactPermit2ProxyABI = [
|
|
358
|
+
{
|
|
359
|
+
type: "function",
|
|
360
|
+
name: "PERMIT2",
|
|
361
|
+
inputs: [],
|
|
362
|
+
outputs: [{ name: "", type: "address", internalType: "contract ISignatureTransfer" }],
|
|
363
|
+
stateMutability: "view"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
type: "function",
|
|
367
|
+
name: "WITNESS_TYPEHASH",
|
|
368
|
+
inputs: [],
|
|
369
|
+
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
|
|
370
|
+
stateMutability: "view"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
type: "function",
|
|
374
|
+
name: "WITNESS_TYPE_STRING",
|
|
375
|
+
inputs: [],
|
|
376
|
+
outputs: [{ name: "", type: "string", internalType: "string" }],
|
|
377
|
+
stateMutability: "view"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
type: "function",
|
|
381
|
+
name: "settle",
|
|
382
|
+
inputs: [
|
|
383
|
+
{
|
|
384
|
+
name: "permit",
|
|
385
|
+
type: "tuple",
|
|
386
|
+
internalType: "struct ISignatureTransfer.PermitTransferFrom",
|
|
387
|
+
components: [
|
|
388
|
+
{
|
|
389
|
+
name: "permitted",
|
|
390
|
+
type: "tuple",
|
|
391
|
+
internalType: "struct ISignatureTransfer.TokenPermissions",
|
|
392
|
+
components: [
|
|
393
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
394
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
395
|
+
]
|
|
396
|
+
},
|
|
397
|
+
{ name: "nonce", type: "uint256", internalType: "uint256" },
|
|
398
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" }
|
|
399
|
+
]
|
|
400
|
+
},
|
|
401
|
+
{ name: "owner", type: "address", internalType: "address" },
|
|
402
|
+
{
|
|
403
|
+
name: "witness",
|
|
404
|
+
type: "tuple",
|
|
405
|
+
internalType: "struct x402ExactPermit2Proxy.Witness",
|
|
406
|
+
components: permit2WitnessABIComponents
|
|
407
|
+
},
|
|
408
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
409
|
+
],
|
|
410
|
+
outputs: [],
|
|
411
|
+
stateMutability: "nonpayable"
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
type: "function",
|
|
415
|
+
name: "settleWithPermit",
|
|
416
|
+
inputs: [
|
|
417
|
+
{
|
|
418
|
+
name: "permit2612",
|
|
419
|
+
type: "tuple",
|
|
420
|
+
internalType: "struct x402ExactPermit2Proxy.EIP2612Permit",
|
|
421
|
+
components: [
|
|
422
|
+
{ name: "value", type: "uint256", internalType: "uint256" },
|
|
423
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" },
|
|
424
|
+
{ name: "r", type: "bytes32", internalType: "bytes32" },
|
|
425
|
+
{ name: "s", type: "bytes32", internalType: "bytes32" },
|
|
426
|
+
{ name: "v", type: "uint8", internalType: "uint8" }
|
|
427
|
+
]
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
name: "permit",
|
|
431
|
+
type: "tuple",
|
|
432
|
+
internalType: "struct ISignatureTransfer.PermitTransferFrom",
|
|
433
|
+
components: [
|
|
434
|
+
{
|
|
435
|
+
name: "permitted",
|
|
436
|
+
type: "tuple",
|
|
437
|
+
internalType: "struct ISignatureTransfer.TokenPermissions",
|
|
438
|
+
components: [
|
|
439
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
440
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
441
|
+
]
|
|
442
|
+
},
|
|
443
|
+
{ name: "nonce", type: "uint256", internalType: "uint256" },
|
|
444
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" }
|
|
445
|
+
]
|
|
446
|
+
},
|
|
447
|
+
{ name: "owner", type: "address", internalType: "address" },
|
|
448
|
+
{
|
|
449
|
+
name: "witness",
|
|
450
|
+
type: "tuple",
|
|
451
|
+
internalType: "struct x402ExactPermit2Proxy.Witness",
|
|
452
|
+
components: permit2WitnessABIComponents
|
|
453
|
+
},
|
|
454
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
455
|
+
],
|
|
456
|
+
outputs: [],
|
|
457
|
+
stateMutability: "nonpayable"
|
|
458
|
+
},
|
|
459
|
+
{ type: "event", name: "Settled", inputs: [], anonymous: false },
|
|
460
|
+
{ type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
|
|
461
|
+
{ type: "error", name: "InvalidAmount", inputs: [] },
|
|
462
|
+
{ type: "error", name: "InvalidDestination", inputs: [] },
|
|
463
|
+
{ type: "error", name: "InvalidOwner", inputs: [] },
|
|
464
|
+
{ type: "error", name: "InvalidPermit2Address", inputs: [] },
|
|
465
|
+
{ type: "error", name: "PaymentTooEarly", inputs: [] },
|
|
466
|
+
{ type: "error", name: "Permit2612AmountMismatch", inputs: [] },
|
|
467
|
+
{ type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] }
|
|
468
|
+
];
|
|
469
|
+
|
|
470
|
+
// src/utils.ts
|
|
471
|
+
var import_viem = require("viem");
|
|
472
|
+
function getEvmChainId(network) {
|
|
473
|
+
if (network.startsWith("eip155:")) {
|
|
474
|
+
const idStr = network.split(":")[1];
|
|
475
|
+
const chainId = parseInt(idStr, 10);
|
|
476
|
+
if (isNaN(chainId)) {
|
|
477
|
+
throw new Error(`Invalid CAIP-2 chain ID: ${network}`);
|
|
478
|
+
}
|
|
479
|
+
return chainId;
|
|
480
|
+
}
|
|
481
|
+
throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);
|
|
482
|
+
}
|
|
483
|
+
function getCrypto() {
|
|
484
|
+
const cryptoObj = globalThis.crypto;
|
|
485
|
+
if (!cryptoObj) {
|
|
486
|
+
throw new Error("Crypto API not available");
|
|
487
|
+
}
|
|
488
|
+
return cryptoObj;
|
|
489
|
+
}
|
|
490
|
+
function createNonce() {
|
|
491
|
+
return (0, import_viem.toHex)(getCrypto().getRandomValues(new Uint8Array(32)));
|
|
492
|
+
}
|
|
493
|
+
function createPermit2Nonce() {
|
|
494
|
+
const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));
|
|
495
|
+
return BigInt((0, import_viem.toHex)(randomBytes)).toString();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/exact/client/eip3009.ts
|
|
499
|
+
async function createEIP3009Payload(signer, x402Version, paymentRequirements) {
|
|
500
|
+
const nonce = createNonce();
|
|
501
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
502
|
+
const authorization = {
|
|
503
|
+
from: signer.address,
|
|
504
|
+
to: (0, import_viem2.getAddress)(paymentRequirements.payTo),
|
|
505
|
+
value: paymentRequirements.amount,
|
|
506
|
+
validAfter: "0",
|
|
507
|
+
validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),
|
|
508
|
+
nonce
|
|
509
|
+
};
|
|
510
|
+
const signature = await signEIP3009Authorization(signer, authorization, paymentRequirements);
|
|
511
|
+
const payload = {
|
|
512
|
+
authorization,
|
|
513
|
+
signature
|
|
514
|
+
};
|
|
515
|
+
return {
|
|
516
|
+
x402Version,
|
|
517
|
+
payload
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
async function signEIP3009Authorization(signer, authorization, requirements) {
|
|
521
|
+
const chainId = getEvmChainId(requirements.network);
|
|
522
|
+
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
523
|
+
throw new Error(
|
|
524
|
+
`EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
const { name, version } = requirements.extra;
|
|
528
|
+
const domain = {
|
|
529
|
+
name,
|
|
530
|
+
version,
|
|
531
|
+
chainId,
|
|
532
|
+
verifyingContract: (0, import_viem2.getAddress)(requirements.asset)
|
|
533
|
+
};
|
|
534
|
+
const message = {
|
|
535
|
+
from: (0, import_viem2.getAddress)(authorization.from),
|
|
536
|
+
to: (0, import_viem2.getAddress)(authorization.to),
|
|
537
|
+
value: BigInt(authorization.value),
|
|
538
|
+
validAfter: BigInt(authorization.validAfter),
|
|
539
|
+
validBefore: BigInt(authorization.validBefore),
|
|
540
|
+
nonce: authorization.nonce
|
|
541
|
+
};
|
|
542
|
+
return await signer.signTypedData({
|
|
543
|
+
domain,
|
|
544
|
+
types: authorizationTypes,
|
|
545
|
+
primaryType: "TransferWithAuthorization",
|
|
546
|
+
message
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// src/exact/client/permit2.ts
|
|
551
|
+
var import_viem6 = require("viem");
|
|
552
|
+
|
|
553
|
+
// src/exact/extensions.ts
|
|
554
|
+
var EIP2612_GAS_SPONSORING_KEY = "eip2612GasSponsoring";
|
|
555
|
+
var ERC20_APPROVAL_GAS_SPONSORING_KEY = "erc20ApprovalGasSponsoring";
|
|
556
|
+
var ERC20_APPROVAL_GAS_SPONSORING_VERSION = "1";
|
|
557
|
+
|
|
558
|
+
// src/shared/permit2.ts
|
|
559
|
+
var import_viem5 = require("viem");
|
|
560
|
+
|
|
561
|
+
// src/multicall.ts
|
|
562
|
+
var import_viem3 = require("viem");
|
|
563
|
+
|
|
564
|
+
// src/shared/erc20approval.ts
|
|
565
|
+
var import_viem4 = require("viem");
|
|
566
|
+
|
|
567
|
+
// src/shared/permit2.ts
|
|
568
|
+
async function createPermit2PayloadForProxy(proxyAddress, signer, x402Version, paymentRequirements) {
|
|
569
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
570
|
+
const nonce = createPermit2Nonce();
|
|
571
|
+
const validAfter = "0";
|
|
572
|
+
const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();
|
|
573
|
+
const permit2Authorization = {
|
|
574
|
+
from: signer.address,
|
|
575
|
+
permitted: {
|
|
576
|
+
token: (0, import_viem5.getAddress)(paymentRequirements.asset),
|
|
577
|
+
amount: paymentRequirements.amount
|
|
578
|
+
},
|
|
579
|
+
spender: proxyAddress,
|
|
580
|
+
nonce,
|
|
581
|
+
deadline,
|
|
582
|
+
witness: {
|
|
583
|
+
to: (0, import_viem5.getAddress)(paymentRequirements.payTo),
|
|
584
|
+
validAfter
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
const signature = await signPermit2Authorization(
|
|
588
|
+
signer,
|
|
589
|
+
permit2Authorization,
|
|
590
|
+
paymentRequirements
|
|
591
|
+
);
|
|
592
|
+
return {
|
|
593
|
+
x402Version,
|
|
594
|
+
payload: { signature, permit2Authorization }
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
async function signPermit2Authorization(signer, permit2Authorization, requirements) {
|
|
598
|
+
const chainId = getEvmChainId(requirements.network);
|
|
599
|
+
return await signer.signTypedData({
|
|
600
|
+
domain: { name: "Permit2", chainId, verifyingContract: PERMIT2_ADDRESS },
|
|
601
|
+
types: permit2WitnessTypes,
|
|
602
|
+
primaryType: "PermitWitnessTransferFrom",
|
|
603
|
+
message: {
|
|
604
|
+
permitted: {
|
|
605
|
+
token: (0, import_viem5.getAddress)(permit2Authorization.permitted.token),
|
|
606
|
+
amount: BigInt(permit2Authorization.permitted.amount)
|
|
607
|
+
},
|
|
608
|
+
spender: (0, import_viem5.getAddress)(permit2Authorization.spender),
|
|
609
|
+
nonce: BigInt(permit2Authorization.nonce),
|
|
610
|
+
deadline: BigInt(permit2Authorization.deadline),
|
|
611
|
+
witness: {
|
|
612
|
+
to: (0, import_viem5.getAddress)(permit2Authorization.witness.to),
|
|
613
|
+
validAfter: BigInt(permit2Authorization.witness.validAfter)
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// src/exact/client/permit2.ts
|
|
620
|
+
var MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
|
621
|
+
async function createPermit2Payload(signer, x402Version, paymentRequirements) {
|
|
622
|
+
return createPermit2PayloadForProxy(
|
|
623
|
+
x402ExactPermit2ProxyAddress,
|
|
624
|
+
signer,
|
|
625
|
+
x402Version,
|
|
626
|
+
paymentRequirements
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
function createPermit2ApprovalTx(tokenAddress) {
|
|
630
|
+
const data = (0, import_viem6.encodeFunctionData)({
|
|
631
|
+
abi: erc20ApproveAbi,
|
|
632
|
+
functionName: "approve",
|
|
633
|
+
args: [PERMIT2_ADDRESS, MAX_UINT256]
|
|
634
|
+
});
|
|
635
|
+
return {
|
|
636
|
+
to: (0, import_viem6.getAddress)(tokenAddress),
|
|
637
|
+
data
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function getPermit2AllowanceReadParams(params) {
|
|
641
|
+
return {
|
|
642
|
+
address: (0, import_viem6.getAddress)(params.tokenAddress),
|
|
643
|
+
abi: erc20AllowanceAbi,
|
|
644
|
+
functionName: "allowance",
|
|
645
|
+
args: [(0, import_viem6.getAddress)(params.ownerAddress), PERMIT2_ADDRESS]
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// src/shared/extensions/gasSponsoring.ts
|
|
650
|
+
var import_viem10 = require("viem");
|
|
651
|
+
|
|
652
|
+
// src/exact/client/eip2612.ts
|
|
653
|
+
var import_viem7 = require("viem");
|
|
654
|
+
async function signEip2612Permit(signer, tokenAddress, tokenName, tokenVersion, chainId, deadline, permittedAmount) {
|
|
655
|
+
const owner = signer.address;
|
|
656
|
+
const spender = (0, import_viem7.getAddress)(PERMIT2_ADDRESS);
|
|
657
|
+
const nonce = await signer.readContract({
|
|
658
|
+
address: tokenAddress,
|
|
659
|
+
abi: eip2612NoncesAbi,
|
|
660
|
+
functionName: "nonces",
|
|
661
|
+
args: [owner]
|
|
662
|
+
});
|
|
663
|
+
const domain = {
|
|
664
|
+
name: tokenName,
|
|
665
|
+
version: tokenVersion,
|
|
666
|
+
chainId,
|
|
667
|
+
verifyingContract: tokenAddress
|
|
668
|
+
};
|
|
669
|
+
const approvalAmount = BigInt(permittedAmount);
|
|
670
|
+
const message = {
|
|
671
|
+
owner,
|
|
672
|
+
spender,
|
|
673
|
+
value: approvalAmount,
|
|
674
|
+
nonce,
|
|
675
|
+
deadline: BigInt(deadline)
|
|
676
|
+
};
|
|
677
|
+
const signature = await signer.signTypedData({
|
|
678
|
+
domain,
|
|
679
|
+
types: eip2612PermitTypes,
|
|
680
|
+
primaryType: "Permit",
|
|
681
|
+
message
|
|
682
|
+
});
|
|
683
|
+
return {
|
|
684
|
+
from: owner,
|
|
685
|
+
asset: tokenAddress,
|
|
686
|
+
spender,
|
|
687
|
+
amount: approvalAmount.toString(),
|
|
688
|
+
nonce: nonce.toString(),
|
|
689
|
+
deadline,
|
|
690
|
+
signature,
|
|
691
|
+
version: "1"
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// src/exact/client/erc20approval.ts
|
|
696
|
+
var import_viem8 = require("viem");
|
|
697
|
+
async function signErc20ApprovalTransaction(signer, tokenAddress, chainId) {
|
|
698
|
+
const from = signer.address;
|
|
699
|
+
const spender = (0, import_viem8.getAddress)(PERMIT2_ADDRESS);
|
|
700
|
+
const data = (0, import_viem8.encodeFunctionData)({
|
|
701
|
+
abi: erc20ApproveAbi,
|
|
702
|
+
functionName: "approve",
|
|
703
|
+
args: [spender, import_viem8.maxUint256]
|
|
704
|
+
});
|
|
705
|
+
const nonce = await signer.getTransactionCount({ address: from });
|
|
706
|
+
let maxFeePerGas;
|
|
707
|
+
let maxPriorityFeePerGas;
|
|
708
|
+
try {
|
|
709
|
+
const fees = await signer.estimateFeesPerGas?.();
|
|
710
|
+
if (!fees) {
|
|
711
|
+
throw new Error("no fee estimates available");
|
|
712
|
+
}
|
|
713
|
+
maxFeePerGas = fees.maxFeePerGas;
|
|
714
|
+
maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
|
|
715
|
+
} catch {
|
|
716
|
+
maxFeePerGas = DEFAULT_MAX_FEE_PER_GAS;
|
|
717
|
+
maxPriorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;
|
|
718
|
+
}
|
|
719
|
+
const signedTransaction = await signer.signTransaction({
|
|
720
|
+
to: tokenAddress,
|
|
721
|
+
data,
|
|
722
|
+
nonce,
|
|
723
|
+
gas: ERC20_APPROVE_GAS_LIMIT,
|
|
724
|
+
maxFeePerGas,
|
|
725
|
+
maxPriorityFeePerGas,
|
|
726
|
+
chainId
|
|
727
|
+
});
|
|
728
|
+
return {
|
|
729
|
+
from,
|
|
730
|
+
asset: tokenAddress,
|
|
731
|
+
spender,
|
|
732
|
+
amount: import_viem8.maxUint256.toString(),
|
|
733
|
+
signedTransaction,
|
|
734
|
+
version: ERC20_APPROVAL_GAS_SPONSORING_VERSION
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// src/shared/rpc.ts
|
|
739
|
+
var import_viem9 = require("viem");
|
|
740
|
+
var rpcClientCache = /* @__PURE__ */ new Map();
|
|
741
|
+
function isConfigByChainId(options) {
|
|
742
|
+
const keys = Object.keys(options);
|
|
743
|
+
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
|
|
744
|
+
}
|
|
745
|
+
function getRpcClient(rpcUrl) {
|
|
746
|
+
const existing = rpcClientCache.get(rpcUrl);
|
|
747
|
+
if (existing) {
|
|
748
|
+
return existing;
|
|
749
|
+
}
|
|
750
|
+
const client = (0, import_viem9.createPublicClient)({
|
|
751
|
+
transport: (0, import_viem9.http)(rpcUrl)
|
|
752
|
+
});
|
|
753
|
+
rpcClientCache.set(rpcUrl, client);
|
|
754
|
+
return client;
|
|
755
|
+
}
|
|
756
|
+
function resolveRpcUrl(network, options) {
|
|
757
|
+
if (!options) {
|
|
758
|
+
return void 0;
|
|
759
|
+
}
|
|
760
|
+
if (isConfigByChainId(options)) {
|
|
761
|
+
const chainId = getEvmChainId(network);
|
|
762
|
+
const optionsByChainId = options;
|
|
763
|
+
return optionsByChainId[chainId]?.rpcUrl;
|
|
764
|
+
}
|
|
765
|
+
return options.rpcUrl;
|
|
766
|
+
}
|
|
767
|
+
function resolveExtensionRpcCapabilities(network, signer, options) {
|
|
768
|
+
const capabilities = {
|
|
769
|
+
signTransaction: signer.signTransaction,
|
|
770
|
+
readContract: signer.readContract,
|
|
771
|
+
getTransactionCount: signer.getTransactionCount,
|
|
772
|
+
estimateFeesPerGas: signer.estimateFeesPerGas
|
|
773
|
+
};
|
|
774
|
+
const needsRpcBackfill = !capabilities.readContract || !capabilities.getTransactionCount || !capabilities.estimateFeesPerGas;
|
|
775
|
+
if (!needsRpcBackfill) {
|
|
776
|
+
return capabilities;
|
|
777
|
+
}
|
|
778
|
+
const rpcUrl = resolveRpcUrl(network, options);
|
|
779
|
+
if (!rpcUrl) {
|
|
780
|
+
return capabilities;
|
|
781
|
+
}
|
|
782
|
+
const rpcClient = getRpcClient(rpcUrl);
|
|
783
|
+
if (!capabilities.readContract) {
|
|
784
|
+
capabilities.readContract = (args) => rpcClient.readContract(args);
|
|
785
|
+
}
|
|
786
|
+
if (!capabilities.getTransactionCount) {
|
|
787
|
+
capabilities.getTransactionCount = async (args) => rpcClient.getTransactionCount({ address: args.address });
|
|
788
|
+
}
|
|
789
|
+
if (!capabilities.estimateFeesPerGas) {
|
|
790
|
+
capabilities.estimateFeesPerGas = async () => rpcClient.estimateFeesPerGas();
|
|
791
|
+
}
|
|
792
|
+
return capabilities;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/shared/extensions/gasSponsoring.ts
|
|
796
|
+
async function trySignEip2612PermitExtension(signer, options, requirements, result, context, approvalAmount) {
|
|
797
|
+
const capabilities = resolveExtensionRpcCapabilities(requirements.network, signer, options);
|
|
798
|
+
if (!capabilities.readContract) {
|
|
799
|
+
return void 0;
|
|
800
|
+
}
|
|
801
|
+
if (!context?.extensions?.[EIP2612_GAS_SPONSORING_KEY]) {
|
|
802
|
+
return void 0;
|
|
803
|
+
}
|
|
804
|
+
const tokenName = requirements.extra?.name;
|
|
805
|
+
const tokenVersion = requirements.extra?.version;
|
|
806
|
+
if (!tokenName || !tokenVersion) {
|
|
807
|
+
return void 0;
|
|
808
|
+
}
|
|
809
|
+
const chainId = getEvmChainId(requirements.network);
|
|
810
|
+
const tokenAddress = (0, import_viem10.getAddress)(requirements.asset);
|
|
811
|
+
const requiredAllowance = approvalAmount ?? requirements.amount;
|
|
812
|
+
try {
|
|
813
|
+
const allowance = await capabilities.readContract({
|
|
814
|
+
address: tokenAddress,
|
|
815
|
+
abi: erc20AllowanceAbi,
|
|
816
|
+
functionName: "allowance",
|
|
817
|
+
args: [signer.address, PERMIT2_ADDRESS]
|
|
818
|
+
});
|
|
819
|
+
if (allowance >= BigInt(requiredAllowance)) {
|
|
820
|
+
return void 0;
|
|
821
|
+
}
|
|
822
|
+
} catch {
|
|
823
|
+
}
|
|
824
|
+
const permit2Auth = result.payload?.permit2Authorization;
|
|
825
|
+
const deadline = permit2Auth?.deadline ?? Math.floor(Date.now() / 1e3 + requirements.maxTimeoutSeconds).toString();
|
|
826
|
+
const info = await signEip2612Permit(
|
|
827
|
+
{
|
|
828
|
+
address: signer.address,
|
|
829
|
+
signTypedData: (msg) => signer.signTypedData(msg),
|
|
830
|
+
readContract: capabilities.readContract
|
|
831
|
+
},
|
|
832
|
+
tokenAddress,
|
|
833
|
+
tokenName,
|
|
834
|
+
tokenVersion,
|
|
835
|
+
chainId,
|
|
836
|
+
deadline,
|
|
837
|
+
requiredAllowance
|
|
838
|
+
);
|
|
839
|
+
return {
|
|
840
|
+
[EIP2612_GAS_SPONSORING_KEY]: { info }
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
async function trySignErc20ApprovalExtension(signer, options, requirements, context, approvalAmount) {
|
|
844
|
+
const capabilities = resolveExtensionRpcCapabilities(requirements.network, signer, options);
|
|
845
|
+
if (!capabilities.readContract) {
|
|
846
|
+
return void 0;
|
|
847
|
+
}
|
|
848
|
+
if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING_KEY]) {
|
|
849
|
+
return void 0;
|
|
850
|
+
}
|
|
851
|
+
if (!capabilities.signTransaction || !capabilities.getTransactionCount) {
|
|
852
|
+
return void 0;
|
|
853
|
+
}
|
|
854
|
+
const chainId = getEvmChainId(requirements.network);
|
|
855
|
+
const tokenAddress = (0, import_viem10.getAddress)(requirements.asset);
|
|
856
|
+
const requiredAllowance = approvalAmount ?? requirements.amount;
|
|
857
|
+
try {
|
|
858
|
+
const allowance = await capabilities.readContract({
|
|
859
|
+
address: tokenAddress,
|
|
860
|
+
abi: erc20AllowanceAbi,
|
|
861
|
+
functionName: "allowance",
|
|
862
|
+
args: [signer.address, PERMIT2_ADDRESS]
|
|
863
|
+
});
|
|
864
|
+
if (allowance >= BigInt(requiredAllowance)) {
|
|
865
|
+
return void 0;
|
|
866
|
+
}
|
|
867
|
+
} catch {
|
|
868
|
+
}
|
|
869
|
+
const info = await signErc20ApprovalTransaction(
|
|
870
|
+
{
|
|
871
|
+
address: signer.address,
|
|
872
|
+
signTransaction: capabilities.signTransaction,
|
|
873
|
+
getTransactionCount: capabilities.getTransactionCount,
|
|
874
|
+
estimateFeesPerGas: capabilities.estimateFeesPerGas
|
|
875
|
+
},
|
|
876
|
+
tokenAddress,
|
|
877
|
+
chainId
|
|
878
|
+
);
|
|
879
|
+
return {
|
|
880
|
+
[ERC20_APPROVAL_GAS_SPONSORING_KEY]: { info }
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// src/shared/extensions/builderCode.ts
|
|
885
|
+
var BUILDER_CODE_KEY = "builder-code";
|
|
886
|
+
var BUILDER_CODE_RESOLVER = async (context, ctx) => {
|
|
887
|
+
const ext = context.getExtension(BUILDER_CODE_KEY);
|
|
888
|
+
if (!ext?.buildDataSuffix) {
|
|
889
|
+
return void 0;
|
|
890
|
+
}
|
|
891
|
+
return ext.buildDataSuffix(ctx);
|
|
892
|
+
};
|
|
893
|
+
var DATA_SUFFIX_RESOLVERS = [BUILDER_CODE_RESOLVER];
|
|
894
|
+
async function resolveDataSuffix(context, ctx) {
|
|
895
|
+
if (!context) {
|
|
896
|
+
return void 0;
|
|
897
|
+
}
|
|
898
|
+
const parts = [];
|
|
899
|
+
for (const resolver of DATA_SUFFIX_RESOLVERS) {
|
|
900
|
+
const suffix = await resolver(context, ctx);
|
|
901
|
+
if (suffix && suffix !== "0x" && suffix.length > 2) {
|
|
902
|
+
parts.push(suffix);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
if (parts.length === 0) {
|
|
906
|
+
return void 0;
|
|
907
|
+
}
|
|
908
|
+
if (parts.length === 1) {
|
|
909
|
+
return parts[0];
|
|
910
|
+
}
|
|
911
|
+
return parts.reduce((acc, part, index) => {
|
|
912
|
+
if (index === 0) {
|
|
913
|
+
return part;
|
|
914
|
+
}
|
|
915
|
+
const stripped = part.startsWith("0x") ? part.slice(2) : part;
|
|
916
|
+
return `${acc}${stripped}`;
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
function appendDataSuffix(calldata, suffix) {
|
|
920
|
+
if (!suffix || suffix === "0x" || suffix.length <= 2) {
|
|
921
|
+
return calldata;
|
|
922
|
+
}
|
|
923
|
+
const suffixHex = suffix.startsWith("0x") ? suffix.slice(2) : suffix;
|
|
924
|
+
return `${calldata}${suffixHex}`;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// src/exact/client/scheme.ts
|
|
928
|
+
var ExactEvmScheme = class {
|
|
929
|
+
/**
|
|
930
|
+
* Creates a new ExactEvmClient instance.
|
|
931
|
+
*
|
|
932
|
+
* @param signer - The EVM signer for client operations.
|
|
933
|
+
* Base flow only requires `address` + `signTypedData`.
|
|
934
|
+
* Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally
|
|
935
|
+
* requires optional capabilities like `readContract` and tx signing helpers.
|
|
936
|
+
* @param options - Optional RPC configuration used to backfill extension capabilities.
|
|
937
|
+
*/
|
|
938
|
+
constructor(signer, options) {
|
|
939
|
+
this.signer = signer;
|
|
940
|
+
this.options = options;
|
|
941
|
+
this.scheme = "exact";
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Creates a payment payload for the Exact scheme.
|
|
945
|
+
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
|
|
946
|
+
*
|
|
947
|
+
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
|
|
948
|
+
* signer supports `readContract`, automatically signs an EIP-2612 permit
|
|
949
|
+
* when Permit2 allowance is insufficient.
|
|
950
|
+
*
|
|
951
|
+
* @param x402Version - The x402 protocol version
|
|
952
|
+
* @param paymentRequirements - The payment requirements
|
|
953
|
+
* @param context - Optional context with server-declared extensions
|
|
954
|
+
* @returns Promise resolving to a payment payload result (with optional extensions)
|
|
955
|
+
*/
|
|
956
|
+
async createPaymentPayload(x402Version, paymentRequirements, context) {
|
|
957
|
+
const assetTransferMethod = paymentRequirements.extra?.assetTransferMethod ?? "eip3009";
|
|
958
|
+
if (assetTransferMethod === "permit2") {
|
|
959
|
+
const result = await createPermit2Payload(this.signer, x402Version, paymentRequirements);
|
|
960
|
+
const eip2612Extensions = await trySignEip2612PermitExtension(
|
|
961
|
+
this.signer,
|
|
962
|
+
this.options,
|
|
963
|
+
paymentRequirements,
|
|
964
|
+
result,
|
|
965
|
+
context
|
|
966
|
+
);
|
|
967
|
+
if (eip2612Extensions) {
|
|
968
|
+
return {
|
|
969
|
+
...result,
|
|
970
|
+
extensions: eip2612Extensions
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
const erc20Extensions = await trySignErc20ApprovalExtension(
|
|
974
|
+
this.signer,
|
|
975
|
+
this.options,
|
|
976
|
+
paymentRequirements,
|
|
977
|
+
context
|
|
978
|
+
);
|
|
979
|
+
if (erc20Extensions) {
|
|
980
|
+
return {
|
|
981
|
+
...result,
|
|
982
|
+
extensions: erc20Extensions
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
return result;
|
|
986
|
+
}
|
|
987
|
+
return createEIP3009Payload(this.signer, x402Version, paymentRequirements);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
// src/exact/v1/client/scheme.ts
|
|
992
|
+
var import_viem13 = require("viem");
|
|
993
|
+
|
|
994
|
+
// src/exact/v1/facilitator/scheme.ts
|
|
995
|
+
var import_viem12 = require("viem");
|
|
996
|
+
|
|
997
|
+
// src/exact/facilitator/eip3009-utils.ts
|
|
998
|
+
var import_viem11 = require("viem");
|
|
999
|
+
|
|
1000
|
+
// src/v1/index.ts
|
|
1001
|
+
var EVM_NETWORK_CHAIN_ID_MAP = {
|
|
1002
|
+
ethereum: 1,
|
|
1003
|
+
sepolia: 11155111,
|
|
1004
|
+
abstract: 2741,
|
|
1005
|
+
"abstract-testnet": 11124,
|
|
1006
|
+
"base-sepolia": 84532,
|
|
1007
|
+
base: 8453,
|
|
1008
|
+
"avalanche-fuji": 43113,
|
|
1009
|
+
avalanche: 43114,
|
|
1010
|
+
iotex: 4689,
|
|
1011
|
+
sei: 1329,
|
|
1012
|
+
"sei-testnet": 1328,
|
|
1013
|
+
polygon: 137,
|
|
1014
|
+
"polygon-amoy": 80002,
|
|
1015
|
+
peaq: 3338,
|
|
1016
|
+
story: 1514,
|
|
1017
|
+
educhain: 41923,
|
|
1018
|
+
"skale-base-sepolia": 324705682,
|
|
1019
|
+
megaeth: 4326,
|
|
1020
|
+
monad: 143,
|
|
1021
|
+
stable: 988,
|
|
1022
|
+
"stable-testnet": 2201
|
|
1023
|
+
};
|
|
1024
|
+
var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
|
|
1025
|
+
|
|
1026
|
+
// src/signer.ts
|
|
1027
|
+
function toClientEvmSigner(signer, publicClient) {
|
|
1028
|
+
const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);
|
|
1029
|
+
const result = {
|
|
1030
|
+
address: signer.address,
|
|
1031
|
+
signTypedData: (msg) => signer.signTypedData(msg)
|
|
1032
|
+
};
|
|
1033
|
+
if (readContract) {
|
|
1034
|
+
result.readContract = readContract;
|
|
1035
|
+
}
|
|
1036
|
+
const signTransaction = signer.signTransaction;
|
|
1037
|
+
if (signTransaction) {
|
|
1038
|
+
result.signTransaction = (args) => signTransaction(args);
|
|
1039
|
+
}
|
|
1040
|
+
const getTransactionCount = signer.getTransactionCount ?? publicClient?.getTransactionCount?.bind(publicClient);
|
|
1041
|
+
if (getTransactionCount) {
|
|
1042
|
+
result.getTransactionCount = (args) => getTransactionCount(args);
|
|
1043
|
+
}
|
|
1044
|
+
const estimateFeesPerGas = signer.estimateFeesPerGas ?? publicClient?.estimateFeesPerGas?.bind(publicClient);
|
|
1045
|
+
if (estimateFeesPerGas) {
|
|
1046
|
+
result.estimateFeesPerGas = () => estimateFeesPerGas();
|
|
1047
|
+
}
|
|
1048
|
+
return result;
|
|
1049
|
+
}
|
|
1050
|
+
function toFacilitatorEvmSigner(client) {
|
|
1051
|
+
return {
|
|
1052
|
+
...client,
|
|
1053
|
+
getAddresses: () => [client.address]
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// src/batch-settlement/types.ts
|
|
1058
|
+
function isObject(payload) {
|
|
1059
|
+
return typeof payload === "object" && payload !== null;
|
|
1060
|
+
}
|
|
1061
|
+
function isVoucherFields(payload) {
|
|
1062
|
+
return isObject(payload) && "channelId" in payload && "maxClaimableAmount" in payload && "signature" in payload;
|
|
1063
|
+
}
|
|
1064
|
+
function isBatchSettlementDepositPayload(payload) {
|
|
1065
|
+
return isObject(payload) && payload.type === "deposit" && "channelConfig" in payload && isVoucherFields(payload.voucher) && isObject(payload.deposit) && typeof payload.deposit.amount === "string" && isObject(payload.deposit.authorization);
|
|
1066
|
+
}
|
|
1067
|
+
function isBatchSettlementVoucherPayload(payload) {
|
|
1068
|
+
return isObject(payload) && payload.type === "voucher" && "channelConfig" in payload && isVoucherFields(payload.voucher);
|
|
1069
|
+
}
|
|
1070
|
+
function isBatchSettlementRefundPayload(payload) {
|
|
1071
|
+
return isObject(payload) && payload.type === "refund" && "channelConfig" in payload && isVoucherFields(payload.voucher);
|
|
1072
|
+
}
|
|
1073
|
+
function isBatchSettlementClaimPayload(payload) {
|
|
1074
|
+
return isObject(payload) && payload.type === "claim" && "claims" in payload;
|
|
1075
|
+
}
|
|
1076
|
+
function isBatchSettlementSettlePayload(payload) {
|
|
1077
|
+
return isObject(payload) && payload.type === "settle" && "receiver" in payload && "token" in payload;
|
|
1078
|
+
}
|
|
1079
|
+
function isBatchSettlementEnrichedRefundPayload(payload) {
|
|
1080
|
+
return isBatchSettlementRefundPayload(payload) && "amount" in payload && "refundNonce" in payload && "claims" in payload;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/types.ts
|
|
1084
|
+
function isPermit2Payload(payload) {
|
|
1085
|
+
return "permit2Authorization" in payload;
|
|
1086
|
+
}
|
|
1087
|
+
function isEIP3009Payload(payload) {
|
|
1088
|
+
return "authorization" in payload;
|
|
1089
|
+
}
|
|
1090
|
+
function isUptoPermit2Payload(payload) {
|
|
1091
|
+
if (typeof payload.signature !== "string") return false;
|
|
1092
|
+
if (!("permit2Authorization" in payload)) return false;
|
|
1093
|
+
const auth = payload.permit2Authorization;
|
|
1094
|
+
if (typeof auth !== "object" || auth === null) return false;
|
|
1095
|
+
const a = auth;
|
|
1096
|
+
if (typeof a.from !== "string") return false;
|
|
1097
|
+
if (typeof a.spender !== "string") return false;
|
|
1098
|
+
if (typeof a.nonce !== "string") return false;
|
|
1099
|
+
if (typeof a.deadline !== "string") return false;
|
|
1100
|
+
const permitted = a.permitted;
|
|
1101
|
+
if (typeof permitted !== "object" || permitted === null) return false;
|
|
1102
|
+
const p = permitted;
|
|
1103
|
+
if (typeof p.token !== "string") return false;
|
|
1104
|
+
if (typeof p.amount !== "string") return false;
|
|
1105
|
+
const witness = a.witness;
|
|
1106
|
+
if (typeof witness !== "object" || witness === null) return false;
|
|
1107
|
+
const w = witness;
|
|
1108
|
+
return typeof w.facilitator === "string" && typeof w.to === "string" && typeof w.validAfter === "string";
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/upto/client/permit2.ts
|
|
1112
|
+
var import_viem14 = require("viem");
|
|
1113
|
+
async function createUptoPermit2Payload(signer, x402Version, paymentRequirements) {
|
|
1114
|
+
const facilitatorAddress = paymentRequirements.extra?.facilitatorAddress;
|
|
1115
|
+
if (!facilitatorAddress) {
|
|
1116
|
+
throw new Error(
|
|
1117
|
+
"upto scheme requires facilitatorAddress in paymentRequirements.extra. Ensure the server is configured with an upto facilitator that provides getExtra()."
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1121
|
+
const nonce = createPermit2Nonce();
|
|
1122
|
+
const validAfter = "0";
|
|
1123
|
+
const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();
|
|
1124
|
+
if (BigInt(deadline) <= BigInt(validAfter)) {
|
|
1125
|
+
throw new Error(
|
|
1126
|
+
`Invalid time window: deadline (${deadline}) must be after validAfter (${validAfter}). Check that maxTimeoutSeconds (${paymentRequirements.maxTimeoutSeconds}) is positive.`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
const permit2Authorization = {
|
|
1130
|
+
from: signer.address,
|
|
1131
|
+
permitted: {
|
|
1132
|
+
token: (0, import_viem14.getAddress)(paymentRequirements.asset),
|
|
1133
|
+
amount: paymentRequirements.amount
|
|
1134
|
+
},
|
|
1135
|
+
spender: x402UptoPermit2ProxyAddress,
|
|
1136
|
+
nonce,
|
|
1137
|
+
deadline,
|
|
1138
|
+
witness: {
|
|
1139
|
+
to: (0, import_viem14.getAddress)(paymentRequirements.payTo),
|
|
1140
|
+
facilitator: (0, import_viem14.getAddress)(facilitatorAddress),
|
|
1141
|
+
validAfter
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
const chainId = getEvmChainId(paymentRequirements.network);
|
|
1145
|
+
const signature = await signer.signTypedData({
|
|
1146
|
+
domain: { name: "Permit2", chainId, verifyingContract: PERMIT2_ADDRESS },
|
|
1147
|
+
types: uptoPermit2WitnessTypes,
|
|
1148
|
+
primaryType: "PermitWitnessTransferFrom",
|
|
1149
|
+
message: {
|
|
1150
|
+
permitted: {
|
|
1151
|
+
token: (0, import_viem14.getAddress)(permit2Authorization.permitted.token),
|
|
1152
|
+
amount: BigInt(permit2Authorization.permitted.amount)
|
|
1153
|
+
},
|
|
1154
|
+
spender: (0, import_viem14.getAddress)(permit2Authorization.spender),
|
|
1155
|
+
nonce: BigInt(permit2Authorization.nonce),
|
|
1156
|
+
deadline: BigInt(permit2Authorization.deadline),
|
|
1157
|
+
witness: {
|
|
1158
|
+
to: (0, import_viem14.getAddress)(permit2Authorization.witness.to),
|
|
1159
|
+
facilitator: (0, import_viem14.getAddress)(permit2Authorization.witness.facilitator),
|
|
1160
|
+
validAfter: BigInt(permit2Authorization.witness.validAfter)
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1164
|
+
return {
|
|
1165
|
+
x402Version,
|
|
1166
|
+
payload: { signature, permit2Authorization }
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/upto/client/scheme.ts
|
|
1171
|
+
var UptoEvmScheme = class {
|
|
1172
|
+
/**
|
|
1173
|
+
* Creates a new UptoEvmScheme instance.
|
|
1174
|
+
*
|
|
1175
|
+
* @param signer - The EVM signer for client operations
|
|
1176
|
+
* @param options - Optional RPC configuration
|
|
1177
|
+
*/
|
|
1178
|
+
constructor(signer, options) {
|
|
1179
|
+
this.signer = signer;
|
|
1180
|
+
this.options = options;
|
|
1181
|
+
this.scheme = "upto";
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Creates a payment payload for the Upto scheme using Permit2.
|
|
1185
|
+
*
|
|
1186
|
+
* @param x402Version - The x402 protocol version
|
|
1187
|
+
* @param paymentRequirements - The payment requirements
|
|
1188
|
+
* @param context - Optional context with server-declared extensions
|
|
1189
|
+
* @returns Promise resolving to a payment payload result
|
|
1190
|
+
*/
|
|
1191
|
+
async createPaymentPayload(x402Version, paymentRequirements, context) {
|
|
1192
|
+
const result = await createUptoPermit2Payload(this.signer, x402Version, paymentRequirements);
|
|
1193
|
+
const eip2612Extensions = await trySignEip2612PermitExtension(
|
|
1194
|
+
this.signer,
|
|
1195
|
+
this.options,
|
|
1196
|
+
paymentRequirements,
|
|
1197
|
+
result,
|
|
1198
|
+
context
|
|
1199
|
+
);
|
|
1200
|
+
if (eip2612Extensions) {
|
|
1201
|
+
return { ...result, extensions: eip2612Extensions };
|
|
1202
|
+
}
|
|
1203
|
+
const erc20Extensions = await trySignErc20ApprovalExtension(
|
|
1204
|
+
this.signer,
|
|
1205
|
+
this.options,
|
|
1206
|
+
paymentRequirements,
|
|
1207
|
+
context
|
|
1208
|
+
);
|
|
1209
|
+
if (erc20Extensions) {
|
|
1210
|
+
return { ...result, extensions: erc20Extensions };
|
|
1211
|
+
}
|
|
1212
|
+
return result;
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
// src/batch-settlement/client/scheme.ts
|
|
1217
|
+
var import_viem22 = require("viem");
|
|
1218
|
+
|
|
1219
|
+
// src/batch-settlement/constants.ts
|
|
1220
|
+
var import_viem15 = require("viem");
|
|
1221
|
+
var BATCH_SETTLEMENT_SCHEME = "batch-settlement";
|
|
1222
|
+
var BATCH_SETTLEMENT_ADDRESS = "0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003";
|
|
1223
|
+
var ERC3009_DEPOSIT_COLLECTOR_ADDRESS = "0x4020806089470a89826cB9fB1f4059150b550004";
|
|
1224
|
+
var PERMIT2_DEPOSIT_COLLECTOR_ADDRESS = "0x4020425FAf3B746C082C2f942b4E5159887B0005";
|
|
1225
|
+
var MIN_WITHDRAW_DELAY = 900;
|
|
1226
|
+
var BATCH_SETTLEMENT_DOMAIN = {
|
|
1227
|
+
name: "x402 Batch Settlement",
|
|
1228
|
+
version: "1"
|
|
1229
|
+
};
|
|
1230
|
+
var CHANNEL_CONFIG_TYPEHASH = (0, import_viem15.keccak256)(
|
|
1231
|
+
(0, import_viem15.toBytes)(
|
|
1232
|
+
"ChannelConfig(address payer,address payerAuthorizer,address receiver,address receiverAuthorizer,address token,uint40 withdrawDelay,bytes32 salt)"
|
|
1233
|
+
)
|
|
1234
|
+
);
|
|
1235
|
+
var channelConfigTypes = {
|
|
1236
|
+
ChannelConfig: [
|
|
1237
|
+
{ name: "payer", type: "address" },
|
|
1238
|
+
{ name: "payerAuthorizer", type: "address" },
|
|
1239
|
+
{ name: "receiver", type: "address" },
|
|
1240
|
+
{ name: "receiverAuthorizer", type: "address" },
|
|
1241
|
+
{ name: "token", type: "address" },
|
|
1242
|
+
{ name: "withdrawDelay", type: "uint40" },
|
|
1243
|
+
{ name: "salt", type: "bytes32" }
|
|
1244
|
+
]
|
|
1245
|
+
};
|
|
1246
|
+
var voucherTypes = {
|
|
1247
|
+
Voucher: [
|
|
1248
|
+
{ name: "channelId", type: "bytes32" },
|
|
1249
|
+
{ name: "maxClaimableAmount", type: "uint128" }
|
|
1250
|
+
]
|
|
1251
|
+
};
|
|
1252
|
+
var refundTypes = {
|
|
1253
|
+
Refund: [
|
|
1254
|
+
{ name: "channelId", type: "bytes32" },
|
|
1255
|
+
{ name: "nonce", type: "uint256" },
|
|
1256
|
+
{ name: "amount", type: "uint128" }
|
|
1257
|
+
]
|
|
1258
|
+
};
|
|
1259
|
+
var claimBatchTypes = {
|
|
1260
|
+
ClaimBatch: [{ name: "claims", type: "ClaimEntry[]" }],
|
|
1261
|
+
ClaimEntry: [
|
|
1262
|
+
{ name: "channelId", type: "bytes32" },
|
|
1263
|
+
{ name: "maxClaimableAmount", type: "uint128" },
|
|
1264
|
+
{ name: "totalClaimed", type: "uint128" }
|
|
1265
|
+
]
|
|
1266
|
+
};
|
|
1267
|
+
var receiveAuthorizationTypes = {
|
|
1268
|
+
ReceiveWithAuthorization: [
|
|
1269
|
+
{ name: "from", type: "address" },
|
|
1270
|
+
{ name: "to", type: "address" },
|
|
1271
|
+
{ name: "value", type: "uint256" },
|
|
1272
|
+
{ name: "validAfter", type: "uint256" },
|
|
1273
|
+
{ name: "validBefore", type: "uint256" },
|
|
1274
|
+
{ name: "nonce", type: "bytes32" }
|
|
1275
|
+
]
|
|
1276
|
+
};
|
|
1277
|
+
var batchPermit2WitnessTypes = {
|
|
1278
|
+
PermitWitnessTransferFrom: [
|
|
1279
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
1280
|
+
{ name: "spender", type: "address" },
|
|
1281
|
+
{ name: "nonce", type: "uint256" },
|
|
1282
|
+
{ name: "deadline", type: "uint256" },
|
|
1283
|
+
{ name: "witness", type: "DepositWitness" }
|
|
1284
|
+
],
|
|
1285
|
+
TokenPermissions: [
|
|
1286
|
+
{ name: "token", type: "address" },
|
|
1287
|
+
{ name: "amount", type: "uint256" }
|
|
1288
|
+
],
|
|
1289
|
+
DepositWitness: [{ name: "channelId", type: "bytes32" }]
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1292
|
+
// src/batch-settlement/utils.ts
|
|
1293
|
+
var import_viem16 = require("viem");
|
|
1294
|
+
function computeChannelId(config, networkOrChainId) {
|
|
1295
|
+
const chainId = typeof networkOrChainId === "number" ? networkOrChainId : getEvmChainId(networkOrChainId);
|
|
1296
|
+
return (0, import_viem16.hashTypedData)({
|
|
1297
|
+
domain: getBatchSettlementEip712Domain(chainId),
|
|
1298
|
+
types: channelConfigTypes,
|
|
1299
|
+
primaryType: "ChannelConfig",
|
|
1300
|
+
message: {
|
|
1301
|
+
payer: config.payer,
|
|
1302
|
+
payerAuthorizer: config.payerAuthorizer,
|
|
1303
|
+
receiver: config.receiver,
|
|
1304
|
+
receiverAuthorizer: config.receiverAuthorizer,
|
|
1305
|
+
token: config.token,
|
|
1306
|
+
withdrawDelay: config.withdrawDelay,
|
|
1307
|
+
salt: config.salt
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
function getBatchSettlementEip712Domain(chainId) {
|
|
1312
|
+
return {
|
|
1313
|
+
...BATCH_SETTLEMENT_DOMAIN,
|
|
1314
|
+
chainId,
|
|
1315
|
+
verifyingContract: (0, import_viem16.getAddress)(BATCH_SETTLEMENT_ADDRESS)
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// src/batch-settlement/client/eip3009.ts
|
|
1320
|
+
var import_viem18 = require("viem");
|
|
1321
|
+
|
|
1322
|
+
// src/batch-settlement/client/voucher.ts
|
|
1323
|
+
async function signVoucher(signer, channelId, maxClaimableAmount, network) {
|
|
1324
|
+
const chainId = getEvmChainId(network);
|
|
1325
|
+
const signature = await signer.signTypedData({
|
|
1326
|
+
domain: getBatchSettlementEip712Domain(chainId),
|
|
1327
|
+
types: voucherTypes,
|
|
1328
|
+
primaryType: "Voucher",
|
|
1329
|
+
message: {
|
|
1330
|
+
channelId,
|
|
1331
|
+
maxClaimableAmount: BigInt(maxClaimableAmount)
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
return {
|
|
1335
|
+
channelId,
|
|
1336
|
+
maxClaimableAmount,
|
|
1337
|
+
signature
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
// src/batch-settlement/encoding.ts
|
|
1342
|
+
var import_viem17 = require("viem");
|
|
1343
|
+
function buildErc3009DepositNonce(channelId, salt) {
|
|
1344
|
+
return (0, import_viem17.keccak256)(
|
|
1345
|
+
(0, import_viem17.encodeAbiParameters)([{ type: "bytes32" }, { type: "uint256" }], [channelId, BigInt(salt)])
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// src/batch-settlement/client/eip3009.ts
|
|
1350
|
+
async function createBatchSettlementEIP3009DepositPayload(signer, x402Version, paymentRequirements, channelConfig, depositAmount, maxClaimableAmount, voucherSigner) {
|
|
1351
|
+
const salt = createNonce();
|
|
1352
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1353
|
+
const chainId = getEvmChainId(paymentRequirements.network);
|
|
1354
|
+
if (!paymentRequirements.extra?.name || !paymentRequirements.extra?.version) {
|
|
1355
|
+
throw new Error(
|
|
1356
|
+
`EIP-712 domain parameters (name, version) are required in payment requirements for asset ${paymentRequirements.asset}`
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
const { name, version } = paymentRequirements.extra;
|
|
1360
|
+
const channelId = computeChannelId(channelConfig, paymentRequirements.network);
|
|
1361
|
+
const erc3009Nonce = buildErc3009DepositNonce(channelId, salt);
|
|
1362
|
+
const signature = await signer.signTypedData({
|
|
1363
|
+
domain: {
|
|
1364
|
+
name,
|
|
1365
|
+
version,
|
|
1366
|
+
chainId,
|
|
1367
|
+
verifyingContract: (0, import_viem18.getAddress)(paymentRequirements.asset)
|
|
1368
|
+
},
|
|
1369
|
+
types: receiveAuthorizationTypes,
|
|
1370
|
+
primaryType: "ReceiveWithAuthorization",
|
|
1371
|
+
message: {
|
|
1372
|
+
from: (0, import_viem18.getAddress)(signer.address),
|
|
1373
|
+
to: (0, import_viem18.getAddress)(ERC3009_DEPOSIT_COLLECTOR_ADDRESS),
|
|
1374
|
+
value: BigInt(depositAmount),
|
|
1375
|
+
validAfter: BigInt(0),
|
|
1376
|
+
validBefore: BigInt(now + paymentRequirements.maxTimeoutSeconds),
|
|
1377
|
+
nonce: erc3009Nonce
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
const vSigner = voucherSigner ?? signer;
|
|
1381
|
+
const voucher = await signVoucher(
|
|
1382
|
+
vSigner,
|
|
1383
|
+
channelId,
|
|
1384
|
+
maxClaimableAmount,
|
|
1385
|
+
paymentRequirements.network
|
|
1386
|
+
);
|
|
1387
|
+
const payload = {
|
|
1388
|
+
type: "deposit",
|
|
1389
|
+
channelConfig,
|
|
1390
|
+
voucher,
|
|
1391
|
+
deposit: {
|
|
1392
|
+
amount: depositAmount,
|
|
1393
|
+
authorization: {
|
|
1394
|
+
erc3009Authorization: {
|
|
1395
|
+
validAfter: "0",
|
|
1396
|
+
validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),
|
|
1397
|
+
salt,
|
|
1398
|
+
signature
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
return {
|
|
1404
|
+
x402Version,
|
|
1405
|
+
payload
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/batch-settlement/client/permit2.ts
|
|
1410
|
+
var import_viem19 = require("viem");
|
|
1411
|
+
async function createBatchSettlementPermit2DepositPayload(signer, x402Version, paymentRequirements, channelConfig, depositAmount, maxClaimableAmount, voucherSigner) {
|
|
1412
|
+
const chainId = getEvmChainId(paymentRequirements.network);
|
|
1413
|
+
const nonce = createPermit2Nonce();
|
|
1414
|
+
const deadline = Math.floor(Date.now() / 1e3 + paymentRequirements.maxTimeoutSeconds).toString();
|
|
1415
|
+
const channelId = computeChannelId(channelConfig, paymentRequirements.network);
|
|
1416
|
+
const permit2Authorization = {
|
|
1417
|
+
from: signer.address,
|
|
1418
|
+
permitted: {
|
|
1419
|
+
token: (0, import_viem19.getAddress)(paymentRequirements.asset),
|
|
1420
|
+
amount: depositAmount
|
|
1421
|
+
},
|
|
1422
|
+
spender: (0, import_viem19.getAddress)(PERMIT2_DEPOSIT_COLLECTOR_ADDRESS),
|
|
1423
|
+
nonce,
|
|
1424
|
+
deadline,
|
|
1425
|
+
witness: {
|
|
1426
|
+
channelId
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
const signature = await signer.signTypedData({
|
|
1430
|
+
domain: { name: "Permit2", chainId, verifyingContract: PERMIT2_ADDRESS },
|
|
1431
|
+
types: batchPermit2WitnessTypes,
|
|
1432
|
+
primaryType: "PermitWitnessTransferFrom",
|
|
1433
|
+
message: {
|
|
1434
|
+
permitted: {
|
|
1435
|
+
token: permit2Authorization.permitted.token,
|
|
1436
|
+
amount: BigInt(permit2Authorization.permitted.amount)
|
|
1437
|
+
},
|
|
1438
|
+
spender: permit2Authorization.spender,
|
|
1439
|
+
nonce: BigInt(permit2Authorization.nonce),
|
|
1440
|
+
deadline: BigInt(permit2Authorization.deadline),
|
|
1441
|
+
witness: {
|
|
1442
|
+
channelId
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
const voucher = await signVoucher(
|
|
1447
|
+
voucherSigner ?? signer,
|
|
1448
|
+
channelId,
|
|
1449
|
+
maxClaimableAmount,
|
|
1450
|
+
paymentRequirements.network
|
|
1451
|
+
);
|
|
1452
|
+
const payload = {
|
|
1453
|
+
type: "deposit",
|
|
1454
|
+
channelConfig,
|
|
1455
|
+
voucher,
|
|
1456
|
+
deposit: {
|
|
1457
|
+
amount: depositAmount,
|
|
1458
|
+
authorization: {
|
|
1459
|
+
permit2Authorization: {
|
|
1460
|
+
...permit2Authorization,
|
|
1461
|
+
signature
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
return { x402Version, payload };
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// src/batch-settlement/client/storage.ts
|
|
1470
|
+
var InMemoryClientChannelStorage = class {
|
|
1471
|
+
constructor() {
|
|
1472
|
+
this.channels = /* @__PURE__ */ new Map();
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Returns the channel record for `key` if present.
|
|
1476
|
+
*
|
|
1477
|
+
* @param key - Channel storage key (channelId).
|
|
1478
|
+
* @returns Persisted context or undefined.
|
|
1479
|
+
*/
|
|
1480
|
+
async get(key) {
|
|
1481
|
+
return this.channels.get(key);
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Stores or replaces the channel record for `key`.
|
|
1485
|
+
*
|
|
1486
|
+
* @param key - Channel storage key.
|
|
1487
|
+
* @param context - Channel fields to persist.
|
|
1488
|
+
* @returns Resolves when stored.
|
|
1489
|
+
*/
|
|
1490
|
+
async set(key, context) {
|
|
1491
|
+
this.channels.set(key, context);
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Removes the channel record for `key` if it exists.
|
|
1495
|
+
*
|
|
1496
|
+
* @param key - Channel storage key.
|
|
1497
|
+
* @returns Resolves when removed.
|
|
1498
|
+
*/
|
|
1499
|
+
async delete(key) {
|
|
1500
|
+
this.channels.delete(key);
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
|
|
1504
|
+
// src/batch-settlement/client/config.ts
|
|
1505
|
+
var DEFAULT_SALT = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
1506
|
+
function isBatchSettlementEvmSchemeOptions(o) {
|
|
1507
|
+
return o !== void 0 && typeof o === "object" && ("storage" in o || "depositPolicy" in o || "depositStrategy" in o || "salt" in o || "payerAuthorizer" in o || "rpcUrl" in o || "voucherSigner" in o);
|
|
1508
|
+
}
|
|
1509
|
+
function resolveClientOptions(second) {
|
|
1510
|
+
if (second === void 0) {
|
|
1511
|
+
return { storage: new InMemoryClientChannelStorage(), salt: DEFAULT_SALT };
|
|
1512
|
+
}
|
|
1513
|
+
if (isBatchSettlementEvmSchemeOptions(second)) {
|
|
1514
|
+
return {
|
|
1515
|
+
storage: second.storage ?? new InMemoryClientChannelStorage(),
|
|
1516
|
+
depositPolicy: second.depositPolicy,
|
|
1517
|
+
depositStrategy: second.depositStrategy,
|
|
1518
|
+
salt: second.salt ?? DEFAULT_SALT,
|
|
1519
|
+
payerAuthorizer: second.payerAuthorizer,
|
|
1520
|
+
voucherSigner: second.voucherSigner,
|
|
1521
|
+
extensionRpcOptions: second.rpcUrl ? { rpcUrl: second.rpcUrl } : void 0
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
return {
|
|
1525
|
+
storage: new InMemoryClientChannelStorage(),
|
|
1526
|
+
depositPolicy: second,
|
|
1527
|
+
salt: DEFAULT_SALT
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
function validateDepositPolicy(policy) {
|
|
1531
|
+
if (!policy) return;
|
|
1532
|
+
const m = policy.depositMultiplier;
|
|
1533
|
+
if (m !== void 0 && (!Number.isInteger(m) || m < 3)) {
|
|
1534
|
+
throw new Error("depositMultiplier must be an integer >= 3");
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function depositAmountForRequest(policy, requestAmount) {
|
|
1538
|
+
const mult = BigInt(policy?.depositMultiplier ?? 5);
|
|
1539
|
+
return (mult * requestAmount).toString();
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// src/batch-settlement/client/refund.ts
|
|
1543
|
+
var import_http2 = require("@bankofai/x402-core/http");
|
|
1544
|
+
var import_client = require("@bankofai/x402-core/client");
|
|
1545
|
+
|
|
1546
|
+
// src/batch-settlement/errors.ts
|
|
1547
|
+
var ErrCumulativeAmountBelowClaimed = "invalid_batch_settlement_evm_cumulative_below_claimed";
|
|
1548
|
+
var ErrCumulativeAmountMismatch = "invalid_batch_settlement_evm_cumulative_amount_mismatch";
|
|
1549
|
+
var ErrRefundNoBalance = "invalid_batch_settlement_evm_refund_no_balance";
|
|
1550
|
+
var ErrRefundAmountInvalid = "invalid_batch_settlement_evm_refund_amount_invalid";
|
|
1551
|
+
|
|
1552
|
+
// src/batch-settlement/client/channel.ts
|
|
1553
|
+
var import_http = require("@bankofai/x402-core/http");
|
|
1554
|
+
var import_viem20 = require("viem");
|
|
1555
|
+
|
|
1556
|
+
// src/batch-settlement/abi.ts
|
|
1557
|
+
var channelConfigComponents = [
|
|
1558
|
+
{ name: "payer", type: "address" },
|
|
1559
|
+
{ name: "payerAuthorizer", type: "address" },
|
|
1560
|
+
{ name: "receiver", type: "address" },
|
|
1561
|
+
{ name: "receiverAuthorizer", type: "address" },
|
|
1562
|
+
{ name: "token", type: "address" },
|
|
1563
|
+
{ name: "withdrawDelay", type: "uint40" },
|
|
1564
|
+
{ name: "salt", type: "bytes32" }
|
|
1565
|
+
];
|
|
1566
|
+
var voucherClaimComponents = [
|
|
1567
|
+
{
|
|
1568
|
+
name: "voucher",
|
|
1569
|
+
type: "tuple",
|
|
1570
|
+
components: [
|
|
1571
|
+
{
|
|
1572
|
+
name: "channel",
|
|
1573
|
+
type: "tuple",
|
|
1574
|
+
components: channelConfigComponents
|
|
1575
|
+
},
|
|
1576
|
+
{ name: "maxClaimableAmount", type: "uint128" }
|
|
1577
|
+
]
|
|
1578
|
+
},
|
|
1579
|
+
{ name: "signature", type: "bytes" },
|
|
1580
|
+
{ name: "totalClaimed", type: "uint128" }
|
|
1581
|
+
];
|
|
1582
|
+
var batchSettlementABI = [
|
|
1583
|
+
{
|
|
1584
|
+
type: "function",
|
|
1585
|
+
name: "multicall",
|
|
1586
|
+
inputs: [{ name: "data", type: "bytes[]" }],
|
|
1587
|
+
outputs: [{ name: "results", type: "bytes[]" }],
|
|
1588
|
+
stateMutability: "nonpayable"
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
type: "function",
|
|
1592
|
+
name: "deposit",
|
|
1593
|
+
inputs: [
|
|
1594
|
+
{ name: "config", type: "tuple", components: channelConfigComponents },
|
|
1595
|
+
{ name: "amount", type: "uint128" },
|
|
1596
|
+
{ name: "collector", type: "address" },
|
|
1597
|
+
{ name: "collectorData", type: "bytes" }
|
|
1598
|
+
],
|
|
1599
|
+
outputs: [],
|
|
1600
|
+
stateMutability: "nonpayable"
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
type: "function",
|
|
1604
|
+
name: "claim",
|
|
1605
|
+
inputs: [{ name: "voucherClaims", type: "tuple[]", components: voucherClaimComponents }],
|
|
1606
|
+
outputs: [],
|
|
1607
|
+
stateMutability: "nonpayable"
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
type: "function",
|
|
1611
|
+
name: "claimWithSignature",
|
|
1612
|
+
inputs: [
|
|
1613
|
+
{ name: "voucherClaims", type: "tuple[]", components: voucherClaimComponents },
|
|
1614
|
+
{ name: "authorizerSignature", type: "bytes" }
|
|
1615
|
+
],
|
|
1616
|
+
outputs: [],
|
|
1617
|
+
stateMutability: "nonpayable"
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
type: "function",
|
|
1621
|
+
name: "settle",
|
|
1622
|
+
inputs: [
|
|
1623
|
+
{ name: "receiver", type: "address" },
|
|
1624
|
+
{ name: "token", type: "address" }
|
|
1625
|
+
],
|
|
1626
|
+
outputs: [],
|
|
1627
|
+
stateMutability: "nonpayable"
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
type: "function",
|
|
1631
|
+
name: "initiateWithdraw",
|
|
1632
|
+
inputs: [
|
|
1633
|
+
{ name: "config", type: "tuple", components: channelConfigComponents },
|
|
1634
|
+
{ name: "amount", type: "uint128" }
|
|
1635
|
+
],
|
|
1636
|
+
outputs: [],
|
|
1637
|
+
stateMutability: "nonpayable"
|
|
1638
|
+
},
|
|
1639
|
+
{
|
|
1640
|
+
type: "function",
|
|
1641
|
+
name: "finalizeWithdraw",
|
|
1642
|
+
inputs: [{ name: "config", type: "tuple", components: channelConfigComponents }],
|
|
1643
|
+
outputs: [],
|
|
1644
|
+
stateMutability: "nonpayable"
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
type: "function",
|
|
1648
|
+
name: "refund",
|
|
1649
|
+
inputs: [
|
|
1650
|
+
{ name: "config", type: "tuple", components: channelConfigComponents },
|
|
1651
|
+
{ name: "amount", type: "uint128" }
|
|
1652
|
+
],
|
|
1653
|
+
outputs: [],
|
|
1654
|
+
stateMutability: "nonpayable"
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
type: "function",
|
|
1658
|
+
name: "refundWithSignature",
|
|
1659
|
+
inputs: [
|
|
1660
|
+
{ name: "config", type: "tuple", components: channelConfigComponents },
|
|
1661
|
+
{ name: "amount", type: "uint128" },
|
|
1662
|
+
{ name: "nonce", type: "uint256" },
|
|
1663
|
+
{ name: "receiverAuthorizerSignature", type: "bytes" }
|
|
1664
|
+
],
|
|
1665
|
+
outputs: [],
|
|
1666
|
+
stateMutability: "nonpayable"
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
type: "function",
|
|
1670
|
+
name: "getChannelId",
|
|
1671
|
+
inputs: [{ name: "config", type: "tuple", components: channelConfigComponents }],
|
|
1672
|
+
outputs: [{ name: "", type: "bytes32" }],
|
|
1673
|
+
stateMutability: "view"
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
type: "function",
|
|
1677
|
+
name: "CHANNEL_CONFIG_TYPEHASH",
|
|
1678
|
+
inputs: [],
|
|
1679
|
+
outputs: [{ name: "", type: "bytes32" }],
|
|
1680
|
+
stateMutability: "view"
|
|
1681
|
+
},
|
|
1682
|
+
{
|
|
1683
|
+
type: "function",
|
|
1684
|
+
name: "channels",
|
|
1685
|
+
inputs: [{ name: "channelId", type: "bytes32" }],
|
|
1686
|
+
outputs: [
|
|
1687
|
+
{ name: "balance", type: "uint128" },
|
|
1688
|
+
{ name: "totalClaimed", type: "uint128" }
|
|
1689
|
+
],
|
|
1690
|
+
stateMutability: "view"
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
type: "function",
|
|
1694
|
+
name: "pendingWithdrawals",
|
|
1695
|
+
inputs: [{ name: "channelId", type: "bytes32" }],
|
|
1696
|
+
outputs: [
|
|
1697
|
+
{ name: "amount", type: "uint128" },
|
|
1698
|
+
{ name: "initiatedAt", type: "uint40" }
|
|
1699
|
+
],
|
|
1700
|
+
stateMutability: "view"
|
|
1701
|
+
},
|
|
1702
|
+
{
|
|
1703
|
+
type: "function",
|
|
1704
|
+
name: "receivers",
|
|
1705
|
+
inputs: [
|
|
1706
|
+
{ name: "receiver", type: "address" },
|
|
1707
|
+
{ name: "token", type: "address" }
|
|
1708
|
+
],
|
|
1709
|
+
outputs: [
|
|
1710
|
+
{ name: "totalClaimed", type: "uint128" },
|
|
1711
|
+
{ name: "totalSettled", type: "uint128" }
|
|
1712
|
+
],
|
|
1713
|
+
stateMutability: "view"
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
type: "function",
|
|
1717
|
+
name: "getVoucherDigest",
|
|
1718
|
+
inputs: [
|
|
1719
|
+
{ name: "channelId", type: "bytes32" },
|
|
1720
|
+
{ name: "maxClaimableAmount", type: "uint128" }
|
|
1721
|
+
],
|
|
1722
|
+
outputs: [{ name: "", type: "bytes32" }],
|
|
1723
|
+
stateMutability: "view"
|
|
1724
|
+
},
|
|
1725
|
+
{
|
|
1726
|
+
type: "function",
|
|
1727
|
+
name: "getRefundDigest",
|
|
1728
|
+
inputs: [
|
|
1729
|
+
{ name: "channelId", type: "bytes32" },
|
|
1730
|
+
{ name: "nonce", type: "uint256" },
|
|
1731
|
+
{ name: "amount", type: "uint128" }
|
|
1732
|
+
],
|
|
1733
|
+
outputs: [{ name: "", type: "bytes32" }],
|
|
1734
|
+
stateMutability: "view"
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
type: "function",
|
|
1738
|
+
name: "refundNonce",
|
|
1739
|
+
inputs: [{ name: "channelId", type: "bytes32" }],
|
|
1740
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
1741
|
+
stateMutability: "view"
|
|
1742
|
+
},
|
|
1743
|
+
{
|
|
1744
|
+
type: "function",
|
|
1745
|
+
name: "getClaimBatchDigest",
|
|
1746
|
+
inputs: [{ name: "voucherClaims", type: "tuple[]", components: voucherClaimComponents }],
|
|
1747
|
+
outputs: [{ name: "", type: "bytes32" }],
|
|
1748
|
+
stateMutability: "view"
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
type: "event",
|
|
1752
|
+
name: "Settled",
|
|
1753
|
+
inputs: [
|
|
1754
|
+
{ name: "receiver", type: "address", indexed: true },
|
|
1755
|
+
{ name: "token", type: "address", indexed: true },
|
|
1756
|
+
{ name: "sender", type: "address", indexed: true },
|
|
1757
|
+
{ name: "amount", type: "uint128", indexed: false }
|
|
1758
|
+
],
|
|
1759
|
+
anonymous: false
|
|
1760
|
+
}
|
|
1761
|
+
];
|
|
1762
|
+
|
|
1763
|
+
// src/batch-settlement/client/channel.ts
|
|
1764
|
+
function readResponseChannelState(extra) {
|
|
1765
|
+
const channelState = extra.channelState;
|
|
1766
|
+
if (typeof channelState !== "object" || channelState === null) {
|
|
1767
|
+
return void 0;
|
|
1768
|
+
}
|
|
1769
|
+
return channelState;
|
|
1770
|
+
}
|
|
1771
|
+
function buildChannelConfig(deps, paymentRequirements) {
|
|
1772
|
+
const extra = paymentRequirements.extra;
|
|
1773
|
+
const receiverAuthorizer = extra?.receiverAuthorizer;
|
|
1774
|
+
if (!receiverAuthorizer || (0, import_viem20.getAddress)(receiverAuthorizer) === "0x0000000000000000000000000000000000000000") {
|
|
1775
|
+
throw new Error("Payment requirements must include a non-zero extra.receiverAuthorizer");
|
|
1776
|
+
}
|
|
1777
|
+
return {
|
|
1778
|
+
payer: deps.signer.address,
|
|
1779
|
+
payerAuthorizer: (0, import_viem20.getAddress)(
|
|
1780
|
+
deps.payerAuthorizer ?? deps.voucherSigner?.address ?? deps.signer.address
|
|
1781
|
+
),
|
|
1782
|
+
receiver: paymentRequirements.payTo,
|
|
1783
|
+
receiverAuthorizer: (0, import_viem20.getAddress)(receiverAuthorizer),
|
|
1784
|
+
token: paymentRequirements.asset,
|
|
1785
|
+
withdrawDelay: typeof extra?.withdrawDelay === "number" ? extra.withdrawDelay : MIN_WITHDRAW_DELAY,
|
|
1786
|
+
salt: deps.salt
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
async function processSettleResponse(storage, settle) {
|
|
1790
|
+
const extra = settle.extra ?? {};
|
|
1791
|
+
const channelState = readResponseChannelState(extra);
|
|
1792
|
+
if (!channelState) return;
|
|
1793
|
+
const channelId = channelState.channelId;
|
|
1794
|
+
const key = channelId.toLowerCase();
|
|
1795
|
+
const prev = await storage.get(key);
|
|
1796
|
+
const next = { ...prev ?? {} };
|
|
1797
|
+
if (channelState.chargedCumulativeAmount !== void 0) {
|
|
1798
|
+
next.chargedCumulativeAmount = String(channelState.chargedCumulativeAmount);
|
|
1799
|
+
}
|
|
1800
|
+
if (channelState.balance !== void 0) {
|
|
1801
|
+
next.balance = String(channelState.balance);
|
|
1802
|
+
}
|
|
1803
|
+
if (channelState.totalClaimed !== void 0) {
|
|
1804
|
+
next.totalClaimed = String(channelState.totalClaimed);
|
|
1805
|
+
}
|
|
1806
|
+
await storage.set(key, next);
|
|
1807
|
+
}
|
|
1808
|
+
async function updateChannelAfterRefund(storage, channelKey, settleExtra) {
|
|
1809
|
+
const channelState = readResponseChannelState(settleExtra);
|
|
1810
|
+
if (!channelState) {
|
|
1811
|
+
await storage.delete(channelKey);
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
const balanceAfter = channelState.balance !== void 0 ? BigInt(String(channelState.balance)) : void 0;
|
|
1815
|
+
if (balanceAfter === void 0 || balanceAfter <= 0n) {
|
|
1816
|
+
await storage.delete(channelKey);
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
const prev = await storage.get(channelKey);
|
|
1820
|
+
const next = { ...prev ?? {} };
|
|
1821
|
+
next.balance = balanceAfter.toString();
|
|
1822
|
+
if (channelState.chargedCumulativeAmount !== void 0) {
|
|
1823
|
+
next.chargedCumulativeAmount = String(channelState.chargedCumulativeAmount);
|
|
1824
|
+
}
|
|
1825
|
+
if (channelState.totalClaimed !== void 0) {
|
|
1826
|
+
next.totalClaimed = String(channelState.totalClaimed);
|
|
1827
|
+
}
|
|
1828
|
+
await storage.set(channelKey, next);
|
|
1829
|
+
}
|
|
1830
|
+
async function recoverChannel(deps, paymentRequirements) {
|
|
1831
|
+
if (!deps.signer.readContract) {
|
|
1832
|
+
throw new Error("recoverChannel requires ClientEvmSigner.readContract");
|
|
1833
|
+
}
|
|
1834
|
+
const config = buildChannelConfig(deps, paymentRequirements);
|
|
1835
|
+
const channelId = computeChannelId(config, paymentRequirements.network);
|
|
1836
|
+
const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed(
|
|
1837
|
+
deps.signer,
|
|
1838
|
+
channelId
|
|
1839
|
+
);
|
|
1840
|
+
const ctx = {
|
|
1841
|
+
chargedCumulativeAmount: chTotalClaimed.toString(),
|
|
1842
|
+
balance: chBalance.toString(),
|
|
1843
|
+
totalClaimed: chTotalClaimed.toString()
|
|
1844
|
+
};
|
|
1845
|
+
await deps.storage.set(channelId.toLowerCase(), ctx);
|
|
1846
|
+
return ctx;
|
|
1847
|
+
}
|
|
1848
|
+
async function readChannelBalanceAndTotalClaimed(signer, channelId) {
|
|
1849
|
+
if (!signer.readContract) {
|
|
1850
|
+
throw new Error("readChannelBalanceAndTotalClaimed requires ClientEvmSigner.readContract");
|
|
1851
|
+
}
|
|
1852
|
+
return await signer.readContract({
|
|
1853
|
+
address: BATCH_SETTLEMENT_ADDRESS,
|
|
1854
|
+
abi: batchSettlementABI,
|
|
1855
|
+
functionName: "channels",
|
|
1856
|
+
args: [channelId]
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// src/batch-settlement/client/recovery.ts
|
|
1861
|
+
var import_viem21 = require("viem");
|
|
1862
|
+
async function processCorrectivePaymentRequired(deps, paymentRequired) {
|
|
1863
|
+
if (paymentRequired.error !== ErrCumulativeAmountMismatch && paymentRequired.error !== ErrCumulativeAmountBelowClaimed) {
|
|
1864
|
+
return false;
|
|
1865
|
+
}
|
|
1866
|
+
const accept = paymentRequired.accepts.find((a) => a.scheme === BATCH_SETTLEMENT_SCHEME);
|
|
1867
|
+
if (!accept) {
|
|
1868
|
+
return false;
|
|
1869
|
+
}
|
|
1870
|
+
const channelState = accept.extra.channelState;
|
|
1871
|
+
const voucherState = accept.extra.voucherState;
|
|
1872
|
+
const hasSig = channelState?.chargedCumulativeAmount !== void 0 && voucherState?.signedMaxClaimable !== void 0 && voucherState.signature !== void 0;
|
|
1873
|
+
if (!hasSig) {
|
|
1874
|
+
return recoverFromOnChainState(deps, accept);
|
|
1875
|
+
}
|
|
1876
|
+
return recoverFromSignature(deps, accept, channelState, voucherState);
|
|
1877
|
+
}
|
|
1878
|
+
async function recoverFromSignature(deps, accept, channelState, voucherState) {
|
|
1879
|
+
const chargedRaw = channelState.chargedCumulativeAmount;
|
|
1880
|
+
const signedRaw = voucherState.signedMaxClaimable;
|
|
1881
|
+
const sig = voucherState.signature;
|
|
1882
|
+
const charged = BigInt(String(chargedRaw));
|
|
1883
|
+
const signed = BigInt(String(signedRaw));
|
|
1884
|
+
if (charged > signed) {
|
|
1885
|
+
return false;
|
|
1886
|
+
}
|
|
1887
|
+
const config = buildChannelConfig(deps, accept);
|
|
1888
|
+
const channelId = computeChannelId(config, accept.network);
|
|
1889
|
+
if (!deps.signer.readContract) {
|
|
1890
|
+
return false;
|
|
1891
|
+
}
|
|
1892
|
+
const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed(
|
|
1893
|
+
deps.signer,
|
|
1894
|
+
channelId
|
|
1895
|
+
);
|
|
1896
|
+
if (charged < chTotalClaimed) {
|
|
1897
|
+
return false;
|
|
1898
|
+
}
|
|
1899
|
+
const chainId = getEvmChainId(accept.network);
|
|
1900
|
+
const recovered = await (0, import_viem21.recoverTypedDataAddress)({
|
|
1901
|
+
domain: getBatchSettlementEip712Domain(chainId),
|
|
1902
|
+
types: voucherTypes,
|
|
1903
|
+
primaryType: "Voucher",
|
|
1904
|
+
message: {
|
|
1905
|
+
channelId,
|
|
1906
|
+
maxClaimableAmount: signed
|
|
1907
|
+
},
|
|
1908
|
+
signature: sig
|
|
1909
|
+
});
|
|
1910
|
+
const expectedSigner = (0, import_viem21.getAddress)(
|
|
1911
|
+
deps.payerAuthorizer ?? deps.voucherSigner?.address ?? deps.signer.address
|
|
1912
|
+
);
|
|
1913
|
+
if (recovered.toLowerCase() !== expectedSigner.toLowerCase()) {
|
|
1914
|
+
return false;
|
|
1915
|
+
}
|
|
1916
|
+
const ctx = {
|
|
1917
|
+
chargedCumulativeAmount: charged.toString(),
|
|
1918
|
+
signedMaxClaimable: signed.toString(),
|
|
1919
|
+
signature: sig,
|
|
1920
|
+
balance: chBalance.toString(),
|
|
1921
|
+
totalClaimed: chTotalClaimed.toString()
|
|
1922
|
+
};
|
|
1923
|
+
await deps.storage.set(channelId.toLowerCase(), ctx);
|
|
1924
|
+
return true;
|
|
1925
|
+
}
|
|
1926
|
+
async function recoverFromOnChainState(deps, accept) {
|
|
1927
|
+
if (!deps.signer.readContract) {
|
|
1928
|
+
return false;
|
|
1929
|
+
}
|
|
1930
|
+
const config = buildChannelConfig(deps, accept);
|
|
1931
|
+
const channelId = computeChannelId(config, accept.network);
|
|
1932
|
+
const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed(
|
|
1933
|
+
deps.signer,
|
|
1934
|
+
channelId
|
|
1935
|
+
);
|
|
1936
|
+
const ctx = {
|
|
1937
|
+
chargedCumulativeAmount: chTotalClaimed.toString(),
|
|
1938
|
+
balance: chBalance.toString(),
|
|
1939
|
+
totalClaimed: chTotalClaimed.toString()
|
|
1940
|
+
};
|
|
1941
|
+
await deps.storage.set(channelId.toLowerCase(), ctx);
|
|
1942
|
+
return true;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
// src/batch-settlement/client/hooks.ts
|
|
1946
|
+
function createBatchSettlementClientHooks(deps) {
|
|
1947
|
+
return {
|
|
1948
|
+
onPaymentResponse: (ctx) => handleBatchSettlementPaymentResponse(deps, ctx)
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
async function handleBatchSettlementPaymentResponse(deps, ctx) {
|
|
1952
|
+
if (ctx.settleResponse) {
|
|
1953
|
+
if (isBatchSettlementRefundPayload(ctx.paymentPayload.payload)) {
|
|
1954
|
+
const extra = ctx.settleResponse.extra ?? {};
|
|
1955
|
+
const channelState = extra.channelState;
|
|
1956
|
+
const channelId = typeof channelState === "object" && channelState !== null && "channelId" in channelState ? channelState.channelId : void 0;
|
|
1957
|
+
if (typeof channelId === "string" && channelId) {
|
|
1958
|
+
await updateChannelAfterRefund(deps.storage, channelId.toLowerCase(), extra);
|
|
1959
|
+
}
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
await processSettleResponse(deps.storage, ctx.settleResponse);
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
if (ctx.paymentRequired) {
|
|
1966
|
+
const recovered = await processCorrectivePaymentRequired(deps, ctx.paymentRequired);
|
|
1967
|
+
return recovered ? { recovered: true } : void 0;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
// src/batch-settlement/client/refund.ts
|
|
1972
|
+
var NON_RECOVERABLE_REFUND_ERRORS = /* @__PURE__ */ new Set([
|
|
1973
|
+
ErrRefundNoBalance,
|
|
1974
|
+
ErrRefundAmountInvalid
|
|
1975
|
+
]);
|
|
1976
|
+
async function refundChannel(ctx, url, options) {
|
|
1977
|
+
const fetchImpl = options?.fetch ?? globalThis.fetch;
|
|
1978
|
+
if (!fetchImpl) {
|
|
1979
|
+
throw new Error("refund requires a fetch implementation (globalThis.fetch unavailable)");
|
|
1980
|
+
}
|
|
1981
|
+
const refundAmount = normalizeRefundAmount(options?.amount);
|
|
1982
|
+
const probe = await probeRefundRequirements(url, fetchImpl);
|
|
1983
|
+
return executeRefund(ctx, url, probe, refundAmount, fetchImpl);
|
|
1984
|
+
}
|
|
1985
|
+
async function probeRefundRequirements(url, fetchImpl) {
|
|
1986
|
+
const probe = await fetchImpl(url, { method: "GET" });
|
|
1987
|
+
if (probe.status !== 402) {
|
|
1988
|
+
throw new Error(`Refund probe expected 402, got ${probe.status}`);
|
|
1989
|
+
}
|
|
1990
|
+
const header = probe.headers.get("PAYMENT-REQUIRED");
|
|
1991
|
+
if (!header) {
|
|
1992
|
+
throw new Error("Refund probe response missing PAYMENT-REQUIRED header");
|
|
1993
|
+
}
|
|
1994
|
+
const paymentRequired = (0, import_http2.decodePaymentRequiredHeader)(header);
|
|
1995
|
+
const requirements = paymentRequired.accepts.find((a) => a.scheme === BATCH_SETTLEMENT_SCHEME);
|
|
1996
|
+
if (!requirements) {
|
|
1997
|
+
throw new Error(`No ${BATCH_SETTLEMENT_SCHEME} payment option at ${url}`);
|
|
1998
|
+
}
|
|
1999
|
+
const extra = requirements.extra;
|
|
2000
|
+
if (!extra?.receiverAuthorizer) {
|
|
2001
|
+
throw new Error("Refund requires a configured receiverAuthorizer on the receiver");
|
|
2002
|
+
}
|
|
2003
|
+
return { paymentRequired, requirements };
|
|
2004
|
+
}
|
|
2005
|
+
async function executeRefund(ctx, url, probe, refundAmount, fetchImpl) {
|
|
2006
|
+
const maxAttempts = 2;
|
|
2007
|
+
const { paymentRequired, requirements } = probe;
|
|
2008
|
+
const httpClient = createRefundHttpClient(ctx, requirements);
|
|
2009
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
2010
|
+
const paymentPayload = await buildRefundPaymentPayload(
|
|
2011
|
+
ctx,
|
|
2012
|
+
paymentRequired,
|
|
2013
|
+
requirements,
|
|
2014
|
+
refundAmount
|
|
2015
|
+
);
|
|
2016
|
+
const headers = httpClient.encodePaymentSignatureHeader(paymentPayload);
|
|
2017
|
+
const response = await fetchImpl(url, { method: "GET", headers });
|
|
2018
|
+
if (response.status === 402) {
|
|
2019
|
+
const nonRecoverable = getNonRecoverableRefundFailure(response);
|
|
2020
|
+
if (nonRecoverable) {
|
|
2021
|
+
throw new Error(nonRecoverable);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
const result = await httpClient.processPaymentResult(
|
|
2025
|
+
paymentPayload,
|
|
2026
|
+
(name) => response.headers.get(name),
|
|
2027
|
+
response.status
|
|
2028
|
+
);
|
|
2029
|
+
if (response.status === 402) {
|
|
2030
|
+
if (result.recovered && attempt < maxAttempts) {
|
|
2031
|
+
continue;
|
|
2032
|
+
}
|
|
2033
|
+
if (result.recovered) {
|
|
2034
|
+
throw new Error(`Refund failed: server returned 402 after ${attempt} attempt(s)`);
|
|
2035
|
+
}
|
|
2036
|
+
const corrective = getRefundPaymentRequired(response);
|
|
2037
|
+
throw new Error(`Refund failed: ${corrective.error ?? "unknown"}`);
|
|
2038
|
+
}
|
|
2039
|
+
if (!result.settleResponse) {
|
|
2040
|
+
throw new Error(
|
|
2041
|
+
`Refund response missing PAYMENT-RESPONSE header (status ${response.status})`
|
|
2042
|
+
);
|
|
2043
|
+
}
|
|
2044
|
+
return result.settleResponse;
|
|
2045
|
+
}
|
|
2046
|
+
throw new Error("Refund failed: retry budget exhausted");
|
|
2047
|
+
}
|
|
2048
|
+
async function buildRefundPaymentPayload(ctx, paymentRequired, requirements, refundAmount) {
|
|
2049
|
+
const config = buildChannelConfig(ctx, requirements);
|
|
2050
|
+
const channelId = computeChannelId(config, requirements.network);
|
|
2051
|
+
const key = channelId.toLowerCase();
|
|
2052
|
+
let channel = await ctx.storage.get(key);
|
|
2053
|
+
if (channel === void 0 && ctx.signer.readContract) {
|
|
2054
|
+
channel = await recoverChannel(ctx, requirements);
|
|
2055
|
+
}
|
|
2056
|
+
if (channel === void 0) {
|
|
2057
|
+
throw new Error(
|
|
2058
|
+
"Refund requires an existing channel record; deposit first or call from a context with an EVM RPC"
|
|
2059
|
+
);
|
|
2060
|
+
}
|
|
2061
|
+
const charged = channel.chargedCumulativeAmount ?? "0";
|
|
2062
|
+
if (channel.balance !== void 0 && BigInt(channel.balance) <= BigInt(charged)) {
|
|
2063
|
+
throw new Error(
|
|
2064
|
+
`Refund failed: channel has no remaining balance (balance=${channel.balance}, chargedCumulativeAmount=${charged})`
|
|
2065
|
+
);
|
|
2066
|
+
}
|
|
2067
|
+
const voucherSigner = ctx.voucherSigner ?? ctx.signer;
|
|
2068
|
+
const voucher = await signVoucher(voucherSigner, channelId, charged, requirements.network);
|
|
2069
|
+
const payload = {
|
|
2070
|
+
type: "refund",
|
|
2071
|
+
channelConfig: config,
|
|
2072
|
+
voucher,
|
|
2073
|
+
...refundAmount !== void 0 ? { amount: refundAmount } : {}
|
|
2074
|
+
};
|
|
2075
|
+
return {
|
|
2076
|
+
x402Version: 2,
|
|
2077
|
+
accepted: requirements,
|
|
2078
|
+
payload,
|
|
2079
|
+
...paymentRequired.resource ? { resource: paymentRequired.resource } : {},
|
|
2080
|
+
...paymentRequired.extensions ? { extensions: paymentRequired.extensions } : {}
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
function createRefundHttpClient(ctx, requirements) {
|
|
2084
|
+
const client = new import_client.x402Client().register(requirements.network, {
|
|
2085
|
+
scheme: BATCH_SETTLEMENT_SCHEME,
|
|
2086
|
+
schemeHooks: createBatchSettlementClientHooks(ctx),
|
|
2087
|
+
createPaymentPayload: async () => {
|
|
2088
|
+
throw new Error("Refund payloads are built by refundChannel");
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
return new import_client.x402HTTPClient(client);
|
|
2092
|
+
}
|
|
2093
|
+
function getNonRecoverableRefundFailure(response) {
|
|
2094
|
+
const settleHeader = response.headers.get("PAYMENT-RESPONSE");
|
|
2095
|
+
if (settleHeader) {
|
|
2096
|
+
return formatRefundFailure((0, import_http2.decodePaymentResponseHeader)(settleHeader));
|
|
2097
|
+
}
|
|
2098
|
+
const paymentRequired = getRefundPaymentRequired(response);
|
|
2099
|
+
const errorCode = paymentRequired.error;
|
|
2100
|
+
if (errorCode && NON_RECOVERABLE_REFUND_ERRORS.has(errorCode)) {
|
|
2101
|
+
return `Refund failed: ${errorCode}`;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
function getRefundPaymentRequired(response) {
|
|
2105
|
+
const requiredHeader = response.headers.get("PAYMENT-REQUIRED");
|
|
2106
|
+
if (!requiredHeader) {
|
|
2107
|
+
throw new Error("Refund 402 missing PAYMENT-REQUIRED header");
|
|
2108
|
+
}
|
|
2109
|
+
return (0, import_http2.decodePaymentRequiredHeader)(requiredHeader);
|
|
2110
|
+
}
|
|
2111
|
+
function formatRefundFailure(settle) {
|
|
2112
|
+
const reason = settle.errorReason ?? "unknown_settlement_error";
|
|
2113
|
+
const message = settle.errorMessage;
|
|
2114
|
+
if (message && message !== reason) {
|
|
2115
|
+
return `Refund failed: ${reason}: ${message}`;
|
|
2116
|
+
}
|
|
2117
|
+
return `Refund failed: ${reason}`;
|
|
2118
|
+
}
|
|
2119
|
+
function normalizeRefundAmount(amount) {
|
|
2120
|
+
if (amount === void 0) return void 0;
|
|
2121
|
+
if (!/^\d+$/.test(amount) || amount === "0") {
|
|
2122
|
+
throw new Error(`Invalid refund amount "${amount}": must be a positive integer string`);
|
|
2123
|
+
}
|
|
2124
|
+
return amount;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
// src/batch-settlement/client/scheme.ts
|
|
2128
|
+
var BatchSettlementEvmScheme = class {
|
|
2129
|
+
/**
|
|
2130
|
+
* Constructs a batched client scheme.
|
|
2131
|
+
*
|
|
2132
|
+
* @param signer - Client EVM wallet used for signing vouchers and ERC-3009 authorizations.
|
|
2133
|
+
* @param optionsOrPolicy - Either a full options object or a bare deposit-policy.
|
|
2134
|
+
*/
|
|
2135
|
+
constructor(signer, optionsOrPolicy) {
|
|
2136
|
+
this.signer = signer;
|
|
2137
|
+
this.scheme = BATCH_SETTLEMENT_SCHEME;
|
|
2138
|
+
const {
|
|
2139
|
+
storage,
|
|
2140
|
+
depositPolicy,
|
|
2141
|
+
depositStrategy,
|
|
2142
|
+
salt,
|
|
2143
|
+
payerAuthorizer,
|
|
2144
|
+
voucherSigner,
|
|
2145
|
+
extensionRpcOptions
|
|
2146
|
+
} = resolveClientOptions(optionsOrPolicy);
|
|
2147
|
+
this.storage = storage;
|
|
2148
|
+
this.depositPolicy = depositPolicy;
|
|
2149
|
+
this.depositStrategy = depositStrategy;
|
|
2150
|
+
this.salt = salt;
|
|
2151
|
+
this.payerAuthorizer = payerAuthorizer;
|
|
2152
|
+
this.voucherSigner = voucherSigner;
|
|
2153
|
+
this.extensionRpcOptions = extensionRpcOptions;
|
|
2154
|
+
if (payerAuthorizer !== void 0 && voucherSigner !== void 0 && (0, import_viem22.getAddress)(payerAuthorizer) !== (0, import_viem22.getAddress)(voucherSigner.address)) {
|
|
2155
|
+
throw new Error("payerAuthorizer address must match voucherSigner.address");
|
|
2156
|
+
}
|
|
2157
|
+
validateDepositPolicy(depositPolicy);
|
|
2158
|
+
this.schemeHooks = createBatchSettlementClientHooks(this.deps());
|
|
2159
|
+
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Creates the payment payload for a batched request.
|
|
2162
|
+
*
|
|
2163
|
+
* If the channel has no onchain deposit (or needs a top-up), builds an
|
|
2164
|
+
* ERC-3009 deposit payload bundled with a voucher. Otherwise, signs and
|
|
2165
|
+
* returns a voucher-only payload.
|
|
2166
|
+
*
|
|
2167
|
+
* @param x402Version - Protocol version for the payload envelope.
|
|
2168
|
+
* @param paymentRequirements - Server payment requirements (scheme, network, asset, amount).
|
|
2169
|
+
* @param context - Optional payment payload context with extension hints.
|
|
2170
|
+
* @returns A {@link PaymentPayloadResult} ready to be sent as the `X-PAYMENT` header.
|
|
2171
|
+
*/
|
|
2172
|
+
async createPaymentPayload(x402Version, paymentRequirements, context) {
|
|
2173
|
+
const deps = this.deps();
|
|
2174
|
+
const config = buildChannelConfig(deps, paymentRequirements);
|
|
2175
|
+
const channelId = computeChannelId(config, paymentRequirements.network);
|
|
2176
|
+
const key = channelId.toLowerCase();
|
|
2177
|
+
let batchedCtx = await this.storage.get(key);
|
|
2178
|
+
if (batchedCtx === void 0 && this.signer.readContract) {
|
|
2179
|
+
batchedCtx = await recoverChannel(deps, paymentRequirements);
|
|
2180
|
+
}
|
|
2181
|
+
batchedCtx = batchedCtx ?? {};
|
|
2182
|
+
const needsInitialDeposit = !batchedCtx.balance || batchedCtx.balance === "0";
|
|
2183
|
+
const baseCumulative = BigInt(batchedCtx.chargedCumulativeAmount ?? "0");
|
|
2184
|
+
const requestAmount = BigInt(paymentRequirements.amount);
|
|
2185
|
+
const maxClaimableAmount = (baseCumulative + requestAmount).toString();
|
|
2186
|
+
const currentBalance = BigInt(batchedCtx.balance ?? "0");
|
|
2187
|
+
const needsTopUp = !needsInitialDeposit && BigInt(maxClaimableAmount) > currentBalance;
|
|
2188
|
+
if (needsInitialDeposit || needsTopUp) {
|
|
2189
|
+
const computedDeposit = depositAmountForRequest(this.depositPolicy, requestAmount);
|
|
2190
|
+
const minimumDepositAmount = BigInt(maxClaimableAmount) - currentBalance;
|
|
2191
|
+
const depositAmount = await this.resolveDepositAmount({
|
|
2192
|
+
paymentRequirements,
|
|
2193
|
+
channelConfig: config,
|
|
2194
|
+
channelId,
|
|
2195
|
+
clientContext: batchedCtx,
|
|
2196
|
+
requestAmount: requestAmount.toString(),
|
|
2197
|
+
maxClaimableAmount,
|
|
2198
|
+
currentBalance: currentBalance.toString(),
|
|
2199
|
+
minimumDepositAmount: minimumDepositAmount.toString(),
|
|
2200
|
+
depositAmount: computedDeposit
|
|
2201
|
+
});
|
|
2202
|
+
if (depositAmount === false) {
|
|
2203
|
+
return this.createVoucherPayload(
|
|
2204
|
+
x402Version,
|
|
2205
|
+
channelId,
|
|
2206
|
+
maxClaimableAmount,
|
|
2207
|
+
paymentRequirements.network,
|
|
2208
|
+
config
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
2211
|
+
const assetTransferMethod = paymentRequirements.extra?.assetTransferMethod ?? "eip3009";
|
|
2212
|
+
if (assetTransferMethod === "eip3009") {
|
|
2213
|
+
return createBatchSettlementEIP3009DepositPayload(
|
|
2214
|
+
this.signer,
|
|
2215
|
+
x402Version,
|
|
2216
|
+
paymentRequirements,
|
|
2217
|
+
config,
|
|
2218
|
+
depositAmount,
|
|
2219
|
+
maxClaimableAmount,
|
|
2220
|
+
this.voucherSigner
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2223
|
+
if (assetTransferMethod !== "permit2") {
|
|
2224
|
+
throw new Error(`unsupported batch-settlement assetTransferMethod: ${assetTransferMethod}`);
|
|
2225
|
+
}
|
|
2226
|
+
const result = await createBatchSettlementPermit2DepositPayload(
|
|
2227
|
+
this.signer,
|
|
2228
|
+
x402Version,
|
|
2229
|
+
paymentRequirements,
|
|
2230
|
+
config,
|
|
2231
|
+
depositAmount,
|
|
2232
|
+
maxClaimableAmount,
|
|
2233
|
+
this.voucherSigner
|
|
2234
|
+
);
|
|
2235
|
+
const eip2612Extensions = await trySignEip2612PermitExtension(
|
|
2236
|
+
this.signer,
|
|
2237
|
+
this.extensionRpcOptions,
|
|
2238
|
+
paymentRequirements,
|
|
2239
|
+
result,
|
|
2240
|
+
context,
|
|
2241
|
+
depositAmount
|
|
2242
|
+
);
|
|
2243
|
+
if (eip2612Extensions) {
|
|
2244
|
+
return { ...result, extensions: eip2612Extensions };
|
|
2245
|
+
}
|
|
2246
|
+
const erc20Extensions = await trySignErc20ApprovalExtension(
|
|
2247
|
+
this.signer,
|
|
2248
|
+
this.extensionRpcOptions,
|
|
2249
|
+
paymentRequirements,
|
|
2250
|
+
context,
|
|
2251
|
+
depositAmount
|
|
2252
|
+
);
|
|
2253
|
+
if (erc20Extensions) {
|
|
2254
|
+
return { ...result, extensions: erc20Extensions };
|
|
2255
|
+
}
|
|
2256
|
+
return result;
|
|
2257
|
+
}
|
|
2258
|
+
return this.createVoucherPayload(
|
|
2259
|
+
x402Version,
|
|
2260
|
+
channelId,
|
|
2261
|
+
maxClaimableAmount,
|
|
2262
|
+
paymentRequirements.network,
|
|
2263
|
+
config
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
/**
|
|
2267
|
+
* Sends a cooperative refund request.
|
|
2268
|
+
*
|
|
2269
|
+
* @param url - The route URL backing the channel to refund.
|
|
2270
|
+
* @param options - Optional `amount` (partial refund) and `fetch` override.
|
|
2271
|
+
* @returns The settle response describing the refund outcome.
|
|
2272
|
+
*/
|
|
2273
|
+
async refund(url, options) {
|
|
2274
|
+
return refundChannel(this.deps(), url, options);
|
|
2275
|
+
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Updates local channel state from a settle response.
|
|
2278
|
+
*
|
|
2279
|
+
* @param settle - The parsed settle response from the server.
|
|
2280
|
+
* @returns Resolves when local channel state has been updated.
|
|
2281
|
+
*/
|
|
2282
|
+
async processSettleResponse(settle) {
|
|
2283
|
+
return processSettleResponse(this.storage, settle);
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Resyncs local channel state from a corrective 402 response.
|
|
2287
|
+
*
|
|
2288
|
+
* @param paymentRequired - The decoded 402 response body.
|
|
2289
|
+
* @returns `true` if local state was successfully resynced and a retry is warranted.
|
|
2290
|
+
*/
|
|
2291
|
+
async processCorrectivePaymentRequired(paymentRequired) {
|
|
2292
|
+
return processCorrectivePaymentRequired(this.deps(), paymentRequired);
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Builds the immutable {@link ChannelConfig} for a given set of payment
|
|
2296
|
+
* requirements, using the scheme's own signer and salt.
|
|
2297
|
+
*
|
|
2298
|
+
* @param paymentRequirements - Server payment requirements for the channel.
|
|
2299
|
+
* @returns The channel config that uniquely identifies the payment channel.
|
|
2300
|
+
*/
|
|
2301
|
+
buildChannelConfig(paymentRequirements) {
|
|
2302
|
+
return buildChannelConfig(this.deps(), paymentRequirements);
|
|
2303
|
+
}
|
|
2304
|
+
/**
|
|
2305
|
+
* Resolves the deposit amount after applying the optional custom strategy.
|
|
2306
|
+
*
|
|
2307
|
+
* @param context - Deposit attempt context exposed to the strategy.
|
|
2308
|
+
* @returns The deposit amount to sign, or `false` to skip this deposit attempt.
|
|
2309
|
+
*/
|
|
2310
|
+
async resolveDepositAmount(context) {
|
|
2311
|
+
const strategyResult = await this.depositStrategy?.(context);
|
|
2312
|
+
if (strategyResult === false) return false;
|
|
2313
|
+
if (strategyResult === void 0) return context.depositAmount;
|
|
2314
|
+
const depositAmount = this.normalizeStrategyDepositAmount(strategyResult);
|
|
2315
|
+
if (BigInt(depositAmount) < BigInt(context.minimumDepositAmount)) {
|
|
2316
|
+
throw new Error(
|
|
2317
|
+
`depositStrategy returned ${depositAmount}, below required top-up ${context.minimumDepositAmount}`
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2320
|
+
return depositAmount;
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Normalizes and validates a strategy-provided base-unit deposit amount.
|
|
2324
|
+
*
|
|
2325
|
+
* @param value - Strategy-provided string or bigint amount.
|
|
2326
|
+
* @returns Normalized decimal string.
|
|
2327
|
+
*/
|
|
2328
|
+
normalizeStrategyDepositAmount(value) {
|
|
2329
|
+
if (typeof value === "bigint") {
|
|
2330
|
+
if (value <= 0n) {
|
|
2331
|
+
throw new Error("depositStrategy must return a positive integer deposit amount");
|
|
2332
|
+
}
|
|
2333
|
+
return value.toString();
|
|
2334
|
+
}
|
|
2335
|
+
if (/^\d+$/.test(value) && BigInt(value) > 0n) {
|
|
2336
|
+
return BigInt(value).toString();
|
|
2337
|
+
}
|
|
2338
|
+
throw new Error("depositStrategy must return a positive integer deposit amount");
|
|
2339
|
+
}
|
|
2340
|
+
/**
|
|
2341
|
+
* Signs a voucher-only payment payload for the current channel.
|
|
2342
|
+
*
|
|
2343
|
+
* @param x402Version - Protocol version for the payload envelope.
|
|
2344
|
+
* @param channelId - Channel identifier for the voucher.
|
|
2345
|
+
* @param maxClaimableAmount - Cumulative ceiling for the voucher.
|
|
2346
|
+
* @param network - CAIP-2 network identifier.
|
|
2347
|
+
* @param config - Immutable channel configuration.
|
|
2348
|
+
* @returns Voucher-only payment payload.
|
|
2349
|
+
*/
|
|
2350
|
+
async createVoucherPayload(x402Version, channelId, maxClaimableAmount, network, config) {
|
|
2351
|
+
const voucherSigner = this.voucherSigner ?? this.signer;
|
|
2352
|
+
const voucher = await signVoucher(voucherSigner, channelId, maxClaimableAmount, network);
|
|
2353
|
+
const payload = {
|
|
2354
|
+
type: "voucher",
|
|
2355
|
+
channelConfig: config,
|
|
2356
|
+
voucher
|
|
2357
|
+
};
|
|
2358
|
+
return {
|
|
2359
|
+
x402Version,
|
|
2360
|
+
payload
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Bundles the class state into the {@link BatchSettlementClientDeps} shape
|
|
2365
|
+
* consumed by the `channel`, `recovery`, and `refund` modules.
|
|
2366
|
+
*
|
|
2367
|
+
* @returns Client deps wrapping the scheme's own signer and storage.
|
|
2368
|
+
*/
|
|
2369
|
+
deps() {
|
|
2370
|
+
return {
|
|
2371
|
+
signer: this.signer,
|
|
2372
|
+
storage: this.storage,
|
|
2373
|
+
salt: this.salt,
|
|
2374
|
+
payerAuthorizer: this.payerAuthorizer,
|
|
2375
|
+
voucherSigner: this.voucherSigner
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
|
|
2380
|
+
// src/shared/defaultAssets.ts
|
|
2381
|
+
var DEFAULT_STABLECOINS = {
|
|
2382
|
+
"eip155:8453": {
|
|
2383
|
+
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
2384
|
+
name: "USD Coin",
|
|
2385
|
+
version: "2",
|
|
2386
|
+
decimals: 6
|
|
2387
|
+
},
|
|
2388
|
+
// Base mainnet USDC
|
|
2389
|
+
"eip155:84532": {
|
|
2390
|
+
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
2391
|
+
name: "USDC",
|
|
2392
|
+
version: "2",
|
|
2393
|
+
decimals: 6
|
|
2394
|
+
},
|
|
2395
|
+
// Base Sepolia USDC
|
|
2396
|
+
"eip155:4326": {
|
|
2397
|
+
address: "0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7",
|
|
2398
|
+
name: "MegaUSD",
|
|
2399
|
+
version: "1",
|
|
2400
|
+
decimals: 18,
|
|
2401
|
+
assetTransferMethod: "permit2",
|
|
2402
|
+
supportsEip2612: true
|
|
2403
|
+
},
|
|
2404
|
+
// MegaETH mainnet MegaUSD (no EIP-3009, supports EIP-2612)
|
|
2405
|
+
"eip155:143": {
|
|
2406
|
+
address: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
|
|
2407
|
+
name: "USD Coin",
|
|
2408
|
+
version: "2",
|
|
2409
|
+
decimals: 6
|
|
2410
|
+
},
|
|
2411
|
+
// Monad mainnet USDC
|
|
2412
|
+
"eip155:988": {
|
|
2413
|
+
address: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
|
|
2414
|
+
name: "USDT0",
|
|
2415
|
+
version: "1",
|
|
2416
|
+
decimals: 6
|
|
2417
|
+
},
|
|
2418
|
+
// Stable mainnet USDT0
|
|
2419
|
+
"eip155:2201": {
|
|
2420
|
+
address: "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9",
|
|
2421
|
+
name: "USDT0",
|
|
2422
|
+
version: "1",
|
|
2423
|
+
decimals: 6
|
|
2424
|
+
},
|
|
2425
|
+
// Stable testnet USDT0
|
|
2426
|
+
"eip155:137": {
|
|
2427
|
+
address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
2428
|
+
name: "USD Coin",
|
|
2429
|
+
version: "2",
|
|
2430
|
+
decimals: 6
|
|
2431
|
+
},
|
|
2432
|
+
// Polygon mainnet USDC
|
|
2433
|
+
"eip155:42161": {
|
|
2434
|
+
address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
2435
|
+
name: "USD Coin",
|
|
2436
|
+
version: "2",
|
|
2437
|
+
decimals: 6
|
|
2438
|
+
},
|
|
2439
|
+
// Arbitrum One USDC
|
|
2440
|
+
"eip155:421614": {
|
|
2441
|
+
address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
|
|
2442
|
+
name: "USD Coin",
|
|
2443
|
+
version: "2",
|
|
2444
|
+
decimals: 6
|
|
2445
|
+
},
|
|
2446
|
+
// Arbitrum Sepolia USDC
|
|
2447
|
+
"eip155:31612": {
|
|
2448
|
+
address: "0xdD468A1DDc392dcdbEf6db6e34E89AA338F9F186",
|
|
2449
|
+
name: "Mezo USD",
|
|
2450
|
+
version: "1",
|
|
2451
|
+
decimals: 18,
|
|
2452
|
+
assetTransferMethod: "permit2",
|
|
2453
|
+
supportsEip2612: true
|
|
2454
|
+
},
|
|
2455
|
+
// Mezo mainnet mUSD (no EIP-3009, supports EIP-2612)
|
|
2456
|
+
"eip155:31611": {
|
|
2457
|
+
address: "0x118917a40FAF1CD7a13dB0Ef56C86De7973Ac503",
|
|
2458
|
+
name: "Mezo USD",
|
|
2459
|
+
version: "1",
|
|
2460
|
+
decimals: 18,
|
|
2461
|
+
assetTransferMethod: "permit2",
|
|
2462
|
+
supportsEip2612: true
|
|
2463
|
+
},
|
|
2464
|
+
// Mezo Testnet mUSD (no EIP-3009, supports EIP-2612)
|
|
2465
|
+
"eip155:723487": {
|
|
2466
|
+
address: "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb",
|
|
2467
|
+
name: "Stable Coin",
|
|
2468
|
+
version: "1",
|
|
2469
|
+
decimals: 6,
|
|
2470
|
+
assetTransferMethod: "permit2",
|
|
2471
|
+
supportsEip2612: true
|
|
2472
|
+
},
|
|
2473
|
+
// Radius Network SBC (no EIP-3009, supports EIP-2612)
|
|
2474
|
+
"eip155:72344": {
|
|
2475
|
+
address: "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb",
|
|
2476
|
+
name: "Stable Coin",
|
|
2477
|
+
version: "1",
|
|
2478
|
+
decimals: 6,
|
|
2479
|
+
assetTransferMethod: "permit2",
|
|
2480
|
+
supportsEip2612: true
|
|
2481
|
+
},
|
|
2482
|
+
// Radius Testnet SBC (no EIP-3009, supports EIP-2612)
|
|
2483
|
+
"eip155:36900": {
|
|
2484
|
+
address: "0x9cb8142aEBBcdc60AF7c97Af897A67A8f3CA71C2",
|
|
2485
|
+
name: "USDC.e",
|
|
2486
|
+
version: "2",
|
|
2487
|
+
decimals: 6
|
|
2488
|
+
},
|
|
2489
|
+
// ADI Chain USDC.e (EIP-3009 supported)
|
|
2490
|
+
"eip155:190415": {
|
|
2491
|
+
address: "0x401eCb1D350407f13ba348573E5630B83638E30D",
|
|
2492
|
+
name: "Bridged USDC",
|
|
2493
|
+
version: "2",
|
|
2494
|
+
decimals: 6
|
|
2495
|
+
},
|
|
2496
|
+
// HPP mainnet USDC.e
|
|
2497
|
+
"eip155:181228": {
|
|
2498
|
+
address: "0x401eCb1D350407f13ba348573E5630B83638E30D",
|
|
2499
|
+
name: "Bridged USDC",
|
|
2500
|
+
version: "2",
|
|
2501
|
+
decimals: 6
|
|
2502
|
+
},
|
|
2503
|
+
// HPP Sepolia USDC.e
|
|
2504
|
+
"eip155:50": {
|
|
2505
|
+
address: "0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1",
|
|
2506
|
+
name: "USDC",
|
|
2507
|
+
version: "2",
|
|
2508
|
+
decimals: 6
|
|
2509
|
+
},
|
|
2510
|
+
// XDC Network mainnet USDC (Bridged USDC Standard, EIP-3009 supported)
|
|
2511
|
+
"eip155:51": {
|
|
2512
|
+
address: "0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4",
|
|
2513
|
+
name: "USDC",
|
|
2514
|
+
version: "2",
|
|
2515
|
+
decimals: 6
|
|
2516
|
+
}
|
|
2517
|
+
// XDC Apothem testnet USDC (Bridged USDC Standard, EIP-3009 supported)
|
|
2518
|
+
};
|
|
2519
|
+
function getDefaultAsset(network) {
|
|
2520
|
+
const info = DEFAULT_STABLECOINS[network];
|
|
2521
|
+
if (!info) {
|
|
2522
|
+
throw new Error(`No default asset configured for network ${network}`);
|
|
2523
|
+
}
|
|
2524
|
+
return info;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
// src/auth-capture/client/scheme.ts
|
|
2528
|
+
var import_viem24 = require("viem");
|
|
2529
|
+
|
|
2530
|
+
// src/auth-capture/constants.ts
|
|
2531
|
+
var AUTH_CAPTURE_SCHEME = "auth-capture";
|
|
2532
|
+
var AUTH_CAPTURE_ESCROW_ADDRESS = "0xBdEA0D1bcC5966192B070Fdf62aB4EF5b4420cff";
|
|
2533
|
+
var EIP3009_TOKEN_COLLECTOR_ADDRESS = "0x0E3dF9510de65469C4518D7843919c0b8C7A7757";
|
|
2534
|
+
var PERMIT2_TOKEN_COLLECTOR_ADDRESS = "0x992476B9Ee81d52a5BdA0622C333938D0Af0aB26";
|
|
2535
|
+
var RECEIVE_AUTHORIZATION_TYPES = {
|
|
2536
|
+
ReceiveWithAuthorization: [
|
|
2537
|
+
{ name: "from", type: "address" },
|
|
2538
|
+
{ name: "to", type: "address" },
|
|
2539
|
+
{ name: "value", type: "uint256" },
|
|
2540
|
+
{ name: "validAfter", type: "uint256" },
|
|
2541
|
+
{ name: "validBefore", type: "uint256" },
|
|
2542
|
+
{ name: "nonce", type: "bytes32" }
|
|
2543
|
+
]
|
|
2544
|
+
};
|
|
2545
|
+
var PERMIT2_TRANSFER_FROM_TYPES = {
|
|
2546
|
+
PermitTransferFrom: [
|
|
2547
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
2548
|
+
{ name: "spender", type: "address" },
|
|
2549
|
+
{ name: "nonce", type: "uint256" },
|
|
2550
|
+
{ name: "deadline", type: "uint256" }
|
|
2551
|
+
],
|
|
2552
|
+
TokenPermissions: [
|
|
2553
|
+
{ name: "token", type: "address" },
|
|
2554
|
+
{ name: "amount", type: "uint256" }
|
|
2555
|
+
]
|
|
2556
|
+
};
|
|
2557
|
+
|
|
2558
|
+
// src/auth-capture/nonce.ts
|
|
2559
|
+
var import_viem23 = require("viem");
|
|
2560
|
+
var PAYMENT_INFO_TYPEHASH = (0, import_viem23.keccak256)(
|
|
2561
|
+
new TextEncoder().encode(
|
|
2562
|
+
"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)"
|
|
2563
|
+
)
|
|
2564
|
+
);
|
|
2565
|
+
function computePayerAgnosticPaymentInfoHash(chainId, paymentInfo) {
|
|
2566
|
+
const paymentInfoEncoded = (0, import_viem23.encodeAbiParameters)(
|
|
2567
|
+
[
|
|
2568
|
+
{ name: "typehash", type: "bytes32" },
|
|
2569
|
+
{ name: "operator", type: "address" },
|
|
2570
|
+
{ name: "payer", type: "address" },
|
|
2571
|
+
{ name: "receiver", type: "address" },
|
|
2572
|
+
{ name: "token", type: "address" },
|
|
2573
|
+
{ name: "maxAmount", type: "uint120" },
|
|
2574
|
+
{ name: "preApprovalExpiry", type: "uint48" },
|
|
2575
|
+
{ name: "authorizationExpiry", type: "uint48" },
|
|
2576
|
+
{ name: "refundExpiry", type: "uint48" },
|
|
2577
|
+
{ name: "minFeeBps", type: "uint16" },
|
|
2578
|
+
{ name: "maxFeeBps", type: "uint16" },
|
|
2579
|
+
{ name: "feeReceiver", type: "address" },
|
|
2580
|
+
{ name: "salt", type: "uint256" }
|
|
2581
|
+
],
|
|
2582
|
+
[
|
|
2583
|
+
PAYMENT_INFO_TYPEHASH,
|
|
2584
|
+
paymentInfo.operator,
|
|
2585
|
+
import_viem23.zeroAddress,
|
|
2586
|
+
paymentInfo.receiver,
|
|
2587
|
+
paymentInfo.token,
|
|
2588
|
+
BigInt(paymentInfo.maxAmount),
|
|
2589
|
+
paymentInfo.preApprovalExpiry,
|
|
2590
|
+
paymentInfo.authorizationExpiry,
|
|
2591
|
+
paymentInfo.refundExpiry,
|
|
2592
|
+
paymentInfo.minFeeBps,
|
|
2593
|
+
paymentInfo.maxFeeBps,
|
|
2594
|
+
paymentInfo.feeReceiver,
|
|
2595
|
+
BigInt(paymentInfo.salt)
|
|
2596
|
+
]
|
|
2597
|
+
);
|
|
2598
|
+
const paymentInfoHash = (0, import_viem23.keccak256)(paymentInfoEncoded);
|
|
2599
|
+
const outerEncoded = (0, import_viem23.encodeAbiParameters)(
|
|
2600
|
+
[
|
|
2601
|
+
{ name: "chainId", type: "uint256" },
|
|
2602
|
+
{ name: "escrow", type: "address" },
|
|
2603
|
+
{ name: "paymentInfoHash", type: "bytes32" }
|
|
2604
|
+
],
|
|
2605
|
+
[BigInt(chainId), AUTH_CAPTURE_ESCROW_ADDRESS, paymentInfoHash]
|
|
2606
|
+
);
|
|
2607
|
+
return (0, import_viem23.keccak256)(outerEncoded);
|
|
2608
|
+
}
|
|
2609
|
+
async function signERC3009(signer, authorization, extra, tokenAddress, chainId) {
|
|
2610
|
+
const domain = {
|
|
2611
|
+
name: extra.name,
|
|
2612
|
+
version: extra.version,
|
|
2613
|
+
chainId,
|
|
2614
|
+
verifyingContract: (0, import_viem23.getAddress)(tokenAddress)
|
|
2615
|
+
};
|
|
2616
|
+
const message = {
|
|
2617
|
+
from: (0, import_viem23.getAddress)(authorization.from),
|
|
2618
|
+
to: (0, import_viem23.getAddress)(authorization.to),
|
|
2619
|
+
value: BigInt(authorization.value),
|
|
2620
|
+
validAfter: BigInt(authorization.validAfter),
|
|
2621
|
+
validBefore: BigInt(authorization.validBefore),
|
|
2622
|
+
nonce: authorization.nonce
|
|
2623
|
+
};
|
|
2624
|
+
return signer.signTypedData({
|
|
2625
|
+
domain,
|
|
2626
|
+
types: RECEIVE_AUTHORIZATION_TYPES,
|
|
2627
|
+
primaryType: "ReceiveWithAuthorization",
|
|
2628
|
+
message
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
async function signPermit2(signer, permit, chainId) {
|
|
2632
|
+
const domain = {
|
|
2633
|
+
name: "Permit2",
|
|
2634
|
+
chainId,
|
|
2635
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
2636
|
+
};
|
|
2637
|
+
const message = {
|
|
2638
|
+
permitted: {
|
|
2639
|
+
token: (0, import_viem23.getAddress)(permit.permitted.token),
|
|
2640
|
+
amount: BigInt(permit.permitted.amount)
|
|
2641
|
+
},
|
|
2642
|
+
spender: (0, import_viem23.getAddress)(permit.spender),
|
|
2643
|
+
nonce: BigInt(permit.nonce),
|
|
2644
|
+
deadline: BigInt(permit.deadline)
|
|
2645
|
+
};
|
|
2646
|
+
return signer.signTypedData({
|
|
2647
|
+
domain,
|
|
2648
|
+
types: PERMIT2_TRANSFER_FROM_TYPES,
|
|
2649
|
+
primaryType: "PermitTransferFrom",
|
|
2650
|
+
message
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
function generateSalt() {
|
|
2654
|
+
const bytes = new Uint8Array(32);
|
|
2655
|
+
crypto.getRandomValues(bytes);
|
|
2656
|
+
return (0, import_viem23.toHex)(bytes);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
// src/auth-capture/utils.ts
|
|
2660
|
+
function parseChainId(network) {
|
|
2661
|
+
const parts = network.split(":");
|
|
2662
|
+
if (parts.length !== 2 || parts[0] !== "eip155") {
|
|
2663
|
+
throw new Error(`Invalid network format: ${network}. Expected 'eip155:<chainId>'`);
|
|
2664
|
+
}
|
|
2665
|
+
const chainId = parseInt(parts[1], 10);
|
|
2666
|
+
if (isNaN(chainId)) {
|
|
2667
|
+
throw new Error(`Invalid chainId in network: ${network}`);
|
|
2668
|
+
}
|
|
2669
|
+
return chainId;
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
// src/auth-capture/client/scheme.ts
|
|
2673
|
+
var AuthCaptureEvmScheme = class {
|
|
2674
|
+
/**
|
|
2675
|
+
* Construct a client-side auth-capture scheme bound to a specific signer.
|
|
2676
|
+
*
|
|
2677
|
+
* @param signer - Client-side signer that exposes `address` and `signTypedData`.
|
|
2678
|
+
*/
|
|
2679
|
+
constructor(signer) {
|
|
2680
|
+
this.signer = signer;
|
|
2681
|
+
this.scheme = AUTH_CAPTURE_SCHEME;
|
|
2682
|
+
}
|
|
2683
|
+
/**
|
|
2684
|
+
* Build and sign an auth-capture payment payload for the given requirements.
|
|
2685
|
+
* Validates all spec-mandated `extra` fields and the asset-transfer method
|
|
2686
|
+
* (default `eip3009`, alternative `permit2`), reconstructs the on-chain
|
|
2687
|
+
* PaymentInfo struct, computes its payer-agnostic hash, and returns the
|
|
2688
|
+
* signed wire payload.
|
|
2689
|
+
*
|
|
2690
|
+
* @param x402Version - Wire protocol version; only `2` is supported.
|
|
2691
|
+
* @param requirements - Resource server's payment requirements (includes scheme `extra`).
|
|
2692
|
+
* @param _ - Unused FacilitatorContext (interface compatibility).
|
|
2693
|
+
* @returns The signed wire payload tagged with the x402 protocol version.
|
|
2694
|
+
* @throws If `x402Version !== 2` or any required `extra` field is missing.
|
|
2695
|
+
*/
|
|
2696
|
+
async createPaymentPayload(x402Version, requirements, _) {
|
|
2697
|
+
if (x402Version !== 2) {
|
|
2698
|
+
throw new Error(`Unsupported x402Version: ${x402Version}. Only version 2 is supported.`);
|
|
2699
|
+
}
|
|
2700
|
+
const extra = requirements.extra;
|
|
2701
|
+
if (!extra.name) {
|
|
2702
|
+
throw new Error(
|
|
2703
|
+
`EIP-712 domain parameter 'name' is required in payment requirements for asset ${requirements.asset}`
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2706
|
+
if (!extra.version) {
|
|
2707
|
+
throw new Error(
|
|
2708
|
+
`EIP-712 domain parameter 'version' is required in payment requirements for asset ${requirements.asset}`
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
if (!extra.captureAuthorizer) {
|
|
2712
|
+
throw new Error(`'captureAuthorizer' is required in payment requirements extra`);
|
|
2713
|
+
}
|
|
2714
|
+
if (!extra.feeRecipient) {
|
|
2715
|
+
throw new Error(`'feeRecipient' is required in payment requirements extra`);
|
|
2716
|
+
}
|
|
2717
|
+
if (typeof extra.captureDeadline !== "number") {
|
|
2718
|
+
throw new Error(`'captureDeadline' is required in payment requirements extra`);
|
|
2719
|
+
}
|
|
2720
|
+
if (typeof extra.refundDeadline !== "number") {
|
|
2721
|
+
throw new Error(`'refundDeadline' is required in payment requirements extra`);
|
|
2722
|
+
}
|
|
2723
|
+
if (typeof extra.minFeeBps !== "number") {
|
|
2724
|
+
throw new Error(`'minFeeBps' is required in payment requirements extra`);
|
|
2725
|
+
}
|
|
2726
|
+
if (typeof extra.maxFeeBps !== "number") {
|
|
2727
|
+
throw new Error(`'maxFeeBps' is required in payment requirements extra`);
|
|
2728
|
+
}
|
|
2729
|
+
if (typeof requirements.maxTimeoutSeconds !== "number") {
|
|
2730
|
+
throw new Error(
|
|
2731
|
+
`'maxTimeoutSeconds' is required in PaymentRequirements (used to derive preApprovalExpiry)`
|
|
2732
|
+
);
|
|
2733
|
+
}
|
|
2734
|
+
const chainId = parseChainId(requirements.network);
|
|
2735
|
+
const maxAmount = requirements.amount;
|
|
2736
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
2737
|
+
const preApprovalExpiry = nowSeconds + requirements.maxTimeoutSeconds;
|
|
2738
|
+
const salt = generateSalt();
|
|
2739
|
+
const assetTransferMethod = extra.assetTransferMethod ?? "eip3009";
|
|
2740
|
+
const paymentInfo = {
|
|
2741
|
+
operator: extra.captureAuthorizer,
|
|
2742
|
+
payer: this.signer.address,
|
|
2743
|
+
receiver: requirements.payTo,
|
|
2744
|
+
token: requirements.asset,
|
|
2745
|
+
maxAmount,
|
|
2746
|
+
preApprovalExpiry,
|
|
2747
|
+
authorizationExpiry: extra.captureDeadline,
|
|
2748
|
+
refundExpiry: extra.refundDeadline,
|
|
2749
|
+
minFeeBps: extra.minFeeBps,
|
|
2750
|
+
maxFeeBps: extra.maxFeeBps,
|
|
2751
|
+
feeReceiver: extra.feeRecipient,
|
|
2752
|
+
salt
|
|
2753
|
+
};
|
|
2754
|
+
const nonce = computePayerAgnosticPaymentInfoHash(chainId, paymentInfo);
|
|
2755
|
+
if (assetTransferMethod === "permit2") {
|
|
2756
|
+
const permit2Authorization = {
|
|
2757
|
+
from: this.signer.address,
|
|
2758
|
+
permitted: {
|
|
2759
|
+
token: requirements.asset,
|
|
2760
|
+
amount: maxAmount
|
|
2761
|
+
},
|
|
2762
|
+
spender: PERMIT2_TOKEN_COLLECTOR_ADDRESS,
|
|
2763
|
+
nonce: (0, import_viem24.hexToBigInt)(nonce).toString(),
|
|
2764
|
+
deadline: String(preApprovalExpiry)
|
|
2765
|
+
};
|
|
2766
|
+
const signature2 = await signPermit2(this.signer, permit2Authorization, chainId);
|
|
2767
|
+
const payload2 = { permit2Authorization, signature: signature2, salt };
|
|
2768
|
+
return { x402Version, payload: payload2 };
|
|
2769
|
+
}
|
|
2770
|
+
const authorization = {
|
|
2771
|
+
from: this.signer.address,
|
|
2772
|
+
to: EIP3009_TOKEN_COLLECTOR_ADDRESS,
|
|
2773
|
+
value: maxAmount,
|
|
2774
|
+
validAfter: "0",
|
|
2775
|
+
validBefore: String(preApprovalExpiry),
|
|
2776
|
+
nonce
|
|
2777
|
+
};
|
|
2778
|
+
const signature = await signERC3009(
|
|
2779
|
+
this.signer,
|
|
2780
|
+
authorization,
|
|
2781
|
+
extra,
|
|
2782
|
+
requirements.asset,
|
|
2783
|
+
chainId
|
|
2784
|
+
);
|
|
2785
|
+
const payload = { authorization, signature, salt };
|
|
2786
|
+
return { x402Version, payload };
|
|
2787
|
+
}
|
|
2788
|
+
};
|
|
2789
|
+
|
|
2790
|
+
// src/auth-capture/types.ts
|
|
2791
|
+
function isAuthCaptureExtra(value) {
|
|
2792
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2793
|
+
const v = value;
|
|
2794
|
+
return typeof v.captureAuthorizer === "string" && typeof v.captureDeadline === "number" && typeof v.refundDeadline === "number" && typeof v.feeRecipient === "string" && typeof v.minFeeBps === "number" && typeof v.maxFeeBps === "number" && typeof v.name === "string" && typeof v.version === "string";
|
|
2795
|
+
}
|
|
2796
|
+
function isEip3009Payload(value) {
|
|
2797
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2798
|
+
const v = value;
|
|
2799
|
+
return "authorization" in v && typeof v.authorization === "object" && v.authorization !== null && typeof v.signature === "string" && typeof v.salt === "string";
|
|
2800
|
+
}
|
|
2801
|
+
function isPermit2Payload2(value) {
|
|
2802
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2803
|
+
const v = value;
|
|
2804
|
+
if (typeof v.signature !== "string" || typeof v.salt !== "string") return false;
|
|
2805
|
+
if (typeof v.permit2Authorization !== "object" || v.permit2Authorization === null) return false;
|
|
2806
|
+
const a = v.permit2Authorization;
|
|
2807
|
+
return typeof a.from === "string" && typeof a.spender === "string" && typeof a.nonce === "string" && typeof a.deadline === "string" && typeof a.permitted === "object" && a.permitted !== null;
|
|
2808
|
+
}
|
|
2809
|
+
function isAuthCapturePayload(value) {
|
|
2810
|
+
return isEip3009Payload(value) || isPermit2Payload2(value);
|
|
2811
|
+
}
|
|
2812
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2813
|
+
0 && (module.exports = {
|
|
2814
|
+
AUTH_CAPTURE_ESCROW_ADDRESS,
|
|
2815
|
+
AUTH_CAPTURE_SCHEME,
|
|
2816
|
+
AuthCaptureEvmScheme,
|
|
2817
|
+
BATCH_SETTLEMENT_ADDRESS,
|
|
2818
|
+
BATCH_SETTLEMENT_DOMAIN,
|
|
2819
|
+
BATCH_SETTLEMENT_SCHEME,
|
|
2820
|
+
BUILDER_CODE_KEY,
|
|
2821
|
+
BatchSettlementEvmScheme,
|
|
2822
|
+
DEFAULT_STABLECOINS,
|
|
2823
|
+
EIP3009_TOKEN_COLLECTOR_ADDRESS,
|
|
2824
|
+
ERC3009_DEPOSIT_COLLECTOR_ADDRESS,
|
|
2825
|
+
ExactEvmScheme,
|
|
2826
|
+
PERMIT2_ADDRESS,
|
|
2827
|
+
PERMIT2_TOKEN_COLLECTOR_ADDRESS,
|
|
2828
|
+
UptoEvmScheme,
|
|
2829
|
+
appendDataSuffix,
|
|
2830
|
+
authorizationTypes,
|
|
2831
|
+
claimBatchTypes,
|
|
2832
|
+
createPermit2ApprovalTx,
|
|
2833
|
+
eip3009ABI,
|
|
2834
|
+
erc20AllowanceAbi,
|
|
2835
|
+
getDefaultAsset,
|
|
2836
|
+
getPermit2AllowanceReadParams,
|
|
2837
|
+
isAuthCaptureExtra,
|
|
2838
|
+
isAuthCapturePayload,
|
|
2839
|
+
isBatchSettlementClaimPayload,
|
|
2840
|
+
isBatchSettlementDepositPayload,
|
|
2841
|
+
isBatchSettlementEnrichedRefundPayload,
|
|
2842
|
+
isBatchSettlementRefundPayload,
|
|
2843
|
+
isBatchSettlementSettlePayload,
|
|
2844
|
+
isBatchSettlementVoucherPayload,
|
|
2845
|
+
isEIP3009Payload,
|
|
2846
|
+
isPermit2Payload,
|
|
2847
|
+
isUptoPermit2Payload,
|
|
2848
|
+
permit2WitnessTypes,
|
|
2849
|
+
refundTypes,
|
|
2850
|
+
resolveDataSuffix,
|
|
2851
|
+
toClientEvmSigner,
|
|
2852
|
+
toFacilitatorEvmSigner,
|
|
2853
|
+
uptoPermit2WitnessTypes,
|
|
2854
|
+
voucherTypes,
|
|
2855
|
+
x402ExactPermit2ProxyABI,
|
|
2856
|
+
x402ExactPermit2ProxyAddress,
|
|
2857
|
+
x402UptoPermit2ProxyABI,
|
|
2858
|
+
x402UptoPermit2ProxyAddress
|
|
2859
|
+
});
|
|
2860
|
+
//# sourceMappingURL=index.js.map
|