@t402/near 2.3.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.
Files changed (38) hide show
  1. package/README.md +173 -0
  2. package/dist/cjs/exact-direct/client/index.d.ts +105 -0
  3. package/dist/cjs/exact-direct/client/index.js +156 -0
  4. package/dist/cjs/exact-direct/client/index.js.map +1 -0
  5. package/dist/cjs/exact-direct/facilitator/index.d.ts +114 -0
  6. package/dist/cjs/exact-direct/facilitator/index.js +304 -0
  7. package/dist/cjs/exact-direct/facilitator/index.js.map +1 -0
  8. package/dist/cjs/exact-direct/server/index.d.ts +129 -0
  9. package/dist/cjs/exact-direct/server/index.js +253 -0
  10. package/dist/cjs/exact-direct/server/index.js.map +1 -0
  11. package/dist/cjs/index.d.ts +226 -0
  12. package/dist/cjs/index.js +711 -0
  13. package/dist/cjs/index.js.map +1 -0
  14. package/dist/cjs/types-Ca7ztL_f.d.ts +169 -0
  15. package/dist/esm/chunk-B3RHERRA.mjs +162 -0
  16. package/dist/esm/chunk-B3RHERRA.mjs.map +1 -0
  17. package/dist/esm/chunk-BU2BQECZ.mjs +206 -0
  18. package/dist/esm/chunk-BU2BQECZ.mjs.map +1 -0
  19. package/dist/esm/chunk-G35SAYZI.mjs +67 -0
  20. package/dist/esm/chunk-G35SAYZI.mjs.map +1 -0
  21. package/dist/esm/chunk-WANNPL6S.mjs +155 -0
  22. package/dist/esm/chunk-WANNPL6S.mjs.map +1 -0
  23. package/dist/esm/chunk-YXBOH4MJ.mjs +103 -0
  24. package/dist/esm/chunk-YXBOH4MJ.mjs.map +1 -0
  25. package/dist/esm/exact-direct/client/index.d.mts +105 -0
  26. package/dist/esm/exact-direct/client/index.mjs +10 -0
  27. package/dist/esm/exact-direct/client/index.mjs.map +1 -0
  28. package/dist/esm/exact-direct/facilitator/index.d.mts +114 -0
  29. package/dist/esm/exact-direct/facilitator/index.mjs +11 -0
  30. package/dist/esm/exact-direct/facilitator/index.mjs.map +1 -0
  31. package/dist/esm/exact-direct/server/index.d.mts +129 -0
  32. package/dist/esm/exact-direct/server/index.mjs +11 -0
  33. package/dist/esm/exact-direct/server/index.mjs.map +1 -0
  34. package/dist/esm/index.d.mts +226 -0
  35. package/dist/esm/index.mjs +97 -0
  36. package/dist/esm/index.mjs.map +1 -0
  37. package/dist/esm/types-Ca7ztL_f.d.mts +169 -0
  38. package/package.json +97 -0
@@ -0,0 +1,711 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ DEFAULT_FT_TRANSFER_GAS: () => DEFAULT_FT_TRANSFER_GAS,
24
+ DEFAULT_STORAGE_DEPOSIT: () => DEFAULT_STORAGE_DEPOSIT,
25
+ DEFAULT_STORAGE_DEPOSIT_GAS: () => DEFAULT_STORAGE_DEPOSIT_GAS,
26
+ DEFAULT_VALIDITY_DURATION: () => DEFAULT_VALIDITY_DURATION,
27
+ ExactDirectNearClient: () => ExactDirectNearClient,
28
+ ExactDirectNearFacilitator: () => ExactDirectNearFacilitator,
29
+ ExactDirectNearServer: () => ExactDirectNearServer,
30
+ FT_TRANSFER_DEPOSIT: () => FT_TRANSFER_DEPOSIT,
31
+ MAX_TRANSACTION_AGE: () => MAX_TRANSACTION_AGE,
32
+ NEAR_CAIP2_NAMESPACE: () => NEAR_CAIP2_NAMESPACE,
33
+ NEAR_MAINNET_CAIP2: () => NEAR_MAINNET_CAIP2,
34
+ NEAR_MAINNET_RPC: () => NEAR_MAINNET_RPC,
35
+ NEAR_NETWORKS: () => NEAR_NETWORKS,
36
+ NEAR_NETWORK_IDS: () => NEAR_NETWORK_IDS,
37
+ NEAR_TESTNET_CAIP2: () => NEAR_TESTNET_CAIP2,
38
+ NEAR_TESTNET_RPC: () => NEAR_TESTNET_RPC,
39
+ NEP141_FT_BALANCE_OF: () => NEP141_FT_BALANCE_OF,
40
+ NEP141_FT_TRANSFER: () => NEP141_FT_TRANSFER,
41
+ NEP141_STORAGE_BALANCE_OF: () => NEP141_STORAGE_BALANCE_OF,
42
+ NEP141_STORAGE_DEPOSIT: () => NEP141_STORAGE_DEPOSIT,
43
+ NETWORK_RPC_ENDPOINTS: () => NETWORK_RPC_ENDPOINTS,
44
+ SCHEME_EXACT_DIRECT: () => SCHEME_EXACT_DIRECT,
45
+ TOKEN_REGISTRY: () => TOKEN_REGISTRY,
46
+ extractNetworkId: () => extractNetworkId,
47
+ formatAmount: () => formatAmount,
48
+ getDefaultToken: () => getDefaultToken,
49
+ getNetworkTokens: () => getNetworkTokens,
50
+ getRpcEndpoint: () => getRpcEndpoint,
51
+ getTokenByContract: () => getTokenByContract,
52
+ getTokenConfig: () => getTokenConfig,
53
+ isNetworkSupported: () => isNetworkSupported,
54
+ isTransactionSuccessful: () => isTransactionSuccessful,
55
+ isValidAccountId: () => isValidAccountId,
56
+ normalizeNetwork: () => normalizeNetwork,
57
+ parseFtTransferArgs: () => parseFtTransferArgs,
58
+ queryTokenBalance: () => queryTokenBalance,
59
+ queryTransaction: () => queryTransaction,
60
+ registerExactDirectNearClient: () => registerExactDirectNearClient,
61
+ registerExactDirectNearFacilitator: () => registerExactDirectNearFacilitator,
62
+ registerExactDirectNearServer: () => registerExactDirectNearServer,
63
+ rpcCall: () => rpcCall,
64
+ toTokenUnits: () => toTokenUnits
65
+ });
66
+ module.exports = __toCommonJS(src_exports);
67
+
68
+ // src/constants.ts
69
+ var NEAR_MAINNET_CAIP2 = "near:mainnet";
70
+ var NEAR_TESTNET_CAIP2 = "near:testnet";
71
+ var NEAR_NETWORKS = [NEAR_MAINNET_CAIP2, NEAR_TESTNET_CAIP2];
72
+ var NEAR_NETWORK_IDS = {
73
+ [NEAR_MAINNET_CAIP2]: "mainnet",
74
+ [NEAR_TESTNET_CAIP2]: "testnet"
75
+ };
76
+ var NEAR_MAINNET_RPC = "https://rpc.mainnet.near.org";
77
+ var NEAR_TESTNET_RPC = "https://rpc.testnet.near.org";
78
+ var NETWORK_RPC_ENDPOINTS = {
79
+ [NEAR_MAINNET_CAIP2]: NEAR_MAINNET_RPC,
80
+ [NEAR_TESTNET_CAIP2]: NEAR_TESTNET_RPC
81
+ };
82
+ var NEP141_FT_TRANSFER = "ft_transfer";
83
+ var NEP141_FT_BALANCE_OF = "ft_balance_of";
84
+ var NEP141_STORAGE_DEPOSIT = "storage_deposit";
85
+ var NEP141_STORAGE_BALANCE_OF = "storage_balance_of";
86
+ var DEFAULT_FT_TRANSFER_GAS = "30000000000000";
87
+ var DEFAULT_STORAGE_DEPOSIT_GAS = "10000000000000";
88
+ var FT_TRANSFER_DEPOSIT = "1";
89
+ var DEFAULT_STORAGE_DEPOSIT = "1250000000000000000000";
90
+ var SCHEME_EXACT_DIRECT = "exact-direct";
91
+ var DEFAULT_VALIDITY_DURATION = 3600;
92
+ var MAX_TRANSACTION_AGE = 5 * 60 * 1e3;
93
+ var NEAR_CAIP2_NAMESPACE = "near";
94
+
95
+ // src/tokens.ts
96
+ var TOKEN_REGISTRY = {
97
+ [NEAR_MAINNET_CAIP2]: [
98
+ {
99
+ // USDC on NEAR (Rainbow Bridge)
100
+ contractId: "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
101
+ symbol: "USDC",
102
+ name: "USD Coin",
103
+ decimals: 6,
104
+ priority: 1
105
+ },
106
+ {
107
+ // USDT on NEAR
108
+ contractId: "usdt.tether-token.near",
109
+ symbol: "USDT",
110
+ name: "Tether USD",
111
+ decimals: 6,
112
+ priority: 2
113
+ }
114
+ ],
115
+ [NEAR_TESTNET_CAIP2]: [
116
+ {
117
+ // Fake USDC on testnet
118
+ contractId: "usdc.fakes.testnet",
119
+ symbol: "USDC",
120
+ name: "USD Coin (Testnet)",
121
+ decimals: 6,
122
+ priority: 1
123
+ }
124
+ ]
125
+ };
126
+ function getTokenConfig(network, symbol) {
127
+ const tokens = TOKEN_REGISTRY[network];
128
+ if (!tokens) return void 0;
129
+ return tokens.find((t) => t.symbol.toUpperCase() === symbol.toUpperCase());
130
+ }
131
+ function getTokenByContract(network, contractId) {
132
+ const tokens = TOKEN_REGISTRY[network];
133
+ if (!tokens) return void 0;
134
+ return tokens.find((t) => t.contractId === contractId);
135
+ }
136
+ function getDefaultToken(network) {
137
+ const tokens = TOKEN_REGISTRY[network];
138
+ if (!tokens || tokens.length === 0) return void 0;
139
+ return [...tokens].sort((a, b) => a.priority - b.priority)[0];
140
+ }
141
+ function getNetworkTokens(network) {
142
+ return TOKEN_REGISTRY[network] || [];
143
+ }
144
+ function isNetworkSupported(network) {
145
+ return network in TOKEN_REGISTRY;
146
+ }
147
+
148
+ // src/utils.ts
149
+ function normalizeNetwork(network) {
150
+ if (network.startsWith(`${NEAR_CAIP2_NAMESPACE}:`)) {
151
+ return network;
152
+ }
153
+ return `${NEAR_CAIP2_NAMESPACE}:${network}`;
154
+ }
155
+ function extractNetworkId(network) {
156
+ if (network.includes(":")) {
157
+ return network.split(":")[1];
158
+ }
159
+ return network;
160
+ }
161
+ function isValidAccountId(accountId) {
162
+ if (!accountId || accountId.length < 2 || accountId.length > 64) {
163
+ return false;
164
+ }
165
+ const regex = /^[a-z0-9]([a-z0-9_-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9_-]*[a-z0-9])?)*$/;
166
+ return regex.test(accountId);
167
+ }
168
+ function getRpcEndpoint(network) {
169
+ const normalizedNetwork = normalizeNetwork(network);
170
+ return NETWORK_RPC_ENDPOINTS[normalizedNetwork] || NETWORK_RPC_ENDPOINTS["near:mainnet"];
171
+ }
172
+ async function rpcCall(network, method, params) {
173
+ const endpoint = getRpcEndpoint(network);
174
+ const request = {
175
+ jsonrpc: "2.0",
176
+ id: `t402-${Date.now()}`,
177
+ method,
178
+ params
179
+ };
180
+ const response = await fetch(endpoint, {
181
+ method: "POST",
182
+ headers: { "Content-Type": "application/json" },
183
+ body: JSON.stringify(request)
184
+ });
185
+ const data = await response.json();
186
+ if (data.error) {
187
+ throw new Error(`NEAR RPC error: ${data.error.message}`);
188
+ }
189
+ return data.result;
190
+ }
191
+ async function queryTransaction(network, txHash, senderAccountId) {
192
+ return rpcCall(network, "tx", [txHash, senderAccountId]);
193
+ }
194
+ async function queryTokenBalance(network, accountId, tokenContract) {
195
+ try {
196
+ const result = await rpcCall(network, "query", {
197
+ request_type: "call_function",
198
+ finality: "final",
199
+ account_id: tokenContract,
200
+ method_name: "ft_balance_of",
201
+ args_base64: btoa(JSON.stringify({ account_id: accountId }))
202
+ });
203
+ const bytes = new Uint8Array(result.result);
204
+ const text = new TextDecoder().decode(bytes);
205
+ const balance = text.replace(/"/g, "");
206
+ return BigInt(balance);
207
+ } catch (error) {
208
+ console.error("Error fetching token balance:", error);
209
+ return 0n;
210
+ }
211
+ }
212
+ function parseFtTransferArgs(argsBase64) {
213
+ try {
214
+ const argsJson = atob(argsBase64);
215
+ return JSON.parse(argsJson);
216
+ } catch {
217
+ try {
218
+ return JSON.parse(argsBase64);
219
+ } catch {
220
+ return null;
221
+ }
222
+ }
223
+ }
224
+ function isTransactionSuccessful(status) {
225
+ return status.SuccessValue !== void 0 && status.Failure === void 0;
226
+ }
227
+ function formatAmount(amount, decimals) {
228
+ const divisor = BigInt(10 ** decimals);
229
+ const whole = amount / divisor;
230
+ const remainder = amount % divisor;
231
+ const decimal = remainder.toString().padStart(decimals, "0").slice(0, 2);
232
+ return `${whole}.${decimal}`;
233
+ }
234
+ function toTokenUnits(decimalAmount, decimals) {
235
+ const amount = typeof decimalAmount === "string" ? parseFloat(decimalAmount) : decimalAmount;
236
+ if (isNaN(amount)) {
237
+ throw new Error(`Invalid amount: ${decimalAmount}`);
238
+ }
239
+ const multiplier = 10 ** decimals;
240
+ return BigInt(Math.floor(amount * multiplier));
241
+ }
242
+
243
+ // src/exact-direct/client/scheme.ts
244
+ var ExactDirectNearClient = class {
245
+ /**
246
+ * Creates a new ExactDirectNearScheme instance.
247
+ *
248
+ * @param signer - The NEAR signer for client operations
249
+ * @param config - Optional configuration overrides
250
+ */
251
+ constructor(signer, config = {}) {
252
+ this.signer = signer;
253
+ this.config = config;
254
+ this.scheme = SCHEME_EXACT_DIRECT;
255
+ }
256
+ /**
257
+ * Creates a payment payload by executing the transfer.
258
+ *
259
+ * Unlike other schemes where the client creates a signed message for
260
+ * the facilitator to execute, the exact-direct scheme has the client
261
+ * execute the transfer directly. The transaction hash is then used
262
+ * as proof of payment.
263
+ *
264
+ * @param t402Version - The t402 protocol version
265
+ * @param paymentRequirements - The payment requirements
266
+ * @returns Promise resolving to a payment payload with transaction hash
267
+ */
268
+ async createPaymentPayload(t402Version, paymentRequirements) {
269
+ normalizeNetwork(paymentRequirements.network);
270
+ if (!paymentRequirements.asset) {
271
+ throw new Error("Asset (token contract address) is required");
272
+ }
273
+ if (!paymentRequirements.payTo) {
274
+ throw new Error("PayTo address is required");
275
+ }
276
+ if (!paymentRequirements.amount) {
277
+ throw new Error("Amount is required");
278
+ }
279
+ if (!isValidAccountId(paymentRequirements.payTo)) {
280
+ throw new Error(`Invalid recipient account ID: ${paymentRequirements.payTo}`);
281
+ }
282
+ if (!isValidAccountId(this.signer.accountId)) {
283
+ throw new Error(`Invalid sender account ID: ${this.signer.accountId}`);
284
+ }
285
+ const tokenContract = paymentRequirements.asset;
286
+ const recipient = paymentRequirements.payTo;
287
+ const amount = paymentRequirements.amount;
288
+ const ftTransferArgs = {
289
+ receiver_id: recipient,
290
+ amount
291
+ };
292
+ if (this.config.memo) {
293
+ ftTransferArgs.memo = this.config.memo;
294
+ }
295
+ const txHash = await this.signer.signAndSendTransaction(
296
+ tokenContract,
297
+ "ft_transfer",
298
+ ftTransferArgs,
299
+ this.config.gasAmount || DEFAULT_FT_TRANSFER_GAS,
300
+ FT_TRANSFER_DEPOSIT
301
+ );
302
+ const payload = {
303
+ txHash,
304
+ from: this.signer.accountId,
305
+ to: recipient,
306
+ amount
307
+ };
308
+ return {
309
+ t402Version,
310
+ payload
311
+ };
312
+ }
313
+ };
314
+
315
+ // src/exact-direct/client/register.ts
316
+ function registerExactDirectNearClient(client, config) {
317
+ const scheme = new ExactDirectNearClient(config.signer, config.schemeConfig);
318
+ if (config.networks && config.networks.length > 0) {
319
+ config.networks.forEach((network) => {
320
+ client.register(network, scheme);
321
+ });
322
+ } else {
323
+ client.register("near:*", scheme);
324
+ }
325
+ if (config.policies) {
326
+ config.policies.forEach((policy) => {
327
+ client.registerPolicy(policy);
328
+ });
329
+ }
330
+ return client;
331
+ }
332
+
333
+ // src/exact-direct/server/scheme.ts
334
+ var ExactDirectNearServer = class {
335
+ constructor(config = {}) {
336
+ this.scheme = SCHEME_EXACT_DIRECT;
337
+ this.moneyParsers = [];
338
+ this.config = config;
339
+ }
340
+ /**
341
+ * Register a custom money parser in the parser chain.
342
+ * Multiple parsers can be registered - they will be tried in registration order.
343
+ * Each parser receives a decimal amount (e.g., 1.50 for $1.50).
344
+ * If a parser returns null, the next parser in the chain will be tried.
345
+ * The default parser is always the final fallback.
346
+ *
347
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
348
+ * @returns The server instance for chaining
349
+ */
350
+ registerMoneyParser(parser) {
351
+ this.moneyParsers.push(parser);
352
+ return this;
353
+ }
354
+ /**
355
+ * Parses a price into an asset amount.
356
+ * If price is already an AssetAmount, returns it directly.
357
+ * If price is Money (string | number), parses to decimal and tries custom parsers.
358
+ * Falls back to default conversion if all custom parsers return null.
359
+ *
360
+ * @param price - The price to parse
361
+ * @param network - The network to use
362
+ * @returns Promise that resolves to the parsed asset amount
363
+ */
364
+ async parsePrice(price, network) {
365
+ const normalizedNetwork = normalizeNetwork(network);
366
+ if (typeof price === "object" && price !== null && "amount" in price) {
367
+ if (!price.asset) {
368
+ throw new Error(`Asset address must be specified for AssetAmount on network ${network}`);
369
+ }
370
+ return {
371
+ amount: price.amount,
372
+ asset: price.asset,
373
+ extra: price.extra || {}
374
+ };
375
+ }
376
+ const amount = this.parseMoneyToDecimal(price);
377
+ for (const parser of this.moneyParsers) {
378
+ const result = await parser(amount, normalizedNetwork);
379
+ if (result !== null) {
380
+ return result;
381
+ }
382
+ }
383
+ return this.defaultMoneyConversion(amount, normalizedNetwork);
384
+ }
385
+ /**
386
+ * Build payment requirements for this scheme/network combination.
387
+ *
388
+ * @param paymentRequirements - Base payment requirements with amount/asset already set
389
+ * @param supportedKind - The supported kind from facilitator's /supported endpoint
390
+ * @param extensionKeys - Extensions supported by the facilitator
391
+ * @returns Enhanced payment requirements ready to be sent to clients
392
+ */
393
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
394
+ void extensionKeys;
395
+ const extra = { ...paymentRequirements.extra };
396
+ if (supportedKind.extra?.assetSymbol) {
397
+ extra.assetSymbol = supportedKind.extra.assetSymbol;
398
+ }
399
+ if (supportedKind.extra?.assetDecimals) {
400
+ extra.assetDecimals = supportedKind.extra.assetDecimals;
401
+ }
402
+ return {
403
+ ...paymentRequirements,
404
+ extra
405
+ };
406
+ }
407
+ /**
408
+ * Parse Money (string | number) to a decimal number.
409
+ * Handles formats like "$1.50", "1.50", 1.50, etc.
410
+ */
411
+ parseMoneyToDecimal(money) {
412
+ if (typeof money === "number") {
413
+ return money;
414
+ }
415
+ const cleanMoney = money.replace(/^\$/, "").trim();
416
+ const amount = parseFloat(cleanMoney);
417
+ if (isNaN(amount)) {
418
+ throw new Error(`Invalid money format: ${money}`);
419
+ }
420
+ return amount;
421
+ }
422
+ /**
423
+ * Default money conversion implementation.
424
+ * Converts decimal amount to the preferred token on the specified network.
425
+ */
426
+ defaultMoneyConversion(amount, network) {
427
+ const token = this.getDefaultAsset(network);
428
+ const tokenAmount = toTokenUnits(amount, token.decimals);
429
+ return {
430
+ amount: tokenAmount.toString(),
431
+ asset: token.contractId,
432
+ extra: {
433
+ symbol: token.symbol,
434
+ name: token.name,
435
+ decimals: token.decimals
436
+ }
437
+ };
438
+ }
439
+ /**
440
+ * Get the default asset info for a network.
441
+ * Priority: configured preferredToken > network default
442
+ */
443
+ getDefaultAsset(network) {
444
+ if (this.config.preferredToken) {
445
+ const preferred = getTokenConfig(network, this.config.preferredToken);
446
+ if (preferred) return preferred;
447
+ }
448
+ const defaultToken = getDefaultToken(network);
449
+ if (defaultToken) return defaultToken;
450
+ throw new Error(`No tokens configured for network ${network}`);
451
+ }
452
+ /**
453
+ * Get all supported networks
454
+ */
455
+ static getSupportedNetworks() {
456
+ return Object.keys(TOKEN_REGISTRY);
457
+ }
458
+ /**
459
+ * Check if a network is supported
460
+ */
461
+ static isNetworkSupported(network) {
462
+ return network in TOKEN_REGISTRY;
463
+ }
464
+ };
465
+
466
+ // src/exact-direct/server/register.ts
467
+ function registerExactDirectNearServer(server, config = {}) {
468
+ const scheme = new ExactDirectNearServer(config.schemeConfig);
469
+ if (config.networks && config.networks.length > 0) {
470
+ config.networks.forEach((network) => {
471
+ server.register(network, scheme);
472
+ });
473
+ } else {
474
+ server.register("near:*", scheme);
475
+ }
476
+ return server;
477
+ }
478
+
479
+ // src/exact-direct/facilitator/scheme.ts
480
+ var ExactDirectNearFacilitator = class {
481
+ constructor(signer, config) {
482
+ this.signer = signer;
483
+ this.scheme = SCHEME_EXACT_DIRECT;
484
+ this.caipFamily = `${NEAR_CAIP2_NAMESPACE}:*`;
485
+ this.usedTxs = /* @__PURE__ */ new Map();
486
+ this.config = {
487
+ maxTransactionAge: config?.maxTransactionAge ?? MAX_TRANSACTION_AGE,
488
+ usedTxCacheDuration: config?.usedTxCacheDuration ?? 24 * 60 * 60 * 1e3
489
+ // 24 hours
490
+ };
491
+ this.startCleanupInterval();
492
+ }
493
+ /**
494
+ * Get extra data for a supported kind
495
+ */
496
+ getExtra(network) {
497
+ const token = getDefaultToken(network);
498
+ if (!token) {
499
+ return void 0;
500
+ }
501
+ return {
502
+ assetSymbol: token.symbol,
503
+ assetDecimals: token.decimals
504
+ };
505
+ }
506
+ /**
507
+ * Get signer addresses for a network
508
+ */
509
+ getSigners(network) {
510
+ return this.signer.getAddresses(network);
511
+ }
512
+ /**
513
+ * Verify a payment payload
514
+ */
515
+ async verify(payload, requirements) {
516
+ const network = normalizeNetwork(requirements.network);
517
+ if (payload.accepted.scheme !== SCHEME_EXACT_DIRECT) {
518
+ return {
519
+ isValid: false,
520
+ invalidReason: "invalid_scheme"
521
+ };
522
+ }
523
+ if (normalizeNetwork(payload.accepted.network) !== network) {
524
+ return {
525
+ isValid: false,
526
+ invalidReason: "network_mismatch"
527
+ };
528
+ }
529
+ const nearPayload = payload.payload;
530
+ if (!nearPayload.txHash) {
531
+ return {
532
+ isValid: false,
533
+ invalidReason: "missing_tx_hash"
534
+ };
535
+ }
536
+ if (!nearPayload.from || !isValidAccountId(nearPayload.from)) {
537
+ return {
538
+ isValid: false,
539
+ invalidReason: "invalid_from_address"
540
+ };
541
+ }
542
+ if (this.isTxUsed(nearPayload.txHash)) {
543
+ return {
544
+ isValid: false,
545
+ invalidReason: "transaction_already_used",
546
+ payer: nearPayload.from
547
+ };
548
+ }
549
+ try {
550
+ const tx = await this.signer.queryTransaction(nearPayload.txHash, nearPayload.from);
551
+ if (!isTransactionSuccessful(tx.status)) {
552
+ return {
553
+ isValid: false,
554
+ invalidReason: "transaction_failed",
555
+ payer: nearPayload.from
556
+ };
557
+ }
558
+ if (tx.transaction.receiver_id !== requirements.asset) {
559
+ return {
560
+ isValid: false,
561
+ invalidReason: "wrong_token_contract",
562
+ payer: nearPayload.from
563
+ };
564
+ }
565
+ let ftTransferArgs = null;
566
+ for (const action of tx.transaction.actions) {
567
+ if (action.FunctionCall?.method_name === "ft_transfer") {
568
+ ftTransferArgs = parseFtTransferArgs(action.FunctionCall.args);
569
+ break;
570
+ }
571
+ }
572
+ if (!ftTransferArgs) {
573
+ return {
574
+ isValid: false,
575
+ invalidReason: "no_ft_transfer_action",
576
+ payer: nearPayload.from
577
+ };
578
+ }
579
+ if (ftTransferArgs.receiver_id !== requirements.payTo) {
580
+ return {
581
+ isValid: false,
582
+ invalidReason: "wrong_recipient",
583
+ payer: nearPayload.from
584
+ };
585
+ }
586
+ const txAmount = BigInt(ftTransferArgs.amount);
587
+ const requiredAmount = BigInt(requirements.amount);
588
+ if (txAmount < requiredAmount) {
589
+ return {
590
+ isValid: false,
591
+ invalidReason: "insufficient_amount",
592
+ payer: nearPayload.from
593
+ };
594
+ }
595
+ this.markTxUsed(nearPayload.txHash);
596
+ return {
597
+ isValid: true,
598
+ payer: nearPayload.from
599
+ };
600
+ } catch {
601
+ return {
602
+ isValid: false,
603
+ invalidReason: "transaction_not_found",
604
+ payer: nearPayload.from
605
+ };
606
+ }
607
+ }
608
+ /**
609
+ * Settle a payment - for exact-direct, the transfer is already complete
610
+ */
611
+ async settle(payload, requirements) {
612
+ const verifyResult = await this.verify(payload, requirements);
613
+ if (!verifyResult.isValid) {
614
+ return {
615
+ success: false,
616
+ errorReason: verifyResult.invalidReason || "verification_failed",
617
+ payer: verifyResult.payer,
618
+ transaction: "",
619
+ network: normalizeNetwork(requirements.network)
620
+ };
621
+ }
622
+ const nearPayload = payload.payload;
623
+ return {
624
+ success: true,
625
+ transaction: nearPayload.txHash,
626
+ network: normalizeNetwork(requirements.network),
627
+ payer: nearPayload.from
628
+ };
629
+ }
630
+ /**
631
+ * Check if a transaction has been used
632
+ */
633
+ isTxUsed(txHash) {
634
+ return this.usedTxs.has(txHash);
635
+ }
636
+ /**
637
+ * Mark a transaction as used
638
+ */
639
+ markTxUsed(txHash) {
640
+ this.usedTxs.set(txHash, Date.now());
641
+ }
642
+ /**
643
+ * Start the cleanup interval for used transactions
644
+ */
645
+ startCleanupInterval() {
646
+ setInterval(
647
+ () => {
648
+ const cutoff = Date.now() - this.config.usedTxCacheDuration;
649
+ for (const [txHash, usedAt] of this.usedTxs.entries()) {
650
+ if (usedAt < cutoff) {
651
+ this.usedTxs.delete(txHash);
652
+ }
653
+ }
654
+ },
655
+ 60 * 60 * 1e3
656
+ );
657
+ }
658
+ };
659
+
660
+ // src/exact-direct/facilitator/register.ts
661
+ function registerExactDirectNearFacilitator(facilitator, config) {
662
+ const scheme = new ExactDirectNearFacilitator(config.signer, config.schemeConfig);
663
+ facilitator.register(config.networks, scheme);
664
+ return facilitator;
665
+ }
666
+ // Annotate the CommonJS export names for ESM import in node:
667
+ 0 && (module.exports = {
668
+ DEFAULT_FT_TRANSFER_GAS,
669
+ DEFAULT_STORAGE_DEPOSIT,
670
+ DEFAULT_STORAGE_DEPOSIT_GAS,
671
+ DEFAULT_VALIDITY_DURATION,
672
+ ExactDirectNearClient,
673
+ ExactDirectNearFacilitator,
674
+ ExactDirectNearServer,
675
+ FT_TRANSFER_DEPOSIT,
676
+ MAX_TRANSACTION_AGE,
677
+ NEAR_CAIP2_NAMESPACE,
678
+ NEAR_MAINNET_CAIP2,
679
+ NEAR_MAINNET_RPC,
680
+ NEAR_NETWORKS,
681
+ NEAR_NETWORK_IDS,
682
+ NEAR_TESTNET_CAIP2,
683
+ NEAR_TESTNET_RPC,
684
+ NEP141_FT_BALANCE_OF,
685
+ NEP141_FT_TRANSFER,
686
+ NEP141_STORAGE_BALANCE_OF,
687
+ NEP141_STORAGE_DEPOSIT,
688
+ NETWORK_RPC_ENDPOINTS,
689
+ SCHEME_EXACT_DIRECT,
690
+ TOKEN_REGISTRY,
691
+ extractNetworkId,
692
+ formatAmount,
693
+ getDefaultToken,
694
+ getNetworkTokens,
695
+ getRpcEndpoint,
696
+ getTokenByContract,
697
+ getTokenConfig,
698
+ isNetworkSupported,
699
+ isTransactionSuccessful,
700
+ isValidAccountId,
701
+ normalizeNetwork,
702
+ parseFtTransferArgs,
703
+ queryTokenBalance,
704
+ queryTransaction,
705
+ registerExactDirectNearClient,
706
+ registerExactDirectNearFacilitator,
707
+ registerExactDirectNearServer,
708
+ rpcCall,
709
+ toTokenUnits
710
+ });
711
+ //# sourceMappingURL=index.js.map