x402-evm-mantle 2.1.1-mantle
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 +183 -0
- package/dist/cjs/exact/client/index.d.ts +53 -0
- package/dist/cjs/exact/client/index.js +270 -0
- package/dist/cjs/exact/client/index.js.map +1 -0
- package/dist/cjs/exact/facilitator/index.d.ts +118 -0
- package/dist/cjs/exact/facilitator/index.js +735 -0
- package/dist/cjs/exact/facilitator/index.js.map +1 -0
- package/dist/cjs/exact/server/index.d.ts +140 -0
- package/dist/cjs/exact/server/index.js +247 -0
- package/dist/cjs/exact/server/index.js.map +1 -0
- package/dist/cjs/exact/v1/client/index.d.ts +37 -0
- package/dist/cjs/exact/v1/client/index.js +147 -0
- package/dist/cjs/exact/v1/client/index.js.map +1 -0
- package/dist/cjs/exact/v1/facilitator/index.d.ts +62 -0
- package/dist/cjs/exact/v1/facilitator/index.js +401 -0
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -0
- package/dist/cjs/index.d.ts +36 -0
- package/dist/cjs/index.js +148 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/signer-5OVDxViv.d.ts +79 -0
- package/dist/cjs/v1/index.d.ts +7 -0
- package/dist/cjs/v1/index.js +171 -0
- package/dist/cjs/v1/index.js.map +1 -0
- package/dist/esm/chunk-CYGMVQCG.mjs +88 -0
- package/dist/esm/chunk-CYGMVQCG.mjs.map +1 -0
- package/dist/esm/chunk-DI3EK7PR.mjs +305 -0
- package/dist/esm/chunk-DI3EK7PR.mjs.map +1 -0
- package/dist/esm/chunk-QLXM7BIB.mjs +23 -0
- package/dist/esm/chunk-QLXM7BIB.mjs.map +1 -0
- package/dist/esm/chunk-S5OEANGR.mjs +92 -0
- package/dist/esm/chunk-S5OEANGR.mjs.map +1 -0
- package/dist/esm/chunk-T3FPOH7F.mjs +88 -0
- package/dist/esm/chunk-T3FPOH7F.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +53 -0
- package/dist/esm/exact/client/index.mjs +36 -0
- package/dist/esm/exact/client/index.mjs.map +1 -0
- package/dist/esm/exact/facilitator/index.d.mts +118 -0
- package/dist/esm/exact/facilitator/index.mjs +324 -0
- package/dist/esm/exact/facilitator/index.mjs.map +1 -0
- package/dist/esm/exact/server/index.d.mts +140 -0
- package/dist/esm/exact/server/index.mjs +219 -0
- package/dist/esm/exact/server/index.mjs.map +1 -0
- package/dist/esm/exact/v1/client/index.d.mts +37 -0
- package/dist/esm/exact/v1/client/index.mjs +8 -0
- package/dist/esm/exact/v1/client/index.mjs.map +1 -0
- package/dist/esm/exact/v1/facilitator/index.d.mts +62 -0
- package/dist/esm/exact/v1/facilitator/index.mjs +8 -0
- package/dist/esm/exact/v1/facilitator/index.mjs.map +1 -0
- package/dist/esm/index.d.mts +36 -0
- package/dist/esm/index.mjs +21 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/signer-5OVDxViv.d.mts +79 -0
- package/dist/esm/v1/index.d.mts +7 -0
- package/dist/esm/v1/index.mjs +13 -0
- package/dist/esm/v1/index.mjs.map +1 -0
- package/package.json +127 -0
|
@@ -0,0 +1,735 @@
|
|
|
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/exact/facilitator/index.ts
|
|
21
|
+
var facilitator_exports = {};
|
|
22
|
+
__export(facilitator_exports, {
|
|
23
|
+
ExactEvmScheme: () => ExactEvmScheme,
|
|
24
|
+
registerExactEvmScheme: () => registerExactEvmScheme
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(facilitator_exports);
|
|
27
|
+
|
|
28
|
+
// src/exact/facilitator/scheme.ts
|
|
29
|
+
var import_viem = require("viem");
|
|
30
|
+
|
|
31
|
+
// src/constants.ts
|
|
32
|
+
var authorizationTypes = {
|
|
33
|
+
TransferWithAuthorization: [
|
|
34
|
+
{ name: "from", type: "address" },
|
|
35
|
+
{ name: "to", type: "address" },
|
|
36
|
+
{ name: "value", type: "uint256" },
|
|
37
|
+
{ name: "validAfter", type: "uint256" },
|
|
38
|
+
{ name: "validBefore", type: "uint256" },
|
|
39
|
+
{ name: "nonce", type: "bytes32" }
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
var eip3009ABI = [
|
|
43
|
+
{
|
|
44
|
+
inputs: [
|
|
45
|
+
{ name: "from", type: "address" },
|
|
46
|
+
{ name: "to", type: "address" },
|
|
47
|
+
{ name: "value", type: "uint256" },
|
|
48
|
+
{ name: "validAfter", type: "uint256" },
|
|
49
|
+
{ name: "validBefore", type: "uint256" },
|
|
50
|
+
{ name: "nonce", type: "bytes32" },
|
|
51
|
+
{ name: "v", type: "uint8" },
|
|
52
|
+
{ name: "r", type: "bytes32" },
|
|
53
|
+
{ name: "s", type: "bytes32" }
|
|
54
|
+
],
|
|
55
|
+
name: "transferWithAuthorization",
|
|
56
|
+
outputs: [],
|
|
57
|
+
stateMutability: "nonpayable",
|
|
58
|
+
type: "function"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
inputs: [
|
|
62
|
+
{ name: "from", type: "address" },
|
|
63
|
+
{ name: "to", type: "address" },
|
|
64
|
+
{ name: "value", type: "uint256" },
|
|
65
|
+
{ name: "validAfter", type: "uint256" },
|
|
66
|
+
{ name: "validBefore", type: "uint256" },
|
|
67
|
+
{ name: "nonce", type: "bytes32" },
|
|
68
|
+
{ name: "signature", type: "bytes" }
|
|
69
|
+
],
|
|
70
|
+
name: "transferWithAuthorization",
|
|
71
|
+
outputs: [],
|
|
72
|
+
stateMutability: "nonpayable",
|
|
73
|
+
type: "function"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
inputs: [{ name: "account", type: "address" }],
|
|
77
|
+
name: "balanceOf",
|
|
78
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
79
|
+
stateMutability: "view",
|
|
80
|
+
type: "function"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
inputs: [],
|
|
84
|
+
name: "version",
|
|
85
|
+
outputs: [{ name: "", type: "string" }],
|
|
86
|
+
stateMutability: "view",
|
|
87
|
+
type: "function"
|
|
88
|
+
}
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
// src/exact/facilitator/scheme.ts
|
|
92
|
+
var ExactEvmScheme = class {
|
|
93
|
+
/**
|
|
94
|
+
* Creates a new ExactEvmFacilitator instance.
|
|
95
|
+
*
|
|
96
|
+
* @param signer - The EVM signer for facilitator operations
|
|
97
|
+
* @param config - Optional configuration for the facilitator
|
|
98
|
+
*/
|
|
99
|
+
constructor(signer, config) {
|
|
100
|
+
this.signer = signer;
|
|
101
|
+
this.scheme = "exact";
|
|
102
|
+
this.caipFamily = "eip155:*";
|
|
103
|
+
this.config = {
|
|
104
|
+
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get mechanism-specific extra data for the supported kinds endpoint.
|
|
109
|
+
* For EVM, no extra data is needed.
|
|
110
|
+
*
|
|
111
|
+
* @param _ - The network identifier (unused for EVM)
|
|
112
|
+
* @returns undefined (EVM has no extra data)
|
|
113
|
+
*/
|
|
114
|
+
getExtra(_) {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get signer addresses used by this facilitator.
|
|
119
|
+
* Returns all addresses this facilitator can use for signing/settling transactions.
|
|
120
|
+
*
|
|
121
|
+
* @param _ - The network identifier (unused for EVM, addresses are network-agnostic)
|
|
122
|
+
* @returns Array of facilitator wallet addresses
|
|
123
|
+
*/
|
|
124
|
+
getSigners(_) {
|
|
125
|
+
return [...this.signer.getAddresses()];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Verifies a payment payload.
|
|
129
|
+
*
|
|
130
|
+
* @param payload - The payment payload to verify
|
|
131
|
+
* @param requirements - The payment requirements
|
|
132
|
+
* @returns Promise resolving to verification response
|
|
133
|
+
*/
|
|
134
|
+
async verify(payload, requirements) {
|
|
135
|
+
const exactEvmPayload = payload.payload;
|
|
136
|
+
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
137
|
+
return {
|
|
138
|
+
isValid: false,
|
|
139
|
+
invalidReason: "unsupported_scheme",
|
|
140
|
+
payer: exactEvmPayload.authorization.from
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
144
|
+
return {
|
|
145
|
+
isValid: false,
|
|
146
|
+
invalidReason: "missing_eip712_domain",
|
|
147
|
+
payer: exactEvmPayload.authorization.from
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const { name, version } = requirements.extra;
|
|
151
|
+
const erc20Address = (0, import_viem.getAddress)(requirements.asset);
|
|
152
|
+
if (payload.accepted.network !== requirements.network) {
|
|
153
|
+
return {
|
|
154
|
+
isValid: false,
|
|
155
|
+
invalidReason: "network_mismatch",
|
|
156
|
+
payer: exactEvmPayload.authorization.from
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const permitTypedData = {
|
|
160
|
+
types: authorizationTypes,
|
|
161
|
+
primaryType: "TransferWithAuthorization",
|
|
162
|
+
domain: {
|
|
163
|
+
name,
|
|
164
|
+
version,
|
|
165
|
+
chainId: parseInt(requirements.network.split(":")[1]),
|
|
166
|
+
verifyingContract: erc20Address
|
|
167
|
+
},
|
|
168
|
+
message: {
|
|
169
|
+
from: exactEvmPayload.authorization.from,
|
|
170
|
+
to: exactEvmPayload.authorization.to,
|
|
171
|
+
value: BigInt(exactEvmPayload.authorization.value),
|
|
172
|
+
validAfter: BigInt(exactEvmPayload.authorization.validAfter),
|
|
173
|
+
validBefore: BigInt(exactEvmPayload.authorization.validBefore),
|
|
174
|
+
nonce: exactEvmPayload.authorization.nonce
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
try {
|
|
178
|
+
const recoveredAddress = await this.signer.verifyTypedData({
|
|
179
|
+
address: exactEvmPayload.authorization.from,
|
|
180
|
+
...permitTypedData,
|
|
181
|
+
signature: exactEvmPayload.signature
|
|
182
|
+
});
|
|
183
|
+
if (!recoveredAddress) {
|
|
184
|
+
return {
|
|
185
|
+
isValid: false,
|
|
186
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
187
|
+
payer: exactEvmPayload.authorization.from
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
const signature = exactEvmPayload.signature;
|
|
192
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
193
|
+
const isSmartWallet = signatureLength > 130;
|
|
194
|
+
if (isSmartWallet) {
|
|
195
|
+
const payerAddress = exactEvmPayload.authorization.from;
|
|
196
|
+
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
197
|
+
if (!bytecode || bytecode === "0x") {
|
|
198
|
+
const erc6492Data = (0, import_viem.parseErc6492Signature)(signature);
|
|
199
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
200
|
+
if (!hasDeploymentInfo) {
|
|
201
|
+
return {
|
|
202
|
+
isValid: false,
|
|
203
|
+
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
|
|
204
|
+
payer: payerAddress
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
return {
|
|
209
|
+
isValid: false,
|
|
210
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
211
|
+
payer: exactEvmPayload.authorization.from
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
return {
|
|
216
|
+
isValid: false,
|
|
217
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
218
|
+
payer: exactEvmPayload.authorization.from
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if ((0, import_viem.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem.getAddress)(requirements.payTo)) {
|
|
223
|
+
return {
|
|
224
|
+
isValid: false,
|
|
225
|
+
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
226
|
+
payer: exactEvmPayload.authorization.from
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
230
|
+
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
|
|
231
|
+
return {
|
|
232
|
+
isValid: false,
|
|
233
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
|
|
234
|
+
payer: exactEvmPayload.authorization.from
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
|
|
238
|
+
return {
|
|
239
|
+
isValid: false,
|
|
240
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
|
|
241
|
+
payer: exactEvmPayload.authorization.from
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const balance = await this.signer.readContract({
|
|
246
|
+
address: erc20Address,
|
|
247
|
+
abi: eip3009ABI,
|
|
248
|
+
functionName: "balanceOf",
|
|
249
|
+
args: [exactEvmPayload.authorization.from]
|
|
250
|
+
});
|
|
251
|
+
if (BigInt(balance) < BigInt(requirements.amount)) {
|
|
252
|
+
return {
|
|
253
|
+
isValid: false,
|
|
254
|
+
invalidReason: "insufficient_funds",
|
|
255
|
+
payer: exactEvmPayload.authorization.from
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
} catch {
|
|
259
|
+
}
|
|
260
|
+
if (BigInt(exactEvmPayload.authorization.value) < BigInt(requirements.amount)) {
|
|
261
|
+
return {
|
|
262
|
+
isValid: false,
|
|
263
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
264
|
+
payer: exactEvmPayload.authorization.from
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
isValid: true,
|
|
269
|
+
invalidReason: void 0,
|
|
270
|
+
payer: exactEvmPayload.authorization.from
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Settles a payment by executing the transfer.
|
|
275
|
+
*
|
|
276
|
+
* @param payload - The payment payload to settle
|
|
277
|
+
* @param requirements - The payment requirements
|
|
278
|
+
* @returns Promise resolving to settlement response
|
|
279
|
+
*/
|
|
280
|
+
async settle(payload, requirements) {
|
|
281
|
+
const exactEvmPayload = payload.payload;
|
|
282
|
+
const valid = await this.verify(payload, requirements);
|
|
283
|
+
if (!valid.isValid) {
|
|
284
|
+
return {
|
|
285
|
+
success: false,
|
|
286
|
+
network: payload.accepted.network,
|
|
287
|
+
transaction: "",
|
|
288
|
+
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
289
|
+
payer: exactEvmPayload.authorization.from
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const parseResult = (0, import_viem.parseErc6492Signature)(exactEvmPayload.signature);
|
|
294
|
+
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
295
|
+
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
296
|
+
const payerAddress = exactEvmPayload.authorization.from;
|
|
297
|
+
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
298
|
+
if (!bytecode || bytecode === "0x") {
|
|
299
|
+
try {
|
|
300
|
+
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
|
|
301
|
+
const deployTx = await this.signer.sendTransaction({
|
|
302
|
+
to: factoryAddress,
|
|
303
|
+
data: factoryCalldata
|
|
304
|
+
});
|
|
305
|
+
await this.signer.waitForTransactionReceipt({ hash: deployTx });
|
|
306
|
+
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
|
|
307
|
+
} catch (deployError) {
|
|
308
|
+
console.error("Smart wallet deployment failed:", deployError);
|
|
309
|
+
throw deployError;
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
316
|
+
const isECDSA = signatureLength === 130;
|
|
317
|
+
let tx;
|
|
318
|
+
if (isECDSA) {
|
|
319
|
+
const parsedSig = (0, import_viem.parseSignature)(signature);
|
|
320
|
+
tx = await this.signer.writeContract({
|
|
321
|
+
address: (0, import_viem.getAddress)(requirements.asset),
|
|
322
|
+
abi: eip3009ABI,
|
|
323
|
+
functionName: "transferWithAuthorization",
|
|
324
|
+
args: [
|
|
325
|
+
(0, import_viem.getAddress)(exactEvmPayload.authorization.from),
|
|
326
|
+
(0, import_viem.getAddress)(exactEvmPayload.authorization.to),
|
|
327
|
+
BigInt(exactEvmPayload.authorization.value),
|
|
328
|
+
BigInt(exactEvmPayload.authorization.validAfter),
|
|
329
|
+
BigInt(exactEvmPayload.authorization.validBefore),
|
|
330
|
+
exactEvmPayload.authorization.nonce,
|
|
331
|
+
parsedSig.v || parsedSig.yParity,
|
|
332
|
+
parsedSig.r,
|
|
333
|
+
parsedSig.s
|
|
334
|
+
]
|
|
335
|
+
});
|
|
336
|
+
} else {
|
|
337
|
+
tx = await this.signer.writeContract({
|
|
338
|
+
address: (0, import_viem.getAddress)(requirements.asset),
|
|
339
|
+
abi: eip3009ABI,
|
|
340
|
+
functionName: "transferWithAuthorization",
|
|
341
|
+
args: [
|
|
342
|
+
(0, import_viem.getAddress)(exactEvmPayload.authorization.from),
|
|
343
|
+
(0, import_viem.getAddress)(exactEvmPayload.authorization.to),
|
|
344
|
+
BigInt(exactEvmPayload.authorization.value),
|
|
345
|
+
BigInt(exactEvmPayload.authorization.validAfter),
|
|
346
|
+
BigInt(exactEvmPayload.authorization.validBefore),
|
|
347
|
+
exactEvmPayload.authorization.nonce,
|
|
348
|
+
signature
|
|
349
|
+
]
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
|
|
353
|
+
if (receipt.status !== "success") {
|
|
354
|
+
return {
|
|
355
|
+
success: false,
|
|
356
|
+
errorReason: "invalid_transaction_state",
|
|
357
|
+
transaction: tx,
|
|
358
|
+
network: payload.accepted.network,
|
|
359
|
+
payer: exactEvmPayload.authorization.from
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
success: true,
|
|
364
|
+
transaction: tx,
|
|
365
|
+
network: payload.accepted.network,
|
|
366
|
+
payer: exactEvmPayload.authorization.from
|
|
367
|
+
};
|
|
368
|
+
} catch (error) {
|
|
369
|
+
console.error("Failed to settle transaction:", error);
|
|
370
|
+
return {
|
|
371
|
+
success: false,
|
|
372
|
+
errorReason: "transaction_failed",
|
|
373
|
+
transaction: "",
|
|
374
|
+
network: payload.accepted.network,
|
|
375
|
+
payer: exactEvmPayload.authorization.from
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/exact/v1/facilitator/scheme.ts
|
|
382
|
+
var import_viem3 = require("viem");
|
|
383
|
+
|
|
384
|
+
// src/utils.ts
|
|
385
|
+
var import_viem2 = require("viem");
|
|
386
|
+
function getEvmChainId(network) {
|
|
387
|
+
const networkMap = {
|
|
388
|
+
base: 8453,
|
|
389
|
+
"base-sepolia": 84532,
|
|
390
|
+
ethereum: 1,
|
|
391
|
+
sepolia: 11155111,
|
|
392
|
+
polygon: 137,
|
|
393
|
+
"polygon-amoy": 80002
|
|
394
|
+
};
|
|
395
|
+
return networkMap[network] || 1;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/exact/v1/facilitator/scheme.ts
|
|
399
|
+
var ExactEvmSchemeV1 = class {
|
|
400
|
+
/**
|
|
401
|
+
* Creates a new ExactEvmFacilitatorV1 instance.
|
|
402
|
+
*
|
|
403
|
+
* @param signer - The EVM signer for facilitator operations
|
|
404
|
+
* @param config - Optional configuration for the facilitator
|
|
405
|
+
*/
|
|
406
|
+
constructor(signer, config) {
|
|
407
|
+
this.signer = signer;
|
|
408
|
+
this.scheme = "exact";
|
|
409
|
+
this.caipFamily = "eip155:*";
|
|
410
|
+
this.config = {
|
|
411
|
+
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Get mechanism-specific extra data for the supported kinds endpoint.
|
|
416
|
+
* For EVM, no extra data is needed.
|
|
417
|
+
*
|
|
418
|
+
* @param _ - The network identifier (unused for EVM)
|
|
419
|
+
* @returns undefined (EVM has no extra data)
|
|
420
|
+
*/
|
|
421
|
+
getExtra(_) {
|
|
422
|
+
return void 0;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Get signer addresses used by this facilitator.
|
|
426
|
+
* Returns all addresses this facilitator can use for signing/settling transactions.
|
|
427
|
+
*
|
|
428
|
+
* @param _ - The network identifier (unused for EVM, addresses are network-agnostic)
|
|
429
|
+
* @returns Array of facilitator wallet addresses
|
|
430
|
+
*/
|
|
431
|
+
getSigners(_) {
|
|
432
|
+
return [...this.signer.getAddresses()];
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Verifies a payment payload (V1).
|
|
436
|
+
*
|
|
437
|
+
* @param payload - The payment payload to verify
|
|
438
|
+
* @param requirements - The payment requirements
|
|
439
|
+
* @returns Promise resolving to verification response
|
|
440
|
+
*/
|
|
441
|
+
async verify(payload, requirements) {
|
|
442
|
+
const requirementsV1 = requirements;
|
|
443
|
+
const payloadV1 = payload;
|
|
444
|
+
const exactEvmPayload = payload.payload;
|
|
445
|
+
if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
|
|
446
|
+
return {
|
|
447
|
+
isValid: false,
|
|
448
|
+
invalidReason: "unsupported_scheme",
|
|
449
|
+
payer: exactEvmPayload.authorization.from
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
const chainId = getEvmChainId(payloadV1.network);
|
|
453
|
+
if (!requirements.extra?.name || !requirements.extra?.version) {
|
|
454
|
+
return {
|
|
455
|
+
isValid: false,
|
|
456
|
+
invalidReason: "missing_eip712_domain",
|
|
457
|
+
payer: exactEvmPayload.authorization.from
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
const { name, version } = requirements.extra;
|
|
461
|
+
const erc20Address = (0, import_viem3.getAddress)(requirements.asset);
|
|
462
|
+
if (payloadV1.network !== requirements.network) {
|
|
463
|
+
return {
|
|
464
|
+
isValid: false,
|
|
465
|
+
invalidReason: "network_mismatch",
|
|
466
|
+
payer: exactEvmPayload.authorization.from
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
const permitTypedData = {
|
|
470
|
+
types: authorizationTypes,
|
|
471
|
+
primaryType: "TransferWithAuthorization",
|
|
472
|
+
domain: {
|
|
473
|
+
name,
|
|
474
|
+
version,
|
|
475
|
+
chainId,
|
|
476
|
+
verifyingContract: erc20Address
|
|
477
|
+
},
|
|
478
|
+
message: {
|
|
479
|
+
from: exactEvmPayload.authorization.from,
|
|
480
|
+
to: exactEvmPayload.authorization.to,
|
|
481
|
+
value: BigInt(exactEvmPayload.authorization.value),
|
|
482
|
+
validAfter: BigInt(exactEvmPayload.authorization.validAfter),
|
|
483
|
+
validBefore: BigInt(exactEvmPayload.authorization.validBefore),
|
|
484
|
+
nonce: exactEvmPayload.authorization.nonce
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
try {
|
|
488
|
+
const recoveredAddress = await this.signer.verifyTypedData({
|
|
489
|
+
address: exactEvmPayload.authorization.from,
|
|
490
|
+
...permitTypedData,
|
|
491
|
+
signature: exactEvmPayload.signature
|
|
492
|
+
});
|
|
493
|
+
if (!recoveredAddress) {
|
|
494
|
+
return {
|
|
495
|
+
isValid: false,
|
|
496
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
497
|
+
payer: exactEvmPayload.authorization.from
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
} catch {
|
|
501
|
+
const signature = exactEvmPayload.signature;
|
|
502
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
503
|
+
const isSmartWallet = signatureLength > 130;
|
|
504
|
+
if (isSmartWallet) {
|
|
505
|
+
const payerAddress = exactEvmPayload.authorization.from;
|
|
506
|
+
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
507
|
+
if (!bytecode || bytecode === "0x") {
|
|
508
|
+
const erc6492Data = (0, import_viem3.parseErc6492Signature)(signature);
|
|
509
|
+
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem3.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
|
|
510
|
+
if (!hasDeploymentInfo) {
|
|
511
|
+
return {
|
|
512
|
+
isValid: false,
|
|
513
|
+
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
|
|
514
|
+
payer: payerAddress
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
} else {
|
|
518
|
+
return {
|
|
519
|
+
isValid: false,
|
|
520
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
521
|
+
payer: exactEvmPayload.authorization.from
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
return {
|
|
526
|
+
isValid: false,
|
|
527
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
528
|
+
payer: exactEvmPayload.authorization.from
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if ((0, import_viem3.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem3.getAddress)(requirements.payTo)) {
|
|
533
|
+
return {
|
|
534
|
+
isValid: false,
|
|
535
|
+
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
536
|
+
payer: exactEvmPayload.authorization.from
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
540
|
+
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
|
|
541
|
+
return {
|
|
542
|
+
isValid: false,
|
|
543
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
|
|
544
|
+
payer: exactEvmPayload.authorization.from
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
|
|
548
|
+
return {
|
|
549
|
+
isValid: false,
|
|
550
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
|
|
551
|
+
payer: exactEvmPayload.authorization.from
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
try {
|
|
555
|
+
const balance = await this.signer.readContract({
|
|
556
|
+
address: erc20Address,
|
|
557
|
+
abi: eip3009ABI,
|
|
558
|
+
functionName: "balanceOf",
|
|
559
|
+
args: [exactEvmPayload.authorization.from]
|
|
560
|
+
});
|
|
561
|
+
if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {
|
|
562
|
+
return {
|
|
563
|
+
isValid: false,
|
|
564
|
+
invalidReason: "insufficient_funds",
|
|
565
|
+
payer: exactEvmPayload.authorization.from
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
} catch {
|
|
569
|
+
}
|
|
570
|
+
if (BigInt(exactEvmPayload.authorization.value) < BigInt(requirementsV1.maxAmountRequired)) {
|
|
571
|
+
return {
|
|
572
|
+
isValid: false,
|
|
573
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
574
|
+
payer: exactEvmPayload.authorization.from
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
isValid: true,
|
|
579
|
+
invalidReason: void 0,
|
|
580
|
+
payer: exactEvmPayload.authorization.from
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Settles a payment by executing the transfer (V1).
|
|
585
|
+
*
|
|
586
|
+
* @param payload - The payment payload to settle
|
|
587
|
+
* @param requirements - The payment requirements
|
|
588
|
+
* @returns Promise resolving to settlement response
|
|
589
|
+
*/
|
|
590
|
+
async settle(payload, requirements) {
|
|
591
|
+
const payloadV1 = payload;
|
|
592
|
+
const exactEvmPayload = payload.payload;
|
|
593
|
+
const valid = await this.verify(payload, requirements);
|
|
594
|
+
if (!valid.isValid) {
|
|
595
|
+
return {
|
|
596
|
+
success: false,
|
|
597
|
+
network: payloadV1.network,
|
|
598
|
+
transaction: "",
|
|
599
|
+
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
600
|
+
payer: exactEvmPayload.authorization.from
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
const parseResult = (0, import_viem3.parseErc6492Signature)(exactEvmPayload.signature);
|
|
605
|
+
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
|
|
606
|
+
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem3.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
|
|
607
|
+
const payerAddress = exactEvmPayload.authorization.from;
|
|
608
|
+
const bytecode = await this.signer.getCode({ address: payerAddress });
|
|
609
|
+
if (!bytecode || bytecode === "0x") {
|
|
610
|
+
try {
|
|
611
|
+
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
|
|
612
|
+
const deployTx = await this.signer.sendTransaction({
|
|
613
|
+
to: factoryAddress,
|
|
614
|
+
data: factoryCalldata
|
|
615
|
+
});
|
|
616
|
+
await this.signer.waitForTransactionReceipt({ hash: deployTx });
|
|
617
|
+
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
|
|
618
|
+
} catch (deployError) {
|
|
619
|
+
console.error("Smart wallet deployment failed:", deployError);
|
|
620
|
+
throw deployError;
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
|
|
627
|
+
const isECDSA = signatureLength === 130;
|
|
628
|
+
let tx;
|
|
629
|
+
if (isECDSA) {
|
|
630
|
+
const parsedSig = (0, import_viem3.parseSignature)(signature);
|
|
631
|
+
tx = await this.signer.writeContract({
|
|
632
|
+
address: (0, import_viem3.getAddress)(requirements.asset),
|
|
633
|
+
abi: eip3009ABI,
|
|
634
|
+
functionName: "transferWithAuthorization",
|
|
635
|
+
args: [
|
|
636
|
+
(0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
|
|
637
|
+
(0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
|
|
638
|
+
BigInt(exactEvmPayload.authorization.value),
|
|
639
|
+
BigInt(exactEvmPayload.authorization.validAfter),
|
|
640
|
+
BigInt(exactEvmPayload.authorization.validBefore),
|
|
641
|
+
exactEvmPayload.authorization.nonce,
|
|
642
|
+
parsedSig.v || parsedSig.yParity,
|
|
643
|
+
parsedSig.r,
|
|
644
|
+
parsedSig.s
|
|
645
|
+
]
|
|
646
|
+
});
|
|
647
|
+
} else {
|
|
648
|
+
tx = await this.signer.writeContract({
|
|
649
|
+
address: (0, import_viem3.getAddress)(requirements.asset),
|
|
650
|
+
abi: eip3009ABI,
|
|
651
|
+
functionName: "transferWithAuthorization",
|
|
652
|
+
args: [
|
|
653
|
+
(0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
|
|
654
|
+
(0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
|
|
655
|
+
BigInt(exactEvmPayload.authorization.value),
|
|
656
|
+
BigInt(exactEvmPayload.authorization.validAfter),
|
|
657
|
+
BigInt(exactEvmPayload.authorization.validBefore),
|
|
658
|
+
exactEvmPayload.authorization.nonce,
|
|
659
|
+
signature
|
|
660
|
+
]
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
|
|
664
|
+
if (receipt.status !== "success") {
|
|
665
|
+
return {
|
|
666
|
+
success: false,
|
|
667
|
+
errorReason: "invalid_transaction_state",
|
|
668
|
+
transaction: tx,
|
|
669
|
+
network: payloadV1.network,
|
|
670
|
+
payer: exactEvmPayload.authorization.from
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
success: true,
|
|
675
|
+
transaction: tx,
|
|
676
|
+
network: payloadV1.network,
|
|
677
|
+
payer: exactEvmPayload.authorization.from
|
|
678
|
+
};
|
|
679
|
+
} catch (error) {
|
|
680
|
+
console.error("Failed to settle transaction:", error);
|
|
681
|
+
return {
|
|
682
|
+
success: false,
|
|
683
|
+
errorReason: "transaction_failed",
|
|
684
|
+
transaction: "",
|
|
685
|
+
network: payloadV1.network,
|
|
686
|
+
payer: exactEvmPayload.authorization.from
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
// src/exact/v1/client/scheme.ts
|
|
693
|
+
var import_viem4 = require("viem");
|
|
694
|
+
|
|
695
|
+
// src/v1/index.ts
|
|
696
|
+
var NETWORKS = [
|
|
697
|
+
"abstract",
|
|
698
|
+
"abstract-testnet",
|
|
699
|
+
"base-sepolia",
|
|
700
|
+
"base",
|
|
701
|
+
"avalanche-fuji",
|
|
702
|
+
"avalanche",
|
|
703
|
+
"iotex",
|
|
704
|
+
"sei",
|
|
705
|
+
"sei-testnet",
|
|
706
|
+
"polygon",
|
|
707
|
+
"polygon-amoy",
|
|
708
|
+
"peaq",
|
|
709
|
+
"story",
|
|
710
|
+
"educhain",
|
|
711
|
+
"skale-base-sepolia"
|
|
712
|
+
];
|
|
713
|
+
|
|
714
|
+
// src/exact/facilitator/register.ts
|
|
715
|
+
function registerExactEvmScheme(facilitator, config) {
|
|
716
|
+
facilitator.register(
|
|
717
|
+
config.networks,
|
|
718
|
+
new ExactEvmScheme(config.signer, {
|
|
719
|
+
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
|
|
720
|
+
})
|
|
721
|
+
);
|
|
722
|
+
facilitator.registerV1(
|
|
723
|
+
NETWORKS,
|
|
724
|
+
new ExactEvmSchemeV1(config.signer, {
|
|
725
|
+
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
|
|
726
|
+
})
|
|
727
|
+
);
|
|
728
|
+
return facilitator;
|
|
729
|
+
}
|
|
730
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
731
|
+
0 && (module.exports = {
|
|
732
|
+
ExactEvmScheme,
|
|
733
|
+
registerExactEvmScheme
|
|
734
|
+
});
|
|
735
|
+
//# sourceMappingURL=index.js.map
|