uvd-x402-sdk 2.0.1

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +782 -0
  3. package/dist/index-BrBqP1I8.d.ts +199 -0
  4. package/dist/index-D6Sr4ARD.d.mts +429 -0
  5. package/dist/index-D6Sr4ARD.d.ts +429 -0
  6. package/dist/index-DJ4Cvrev.d.mts +199 -0
  7. package/dist/index.d.mts +3 -0
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.js +1178 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/index.mjs +1146 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/dist/providers/evm/index.d.mts +84 -0
  14. package/dist/providers/evm/index.d.ts +84 -0
  15. package/dist/providers/evm/index.js +740 -0
  16. package/dist/providers/evm/index.js.map +1 -0
  17. package/dist/providers/evm/index.mjs +735 -0
  18. package/dist/providers/evm/index.mjs.map +1 -0
  19. package/dist/providers/near/index.d.mts +99 -0
  20. package/dist/providers/near/index.d.ts +99 -0
  21. package/dist/providers/near/index.js +483 -0
  22. package/dist/providers/near/index.js.map +1 -0
  23. package/dist/providers/near/index.mjs +478 -0
  24. package/dist/providers/near/index.mjs.map +1 -0
  25. package/dist/providers/solana/index.d.mts +115 -0
  26. package/dist/providers/solana/index.d.ts +115 -0
  27. package/dist/providers/solana/index.js +771 -0
  28. package/dist/providers/solana/index.js.map +1 -0
  29. package/dist/providers/solana/index.mjs +765 -0
  30. package/dist/providers/solana/index.mjs.map +1 -0
  31. package/dist/providers/stellar/index.d.mts +67 -0
  32. package/dist/providers/stellar/index.d.ts +67 -0
  33. package/dist/providers/stellar/index.js +306 -0
  34. package/dist/providers/stellar/index.js.map +1 -0
  35. package/dist/providers/stellar/index.mjs +301 -0
  36. package/dist/providers/stellar/index.mjs.map +1 -0
  37. package/dist/react/index.d.mts +73 -0
  38. package/dist/react/index.d.ts +73 -0
  39. package/dist/react/index.js +1218 -0
  40. package/dist/react/index.js.map +1 -0
  41. package/dist/react/index.mjs +1211 -0
  42. package/dist/react/index.mjs.map +1 -0
  43. package/dist/utils/index.d.mts +103 -0
  44. package/dist/utils/index.d.ts +103 -0
  45. package/dist/utils/index.js +575 -0
  46. package/dist/utils/index.js.map +1 -0
  47. package/dist/utils/index.mjs +562 -0
  48. package/dist/utils/index.mjs.map +1 -0
  49. package/package.json +149 -0
  50. package/src/chains/index.ts +539 -0
  51. package/src/client/X402Client.ts +663 -0
  52. package/src/client/index.ts +1 -0
  53. package/src/index.ts +166 -0
  54. package/src/providers/evm/index.ts +394 -0
  55. package/src/providers/near/index.ts +664 -0
  56. package/src/providers/solana/index.ts +489 -0
  57. package/src/providers/stellar/index.ts +376 -0
  58. package/src/react/index.tsx +417 -0
  59. package/src/types/index.ts +561 -0
  60. package/src/utils/index.ts +20 -0
  61. package/src/utils/x402.ts +295 -0
@@ -0,0 +1,664 @@
1
+ /**
2
+ * uvd-x402-sdk - NEAR Provider
3
+ *
4
+ * Provides NEAR wallet connection and payment creation via MyNearWallet or Meteor.
5
+ * Uses NEP-366 meta-transactions where the facilitator pays all gas fees.
6
+ *
7
+ * NEP-366 Flow:
8
+ * 1. User creates a DelegateAction (ft_transfer on USDC contract)
9
+ * 2. User signs the DelegateAction with their ED25519 key
10
+ * 3. SignedDelegateAction is sent to facilitator
11
+ * 4. Facilitator wraps it and submits to NEAR, paying all gas
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { NEARProvider } from 'uvd-x402-sdk/near';
16
+ * import { getChainByName } from 'uvd-x402-sdk';
17
+ *
18
+ * const near = new NEARProvider();
19
+ *
20
+ * // Connect
21
+ * const accountId = await near.connect();
22
+ *
23
+ * // Create payment
24
+ * const chainConfig = getChainByName('near')!;
25
+ * const paymentPayload = await near.signPayment(paymentInfo, chainConfig);
26
+ * const header = near.encodePaymentHeader(paymentPayload);
27
+ * ```
28
+ */
29
+
30
+ import type {
31
+ ChainConfig,
32
+ PaymentInfo,
33
+ NEARPaymentPayload,
34
+ WalletAdapter,
35
+ } from '../../types';
36
+ import { X402Error } from '../../types';
37
+
38
+ // NEAR configuration
39
+ const NEAR_CONFIG = {
40
+ networkId: 'mainnet',
41
+ nodeUrl: 'https://rpc.mainnet.near.org',
42
+ walletUrl: 'https://wallet.mainnet.near.org',
43
+ helperUrl: 'https://helper.mainnet.near.org',
44
+ };
45
+
46
+ // NEP-366 prefix: (2^30 + 366) as u32 little-endian
47
+ const NEP366_PREFIX = new Uint8Array([0x6e, 0x01, 0x00, 0x40]);
48
+
49
+ /**
50
+ * Simple Borsh serializer for NEAR transactions
51
+ */
52
+ class BorshSerializer {
53
+ private buffer: number[] = [];
54
+
55
+ writeU8(value: number): void {
56
+ this.buffer.push(value & 0xff);
57
+ }
58
+
59
+ writeU32(value: number): void {
60
+ this.buffer.push(value & 0xff);
61
+ this.buffer.push((value >> 8) & 0xff);
62
+ this.buffer.push((value >> 16) & 0xff);
63
+ this.buffer.push((value >> 24) & 0xff);
64
+ }
65
+
66
+ writeU64(value: bigint | number): void {
67
+ const val = BigInt(value);
68
+ for (let i = 0; i < 8; i++) {
69
+ this.buffer.push(Number((val >> BigInt(i * 8)) & BigInt(0xff)));
70
+ }
71
+ }
72
+
73
+ writeU128(value: bigint | number): void {
74
+ const val = BigInt(value);
75
+ for (let i = 0; i < 16; i++) {
76
+ this.buffer.push(Number((val >> BigInt(i * 8)) & BigInt(0xff)));
77
+ }
78
+ }
79
+
80
+ writeString(value: string): void {
81
+ const encoded = new TextEncoder().encode(value);
82
+ this.writeU32(encoded.length);
83
+ this.buffer.push(...encoded);
84
+ }
85
+
86
+ writeFixedBytes(data: Uint8Array): void {
87
+ this.buffer.push(...data);
88
+ }
89
+
90
+ writeBytes(data: Uint8Array): void {
91
+ this.writeU32(data.length);
92
+ this.buffer.push(...data);
93
+ }
94
+
95
+ getBytes(): Uint8Array {
96
+ return new Uint8Array(this.buffer);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Serialize a NonDelegateAction for ft_transfer (NEP-366)
102
+ */
103
+ function serializeNonDelegateAction(
104
+ receiverId: string,
105
+ amount: bigint,
106
+ memo?: string
107
+ ): Uint8Array {
108
+ const args: Record<string, string> = {
109
+ receiver_id: receiverId,
110
+ amount: amount.toString(),
111
+ };
112
+ if (memo) {
113
+ args.memo = memo;
114
+ }
115
+ const argsJson = new TextEncoder().encode(JSON.stringify(args));
116
+
117
+ const ser = new BorshSerializer();
118
+ ser.writeU8(2); // FunctionCall action type
119
+ ser.writeString('ft_transfer');
120
+ ser.writeBytes(argsJson);
121
+ ser.writeU64(BigInt(30_000_000_000_000)); // 30 TGas
122
+ ser.writeU128(BigInt(1)); // 1 yoctoNEAR deposit (required for ft_transfer)
123
+ return ser.getBytes();
124
+ }
125
+
126
+ /**
127
+ * Serialize a DelegateAction for NEP-366 meta-transactions
128
+ */
129
+ function serializeDelegateAction(
130
+ senderId: string,
131
+ receiverId: string,
132
+ actionsBytes: Uint8Array,
133
+ nonce: bigint,
134
+ maxBlockHeight: bigint,
135
+ publicKeyBytes: Uint8Array
136
+ ): Uint8Array {
137
+ const ser = new BorshSerializer();
138
+ ser.writeString(senderId);
139
+ ser.writeString(receiverId);
140
+ ser.writeU32(1); // 1 action
141
+ ser.writeFixedBytes(actionsBytes);
142
+ ser.writeU64(nonce);
143
+ ser.writeU64(maxBlockHeight);
144
+ ser.writeU8(0); // ED25519 key type
145
+ ser.writeFixedBytes(publicKeyBytes);
146
+ return ser.getBytes();
147
+ }
148
+
149
+ /**
150
+ * Serialize a SignedDelegateAction for NEP-366
151
+ */
152
+ function serializeSignedDelegateAction(
153
+ delegateActionBytes: Uint8Array,
154
+ signatureBytes: Uint8Array
155
+ ): Uint8Array {
156
+ const ser = new BorshSerializer();
157
+ ser.writeFixedBytes(delegateActionBytes);
158
+ ser.writeU8(0); // ED25519 signature type
159
+ ser.writeFixedBytes(signatureBytes);
160
+ return ser.getBytes();
161
+ }
162
+
163
+ /**
164
+ * SHA-256 hash function
165
+ */
166
+ async function sha256(data: Uint8Array): Promise<Uint8Array> {
167
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data as BufferSource);
168
+ return new Uint8Array(hashBuffer);
169
+ }
170
+
171
+ /**
172
+ * NEAR RPC call
173
+ */
174
+ async function nearRpcCall<T>(
175
+ rpcUrl: string,
176
+ method: string,
177
+ params: Record<string, unknown>
178
+ ): Promise<T> {
179
+ const response = await fetch(rpcUrl, {
180
+ method: 'POST',
181
+ headers: { 'Content-Type': 'application/json' },
182
+ body: JSON.stringify({
183
+ jsonrpc: '2.0',
184
+ id: 'dontcare',
185
+ method,
186
+ params,
187
+ }),
188
+ });
189
+
190
+ const data = await response.json();
191
+ if (data.error) {
192
+ throw new Error(`NEAR RPC error: ${JSON.stringify(data.error)}`);
193
+ }
194
+ return data.result as T;
195
+ }
196
+
197
+ /**
198
+ * NEAR wallet selector interface
199
+ */
200
+ interface NEARWalletSelector {
201
+ isSignedIn(): boolean;
202
+ getAccountId(): string | null;
203
+ signIn(options?: { contractId?: string }): Promise<void>;
204
+ signOut(): Promise<void>;
205
+ }
206
+
207
+ /**
208
+ * MyNearWallet interface
209
+ */
210
+ interface MyNearWallet {
211
+ isInstalled?: () => boolean;
212
+ signIn?: (options?: { contractId?: string }) => Promise<{ accountId: string }>;
213
+ signOut?: () => Promise<void>;
214
+ getAccountId?: () => string | null;
215
+ signMessage?: (params: {
216
+ message: Uint8Array;
217
+ recipient: string;
218
+ nonce: Uint8Array;
219
+ }) => Promise<{ signature: Uint8Array; publicKey: string }>;
220
+ }
221
+
222
+ /**
223
+ * NEARProvider - Wallet adapter for NEAR Protocol via MyNearWallet/Meteor
224
+ */
225
+ export class NEARProvider implements WalletAdapter {
226
+ readonly id = 'near-wallet';
227
+ readonly name = 'NEAR Wallet';
228
+ readonly networkType = 'near' as const;
229
+
230
+ private accountId: string | null = null;
231
+ private publicKey: Uint8Array | null = null;
232
+ private rpcUrl: string = NEAR_CONFIG.nodeUrl;
233
+
234
+ /**
235
+ * Check if NEAR wallet is available
236
+ */
237
+ isAvailable(): boolean {
238
+ if (typeof window === 'undefined') return false;
239
+ // Check for NEAR wallet selector or injected wallet
240
+ const win = window as Window & {
241
+ nearWalletSelector?: NEARWalletSelector;
242
+ myNearWallet?: MyNearWallet;
243
+ near?: { wallet?: NEARWalletSelector };
244
+ };
245
+ return !!(
246
+ win.nearWalletSelector ||
247
+ win.myNearWallet?.isInstalled?.() ||
248
+ win.near?.wallet
249
+ );
250
+ }
251
+
252
+ /**
253
+ * Connect to NEAR wallet
254
+ */
255
+ async connect(): Promise<string> {
256
+ // Try to get wallet from window
257
+ const win = window as Window & {
258
+ nearWalletSelector?: NEARWalletSelector;
259
+ myNearWallet?: MyNearWallet;
260
+ near?: { wallet?: NEARWalletSelector };
261
+ };
262
+
263
+ try {
264
+ // Try NEAR wallet selector first
265
+ if (win.nearWalletSelector) {
266
+ if (!win.nearWalletSelector.isSignedIn()) {
267
+ await win.nearWalletSelector.signIn();
268
+ }
269
+ const accountId = win.nearWalletSelector.getAccountId();
270
+ if (!accountId) {
271
+ throw new X402Error('Failed to get NEAR account ID', 'WALLET_CONNECTION_REJECTED');
272
+ }
273
+ this.accountId = accountId;
274
+ await this.fetchPublicKey();
275
+ return accountId;
276
+ }
277
+
278
+ // Try MyNearWallet
279
+ if (win.myNearWallet?.signIn) {
280
+ const result = await win.myNearWallet.signIn();
281
+ this.accountId = result.accountId;
282
+ await this.fetchPublicKey();
283
+ return result.accountId;
284
+ }
285
+
286
+ // Try legacy near.wallet
287
+ if (win.near?.wallet) {
288
+ if (!win.near.wallet.isSignedIn()) {
289
+ await win.near.wallet.signIn();
290
+ }
291
+ const accountId = win.near.wallet.getAccountId();
292
+ if (!accountId) {
293
+ throw new X402Error('Failed to get NEAR account ID', 'WALLET_CONNECTION_REJECTED');
294
+ }
295
+ this.accountId = accountId;
296
+ await this.fetchPublicKey();
297
+ return accountId;
298
+ }
299
+
300
+ throw new X402Error(
301
+ 'No NEAR wallet found. Please install MyNearWallet or Meteor.',
302
+ 'WALLET_NOT_FOUND'
303
+ );
304
+ } catch (error: unknown) {
305
+ if (error instanceof X402Error) throw error;
306
+
307
+ if (error instanceof Error) {
308
+ if (error.message.includes('User rejected') || error.message.includes('cancelled')) {
309
+ throw new X402Error('Connection rejected by user', 'WALLET_CONNECTION_REJECTED');
310
+ }
311
+ }
312
+
313
+ throw new X402Error(
314
+ `Failed to connect NEAR wallet: ${error instanceof Error ? error.message : 'Unknown error'}`,
315
+ 'UNKNOWN_ERROR',
316
+ error
317
+ );
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Disconnect from NEAR wallet
323
+ */
324
+ async disconnect(): Promise<void> {
325
+ const win = window as Window & {
326
+ nearWalletSelector?: NEARWalletSelector;
327
+ myNearWallet?: MyNearWallet;
328
+ near?: { wallet?: NEARWalletSelector };
329
+ };
330
+
331
+ try {
332
+ if (win.nearWalletSelector) {
333
+ await win.nearWalletSelector.signOut();
334
+ } else if (win.myNearWallet?.signOut) {
335
+ await win.myNearWallet.signOut();
336
+ } else if (win.near?.wallet) {
337
+ await win.near.wallet.signOut();
338
+ }
339
+ } catch {
340
+ // Ignore disconnect errors
341
+ }
342
+
343
+ this.accountId = null;
344
+ this.publicKey = null;
345
+ }
346
+
347
+ /**
348
+ * Get current account ID
349
+ */
350
+ getAddress(): string | null {
351
+ return this.accountId;
352
+ }
353
+
354
+ /**
355
+ * Get USDC balance on NEAR
356
+ */
357
+ async getBalance(chainConfig: ChainConfig): Promise<string> {
358
+ if (!this.accountId) {
359
+ throw new X402Error('Wallet not connected', 'WALLET_NOT_CONNECTED');
360
+ }
361
+
362
+ try {
363
+ const args = JSON.stringify({ account_id: this.accountId });
364
+ const argsBase64 = btoa(args);
365
+
366
+ const result = await nearRpcCall<{ result: number[] }>(
367
+ chainConfig.rpcUrl || this.rpcUrl,
368
+ 'query',
369
+ {
370
+ request_type: 'call_function',
371
+ finality: 'final',
372
+ account_id: chainConfig.usdc.address,
373
+ method_name: 'ft_balance_of',
374
+ args_base64: argsBase64,
375
+ }
376
+ );
377
+
378
+ const resultBytes = new Uint8Array(result.result);
379
+ const balanceStr = new TextDecoder().decode(resultBytes).replace(/"/g, '');
380
+ const balance = Number(balanceStr) / Math.pow(10, chainConfig.usdc.decimals);
381
+
382
+ return balance.toFixed(2);
383
+ } catch {
384
+ return '0.00';
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Create NEAR payment (NEP-366 SignedDelegateAction)
390
+ *
391
+ * User signs a DelegateAction that authorizes ft_transfer.
392
+ * Facilitator wraps this and submits to NEAR, paying all gas fees.
393
+ */
394
+ async signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string> {
395
+ if (!this.accountId || !this.publicKey) {
396
+ throw new X402Error('Wallet not connected', 'WALLET_NOT_CONNECTED');
397
+ }
398
+
399
+ // Get recipient
400
+ const recipient = paymentInfo.recipients?.near || paymentInfo.recipient;
401
+
402
+ // Parse amount (6 decimals for USDC)
403
+ const amount = BigInt(Math.floor(parseFloat(paymentInfo.amount) * 1_000_000));
404
+
405
+ try {
406
+ // Get access key nonce
407
+ const accessKey = await this.getAccessKeyNonce();
408
+ const nonce = BigInt(accessKey.nonce) + BigInt(1);
409
+
410
+ // Get current block height
411
+ const block = await this.getLatestBlock();
412
+ const maxBlockHeight = BigInt(block.header.height) + BigInt(1000);
413
+
414
+ // Serialize ft_transfer action
415
+ const actionBytes = serializeNonDelegateAction(
416
+ recipient,
417
+ amount,
418
+ 'x402 payment via uvd-x402-sdk'
419
+ );
420
+
421
+ // Serialize DelegateAction
422
+ const delegateActionBytes = serializeDelegateAction(
423
+ this.accountId,
424
+ chainConfig.usdc.address, // USDC contract
425
+ actionBytes,
426
+ nonce,
427
+ maxBlockHeight,
428
+ this.publicKey
429
+ );
430
+
431
+ // Create hash for signing (NEP-366 prefix + delegateAction)
432
+ const hashInput = new Uint8Array(NEP366_PREFIX.length + delegateActionBytes.length);
433
+ hashInput.set(NEP366_PREFIX, 0);
434
+ hashInput.set(delegateActionBytes, NEP366_PREFIX.length);
435
+ const delegateHash = await sha256(hashInput);
436
+
437
+ // Sign the hash
438
+ const signature = await this.signMessage(delegateHash);
439
+
440
+ // Serialize SignedDelegateAction
441
+ const signedDelegateActionBytes = serializeSignedDelegateAction(
442
+ delegateActionBytes,
443
+ signature
444
+ );
445
+
446
+ // Base64 encode
447
+ const signedDelegateB64 = btoa(
448
+ String.fromCharCode(...signedDelegateActionBytes)
449
+ );
450
+
451
+ const payload: NEARPaymentPayload = {
452
+ signedDelegateAction: signedDelegateB64,
453
+ network: 'near',
454
+ };
455
+
456
+ return JSON.stringify(payload);
457
+ } catch (error: unknown) {
458
+ if (error instanceof X402Error) throw error;
459
+
460
+ if (error instanceof Error) {
461
+ if (error.message.includes('User rejected') || error.message.includes('cancelled')) {
462
+ throw new X402Error('Signature rejected by user', 'SIGNATURE_REJECTED');
463
+ }
464
+ }
465
+
466
+ throw new X402Error(
467
+ `Failed to create NEAR payment: ${error instanceof Error ? error.message : 'Unknown error'}`,
468
+ 'PAYMENT_FAILED',
469
+ error
470
+ );
471
+ }
472
+ }
473
+
474
+ /**
475
+ * Encode NEAR payment as X-PAYMENT header
476
+ */
477
+ encodePaymentHeader(paymentPayload: string): string {
478
+ const payload = JSON.parse(paymentPayload) as NEARPaymentPayload;
479
+
480
+ const x402Payload = {
481
+ x402Version: 1,
482
+ scheme: 'exact',
483
+ network: 'near',
484
+ payload: {
485
+ signedDelegateAction: payload.signedDelegateAction,
486
+ },
487
+ };
488
+
489
+ return btoa(JSON.stringify(x402Payload));
490
+ }
491
+
492
+ // Private helpers
493
+
494
+ /**
495
+ * Fetch public key from NEAR RPC
496
+ */
497
+ private async fetchPublicKey(): Promise<void> {
498
+ if (!this.accountId) return;
499
+
500
+ try {
501
+ const result = await nearRpcCall<{ keys: Array<{ public_key: string }> }>(
502
+ this.rpcUrl,
503
+ 'query',
504
+ {
505
+ request_type: 'view_access_key_list',
506
+ finality: 'final',
507
+ account_id: this.accountId,
508
+ }
509
+ );
510
+
511
+ if (result.keys && result.keys.length > 0) {
512
+ // Get first full access key
513
+ const keyStr = result.keys[0].public_key;
514
+ // Remove ed25519: prefix and decode base58
515
+ const keyB58 = keyStr.replace('ed25519:', '');
516
+ this.publicKey = this.base58Decode(keyB58);
517
+ }
518
+ } catch {
519
+ // Will be set during signing if not available
520
+ }
521
+ }
522
+
523
+ /**
524
+ * Get access key nonce from NEAR RPC
525
+ */
526
+ private async getAccessKeyNonce(): Promise<{ nonce: number }> {
527
+ if (!this.accountId || !this.publicKey) {
528
+ throw new Error('Account not connected');
529
+ }
530
+
531
+ const publicKeyB58 = this.base58Encode(this.publicKey);
532
+
533
+ const result = await nearRpcCall<{ nonce: number }>(
534
+ this.rpcUrl,
535
+ 'query',
536
+ {
537
+ request_type: 'view_access_key',
538
+ finality: 'final',
539
+ account_id: this.accountId,
540
+ public_key: `ed25519:${publicKeyB58}`,
541
+ }
542
+ );
543
+
544
+ return result;
545
+ }
546
+
547
+ /**
548
+ * Get latest block from NEAR RPC
549
+ */
550
+ private async getLatestBlock(): Promise<{ header: { height: number } }> {
551
+ return nearRpcCall(this.rpcUrl, 'block', { finality: 'final' });
552
+ }
553
+
554
+ /**
555
+ * Sign a message using the connected wallet
556
+ */
557
+ private async signMessage(message: Uint8Array): Promise<Uint8Array> {
558
+ const win = window as Window & {
559
+ nearWalletSelector?: NEARWalletSelector;
560
+ myNearWallet?: MyNearWallet;
561
+ };
562
+
563
+ // Try MyNearWallet signMessage
564
+ if (win.myNearWallet?.signMessage) {
565
+ const result = await win.myNearWallet.signMessage({
566
+ message,
567
+ recipient: 'uvd-x402-sdk',
568
+ nonce: crypto.getRandomValues(new Uint8Array(32)),
569
+ });
570
+ return result.signature;
571
+ }
572
+
573
+ // For other wallets, we need to use the @near-js/crypto library
574
+ // This will be handled by the wallet selector
575
+ throw new X402Error(
576
+ 'Signing not supported. Please use MyNearWallet or install @near-wallet-selector/core',
577
+ 'PAYMENT_FAILED'
578
+ );
579
+ }
580
+
581
+ /**
582
+ * Base58 decode (NEAR style)
583
+ */
584
+ private base58Decode(str: string): Uint8Array {
585
+ const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
586
+ const ALPHABET_MAP: Record<string, number> = {};
587
+ for (let i = 0; i < ALPHABET.length; i++) {
588
+ ALPHABET_MAP[ALPHABET[i]] = i;
589
+ }
590
+
591
+ let bytes: number[] = [0];
592
+ for (let i = 0; i < str.length; i++) {
593
+ const value = ALPHABET_MAP[str[i]];
594
+ if (value === undefined) {
595
+ throw new Error(`Invalid base58 character: ${str[i]}`);
596
+ }
597
+
598
+ for (let j = 0; j < bytes.length; j++) {
599
+ bytes[j] *= 58;
600
+ }
601
+ bytes[0] += value;
602
+
603
+ let carry = 0;
604
+ for (let j = 0; j < bytes.length; j++) {
605
+ bytes[j] += carry;
606
+ carry = bytes[j] >> 8;
607
+ bytes[j] &= 0xff;
608
+ }
609
+
610
+ while (carry) {
611
+ bytes.push(carry & 0xff);
612
+ carry >>= 8;
613
+ }
614
+ }
615
+
616
+ // Handle leading zeros
617
+ for (let i = 0; i < str.length && str[i] === '1'; i++) {
618
+ bytes.push(0);
619
+ }
620
+
621
+ return new Uint8Array(bytes.reverse());
622
+ }
623
+
624
+ /**
625
+ * Base58 encode (NEAR style)
626
+ */
627
+ private base58Encode(bytes: Uint8Array): string {
628
+ const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
629
+
630
+ let digits = [0];
631
+ for (let i = 0; i < bytes.length; i++) {
632
+ for (let j = 0; j < digits.length; j++) {
633
+ digits[j] <<= 8;
634
+ }
635
+ digits[0] += bytes[i];
636
+
637
+ let carry = 0;
638
+ for (let j = 0; j < digits.length; j++) {
639
+ digits[j] += carry;
640
+ carry = (digits[j] / 58) | 0;
641
+ digits[j] %= 58;
642
+ }
643
+
644
+ while (carry) {
645
+ digits.push(carry % 58);
646
+ carry = (carry / 58) | 0;
647
+ }
648
+ }
649
+
650
+ // Handle leading zeros
651
+ let str = '';
652
+ for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
653
+ str += '1';
654
+ }
655
+
656
+ for (let i = digits.length - 1; i >= 0; i--) {
657
+ str += ALPHABET[digits[i]];
658
+ }
659
+
660
+ return str;
661
+ }
662
+ }
663
+
664
+ export default NEARProvider;