@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
package/src/tokens.ts ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Polkadot Asset Hub Token Registry
3
+ *
4
+ * On Polkadot Asset Hub, tokens are identified by Asset IDs.
5
+ * USDT is Asset ID 1984, created by Tether.
6
+ */
7
+
8
+ import {
9
+ POLKADOT_ASSET_HUB_CAIP2,
10
+ KUSAMA_ASSET_HUB_CAIP2,
11
+ WESTEND_ASSET_HUB_CAIP2,
12
+ } from "./constants.js";
13
+
14
+ /**
15
+ * Token configuration for Polkadot Asset Hub
16
+ */
17
+ export interface TokenConfig {
18
+ /** Asset ID on Asset Hub */
19
+ readonly assetId: number;
20
+ /** Token symbol */
21
+ readonly symbol: string;
22
+ /** Token name */
23
+ readonly name: string;
24
+ /** Decimal places */
25
+ readonly decimals: number;
26
+ /** Issuer (creator of the asset) */
27
+ readonly issuer?: string;
28
+ }
29
+
30
+ /**
31
+ * USDT on Polkadot Asset Hub
32
+ * Asset ID: 1984
33
+ * Decimals: 6
34
+ */
35
+ export const USDT_POLKADOT: TokenConfig = {
36
+ assetId: 1984,
37
+ symbol: "USDT",
38
+ name: "Tether USD",
39
+ decimals: 6,
40
+ issuer: "Tether",
41
+ };
42
+
43
+ /**
44
+ * USDT on Kusama Asset Hub
45
+ * Asset ID: 1984 (same as Polkadot)
46
+ */
47
+ export const USDT_KUSAMA: TokenConfig = {
48
+ assetId: 1984,
49
+ symbol: "USDT",
50
+ name: "Tether USD",
51
+ decimals: 6,
52
+ issuer: "Tether",
53
+ };
54
+
55
+ /**
56
+ * Test USDT on Westend Asset Hub (testnet)
57
+ */
58
+ export const USDT_WESTEND: TokenConfig = {
59
+ assetId: 1984,
60
+ symbol: "USDT",
61
+ name: "Test Tether USD",
62
+ decimals: 6,
63
+ };
64
+
65
+ /**
66
+ * Network-specific token registries
67
+ */
68
+ export const TOKEN_REGISTRY: Record<string, Record<string, TokenConfig>> = {
69
+ [POLKADOT_ASSET_HUB_CAIP2]: {
70
+ USDT: USDT_POLKADOT,
71
+ },
72
+ [KUSAMA_ASSET_HUB_CAIP2]: {
73
+ USDT: USDT_KUSAMA,
74
+ },
75
+ [WESTEND_ASSET_HUB_CAIP2]: {
76
+ USDT: USDT_WESTEND,
77
+ },
78
+ };
79
+
80
+ /**
81
+ * Default tokens per network
82
+ */
83
+ export const DEFAULT_TOKENS: Record<string, TokenConfig> = {
84
+ [POLKADOT_ASSET_HUB_CAIP2]: USDT_POLKADOT,
85
+ [KUSAMA_ASSET_HUB_CAIP2]: USDT_KUSAMA,
86
+ [WESTEND_ASSET_HUB_CAIP2]: USDT_WESTEND,
87
+ };
88
+
89
+ /**
90
+ * Get token configuration by network and symbol
91
+ */
92
+ export function getTokenConfig(
93
+ network: string,
94
+ symbol: string = "USDT",
95
+ ): TokenConfig | undefined {
96
+ return TOKEN_REGISTRY[network]?.[symbol];
97
+ }
98
+
99
+ /**
100
+ * Get the default token for a network
101
+ */
102
+ export function getDefaultToken(network: string): TokenConfig | undefined {
103
+ return DEFAULT_TOKENS[network];
104
+ }
105
+
106
+ /**
107
+ * Get asset ID for a token on a network
108
+ */
109
+ export function getAssetId(network: string, symbol: string = "USDT"): number | undefined {
110
+ return getTokenConfig(network, symbol)?.assetId;
111
+ }
package/src/types.ts ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Polkadot Asset Hub T402 Types
3
+ */
4
+
5
+ import type { Network } from "@t402/core/types";
6
+
7
+ /**
8
+ * Payment payload for exact-direct scheme on Polkadot
9
+ */
10
+ export type ExactDirectPolkadotPayload = {
11
+ /** Extrinsic hash (block hash + extrinsic index) */
12
+ extrinsicHash: string;
13
+ /** Block hash containing the extrinsic */
14
+ blockHash: string;
15
+ /** Extrinsic index within the block */
16
+ extrinsicIndex: number;
17
+ /** Sender address (SS58 format) */
18
+ from: string;
19
+ /** Recipient address (SS58 format) */
20
+ to: string;
21
+ /** Amount in smallest unit (with decimals) */
22
+ amount: string;
23
+ /** Asset ID */
24
+ assetId: number;
25
+ };
26
+
27
+ /**
28
+ * Result of a Polkadot extrinsic query
29
+ */
30
+ export interface PolkadotExtrinsicResult {
31
+ /** Extrinsic hash */
32
+ extrinsicHash: string;
33
+ /** Block hash */
34
+ blockHash: string;
35
+ /** Block number */
36
+ blockNumber: number;
37
+ /** Extrinsic index */
38
+ extrinsicIndex: number;
39
+ /** Timestamp (ISO 8601) */
40
+ timestamp: string;
41
+ /** Signer address */
42
+ signer: string;
43
+ /** Success status */
44
+ success: boolean;
45
+ /** Module name (e.g., "assets") */
46
+ module: string;
47
+ /** Call name (e.g., "transfer") */
48
+ call: string;
49
+ /** Call arguments */
50
+ args: Record<string, unknown>;
51
+ /** Events emitted by the extrinsic */
52
+ events: PolkadotEvent[];
53
+ }
54
+
55
+ /**
56
+ * Polkadot event structure
57
+ */
58
+ export interface PolkadotEvent {
59
+ /** Module name */
60
+ module: string;
61
+ /** Event name */
62
+ name: string;
63
+ /** Event data */
64
+ data: Record<string, unknown>;
65
+ }
66
+
67
+ /**
68
+ * Parsed asset transfer from extrinsic
69
+ */
70
+ export interface ParsedAssetTransfer {
71
+ /** Asset ID */
72
+ assetId: number;
73
+ /** Sender address */
74
+ from: string;
75
+ /** Recipient address */
76
+ to: string;
77
+ /** Amount transferred */
78
+ amount: string;
79
+ /** Whether the transfer was successful */
80
+ success: boolean;
81
+ }
82
+
83
+ /**
84
+ * Signer interface for Polkadot facilitator
85
+ */
86
+ export interface FacilitatorPolkadotSigner {
87
+ /**
88
+ * Get the facilitator's addresses for a network
89
+ */
90
+ getAddresses(network: Network): string[];
91
+
92
+ /**
93
+ * Query an extrinsic by hash
94
+ */
95
+ queryExtrinsic(
96
+ extrinsicHash: string,
97
+ blockHash?: string,
98
+ extrinsicIndex?: number,
99
+ ): Promise<PolkadotExtrinsicResult | null>;
100
+
101
+ /**
102
+ * Get balance of an asset for an address
103
+ */
104
+ getBalance(assetId: number, address: string): Promise<string>;
105
+ }
106
+
107
+ /**
108
+ * Client signer interface for signing transactions
109
+ */
110
+ export interface ClientPolkadotSigner {
111
+ /**
112
+ * Get the signer's address
113
+ */
114
+ getAddress(): Promise<string>;
115
+
116
+ /**
117
+ * Sign and submit an asset transfer
118
+ * Returns the extrinsic hash, block hash, and extrinsic index
119
+ */
120
+ transferAsset(
121
+ assetId: number,
122
+ to: string,
123
+ amount: string,
124
+ ): Promise<{
125
+ extrinsicHash: string;
126
+ blockHash: string;
127
+ extrinsicIndex: number;
128
+ }>;
129
+ }
130
+
131
+ /**
132
+ * Configuration for Polkadot server
133
+ */
134
+ export interface PolkadotServerConfig {
135
+ /** Custom RPC URL */
136
+ rpcUrl?: string;
137
+ /** Custom indexer URL */
138
+ indexerUrl?: string;
139
+ /** Facilitator addresses per network */
140
+ facilitatorAddresses?: Record<string, string>;
141
+ }
142
+
143
+ /**
144
+ * Configuration for Polkadot facilitator
145
+ */
146
+ export interface PolkadotFacilitatorConfig {
147
+ /** Maximum age of extrinsic to accept (in seconds) */
148
+ maxExtrinsicAge?: number;
149
+ /** Duration to cache used extrinsic hashes */
150
+ usedExtrinsicCacheDuration?: number;
151
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Polkadot Asset Hub Utility Functions
3
+ */
4
+
5
+ import type { PolkadotExtrinsicResult, ParsedAssetTransfer } from "./types.js";
6
+
7
+ /**
8
+ * Validate a Polkadot SS58 address format
9
+ * SS58 addresses are base58-encoded with a checksum
10
+ */
11
+ export function isValidAddress(address: string): boolean {
12
+ if (!address || typeof address !== "string") {
13
+ return false;
14
+ }
15
+
16
+ // SS58 addresses typically start with 1 (Polkadot), or have other prefixes
17
+ // Length is typically 47-48 characters for Polkadot addresses
18
+ // For a simple validation, check base58 characters and length
19
+ const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{45,50}$/;
20
+ return base58Regex.test(address);
21
+ }
22
+
23
+ /**
24
+ * Validate an extrinsic hash format
25
+ * Extrinsic hashes are 32-byte hex strings prefixed with 0x
26
+ */
27
+ export function isValidExtrinsicHash(hash: string): boolean {
28
+ if (!hash || typeof hash !== "string") {
29
+ return false;
30
+ }
31
+ return /^0x[a-fA-F0-9]{64}$/.test(hash);
32
+ }
33
+
34
+ /**
35
+ * Validate a block hash format
36
+ */
37
+ export function isValidBlockHash(hash: string): boolean {
38
+ return isValidExtrinsicHash(hash); // Same format
39
+ }
40
+
41
+ /**
42
+ * Compare two SS58 addresses (case-sensitive)
43
+ */
44
+ export function compareAddresses(addr1: string, addr2: string): boolean {
45
+ return addr1 === addr2;
46
+ }
47
+
48
+ /**
49
+ * Format an amount with decimals for display
50
+ */
51
+ export function formatAmount(amount: string, decimals: number): string {
52
+ const amountBigInt = BigInt(amount);
53
+ const divisor = BigInt(10 ** decimals);
54
+ const wholePart = amountBigInt / divisor;
55
+ const fractionalPart = amountBigInt % divisor;
56
+
57
+ if (fractionalPart === 0n) {
58
+ return wholePart.toString();
59
+ }
60
+
61
+ const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
62
+ const trimmedFractional = fractionalStr.replace(/0+$/, "");
63
+ return `${wholePart}.${trimmedFractional}`;
64
+ }
65
+
66
+ /**
67
+ * Parse an amount string to the smallest unit (with decimals applied)
68
+ */
69
+ export function parseAmount(amount: string, decimals: number): string {
70
+ const parts = amount.split(".");
71
+ const wholePart = parts[0] || "0";
72
+ const fractionalPart = (parts[1] || "").padEnd(decimals, "0").slice(0, decimals);
73
+ return BigInt(wholePart + fractionalPart).toString();
74
+ }
75
+
76
+ /**
77
+ * Extract asset transfer details from an extrinsic result
78
+ */
79
+ export function extractAssetTransfer(
80
+ result: PolkadotExtrinsicResult,
81
+ ): ParsedAssetTransfer | null {
82
+ if (!result.success) {
83
+ return null;
84
+ }
85
+
86
+ // Check if this is an assets.transfer or assets.transferKeepAlive call
87
+ if (result.module !== "assets") {
88
+ return null;
89
+ }
90
+
91
+ if (result.call !== "transfer" && result.call !== "transferKeepAlive") {
92
+ return null;
93
+ }
94
+
95
+ // Extract transfer details from args
96
+ const assetId = result.args.id as number | undefined;
97
+ const to = result.args.target as string | undefined;
98
+ const amount = result.args.amount as string | undefined;
99
+
100
+ if (assetId === undefined || !to || !amount) {
101
+ return null;
102
+ }
103
+
104
+ return {
105
+ assetId,
106
+ from: result.signer,
107
+ to,
108
+ amount: amount.toString(),
109
+ success: true,
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Extract asset transfer from events (alternative method)
115
+ */
116
+ export function extractAssetTransferFromEvents(
117
+ result: PolkadotExtrinsicResult,
118
+ ): ParsedAssetTransfer | null {
119
+ if (!result.success) {
120
+ return null;
121
+ }
122
+
123
+ // Look for assets.Transferred event
124
+ const transferEvent = result.events.find(
125
+ (e) => e.module === "assets" && e.name === "Transferred",
126
+ );
127
+
128
+ if (!transferEvent) {
129
+ return null;
130
+ }
131
+
132
+ const assetId = transferEvent.data.assetId as number | undefined;
133
+ const from = transferEvent.data.from as string | undefined;
134
+ const to = transferEvent.data.to as string | undefined;
135
+ const amount = transferEvent.data.amount as string | undefined;
136
+
137
+ if (assetId === undefined || !from || !to || !amount) {
138
+ return null;
139
+ }
140
+
141
+ return {
142
+ assetId,
143
+ from,
144
+ to,
145
+ amount: amount.toString(),
146
+ success: true,
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Build a unique extrinsic identifier from block hash and index
152
+ */
153
+ export function buildExtrinsicId(blockHash: string, extrinsicIndex: number): string {
154
+ return `${blockHash}-${extrinsicIndex}`;
155
+ }
156
+
157
+ /**
158
+ * Parse an extrinsic identifier back to components
159
+ */
160
+ export function parseExtrinsicId(
161
+ extrinsicId: string,
162
+ ): { blockHash: string; extrinsicIndex: number } | null {
163
+ const lastDashIndex = extrinsicId.lastIndexOf("-");
164
+ if (lastDashIndex === -1) {
165
+ return null;
166
+ }
167
+
168
+ const blockHash = extrinsicId.slice(0, lastDashIndex);
169
+ const extrinsicIndex = parseInt(extrinsicId.slice(lastDashIndex + 1), 10);
170
+
171
+ if (!isValidBlockHash(blockHash) || isNaN(extrinsicIndex)) {
172
+ return null;
173
+ }
174
+
175
+ return { blockHash, extrinsicIndex };
176
+ }