@t402/polkadot 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 (40) hide show
  1. package/README.md +139 -0
  2. package/dist/exact-direct/client/index.cjs +189 -0
  3. package/dist/exact-direct/client/index.cjs.map +1 -0
  4. package/dist/exact-direct/client/index.d.cts +39 -0
  5. package/dist/exact-direct/client/index.d.ts +39 -0
  6. package/dist/exact-direct/client/index.mjs +161 -0
  7. package/dist/exact-direct/client/index.mjs.map +1 -0
  8. package/dist/exact-direct/facilitator/index.cjs +394 -0
  9. package/dist/exact-direct/facilitator/index.cjs.map +1 -0
  10. package/dist/exact-direct/facilitator/index.d.cts +55 -0
  11. package/dist/exact-direct/facilitator/index.d.ts +55 -0
  12. package/dist/exact-direct/facilitator/index.mjs +366 -0
  13. package/dist/exact-direct/facilitator/index.mjs.map +1 -0
  14. package/dist/exact-direct/server/index.cjs +277 -0
  15. package/dist/exact-direct/server/index.cjs.map +1 -0
  16. package/dist/exact-direct/server/index.d.cts +109 -0
  17. package/dist/exact-direct/server/index.d.ts +109 -0
  18. package/dist/exact-direct/server/index.mjs +248 -0
  19. package/dist/exact-direct/server/index.mjs.map +1 -0
  20. package/dist/index.cjs +293 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.cts +148 -0
  23. package/dist/index.d.ts +148 -0
  24. package/dist/index.mjs +235 -0
  25. package/dist/index.mjs.map +1 -0
  26. package/dist/types-Dbjfcz2Y.d.cts +135 -0
  27. package/dist/types-Dbjfcz2Y.d.ts +135 -0
  28. package/package.json +103 -0
  29. package/src/constants.ts +87 -0
  30. package/src/exact-direct/client/index.ts +5 -0
  31. package/src/exact-direct/client/scheme.ts +117 -0
  32. package/src/exact-direct/facilitator/index.ts +4 -0
  33. package/src/exact-direct/facilitator/scheme.ts +315 -0
  34. package/src/exact-direct/server/index.ts +9 -0
  35. package/src/exact-direct/server/register.ts +57 -0
  36. package/src/exact-direct/server/scheme.ts +216 -0
  37. package/src/index.ts +84 -0
  38. package/src/tokens.ts +111 -0
  39. package/src/types.ts +151 -0
  40. package/src/utils.ts +176 -0
@@ -0,0 +1,366 @@
1
+ // src/constants.ts
2
+ var POLKADOT_CAIP2_NAMESPACE = "polkadot";
3
+ var POLKADOT_ASSET_HUB_CAIP2 = "polkadot:68d56f15f85d3136970ec16946040bc1";
4
+ var KUSAMA_ASSET_HUB_CAIP2 = "polkadot:48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a";
5
+ var WESTEND_ASSET_HUB_CAIP2 = "polkadot:e143f23803ac50e8f6f8e62695d1ce9e";
6
+ var SCHEME_EXACT_DIRECT = "exact-direct";
7
+ var DEFAULT_POLKADOT_INDEXER = "https://assethub-polkadot.api.subscan.io";
8
+ var DEFAULT_KUSAMA_INDEXER = "https://assethub-kusama.api.subscan.io";
9
+ var DEFAULT_WESTEND_INDEXER = "https://assethub-westend.api.subscan.io";
10
+ var DEFAULT_POLKADOT_RPC = "wss://polkadot-asset-hub-rpc.polkadot.io";
11
+ var DEFAULT_KUSAMA_RPC = "wss://kusama-asset-hub-rpc.polkadot.io";
12
+ var DEFAULT_WESTEND_RPC = "wss://westend-asset-hub-rpc.polkadot.io";
13
+ var POLKADOT_NETWORKS = {
14
+ [POLKADOT_ASSET_HUB_CAIP2]: {
15
+ name: "Polkadot Asset Hub",
16
+ caip2: POLKADOT_ASSET_HUB_CAIP2,
17
+ rpcUrl: DEFAULT_POLKADOT_RPC,
18
+ indexerUrl: DEFAULT_POLKADOT_INDEXER,
19
+ genesisHash: "0x68d56f15f85d3136970ec16946040bc1752654e906147f7e43e9d539d7c3de2f",
20
+ ss58Prefix: 0,
21
+ // Polkadot
22
+ isTestnet: false
23
+ },
24
+ [KUSAMA_ASSET_HUB_CAIP2]: {
25
+ name: "Kusama Asset Hub",
26
+ caip2: KUSAMA_ASSET_HUB_CAIP2,
27
+ rpcUrl: DEFAULT_KUSAMA_RPC,
28
+ indexerUrl: DEFAULT_KUSAMA_INDEXER,
29
+ genesisHash: "0x48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a",
30
+ ss58Prefix: 2,
31
+ // Kusama
32
+ isTestnet: false
33
+ },
34
+ [WESTEND_ASSET_HUB_CAIP2]: {
35
+ name: "Westend Asset Hub",
36
+ caip2: WESTEND_ASSET_HUB_CAIP2,
37
+ rpcUrl: DEFAULT_WESTEND_RPC,
38
+ indexerUrl: DEFAULT_WESTEND_INDEXER,
39
+ genesisHash: "0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e",
40
+ ss58Prefix: 42,
41
+ // Generic Substrate
42
+ isTestnet: true
43
+ }
44
+ };
45
+ function getNetworkConfig(network) {
46
+ return POLKADOT_NETWORKS[network];
47
+ }
48
+
49
+ // src/tokens.ts
50
+ var USDT_POLKADOT = {
51
+ assetId: 1984,
52
+ symbol: "USDT",
53
+ name: "Tether USD",
54
+ decimals: 6,
55
+ issuer: "Tether"
56
+ };
57
+ var USDT_KUSAMA = {
58
+ assetId: 1984,
59
+ symbol: "USDT",
60
+ name: "Tether USD",
61
+ decimals: 6,
62
+ issuer: "Tether"
63
+ };
64
+ var USDT_WESTEND = {
65
+ assetId: 1984,
66
+ symbol: "USDT",
67
+ name: "Test Tether USD",
68
+ decimals: 6
69
+ };
70
+ var TOKEN_REGISTRY = {
71
+ [POLKADOT_ASSET_HUB_CAIP2]: {
72
+ USDT: USDT_POLKADOT
73
+ },
74
+ [KUSAMA_ASSET_HUB_CAIP2]: {
75
+ USDT: USDT_KUSAMA
76
+ },
77
+ [WESTEND_ASSET_HUB_CAIP2]: {
78
+ USDT: USDT_WESTEND
79
+ }
80
+ };
81
+ var DEFAULT_TOKENS = {
82
+ [POLKADOT_ASSET_HUB_CAIP2]: USDT_POLKADOT,
83
+ [KUSAMA_ASSET_HUB_CAIP2]: USDT_KUSAMA,
84
+ [WESTEND_ASSET_HUB_CAIP2]: USDT_WESTEND
85
+ };
86
+ function getDefaultToken(network) {
87
+ return DEFAULT_TOKENS[network];
88
+ }
89
+
90
+ // src/utils.ts
91
+ function isValidExtrinsicHash(hash) {
92
+ if (!hash || typeof hash !== "string") {
93
+ return false;
94
+ }
95
+ return /^0x[a-fA-F0-9]{64}$/.test(hash);
96
+ }
97
+ function isValidBlockHash(hash) {
98
+ return isValidExtrinsicHash(hash);
99
+ }
100
+ function compareAddresses(addr1, addr2) {
101
+ return addr1 === addr2;
102
+ }
103
+ function extractAssetTransfer(result) {
104
+ if (!result.success) {
105
+ return null;
106
+ }
107
+ if (result.module !== "assets") {
108
+ return null;
109
+ }
110
+ if (result.call !== "transfer" && result.call !== "transferKeepAlive") {
111
+ return null;
112
+ }
113
+ const assetId = result.args.id;
114
+ const to = result.args.target;
115
+ const amount = result.args.amount;
116
+ if (assetId === void 0 || !to || !amount) {
117
+ return null;
118
+ }
119
+ return {
120
+ assetId,
121
+ from: result.signer,
122
+ to,
123
+ amount: amount.toString(),
124
+ success: true
125
+ };
126
+ }
127
+ function extractAssetTransferFromEvents(result) {
128
+ if (!result.success) {
129
+ return null;
130
+ }
131
+ const transferEvent = result.events.find(
132
+ (e) => e.module === "assets" && e.name === "Transferred"
133
+ );
134
+ if (!transferEvent) {
135
+ return null;
136
+ }
137
+ const assetId = transferEvent.data.assetId;
138
+ const from = transferEvent.data.from;
139
+ const to = transferEvent.data.to;
140
+ const amount = transferEvent.data.amount;
141
+ if (assetId === void 0 || !from || !to || !amount) {
142
+ return null;
143
+ }
144
+ return {
145
+ assetId,
146
+ from,
147
+ to,
148
+ amount: amount.toString(),
149
+ success: true
150
+ };
151
+ }
152
+ function buildExtrinsicId(blockHash, extrinsicIndex) {
153
+ return `${blockHash}-${extrinsicIndex}`;
154
+ }
155
+
156
+ // src/exact-direct/facilitator/scheme.ts
157
+ var DEFAULT_MAX_EXTRINSIC_AGE = 3600;
158
+ var DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1e3;
159
+ var ExactDirectPolkadotFacilitator = class {
160
+ scheme = SCHEME_EXACT_DIRECT;
161
+ caipFamily = `${POLKADOT_CAIP2_NAMESPACE}:*`;
162
+ signer;
163
+ config;
164
+ usedExtrinsics = /* @__PURE__ */ new Map();
165
+ constructor(signer, config = {}) {
166
+ this.signer = signer;
167
+ this.config = {
168
+ maxExtrinsicAge: config.maxExtrinsicAge ?? DEFAULT_MAX_EXTRINSIC_AGE,
169
+ usedExtrinsicCacheDuration: config.usedExtrinsicCacheDuration ?? DEFAULT_CACHE_DURATION
170
+ };
171
+ this.startCleanupInterval();
172
+ }
173
+ /**
174
+ * Get extra data for payment requirements
175
+ */
176
+ getExtra(network) {
177
+ const config = getNetworkConfig(network);
178
+ if (!config) return void 0;
179
+ const token = getDefaultToken(network);
180
+ return {
181
+ assetId: token?.assetId,
182
+ assetSymbol: token?.symbol,
183
+ assetDecimals: token?.decimals,
184
+ networkName: config.name
185
+ };
186
+ }
187
+ /**
188
+ * Get facilitator signer addresses for a network
189
+ */
190
+ getSigners(network) {
191
+ return this.signer.getAddresses(network);
192
+ }
193
+ /**
194
+ * Verify a payment payload
195
+ */
196
+ async verify(payload, requirements) {
197
+ const network = requirements.network;
198
+ if (payload.accepted.scheme !== SCHEME_EXACT_DIRECT) {
199
+ return {
200
+ isValid: false,
201
+ invalidReason: `invalid_scheme: expected ${SCHEME_EXACT_DIRECT}, got ${payload.accepted.scheme}`
202
+ };
203
+ }
204
+ if (payload.accepted.network !== network) {
205
+ return {
206
+ isValid: false,
207
+ invalidReason: `network_mismatch: expected ${network}, got ${payload.accepted.network}`
208
+ };
209
+ }
210
+ const polkadotPayload = payload.payload;
211
+ if (!polkadotPayload.extrinsicHash && !polkadotPayload.blockHash) {
212
+ return {
213
+ isValid: false,
214
+ invalidReason: "missing_extrinsic_identifier: need extrinsicHash or blockHash"
215
+ };
216
+ }
217
+ if (polkadotPayload.extrinsicHash && !isValidExtrinsicHash(polkadotPayload.extrinsicHash)) {
218
+ return {
219
+ isValid: false,
220
+ invalidReason: "invalid_extrinsic_hash_format"
221
+ };
222
+ }
223
+ if (polkadotPayload.blockHash && !isValidBlockHash(polkadotPayload.blockHash)) {
224
+ return {
225
+ isValid: false,
226
+ invalidReason: "invalid_block_hash_format"
227
+ };
228
+ }
229
+ if (!polkadotPayload.from) {
230
+ return {
231
+ isValid: false,
232
+ invalidReason: "missing_from_address"
233
+ };
234
+ }
235
+ const extrinsicId = polkadotPayload.extrinsicHash || buildExtrinsicId(polkadotPayload.blockHash, polkadotPayload.extrinsicIndex);
236
+ if (this.isExtrinsicUsed(extrinsicId)) {
237
+ return {
238
+ isValid: false,
239
+ invalidReason: "extrinsic_already_used",
240
+ payer: polkadotPayload.from
241
+ };
242
+ }
243
+ const extrinsicResult = await this.signer.queryExtrinsic(
244
+ polkadotPayload.extrinsicHash,
245
+ polkadotPayload.blockHash,
246
+ polkadotPayload.extrinsicIndex
247
+ );
248
+ if (!extrinsicResult) {
249
+ return {
250
+ isValid: false,
251
+ invalidReason: "extrinsic_not_found",
252
+ payer: polkadotPayload.from
253
+ };
254
+ }
255
+ if (!extrinsicResult.success) {
256
+ return {
257
+ isValid: false,
258
+ invalidReason: "extrinsic_failed",
259
+ payer: polkadotPayload.from
260
+ };
261
+ }
262
+ if (this.config.maxExtrinsicAge > 0) {
263
+ const extrinsicTime = new Date(extrinsicResult.timestamp).getTime();
264
+ const age = (Date.now() - extrinsicTime) / 1e3;
265
+ if (age > this.config.maxExtrinsicAge) {
266
+ return {
267
+ isValid: false,
268
+ invalidReason: `extrinsic_too_old: ${Math.round(age)} seconds`,
269
+ payer: polkadotPayload.from
270
+ };
271
+ }
272
+ }
273
+ const transfer = extractAssetTransfer(extrinsicResult) || extractAssetTransferFromEvents(extrinsicResult);
274
+ if (!transfer) {
275
+ return {
276
+ isValid: false,
277
+ invalidReason: "not_asset_transfer",
278
+ payer: polkadotPayload.from
279
+ };
280
+ }
281
+ const expectedAssetId = requirements.extra?.assetId ?? polkadotPayload.assetId;
282
+ if (transfer.assetId !== expectedAssetId) {
283
+ return {
284
+ isValid: false,
285
+ invalidReason: `asset_mismatch: expected ${expectedAssetId}, got ${transfer.assetId}`,
286
+ payer: polkadotPayload.from
287
+ };
288
+ }
289
+ if (!compareAddresses(transfer.to, requirements.payTo)) {
290
+ return {
291
+ isValid: false,
292
+ invalidReason: `recipient_mismatch: expected ${requirements.payTo}, got ${transfer.to}`,
293
+ payer: polkadotPayload.from
294
+ };
295
+ }
296
+ const txAmount = BigInt(transfer.amount);
297
+ const requiredAmount = BigInt(requirements.amount);
298
+ if (txAmount < requiredAmount) {
299
+ return {
300
+ isValid: false,
301
+ invalidReason: `insufficient_amount: expected ${requirements.amount}, got ${transfer.amount}`,
302
+ payer: polkadotPayload.from
303
+ };
304
+ }
305
+ this.markExtrinsicUsed(extrinsicId);
306
+ return {
307
+ isValid: true,
308
+ payer: polkadotPayload.from
309
+ };
310
+ }
311
+ /**
312
+ * Settle a payment (for exact-direct, the transfer is already complete)
313
+ */
314
+ async settle(payload, requirements) {
315
+ const verifyResult = await this.verify(payload, requirements);
316
+ if (!verifyResult.isValid) {
317
+ return {
318
+ success: false,
319
+ errorReason: verifyResult.invalidReason || "verification_failed",
320
+ payer: verifyResult.payer,
321
+ transaction: "",
322
+ network: requirements.network
323
+ };
324
+ }
325
+ const polkadotPayload = payload.payload;
326
+ return {
327
+ success: true,
328
+ transaction: polkadotPayload.extrinsicHash || buildExtrinsicId(polkadotPayload.blockHash, polkadotPayload.extrinsicIndex),
329
+ network: requirements.network,
330
+ payer: verifyResult.payer
331
+ };
332
+ }
333
+ /**
334
+ * Check if an extrinsic has been used
335
+ */
336
+ isExtrinsicUsed(extrinsicId) {
337
+ return this.usedExtrinsics.has(extrinsicId);
338
+ }
339
+ /**
340
+ * Mark an extrinsic as used
341
+ */
342
+ markExtrinsicUsed(extrinsicId) {
343
+ this.usedExtrinsics.set(extrinsicId, Date.now());
344
+ }
345
+ /**
346
+ * Start the cleanup interval for used extrinsics cache
347
+ */
348
+ startCleanupInterval() {
349
+ setInterval(() => {
350
+ const cutoff = Date.now() - this.config.usedExtrinsicCacheDuration;
351
+ for (const [extrinsicId, timestamp] of this.usedExtrinsics) {
352
+ if (timestamp < cutoff) {
353
+ this.usedExtrinsics.delete(extrinsicId);
354
+ }
355
+ }
356
+ }, 60 * 60 * 1e3);
357
+ }
358
+ };
359
+ function createExactDirectPolkadotFacilitator(signer, config = {}) {
360
+ return new ExactDirectPolkadotFacilitator(signer, config);
361
+ }
362
+ export {
363
+ ExactDirectPolkadotFacilitator,
364
+ createExactDirectPolkadotFacilitator
365
+ };
366
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/constants.ts","../../../src/tokens.ts","../../../src/utils.ts","../../../src/exact-direct/facilitator/scheme.ts"],"sourcesContent":["/**\n * Polkadot Asset Hub T402 Constants\n *\n * Polkadot Asset Hub (formerly Statemint) is a common-good parachain\n * that hosts assets like USDT on the Polkadot network.\n */\n\n// CAIP-2 namespace for Polkadot\nexport const POLKADOT_CAIP2_NAMESPACE = \"polkadot\";\n\n// CAIP-2 network identifiers (first 32 chars of genesis hash)\n// Polkadot Asset Hub (Parachain ID: 1000)\nexport const POLKADOT_ASSET_HUB_CAIP2 = \"polkadot:68d56f15f85d3136970ec16946040bc1\";\n\n// Kusama Asset Hub (Parachain ID: 1000 on Kusama)\nexport const KUSAMA_ASSET_HUB_CAIP2 = \"polkadot:48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a\";\n\n// Westend Asset Hub (Testnet)\nexport const WESTEND_ASSET_HUB_CAIP2 = \"polkadot:e143f23803ac50e8f6f8e62695d1ce9e\";\n\n// Scheme identifier\nexport const SCHEME_EXACT_DIRECT = \"exact-direct\";\n\n// Default indexers (Subscan API)\nexport const DEFAULT_POLKADOT_INDEXER = \"https://assethub-polkadot.api.subscan.io\";\nexport const DEFAULT_KUSAMA_INDEXER = \"https://assethub-kusama.api.subscan.io\";\nexport const DEFAULT_WESTEND_INDEXER = \"https://assethub-westend.api.subscan.io\";\n\n// Default RPC endpoints\nexport const DEFAULT_POLKADOT_RPC = \"wss://polkadot-asset-hub-rpc.polkadot.io\";\nexport const DEFAULT_KUSAMA_RPC = \"wss://kusama-asset-hub-rpc.polkadot.io\";\nexport const DEFAULT_WESTEND_RPC = \"wss://westend-asset-hub-rpc.polkadot.io\";\n\n// Network configurations\nexport interface PolkadotNetworkConfig {\n readonly name: string;\n readonly caip2: string;\n readonly rpcUrl: string;\n readonly indexerUrl: string;\n readonly genesisHash: string;\n readonly ss58Prefix: number;\n readonly isTestnet: boolean;\n}\n\nexport const POLKADOT_NETWORKS: Record<string, PolkadotNetworkConfig> = {\n [POLKADOT_ASSET_HUB_CAIP2]: {\n name: \"Polkadot Asset Hub\",\n caip2: POLKADOT_ASSET_HUB_CAIP2,\n rpcUrl: DEFAULT_POLKADOT_RPC,\n indexerUrl: DEFAULT_POLKADOT_INDEXER,\n genesisHash: \"0x68d56f15f85d3136970ec16946040bc1752654e906147f7e43e9d539d7c3de2f\",\n ss58Prefix: 0, // Polkadot\n isTestnet: false,\n },\n [KUSAMA_ASSET_HUB_CAIP2]: {\n name: \"Kusama Asset Hub\",\n caip2: KUSAMA_ASSET_HUB_CAIP2,\n rpcUrl: DEFAULT_KUSAMA_RPC,\n indexerUrl: DEFAULT_KUSAMA_INDEXER,\n genesisHash: \"0x48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a\",\n ss58Prefix: 2, // Kusama\n isTestnet: false,\n },\n [WESTEND_ASSET_HUB_CAIP2]: {\n name: \"Westend Asset Hub\",\n caip2: WESTEND_ASSET_HUB_CAIP2,\n rpcUrl: DEFAULT_WESTEND_RPC,\n indexerUrl: DEFAULT_WESTEND_INDEXER,\n genesisHash: \"0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e\",\n ss58Prefix: 42, // Generic Substrate\n isTestnet: true,\n },\n};\n\n/**\n * Get network configuration by CAIP-2 identifier\n */\nexport function getNetworkConfig(network: string): PolkadotNetworkConfig | undefined {\n return POLKADOT_NETWORKS[network];\n}\n\n/**\n * Check if a network identifier is a Polkadot network\n */\nexport function isPolkadotNetwork(network: string): boolean {\n return network.startsWith(`${POLKADOT_CAIP2_NAMESPACE}:`);\n}\n","/**\n * Polkadot Asset Hub Token Registry\n *\n * On Polkadot Asset Hub, tokens are identified by Asset IDs.\n * USDT is Asset ID 1984, created by Tether.\n */\n\nimport {\n POLKADOT_ASSET_HUB_CAIP2,\n KUSAMA_ASSET_HUB_CAIP2,\n WESTEND_ASSET_HUB_CAIP2,\n} from \"./constants.js\";\n\n/**\n * Token configuration for Polkadot Asset Hub\n */\nexport interface TokenConfig {\n /** Asset ID on Asset Hub */\n readonly assetId: number;\n /** Token symbol */\n readonly symbol: string;\n /** Token name */\n readonly name: string;\n /** Decimal places */\n readonly decimals: number;\n /** Issuer (creator of the asset) */\n readonly issuer?: string;\n}\n\n/**\n * USDT on Polkadot Asset Hub\n * Asset ID: 1984\n * Decimals: 6\n */\nexport const USDT_POLKADOT: TokenConfig = {\n assetId: 1984,\n symbol: \"USDT\",\n name: \"Tether USD\",\n decimals: 6,\n issuer: \"Tether\",\n};\n\n/**\n * USDT on Kusama Asset Hub\n * Asset ID: 1984 (same as Polkadot)\n */\nexport const USDT_KUSAMA: TokenConfig = {\n assetId: 1984,\n symbol: \"USDT\",\n name: \"Tether USD\",\n decimals: 6,\n issuer: \"Tether\",\n};\n\n/**\n * Test USDT on Westend Asset Hub (testnet)\n */\nexport const USDT_WESTEND: TokenConfig = {\n assetId: 1984,\n symbol: \"USDT\",\n name: \"Test Tether USD\",\n decimals: 6,\n};\n\n/**\n * Network-specific token registries\n */\nexport const TOKEN_REGISTRY: Record<string, Record<string, TokenConfig>> = {\n [POLKADOT_ASSET_HUB_CAIP2]: {\n USDT: USDT_POLKADOT,\n },\n [KUSAMA_ASSET_HUB_CAIP2]: {\n USDT: USDT_KUSAMA,\n },\n [WESTEND_ASSET_HUB_CAIP2]: {\n USDT: USDT_WESTEND,\n },\n};\n\n/**\n * Default tokens per network\n */\nexport const DEFAULT_TOKENS: Record<string, TokenConfig> = {\n [POLKADOT_ASSET_HUB_CAIP2]: USDT_POLKADOT,\n [KUSAMA_ASSET_HUB_CAIP2]: USDT_KUSAMA,\n [WESTEND_ASSET_HUB_CAIP2]: USDT_WESTEND,\n};\n\n/**\n * Get token configuration by network and symbol\n */\nexport function getTokenConfig(\n network: string,\n symbol: string = \"USDT\",\n): TokenConfig | undefined {\n return TOKEN_REGISTRY[network]?.[symbol];\n}\n\n/**\n * Get the default token for a network\n */\nexport function getDefaultToken(network: string): TokenConfig | undefined {\n return DEFAULT_TOKENS[network];\n}\n\n/**\n * Get asset ID for a token on a network\n */\nexport function getAssetId(network: string, symbol: string = \"USDT\"): number | undefined {\n return getTokenConfig(network, symbol)?.assetId;\n}\n","/**\n * Polkadot Asset Hub Utility Functions\n */\n\nimport type { PolkadotExtrinsicResult, ParsedAssetTransfer } from \"./types.js\";\n\n/**\n * Validate a Polkadot SS58 address format\n * SS58 addresses are base58-encoded with a checksum\n */\nexport function isValidAddress(address: string): boolean {\n if (!address || typeof address !== \"string\") {\n return false;\n }\n\n // SS58 addresses typically start with 1 (Polkadot), or have other prefixes\n // Length is typically 47-48 characters for Polkadot addresses\n // For a simple validation, check base58 characters and length\n const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{45,50}$/;\n return base58Regex.test(address);\n}\n\n/**\n * Validate an extrinsic hash format\n * Extrinsic hashes are 32-byte hex strings prefixed with 0x\n */\nexport function isValidExtrinsicHash(hash: string): boolean {\n if (!hash || typeof hash !== \"string\") {\n return false;\n }\n return /^0x[a-fA-F0-9]{64}$/.test(hash);\n}\n\n/**\n * Validate a block hash format\n */\nexport function isValidBlockHash(hash: string): boolean {\n return isValidExtrinsicHash(hash); // Same format\n}\n\n/**\n * Compare two SS58 addresses (case-sensitive)\n */\nexport function compareAddresses(addr1: string, addr2: string): boolean {\n return addr1 === addr2;\n}\n\n/**\n * Format an amount with decimals for display\n */\nexport function formatAmount(amount: string, decimals: number): string {\n const amountBigInt = BigInt(amount);\n const divisor = BigInt(10 ** decimals);\n const wholePart = amountBigInt / divisor;\n const fractionalPart = amountBigInt % divisor;\n\n if (fractionalPart === 0n) {\n return wholePart.toString();\n }\n\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n const trimmedFractional = fractionalStr.replace(/0+$/, \"\");\n return `${wholePart}.${trimmedFractional}`;\n}\n\n/**\n * Parse an amount string to the smallest unit (with decimals applied)\n */\nexport function parseAmount(amount: string, decimals: number): string {\n const parts = amount.split(\".\");\n const wholePart = parts[0] || \"0\";\n const fractionalPart = (parts[1] || \"\").padEnd(decimals, \"0\").slice(0, decimals);\n return BigInt(wholePart + fractionalPart).toString();\n}\n\n/**\n * Extract asset transfer details from an extrinsic result\n */\nexport function extractAssetTransfer(\n result: PolkadotExtrinsicResult,\n): ParsedAssetTransfer | null {\n if (!result.success) {\n return null;\n }\n\n // Check if this is an assets.transfer or assets.transferKeepAlive call\n if (result.module !== \"assets\") {\n return null;\n }\n\n if (result.call !== \"transfer\" && result.call !== \"transferKeepAlive\") {\n return null;\n }\n\n // Extract transfer details from args\n const assetId = result.args.id as number | undefined;\n const to = result.args.target as string | undefined;\n const amount = result.args.amount as string | undefined;\n\n if (assetId === undefined || !to || !amount) {\n return null;\n }\n\n return {\n assetId,\n from: result.signer,\n to,\n amount: amount.toString(),\n success: true,\n };\n}\n\n/**\n * Extract asset transfer from events (alternative method)\n */\nexport function extractAssetTransferFromEvents(\n result: PolkadotExtrinsicResult,\n): ParsedAssetTransfer | null {\n if (!result.success) {\n return null;\n }\n\n // Look for assets.Transferred event\n const transferEvent = result.events.find(\n (e) => e.module === \"assets\" && e.name === \"Transferred\",\n );\n\n if (!transferEvent) {\n return null;\n }\n\n const assetId = transferEvent.data.assetId as number | undefined;\n const from = transferEvent.data.from as string | undefined;\n const to = transferEvent.data.to as string | undefined;\n const amount = transferEvent.data.amount as string | undefined;\n\n if (assetId === undefined || !from || !to || !amount) {\n return null;\n }\n\n return {\n assetId,\n from,\n to,\n amount: amount.toString(),\n success: true,\n };\n}\n\n/**\n * Build a unique extrinsic identifier from block hash and index\n */\nexport function buildExtrinsicId(blockHash: string, extrinsicIndex: number): string {\n return `${blockHash}-${extrinsicIndex}`;\n}\n\n/**\n * Parse an extrinsic identifier back to components\n */\nexport function parseExtrinsicId(\n extrinsicId: string,\n): { blockHash: string; extrinsicIndex: number } | null {\n const lastDashIndex = extrinsicId.lastIndexOf(\"-\");\n if (lastDashIndex === -1) {\n return null;\n }\n\n const blockHash = extrinsicId.slice(0, lastDashIndex);\n const extrinsicIndex = parseInt(extrinsicId.slice(lastDashIndex + 1), 10);\n\n if (!isValidBlockHash(blockHash) || isNaN(extrinsicIndex)) {\n return null;\n }\n\n return { blockHash, extrinsicIndex };\n}\n","/**\n * Polkadot Exact-Direct Facilitator Scheme\n *\n * Verifies that a Polkadot asset transfer was executed correctly\n * by querying the Subscan indexer.\n */\n\nimport type {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@t402/core/types\";\nimport { POLKADOT_CAIP2_NAMESPACE, SCHEME_EXACT_DIRECT, getNetworkConfig } from \"../../constants.js\";\nimport { getDefaultToken } from \"../../tokens.js\";\nimport type {\n ExactDirectPolkadotPayload,\n FacilitatorPolkadotSigner,\n PolkadotFacilitatorConfig,\n} from \"../../types.js\";\nimport {\n buildExtrinsicId,\n compareAddresses,\n extractAssetTransfer,\n extractAssetTransferFromEvents,\n isValidBlockHash,\n isValidExtrinsicHash,\n} from \"../../utils.js\";\n\n// Default configuration\nconst DEFAULT_MAX_EXTRINSIC_AGE = 3600; // 1 hour\nconst DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours in ms\n\n/**\n * Exact-direct facilitator scheme for Polkadot Asset Hub\n */\nexport class ExactDirectPolkadotFacilitator implements SchemeNetworkFacilitator {\n readonly scheme = SCHEME_EXACT_DIRECT;\n readonly caipFamily = `${POLKADOT_CAIP2_NAMESPACE}:*`;\n\n private readonly signer: FacilitatorPolkadotSigner;\n private readonly config: Required<PolkadotFacilitatorConfig>;\n private readonly usedExtrinsics = new Map<string, number>();\n\n constructor(\n signer: FacilitatorPolkadotSigner,\n config: PolkadotFacilitatorConfig = {},\n ) {\n this.signer = signer;\n this.config = {\n maxExtrinsicAge: config.maxExtrinsicAge ?? DEFAULT_MAX_EXTRINSIC_AGE,\n usedExtrinsicCacheDuration:\n config.usedExtrinsicCacheDuration ?? DEFAULT_CACHE_DURATION,\n };\n\n // Start cleanup interval\n this.startCleanupInterval();\n }\n\n /**\n * Get extra data for payment requirements\n */\n getExtra(network: Network): Record<string, unknown> | undefined {\n const config = getNetworkConfig(network);\n if (!config) return undefined;\n\n const token = getDefaultToken(network);\n return {\n assetId: token?.assetId,\n assetSymbol: token?.symbol,\n assetDecimals: token?.decimals,\n networkName: config.name,\n };\n }\n\n /**\n * Get facilitator signer addresses for a network\n */\n getSigners(network: Network): string[] {\n return this.signer.getAddresses(network);\n }\n\n /**\n * Verify a payment payload\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const network = requirements.network;\n\n // Validate scheme\n if (payload.accepted.scheme !== SCHEME_EXACT_DIRECT) {\n return {\n isValid: false,\n invalidReason: `invalid_scheme: expected ${SCHEME_EXACT_DIRECT}, got ${payload.accepted.scheme}`,\n };\n }\n\n // Validate network\n if (payload.accepted.network !== network) {\n return {\n isValid: false,\n invalidReason: `network_mismatch: expected ${network}, got ${payload.accepted.network}`,\n };\n }\n\n // Parse payload\n const polkadotPayload = payload.payload as unknown as ExactDirectPolkadotPayload;\n\n // Validate required fields\n if (!polkadotPayload.extrinsicHash && !polkadotPayload.blockHash) {\n return {\n isValid: false,\n invalidReason: \"missing_extrinsic_identifier: need extrinsicHash or blockHash\",\n };\n }\n\n // Validate extrinsic hash format if provided\n if (polkadotPayload.extrinsicHash && !isValidExtrinsicHash(polkadotPayload.extrinsicHash)) {\n return {\n isValid: false,\n invalidReason: \"invalid_extrinsic_hash_format\",\n };\n }\n\n // Validate block hash format if provided\n if (polkadotPayload.blockHash && !isValidBlockHash(polkadotPayload.blockHash)) {\n return {\n isValid: false,\n invalidReason: \"invalid_block_hash_format\",\n };\n }\n\n if (!polkadotPayload.from) {\n return {\n isValid: false,\n invalidReason: \"missing_from_address\",\n };\n }\n\n // Build unique identifier for replay protection\n const extrinsicId = polkadotPayload.extrinsicHash ||\n buildExtrinsicId(polkadotPayload.blockHash, polkadotPayload.extrinsicIndex);\n\n // Check for replay attack\n if (this.isExtrinsicUsed(extrinsicId)) {\n return {\n isValid: false,\n invalidReason: \"extrinsic_already_used\",\n payer: polkadotPayload.from,\n };\n }\n\n // Query extrinsic\n const extrinsicResult = await this.signer.queryExtrinsic(\n polkadotPayload.extrinsicHash,\n polkadotPayload.blockHash,\n polkadotPayload.extrinsicIndex,\n );\n\n if (!extrinsicResult) {\n return {\n isValid: false,\n invalidReason: \"extrinsic_not_found\",\n payer: polkadotPayload.from,\n };\n }\n\n // Verify extrinsic was successful\n if (!extrinsicResult.success) {\n return {\n isValid: false,\n invalidReason: \"extrinsic_failed\",\n payer: polkadotPayload.from,\n };\n }\n\n // Check extrinsic age\n if (this.config.maxExtrinsicAge > 0) {\n const extrinsicTime = new Date(extrinsicResult.timestamp).getTime();\n const age = (Date.now() - extrinsicTime) / 1000;\n if (age > this.config.maxExtrinsicAge) {\n return {\n isValid: false,\n invalidReason: `extrinsic_too_old: ${Math.round(age)} seconds`,\n payer: polkadotPayload.from,\n };\n }\n }\n\n // Extract transfer details\n const transfer =\n extractAssetTransfer(extrinsicResult) ||\n extractAssetTransferFromEvents(extrinsicResult);\n\n if (!transfer) {\n return {\n isValid: false,\n invalidReason: \"not_asset_transfer\",\n payer: polkadotPayload.from,\n };\n }\n\n // Verify asset ID\n const expectedAssetId = (requirements.extra?.assetId as number) ?? polkadotPayload.assetId;\n if (transfer.assetId !== expectedAssetId) {\n return {\n isValid: false,\n invalidReason: `asset_mismatch: expected ${expectedAssetId}, got ${transfer.assetId}`,\n payer: polkadotPayload.from,\n };\n }\n\n // Verify recipient\n if (!compareAddresses(transfer.to, requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: `recipient_mismatch: expected ${requirements.payTo}, got ${transfer.to}`,\n payer: polkadotPayload.from,\n };\n }\n\n // Verify amount\n const txAmount = BigInt(transfer.amount);\n const requiredAmount = BigInt(requirements.amount);\n if (txAmount < requiredAmount) {\n return {\n isValid: false,\n invalidReason: `insufficient_amount: expected ${requirements.amount}, got ${transfer.amount}`,\n payer: polkadotPayload.from,\n };\n }\n\n // Mark extrinsic as used\n this.markExtrinsicUsed(extrinsicId);\n\n return {\n isValid: true,\n payer: polkadotPayload.from,\n };\n }\n\n /**\n * Settle a payment (for exact-direct, the transfer is already complete)\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n // Verify first\n const verifyResult = await this.verify(payload, requirements);\n\n if (!verifyResult.isValid) {\n return {\n success: false,\n errorReason: verifyResult.invalidReason || \"verification_failed\",\n payer: verifyResult.payer,\n transaction: \"\",\n network: requirements.network,\n };\n }\n\n const polkadotPayload = payload.payload as unknown as ExactDirectPolkadotPayload;\n\n // For exact-direct, settlement is already complete\n return {\n success: true,\n transaction: polkadotPayload.extrinsicHash ||\n buildExtrinsicId(polkadotPayload.blockHash, polkadotPayload.extrinsicIndex),\n network: requirements.network,\n payer: verifyResult.payer,\n };\n }\n\n /**\n * Check if an extrinsic has been used\n */\n private isExtrinsicUsed(extrinsicId: string): boolean {\n return this.usedExtrinsics.has(extrinsicId);\n }\n\n /**\n * Mark an extrinsic as used\n */\n private markExtrinsicUsed(extrinsicId: string): void {\n this.usedExtrinsics.set(extrinsicId, Date.now());\n }\n\n /**\n * Start the cleanup interval for used extrinsics cache\n */\n private startCleanupInterval(): void {\n setInterval(() => {\n const cutoff = Date.now() - this.config.usedExtrinsicCacheDuration;\n for (const [extrinsicId, timestamp] of this.usedExtrinsics) {\n if (timestamp < cutoff) {\n this.usedExtrinsics.delete(extrinsicId);\n }\n }\n }, 60 * 60 * 1000); // Run every hour\n }\n}\n\n/**\n * Create an exact-direct facilitator for Polkadot\n */\nexport function createExactDirectPolkadotFacilitator(\n signer: FacilitatorPolkadotSigner,\n config: PolkadotFacilitatorConfig = {},\n): ExactDirectPolkadotFacilitator {\n return new ExactDirectPolkadotFacilitator(signer, config);\n}\n"],"mappings":"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","names":[]}