pwc-sdk-wallet 0.6.3

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 (46) hide show
  1. package/README.md +2062 -0
  2. package/dist/Vault.d.ts +493 -0
  3. package/dist/Vault.js +1090 -0
  4. package/dist/chain/ChainService.d.ts +84 -0
  5. package/dist/chain/ChainService.js +136 -0
  6. package/dist/chain/SolanaChainService.d.ts +94 -0
  7. package/dist/chain/SolanaChainService.js +167 -0
  8. package/dist/config/chains.d.ts +233 -0
  9. package/dist/config/chains.js +285 -0
  10. package/dist/config/constants.d.ts +102 -0
  11. package/dist/config/constants.js +109 -0
  12. package/dist/config/environment.d.ts +46 -0
  13. package/dist/config/environment.js +114 -0
  14. package/dist/config/gas.d.ts +107 -0
  15. package/dist/config/gas.js +123 -0
  16. package/dist/crypto/EncryptionService.d.ts +74 -0
  17. package/dist/crypto/EncryptionService.js +178 -0
  18. package/dist/index.d.ts +22 -0
  19. package/dist/index.js +96 -0
  20. package/dist/keyrings/HDKeyring.d.ts +72 -0
  21. package/dist/keyrings/HDKeyring.js +156 -0
  22. package/dist/keyrings/SimpleKeyring.d.ts +31 -0
  23. package/dist/keyrings/SimpleKeyring.js +49 -0
  24. package/dist/keyrings/SolanaKeyring.d.ts +71 -0
  25. package/dist/keyrings/SolanaKeyring.js +159 -0
  26. package/dist/services/BatchProcessor.d.ts +42 -0
  27. package/dist/services/BatchProcessor.js +188 -0
  28. package/dist/services/MultiTransferService.d.ts +78 -0
  29. package/dist/services/MultiTransferService.js +252 -0
  30. package/dist/services/QRCodeService.d.ts +193 -0
  31. package/dist/services/QRCodeService.js +299 -0
  32. package/dist/services/TokenUtils.d.ts +307 -0
  33. package/dist/services/TokenUtils.js +429 -0
  34. package/dist/services/nft/MetadataResolver.d.ts +57 -0
  35. package/dist/services/nft/MetadataResolver.js +162 -0
  36. package/dist/services/nft/NFTAPIService.d.ts +53 -0
  37. package/dist/services/nft/NFTAPIService.js +122 -0
  38. package/dist/services/nft/NFTService.d.ts +241 -0
  39. package/dist/services/nft/NFTService.js +910 -0
  40. package/dist/types/multiTransfer.d.ts +68 -0
  41. package/dist/types/multiTransfer.js +2 -0
  42. package/dist/types/nft/index.d.ts +68 -0
  43. package/dist/types/nft/index.js +2 -0
  44. package/dist/types/nft.d.ts +265 -0
  45. package/dist/types/nft.js +6 -0
  46. package/package.json +70 -0
@@ -0,0 +1,429 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getProviderAuto = getProviderAuto;
4
+ exports.getTokenBalance = getTokenBalance;
5
+ exports.getTokenInfo = getTokenInfo;
6
+ exports.getNativeBalance = getNativeBalance;
7
+ exports.checkAllowance = checkAllowance;
8
+ exports.buildTransaction = buildTransaction;
9
+ exports.signTransactionWithVault = signTransactionWithVault;
10
+ exports.approveTokenWithVault = approveTokenWithVault;
11
+ exports.sendTransaction = sendTransaction;
12
+ exports.trackTxStatus = trackTxStatus;
13
+ exports.getNonce = getNonce;
14
+ exports.signMessageWithVault = signMessageWithVault;
15
+ exports.signMessage = signMessage;
16
+ exports.verifyMessage = verifyMessage;
17
+ exports.signTypedDataWithVault = signTypedDataWithVault;
18
+ exports.signTypedData = signTypedData;
19
+ exports.verifyTypedData = verifyTypedData;
20
+ exports.signMessageWithNonce = signMessageWithNonce;
21
+ exports.signMessageWithNoncePrivateKey = signMessageWithNoncePrivateKey;
22
+ exports.verifyMessageWithNonce = verifyMessageWithNonce;
23
+ const ethers_1 = require("ethers");
24
+ const chains_1 = require("../config/chains");
25
+ const ERC20_ABI = [
26
+ "function name() view returns (string)",
27
+ "function symbol() view returns (string)",
28
+ "function decimals() view returns (uint8)",
29
+ "function totalSupply() view returns (uint256)",
30
+ "function balanceOf(address) view returns (uint)",
31
+ "function transfer(address to, uint amount) returns (bool)",
32
+ "function approve(address spender, uint amount) returns (bool)",
33
+ "function allowance(address owner, address spender) view returns (uint)"
34
+ ];
35
+ // Provider manager: cache provider per chainId
36
+ const providerCache = {};
37
+ /**
38
+ * Gets or creates a cached provider for the specified chain.
39
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
40
+ * @returns Cached ethers provider for the chain
41
+ */
42
+ function getProviderAuto(chainId) {
43
+ if (!providerCache[chainId]) {
44
+ providerCache[chainId] = (0, chains_1.getProvider)(chainId);
45
+ }
46
+ return providerCache[chainId];
47
+ }
48
+ /**
49
+ * Gets the token balance for a specific account.
50
+ * @param tokenAddress - The ERC-20 token contract address
51
+ * @param account - The account address to check balance for
52
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
53
+ * @returns Promise resolving to the token balance as bigint
54
+ * @example
55
+ * ```typescript
56
+ * const balance = await getTokenBalance('0xToken...', '0xAccount...', '1');
57
+ * console.log('Balance:', ethers.formatUnits(balance, 18));
58
+ * ```
59
+ */
60
+ async function getTokenBalance(tokenAddress, account, chainId) {
61
+ const provider = getProviderAuto(chainId);
62
+ const contract = new ethers_1.Contract(tokenAddress, ERC20_ABI, provider);
63
+ return contract.balanceOf(account);
64
+ }
65
+ /**
66
+ * Gets comprehensive information about an ERC-20 token.
67
+ * @param tokenAddress - The ERC-20 token contract address
68
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
69
+ * @returns Promise resolving to token information including name, symbol, decimals, total supply
70
+ * @example
71
+ * ```typescript
72
+ * const info = await getTokenInfo('0xToken...', '1');
73
+ * console.log('Token:', info.name, '(', info.symbol, ')');
74
+ * ```
75
+ */
76
+ async function getTokenInfo(tokenAddress, chainId) {
77
+ const provider = getProviderAuto(chainId);
78
+ const contract = new ethers_1.Contract(tokenAddress, ERC20_ABI, provider);
79
+ const [name, symbol, decimals, totalSupply] = await Promise.all([
80
+ contract.name(),
81
+ contract.symbol(),
82
+ contract.decimals(),
83
+ contract.totalSupply()
84
+ ]);
85
+ return { name, symbol, decimals, totalSupply, address: tokenAddress };
86
+ }
87
+ /**
88
+ * Gets the native token balance (ETH, BNB, MATIC, etc.) for an account.
89
+ * @param account - The account address to check balance for
90
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
91
+ * @returns Promise resolving to the native token balance as bigint
92
+ * @example
93
+ * ```typescript
94
+ * const balance = await getNativeBalance('0xAccount...', '1');
95
+ * console.log('ETH Balance:', ethers.formatEther(balance));
96
+ * ```
97
+ */
98
+ async function getNativeBalance(account, chainId) {
99
+ const provider = getProviderAuto(chainId);
100
+ return provider.getBalance(account);
101
+ }
102
+ /**
103
+ * Checks the allowance granted by an owner to a spender for a specific token.
104
+ * @param tokenAddress - The ERC-20 token contract address
105
+ * @param owner - The token owner's address
106
+ * @param spender - The spender's address (e.g., DEX contract address)
107
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
108
+ * @returns Promise resolving to the allowance amount as bigint
109
+ * @example
110
+ * ```typescript
111
+ * const allowance = await checkAllowance('0xToken...', '0xOwner...', '0xSpender...', '1');
112
+ * console.log('Allowance:', ethers.formatUnits(allowance, 18));
113
+ * ```
114
+ */
115
+ async function checkAllowance(tokenAddress, owner, spender, chainId) {
116
+ const provider = getProviderAuto(chainId);
117
+ const contract = new ethers_1.Contract(tokenAddress, ERC20_ABI, provider);
118
+ return contract.allowance(owner, spender);
119
+ }
120
+ /**
121
+ * Builds a generic transaction for any contract method.
122
+ * @param contractAddress - The contract address to interact with
123
+ * @param abi - The contract ABI array
124
+ * @param method - The method name to call
125
+ * @param args - Arguments to pass to the method (default: [])
126
+ * @param value - Native token value to send with transaction (default: undefined)
127
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
128
+ * @returns Promise resolving to the unsigned transaction object
129
+ * @example
130
+ * ```typescript
131
+ * const tx = await buildTransaction({
132
+ * contractAddress: '0xContract...',
133
+ * abi: [...],
134
+ * method: 'transfer',
135
+ * args: ['0xTo...', '1000000000000000000'],
136
+ * chainId: '1'
137
+ * });
138
+ * ```
139
+ */
140
+ async function buildTransaction({ contractAddress, abi, method, args = [], value = undefined, chainId }) {
141
+ const provider = getProviderAuto(chainId);
142
+ const contract = new ethers_1.Contract(contractAddress, abi, provider);
143
+ const data = contract.interface.encodeFunctionData(method, args);
144
+ return {
145
+ to: contractAddress,
146
+ data,
147
+ value
148
+ };
149
+ }
150
+ /**
151
+ * Signs an unsigned transaction using Vault (RECOMMENDED).
152
+ * @param unsignedTx - The unsigned transaction object
153
+ * @param vault - The vault instance containing the account
154
+ * @param fromAddress - The sender's address
155
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
156
+ * @returns Promise resolving to the signed transaction as hex string
157
+ * @example
158
+ * ```typescript
159
+ * const signedTx = await signTransactionWithVault(unsignedTx, vault, '0xYourAddress', '1');
160
+ * ```
161
+ */
162
+ async function signTransactionWithVault(unsignedTx, vault, fromAddress, chainId) {
163
+ const privateKey = await vault.getPrivateKeyFor(fromAddress);
164
+ const provider = (0, chains_1.getProvider)(chainId);
165
+ const wallet = new ethers_1.Wallet(privateKey, provider);
166
+ return wallet.signTransaction(unsignedTx);
167
+ }
168
+ /**
169
+ * Approves a spender to spend tokens on behalf of the owner using Vault (RECOMMENDED).
170
+ * @param vault - The vault instance containing the owner's account
171
+ * @param fromAddress - The owner's address
172
+ * @param tokenAddress - The ERC-20 token contract address
173
+ * @param spender - The spender's address (e.g., DEX contract address)
174
+ * @param amount - The amount to approve (string or bigint)
175
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
176
+ * @returns Promise resolving to the transaction response
177
+ * @example
178
+ * ```typescript
179
+ * const receipt = await approveTokenWithVault(vault, '0xOwner...', '0xToken...', '0xSpender...', '1000', '1');
180
+ * ```
181
+ */
182
+ async function approveTokenWithVault(vault, fromAddress, tokenAddress, spender, amount, chainId) {
183
+ const privateKey = await vault.getPrivateKeyFor(fromAddress);
184
+ const provider = (0, chains_1.getProvider)(chainId);
185
+ const wallet = new ethers_1.Wallet(privateKey, provider);
186
+ const contract = new ethers_1.Contract(tokenAddress, ERC20_ABI, wallet);
187
+ const decimals = await contract.decimals();
188
+ const parsedAmount = typeof amount === 'string' ? ethers_1.ethers.parseUnits(amount, decimals) : amount;
189
+ const tx = await contract.approve(spender, parsedAmount);
190
+ if (typeof tx.wait === 'function') {
191
+ return tx.wait();
192
+ }
193
+ return tx;
194
+ }
195
+ /**
196
+ * Broadcasts a signed transaction to the network.
197
+ * @param signedTx - The signed transaction as hex string
198
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
199
+ * @returns Promise resolving to the transaction response
200
+ * @example
201
+ * ```typescript
202
+ * const txResponse = await sendTransaction(signedTx, '1');
203
+ * console.log('Transaction hash:', txResponse.hash);
204
+ * ```
205
+ */
206
+ async function sendTransaction(signedTx, chainId) {
207
+ const provider = getProviderAuto(chainId);
208
+ return provider.broadcastTransaction(signedTx);
209
+ }
210
+ /**
211
+ * Tracks the status of a transaction with polling and callback notifications.
212
+ * @param txHash - The transaction hash to track
213
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
214
+ * @param callback - Function called with status updates ('pending', 'confirmed', 'failed')
215
+ * @param pollInterval - Polling interval in milliseconds (default: 3000)
216
+ * @example
217
+ * ```typescript
218
+ * trackTxStatus('0xTxHash...', '1', (status, receipt) => {
219
+ * if (status === 'confirmed') {
220
+ * console.log('Transaction confirmed!');
221
+ * }
222
+ * });
223
+ * ```
224
+ */
225
+ async function trackTxStatus(txHash, chainId, callback, pollInterval = 3000) {
226
+ const provider = getProviderAuto(chainId);
227
+ let done = false;
228
+ while (!done) {
229
+ const receipt = await provider.getTransactionReceipt(txHash);
230
+ if (receipt) {
231
+ if (receipt.status === 1) {
232
+ callback('confirmed', receipt);
233
+ }
234
+ else {
235
+ callback('failed', receipt);
236
+ }
237
+ done = true;
238
+ }
239
+ else {
240
+ callback('pending');
241
+ await new Promise(res => setTimeout(res, pollInterval));
242
+ }
243
+ }
244
+ }
245
+ /**
246
+ * Gets the transaction count (nonce) for an address.
247
+ * This is useful for message signing with nonce and transaction building.
248
+ * @param address - The address to get nonce for
249
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
250
+ * @returns Promise resolving to the nonce as number
251
+ * @example
252
+ * ```typescript
253
+ * const nonce = await getNonce('0xYourAddress', '1');
254
+ * console.log('Current nonce:', nonce);
255
+ * ```
256
+ */
257
+ async function getNonce(address, chainId) {
258
+ const provider = getProviderAuto(chainId);
259
+ return provider.getTransactionCount(address);
260
+ }
261
+ /**
262
+ * Signs a message using Vault (RECOMMENDED).
263
+ * This is equivalent to MetaMask's personal_sign method.
264
+ * @param message - The message to sign (string or hex string)
265
+ * @param vault - The vault instance containing the account
266
+ * @param fromAddress - The signer's address
267
+ * @returns Promise resolving to the signature as hex string
268
+ * @example
269
+ * ```typescript
270
+ * const signature = await signMessageWithVault('Hello World', vault, '0xYourAddress');
271
+ * console.log('Signature:', signature);
272
+ * ```
273
+ */
274
+ async function signMessageWithVault(message, vault, fromAddress) {
275
+ const privateKey = await vault.getPrivateKeyFor(fromAddress);
276
+ const wallet = new ethers_1.Wallet(privateKey);
277
+ return wallet.signMessage(message);
278
+ }
279
+ /**
280
+ * Signs a message using private key (DEPRECATED).
281
+ * ⚠️ **DEPRECATED**: Use signMessageWithVault instead for better security.
282
+ * @param message - The message to sign (string or hex string)
283
+ * @param privateKey - The private key to sign with (without 0x prefix)
284
+ * @returns Promise resolving to the signature as hex string
285
+ * @example
286
+ * ```typescript
287
+ * const signature = await signMessage('Hello World', 'your-private-key');
288
+ * console.log('Signature:', signature);
289
+ * ```
290
+ */
291
+ async function signMessage(message, privateKey) {
292
+ const wallet = new ethers_1.Wallet(privateKey);
293
+ return wallet.signMessage(message);
294
+ }
295
+ /**
296
+ * Verifies a message signature and returns the signer's address.
297
+ * @param message - The original message that was signed
298
+ * @param signature - The signature to verify
299
+ * @returns Promise resolving to the signer's address
300
+ * @example
301
+ * ```typescript
302
+ * const signerAddress = await verifyMessage('Hello World', '0xSignature...');
303
+ * console.log('Message was signed by:', signerAddress);
304
+ * ```
305
+ */
306
+ async function verifyMessage(message, signature) {
307
+ return ethers_1.ethers.verifyMessage(message, signature);
308
+ }
309
+ /**
310
+ * Signs a typed data message using Vault (RECOMMENDED).
311
+ * This is equivalent to MetaMask's eth_signTypedData method.
312
+ * @param typedData - The typed data object to sign
313
+ * @param vault - The vault instance containing the account
314
+ * @param fromAddress - The signer's address
315
+ * @returns Promise resolving to the signature as hex string
316
+ * @example
317
+ * ```typescript
318
+ * const typedData = {
319
+ * types: {
320
+ * Person: [
321
+ * { name: 'name', type: 'string' },
322
+ * { name: 'wallet', type: 'address' }
323
+ * ]
324
+ * },
325
+ * primaryType: 'Person',
326
+ * domain: { name: 'MyApp', version: '1' },
327
+ * message: { name: 'Alice', wallet: '0x123...' }
328
+ * };
329
+ * const signature = await signTypedDataWithVault(typedData, vault, '0xYourAddress');
330
+ * ```
331
+ */
332
+ async function signTypedDataWithVault(typedData, vault, fromAddress) {
333
+ const privateKey = await vault.getPrivateKeyFor(fromAddress);
334
+ const wallet = new ethers_1.Wallet(privateKey);
335
+ return wallet.signTypedData(typedData.domain, typedData.types, typedData.message);
336
+ }
337
+ /**
338
+ * Signs a typed data message using private key (DEPRECATED).
339
+ * ⚠️ **DEPRECATED**: Use signTypedDataWithVault instead for better security.
340
+ * @param typedData - The typed data object to sign
341
+ * @param privateKey - The private key to sign with (without 0x prefix)
342
+ * @returns Promise resolving to the signature as hex string
343
+ * @example
344
+ * ```typescript
345
+ * const typedData = {
346
+ * types: { Person: [{ name: 'name', type: 'string' }] },
347
+ * primaryType: 'Person',
348
+ * domain: { name: 'MyApp' },
349
+ * message: { name: 'Alice' }
350
+ * };
351
+ * const signature = await signTypedData(typedData, 'your-private-key');
352
+ * ```
353
+ */
354
+ async function signTypedData(typedData, privateKey) {
355
+ const wallet = new ethers_1.Wallet(privateKey);
356
+ return wallet.signTypedData(typedData.domain, typedData.types, typedData.message);
357
+ }
358
+ /**
359
+ * Verifies a typed data signature and returns the signer's address.
360
+ * @param typedData - The original typed data that was signed
361
+ * @param signature - The signature to verify
362
+ * @returns Promise resolving to the signer's address
363
+ * @example
364
+ * ```typescript
365
+ * const signerAddress = await verifyTypedData(typedData, '0xSignature...');
366
+ * console.log('Typed data was signed by:', signerAddress);
367
+ * ```
368
+ */
369
+ async function verifyTypedData(typedData, signature) {
370
+ return ethers_1.ethers.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature);
371
+ }
372
+ /**
373
+ * Signs a message with nonce using Vault (RECOMMENDED).
374
+ * This includes nonce in the message to prevent replay attacks.
375
+ * @param message - The message to sign (string or hex string)
376
+ * @param vault - The vault instance containing the account
377
+ * @param fromAddress - The signer's address
378
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
379
+ * @returns Promise resolving to an object containing signature and nonce
380
+ * @example
381
+ * ```typescript
382
+ * const result = await signMessageWithNonce('Hello World', vault, '0xYourAddress', '1');
383
+ * console.log('Signature:', result.signature);
384
+ * console.log('Nonce:', result.nonce);
385
+ * ```
386
+ */
387
+ async function signMessageWithNonce(message, vault, fromAddress, chainId) {
388
+ const nonce = await getNonce(fromAddress, chainId);
389
+ const messageWithNonce = `${message}\nNonce: ${nonce}`;
390
+ const signature = await signMessageWithVault(messageWithNonce, vault, fromAddress);
391
+ return { signature, nonce };
392
+ }
393
+ /**
394
+ * Signs a message with nonce using private key (DEPRECATED).
395
+ * ⚠️ **DEPRECATED**: Use signMessageWithNonceWithVault instead for better security.
396
+ * @param message - The message to sign (string or hex string)
397
+ * @param privateKey - The private key to sign with (without 0x prefix)
398
+ * @param address - The signer's address (needed to get nonce)
399
+ * @param chainId - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
400
+ * @returns Promise resolving to an object containing signature and nonce
401
+ * @example
402
+ * ```typescript
403
+ * const result = await signMessageWithNoncePrivateKey('Hello World', 'your-private-key', '0xYourAddress', '1');
404
+ * console.log('Signature:', result.signature);
405
+ * console.log('Nonce:', result.nonce);
406
+ * ```
407
+ */
408
+ async function signMessageWithNoncePrivateKey(message, privateKey, address, chainId) {
409
+ const nonce = await getNonce(address, chainId);
410
+ const messageWithNonce = `${message}\nNonce: ${nonce}`;
411
+ const signature = await signMessage(messageWithNonce, privateKey);
412
+ return { signature, nonce };
413
+ }
414
+ /**
415
+ * Verifies a message signature with nonce and returns the signer's address.
416
+ * @param message - The original message that was signed (without nonce)
417
+ * @param signature - The signature to verify
418
+ * @param nonce - The nonce that was used in signing
419
+ * @returns Promise resolving to the signer's address
420
+ * @example
421
+ * ```typescript
422
+ * const signerAddress = await verifyMessageWithNonce('Hello World', '0xSignature...', 5);
423
+ * console.log('Message was signed by:', signerAddress);
424
+ * ```
425
+ */
426
+ async function verifyMessageWithNonce(message, signature, nonce) {
427
+ const messageWithNonce = `${message}\nNonce: ${nonce}`;
428
+ return verifyMessage(messageWithNonce, signature);
429
+ }
@@ -0,0 +1,57 @@
1
+ import { NFTMetadata } from '../../types/nft';
2
+ /**
3
+ * Service for resolving NFT metadata from various sources (IPFS, HTTP)
4
+ */
5
+ export declare class MetadataResolver {
6
+ private static readonly IPFS_GATEWAYS;
7
+ private static readonly CACHE_DURATION;
8
+ private static metadataCache;
9
+ /**
10
+ * Resolves metadata from a URI (IPFS or HTTP)
11
+ * @param uri - The metadata URI to resolve
12
+ * @returns Promise resolving to NFT metadata
13
+ */
14
+ resolveMetadata(uri: string): Promise<NFTMetadata>;
15
+ /**
16
+ * Resolves IPFS URI to HTTP URL using multiple gateways
17
+ * @param ipfsUri - IPFS URI (ipfs://...)
18
+ * @returns Promise resolving to HTTP URL
19
+ */
20
+ private resolveIPFS;
21
+ /**
22
+ * Fetches metadata from HTTP URL
23
+ * @param url - HTTP URL to fetch metadata from
24
+ * @returns Promise resolving to NFT metadata
25
+ */
26
+ private fetchMetadata;
27
+ /**
28
+ * Parses raw metadata into standardized format
29
+ * @param rawData - Raw metadata from contract
30
+ * @returns Parsed NFT metadata
31
+ */
32
+ private parseMetadata;
33
+ /**
34
+ * Gets cached metadata if available and not expired
35
+ * @param uri - Metadata URI
36
+ * @returns Cached metadata or null if not found/expired
37
+ */
38
+ private getCachedMetadata;
39
+ /**
40
+ * Caches metadata for future use
41
+ * @param uri - Metadata URI
42
+ * @param metadata - Metadata to cache
43
+ */
44
+ private cacheMetadata;
45
+ /**
46
+ * Clears the metadata cache
47
+ */
48
+ static clearCache(): void;
49
+ /**
50
+ * Gets cache statistics
51
+ * @returns Cache statistics
52
+ */
53
+ static getCacheStats(): {
54
+ size: number;
55
+ entries: number;
56
+ };
57
+ }
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MetadataResolver = void 0;
4
+ /**
5
+ * Service for resolving NFT metadata from various sources (IPFS, HTTP)
6
+ */
7
+ class MetadataResolver {
8
+ /**
9
+ * Resolves metadata from a URI (IPFS or HTTP)
10
+ * @param uri - The metadata URI to resolve
11
+ * @returns Promise resolving to NFT metadata
12
+ */
13
+ async resolveMetadata(uri) {
14
+ // Check cache first
15
+ const cached = this.getCachedMetadata(uri);
16
+ if (cached) {
17
+ return cached;
18
+ }
19
+ let resolvedUri;
20
+ if (uri.startsWith('ipfs://')) {
21
+ resolvedUri = await this.resolveIPFS(uri);
22
+ }
23
+ else if (uri.startsWith('http://') || uri.startsWith('https://')) {
24
+ resolvedUri = uri;
25
+ }
26
+ else {
27
+ throw new Error(`Unsupported URI format: ${uri}`);
28
+ }
29
+ const metadata = await this.fetchMetadata(resolvedUri);
30
+ this.cacheMetadata(uri, metadata);
31
+ return metadata;
32
+ }
33
+ /**
34
+ * Resolves IPFS URI to HTTP URL using multiple gateways
35
+ * @param ipfsUri - IPFS URI (ipfs://...)
36
+ * @returns Promise resolving to HTTP URL
37
+ */
38
+ async resolveIPFS(ipfsUri) {
39
+ const ipfsHash = ipfsUri.replace('ipfs://', '');
40
+ // Try multiple gateways for redundancy
41
+ for (const gateway of MetadataResolver.IPFS_GATEWAYS) {
42
+ try {
43
+ const url = gateway + ipfsHash;
44
+ const response = await fetch(url, { method: 'HEAD' });
45
+ if (response.ok) {
46
+ return url;
47
+ }
48
+ }
49
+ catch (error) {
50
+ console.warn(`IPFS gateway ${gateway} failed:`, error);
51
+ continue;
52
+ }
53
+ }
54
+ throw new Error(`Failed to resolve IPFS URI: ${ipfsUri}`);
55
+ }
56
+ /**
57
+ * Fetches metadata from HTTP URL
58
+ * @param url - HTTP URL to fetch metadata from
59
+ * @returns Promise resolving to NFT metadata
60
+ */
61
+ async fetchMetadata(url) {
62
+ try {
63
+ const response = await fetch(url, {
64
+ method: 'GET',
65
+ headers: {
66
+ 'Accept': 'application/json',
67
+ 'User-Agent': 'PWC-Wallet-SDK/1.0'
68
+ }
69
+ });
70
+ if (!response.ok) {
71
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
72
+ }
73
+ const rawData = await response.json();
74
+ return this.parseMetadata(rawData);
75
+ }
76
+ catch (error) {
77
+ throw new Error(`Failed to fetch metadata from ${url}: ${error instanceof Error ? error.message : 'Unknown error'}`);
78
+ }
79
+ }
80
+ /**
81
+ * Parses raw metadata into standardized format
82
+ * @param rawData - Raw metadata from contract
83
+ * @returns Parsed NFT metadata
84
+ */
85
+ parseMetadata(rawData) {
86
+ // Handle different metadata formats
87
+ const metadata = {
88
+ name: rawData.name || rawData.title || 'Unknown NFT',
89
+ description: rawData.description || '',
90
+ image: rawData.image || rawData.image_url || '',
91
+ external_url: rawData.external_url || rawData.externalUrl || undefined,
92
+ attributes: []
93
+ };
94
+ // Parse attributes
95
+ if (rawData.attributes && Array.isArray(rawData.attributes)) {
96
+ metadata.attributes = rawData.attributes.map((attr) => ({
97
+ trait_type: attr.trait_type || attr.traitType || '',
98
+ value: attr.value || '',
99
+ display_type: attr.display_type || attr.displayType || undefined
100
+ }));
101
+ }
102
+ // Validate required fields
103
+ if (!metadata.name || !metadata.image) {
104
+ throw new Error('Invalid metadata: missing required fields (name, image)');
105
+ }
106
+ return metadata;
107
+ }
108
+ /**
109
+ * Gets cached metadata if available and not expired
110
+ * @param uri - Metadata URI
111
+ * @returns Cached metadata or null if not found/expired
112
+ */
113
+ getCachedMetadata(uri) {
114
+ const cached = MetadataResolver.metadataCache.get(uri);
115
+ if (!cached) {
116
+ return null;
117
+ }
118
+ const now = Date.now();
119
+ if (now - cached.timestamp > MetadataResolver.CACHE_DURATION) {
120
+ MetadataResolver.metadataCache.delete(uri);
121
+ return null;
122
+ }
123
+ return cached.data;
124
+ }
125
+ /**
126
+ * Caches metadata for future use
127
+ * @param uri - Metadata URI
128
+ * @param metadata - Metadata to cache
129
+ */
130
+ cacheMetadata(uri, metadata) {
131
+ MetadataResolver.metadataCache.set(uri, {
132
+ data: metadata,
133
+ timestamp: Date.now()
134
+ });
135
+ }
136
+ /**
137
+ * Clears the metadata cache
138
+ */
139
+ static clearCache() {
140
+ MetadataResolver.metadataCache.clear();
141
+ }
142
+ /**
143
+ * Gets cache statistics
144
+ * @returns Cache statistics
145
+ */
146
+ static getCacheStats() {
147
+ return {
148
+ size: MetadataResolver.metadataCache.size,
149
+ entries: Array.from(MetadataResolver.metadataCache.values()).length
150
+ };
151
+ }
152
+ }
153
+ exports.MetadataResolver = MetadataResolver;
154
+ MetadataResolver.IPFS_GATEWAYS = [
155
+ 'https://ipfs.io/ipfs/',
156
+ 'https://gateway.pinata.cloud/ipfs/',
157
+ 'https://cloudflare-ipfs.com/ipfs/',
158
+ 'https://dweb.link/ipfs/',
159
+ 'https://gateway.ipfs.io/ipfs/'
160
+ ];
161
+ MetadataResolver.CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
162
+ MetadataResolver.metadataCache = new Map();