@t402/ton 2.0.0 → 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/dist/cjs/exact/client/index.d.ts +63 -4
  2. package/dist/cjs/exact/client/index.js +29 -3
  3. package/dist/cjs/exact/client/index.js.map +1 -1
  4. package/dist/cjs/exact/facilitator/index.d.ts +63 -3
  5. package/dist/cjs/exact/facilitator/index.js +31 -4
  6. package/dist/cjs/exact/facilitator/index.js.map +1 -1
  7. package/dist/cjs/exact/server/index.d.ts +42 -17
  8. package/dist/cjs/exact/server/index.js +22 -40
  9. package/dist/cjs/exact/server/index.js.map +1 -1
  10. package/dist/cjs/index.d.ts +7 -2
  11. package/dist/cjs/index.js +496 -13
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/{signer-CFiw2DST.d.ts → signer-Bqn2K0b4.d.ts} +1 -1
  14. package/dist/esm/{chunk-6LOUEHJT.mjs → chunk-3BN2G4M7.mjs} +6 -1
  15. package/dist/esm/chunk-3BN2G4M7.mjs.map +1 -0
  16. package/dist/esm/{chunk-ZCMWKFVA.mjs → chunk-7OE2PWYP.mjs} +28 -4
  17. package/dist/esm/chunk-7OE2PWYP.mjs.map +1 -0
  18. package/dist/esm/chunk-NGYEU24R.mjs +271 -0
  19. package/dist/esm/chunk-NGYEU24R.mjs.map +1 -0
  20. package/dist/esm/chunk-ZJA7AWWH.mjs +284 -0
  21. package/dist/esm/chunk-ZJA7AWWH.mjs.map +1 -0
  22. package/dist/esm/exact/client/index.d.mts +63 -4
  23. package/dist/esm/exact/client/index.mjs +6 -4
  24. package/dist/esm/exact/facilitator/index.d.mts +63 -3
  25. package/dist/esm/exact/facilitator/index.mjs +6 -254
  26. package/dist/esm/exact/facilitator/index.mjs.map +1 -1
  27. package/dist/esm/exact/server/index.d.mts +42 -17
  28. package/dist/esm/exact/server/index.mjs +6 -208
  29. package/dist/esm/exact/server/index.mjs.map +1 -1
  30. package/dist/esm/index.d.mts +7 -2
  31. package/dist/esm/index.mjs +13 -5
  32. package/dist/esm/index.mjs.map +1 -1
  33. package/dist/esm/{signer-CFiw2DST.d.mts → signer-Bqn2K0b4.d.mts} +1 -1
  34. package/package.json +8 -7
  35. package/dist/esm/chunk-6LOUEHJT.mjs.map +0 -1
  36. package/dist/esm/chunk-RST5PY7E.mjs +0 -85
  37. package/dist/esm/chunk-RST5PY7E.mjs.map +0 -1
  38. package/dist/esm/chunk-ZCMWKFVA.mjs.map +0 -1
@@ -0,0 +1,271 @@
1
+ import {
2
+ SCHEME_EXACT,
3
+ TON_MAINNET_CAIP2,
4
+ TON_TESTNET_CAIP2,
5
+ __publicField,
6
+ normalizeNetwork
7
+ } from "./chunk-3BN2G4M7.mjs";
8
+
9
+ // src/tokens.ts
10
+ var USDT_ADDRESSES = {
11
+ // TON Mainnet - Official Tether USDT
12
+ [TON_MAINNET_CAIP2]: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
13
+ // TON Testnet - Test USDT (may vary)
14
+ [TON_TESTNET_CAIP2]: "kQBqSpvo4S87mX9tTc4FX3Sfqf4uSp3Tx-Fz4RBUfTRWBx"
15
+ };
16
+ var JETTON_REGISTRY = {
17
+ // TON Mainnet
18
+ [TON_MAINNET_CAIP2]: {
19
+ USDT: {
20
+ masterAddress: USDT_ADDRESSES[TON_MAINNET_CAIP2],
21
+ symbol: "USDT",
22
+ name: "Tether USD",
23
+ decimals: 6,
24
+ priority: 1
25
+ }
26
+ },
27
+ // TON Testnet
28
+ [TON_TESTNET_CAIP2]: {
29
+ USDT: {
30
+ masterAddress: USDT_ADDRESSES[TON_TESTNET_CAIP2],
31
+ symbol: "USDT",
32
+ name: "Tether USD (Testnet)",
33
+ decimals: 6,
34
+ priority: 1
35
+ }
36
+ }
37
+ };
38
+ function getJettonConfig(network, symbol) {
39
+ return JETTON_REGISTRY[network]?.[symbol.toUpperCase()];
40
+ }
41
+ function getNetworkJettons(network) {
42
+ const jettons = JETTON_REGISTRY[network];
43
+ if (!jettons) return [];
44
+ return Object.values(jettons).sort((a, b) => a.priority - b.priority);
45
+ }
46
+ function getDefaultJetton(network) {
47
+ const jettons = getNetworkJettons(network);
48
+ return jettons[0];
49
+ }
50
+ function getJettonByAddress(network, address) {
51
+ const jettons = JETTON_REGISTRY[network];
52
+ if (!jettons) return void 0;
53
+ return Object.values(jettons).find((j) => j.masterAddress.toLowerCase() === address.toLowerCase());
54
+ }
55
+ function getNetworksForJetton(symbol) {
56
+ const networks = [];
57
+ for (const [network, jettons] of Object.entries(JETTON_REGISTRY)) {
58
+ if (jettons[symbol.toUpperCase()]) {
59
+ networks.push(network);
60
+ }
61
+ }
62
+ return networks;
63
+ }
64
+ function getUsdtNetworks() {
65
+ return getNetworksForJetton("USDT");
66
+ }
67
+ function isNetworkSupported(network) {
68
+ return network in JETTON_REGISTRY;
69
+ }
70
+ function getSupportedNetworks() {
71
+ return Object.keys(JETTON_REGISTRY);
72
+ }
73
+
74
+ // src/exact/server/scheme.ts
75
+ var ExactTonScheme = class {
76
+ constructor(config = {}) {
77
+ __publicField(this, "scheme", SCHEME_EXACT);
78
+ __publicField(this, "moneyParsers", []);
79
+ __publicField(this, "config");
80
+ this.config = config;
81
+ }
82
+ /**
83
+ * Register a custom money parser in the parser chain.
84
+ * Multiple parsers can be registered - they will be tried in registration order.
85
+ * Each parser receives a decimal amount (e.g., 1.50 for $1.50).
86
+ * If a parser returns null, the next parser in the chain will be tried.
87
+ * The default parser is always the final fallback.
88
+ *
89
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
90
+ * @returns The server instance for chaining
91
+ *
92
+ * @example
93
+ * tonServer.registerMoneyParser(async (amount, network) => {
94
+ * // Use custom Jetton for large amounts
95
+ * if (amount > 1000) {
96
+ * return {
97
+ * amount: (amount * 1e9).toString(),
98
+ * asset: "EQCustomJettonAddress...",
99
+ * extra: { tier: "premium" }
100
+ * };
101
+ * }
102
+ * return null; // Use next parser
103
+ * });
104
+ */
105
+ registerMoneyParser(parser) {
106
+ this.moneyParsers.push(parser);
107
+ return this;
108
+ }
109
+ /**
110
+ * Parses a price into an asset amount.
111
+ * If price is already an AssetAmount, returns it directly.
112
+ * If price is Money (string | number), parses to decimal and tries custom parsers.
113
+ * Falls back to default conversion if all custom parsers return null.
114
+ *
115
+ * @param price - The price to parse
116
+ * @param network - The network to use
117
+ * @returns Promise that resolves to the parsed asset amount
118
+ */
119
+ async parsePrice(price, network) {
120
+ const normalizedNetwork = normalizeNetwork(network);
121
+ if (typeof price === "object" && price !== null && "amount" in price) {
122
+ if (!price.asset) {
123
+ throw new Error(`Asset address must be specified for AssetAmount on network ${network}`);
124
+ }
125
+ return {
126
+ amount: price.amount,
127
+ asset: price.asset,
128
+ extra: price.extra || {}
129
+ };
130
+ }
131
+ const amount = this.parseMoneyToDecimal(price);
132
+ for (const parser of this.moneyParsers) {
133
+ const result = await parser(amount, normalizedNetwork);
134
+ if (result !== null) {
135
+ return result;
136
+ }
137
+ }
138
+ return this.defaultMoneyConversion(amount, normalizedNetwork);
139
+ }
140
+ /**
141
+ * Build payment requirements for this scheme/network combination.
142
+ * Adds TON-specific fields like gas sponsor if provided by facilitator.
143
+ *
144
+ * @param paymentRequirements - Base payment requirements with amount/asset already set
145
+ * @param supportedKind - The supported kind from facilitator's /supported endpoint
146
+ * @param extensionKeys - Extensions supported by the facilitator (unused)
147
+ * @returns Enhanced payment requirements ready to be sent to clients
148
+ */
149
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
150
+ void extensionKeys;
151
+ const extra = { ...paymentRequirements.extra };
152
+ if (supportedKind.extra?.gasSponsor) {
153
+ extra.gasSponsor = supportedKind.extra.gasSponsor;
154
+ }
155
+ return {
156
+ ...paymentRequirements,
157
+ extra
158
+ };
159
+ }
160
+ /**
161
+ * Parse Money (string | number) to a decimal number.
162
+ * Handles formats like "$1.50", "1.50", 1.50, etc.
163
+ *
164
+ * @param money - The money value to parse
165
+ * @returns Decimal number
166
+ */
167
+ parseMoneyToDecimal(money) {
168
+ if (typeof money === "number") {
169
+ return money;
170
+ }
171
+ const cleanMoney = money.replace(/^\$/, "").trim();
172
+ const amount = parseFloat(cleanMoney);
173
+ if (isNaN(amount)) {
174
+ throw new Error(`Invalid money format: ${money}`);
175
+ }
176
+ return amount;
177
+ }
178
+ /**
179
+ * Default money conversion implementation.
180
+ * Converts decimal amount to the preferred Jetton on the specified network.
181
+ *
182
+ * @param amount - The decimal amount (e.g., 1.50)
183
+ * @param network - The network to use
184
+ * @returns The parsed asset amount
185
+ */
186
+ defaultMoneyConversion(amount, network) {
187
+ const jetton = this.getDefaultAsset(network);
188
+ const tokenAmount = this.convertToTokenAmount(amount.toString(), jetton.decimals);
189
+ return {
190
+ amount: tokenAmount,
191
+ asset: jetton.masterAddress,
192
+ extra: {
193
+ symbol: jetton.symbol,
194
+ name: jetton.name,
195
+ decimals: jetton.decimals
196
+ }
197
+ };
198
+ }
199
+ /**
200
+ * Convert decimal amount to token units (e.g., 0.10 -> 100000 for 6-decimal tokens)
201
+ *
202
+ * @param decimalAmount - The decimal amount to convert
203
+ * @param decimals - Number of decimals for the token
204
+ * @returns The token amount as a string
205
+ */
206
+ convertToTokenAmount(decimalAmount, decimals) {
207
+ const amount = parseFloat(decimalAmount);
208
+ if (isNaN(amount)) {
209
+ throw new Error(`Invalid amount: ${decimalAmount}`);
210
+ }
211
+ const tokenAmount = Math.floor(amount * Math.pow(10, decimals));
212
+ return tokenAmount.toString();
213
+ }
214
+ /**
215
+ * Get the default asset info for a network.
216
+ * Priority: configured preferredJetton > USDT > first available
217
+ *
218
+ * @param network - The network to get asset info for
219
+ * @returns The Jetton configuration
220
+ */
221
+ getDefaultAsset(network) {
222
+ if (this.config.preferredJetton) {
223
+ const preferred = getJettonConfig(network, this.config.preferredJetton);
224
+ if (preferred) return preferred;
225
+ }
226
+ const defaultJetton = getDefaultJetton(network);
227
+ if (defaultJetton) return defaultJetton;
228
+ throw new Error(`No Jettons configured for network ${network}`);
229
+ }
230
+ /**
231
+ * Get all supported networks
232
+ */
233
+ static getSupportedNetworks() {
234
+ return Object.keys(JETTON_REGISTRY);
235
+ }
236
+ /**
237
+ * Check if a network is supported
238
+ */
239
+ static isNetworkSupported(network) {
240
+ return network in JETTON_REGISTRY;
241
+ }
242
+ };
243
+
244
+ // src/exact/server/register.ts
245
+ function registerExactTonScheme(server, config = {}) {
246
+ const scheme = new ExactTonScheme(config.schemeConfig);
247
+ if (config.networks && config.networks.length > 0) {
248
+ config.networks.forEach((network) => {
249
+ server.register(network, scheme);
250
+ });
251
+ } else {
252
+ server.register("ton:*", scheme);
253
+ }
254
+ return server;
255
+ }
256
+
257
+ export {
258
+ USDT_ADDRESSES,
259
+ JETTON_REGISTRY,
260
+ getJettonConfig,
261
+ getNetworkJettons,
262
+ getDefaultJetton,
263
+ getJettonByAddress,
264
+ getNetworksForJetton,
265
+ getUsdtNetworks,
266
+ isNetworkSupported,
267
+ getSupportedNetworks,
268
+ ExactTonScheme,
269
+ registerExactTonScheme
270
+ };
271
+ //# sourceMappingURL=chunk-NGYEU24R.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tokens.ts","../../src/exact/server/scheme.ts","../../src/exact/server/register.ts"],"sourcesContent":["/**\n * TON Jetton Token Configuration\n *\n * This module provides comprehensive Jetton token definitions including:\n * - USDT (Tether USD on TON)\n * - Network-specific configurations\n * - Helper functions for token lookups\n */\n\nimport { TON_MAINNET_CAIP2, TON_TESTNET_CAIP2 } from './constants.js'\n\n/**\n * Jetton token configuration\n */\nexport interface JettonConfig {\n /** Jetton master contract address (friendly format) */\n masterAddress: string\n /** Token symbol */\n symbol: string\n /** Token name */\n name: string\n /** Number of decimal places */\n decimals: number\n /** Payment priority (lower = higher priority) */\n priority: number\n}\n\n/**\n * Network token registry mapping network -> symbol -> config\n */\nexport type NetworkJettonRegistry = Record<string, Record<string, JettonConfig>>\n\n/**\n * USDT Jetton Master Contract Addresses by Network\n *\n * USDT on TON follows the TEP-74 Jetton standard.\n * @see https://docs.tether.to/tether-on-ton\n */\nexport const USDT_ADDRESSES: Record<string, string> = {\n // TON Mainnet - Official Tether USDT\n [TON_MAINNET_CAIP2]: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',\n // TON Testnet - Test USDT (may vary)\n [TON_TESTNET_CAIP2]: 'kQBqSpvo4S87mX9tTc4FX3Sfqf4uSp3Tx-Fz4RBUfTRWBx',\n}\n\n/**\n * Complete Jetton registry with all supported tokens per network\n */\nexport const JETTON_REGISTRY: NetworkJettonRegistry = {\n // TON Mainnet\n [TON_MAINNET_CAIP2]: {\n USDT: {\n masterAddress: USDT_ADDRESSES[TON_MAINNET_CAIP2],\n symbol: 'USDT',\n name: 'Tether USD',\n decimals: 6,\n priority: 1,\n },\n },\n\n // TON Testnet\n [TON_TESTNET_CAIP2]: {\n USDT: {\n masterAddress: USDT_ADDRESSES[TON_TESTNET_CAIP2],\n symbol: 'USDT',\n name: 'Tether USD (Testnet)',\n decimals: 6,\n priority: 1,\n },\n },\n}\n\n/**\n * Get Jetton configuration for a specific token on a network\n *\n * @param network - Network identifier (CAIP-2 format)\n * @param symbol - Token symbol (e.g., \"USDT\")\n * @returns Jetton configuration or undefined\n */\nexport function getJettonConfig(network: string, symbol: string): JettonConfig | undefined {\n return JETTON_REGISTRY[network]?.[symbol.toUpperCase()]\n}\n\n/**\n * Get all Jettons available on a network\n *\n * @param network - Network identifier\n * @returns Array of Jetton configurations sorted by priority\n */\nexport function getNetworkJettons(network: string): JettonConfig[] {\n const jettons = JETTON_REGISTRY[network]\n if (!jettons) return []\n return Object.values(jettons).sort((a, b) => a.priority - b.priority)\n}\n\n/**\n * Get the default/preferred Jetton for a network\n * Prefers USDT based on priority\n *\n * @param network - Network identifier\n * @returns Default Jetton configuration or undefined\n */\nexport function getDefaultJetton(network: string): JettonConfig | undefined {\n const jettons = getNetworkJettons(network)\n return jettons[0] // Already sorted by priority\n}\n\n/**\n * Get Jetton by master contract address on a network\n *\n * @param network - Network identifier\n * @param address - Jetton master contract address\n * @returns Jetton configuration or undefined\n */\nexport function getJettonByAddress(network: string, address: string): JettonConfig | undefined {\n const jettons = JETTON_REGISTRY[network]\n if (!jettons) return undefined\n\n // Normalize address comparison (case-insensitive for base64)\n return Object.values(jettons).find((j) => j.masterAddress.toLowerCase() === address.toLowerCase())\n}\n\n/**\n * Get all networks that support a specific Jetton\n *\n * @param symbol - Token symbol\n * @returns Array of network identifiers\n */\nexport function getNetworksForJetton(symbol: string): string[] {\n const networks: string[] = []\n for (const [network, jettons] of Object.entries(JETTON_REGISTRY)) {\n if (jettons[symbol.toUpperCase()]) {\n networks.push(network)\n }\n }\n return networks\n}\n\n/**\n * Get USDT networks on TON\n *\n * @returns Array of networks supporting USDT\n */\nexport function getUsdtNetworks(): string[] {\n return getNetworksForJetton('USDT')\n}\n\n/**\n * Check if a network is supported\n *\n * @param network - Network identifier to check\n * @returns true if network has configured Jettons\n */\nexport function isNetworkSupported(network: string): boolean {\n return network in JETTON_REGISTRY\n}\n\n/**\n * Get all supported networks\n *\n * @returns Array of all supported network identifiers\n */\nexport function getSupportedNetworks(): string[] {\n return Object.keys(JETTON_REGISTRY)\n}\n","/**\n * TON Server Scheme Implementation\n *\n * Handles price parsing and payment requirement enhancement for\n * TON Jetton payments using the exact scheme.\n */\n\nimport type {\n AssetAmount,\n Network,\n PaymentRequirements,\n Price,\n SchemeNetworkServer,\n MoneyParser,\n} from '@t402/core/types'\nimport { SCHEME_EXACT } from '../../constants.js'\nimport { getDefaultJetton, getJettonConfig, JETTON_REGISTRY } from '../../tokens.js'\nimport { normalizeNetwork } from '../../utils.js'\n\n/**\n * Configuration options for ExactTonScheme server\n */\nexport interface ExactTonSchemeConfig {\n /** Preferred Jetton symbol (e.g., \"USDT\"). Defaults to network's highest priority token. */\n preferredJetton?: string\n}\n\n/**\n * TON server implementation for the Exact payment scheme.\n * Handles price parsing and converts user-friendly amounts to Jetton amounts.\n */\nexport class ExactTonScheme implements SchemeNetworkServer {\n readonly scheme = SCHEME_EXACT\n private moneyParsers: MoneyParser[] = []\n private config: ExactTonSchemeConfig\n\n constructor(config: ExactTonSchemeConfig = {}) {\n this.config = config\n }\n\n /**\n * Register a custom money parser in the parser chain.\n * Multiple parsers can be registered - they will be tried in registration order.\n * Each parser receives a decimal amount (e.g., 1.50 for $1.50).\n * If a parser returns null, the next parser in the chain will be tried.\n * The default parser is always the final fallback.\n *\n * @param parser - Custom function to convert amount to AssetAmount (or null to skip)\n * @returns The server instance for chaining\n *\n * @example\n * tonServer.registerMoneyParser(async (amount, network) => {\n * // Use custom Jetton for large amounts\n * if (amount > 1000) {\n * return {\n * amount: (amount * 1e9).toString(),\n * asset: \"EQCustomJettonAddress...\",\n * extra: { tier: \"premium\" }\n * };\n * }\n * return null; // Use next parser\n * });\n */\n registerMoneyParser(parser: MoneyParser): ExactTonScheme {\n this.moneyParsers.push(parser)\n return this\n }\n\n /**\n * Parses a price into an asset amount.\n * If price is already an AssetAmount, returns it directly.\n * If price is Money (string | number), parses to decimal and tries custom parsers.\n * Falls back to default conversion if all custom parsers return null.\n *\n * @param price - The price to parse\n * @param network - The network to use\n * @returns Promise that resolves to the parsed asset amount\n */\n async parsePrice(price: Price, network: Network): Promise<AssetAmount> {\n // Normalize network to CAIP-2 format\n const normalizedNetwork = normalizeNetwork(network)\n\n // If already an AssetAmount, return it directly\n if (typeof price === 'object' && price !== null && 'amount' in price) {\n if (!price.asset) {\n throw new Error(`Asset address must be specified for AssetAmount on network ${network}`)\n }\n return {\n amount: price.amount,\n asset: price.asset,\n extra: price.extra || {},\n }\n }\n\n // Parse Money to decimal number\n const amount = this.parseMoneyToDecimal(price)\n\n // Try each custom money parser in order\n for (const parser of this.moneyParsers) {\n const result = await parser(amount, normalizedNetwork)\n if (result !== null) {\n return result\n }\n }\n\n // All custom parsers returned null, use default conversion\n return this.defaultMoneyConversion(amount, normalizedNetwork)\n }\n\n /**\n * Build payment requirements for this scheme/network combination.\n * Adds TON-specific fields like gas sponsor if provided by facilitator.\n *\n * @param paymentRequirements - Base payment requirements with amount/asset already set\n * @param supportedKind - The supported kind from facilitator's /supported endpoint\n * @param extensionKeys - Extensions supported by the facilitator (unused)\n * @returns Enhanced payment requirements ready to be sent to clients\n */\n async enhancePaymentRequirements(\n paymentRequirements: PaymentRequirements,\n supportedKind: {\n t402Version: number\n scheme: string\n network: Network\n extra?: Record<string, unknown>\n },\n extensionKeys: string[],\n ): Promise<PaymentRequirements> {\n // Mark unused parameters to satisfy linter\n void extensionKeys\n\n // Start with existing extra fields\n const extra = { ...paymentRequirements.extra }\n\n // Add gas sponsor from facilitator if provided\n if (supportedKind.extra?.gasSponsor) {\n extra.gasSponsor = supportedKind.extra.gasSponsor\n }\n\n return {\n ...paymentRequirements,\n extra,\n }\n }\n\n /**\n * Parse Money (string | number) to a decimal number.\n * Handles formats like \"$1.50\", \"1.50\", 1.50, etc.\n *\n * @param money - The money value to parse\n * @returns Decimal number\n */\n private parseMoneyToDecimal(money: string | number): number {\n if (typeof money === 'number') {\n return money\n }\n\n // Remove $ sign and whitespace, then parse\n const cleanMoney = money.replace(/^\\$/, '').trim()\n const amount = parseFloat(cleanMoney)\n\n if (isNaN(amount)) {\n throw new Error(`Invalid money format: ${money}`)\n }\n\n return amount\n }\n\n /**\n * Default money conversion implementation.\n * Converts decimal amount to the preferred Jetton on the specified network.\n *\n * @param amount - The decimal amount (e.g., 1.50)\n * @param network - The network to use\n * @returns The parsed asset amount\n */\n private defaultMoneyConversion(amount: number, network: Network): AssetAmount {\n const jetton = this.getDefaultAsset(network)\n\n // Convert decimal amount to token amount\n const tokenAmount = this.convertToTokenAmount(amount.toString(), jetton.decimals)\n\n return {\n amount: tokenAmount,\n asset: jetton.masterAddress,\n extra: {\n symbol: jetton.symbol,\n name: jetton.name,\n decimals: jetton.decimals,\n },\n }\n }\n\n /**\n * Convert decimal amount to token units (e.g., 0.10 -> 100000 for 6-decimal tokens)\n *\n * @param decimalAmount - The decimal amount to convert\n * @param decimals - Number of decimals for the token\n * @returns The token amount as a string\n */\n private convertToTokenAmount(decimalAmount: string, decimals: number): string {\n const amount = parseFloat(decimalAmount)\n if (isNaN(amount)) {\n throw new Error(`Invalid amount: ${decimalAmount}`)\n }\n // Convert to smallest unit (e.g., for USDT with 6 decimals: 0.10 * 10^6 = 100000)\n const tokenAmount = Math.floor(amount * Math.pow(10, decimals))\n return tokenAmount.toString()\n }\n\n /**\n * Get the default asset info for a network.\n * Priority: configured preferredJetton > USDT > first available\n *\n * @param network - The network to get asset info for\n * @returns The Jetton configuration\n */\n private getDefaultAsset(network: Network): {\n masterAddress: string\n symbol: string\n name: string\n decimals: number\n } {\n // If a preferred Jetton is configured, try to use it\n if (this.config.preferredJetton) {\n const preferred = getJettonConfig(network, this.config.preferredJetton)\n if (preferred) return preferred\n }\n\n // Use the network's default token (sorted by priority)\n const defaultJetton = getDefaultJetton(network)\n if (defaultJetton) return defaultJetton\n\n throw new Error(`No Jettons configured for network ${network}`)\n }\n\n /**\n * Get all supported networks\n */\n static getSupportedNetworks(): string[] {\n return Object.keys(JETTON_REGISTRY)\n }\n\n /**\n * Check if a network is supported\n */\n static isNetworkSupported(network: string): boolean {\n return network in JETTON_REGISTRY\n }\n}\n","import { t402ResourceServer } from '@t402/core/server'\nimport { Network } from '@t402/core/types'\nimport { ExactTonScheme, ExactTonSchemeConfig } from './scheme.js'\n\n/**\n * Configuration options for registering TON schemes to an t402ResourceServer\n */\nexport interface TonResourceServerConfig {\n /**\n * Optional specific networks to register\n * If not provided, registers wildcard support (ton:*)\n */\n networks?: Network[]\n\n /**\n * Optional scheme configuration (preferred Jetton, etc.)\n */\n schemeConfig?: ExactTonSchemeConfig\n}\n\n/**\n * Registers TON exact payment schemes to an t402ResourceServer instance.\n *\n * This function registers:\n * - V2: ton:* wildcard scheme with ExactTonScheme (or specific networks if provided)\n *\n * @param server - The t402ResourceServer instance to register schemes to\n * @param config - Configuration for TON resource server registration\n * @returns The server instance for chaining\n *\n * @example\n * ```typescript\n * import { registerExactTonScheme } from \"@t402/ton/exact/server/register\";\n * import { t402ResourceServer } from \"@t402/core/server\";\n *\n * const server = new t402ResourceServer(facilitatorClient);\n * registerExactTonScheme(server, {});\n *\n * // Or with specific Jetton preference\n * registerExactTonScheme(server, {\n * schemeConfig: { preferredJetton: \"USDT\" }\n * });\n * ```\n */\nexport function registerExactTonScheme(\n server: t402ResourceServer,\n config: TonResourceServerConfig = {},\n): t402ResourceServer {\n const scheme = new ExactTonScheme(config.schemeConfig)\n\n // Register V2 scheme\n if (config.networks && config.networks.length > 0) {\n // Register specific networks\n config.networks.forEach((network) => {\n server.register(network, scheme)\n })\n } else {\n // Register wildcard for all TON networks\n server.register('ton:*', scheme)\n }\n\n return server\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,284 @@
1
+ import {
2
+ SCHEME_EXACT,
3
+ __publicField,
4
+ addressesEqual,
5
+ normalizeNetwork
6
+ } from "./chunk-3BN2G4M7.mjs";
7
+
8
+ // src/exact/facilitator/scheme.ts
9
+ import { Cell } from "@ton/core";
10
+ var ExactTonScheme = class {
11
+ /**
12
+ * Creates a new ExactTonScheme facilitator instance.
13
+ *
14
+ * @param signer - The TON signer for facilitator operations
15
+ * @param config - Optional configuration
16
+ */
17
+ constructor(signer, config = {}) {
18
+ this.signer = signer;
19
+ __publicField(this, "scheme", SCHEME_EXACT);
20
+ __publicField(this, "caipFamily", "ton:*");
21
+ __publicField(this, "config");
22
+ this.config = config;
23
+ }
24
+ /**
25
+ * Get mechanism-specific extra data for the supported kinds endpoint.
26
+ * For TON, optionally returns gas sponsor address if configured.
27
+ *
28
+ * @param network - The network identifier
29
+ * @returns Extra data object or undefined
30
+ */
31
+ getExtra(network) {
32
+ void network;
33
+ if (this.config.canSponsorGas) {
34
+ const addresses = this.signer.getAddresses();
35
+ if (addresses.length > 0) {
36
+ return {
37
+ gasSponsor: addresses[0]
38
+ };
39
+ }
40
+ }
41
+ return void 0;
42
+ }
43
+ /**
44
+ * Get signer addresses used by this facilitator.
45
+ * Returns all addresses this facilitator can use for operations.
46
+ *
47
+ * @param network - The network identifier
48
+ * @returns Array of facilitator addresses
49
+ */
50
+ getSigners(network) {
51
+ void network;
52
+ return [...this.signer.getAddresses()];
53
+ }
54
+ /**
55
+ * Verifies a payment payload.
56
+ *
57
+ * Performs comprehensive validation:
58
+ * 1. Scheme and network matching
59
+ * 2. BOC format validation
60
+ * 3. Message structure verification
61
+ * 4. Authorization expiry check
62
+ * 5. Balance verification
63
+ * 6. Amount and recipient validation
64
+ *
65
+ * @param payload - The payment payload to verify
66
+ * @param requirements - The payment requirements
67
+ * @returns Promise resolving to verification response
68
+ */
69
+ async verify(payload, requirements) {
70
+ const tonPayload = payload.payload;
71
+ if (!tonPayload?.authorization?.from || !tonPayload?.signedBoc) {
72
+ return {
73
+ isValid: false,
74
+ invalidReason: "invalid_payload_structure",
75
+ payer: ""
76
+ };
77
+ }
78
+ const authorization = tonPayload.authorization;
79
+ if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {
80
+ return {
81
+ isValid: false,
82
+ invalidReason: "unsupported_scheme",
83
+ payer: authorization.from
84
+ };
85
+ }
86
+ try {
87
+ const payloadNetwork = normalizeNetwork(payload.accepted.network);
88
+ const requirementsNetwork = normalizeNetwork(requirements.network);
89
+ if (payloadNetwork !== requirementsNetwork) {
90
+ return {
91
+ isValid: false,
92
+ invalidReason: "network_mismatch",
93
+ payer: authorization.from
94
+ };
95
+ }
96
+ } catch {
97
+ return {
98
+ isValid: false,
99
+ invalidReason: "invalid_network",
100
+ payer: authorization.from
101
+ };
102
+ }
103
+ try {
104
+ Cell.fromBase64(tonPayload.signedBoc);
105
+ } catch {
106
+ return {
107
+ isValid: false,
108
+ invalidReason: "invalid_boc_format",
109
+ payer: authorization.from
110
+ };
111
+ }
112
+ const verifyResult = await this.signer.verifyMessage({
113
+ signedBoc: tonPayload.signedBoc,
114
+ expectedFrom: authorization.from,
115
+ expectedTransfer: {
116
+ jettonAmount: BigInt(authorization.jettonAmount),
117
+ destination: requirements.payTo,
118
+ jettonMaster: requirements.asset
119
+ }
120
+ });
121
+ if (!verifyResult.valid) {
122
+ return {
123
+ isValid: false,
124
+ invalidReason: verifyResult.reason || "message_verification_failed",
125
+ payer: authorization.from
126
+ };
127
+ }
128
+ const now = Math.floor(Date.now() / 1e3);
129
+ if (authorization.validUntil < now + 30) {
130
+ return {
131
+ isValid: false,
132
+ invalidReason: "authorization_expired",
133
+ payer: authorization.from
134
+ };
135
+ }
136
+ try {
137
+ const balance = await this.signer.getJettonBalance({
138
+ ownerAddress: authorization.from,
139
+ jettonMasterAddress: requirements.asset
140
+ });
141
+ if (balance < BigInt(requirements.amount)) {
142
+ return {
143
+ isValid: false,
144
+ invalidReason: "insufficient_jetton_balance",
145
+ payer: authorization.from
146
+ };
147
+ }
148
+ } catch (error) {
149
+ console.warn("Could not verify Jetton balance:", error);
150
+ }
151
+ if (BigInt(authorization.jettonAmount) < BigInt(requirements.amount)) {
152
+ return {
153
+ isValid: false,
154
+ invalidReason: "insufficient_amount",
155
+ payer: authorization.from
156
+ };
157
+ }
158
+ if (!addressesEqual(authorization.to, requirements.payTo)) {
159
+ return {
160
+ isValid: false,
161
+ invalidReason: "recipient_mismatch",
162
+ payer: authorization.from
163
+ };
164
+ }
165
+ if (!addressesEqual(authorization.jettonMaster, requirements.asset)) {
166
+ return {
167
+ isValid: false,
168
+ invalidReason: "asset_mismatch",
169
+ payer: authorization.from
170
+ };
171
+ }
172
+ try {
173
+ const currentSeqno = await this.signer.getSeqno(authorization.from);
174
+ if (authorization.seqno < currentSeqno) {
175
+ return {
176
+ isValid: false,
177
+ invalidReason: "seqno_already_used",
178
+ payer: authorization.from
179
+ };
180
+ }
181
+ if (authorization.seqno > currentSeqno) {
182
+ return {
183
+ isValid: false,
184
+ invalidReason: "seqno_too_high",
185
+ payer: authorization.from
186
+ };
187
+ }
188
+ } catch (error) {
189
+ console.warn("Could not verify seqno:", error);
190
+ }
191
+ try {
192
+ const isDeployed = await this.signer.isDeployed(authorization.from);
193
+ if (!isDeployed) {
194
+ return {
195
+ isValid: false,
196
+ invalidReason: "wallet_not_deployed",
197
+ payer: authorization.from
198
+ };
199
+ }
200
+ } catch (error) {
201
+ console.warn("Could not verify wallet deployment:", error);
202
+ }
203
+ return {
204
+ isValid: true,
205
+ invalidReason: void 0,
206
+ payer: authorization.from
207
+ };
208
+ }
209
+ /**
210
+ * Settles a payment by broadcasting the signed message.
211
+ *
212
+ * @param payload - The payment payload to settle
213
+ * @param requirements - The payment requirements
214
+ * @returns Promise resolving to settlement response
215
+ */
216
+ async settle(payload, requirements) {
217
+ const tonPayload = payload.payload;
218
+ if (!tonPayload?.authorization?.from || !tonPayload?.signedBoc) {
219
+ return {
220
+ success: false,
221
+ network: payload.accepted.network,
222
+ transaction: "",
223
+ errorReason: "invalid_payload_structure",
224
+ payer: ""
225
+ };
226
+ }
227
+ const verifyResult = await this.verify(payload, requirements);
228
+ if (!verifyResult.isValid) {
229
+ return {
230
+ success: false,
231
+ network: payload.accepted.network,
232
+ transaction: "",
233
+ errorReason: verifyResult.invalidReason ?? "verification_failed",
234
+ payer: tonPayload.authorization.from
235
+ };
236
+ }
237
+ try {
238
+ const txHash = await this.signer.sendExternalMessage(tonPayload.signedBoc);
239
+ const confirmation = await this.signer.waitForTransaction({
240
+ address: tonPayload.authorization.from,
241
+ seqno: tonPayload.authorization.seqno + 1,
242
+ // Wait for next seqno
243
+ timeout: 6e4
244
+ // 60 second timeout
245
+ });
246
+ if (!confirmation.success) {
247
+ return {
248
+ success: false,
249
+ errorReason: confirmation.error || "transaction_not_confirmed",
250
+ transaction: txHash,
251
+ network: payload.accepted.network,
252
+ payer: tonPayload.authorization.from
253
+ };
254
+ }
255
+ return {
256
+ success: true,
257
+ transaction: confirmation.hash || txHash,
258
+ network: payload.accepted.network,
259
+ payer: tonPayload.authorization.from
260
+ };
261
+ } catch (error) {
262
+ console.error("Failed to settle TON transaction:", error);
263
+ return {
264
+ success: false,
265
+ errorReason: "transaction_failed",
266
+ transaction: "",
267
+ network: payload.accepted.network,
268
+ payer: tonPayload.authorization.from
269
+ };
270
+ }
271
+ }
272
+ };
273
+
274
+ // src/exact/facilitator/register.ts
275
+ function registerExactTonScheme(facilitator, config) {
276
+ facilitator.register(config.networks, new ExactTonScheme(config.signer, config.schemeConfig));
277
+ return facilitator;
278
+ }
279
+
280
+ export {
281
+ ExactTonScheme,
282
+ registerExactTonScheme
283
+ };
284
+ //# sourceMappingURL=chunk-ZJA7AWWH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/exact/facilitator/scheme.ts","../../src/exact/facilitator/register.ts"],"sourcesContent":["/**\n * TON Facilitator Scheme Implementation\n *\n * Verifies and settles TON Jetton payments using the exact scheme.\n * Validates signed messages and broadcasts transactions to the network.\n */\n\nimport { Cell } from '@ton/core'\nimport type {\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from '@t402/core/types'\nimport type { FacilitatorTonSigner } from '../../signer.js'\nimport type { ExactTonPayloadV2 } from '../../types.js'\nimport { SCHEME_EXACT } from '../../constants.js'\nimport { addressesEqual, normalizeNetwork } from '../../utils.js'\n\n/**\n * Configuration options for ExactTonScheme facilitator\n */\nexport interface ExactTonSchemeConfig {\n /** Whether this facilitator can sponsor gas for transactions */\n canSponsorGas?: boolean\n}\n\n/**\n * TON facilitator implementation for the Exact payment scheme.\n *\n * Verifies signed Jetton transfer messages and broadcasts them\n * to the TON network to complete payments.\n */\nexport class ExactTonScheme implements SchemeNetworkFacilitator {\n readonly scheme = SCHEME_EXACT\n readonly caipFamily = 'ton:*'\n private config: ExactTonSchemeConfig\n\n /**\n * Creates a new ExactTonScheme facilitator instance.\n *\n * @param signer - The TON signer for facilitator operations\n * @param config - Optional configuration\n */\n constructor(\n private readonly signer: FacilitatorTonSigner,\n config: ExactTonSchemeConfig = {},\n ) {\n this.config = config\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For TON, optionally returns gas sponsor address if configured.\n *\n * @param network - The network identifier\n * @returns Extra data object or undefined\n */\n getExtra(network: string): Record<string, unknown> | undefined {\n void network\n\n if (this.config.canSponsorGas) {\n const addresses = this.signer.getAddresses()\n if (addresses.length > 0) {\n return {\n gasSponsor: addresses[0],\n }\n }\n }\n\n return undefined\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for operations.\n *\n * @param network - The network identifier\n * @returns Array of facilitator addresses\n */\n getSigners(network: string): string[] {\n void network\n return [...this.signer.getAddresses()]\n }\n\n /**\n * Verifies a payment payload.\n *\n * Performs comprehensive validation:\n * 1. Scheme and network matching\n * 2. BOC format validation\n * 3. Message structure verification\n * 4. Authorization expiry check\n * 5. Balance verification\n * 6. Amount and recipient validation\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const tonPayload = payload.payload as ExactTonPayloadV2 | undefined\n\n // Validate payload structure\n if (!tonPayload?.authorization?.from || !tonPayload?.signedBoc) {\n return {\n isValid: false,\n invalidReason: 'invalid_payload_structure',\n payer: '',\n }\n }\n\n const authorization = tonPayload.authorization\n\n // Step 1: Verify scheme matches\n if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {\n return {\n isValid: false,\n invalidReason: 'unsupported_scheme',\n payer: authorization.from,\n }\n }\n\n // Step 2: Verify network matches\n try {\n const payloadNetwork = normalizeNetwork(payload.accepted.network)\n const requirementsNetwork = normalizeNetwork(requirements.network)\n\n if (payloadNetwork !== requirementsNetwork) {\n return {\n isValid: false,\n invalidReason: 'network_mismatch',\n payer: authorization.from,\n }\n }\n } catch {\n return {\n isValid: false,\n invalidReason: 'invalid_network',\n payer: authorization.from,\n }\n }\n\n // Step 3: Parse and validate the signed BOC\n try {\n Cell.fromBase64(tonPayload.signedBoc)\n } catch {\n return {\n isValid: false,\n invalidReason: 'invalid_boc_format',\n payer: authorization.from,\n }\n }\n\n // Step 4: Verify the message structure and parameters\n const verifyResult = await this.signer.verifyMessage({\n signedBoc: tonPayload.signedBoc,\n expectedFrom: authorization.from,\n expectedTransfer: {\n jettonAmount: BigInt(authorization.jettonAmount),\n destination: requirements.payTo,\n jettonMaster: requirements.asset,\n },\n })\n\n if (!verifyResult.valid) {\n return {\n isValid: false,\n invalidReason: verifyResult.reason || 'message_verification_failed',\n payer: authorization.from,\n }\n }\n\n // Step 5: Check validUntil is in the future (with 30 second buffer)\n const now = Math.floor(Date.now() / 1000)\n if (authorization.validUntil < now + 30) {\n return {\n isValid: false,\n invalidReason: 'authorization_expired',\n payer: authorization.from,\n }\n }\n\n // Step 6: Verify Jetton balance\n try {\n const balance = await this.signer.getJettonBalance({\n ownerAddress: authorization.from,\n jettonMasterAddress: requirements.asset,\n })\n\n if (balance < BigInt(requirements.amount)) {\n return {\n isValid: false,\n invalidReason: 'insufficient_jetton_balance',\n payer: authorization.from,\n }\n }\n } catch (error) {\n // If we can't check balance, log warning but continue\n console.warn('Could not verify Jetton balance:', error)\n }\n\n // Step 7: Verify amount is sufficient\n if (BigInt(authorization.jettonAmount) < BigInt(requirements.amount)) {\n return {\n isValid: false,\n invalidReason: 'insufficient_amount',\n payer: authorization.from,\n }\n }\n\n // Step 8: Verify recipient matches\n if (!addressesEqual(authorization.to, requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: 'recipient_mismatch',\n payer: authorization.from,\n }\n }\n\n // Step 9: Verify Jetton master matches\n if (!addressesEqual(authorization.jettonMaster, requirements.asset)) {\n return {\n isValid: false,\n invalidReason: 'asset_mismatch',\n payer: authorization.from,\n }\n }\n\n // Step 10: Check seqno hasn't been used (replay protection)\n try {\n const currentSeqno = await this.signer.getSeqno(authorization.from)\n if (authorization.seqno < currentSeqno) {\n return {\n isValid: false,\n invalidReason: 'seqno_already_used',\n payer: authorization.from,\n }\n }\n if (authorization.seqno > currentSeqno) {\n return {\n isValid: false,\n invalidReason: 'seqno_too_high',\n payer: authorization.from,\n }\n }\n } catch (error) {\n console.warn('Could not verify seqno:', error)\n }\n\n // Step 11: Verify wallet is deployed\n try {\n const isDeployed = await this.signer.isDeployed(authorization.from)\n if (!isDeployed) {\n return {\n isValid: false,\n invalidReason: 'wallet_not_deployed',\n payer: authorization.from,\n }\n }\n } catch (error) {\n console.warn('Could not verify wallet deployment:', error)\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer: authorization.from,\n }\n }\n\n /**\n * Settles a payment by broadcasting the signed message.\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const tonPayload = payload.payload as ExactTonPayloadV2 | undefined\n\n // Validate payload structure\n if (!tonPayload?.authorization?.from || !tonPayload?.signedBoc) {\n return {\n success: false,\n network: payload.accepted.network,\n transaction: '',\n errorReason: 'invalid_payload_structure',\n payer: '',\n }\n }\n\n // Re-verify before settling\n const verifyResult = await this.verify(payload, requirements)\n if (!verifyResult.isValid) {\n return {\n success: false,\n network: payload.accepted.network,\n transaction: '',\n errorReason: verifyResult.invalidReason ?? 'verification_failed',\n payer: tonPayload.authorization.from,\n }\n }\n\n try {\n // Send the pre-signed external message\n const txHash = await this.signer.sendExternalMessage(tonPayload.signedBoc)\n\n // Wait for confirmation\n const confirmation = await this.signer.waitForTransaction({\n address: tonPayload.authorization.from,\n seqno: tonPayload.authorization.seqno + 1, // Wait for next seqno\n timeout: 60000, // 60 second timeout\n })\n\n if (!confirmation.success) {\n return {\n success: false,\n errorReason: confirmation.error || 'transaction_not_confirmed',\n transaction: txHash,\n network: payload.accepted.network,\n payer: tonPayload.authorization.from,\n }\n }\n\n return {\n success: true,\n transaction: confirmation.hash || txHash,\n network: payload.accepted.network,\n payer: tonPayload.authorization.from,\n }\n } catch (error) {\n console.error('Failed to settle TON transaction:', error)\n return {\n success: false,\n errorReason: 'transaction_failed',\n transaction: '',\n network: payload.accepted.network,\n payer: tonPayload.authorization.from,\n }\n }\n }\n}\n","import { t402Facilitator } from '@t402/core/facilitator'\nimport { Network } from '@t402/core/types'\nimport { FacilitatorTonSigner } from '../../signer.js'\nimport { ExactTonScheme, ExactTonSchemeConfig } from './scheme.js'\n\n/**\n * Configuration options for registering TON schemes to an t402Facilitator\n */\nexport interface TonFacilitatorConfig {\n /**\n * The TON signer for facilitator operations (verify and settle)\n */\n signer: FacilitatorTonSigner\n\n /**\n * Networks to register (single network or array of networks)\n * Examples: \"ton:mainnet\", [\"ton:mainnet\", \"ton:testnet\"]\n */\n networks: Network | Network[]\n\n /**\n * Optional scheme configuration (gas sponsorship, etc.)\n */\n schemeConfig?: ExactTonSchemeConfig\n}\n\n/**\n * Registers TON exact payment schemes to an t402Facilitator instance.\n *\n * This function registers:\n * - V2: Specified networks with ExactTonScheme\n *\n * @param facilitator - The t402Facilitator instance to register schemes to\n * @param config - Configuration for TON facilitator registration\n * @returns The facilitator instance for chaining\n *\n * @example\n * ```typescript\n * import { registerExactTonScheme } from \"@t402/ton/exact/facilitator/register\";\n * import { t402Facilitator } from \"@t402/core/facilitator\";\n * import { TonClient } from \"@ton/ton\";\n *\n * const tonClient = new TonClient({ endpoint: \"...\" });\n * const facilitator = new t402Facilitator();\n *\n * // Single network\n * registerExactTonScheme(facilitator, {\n * signer: toFacilitatorTonSigner(tonClient),\n * networks: \"ton:mainnet\"\n * });\n *\n * // Multiple networks\n * registerExactTonScheme(facilitator, {\n * signer: toFacilitatorTonSigner(tonClient),\n * networks: [\"ton:mainnet\", \"ton:testnet\"]\n * });\n *\n * // With gas sponsorship\n * registerExactTonScheme(facilitator, {\n * signer: toFacilitatorTonSigner(tonClient),\n * networks: \"ton:mainnet\",\n * schemeConfig: { canSponsorGas: true }\n * });\n * ```\n */\nexport function registerExactTonScheme(\n facilitator: t402Facilitator,\n config: TonFacilitatorConfig,\n): t402Facilitator {\n // Register V2 scheme with specified networks\n facilitator.register(config.networks, new ExactTonScheme(config.signer, config.schemeConfig))\n\n return facilitator\n}\n"],"mappings":"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","names":[]}