@wtflabs/x402 0.0.1-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 +60 -0
- package/dist/cjs/client/index.d.ts +64 -0
- package/dist/cjs/client/index.js +832 -0
- package/dist/cjs/client/index.js.map +1 -0
- package/dist/cjs/config-CFBSAuxW.d.ts +10 -0
- package/dist/cjs/config-Dfuvno71.d.ts +19 -0
- package/dist/cjs/facilitator/index.d.ts +42 -0
- package/dist/cjs/facilitator/index.js +2574 -0
- package/dist/cjs/facilitator/index.js.map +1 -0
- package/dist/cjs/index.d.ts +16 -0
- package/dist/cjs/index.js +2974 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/middleware-6_1ApcJn.d.ts +93 -0
- package/dist/cjs/middleware-B_ewwsQp.d.ts +93 -0
- package/dist/cjs/middleware-Brgsx32F.d.ts +93 -0
- package/dist/cjs/middleware-BwfW7mAs.d.ts +93 -0
- package/dist/cjs/middleware-CQb61c1k.d.ts +93 -0
- package/dist/cjs/middleware-DB9lqy9f.d.ts +93 -0
- package/dist/cjs/middleware-DcHctwQV.d.ts +93 -0
- package/dist/cjs/middleware-De0jD3Bp.d.ts +93 -0
- package/dist/cjs/middleware-HoFOmpgv.d.ts +93 -0
- package/dist/cjs/middleware-Y8AiAfYw.d.ts +93 -0
- package/dist/cjs/middleware-pnres9YM.d.ts +93 -0
- package/dist/cjs/network-FrFmmiyj.d.ts +11 -0
- package/dist/cjs/network-RtNddYQk.d.ts +11 -0
- package/dist/cjs/paywall/index.d.ts +30 -0
- package/dist/cjs/paywall/index.js +131 -0
- package/dist/cjs/paywall/index.js.map +1 -0
- package/dist/cjs/rpc-BMvnNNHd.d.ts +35 -0
- package/dist/cjs/rpc-Ca8eHCWz.d.ts +35 -0
- package/dist/cjs/schemes/index.d.ts +533 -0
- package/dist/cjs/schemes/index.js +3144 -0
- package/dist/cjs/schemes/index.js.map +1 -0
- package/dist/cjs/shared/evm/index.d.ts +71 -0
- package/dist/cjs/shared/evm/index.js +947 -0
- package/dist/cjs/shared/evm/index.js.map +1 -0
- package/dist/cjs/shared/index.d.ts +182 -0
- package/dist/cjs/shared/index.js +674 -0
- package/dist/cjs/shared/index.js.map +1 -0
- package/dist/cjs/types/index.d.ts +1515 -0
- package/dist/cjs/types/index.js +1645 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/verify/index.d.ts +7 -0
- package/dist/cjs/verify/index.js +438 -0
- package/dist/cjs/verify/index.js.map +1 -0
- package/dist/cjs/wallet-BRWfOM5D.d.ts +153 -0
- package/dist/cjs/wallet-BTqCm9Zp.d.ts +27 -0
- package/dist/cjs/wallet-BYRAGtOB.d.ts +153 -0
- package/dist/cjs/wallet-BmEtlgEf.d.ts +48 -0
- package/dist/cjs/wallet-CNOAmyZ6.d.ts +48 -0
- package/dist/cjs/wallet-CQ0Fe_M5.d.ts +88 -0
- package/dist/cjs/wallet-D1SoxFTw.d.ts +48 -0
- package/dist/cjs/wallet-SJ-hbjm9.d.ts +153 -0
- package/dist/cjs/wallet-SJKJpUgQ.d.ts +167 -0
- package/dist/cjs/wallet-ecnda4Aj.d.ts +48 -0
- package/dist/cjs/wallet-gP8Qoi-c.d.ts +74 -0
- package/dist/cjs/x402Specs-B7InXo2L.d.ts +1065 -0
- package/dist/cjs/x402Specs-BLH3j34O.d.ts +1696 -0
- package/dist/cjs/x402Specs-C7LipAZg.d.ts +1715 -0
- package/dist/cjs/x402Specs-CYq5tSY1.d.ts +1745 -0
- package/dist/cjs/x402Specs-CeajqonG.d.ts +1696 -0
- package/dist/cjs/x402Specs-qMujgEV5.d.ts +1715 -0
- package/dist/cjs/x402Specs-qUBCpcuz.d.ts +1715 -0
- package/dist/esm/chunk-34YNR4LY.mjs +106 -0
- package/dist/esm/chunk-34YNR4LY.mjs.map +1 -0
- package/dist/esm/chunk-57UEJN5U.mjs +1416 -0
- package/dist/esm/chunk-57UEJN5U.mjs.map +1 -0
- package/dist/esm/chunk-5LTKIVOA.mjs +858 -0
- package/dist/esm/chunk-5LTKIVOA.mjs.map +1 -0
- package/dist/esm/chunk-AQQR4PXH.mjs +80 -0
- package/dist/esm/chunk-AQQR4PXH.mjs.map +1 -0
- package/dist/esm/chunk-LGXWNXCO.mjs +76 -0
- package/dist/esm/chunk-LGXWNXCO.mjs.map +1 -0
- package/dist/esm/chunk-RX2JKK4O.mjs +349 -0
- package/dist/esm/chunk-RX2JKK4O.mjs.map +1 -0
- package/dist/esm/chunk-UCBE7FDY.mjs +1041 -0
- package/dist/esm/chunk-UCBE7FDY.mjs.map +1 -0
- package/dist/esm/client/index.mjs +17 -0
- package/dist/esm/client/index.mjs.map +1 -0
- package/dist/esm/facilitator/index.mjs +14 -0
- package/dist/esm/facilitator/index.mjs.map +1 -0
- package/dist/esm/index.mjs +28 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/paywall/index.mjs +46 -0
- package/dist/esm/paywall/index.mjs.map +1 -0
- package/dist/esm/schemes/index.mjs +16 -0
- package/dist/esm/schemes/index.mjs.map +1 -0
- package/dist/esm/shared/evm/index.mjs +20 -0
- package/dist/esm/shared/evm/index.mjs.map +1 -0
- package/dist/esm/shared/index.mjs +31 -0
- package/dist/esm/shared/index.mjs.map +1 -0
- package/dist/esm/types/index.mjs +87 -0
- package/dist/esm/types/index.mjs.map +1 -0
- package/dist/esm/verify/index.mjs +105 -0
- package/dist/esm/verify/index.mjs.map +1 -0
- package/package.json +148 -0
|
@@ -0,0 +1,1416 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAndSignPayment,
|
|
3
|
+
createNonce,
|
|
4
|
+
createPayment,
|
|
5
|
+
createPaymentHeader,
|
|
6
|
+
createPaymentHeader2,
|
|
7
|
+
decodePayment,
|
|
8
|
+
encodePayment,
|
|
9
|
+
preparePaymentHeader,
|
|
10
|
+
signAuthorization,
|
|
11
|
+
signPaymentHeader
|
|
12
|
+
} from "./chunk-RX2JKK4O.mjs";
|
|
13
|
+
import {
|
|
14
|
+
ErrorReasons,
|
|
15
|
+
PERMIT2_ADDRESS,
|
|
16
|
+
SupportedSVMNetworks,
|
|
17
|
+
authorizationTypes,
|
|
18
|
+
decodeTransactionFromPayload,
|
|
19
|
+
erc20PermitABI,
|
|
20
|
+
getNetworkId,
|
|
21
|
+
getRpcClient,
|
|
22
|
+
getRpcSubscriptions,
|
|
23
|
+
getTokenPayerFromTransaction,
|
|
24
|
+
isSignerWallet,
|
|
25
|
+
permit2ABI,
|
|
26
|
+
permit2Types,
|
|
27
|
+
permitTypes,
|
|
28
|
+
signAndSimulateTransaction
|
|
29
|
+
} from "./chunk-UCBE7FDY.mjs";
|
|
30
|
+
import {
|
|
31
|
+
getERC20Allowance,
|
|
32
|
+
getERC20Balance,
|
|
33
|
+
getVersion,
|
|
34
|
+
usdcABI
|
|
35
|
+
} from "./chunk-5LTKIVOA.mjs";
|
|
36
|
+
import {
|
|
37
|
+
__export,
|
|
38
|
+
config
|
|
39
|
+
} from "./chunk-AQQR4PXH.mjs";
|
|
40
|
+
|
|
41
|
+
// src/schemes/exact/index.ts
|
|
42
|
+
var exact_exports = {};
|
|
43
|
+
__export(exact_exports, {
|
|
44
|
+
SCHEME: () => SCHEME,
|
|
45
|
+
evm: () => evm_exports,
|
|
46
|
+
svm: () => svm_exports
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// src/schemes/exact/evm/index.ts
|
|
50
|
+
var evm_exports = {};
|
|
51
|
+
__export(evm_exports, {
|
|
52
|
+
decodePayment: () => decodePayment,
|
|
53
|
+
eip3009: () => eip3009_exports,
|
|
54
|
+
encodePayment: () => encodePayment,
|
|
55
|
+
permit: () => permit_exports,
|
|
56
|
+
permit2: () => permit2_exports,
|
|
57
|
+
settle: () => settle4,
|
|
58
|
+
verify: () => verify4
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// src/schemes/exact/evm/eip3009/facilitator.ts
|
|
62
|
+
import { getAddress, parseErc6492Signature } from "viem";
|
|
63
|
+
async function verify(client, payload, paymentRequirements) {
|
|
64
|
+
const exactEvmPayload = payload.payload;
|
|
65
|
+
if (exactEvmPayload.authorizationType !== "eip3009") {
|
|
66
|
+
return {
|
|
67
|
+
isValid: false,
|
|
68
|
+
invalidReason: "unsupported_authorization_type",
|
|
69
|
+
payer: ""
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (payload.scheme !== SCHEME || paymentRequirements.scheme !== SCHEME) {
|
|
73
|
+
return {
|
|
74
|
+
isValid: false,
|
|
75
|
+
invalidReason: `unsupported_scheme`,
|
|
76
|
+
payer: exactEvmPayload.authorization.from
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
let name;
|
|
80
|
+
let chainId;
|
|
81
|
+
let erc20Address;
|
|
82
|
+
let version;
|
|
83
|
+
try {
|
|
84
|
+
chainId = getNetworkId(payload.network);
|
|
85
|
+
name = paymentRequirements.extra?.name ?? config[chainId.toString()].usdcName;
|
|
86
|
+
erc20Address = paymentRequirements.asset;
|
|
87
|
+
version = paymentRequirements.extra?.version ?? await getVersion(client, erc20Address);
|
|
88
|
+
} catch {
|
|
89
|
+
return {
|
|
90
|
+
isValid: false,
|
|
91
|
+
invalidReason: `invalid_network`,
|
|
92
|
+
payer: exactEvmPayload.authorization.from
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const permitTypedData = {
|
|
96
|
+
types: authorizationTypes,
|
|
97
|
+
primaryType: "TransferWithAuthorization",
|
|
98
|
+
domain: {
|
|
99
|
+
name,
|
|
100
|
+
version,
|
|
101
|
+
chainId,
|
|
102
|
+
verifyingContract: erc20Address
|
|
103
|
+
},
|
|
104
|
+
message: {
|
|
105
|
+
from: exactEvmPayload.authorization.from,
|
|
106
|
+
to: exactEvmPayload.authorization.to,
|
|
107
|
+
value: exactEvmPayload.authorization.value,
|
|
108
|
+
validAfter: exactEvmPayload.authorization.validAfter,
|
|
109
|
+
validBefore: exactEvmPayload.authorization.validBefore,
|
|
110
|
+
nonce: exactEvmPayload.authorization.nonce
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const recoveredAddress = await client.verifyTypedData({
|
|
114
|
+
address: exactEvmPayload.authorization.from,
|
|
115
|
+
...permitTypedData,
|
|
116
|
+
signature: exactEvmPayload.signature
|
|
117
|
+
});
|
|
118
|
+
if (!recoveredAddress) {
|
|
119
|
+
return {
|
|
120
|
+
isValid: false,
|
|
121
|
+
invalidReason: "invalid_exact_evm_payload_signature",
|
|
122
|
+
//"Invalid permit signature",
|
|
123
|
+
payer: exactEvmPayload.authorization.from
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (getAddress(exactEvmPayload.authorization.to) !== getAddress(paymentRequirements.payTo)) {
|
|
127
|
+
return {
|
|
128
|
+
isValid: false,
|
|
129
|
+
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
|
|
130
|
+
payer: exactEvmPayload.authorization.from
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(Math.floor(Date.now() / 1e3) + 6)) {
|
|
134
|
+
return {
|
|
135
|
+
isValid: false,
|
|
136
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
|
|
137
|
+
//"Deadline on permit isn't far enough in the future",
|
|
138
|
+
payer: exactEvmPayload.authorization.from
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(Math.floor(Date.now() / 1e3))) {
|
|
142
|
+
return {
|
|
143
|
+
isValid: false,
|
|
144
|
+
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
|
|
145
|
+
//"Deadline on permit is in the future",
|
|
146
|
+
payer: exactEvmPayload.authorization.from
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const balance = await getERC20Balance(
|
|
150
|
+
client,
|
|
151
|
+
erc20Address,
|
|
152
|
+
exactEvmPayload.authorization.from
|
|
153
|
+
);
|
|
154
|
+
if (balance < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
155
|
+
return {
|
|
156
|
+
isValid: false,
|
|
157
|
+
invalidReason: "insufficient_funds",
|
|
158
|
+
//"Client does not have enough funds",
|
|
159
|
+
payer: exactEvmPayload.authorization.from
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (BigInt(exactEvmPayload.authorization.value) < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
163
|
+
return {
|
|
164
|
+
isValid: false,
|
|
165
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
166
|
+
//"Value in payload is not enough to cover paymentRequirements.maxAmountRequired",
|
|
167
|
+
payer: exactEvmPayload.authorization.from
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
isValid: true,
|
|
172
|
+
invalidReason: void 0,
|
|
173
|
+
payer: exactEvmPayload.authorization.from
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async function settle(wallet, paymentPayload, paymentRequirements) {
|
|
177
|
+
const payload = paymentPayload.payload;
|
|
178
|
+
if (payload.authorizationType !== "eip3009") {
|
|
179
|
+
return {
|
|
180
|
+
success: false,
|
|
181
|
+
errorReason: "unsupported_authorization_type",
|
|
182
|
+
transaction: "",
|
|
183
|
+
network: paymentPayload.network,
|
|
184
|
+
payer: ""
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const valid = await verify(wallet, paymentPayload, paymentRequirements);
|
|
188
|
+
if (!valid.isValid) {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
network: paymentPayload.network,
|
|
192
|
+
transaction: "",
|
|
193
|
+
errorReason: valid.invalidReason ?? "invalid_scheme",
|
|
194
|
+
//`Payment is no longer valid: ${valid.invalidReason}`,
|
|
195
|
+
payer: payload.authorization.from
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const { signature } = parseErc6492Signature(payload.signature);
|
|
199
|
+
const tx = await wallet.writeContract({
|
|
200
|
+
address: paymentRequirements.asset,
|
|
201
|
+
abi: usdcABI,
|
|
202
|
+
functionName: "transferWithAuthorization",
|
|
203
|
+
args: [
|
|
204
|
+
payload.authorization.from,
|
|
205
|
+
payload.authorization.to,
|
|
206
|
+
BigInt(payload.authorization.value),
|
|
207
|
+
BigInt(payload.authorization.validAfter),
|
|
208
|
+
BigInt(payload.authorization.validBefore),
|
|
209
|
+
payload.authorization.nonce,
|
|
210
|
+
signature
|
|
211
|
+
],
|
|
212
|
+
chain: wallet.chain
|
|
213
|
+
});
|
|
214
|
+
const receipt = await wallet.waitForTransactionReceipt({ hash: tx });
|
|
215
|
+
if (receipt.status !== "success") {
|
|
216
|
+
return {
|
|
217
|
+
success: false,
|
|
218
|
+
errorReason: "invalid_transaction_state",
|
|
219
|
+
//`Transaction failed`,
|
|
220
|
+
transaction: tx,
|
|
221
|
+
network: paymentPayload.network,
|
|
222
|
+
payer: payload.authorization.from
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
success: true,
|
|
227
|
+
transaction: tx,
|
|
228
|
+
network: paymentPayload.network,
|
|
229
|
+
payer: payload.authorization.from
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/schemes/exact/evm/permit/facilitator.ts
|
|
234
|
+
import { getAddress as getAddress3 } from "viem";
|
|
235
|
+
|
|
236
|
+
// src/schemes/exact/evm/permit/sign.ts
|
|
237
|
+
import { getAddress as getAddress2 } from "viem";
|
|
238
|
+
async function signPermit(walletClient, { owner, spender, value, deadline }, { asset, network }) {
|
|
239
|
+
const chainId = getNetworkId(network);
|
|
240
|
+
const tokenAddress = getAddress2(asset);
|
|
241
|
+
let nonce;
|
|
242
|
+
let name;
|
|
243
|
+
let version;
|
|
244
|
+
if (isSignerWallet(walletClient)) {
|
|
245
|
+
[nonce, name, version] = await Promise.all([
|
|
246
|
+
walletClient.readContract({
|
|
247
|
+
address: tokenAddress,
|
|
248
|
+
abi: erc20PermitABI,
|
|
249
|
+
functionName: "nonces",
|
|
250
|
+
args: [getAddress2(owner)]
|
|
251
|
+
}),
|
|
252
|
+
walletClient.readContract({
|
|
253
|
+
address: tokenAddress,
|
|
254
|
+
abi: erc20PermitABI,
|
|
255
|
+
functionName: "name"
|
|
256
|
+
}),
|
|
257
|
+
walletClient.readContract({
|
|
258
|
+
address: tokenAddress,
|
|
259
|
+
abi: erc20PermitABI,
|
|
260
|
+
functionName: "version"
|
|
261
|
+
})
|
|
262
|
+
]);
|
|
263
|
+
} else {
|
|
264
|
+
throw new Error("Local account signing for permit requires a connected client");
|
|
265
|
+
}
|
|
266
|
+
const data = {
|
|
267
|
+
types: permitTypes,
|
|
268
|
+
domain: {
|
|
269
|
+
name,
|
|
270
|
+
version,
|
|
271
|
+
chainId,
|
|
272
|
+
verifyingContract: tokenAddress
|
|
273
|
+
},
|
|
274
|
+
primaryType: "Permit",
|
|
275
|
+
message: {
|
|
276
|
+
owner: getAddress2(owner),
|
|
277
|
+
spender: getAddress2(spender),
|
|
278
|
+
value,
|
|
279
|
+
nonce,
|
|
280
|
+
deadline
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
if (isSignerWallet(walletClient)) {
|
|
284
|
+
const signature = await walletClient.signTypedData(data);
|
|
285
|
+
return {
|
|
286
|
+
signature,
|
|
287
|
+
nonce: nonce.toString()
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const account = walletClient;
|
|
291
|
+
if (account.signTypedData) {
|
|
292
|
+
const signature = await account.signTypedData(data);
|
|
293
|
+
return {
|
|
294
|
+
signature,
|
|
295
|
+
nonce: nonce.toString()
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
throw new Error("Invalid wallet client provided does not support signTypedData");
|
|
299
|
+
}
|
|
300
|
+
function splitSignature(signature) {
|
|
301
|
+
const sig = signature.slice(2);
|
|
302
|
+
const r = `0x${sig.slice(0, 64)}`;
|
|
303
|
+
const s = `0x${sig.slice(64, 128)}`;
|
|
304
|
+
let v = parseInt(sig.slice(128, 130), 16);
|
|
305
|
+
if (v < 27) {
|
|
306
|
+
v += 27;
|
|
307
|
+
}
|
|
308
|
+
return { v, r, s };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/types/shared/evm/permitProxyABI.ts
|
|
312
|
+
var permitProxyContractABI = [
|
|
313
|
+
{
|
|
314
|
+
inputs: [
|
|
315
|
+
{
|
|
316
|
+
internalType: "address",
|
|
317
|
+
name: "token",
|
|
318
|
+
type: "address"
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
internalType: "address",
|
|
322
|
+
name: "owner",
|
|
323
|
+
type: "address"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
internalType: "address",
|
|
327
|
+
name: "spender",
|
|
328
|
+
type: "address"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
internalType: "uint256",
|
|
332
|
+
name: "value",
|
|
333
|
+
type: "uint256"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
internalType: "uint256",
|
|
337
|
+
name: "deadline",
|
|
338
|
+
type: "uint256"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
internalType: "uint8",
|
|
342
|
+
name: "v",
|
|
343
|
+
type: "uint8"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
internalType: "bytes32",
|
|
347
|
+
name: "r",
|
|
348
|
+
type: "bytes32"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
internalType: "bytes32",
|
|
352
|
+
name: "s",
|
|
353
|
+
type: "bytes32"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
internalType: "address",
|
|
357
|
+
name: "to",
|
|
358
|
+
type: "address"
|
|
359
|
+
}
|
|
360
|
+
],
|
|
361
|
+
name: "permitAndTransfer",
|
|
362
|
+
outputs: [],
|
|
363
|
+
stateMutability: "nonpayable",
|
|
364
|
+
type: "function"
|
|
365
|
+
}
|
|
366
|
+
];
|
|
367
|
+
|
|
368
|
+
// src/schemes/exact/evm/permit/facilitator.ts
|
|
369
|
+
async function verify2(client, payload, paymentRequirements) {
|
|
370
|
+
if (payload.payload.authorizationType !== "permit" || payload.scheme !== SCHEME || paymentRequirements.scheme !== SCHEME) {
|
|
371
|
+
return {
|
|
372
|
+
isValid: false,
|
|
373
|
+
invalidReason: "unsupported_scheme"
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const permitPayload = payload.payload;
|
|
377
|
+
const { owner, spender, value, deadline, nonce } = permitPayload.authorization;
|
|
378
|
+
let name;
|
|
379
|
+
let version;
|
|
380
|
+
let erc20Address;
|
|
381
|
+
let chainId;
|
|
382
|
+
try {
|
|
383
|
+
chainId = getNetworkId(payload.network);
|
|
384
|
+
erc20Address = paymentRequirements.asset;
|
|
385
|
+
name = paymentRequirements.extra?.name ?? await client.readContract({
|
|
386
|
+
address: erc20Address,
|
|
387
|
+
abi: erc20PermitABI,
|
|
388
|
+
functionName: "name"
|
|
389
|
+
});
|
|
390
|
+
version = paymentRequirements.extra?.version ?? await getVersion(client, erc20Address);
|
|
391
|
+
} catch {
|
|
392
|
+
return {
|
|
393
|
+
isValid: false,
|
|
394
|
+
invalidReason: "invalid_network",
|
|
395
|
+
payer: owner
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
const permitTypedData = {
|
|
399
|
+
types: permitTypes,
|
|
400
|
+
domain: {
|
|
401
|
+
name,
|
|
402
|
+
version,
|
|
403
|
+
chainId,
|
|
404
|
+
verifyingContract: erc20Address
|
|
405
|
+
},
|
|
406
|
+
primaryType: "Permit",
|
|
407
|
+
message: {
|
|
408
|
+
owner: getAddress3(owner),
|
|
409
|
+
spender: getAddress3(spender),
|
|
410
|
+
value,
|
|
411
|
+
nonce,
|
|
412
|
+
deadline
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const recoveredAddress = await client.verifyTypedData({
|
|
416
|
+
address: owner,
|
|
417
|
+
...permitTypedData,
|
|
418
|
+
signature: permitPayload.signature
|
|
419
|
+
});
|
|
420
|
+
if (!recoveredAddress) {
|
|
421
|
+
return {
|
|
422
|
+
isValid: false,
|
|
423
|
+
invalidReason: "invalid_permit_signature",
|
|
424
|
+
payer: owner
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
428
|
+
if (BigInt(deadline) < now) {
|
|
429
|
+
return {
|
|
430
|
+
isValid: false,
|
|
431
|
+
invalidReason: "permit_expired",
|
|
432
|
+
payer: owner
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
if (paymentRequirements.extra?.proxyAddress) {
|
|
436
|
+
if (getAddress3(spender) !== getAddress3(paymentRequirements.extra?.proxyAddress)) {
|
|
437
|
+
return {
|
|
438
|
+
isValid: false,
|
|
439
|
+
invalidReason: "invalid_spender_address",
|
|
440
|
+
payer: owner
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
if (client.account && getAddress3(spender) !== getAddress3(client.account.address)) {
|
|
445
|
+
return {
|
|
446
|
+
isValid: false,
|
|
447
|
+
invalidReason: "invalid_spender_address",
|
|
448
|
+
payer: owner
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const balance = await getERC20Balance(client, erc20Address, owner);
|
|
453
|
+
if (balance < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
454
|
+
return {
|
|
455
|
+
isValid: false,
|
|
456
|
+
invalidReason: "insufficient_funds",
|
|
457
|
+
payer: owner
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
if (BigInt(value) < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
461
|
+
return {
|
|
462
|
+
isValid: false,
|
|
463
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
464
|
+
payer: owner
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
isValid: true,
|
|
469
|
+
payer: owner
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
async function settle2(wallet, paymentPayload, paymentRequirements) {
|
|
473
|
+
const permitPayload = paymentPayload.payload;
|
|
474
|
+
if (permitPayload.authorizationType !== "permit") {
|
|
475
|
+
return {
|
|
476
|
+
success: false,
|
|
477
|
+
errorReason: "invalid_authorization_type",
|
|
478
|
+
transaction: "",
|
|
479
|
+
network: paymentPayload.network,
|
|
480
|
+
payer: ""
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
const valid = await verify2(wallet, paymentPayload, paymentRequirements);
|
|
484
|
+
if (!valid.isValid) {
|
|
485
|
+
return {
|
|
486
|
+
success: false,
|
|
487
|
+
network: paymentPayload.network,
|
|
488
|
+
transaction: "",
|
|
489
|
+
errorReason: valid.invalidReason ?? "invalid_payment",
|
|
490
|
+
payer: permitPayload.authorization.owner
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
const { owner, spender, value, deadline } = permitPayload.authorization;
|
|
494
|
+
const { v, r, s } = splitSignature(permitPayload.signature);
|
|
495
|
+
const tokenAddress = paymentRequirements.asset;
|
|
496
|
+
const txNonce = await wallet.getTransactionCount({
|
|
497
|
+
address: wallet.account.address
|
|
498
|
+
});
|
|
499
|
+
let transactionHash;
|
|
500
|
+
if (paymentRequirements.extra?.proxyAddress) {
|
|
501
|
+
transactionHash = await wallet.writeContract({
|
|
502
|
+
address: paymentRequirements.extra.proxyAddress,
|
|
503
|
+
abi: permitProxyContractABI,
|
|
504
|
+
functionName: "permitAndTransfer",
|
|
505
|
+
args: [
|
|
506
|
+
tokenAddress,
|
|
507
|
+
owner,
|
|
508
|
+
spender,
|
|
509
|
+
BigInt(value),
|
|
510
|
+
BigInt(deadline),
|
|
511
|
+
v,
|
|
512
|
+
r,
|
|
513
|
+
s,
|
|
514
|
+
paymentRequirements.payTo
|
|
515
|
+
],
|
|
516
|
+
chain: wallet.chain,
|
|
517
|
+
nonce: txNonce
|
|
518
|
+
});
|
|
519
|
+
const receipt = await wallet.waitForTransactionReceipt({ hash: transactionHash });
|
|
520
|
+
if (receipt.status !== "success") {
|
|
521
|
+
return {
|
|
522
|
+
success: false,
|
|
523
|
+
errorReason: "transaction_failed",
|
|
524
|
+
transaction: transactionHash,
|
|
525
|
+
network: paymentPayload.network,
|
|
526
|
+
payer: owner
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
} else {
|
|
530
|
+
const [permitTx, transferTx] = await Promise.all([
|
|
531
|
+
// Call permit to approve the spender
|
|
532
|
+
wallet.writeContract({
|
|
533
|
+
address: tokenAddress,
|
|
534
|
+
abi: erc20PermitABI,
|
|
535
|
+
functionName: "permit",
|
|
536
|
+
args: [owner, spender, BigInt(value), BigInt(deadline), v, r, s],
|
|
537
|
+
chain: wallet.chain,
|
|
538
|
+
nonce: txNonce
|
|
539
|
+
}),
|
|
540
|
+
// Call transferFrom to transfer tokens to payTo address
|
|
541
|
+
wallet.writeContract({
|
|
542
|
+
address: tokenAddress,
|
|
543
|
+
abi: erc20PermitABI,
|
|
544
|
+
functionName: "transferFrom",
|
|
545
|
+
args: [owner, paymentRequirements.payTo, BigInt(value)],
|
|
546
|
+
chain: wallet.chain,
|
|
547
|
+
nonce: txNonce + 1
|
|
548
|
+
})
|
|
549
|
+
]);
|
|
550
|
+
const [, receipt] = await Promise.all([
|
|
551
|
+
wallet.waitForTransactionReceipt({ hash: permitTx }),
|
|
552
|
+
wallet.waitForTransactionReceipt({ hash: transferTx })
|
|
553
|
+
]);
|
|
554
|
+
if (receipt.status !== "success") {
|
|
555
|
+
return {
|
|
556
|
+
success: false,
|
|
557
|
+
errorReason: "transaction_failed",
|
|
558
|
+
transaction: transferTx,
|
|
559
|
+
network: paymentPayload.network,
|
|
560
|
+
payer: owner
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
transactionHash = transferTx;
|
|
564
|
+
}
|
|
565
|
+
return {
|
|
566
|
+
success: true,
|
|
567
|
+
transaction: transactionHash,
|
|
568
|
+
network: paymentPayload.network,
|
|
569
|
+
payer: owner
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/schemes/exact/evm/permit2/facilitator.ts
|
|
574
|
+
import { getAddress as getAddress4 } from "viem";
|
|
575
|
+
async function verify3(client, payload, paymentRequirements) {
|
|
576
|
+
if (payload.payload.authorizationType !== "permit2" || payload.scheme !== SCHEME || paymentRequirements.scheme !== SCHEME) {
|
|
577
|
+
return {
|
|
578
|
+
isValid: false,
|
|
579
|
+
invalidReason: "unsupported_scheme"
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
const permit2Payload = payload.payload;
|
|
583
|
+
const { owner, spender, token, amount, deadline, nonce } = permit2Payload.authorization;
|
|
584
|
+
const chainId = getNetworkId(payload.network);
|
|
585
|
+
const tokenAddress = getAddress4(token);
|
|
586
|
+
const ownerAddress = getAddress4(owner);
|
|
587
|
+
const permit2TypedData = {
|
|
588
|
+
types: permit2Types,
|
|
589
|
+
domain: {
|
|
590
|
+
name: "Permit2",
|
|
591
|
+
chainId,
|
|
592
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
593
|
+
},
|
|
594
|
+
primaryType: "PermitTransferFrom",
|
|
595
|
+
message: {
|
|
596
|
+
permitted: {
|
|
597
|
+
token: tokenAddress,
|
|
598
|
+
amount
|
|
599
|
+
},
|
|
600
|
+
spender: getAddress4(spender),
|
|
601
|
+
nonce,
|
|
602
|
+
deadline
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
const recoveredAddress = await client.verifyTypedData({
|
|
606
|
+
address: ownerAddress,
|
|
607
|
+
...permit2TypedData,
|
|
608
|
+
signature: permit2Payload.signature
|
|
609
|
+
});
|
|
610
|
+
if (!recoveredAddress) {
|
|
611
|
+
return {
|
|
612
|
+
isValid: false,
|
|
613
|
+
invalidReason: "invalid_permit2_signature",
|
|
614
|
+
payer: owner
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
618
|
+
if (BigInt(deadline) < now) {
|
|
619
|
+
return {
|
|
620
|
+
isValid: false,
|
|
621
|
+
invalidReason: "permit2_expired",
|
|
622
|
+
payer: owner
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
if (client.account && getAddress4(spender) !== getAddress4(client.account.address)) {
|
|
626
|
+
return {
|
|
627
|
+
isValid: false,
|
|
628
|
+
invalidReason: "invalid_spender_address",
|
|
629
|
+
payer: owner
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
if (tokenAddress.toLowerCase() !== paymentRequirements.asset.toLowerCase()) {
|
|
633
|
+
return {
|
|
634
|
+
isValid: false,
|
|
635
|
+
invalidReason: "token_mismatch",
|
|
636
|
+
payer: owner
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
const allowance = await getERC20Allowance(client, tokenAddress, ownerAddress, PERMIT2_ADDRESS);
|
|
640
|
+
if (allowance < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
641
|
+
return {
|
|
642
|
+
isValid: false,
|
|
643
|
+
invalidReason: "permit2_not_approved",
|
|
644
|
+
payer: owner
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
const balance = await getERC20Balance(client, tokenAddress, ownerAddress);
|
|
648
|
+
if (balance < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
649
|
+
return {
|
|
650
|
+
isValid: false,
|
|
651
|
+
invalidReason: "insufficient_funds",
|
|
652
|
+
payer: owner
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if (BigInt(amount) < BigInt(paymentRequirements.maxAmountRequired)) {
|
|
656
|
+
return {
|
|
657
|
+
isValid: false,
|
|
658
|
+
invalidReason: "invalid_exact_evm_payload_authorization_value",
|
|
659
|
+
payer: owner
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
return {
|
|
663
|
+
isValid: true,
|
|
664
|
+
payer: owner
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
async function settle3(wallet, paymentPayload, paymentRequirements) {
|
|
668
|
+
const permit2Payload = paymentPayload.payload;
|
|
669
|
+
if (permit2Payload.authorizationType !== "permit2") {
|
|
670
|
+
return {
|
|
671
|
+
success: false,
|
|
672
|
+
errorReason: "invalid_authorization_type",
|
|
673
|
+
transaction: "",
|
|
674
|
+
network: paymentPayload.network,
|
|
675
|
+
payer: ""
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
const valid = await verify3(wallet, paymentPayload, paymentRequirements);
|
|
679
|
+
if (!valid.isValid) {
|
|
680
|
+
return {
|
|
681
|
+
success: false,
|
|
682
|
+
network: paymentPayload.network,
|
|
683
|
+
transaction: "",
|
|
684
|
+
errorReason: valid.invalidReason ?? "invalid_payment",
|
|
685
|
+
payer: permit2Payload.authorization.owner
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
const { owner, token, amount, deadline, nonce } = permit2Payload.authorization;
|
|
689
|
+
const tokenAddress = getAddress4(token);
|
|
690
|
+
const ownerAddress = getAddress4(owner);
|
|
691
|
+
const tx = await wallet.writeContract({
|
|
692
|
+
address: PERMIT2_ADDRESS,
|
|
693
|
+
abi: permit2ABI,
|
|
694
|
+
functionName: "permitTransferFrom",
|
|
695
|
+
args: [
|
|
696
|
+
{
|
|
697
|
+
permitted: {
|
|
698
|
+
token: tokenAddress,
|
|
699
|
+
amount: BigInt(amount)
|
|
700
|
+
},
|
|
701
|
+
nonce: BigInt(nonce),
|
|
702
|
+
deadline: BigInt(deadline)
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
to: paymentRequirements.payTo,
|
|
706
|
+
requestedAmount: BigInt(amount)
|
|
707
|
+
},
|
|
708
|
+
ownerAddress,
|
|
709
|
+
permit2Payload.signature
|
|
710
|
+
],
|
|
711
|
+
chain: wallet.chain
|
|
712
|
+
});
|
|
713
|
+
const receipt = await wallet.waitForTransactionReceipt({ hash: tx });
|
|
714
|
+
if (receipt.status !== "success") {
|
|
715
|
+
return {
|
|
716
|
+
success: false,
|
|
717
|
+
errorReason: "transaction_failed",
|
|
718
|
+
transaction: tx,
|
|
719
|
+
network: paymentPayload.network,
|
|
720
|
+
payer: owner
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
return {
|
|
724
|
+
success: true,
|
|
725
|
+
transaction: tx,
|
|
726
|
+
network: paymentPayload.network,
|
|
727
|
+
payer: owner
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/schemes/exact/evm/eip3009/index.ts
|
|
732
|
+
var eip3009_exports = {};
|
|
733
|
+
__export(eip3009_exports, {
|
|
734
|
+
createNonce: () => createNonce,
|
|
735
|
+
createPayment: () => createPayment,
|
|
736
|
+
createPaymentHeader: () => createPaymentHeader,
|
|
737
|
+
preparePaymentHeader: () => preparePaymentHeader,
|
|
738
|
+
settle: () => settle,
|
|
739
|
+
signAuthorization: () => signAuthorization,
|
|
740
|
+
signPaymentHeader: () => signPaymentHeader,
|
|
741
|
+
verify: () => verify
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
// src/schemes/exact/evm/permit/index.ts
|
|
745
|
+
var permit_exports = {};
|
|
746
|
+
__export(permit_exports, {
|
|
747
|
+
createPayment: () => createPayment2,
|
|
748
|
+
createPaymentHeader: () => createPaymentHeader3,
|
|
749
|
+
preparePaymentHeader: () => preparePaymentHeader2,
|
|
750
|
+
settle: () => settle2,
|
|
751
|
+
signPaymentHeader: () => signPaymentHeader2,
|
|
752
|
+
signPermit: () => signPermit,
|
|
753
|
+
splitSignature: () => splitSignature,
|
|
754
|
+
verify: () => verify2
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
// src/schemes/exact/evm/permit/client.ts
|
|
758
|
+
function preparePaymentHeader2(from, x402Version, paymentRequirements) {
|
|
759
|
+
const deadline = BigInt(
|
|
760
|
+
Math.floor(Date.now() / 1e3 + paymentRequirements.maxTimeoutSeconds)
|
|
761
|
+
).toString();
|
|
762
|
+
return {
|
|
763
|
+
x402Version,
|
|
764
|
+
scheme: paymentRequirements.scheme,
|
|
765
|
+
network: paymentRequirements.network,
|
|
766
|
+
payload: {
|
|
767
|
+
authorizationType: "permit",
|
|
768
|
+
signature: void 0,
|
|
769
|
+
authorization: {
|
|
770
|
+
owner: from,
|
|
771
|
+
spender: paymentRequirements.payTo,
|
|
772
|
+
value: paymentRequirements.maxAmountRequired,
|
|
773
|
+
deadline
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async function signPaymentHeader2(client, paymentRequirements, unsignedPaymentHeader) {
|
|
779
|
+
const { owner, spender, value, deadline } = unsignedPaymentHeader.payload.authorization;
|
|
780
|
+
const { signature, nonce } = await signPermit(
|
|
781
|
+
client,
|
|
782
|
+
{ owner, spender, value, deadline },
|
|
783
|
+
paymentRequirements
|
|
784
|
+
);
|
|
785
|
+
return {
|
|
786
|
+
...unsignedPaymentHeader,
|
|
787
|
+
payload: {
|
|
788
|
+
authorizationType: "permit",
|
|
789
|
+
signature,
|
|
790
|
+
authorization: {
|
|
791
|
+
owner,
|
|
792
|
+
spender,
|
|
793
|
+
value,
|
|
794
|
+
deadline,
|
|
795
|
+
nonce: nonce.toString()
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
async function createPayment2(client, x402Version, paymentRequirements) {
|
|
801
|
+
const from = isSignerWallet(client) ? client.account.address : client.address;
|
|
802
|
+
const unsignedPaymentHeader = preparePaymentHeader2(from, x402Version, paymentRequirements);
|
|
803
|
+
return signPaymentHeader2(client, paymentRequirements, unsignedPaymentHeader);
|
|
804
|
+
}
|
|
805
|
+
async function createPaymentHeader3(client, x402Version, paymentRequirements) {
|
|
806
|
+
const payment = await createPayment2(client, x402Version, paymentRequirements);
|
|
807
|
+
return encodePayment(payment);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// src/schemes/exact/evm/permit2/index.ts
|
|
811
|
+
var permit2_exports = {};
|
|
812
|
+
__export(permit2_exports, {
|
|
813
|
+
createPayment: () => createPayment3,
|
|
814
|
+
createPaymentHeader: () => createPaymentHeader4,
|
|
815
|
+
createPermit2Nonce: () => createPermit2Nonce,
|
|
816
|
+
preparePaymentHeader: () => preparePaymentHeader3,
|
|
817
|
+
settle: () => settle3,
|
|
818
|
+
signPaymentHeader: () => signPaymentHeader3,
|
|
819
|
+
signPermit2: () => signPermit2,
|
|
820
|
+
verify: () => verify3
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
// src/schemes/exact/evm/permit2/sign.ts
|
|
824
|
+
import { getAddress as getAddress5 } from "viem";
|
|
825
|
+
async function signPermit2(walletClient, { owner, spender, token, amount, deadline }, { network }) {
|
|
826
|
+
const chainId = getNetworkId(network);
|
|
827
|
+
const tokenAddress = getAddress5(token);
|
|
828
|
+
const ownerAddress = getAddress5(owner);
|
|
829
|
+
const spenderAddress = getAddress5(spender);
|
|
830
|
+
const nonce = await createPermit2Nonce(walletClient, ownerAddress);
|
|
831
|
+
const data = {
|
|
832
|
+
types: permit2Types,
|
|
833
|
+
domain: {
|
|
834
|
+
name: "Permit2",
|
|
835
|
+
chainId,
|
|
836
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
837
|
+
},
|
|
838
|
+
primaryType: "PermitTransferFrom",
|
|
839
|
+
message: {
|
|
840
|
+
permitted: {
|
|
841
|
+
token: tokenAddress,
|
|
842
|
+
amount: BigInt(amount)
|
|
843
|
+
},
|
|
844
|
+
spender: spenderAddress,
|
|
845
|
+
nonce,
|
|
846
|
+
deadline: BigInt(deadline)
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
if (isSignerWallet(walletClient)) {
|
|
850
|
+
const signature = await walletClient.signTypedData(data);
|
|
851
|
+
return {
|
|
852
|
+
signature,
|
|
853
|
+
nonce: nonce.toString()
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
const account = walletClient;
|
|
857
|
+
if (account.signTypedData) {
|
|
858
|
+
const signature = await account.signTypedData(data);
|
|
859
|
+
return {
|
|
860
|
+
signature,
|
|
861
|
+
nonce: nonce.toString()
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
throw new Error("Invalid wallet client provided does not support signTypedData");
|
|
865
|
+
}
|
|
866
|
+
async function createPermit2Nonce(walletClient, ownerAddress) {
|
|
867
|
+
if (!isSignerWallet(walletClient)) {
|
|
868
|
+
throw new Error("Local account signing for permit2 requires a connected client");
|
|
869
|
+
}
|
|
870
|
+
const timestamp = BigInt(Math.floor(Date.now() / 1e3));
|
|
871
|
+
const randomOffset = BigInt(Math.floor(Math.random() * 1e3));
|
|
872
|
+
let nonce = timestamp * 1000n + randomOffset;
|
|
873
|
+
try {
|
|
874
|
+
const wordPos = nonce / 256n;
|
|
875
|
+
const bitIndex = nonce % 256n;
|
|
876
|
+
const bitmap = await walletClient.readContract({
|
|
877
|
+
address: PERMIT2_ADDRESS,
|
|
878
|
+
abi: permit2ABI,
|
|
879
|
+
functionName: "nonceBitmap",
|
|
880
|
+
args: [ownerAddress, wordPos]
|
|
881
|
+
});
|
|
882
|
+
const used = bitmap >> bitIndex & 1n;
|
|
883
|
+
if (used === 1n) {
|
|
884
|
+
nonce += 1n;
|
|
885
|
+
}
|
|
886
|
+
} catch (error) {
|
|
887
|
+
console.warn("Could not check nonce bitmap, using timestamp-based nonce:", error);
|
|
888
|
+
}
|
|
889
|
+
return nonce;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// src/schemes/exact/evm/permit2/client.ts
|
|
893
|
+
function preparePaymentHeader3(from, x402Version, paymentRequirements) {
|
|
894
|
+
const deadline = BigInt(
|
|
895
|
+
Math.floor(Date.now() / 1e3 + paymentRequirements.maxTimeoutSeconds)
|
|
896
|
+
).toString();
|
|
897
|
+
return {
|
|
898
|
+
x402Version,
|
|
899
|
+
scheme: paymentRequirements.scheme,
|
|
900
|
+
network: paymentRequirements.network,
|
|
901
|
+
payload: {
|
|
902
|
+
authorizationType: "permit2",
|
|
903
|
+
signature: void 0,
|
|
904
|
+
authorization: {
|
|
905
|
+
owner: from,
|
|
906
|
+
spender: paymentRequirements.payTo,
|
|
907
|
+
token: paymentRequirements.asset,
|
|
908
|
+
amount: paymentRequirements.maxAmountRequired,
|
|
909
|
+
deadline
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
async function signPaymentHeader3(client, paymentRequirements, unsignedPaymentHeader) {
|
|
915
|
+
const { owner, spender, token, amount, deadline } = unsignedPaymentHeader.payload.authorization;
|
|
916
|
+
const { signature, nonce } = await signPermit2(
|
|
917
|
+
client,
|
|
918
|
+
{ owner, spender, token, amount, deadline },
|
|
919
|
+
paymentRequirements
|
|
920
|
+
);
|
|
921
|
+
return {
|
|
922
|
+
...unsignedPaymentHeader,
|
|
923
|
+
payload: {
|
|
924
|
+
authorizationType: "permit2",
|
|
925
|
+
signature,
|
|
926
|
+
authorization: {
|
|
927
|
+
owner,
|
|
928
|
+
spender,
|
|
929
|
+
token,
|
|
930
|
+
amount,
|
|
931
|
+
deadline,
|
|
932
|
+
nonce
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
async function createPayment3(client, x402Version, paymentRequirements) {
|
|
938
|
+
const from = isSignerWallet(client) ? client.account.address : client.address;
|
|
939
|
+
const unsignedPaymentHeader = preparePaymentHeader3(from, x402Version, paymentRequirements);
|
|
940
|
+
return signPaymentHeader3(client, paymentRequirements, unsignedPaymentHeader);
|
|
941
|
+
}
|
|
942
|
+
async function createPaymentHeader4(client, x402Version, paymentRequirements) {
|
|
943
|
+
const payment = await createPayment3(client, x402Version, paymentRequirements);
|
|
944
|
+
return encodePayment(payment);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// src/schemes/exact/evm/index.ts
|
|
948
|
+
async function verify4(client, payload, paymentRequirements) {
|
|
949
|
+
const exactEvmPayload = payload.payload;
|
|
950
|
+
switch (exactEvmPayload.authorizationType) {
|
|
951
|
+
case "eip3009":
|
|
952
|
+
return verify(
|
|
953
|
+
client,
|
|
954
|
+
payload,
|
|
955
|
+
paymentRequirements
|
|
956
|
+
);
|
|
957
|
+
case "permit":
|
|
958
|
+
return verify2(client, payload, paymentRequirements);
|
|
959
|
+
case "permit2":
|
|
960
|
+
return verify3(
|
|
961
|
+
client,
|
|
962
|
+
payload,
|
|
963
|
+
paymentRequirements
|
|
964
|
+
);
|
|
965
|
+
default:
|
|
966
|
+
return {
|
|
967
|
+
isValid: false,
|
|
968
|
+
invalidReason: "unsupported_authorization_type",
|
|
969
|
+
payer: ""
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
async function settle4(wallet, paymentPayload, paymentRequirements) {
|
|
974
|
+
const payload = paymentPayload.payload;
|
|
975
|
+
switch (payload.authorizationType) {
|
|
976
|
+
case "eip3009":
|
|
977
|
+
return settle(
|
|
978
|
+
wallet,
|
|
979
|
+
paymentPayload,
|
|
980
|
+
paymentRequirements
|
|
981
|
+
);
|
|
982
|
+
case "permit":
|
|
983
|
+
return settle2(
|
|
984
|
+
wallet,
|
|
985
|
+
paymentPayload,
|
|
986
|
+
paymentRequirements
|
|
987
|
+
);
|
|
988
|
+
case "permit2":
|
|
989
|
+
return settle3(
|
|
990
|
+
wallet,
|
|
991
|
+
paymentPayload,
|
|
992
|
+
paymentRequirements
|
|
993
|
+
);
|
|
994
|
+
default:
|
|
995
|
+
return {
|
|
996
|
+
success: false,
|
|
997
|
+
errorReason: "unsupported_authorization_type",
|
|
998
|
+
transaction: "",
|
|
999
|
+
network: paymentPayload.network,
|
|
1000
|
+
payer: ""
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/schemes/exact/svm/index.ts
|
|
1006
|
+
var svm_exports = {};
|
|
1007
|
+
__export(svm_exports, {
|
|
1008
|
+
confirmSignedTransaction: () => confirmSignedTransaction,
|
|
1009
|
+
createAndSignPayment: () => createAndSignPayment,
|
|
1010
|
+
createPaymentHeader: () => createPaymentHeader2,
|
|
1011
|
+
getValidatedTransferCheckedInstruction: () => getValidatedTransferCheckedInstruction,
|
|
1012
|
+
sendAndConfirmSignedTransaction: () => sendAndConfirmSignedTransaction,
|
|
1013
|
+
sendSignedTransaction: () => sendSignedTransaction,
|
|
1014
|
+
settle: () => settle5,
|
|
1015
|
+
transactionIntrospection: () => transactionIntrospection,
|
|
1016
|
+
verify: () => verify5,
|
|
1017
|
+
verifyComputeLimitInstruction: () => verifyComputeLimitInstruction,
|
|
1018
|
+
verifyComputePriceInstruction: () => verifyComputePriceInstruction,
|
|
1019
|
+
verifyCreateATAInstruction: () => verifyCreateATAInstruction,
|
|
1020
|
+
verifySchemesAndNetworks: () => verifySchemesAndNetworks,
|
|
1021
|
+
verifyTransactionInstructions: () => verifyTransactionInstructions,
|
|
1022
|
+
verifyTransferCheckedInstruction: () => verifyTransferCheckedInstruction,
|
|
1023
|
+
verifyTransferInstruction: () => verifyTransferInstruction
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
// src/schemes/exact/svm/facilitator/settle.ts
|
|
1027
|
+
import {
|
|
1028
|
+
assertIsTransactionMessageWithBlockhashLifetime,
|
|
1029
|
+
decompileTransactionMessageFetchingLookupTables,
|
|
1030
|
+
getBase64EncodedWireTransaction,
|
|
1031
|
+
getCompiledTransactionMessageDecoder as getCompiledTransactionMessageDecoder2,
|
|
1032
|
+
getSignatureFromTransaction,
|
|
1033
|
+
isSolanaError,
|
|
1034
|
+
signTransaction,
|
|
1035
|
+
SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED
|
|
1036
|
+
} from "@solana/kit";
|
|
1037
|
+
import {
|
|
1038
|
+
createBlockHeightExceedencePromiseFactory,
|
|
1039
|
+
waitForRecentTransactionConfirmation,
|
|
1040
|
+
createRecentSignatureConfirmationPromiseFactory
|
|
1041
|
+
} from "@solana/transaction-confirmation";
|
|
1042
|
+
|
|
1043
|
+
// src/schemes/exact/svm/facilitator/verify.ts
|
|
1044
|
+
import {
|
|
1045
|
+
assertIsInstructionWithAccounts,
|
|
1046
|
+
assertIsInstructionWithData,
|
|
1047
|
+
decompileTransactionMessage,
|
|
1048
|
+
fetchEncodedAccounts,
|
|
1049
|
+
getCompiledTransactionMessageDecoder
|
|
1050
|
+
} from "@solana/kit";
|
|
1051
|
+
import {
|
|
1052
|
+
parseSetComputeUnitLimitInstruction,
|
|
1053
|
+
parseSetComputeUnitPriceInstruction,
|
|
1054
|
+
COMPUTE_BUDGET_PROGRAM_ADDRESS
|
|
1055
|
+
} from "@solana-program/compute-budget";
|
|
1056
|
+
import {
|
|
1057
|
+
findAssociatedTokenPda,
|
|
1058
|
+
identifyToken2022Instruction,
|
|
1059
|
+
parseCreateAssociatedTokenInstruction,
|
|
1060
|
+
parseTransferCheckedInstruction as parseTransferCheckedInstruction2022,
|
|
1061
|
+
Token2022Instruction,
|
|
1062
|
+
TOKEN_2022_PROGRAM_ADDRESS
|
|
1063
|
+
} from "@solana-program/token-2022";
|
|
1064
|
+
import {
|
|
1065
|
+
identifyTokenInstruction,
|
|
1066
|
+
parseTransferCheckedInstruction as parseTransferCheckedInstructionToken,
|
|
1067
|
+
TOKEN_PROGRAM_ADDRESS,
|
|
1068
|
+
TokenInstruction
|
|
1069
|
+
} from "@solana-program/token";
|
|
1070
|
+
async function verify5(signer, payload, paymentRequirements, config2) {
|
|
1071
|
+
try {
|
|
1072
|
+
verifySchemesAndNetworks(payload, paymentRequirements);
|
|
1073
|
+
const svmPayload = payload.payload;
|
|
1074
|
+
const decodedTransaction = decodeTransactionFromPayload(svmPayload);
|
|
1075
|
+
const rpc = getRpcClient(paymentRequirements.network, config2?.svmConfig?.rpcUrl);
|
|
1076
|
+
await transactionIntrospection(svmPayload, paymentRequirements, config2);
|
|
1077
|
+
const simulateResult = await signAndSimulateTransaction(signer, decodedTransaction, rpc);
|
|
1078
|
+
if (simulateResult.value?.err) {
|
|
1079
|
+
throw new Error(`invalid_exact_svm_payload_transaction_simulation_failed`);
|
|
1080
|
+
}
|
|
1081
|
+
return {
|
|
1082
|
+
isValid: true,
|
|
1083
|
+
invalidReason: void 0,
|
|
1084
|
+
payer: getTokenPayerFromTransaction(decodedTransaction)
|
|
1085
|
+
};
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
if (error instanceof Error) {
|
|
1088
|
+
if (ErrorReasons.includes(error.message)) {
|
|
1089
|
+
return {
|
|
1090
|
+
isValid: false,
|
|
1091
|
+
invalidReason: error.message,
|
|
1092
|
+
payer: (() => {
|
|
1093
|
+
try {
|
|
1094
|
+
const tx = decodeTransactionFromPayload(payload.payload);
|
|
1095
|
+
return getTokenPayerFromTransaction(tx);
|
|
1096
|
+
} catch {
|
|
1097
|
+
return void 0;
|
|
1098
|
+
}
|
|
1099
|
+
})()
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
console.error(error);
|
|
1104
|
+
return {
|
|
1105
|
+
isValid: false,
|
|
1106
|
+
invalidReason: "unexpected_verify_error",
|
|
1107
|
+
payer: (() => {
|
|
1108
|
+
try {
|
|
1109
|
+
const tx = decodeTransactionFromPayload(payload.payload);
|
|
1110
|
+
return getTokenPayerFromTransaction(tx);
|
|
1111
|
+
} catch {
|
|
1112
|
+
return void 0;
|
|
1113
|
+
}
|
|
1114
|
+
})()
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
function verifySchemesAndNetworks(payload, paymentRequirements) {
|
|
1119
|
+
if (payload.scheme !== SCHEME || paymentRequirements.scheme !== SCHEME) {
|
|
1120
|
+
throw new Error("unsupported_scheme");
|
|
1121
|
+
}
|
|
1122
|
+
if (payload.network !== paymentRequirements.network || !SupportedSVMNetworks.includes(paymentRequirements.network)) {
|
|
1123
|
+
throw new Error("invalid_network");
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
async function transactionIntrospection(svmPayload, paymentRequirements, config2) {
|
|
1127
|
+
const rpc = getRpcClient(paymentRequirements.network, config2?.svmConfig?.rpcUrl);
|
|
1128
|
+
const decodedTransaction = decodeTransactionFromPayload(svmPayload);
|
|
1129
|
+
const compiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(
|
|
1130
|
+
decodedTransaction.messageBytes
|
|
1131
|
+
);
|
|
1132
|
+
const transactionMessage = decompileTransactionMessage(
|
|
1133
|
+
compiledTransactionMessage
|
|
1134
|
+
);
|
|
1135
|
+
await verifyTransactionInstructions(transactionMessage, paymentRequirements, rpc);
|
|
1136
|
+
}
|
|
1137
|
+
async function verifyTransactionInstructions(transactionMessage, paymentRequirements, rpc) {
|
|
1138
|
+
if (transactionMessage.instructions.length !== 3 && transactionMessage.instructions.length !== 4) {
|
|
1139
|
+
throw new Error(`invalid_exact_svm_payload_transaction_instructions_length`);
|
|
1140
|
+
}
|
|
1141
|
+
verifyComputeLimitInstruction(transactionMessage.instructions[0]);
|
|
1142
|
+
verifyComputePriceInstruction(transactionMessage.instructions[1]);
|
|
1143
|
+
if (transactionMessage.instructions.length === 3) {
|
|
1144
|
+
await verifyTransferInstruction(
|
|
1145
|
+
transactionMessage.instructions[2],
|
|
1146
|
+
paymentRequirements,
|
|
1147
|
+
{
|
|
1148
|
+
txHasCreateDestATAInstruction: false
|
|
1149
|
+
},
|
|
1150
|
+
rpc
|
|
1151
|
+
);
|
|
1152
|
+
} else {
|
|
1153
|
+
verifyCreateATAInstruction(transactionMessage.instructions[2], paymentRequirements);
|
|
1154
|
+
await verifyTransferInstruction(
|
|
1155
|
+
transactionMessage.instructions[3],
|
|
1156
|
+
paymentRequirements,
|
|
1157
|
+
{
|
|
1158
|
+
txHasCreateDestATAInstruction: true
|
|
1159
|
+
},
|
|
1160
|
+
rpc
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
function verifyComputeLimitInstruction(instruction) {
|
|
1165
|
+
try {
|
|
1166
|
+
if (instruction.programAddress.toString() !== COMPUTE_BUDGET_PROGRAM_ADDRESS.toString() || instruction.data?.[0] !== 2) {
|
|
1167
|
+
throw new Error(
|
|
1168
|
+
`invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction`
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
parseSetComputeUnitLimitInstruction(
|
|
1172
|
+
instruction
|
|
1173
|
+
);
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
console.error(error);
|
|
1176
|
+
throw new Error(`invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction`);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function verifyComputePriceInstruction(instruction) {
|
|
1180
|
+
if (instruction.programAddress.toString() !== COMPUTE_BUDGET_PROGRAM_ADDRESS.toString() || instruction.data?.[0] !== 3) {
|
|
1181
|
+
throw new Error(`invalid_exact_svm_payload_transaction_instructions_compute_price_instruction`);
|
|
1182
|
+
}
|
|
1183
|
+
const parsedInstruction = parseSetComputeUnitPriceInstruction(
|
|
1184
|
+
instruction
|
|
1185
|
+
);
|
|
1186
|
+
if (parsedInstruction.data.microLamports > 5 * 1e6) {
|
|
1187
|
+
throw new Error(
|
|
1188
|
+
`invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high`
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
function verifyCreateATAInstruction(instruction, paymentRequirements) {
|
|
1193
|
+
let createATAInstruction;
|
|
1194
|
+
try {
|
|
1195
|
+
assertIsInstructionWithAccounts(instruction);
|
|
1196
|
+
assertIsInstructionWithData(instruction);
|
|
1197
|
+
createATAInstruction = parseCreateAssociatedTokenInstruction({
|
|
1198
|
+
...instruction,
|
|
1199
|
+
data: new Uint8Array(instruction.data)
|
|
1200
|
+
});
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
console.error(error);
|
|
1203
|
+
throw new Error(`invalid_exact_svm_payload_transaction_create_ata_instruction`);
|
|
1204
|
+
}
|
|
1205
|
+
if (createATAInstruction.accounts.owner.address !== paymentRequirements.payTo) {
|
|
1206
|
+
throw new Error(`invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee`);
|
|
1207
|
+
}
|
|
1208
|
+
if (createATAInstruction.accounts.mint.address !== paymentRequirements.asset) {
|
|
1209
|
+
throw new Error(`invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset`);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
async function verifyTransferInstruction(instruction, paymentRequirements, { txHasCreateDestATAInstruction }, rpc) {
|
|
1213
|
+
const tokenInstruction = getValidatedTransferCheckedInstruction(instruction);
|
|
1214
|
+
await verifyTransferCheckedInstruction(
|
|
1215
|
+
tokenInstruction,
|
|
1216
|
+
paymentRequirements,
|
|
1217
|
+
{
|
|
1218
|
+
txHasCreateDestATAInstruction
|
|
1219
|
+
},
|
|
1220
|
+
rpc
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
async function verifyTransferCheckedInstruction(parsedInstruction, paymentRequirements, { txHasCreateDestATAInstruction }, rpc) {
|
|
1224
|
+
const tokenProgramAddress = parsedInstruction.programAddress.toString() === TOKEN_PROGRAM_ADDRESS.toString() ? TOKEN_PROGRAM_ADDRESS : TOKEN_2022_PROGRAM_ADDRESS;
|
|
1225
|
+
const payToATA = await findAssociatedTokenPda({
|
|
1226
|
+
mint: paymentRequirements.asset,
|
|
1227
|
+
owner: paymentRequirements.payTo,
|
|
1228
|
+
tokenProgram: tokenProgramAddress
|
|
1229
|
+
});
|
|
1230
|
+
if (parsedInstruction.accounts.destination.address !== payToATA[0]) {
|
|
1231
|
+
throw new Error(`invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata`);
|
|
1232
|
+
}
|
|
1233
|
+
const addresses = [parsedInstruction.accounts.source.address, payToATA[0]];
|
|
1234
|
+
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses);
|
|
1235
|
+
const missingAccounts = maybeAccounts.filter((a) => !a.exists);
|
|
1236
|
+
for (const missingAccount of missingAccounts) {
|
|
1237
|
+
if (missingAccount.address === parsedInstruction.accounts.source.address) {
|
|
1238
|
+
throw new Error(`invalid_exact_svm_payload_transaction_sender_ata_not_found`);
|
|
1239
|
+
}
|
|
1240
|
+
if (missingAccount.address === payToATA[0] && !txHasCreateDestATAInstruction) {
|
|
1241
|
+
throw new Error(`invalid_exact_svm_payload_transaction_receiver_ata_not_found`);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
const instructionAmount = parsedInstruction.data.amount;
|
|
1245
|
+
const paymentRequirementsAmount = BigInt(paymentRequirements.maxAmountRequired);
|
|
1246
|
+
if (instructionAmount !== paymentRequirementsAmount) {
|
|
1247
|
+
throw new Error(`invalid_exact_svm_payload_transaction_amount_mismatch`);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
function getValidatedTransferCheckedInstruction(instruction) {
|
|
1251
|
+
try {
|
|
1252
|
+
assertIsInstructionWithData(instruction);
|
|
1253
|
+
assertIsInstructionWithAccounts(instruction);
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
console.error(error);
|
|
1256
|
+
throw new Error(`invalid_exact_svm_payload_transaction_instructions`);
|
|
1257
|
+
}
|
|
1258
|
+
let tokenInstruction;
|
|
1259
|
+
if (instruction.programAddress.toString() === TOKEN_PROGRAM_ADDRESS.toString()) {
|
|
1260
|
+
const identifiedInstruction = identifyTokenInstruction(instruction);
|
|
1261
|
+
if (identifiedInstruction !== TokenInstruction.TransferChecked) {
|
|
1262
|
+
throw new Error(
|
|
1263
|
+
`invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked`
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
tokenInstruction = parseTransferCheckedInstructionToken({
|
|
1267
|
+
...instruction,
|
|
1268
|
+
data: new Uint8Array(instruction.data)
|
|
1269
|
+
});
|
|
1270
|
+
} else if (instruction.programAddress.toString() === TOKEN_2022_PROGRAM_ADDRESS.toString()) {
|
|
1271
|
+
const identifiedInstruction = identifyToken2022Instruction(instruction);
|
|
1272
|
+
if (identifiedInstruction !== Token2022Instruction.TransferChecked) {
|
|
1273
|
+
throw new Error(
|
|
1274
|
+
`invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
tokenInstruction = parseTransferCheckedInstruction2022({
|
|
1278
|
+
...instruction,
|
|
1279
|
+
data: new Uint8Array(instruction.data)
|
|
1280
|
+
});
|
|
1281
|
+
} else {
|
|
1282
|
+
throw new Error(`invalid_exact_svm_payload_transaction_not_a_transfer_instruction`);
|
|
1283
|
+
}
|
|
1284
|
+
return tokenInstruction;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// src/schemes/exact/svm/facilitator/settle.ts
|
|
1288
|
+
async function settle5(signer, payload, paymentRequirements, config2) {
|
|
1289
|
+
const verifyResponse = await verify5(signer, payload, paymentRequirements, config2);
|
|
1290
|
+
if (!verifyResponse.isValid) {
|
|
1291
|
+
return {
|
|
1292
|
+
success: false,
|
|
1293
|
+
errorReason: verifyResponse.invalidReason,
|
|
1294
|
+
network: payload.network,
|
|
1295
|
+
transaction: ""
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
const svmPayload = payload.payload;
|
|
1299
|
+
const decodedTransaction = decodeTransactionFromPayload(svmPayload);
|
|
1300
|
+
const signedTransaction = await signTransaction([signer.keyPair], decodedTransaction);
|
|
1301
|
+
const payer = getTokenPayerFromTransaction(decodedTransaction);
|
|
1302
|
+
const rpc = getRpcClient(paymentRequirements.network, config2?.svmConfig?.rpcUrl);
|
|
1303
|
+
const rpcSubscriptions = getRpcSubscriptions(
|
|
1304
|
+
paymentRequirements.network,
|
|
1305
|
+
config2?.svmConfig?.rpcUrl
|
|
1306
|
+
);
|
|
1307
|
+
try {
|
|
1308
|
+
const { success, errorReason, signature } = await sendAndConfirmSignedTransaction(
|
|
1309
|
+
signedTransaction,
|
|
1310
|
+
rpc,
|
|
1311
|
+
rpcSubscriptions
|
|
1312
|
+
);
|
|
1313
|
+
return {
|
|
1314
|
+
success,
|
|
1315
|
+
errorReason,
|
|
1316
|
+
payer,
|
|
1317
|
+
transaction: signature,
|
|
1318
|
+
network: payload.network
|
|
1319
|
+
};
|
|
1320
|
+
} catch (error) {
|
|
1321
|
+
console.error("Unexpected error during transaction settlement:", error);
|
|
1322
|
+
return {
|
|
1323
|
+
success: false,
|
|
1324
|
+
errorReason: "unexpected_settle_error",
|
|
1325
|
+
network: payload.network,
|
|
1326
|
+
transaction: getSignatureFromTransaction(signedTransaction),
|
|
1327
|
+
payer
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
async function sendSignedTransaction(signedTransaction, rpc, sendTxConfig = {
|
|
1332
|
+
skipPreflight: true,
|
|
1333
|
+
encoding: "base64"
|
|
1334
|
+
}) {
|
|
1335
|
+
const base64EncodedTransaction = getBase64EncodedWireTransaction(signedTransaction);
|
|
1336
|
+
return await rpc.sendTransaction(base64EncodedTransaction, sendTxConfig).send();
|
|
1337
|
+
}
|
|
1338
|
+
async function confirmSignedTransaction(signedTransaction, rpc, rpcSubscriptions) {
|
|
1339
|
+
const signature = getSignatureFromTransaction(signedTransaction);
|
|
1340
|
+
const abortController = new AbortController();
|
|
1341
|
+
const timeout = setTimeout(() => {
|
|
1342
|
+
abortController.abort("Transaction confirmation timed out after 60 seconds");
|
|
1343
|
+
}, 6e4);
|
|
1344
|
+
try {
|
|
1345
|
+
const compiledTransactionMessage = getCompiledTransactionMessageDecoder2().decode(
|
|
1346
|
+
signedTransaction.messageBytes
|
|
1347
|
+
);
|
|
1348
|
+
const decompiledTransactionMessage = await decompileTransactionMessageFetchingLookupTables(
|
|
1349
|
+
compiledTransactionMessage,
|
|
1350
|
+
rpc
|
|
1351
|
+
);
|
|
1352
|
+
assertIsTransactionMessageWithBlockhashLifetime(decompiledTransactionMessage);
|
|
1353
|
+
const signedTransactionWithBlockhashLifetime = {
|
|
1354
|
+
...signedTransaction,
|
|
1355
|
+
lifetimeConstraint: decompiledTransactionMessage.lifetimeConstraint
|
|
1356
|
+
};
|
|
1357
|
+
const commitment = "confirmed";
|
|
1358
|
+
const getRecentSignatureConfirmationPromise = createRecentSignatureConfirmationPromiseFactory({
|
|
1359
|
+
rpc,
|
|
1360
|
+
rpcSubscriptions
|
|
1361
|
+
});
|
|
1362
|
+
const getBlockHeightExceedencePromise = createBlockHeightExceedencePromiseFactory({
|
|
1363
|
+
rpc,
|
|
1364
|
+
rpcSubscriptions
|
|
1365
|
+
});
|
|
1366
|
+
const config2 = {
|
|
1367
|
+
abortSignal: abortController.signal,
|
|
1368
|
+
commitment,
|
|
1369
|
+
getBlockHeightExceedencePromise,
|
|
1370
|
+
getRecentSignatureConfirmationPromise
|
|
1371
|
+
};
|
|
1372
|
+
await waitForRecentTransactionConfirmation({
|
|
1373
|
+
...config2,
|
|
1374
|
+
transaction: signedTransactionWithBlockhashLifetime
|
|
1375
|
+
});
|
|
1376
|
+
return {
|
|
1377
|
+
success: true,
|
|
1378
|
+
signature
|
|
1379
|
+
};
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
console.error(error);
|
|
1382
|
+
if (isSolanaError(error, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED)) {
|
|
1383
|
+
return {
|
|
1384
|
+
success: false,
|
|
1385
|
+
errorReason: "settle_exact_svm_block_height_exceeded",
|
|
1386
|
+
signature
|
|
1387
|
+
};
|
|
1388
|
+
} else if (error instanceof DOMException && error.name === "AbortError") {
|
|
1389
|
+
return {
|
|
1390
|
+
success: false,
|
|
1391
|
+
errorReason: "settle_exact_svm_transaction_confirmation_timed_out",
|
|
1392
|
+
signature
|
|
1393
|
+
};
|
|
1394
|
+
} else {
|
|
1395
|
+
throw error;
|
|
1396
|
+
}
|
|
1397
|
+
} finally {
|
|
1398
|
+
clearTimeout(timeout);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
async function sendAndConfirmSignedTransaction(signedTransaction, rpc, rpcSubscriptions) {
|
|
1402
|
+
await sendSignedTransaction(signedTransaction, rpc);
|
|
1403
|
+
return await confirmSignedTransaction(signedTransaction, rpc, rpcSubscriptions);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
// src/schemes/exact/index.ts
|
|
1407
|
+
var SCHEME = "exact";
|
|
1408
|
+
|
|
1409
|
+
export {
|
|
1410
|
+
verify5 as verify,
|
|
1411
|
+
settle5 as settle,
|
|
1412
|
+
exact_exports,
|
|
1413
|
+
verify4 as verify2,
|
|
1414
|
+
settle4 as settle2
|
|
1415
|
+
};
|
|
1416
|
+
//# sourceMappingURL=chunk-57UEJN5U.mjs.map
|