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.
- package/README.md +2062 -0
- package/dist/Vault.d.ts +493 -0
- package/dist/Vault.js +1090 -0
- package/dist/chain/ChainService.d.ts +84 -0
- package/dist/chain/ChainService.js +136 -0
- package/dist/chain/SolanaChainService.d.ts +94 -0
- package/dist/chain/SolanaChainService.js +167 -0
- package/dist/config/chains.d.ts +233 -0
- package/dist/config/chains.js +285 -0
- package/dist/config/constants.d.ts +102 -0
- package/dist/config/constants.js +109 -0
- package/dist/config/environment.d.ts +46 -0
- package/dist/config/environment.js +114 -0
- package/dist/config/gas.d.ts +107 -0
- package/dist/config/gas.js +123 -0
- package/dist/crypto/EncryptionService.d.ts +74 -0
- package/dist/crypto/EncryptionService.js +178 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +96 -0
- package/dist/keyrings/HDKeyring.d.ts +72 -0
- package/dist/keyrings/HDKeyring.js +156 -0
- package/dist/keyrings/SimpleKeyring.d.ts +31 -0
- package/dist/keyrings/SimpleKeyring.js +49 -0
- package/dist/keyrings/SolanaKeyring.d.ts +71 -0
- package/dist/keyrings/SolanaKeyring.js +159 -0
- package/dist/services/BatchProcessor.d.ts +42 -0
- package/dist/services/BatchProcessor.js +188 -0
- package/dist/services/MultiTransferService.d.ts +78 -0
- package/dist/services/MultiTransferService.js +252 -0
- package/dist/services/QRCodeService.d.ts +193 -0
- package/dist/services/QRCodeService.js +299 -0
- package/dist/services/TokenUtils.d.ts +307 -0
- package/dist/services/TokenUtils.js +429 -0
- package/dist/services/nft/MetadataResolver.d.ts +57 -0
- package/dist/services/nft/MetadataResolver.js +162 -0
- package/dist/services/nft/NFTAPIService.d.ts +53 -0
- package/dist/services/nft/NFTAPIService.js +122 -0
- package/dist/services/nft/NFTService.d.ts +241 -0
- package/dist/services/nft/NFTService.js +910 -0
- package/dist/types/multiTransfer.d.ts +68 -0
- package/dist/types/multiTransfer.js +2 -0
- package/dist/types/nft/index.d.ts +68 -0
- package/dist/types/nft/index.js +2 -0
- package/dist/types/nft.d.ts +265 -0
- package/dist/types/nft.js +6 -0
- package/package.json +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,2062 @@
|
|
|
1
|
+
# PWC Wallet SDK
|
|
2
|
+
|
|
3
|
+
A comprehensive, secure, and user-friendly wallet SDK for React Native applications. This SDK provides a complete solution for managing cryptocurrency wallets with support for multiple blockchains, HD wallet generation, vanity addresses, NFT support, and advanced features like multi-transfer operations.
|
|
4
|
+
|
|
5
|
+
## 📋 Table of Contents
|
|
6
|
+
|
|
7
|
+
### 🚀 Quick Start
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Basic Wallet Creation](#1-basic-wallet-creation)
|
|
10
|
+
- [Import Existing Wallet from Seed Phrase](#11-import-existing-wallet-from-seed-phrase)
|
|
11
|
+
- [Vanity Wallet Generation](#2-vanity-wallet-generation)
|
|
12
|
+
- [Custom Chain Configuration](#3-custom-chain-configuration)
|
|
13
|
+
|
|
14
|
+
### 📱 React Native Usage
|
|
15
|
+
- [Simple Wallet Component](#simple-wallet-component)
|
|
16
|
+
- [Custom Hook for Wallet Management](#custom-hook-for-wallet-management)
|
|
17
|
+
|
|
18
|
+
### ⚙️ Configuration
|
|
19
|
+
- [Hybrid Configuration (Mobile App & SDK)](#hybrid-configuration-mobile-app--sdk)
|
|
20
|
+
- [Built-in Chains](#built-in-chains)
|
|
21
|
+
- [Custom Chain Management](#custom-chain-management)
|
|
22
|
+
- [Override Built-in Chains](#override-built-in-chains)
|
|
23
|
+
- [Add Custom Chains](#add-custom-chains)
|
|
24
|
+
- [Setup All Chains at Once](#setup-all-chains-at-once)
|
|
25
|
+
- [Chain Configuration Priority](#chain-configuration-priority)
|
|
26
|
+
- [Utility Functions](#utility-functions)
|
|
27
|
+
- [Vanity Wallet Settings](#vanity-wallet-settings)
|
|
28
|
+
- [Supported Chains](#supported-chains)
|
|
29
|
+
|
|
30
|
+
### 💰 Core Wallet Functions
|
|
31
|
+
- [Account Management](#account-management)
|
|
32
|
+
- [Add New HD Account](#add-new-hd-account)
|
|
33
|
+
- [Add New Solana Account](#add-new-solana-account)
|
|
34
|
+
- [Import Account](#import-account)
|
|
35
|
+
- [Get Accounts](#get-accounts)
|
|
36
|
+
- [Balance & Token Functions](#balance--token-functions)
|
|
37
|
+
- [Get Native Balance](#get-native-balance)
|
|
38
|
+
- [Get Token Balance](#get-token-balance)
|
|
39
|
+
- [Get Token Info](#get-token-info)
|
|
40
|
+
- [Transaction Functions](#transaction-functions)
|
|
41
|
+
- [Send Native Token](#send-native-token)
|
|
42
|
+
- [Send Token](#send-token)
|
|
43
|
+
- [Export Mnemonic](#export-mnemonic)
|
|
44
|
+
|
|
45
|
+
### 🔄 Multi-Transfer Operations
|
|
46
|
+
- [Batch Send Native Tokens](#batch-send-native-tokens)
|
|
47
|
+
- [Batch Send ERC-20 Tokens](#batch-send-erc-20-tokens)
|
|
48
|
+
|
|
49
|
+
### 📱 QR Code Functionality
|
|
50
|
+
- [Generate Address QR](#generate-address-qr)
|
|
51
|
+
- [Generate Mnemonic QR](#generate-mnemonic-qr)
|
|
52
|
+
- [Generate Transaction QR](#generate-transaction-qr)
|
|
53
|
+
- [Import Wallet from QR](#import-wallet-from-qr)
|
|
54
|
+
- [Process Transaction from QR](#process-transaction-from-qr)
|
|
55
|
+
- [Validate QR Code](#validate-qr-code)
|
|
56
|
+
- [Generate EIP-681 Compatible Address QR (for Metamask, Binance, Trust Wallet)](#generate-eip-681-compatible-address-qr-for-metamask-binance-trust-wallet)
|
|
57
|
+
|
|
58
|
+
### 🖼️ NFT Functionality
|
|
59
|
+
- [Get NFT Details](#get-nft-details)
|
|
60
|
+
- [Get NFT Balance](#get-nft-balance)
|
|
61
|
+
- [Get Collection Information](#get-collection-information)
|
|
62
|
+
- [NFT Metadata & Attributes](#nft-metadata--attributes)
|
|
63
|
+
- [NFT Transaction History](#nft-transaction-history)
|
|
64
|
+
- [NFT Types and Interfaces](#nft-types-and-interfaces)
|
|
65
|
+
- [React Native NFT Component Example](#react-native-nft-component-example)
|
|
66
|
+
- [Get Owned NFTs](#get-owned-nfts)
|
|
67
|
+
- [Transfer NFT](#transfer-nft)
|
|
68
|
+
- [Estimate NFT Transfer Gas](#estimate-nft-transfer-gas)
|
|
69
|
+
|
|
70
|
+
### ⛽ Advanced Features
|
|
71
|
+
- [Gas Estimation](#gas-estimation)
|
|
72
|
+
- [Estimate Native Transfer Gas](#estimate-native-transfer-gas)
|
|
73
|
+
- [Estimate Token Transfer Gas](#estimate-token-transfer-gas)
|
|
74
|
+
- [Estimate Multi-Transfer Gas](#estimate-multi-transfer-gas)
|
|
75
|
+
- [Estimate NFT Transfer Gas](#estimate-nft-transfer-gas)
|
|
76
|
+
|
|
77
|
+
### 🛠️ Advanced Transaction Utilities
|
|
78
|
+
- [Build Generic Transaction](#build-generic-transaction)
|
|
79
|
+
- [Sign Transaction](#sign-transaction)
|
|
80
|
+
- [Send Raw Transaction](#send-raw-transaction)
|
|
81
|
+
- [Approve Token (Public Utility)](#approve-token-public-utility)
|
|
82
|
+
- [Track Transaction Status](#track-transaction-status)
|
|
83
|
+
|
|
84
|
+
### 🔐 Message Signing
|
|
85
|
+
- [Sign Message (Vault)](#sign-message-recommended---using-vault)
|
|
86
|
+
- [Sign Message (Private Key)](#sign-message-deprecated---using-private-key)
|
|
87
|
+
- [Verify Message](#verify-message)
|
|
88
|
+
- [Sign Typed Data (Vault)](#sign-typed-data-recommended---using-vault)
|
|
89
|
+
- [Sign Typed Data (Private Key)](#sign-typed-data-deprecated---using-private-key)
|
|
90
|
+
- [Verify Typed Data](#verify-typed-data)
|
|
91
|
+
|
|
92
|
+
### 🔢 Nonce Management
|
|
93
|
+
- [Get Nonce](#get-nonce)
|
|
94
|
+
- [Sign Message with Nonce (Vault)](#sign-message-with-nonce-recommended---using-vault)
|
|
95
|
+
- [Sign Message with Nonce (Private Key)](#sign-message-with-nonce-deprecated---using-private-key)
|
|
96
|
+
- [Verify Message with Nonce](#verify-message-with-nonce)
|
|
97
|
+
|
|
98
|
+
### 🔍 Read-Only Utilities (Token & NFT)
|
|
99
|
+
- [Get Token Balance](#get-token-balance)
|
|
100
|
+
- [Get Token Info](#get-token-info)
|
|
101
|
+
- [Get Native Balance](#get-native-balance)
|
|
102
|
+
- [Check Allowance](#check-allowance)
|
|
103
|
+
- [Get NFT Details](#get-nft-details)
|
|
104
|
+
- [Get NFT Balance](#get-nft-balance)
|
|
105
|
+
- [Get Owned NFTs](#get-owned-nfts)
|
|
106
|
+
|
|
107
|
+
### 🔒 Security & Error Handling
|
|
108
|
+
- [Security Considerations](#security-considerations)
|
|
109
|
+
- [Error Handling](#error-handling)
|
|
110
|
+
|
|
111
|
+
### 🛠️ Development
|
|
112
|
+
- [Contributing](#contributing)
|
|
113
|
+
|
|
114
|
+
### 🛠️ Advanced Transaction Utilities
|
|
115
|
+
|
|
116
|
+
### Build Generic Transaction
|
|
117
|
+
Builds an unsigned transaction for any contract method.
|
|
118
|
+
|
|
119
|
+
**Parameters:**
|
|
120
|
+
- `contractAddress` - The contract address to interact with
|
|
121
|
+
- `abi` - The contract ABI array
|
|
122
|
+
- `method` - The method name to call
|
|
123
|
+
- `args` - Arguments to pass to the method (optional)
|
|
124
|
+
- `value` - Native token value to send (optional)
|
|
125
|
+
- `chainId` - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { buildTransaction } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
129
|
+
|
|
130
|
+
const unsignedTx = await buildTransaction({
|
|
131
|
+
contractAddress: '0xA0b86a33E6441b8c4C8C8C8C8C8C8C8C8C8C8C8', // USDT contract
|
|
132
|
+
abi: [
|
|
133
|
+
"function transfer(address to, uint256 amount) returns (bool)",
|
|
134
|
+
"function balanceOf(address account) view returns (uint256)"
|
|
135
|
+
],
|
|
136
|
+
method: 'transfer',
|
|
137
|
+
args: ['0xRecipientAddress...', '1000000000'], // to address, amount (in smallest unit)
|
|
138
|
+
chainId: '1' // Ethereum mainnet
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Sign Transaction (RECOMMENDED - Using Vault)
|
|
143
|
+
Signs an unsigned transaction using Vault for better security.
|
|
144
|
+
|
|
145
|
+
**Parameters:**
|
|
146
|
+
- `unsignedTx` - The unsigned transaction object from buildTransaction
|
|
147
|
+
- `vault` - The vault instance containing the account
|
|
148
|
+
- `fromAddress` - The sender's address
|
|
149
|
+
- `chainId` - The chain ID
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { signTransactionWithVault } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
153
|
+
|
|
154
|
+
const signedTx = await signTransactionWithVault(unsignedTx, vault, '0xYourAddress', '1');
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Sign Transaction (DEPRECATED - Using Private Key)
|
|
158
|
+
⚠️ **DEPRECATED**: Use signTransactionWithVault instead for better security.
|
|
159
|
+
|
|
160
|
+
**Parameters:**
|
|
161
|
+
- `unsignedTx` - The unsigned transaction object from buildTransaction
|
|
162
|
+
- `privateKey` - The private key to sign with (without 0x prefix)
|
|
163
|
+
- `chainId` - The chain ID
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { signTransaction } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
167
|
+
|
|
168
|
+
const privateKey = 'your-private-key-without-0x-prefix';
|
|
169
|
+
const signedTx = await signTransaction(unsignedTx, privateKey, '1');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Send Raw Transaction
|
|
173
|
+
Broadcasts a signed transaction to the network.
|
|
174
|
+
|
|
175
|
+
**Parameters:**
|
|
176
|
+
- `signedTx` - The signed transaction as hex string
|
|
177
|
+
- `chainId` - The chain ID
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { sendTransaction } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
181
|
+
|
|
182
|
+
const txResponse = await sendTransaction(signedTx, '1');
|
|
183
|
+
console.log('Transaction hash:', txResponse.hash);
|
|
184
|
+
console.log('Block number:', txResponse.blockNumber);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Approve Token (RECOMMENDED - Using Vault)
|
|
188
|
+
Approves a spender to spend tokens using Vault for better security.
|
|
189
|
+
|
|
190
|
+
**Parameters:**
|
|
191
|
+
- `vault` - The vault instance containing the owner's account
|
|
192
|
+
- `fromAddress` - The owner's address
|
|
193
|
+
- `tokenAddress` - The ERC-20 token contract address
|
|
194
|
+
- `spender` - The spender's address (e.g., DEX contract address)
|
|
195
|
+
- `amount` - The amount to approve (string or bigint)
|
|
196
|
+
- `chainId` - The chain ID
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { approveTokenWithVault } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
200
|
+
|
|
201
|
+
const receipt = await approveTokenWithVault(
|
|
202
|
+
vault,
|
|
203
|
+
'0xOwner...',
|
|
204
|
+
'0xToken...',
|
|
205
|
+
'0xSpender...',
|
|
206
|
+
'1000',
|
|
207
|
+
'1'
|
|
208
|
+
);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Approve Token (DEPRECATED - Using Private Key)
|
|
212
|
+
⚠️ **DEPRECATED**: Use approveTokenWithVault instead for better security.
|
|
213
|
+
|
|
214
|
+
**Parameters:**
|
|
215
|
+
- `privateKey` - The owner's private key (without 0x prefix)
|
|
216
|
+
- `tokenAddress` - The ERC-20 token contract address
|
|
217
|
+
- `spender` - The spender's address (e.g., DEX contract address)
|
|
218
|
+
- `amount` - The amount to approve (string or bigint)
|
|
219
|
+
- `chainId` - The chain ID
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { approveToken } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
223
|
+
|
|
224
|
+
const receipt = await approveToken('privateKey...', '0xToken...', '0xSpender...', '1000', '1');
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Track Transaction Status
|
|
228
|
+
Tracks the status of a transaction with polling and callback notifications.
|
|
229
|
+
|
|
230
|
+
**Parameters:**
|
|
231
|
+
- `txHash` - The transaction hash to track
|
|
232
|
+
- `chainId` - The chain ID
|
|
233
|
+
- `callback` - Function called with status updates ('pending', 'confirmed', 'failed')
|
|
234
|
+
- `pollInterval` - Polling interval in milliseconds (optional, default: 3000)
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { trackTxStatus } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
238
|
+
|
|
239
|
+
trackTxStatus('0xTransactionHash...', '1', (status, receipt) => {
|
|
240
|
+
switch (status) {
|
|
241
|
+
case 'pending':
|
|
242
|
+
console.log('Transaction is pending...');
|
|
243
|
+
break;
|
|
244
|
+
case 'confirmed':
|
|
245
|
+
console.log('Transaction confirmed!', receipt?.transactionHash);
|
|
246
|
+
break;
|
|
247
|
+
case 'failed':
|
|
248
|
+
console.log('Transaction failed!', receipt?.transactionHash);
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}, 5000); // Poll every 5 seconds
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 🔐 Message Signing
|
|
255
|
+
|
|
256
|
+
### Sign Message (RECOMMENDED - Using Vault)
|
|
257
|
+
Signs a message using Vault for better security. This is equivalent to MetaMask's `personal_sign` method.
|
|
258
|
+
|
|
259
|
+
**Parameters:**
|
|
260
|
+
- `message` - The message to sign (string or hex string)
|
|
261
|
+
- `vault` - The vault instance containing the account
|
|
262
|
+
- `fromAddress` - The signer's address
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { signMessageWithVault } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
266
|
+
|
|
267
|
+
const signature = await signMessageWithVault('Hello World', vault, '0xYourAddress');
|
|
268
|
+
console.log('Signature:', signature);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Sign Message (DEPRECATED - Using Private Key)
|
|
272
|
+
⚠️ **DEPRECATED**: Use `signMessageWithVault` instead for better security.
|
|
273
|
+
|
|
274
|
+
**Parameters:**
|
|
275
|
+
- `message` - The message to sign (string or hex string)
|
|
276
|
+
- `privateKey` - The private key to sign with (without 0x prefix)
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { signMessage } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
280
|
+
|
|
281
|
+
const signature = await signMessage('Hello World', 'your-private-key');
|
|
282
|
+
console.log('Signature:', signature);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Verify Message
|
|
286
|
+
Verifies a message signature and returns the signer's address.
|
|
287
|
+
|
|
288
|
+
**Parameters:**
|
|
289
|
+
- `message` - The original message that was signed
|
|
290
|
+
- `signature` - The signature to verify
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
import { verifyMessage } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
294
|
+
|
|
295
|
+
const signerAddress = await verifyMessage('Hello World', '0xSignature...');
|
|
296
|
+
console.log('Message was signed by:', signerAddress);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Sign Typed Data (RECOMMENDED - Using Vault)
|
|
300
|
+
Signs a typed data message using Vault. This is equivalent to MetaMask's `eth_signTypedData` method.
|
|
301
|
+
|
|
302
|
+
**Parameters:**
|
|
303
|
+
- `typedData` - The typed data object to sign
|
|
304
|
+
- `vault` - The vault instance containing the account
|
|
305
|
+
- `fromAddress` - The signer's address
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
import { signTypedDataWithVault } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
309
|
+
|
|
310
|
+
const typedData = {
|
|
311
|
+
types: {
|
|
312
|
+
Person: [
|
|
313
|
+
{ name: 'name', type: 'string' },
|
|
314
|
+
{ name: 'wallet', type: 'address' }
|
|
315
|
+
]
|
|
316
|
+
},
|
|
317
|
+
primaryType: 'Person',
|
|
318
|
+
domain: { name: 'MyApp', version: '1' },
|
|
319
|
+
message: { name: 'Alice', wallet: '0x123...' }
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const signature = await signTypedDataWithVault(typedData, vault, '0xYourAddress');
|
|
323
|
+
console.log('Typed Data Signature:', signature);
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Sign Typed Data (DEPRECATED - Using Private Key)
|
|
327
|
+
⚠️ **DEPRECATED**: Use `signTypedDataWithVault` instead for better security.
|
|
328
|
+
|
|
329
|
+
**Parameters:**
|
|
330
|
+
- `typedData` - The typed data object to sign
|
|
331
|
+
- `privateKey` - The private key to sign with (without 0x prefix)
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { signTypedData } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
335
|
+
|
|
336
|
+
const typedData = {
|
|
337
|
+
types: { Person: [{ name: 'name', type: 'string' }] },
|
|
338
|
+
primaryType: 'Person',
|
|
339
|
+
domain: { name: 'MyApp' },
|
|
340
|
+
message: { name: 'Alice' }
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const signature = await signTypedData(typedData, 'your-private-key');
|
|
344
|
+
console.log('Typed Data Signature:', signature);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Verify Typed Data
|
|
348
|
+
Verifies a typed data signature and returns the signer's address.
|
|
349
|
+
|
|
350
|
+
**Parameters:**
|
|
351
|
+
- `typedData` - The original typed data that was signed
|
|
352
|
+
- `signature` - The signature to verify
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { verifyTypedData } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
356
|
+
|
|
357
|
+
const signerAddress = await verifyTypedData(typedData, '0xSignature...');
|
|
358
|
+
console.log('Typed data was signed by:', signerAddress);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### 🔢 Nonce Management
|
|
362
|
+
|
|
363
|
+
### Get Nonce
|
|
364
|
+
Gets the transaction count (nonce) for an address. Useful for message signing with nonce and transaction building.
|
|
365
|
+
|
|
366
|
+
**Parameters:**
|
|
367
|
+
- `address` - The address to get nonce for
|
|
368
|
+
- `chainId` - The chain ID (e.g., '1' for Ethereum, '56' for BSC)
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { getNonce } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
372
|
+
|
|
373
|
+
const nonce = await getNonce('0xYourAddress', '1');
|
|
374
|
+
console.log('Current nonce:', nonce);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Sign Message with Nonce (RECOMMENDED - Using Vault)
|
|
378
|
+
Signs a message with nonce using Vault for better security. This prevents replay attacks by including the current nonce in the message.
|
|
379
|
+
|
|
380
|
+
**Parameters:**
|
|
381
|
+
- `message` - The message to sign (string or hex string)
|
|
382
|
+
- `vault` - The vault instance containing the account
|
|
383
|
+
- `fromAddress` - The signer's address
|
|
384
|
+
- `chainId` - The chain ID
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
import { signMessageWithNonce } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
388
|
+
|
|
389
|
+
const result = await signMessageWithNonce('Hello World', vault, '0xYourAddress', '1');
|
|
390
|
+
console.log('Signature:', result.signature);
|
|
391
|
+
console.log('Nonce:', result.nonce);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Sign Message with Nonce (DEPRECATED - Using Private Key)
|
|
395
|
+
⚠️ **DEPRECATED**: Use `signMessageWithNonce` with Vault instead for better security.
|
|
396
|
+
|
|
397
|
+
**Parameters:**
|
|
398
|
+
- `message` - The message to sign (string or hex string)
|
|
399
|
+
- `privateKey` - The private key to sign with (without 0x prefix)
|
|
400
|
+
- `address` - The signer's address (needed to get nonce)
|
|
401
|
+
- `chainId` - The chain ID
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
import { signMessageWithNoncePrivateKey } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
405
|
+
|
|
406
|
+
const result = await signMessageWithNoncePrivateKey('Hello World', 'your-private-key', '0xYourAddress', '1');
|
|
407
|
+
console.log('Signature:', result.signature);
|
|
408
|
+
console.log('Nonce:', result.nonce);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Verify Message with Nonce
|
|
412
|
+
Verifies a message signature with nonce and returns the signer's address.
|
|
413
|
+
|
|
414
|
+
**Parameters:**
|
|
415
|
+
- `message` - The original message that was signed (without nonce)
|
|
416
|
+
- `signature` - The signature to verify
|
|
417
|
+
- `nonce` - The nonce that was used in signing
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
import { verifyMessageWithNonce } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
421
|
+
|
|
422
|
+
const signerAddress = await verifyMessageWithNonce('Hello World', '0xSignature...', 5);
|
|
423
|
+
console.log('Message was signed by:', signerAddress);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### 🔍 Read-Only Utilities (Token & NFT)
|
|
427
|
+
|
|
428
|
+
### Get Token Balance
|
|
429
|
+
Gets the token balance for a specific account.
|
|
430
|
+
|
|
431
|
+
**Parameters:**
|
|
432
|
+
- `tokenAddress` - The ERC-20 token contract address
|
|
433
|
+
- `account` - The account address to check balance for
|
|
434
|
+
- `chainId` - The chain ID
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
import { getTokenBalance } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
438
|
+
|
|
439
|
+
const balance = await getTokenBalance(
|
|
440
|
+
'0xA0b86a33E6441b8c4C8C8C8C8C8C8C8C8C8C8C8', // USDT contract
|
|
441
|
+
'0xYourWalletAddress...',
|
|
442
|
+
'1' // Ethereum mainnet
|
|
443
|
+
);
|
|
444
|
+
console.log('USDT Balance:', ethers.formatUnits(balance, 6)); // USDT has 6 decimals
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Get Token Info
|
|
448
|
+
Gets comprehensive information about an ERC-20 token.
|
|
449
|
+
|
|
450
|
+
**Parameters:**
|
|
451
|
+
- `tokenAddress` - The ERC-20 token contract address
|
|
452
|
+
- `chainId` - The chain ID
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
import { getTokenInfo } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
456
|
+
|
|
457
|
+
const info = await getTokenInfo(
|
|
458
|
+
'0xA0b86a33E6441b8c4C8C8C8C8C8C8C8C8C8C8C8', // USDT contract
|
|
459
|
+
'1' // Ethereum mainnet
|
|
460
|
+
);
|
|
461
|
+
console.log('Token:', info.name, '(', info.symbol, ')');
|
|
462
|
+
console.log('Decimals:', info.decimals);
|
|
463
|
+
console.log('Total Supply:', ethers.formatUnits(info.totalSupply, info.decimals));
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Get Native Balance
|
|
467
|
+
Gets the native token balance (ETH, BNB, MATIC, etc.) for an account.
|
|
468
|
+
|
|
469
|
+
**Parameters:**
|
|
470
|
+
- `account` - The account address to check balance for
|
|
471
|
+
- `chainId` - The chain ID
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
import { getNativeBalance } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
475
|
+
|
|
476
|
+
const balance = await getNativeBalance('0xYourWalletAddress...', '1');
|
|
477
|
+
console.log('ETH Balance:', ethers.formatEther(balance));
|
|
478
|
+
|
|
479
|
+
// For BSC
|
|
480
|
+
const bnbBalance = await getNativeBalance('0xYourWalletAddress...', '56');
|
|
481
|
+
console.log('BNB Balance:', ethers.formatEther(bnbBalance));
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Check Allowance
|
|
485
|
+
Checks the allowance granted by an owner to a spender for a specific token.
|
|
486
|
+
|
|
487
|
+
**Parameters:**
|
|
488
|
+
- `tokenAddress` - The ERC-20 token contract address
|
|
489
|
+
- `owner` - The token owner's address
|
|
490
|
+
- `spender` - The spender's address (e.g., DEX contract address)
|
|
491
|
+
- `chainId` - The chain ID
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
import { checkAllowance } from 'pwc-wallet-sdk/services/TokenUtils';
|
|
495
|
+
|
|
496
|
+
const allowance = await checkAllowance(
|
|
497
|
+
'0xA0b86a33E6441b8c4C8C8C8C8C8C8C8C8C8C8C8', // USDT contract
|
|
498
|
+
'0xYourWalletAddress...', // Owner
|
|
499
|
+
'0xDexContractAddress...', // Spender (DEX)
|
|
500
|
+
'1' // Ethereum mainnet
|
|
501
|
+
);
|
|
502
|
+
console.log('Allowance:', ethers.formatUnits(allowance, 6)); // USDT has 6 decimals
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Get NFT Details
|
|
506
|
+
Gets comprehensive NFT detail by reading directly from blockchain. Supports both ERC-721 and ERC-1155 NFTs.
|
|
507
|
+
|
|
508
|
+
**ERC-1155 Support Features:**
|
|
509
|
+
- ✅ **Auto-detection**: Automatically detects ERC-721 vs ERC-1155 contracts
|
|
510
|
+
- ✅ **Metadata resolution**: Reads metadata from `uri(tokenId)` function
|
|
511
|
+
- ✅ **Transaction history**: Supports TransferSingle and TransferBatch events
|
|
512
|
+
- ✅ **Collection info**: Gets collection name and symbol
|
|
513
|
+
- ✅ **Token validation**: Checks if token exists via `exists(tokenId)`
|
|
514
|
+
- ✅ **Multiple owners**: Handles ERC-1155's multiple ownership model
|
|
515
|
+
|
|
516
|
+
**Parameters:**
|
|
517
|
+
- `contractAddress` - NFT contract address
|
|
518
|
+
- `tokenId` - Token ID (string)
|
|
519
|
+
- `options` - Optional parameters for additional data
|
|
520
|
+
- `includeMetadata` - Whether to fetch metadata (default: false)
|
|
521
|
+
- `includeHistory` - Whether to fetch transaction history (default: false)
|
|
522
|
+
- `includeCollection` - Whether to fetch collection info (default: false)
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
import { NFTService } from 'pwc-wallet-sdk';
|
|
526
|
+
|
|
527
|
+
const nftService = new NFTService('1'); // chainId = '1' for Ethereum (read-only)
|
|
528
|
+
|
|
529
|
+
// For ERC-721 NFTs
|
|
530
|
+
const nftDetail = await nftService.getNFTDetail(
|
|
531
|
+
'0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D', // BAYC contract
|
|
532
|
+
'1234', // Token ID
|
|
533
|
+
{
|
|
534
|
+
includeMetadata: true,
|
|
535
|
+
includeHistory: true,
|
|
536
|
+
includeCollection: true
|
|
537
|
+
}
|
|
538
|
+
);
|
|
539
|
+
console.log('NFT Name:', nftDetail.name);
|
|
540
|
+
console.log('Owner:', nftDetail.owner);
|
|
541
|
+
console.log('Image URL:', nftDetail.image);
|
|
542
|
+
console.log('Attributes:', nftDetail.attributes);
|
|
543
|
+
|
|
544
|
+
// For ERC-1155 NFTs
|
|
545
|
+
const erc1155Detail = await nftService.getNFTDetail(
|
|
546
|
+
'0xERC1155Contract...', // ERC-1155 contract
|
|
547
|
+
'123', // Token ID
|
|
548
|
+
{
|
|
549
|
+
includeMetadata: true,
|
|
550
|
+
includeHistory: true,
|
|
551
|
+
includeCollection: true
|
|
552
|
+
}
|
|
553
|
+
);
|
|
554
|
+
console.log('ERC-1155 Name:', erc1155Detail.name);
|
|
555
|
+
console.log('Owner:', erc1155Detail.owner); // 'Multiple Owners' for ERC-1155
|
|
556
|
+
console.log('Token Type:', erc1155Detail.tokenType); // 'ERC-1155'
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Get NFT Balance
|
|
560
|
+
Gets NFT balance for an address from a specific contract. Supports both ERC-721 and ERC-1155.
|
|
561
|
+
|
|
562
|
+
**Parameters:**
|
|
563
|
+
- `address` - Wallet address to check balance for
|
|
564
|
+
- `contractAddress` - NFT contract address
|
|
565
|
+
- `tokenId` - (Optional) Token ID for ERC-1155 contracts
|
|
566
|
+
|
|
567
|
+
```typescript
|
|
568
|
+
// For ERC-721 NFTs
|
|
569
|
+
const nftBalance = await nftService.getNFTBalance(
|
|
570
|
+
'0xYourWalletAddress...',
|
|
571
|
+
'0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D' // BAYC contract
|
|
572
|
+
);
|
|
573
|
+
console.log('ERC-721 Count:', nftBalance.count);
|
|
574
|
+
|
|
575
|
+
// For ERC-1155 NFTs (with specific token ID)
|
|
576
|
+
const nftBalance = await nftService.getNFTBalance(
|
|
577
|
+
'0xYourWalletAddress...',
|
|
578
|
+
'0xERC1155Contract...',
|
|
579
|
+
'123' // Token ID
|
|
580
|
+
);
|
|
581
|
+
console.log('ERC-1155 Balance:', nftBalance.count);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### Get ERC-1155 Balance
|
|
585
|
+
Gets ERC-1155 token balance for a specific address and token ID.
|
|
586
|
+
|
|
587
|
+
**Parameters:**
|
|
588
|
+
- `address` - Wallet address to check balance for
|
|
589
|
+
- `contractAddress` - ERC-1155 contract address
|
|
590
|
+
- `tokenId` - Token ID to check balance for
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
const balance = await nftService.getERC1155Balance(
|
|
594
|
+
'0xYourWalletAddress...',
|
|
595
|
+
'0xERC1155Contract...',
|
|
596
|
+
'123' // Token ID
|
|
597
|
+
);
|
|
598
|
+
console.log('ERC-1155 Balance:', balance.toString());
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Get Multiple ERC-1155 Balances
|
|
602
|
+
Gets balances for multiple ERC-1155 tokens at once.
|
|
603
|
+
|
|
604
|
+
**Parameters:**
|
|
605
|
+
- `address` - Wallet address to check balances for
|
|
606
|
+
- `contractAddress` - ERC-1155 contract address
|
|
607
|
+
- `tokenIds` - Array of token IDs to check
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
const balances = await nftService.getERC1155Balances(
|
|
611
|
+
'0xYourWalletAddress...',
|
|
612
|
+
'0xERC1155Contract...',
|
|
613
|
+
['123', '456', '789'] // Multiple token IDs
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
balances.forEach(balance => {
|
|
617
|
+
console.log(`Token ${balance.tokenId}: ${balance.amount.toString()}`);
|
|
618
|
+
});
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Get Collection Information
|
|
622
|
+
Gets collection information directly from the NFT contract.
|
|
623
|
+
|
|
624
|
+
**Parameters:**
|
|
625
|
+
- `contractAddress` - NFT contract address
|
|
626
|
+
|
|
627
|
+
```typescript
|
|
628
|
+
const collection = await nftService.getCollectionInfo('0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D');
|
|
629
|
+
console.log('Collection Name:', collection.name);
|
|
630
|
+
console.log('Total Supply:', collection.totalSupply);
|
|
631
|
+
console.log('Token Type:', collection.tokenType);
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### NFT Metadata & Attributes
|
|
635
|
+
NFT metadata is automatically resolved from tokenURI (IPFS or HTTP). Works for both ERC-721 and ERC-1155.
|
|
636
|
+
|
|
637
|
+
**Key Differences:**
|
|
638
|
+
- **ERC-721**: Single owner per token, uses `tokenURI(tokenId)`
|
|
639
|
+
- **ERC-1155**: Multiple owners possible, uses `uri(tokenId)`, owner field shows "Multiple Owners"
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
import { NFTDetail, NFTDetailExtended, NFTCollection, NFTOptions } from 'pwc-wallet-sdk';
|
|
643
|
+
|
|
644
|
+
// Basic NFT information (on-chain data)
|
|
645
|
+
interface NFTDetail {
|
|
646
|
+
contractAddress: string;
|
|
647
|
+
tokenId: string;
|
|
648
|
+
name: string;
|
|
649
|
+
owner: string;
|
|
650
|
+
tokenType: 'ERC-721' | 'ERC-1155' | 'SPL-NFT';
|
|
651
|
+
chainId: string;
|
|
652
|
+
tokenUri?: string;
|
|
653
|
+
createdAt?: number;
|
|
654
|
+
lastTransferAt?: number;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Extended NFT information with metadata
|
|
658
|
+
interface NFTDetailExtended extends NFTDetail {
|
|
659
|
+
description?: string;
|
|
660
|
+
image?: string;
|
|
661
|
+
attributes?: Array<{ trait_type: string; value: string; display_type?: string }>;
|
|
662
|
+
metadata?: NFTMetadata;
|
|
663
|
+
collection?: NFTCollection;
|
|
664
|
+
transactionHistory?: NFTTransaction[];
|
|
665
|
+
metadataSource?: 'ipfs' | 'http';
|
|
666
|
+
lastUpdated: number;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Collection information
|
|
670
|
+
interface NFTCollection {
|
|
671
|
+
contractAddress: string;
|
|
672
|
+
name: string;
|
|
673
|
+
symbol: string;
|
|
674
|
+
tokenType: string;
|
|
675
|
+
chainId: string;
|
|
676
|
+
totalSupply?: number;
|
|
677
|
+
}
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
### NFT Transaction History
|
|
681
|
+
Gets transaction history from blockchain events.
|
|
682
|
+
|
|
683
|
+
**Parameters:**
|
|
684
|
+
- `contractAddress` - NFT contract address
|
|
685
|
+
- `tokenId` - Token ID (string)
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
const history = await nftService.getTransactionHistory(
|
|
689
|
+
'0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D', // NFT contract
|
|
690
|
+
'1234' // Token ID
|
|
691
|
+
);
|
|
692
|
+
console.log('Transaction History:', history);
|
|
693
|
+
// Returns array of: { hash, from, to, blockNumber, timestamp, type }
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### NFT Types and Interfaces
|
|
697
|
+
Complete TypeScript interfaces for NFT functionality.
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
import {
|
|
701
|
+
NFTDetail,
|
|
702
|
+
NFTDetailExtended,
|
|
703
|
+
NFTCollection,
|
|
704
|
+
NFTOptions,
|
|
705
|
+
NFTMetadata,
|
|
706
|
+
NFTTransaction,
|
|
707
|
+
NFTBalance
|
|
708
|
+
} from 'pwc-wallet-sdk';
|
|
709
|
+
|
|
710
|
+
// Basic NFT information (on-chain data)
|
|
711
|
+
interface NFTDetail {
|
|
712
|
+
contractAddress: string;
|
|
713
|
+
tokenId: string;
|
|
714
|
+
name: string;
|
|
715
|
+
owner: string;
|
|
716
|
+
tokenType: 'ERC-721' | 'ERC-1155' | 'SPL-NFT';
|
|
717
|
+
chainId: string;
|
|
718
|
+
tokenUri?: string;
|
|
719
|
+
createdAt?: number;
|
|
720
|
+
lastTransferAt?: number;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Extended NFT information with metadata
|
|
724
|
+
interface NFTDetailExtended extends NFTDetail {
|
|
725
|
+
description?: string;
|
|
726
|
+
image?: string;
|
|
727
|
+
attributes?: Array<{ trait_type: string; value: string; display_type?: string }>;
|
|
728
|
+
metadata?: NFTMetadata;
|
|
729
|
+
collection?: NFTCollection;
|
|
730
|
+
transactionHistory?: NFTTransaction[];
|
|
731
|
+
metadataSource?: 'ipfs' | 'http';
|
|
732
|
+
lastUpdated: number;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// NFT metadata from tokenURI
|
|
736
|
+
interface NFTMetadata {
|
|
737
|
+
name: string;
|
|
738
|
+
description?: string;
|
|
739
|
+
image?: string;
|
|
740
|
+
attributes?: Array<{ trait_type: string; value: string; display_type?: string }>;
|
|
741
|
+
external_url?: string;
|
|
742
|
+
animation_url?: string;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Collection information
|
|
746
|
+
interface NFTCollection {
|
|
747
|
+
contractAddress: string;
|
|
748
|
+
name: string;
|
|
749
|
+
symbol: string;
|
|
750
|
+
tokenType: string;
|
|
751
|
+
chainId: string;
|
|
752
|
+
totalSupply?: number;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// NFT transaction history
|
|
756
|
+
interface NFTTransaction {
|
|
757
|
+
hash: string;
|
|
758
|
+
from: string;
|
|
759
|
+
to: string;
|
|
760
|
+
blockNumber: number;
|
|
761
|
+
timestamp: number;
|
|
762
|
+
type: 'mint' | 'transfer';
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// NFT balance information
|
|
766
|
+
interface NFTBalance {
|
|
767
|
+
contractAddress: string;
|
|
768
|
+
tokenIds: string[];
|
|
769
|
+
count: number;
|
|
770
|
+
tokenType: string;
|
|
771
|
+
chainId: string;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// NFT options for queries
|
|
775
|
+
interface NFTOptions {
|
|
776
|
+
includeMetadata?: boolean;
|
|
777
|
+
includeHistory?: boolean;
|
|
778
|
+
includeCollection?: boolean;
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
### React Native NFT Component Example
|
|
783
|
+
```typescript
|
|
784
|
+
import React, { useState, useEffect } from 'react';
|
|
785
|
+
import { View, Text, Image, ScrollView } from 'react-native';
|
|
786
|
+
import { NFTService, NFTDetailExtended } from 'pwc-wallet-sdk';
|
|
787
|
+
|
|
788
|
+
const NFTDetailView = ({ contractAddress, tokenId, chainId }) => {
|
|
789
|
+
const [nft, setNft] = useState(null);
|
|
790
|
+
const [loading, setLoading] = useState(true);
|
|
791
|
+
const [error, setError] = useState(null);
|
|
792
|
+
|
|
793
|
+
useEffect(() => {
|
|
794
|
+
loadNFTDetail();
|
|
795
|
+
}, [contractAddress, tokenId]);
|
|
796
|
+
|
|
797
|
+
const loadNFTDetail = async () => {
|
|
798
|
+
try {
|
|
799
|
+
setLoading(true);
|
|
800
|
+
setError(null);
|
|
801
|
+
|
|
802
|
+
const nftService = new NFTService(chainId); // Read-only operations
|
|
803
|
+
const nftDetail = await nftService.getNFTDetail(
|
|
804
|
+
contractAddress,
|
|
805
|
+
tokenId,
|
|
806
|
+
{ includeMetadata: true, includeHistory: true }
|
|
807
|
+
);
|
|
808
|
+
setNft(nftDetail);
|
|
809
|
+
} catch (err) {
|
|
810
|
+
setError(err.message);
|
|
811
|
+
console.error('Failed to load NFT:', err);
|
|
812
|
+
} finally {
|
|
813
|
+
setLoading(false);
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
if (loading) {
|
|
818
|
+
return <Text>Loading NFT...</Text>;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
if (error) {
|
|
822
|
+
return <Text>Error: {error}</Text>;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (!nft) {
|
|
826
|
+
return <Text>NFT not found</Text>;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
return (
|
|
830
|
+
<ScrollView style={{ padding: 20 }}>
|
|
831
|
+
{nft.image && (
|
|
832
|
+
<Image
|
|
833
|
+
source={{ uri: nft.image }}
|
|
834
|
+
style={{ width: 300, height: 300, alignSelf: 'center' }}
|
|
835
|
+
resizeMode="cover"
|
|
836
|
+
/>
|
|
837
|
+
)}
|
|
838
|
+
<Text style={{ fontSize: 24, fontWeight: 'bold', marginTop: 10 }}>
|
|
839
|
+
{nft.name}
|
|
840
|
+
</Text>
|
|
841
|
+
{nft.description && (
|
|
842
|
+
<Text style={{ marginTop: 5 }}>{nft.description}</Text>
|
|
843
|
+
)}
|
|
844
|
+
<Text style={{ marginTop: 10 }}>
|
|
845
|
+
Contract: {nft.contractAddress}
|
|
846
|
+
</Text>
|
|
847
|
+
<Text>Token ID: {nft.tokenId}</Text>
|
|
848
|
+
<Text>Owner: {nft.owner}</Text>
|
|
849
|
+
<Text>Type: {nft.tokenType}</Text>
|
|
850
|
+
|
|
851
|
+
{nft.attributes && nft.attributes.length > 0 && (
|
|
852
|
+
<View style={{ marginTop: 15 }}>
|
|
853
|
+
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>Attributes:</Text>
|
|
854
|
+
{nft.attributes.map((attr, index) => (
|
|
855
|
+
<Text key={index}>
|
|
856
|
+
{attr.trait_type}: {attr.value}
|
|
857
|
+
</Text>
|
|
858
|
+
))}
|
|
859
|
+
</View>
|
|
860
|
+
)}
|
|
861
|
+
</ScrollView>
|
|
862
|
+
);
|
|
863
|
+
};
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
### Get Owned NFTs
|
|
867
|
+
Gets all NFTs owned by an address from multiple contracts.
|
|
868
|
+
|
|
869
|
+
**Parameters:**
|
|
870
|
+
- `account` - Wallet address to check
|
|
871
|
+
- `contractAddresses` - Array of NFT contract addresses
|
|
872
|
+
- `options` - Optional parameters (same as getNFTDetail)
|
|
873
|
+
|
|
874
|
+
```typescript
|
|
875
|
+
const nfts = await nftService.getOwnedNFTs(
|
|
876
|
+
'0xYourWalletAddress...',
|
|
877
|
+
['0xContract1...', '0xContract2...'],
|
|
878
|
+
{ includeMetadata: true }
|
|
879
|
+
);
|
|
880
|
+
console.log('Total NFTs:', nfts.length);
|
|
881
|
+
nfts.forEach(nft => {
|
|
882
|
+
console.log(`${nft.name} (${nft.contractAddress})`);
|
|
883
|
+
});
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
### Transfer NFT
|
|
887
|
+
Transfers an NFT (ERC-721) from one address to another.
|
|
888
|
+
|
|
889
|
+
**Parameters:**
|
|
890
|
+
- `fromAddress` - Sender's address
|
|
891
|
+
- `toAddress` - Recipient's address
|
|
892
|
+
- `contractAddress` - NFT contract address (ERC-721)
|
|
893
|
+
- `tokenId` - Token ID to transfer (string)
|
|
894
|
+
|
|
895
|
+
```typescript
|
|
896
|
+
// Gửi NFT ERC-721 từ ví này sang ví khác
|
|
897
|
+
const tx = await vault.transferNFT(
|
|
898
|
+
'0xSenderAddress',
|
|
899
|
+
'0xRecipientAddress',
|
|
900
|
+
'0xNFTContractAddress',
|
|
901
|
+
'1234' // Token ID
|
|
902
|
+
);
|
|
903
|
+
console.log('NFT transfer tx hash:', tx.hash);
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
> **Note:** Hiện tại chỉ hỗ trợ EVM chains (Ethereum, BSC, v.v.). Solana NFT transfer chưa được hỗ trợ.
|
|
907
|
+
|
|
908
|
+
---
|
|
909
|
+
|
|
910
|
+
## NFT Transfer (ERC-721 & ERC-1155)
|
|
911
|
+
|
|
912
|
+
### Initialize NFTService for Transfer Operations
|
|
913
|
+
For transfer operations, you need to initialize `NFTService` with vault and sender address:
|
|
914
|
+
|
|
915
|
+
```typescript
|
|
916
|
+
import { NFTService, Vault } from 'pwc-wallet-sdk';
|
|
917
|
+
|
|
918
|
+
// Initialize for read-only operations
|
|
919
|
+
const nftService = new NFTService('1'); // chainId = '1' for Ethereum
|
|
920
|
+
|
|
921
|
+
// Initialize for write operations (transfer)
|
|
922
|
+
const nftService = new NFTService('1', vault, fromAddress);
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
### Transfer NFT (RECOMMENDED - Using Vault)
|
|
926
|
+
The `transferNFTWithVault` function supports transferring both ERC-721 and ERC-1155 NFTs.
|
|
927
|
+
|
|
928
|
+
**Parameters:**
|
|
929
|
+
- `vault` - The Vault instance containing the sender's account
|
|
930
|
+
- `fromAddress` - The sender's wallet address
|
|
931
|
+
- `toAddress` - The recipient's wallet address
|
|
932
|
+
- `contractAddress` - The NFT contract address
|
|
933
|
+
- `tokenId` - The token ID to transfer
|
|
934
|
+
- `amount` (optional, default "1") - The amount to transfer (required for ERC-1155, default 1 for ERC-721)
|
|
935
|
+
|
|
936
|
+
**Usage:**
|
|
937
|
+
```typescript
|
|
938
|
+
// Initialize NFTService for transfer operations
|
|
939
|
+
const nftService = new NFTService('1', vault, fromAddress);
|
|
940
|
+
|
|
941
|
+
// ERC-721: only basic parameters are required
|
|
942
|
+
await nftService.transferNFTWithVault(
|
|
943
|
+
fromAddress,
|
|
944
|
+
toAddress,
|
|
945
|
+
contractAddress,
|
|
946
|
+
tokenId
|
|
947
|
+
);
|
|
948
|
+
|
|
949
|
+
// ERC-1155: specify the amount (number of NFTs to transfer)
|
|
950
|
+
await nftService.transferNFTWithVault(
|
|
951
|
+
fromAddress,
|
|
952
|
+
toAddress,
|
|
953
|
+
contractAddress,
|
|
954
|
+
tokenId,
|
|
955
|
+
"5" // transfer 5 ERC-1155 NFTs
|
|
956
|
+
);
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
- The function will automatically detect the contract type (ERC-721 or ERC-1155) and call the correct transfer method.
|
|
960
|
+
- If the contract is ERC-721, `amount` will default to 1.
|
|
961
|
+
- If the contract is ERC-1155, `amount` is the number of NFTs to transfer.
|
|
962
|
+
|
|
963
|
+
### Deprecated: transferNFT
|
|
964
|
+
The `transferNFT` function (without vault) also supports both standards, but is **not recommended for production**.
|
|
965
|
+
|
|
966
|
+
### Estimate NFT Transfer Gas
|
|
967
|
+
Estimates the gas cost for transferring NFTs (ERC-721 and ERC-1155).
|
|
968
|
+
|
|
969
|
+
**Parameters:**
|
|
970
|
+
- `fromAddress` - The sender's address
|
|
971
|
+
- `toAddress` - The recipient's address
|
|
972
|
+
- `contractAddress` - The NFT contract address
|
|
973
|
+
- `tokenId` - The token ID to transfer
|
|
974
|
+
- `amount` (optional, default "1") - The amount to transfer (for ERC-1155, default 1 for ERC-721)
|
|
975
|
+
|
|
976
|
+
**Usage:**
|
|
977
|
+
```typescript
|
|
978
|
+
import { NFTService } from 'pwc-wallet-sdk';
|
|
979
|
+
|
|
980
|
+
// Initialize NFTService
|
|
981
|
+
const nftService = new NFTService('1'); // Ethereum mainnet
|
|
982
|
+
|
|
983
|
+
// Estimate gas for ERC-721 transfer
|
|
984
|
+
const erc721Gas = await nftService.estimateGasForTransfer(
|
|
985
|
+
'0xSender...',
|
|
986
|
+
'0xRecipient...',
|
|
987
|
+
'0xContract...',
|
|
988
|
+
'123'
|
|
989
|
+
);
|
|
990
|
+
console.log('ERC-721 transfer gas:', erc721Gas.toString());
|
|
991
|
+
|
|
992
|
+
// Estimate gas for ERC-1155 transfer
|
|
993
|
+
const erc1155Gas = await nftService.estimateGasForTransfer(
|
|
994
|
+
'0xSender...',
|
|
995
|
+
'0xRecipient...',
|
|
996
|
+
'0xContract...',
|
|
997
|
+
'123',
|
|
998
|
+
'5' // transfer 5 ERC-1155 NFTs
|
|
999
|
+
);
|
|
1000
|
+
console.log('ERC-1155 transfer gas:', erc1155Gas.toString());
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
### Estimate Gas for Various NFT Operations
|
|
1004
|
+
Estimates gas cost for different NFT operations including transfer, approve, and setApprovalForAll.
|
|
1005
|
+
|
|
1006
|
+
**Parameters:**
|
|
1007
|
+
- `operation` - The operation type: 'transfer', 'approve', or 'setApprovalForAll'
|
|
1008
|
+
- `contractAddress` - The NFT contract address
|
|
1009
|
+
- `params` - Operation-specific parameters
|
|
1010
|
+
|
|
1011
|
+
**Usage:**
|
|
1012
|
+
```typescript
|
|
1013
|
+
// Estimate gas for ERC-721 approve
|
|
1014
|
+
const approveGas = await nftService.estimateGas('approve', '0xContract...', {
|
|
1015
|
+
toAddress: '0xSpender...',
|
|
1016
|
+
tokenId: '123'
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
// Estimate gas for ERC-721 setApprovalForAll
|
|
1020
|
+
const setApprovalGas = await nftService.estimateGas('setApprovalForAll', '0xContract...', {
|
|
1021
|
+
toAddress: '0xOperator...',
|
|
1022
|
+
approved: true
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
// Estimate gas for ERC-721 transfer
|
|
1026
|
+
const transferGas = await nftService.estimateGas('transfer', '0xContract...', {
|
|
1027
|
+
fromAddress: '0xSender...',
|
|
1028
|
+
toAddress: '0xRecipient...',
|
|
1029
|
+
tokenId: '123'
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
// Estimate gas for ERC-1155 transfer
|
|
1033
|
+
const erc1155TransferGas = await nftService.estimateGas('transfer', '0xContract...', {
|
|
1034
|
+
fromAddress: '0xSender...',
|
|
1035
|
+
toAddress: '0xRecipient...',
|
|
1036
|
+
tokenId: '123',
|
|
1037
|
+
amount: '3'
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
console.log('Approve gas:', approveGas.toString());
|
|
1041
|
+
console.log('Set approval gas:', setApprovalGas.toString());
|
|
1042
|
+
console.log('Transfer gas:', transferGas.toString());
|
|
1043
|
+
console.log('ERC-1155 transfer gas:', erc1155TransferGas.toString());
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
**Supported Operations:**
|
|
1047
|
+
- **ERC-721**: `transfer`, `approve`, `setApprovalForAll`
|
|
1048
|
+
- **ERC-1155**: `transfer` only (approve operations not supported)
|
|
1049
|
+
|
|
1050
|
+
**Features:**
|
|
1051
|
+
- ✅ **Automatic Contract Detection**: Automatically detects ERC-721 vs ERC-1155
|
|
1052
|
+
- ✅ **Token Validation**: Verifies token exists before estimating gas
|
|
1053
|
+
- ✅ **Parameter Validation**: Validates required parameters for each operation
|
|
1054
|
+
- ✅ **Error Handling**: Comprehensive error messages for invalid operations
|
|
1055
|
+
|
|
1056
|
+
---
|
|
1057
|
+
|
|
1058
|
+
## Features
|
|
1059
|
+
|
|
1060
|
+
- 🔐 **Secure HD Wallet Management**: BIP-44 compliant hierarchical deterministic wallets
|
|
1061
|
+
- 🎯 **Vanity Address Generation**: Generate wallets with custom address prefixes
|
|
1062
|
+
- 🔗 **Multi-Chain Support**: Ethereum, BSC, Polygon, Arbitrum, Optimism, Base, and Solana
|
|
1063
|
+
- 🚀 **Multi-Transfer Operations**: Batch send tokens to multiple recipients
|
|
1064
|
+
- 🔧 **Custom Chain Support**: Add custom chains and override built-in configurations
|
|
1065
|
+
- 📱 **React Native Optimized**: Designed specifically for mobile applications
|
|
1066
|
+
- 🔒 **Encryption**: AES-256 encryption for secure vault storage
|
|
1067
|
+
- 🎨 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
1068
|
+
- 🖼️ **NFT Support**: Core NFT functionality for individual tokens and collections
|
|
1069
|
+
- ⛽ **Gas Estimation**: Comprehensive gas estimation for native tokens, ERC-20 tokens, and NFTs
|
|
1070
|
+
|
|
1071
|
+
## Installation
|
|
1072
|
+
|
|
1073
|
+
```bash
|
|
1074
|
+
npm install pwc-wallet-sdk
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
## Quick Start
|
|
1078
|
+
|
|
1079
|
+
### 1. Basic Wallet Creation
|
|
1080
|
+
|
|
1081
|
+
```typescript
|
|
1082
|
+
import { Vault } from 'pwc-wallet-sdk';
|
|
1083
|
+
|
|
1084
|
+
// Create a new wallet
|
|
1085
|
+
const { vault, encryptedVault } = await Vault.createNew('your-secure-password');
|
|
1086
|
+
|
|
1087
|
+
// Get wallet accounts
|
|
1088
|
+
const accounts = vault.getAccounts();
|
|
1089
|
+
console.log('Wallet addresses:', accounts.map(acc => acc.address));
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
### 1.1. Import Existing Wallet from Seed Phrase
|
|
1093
|
+
|
|
1094
|
+
```typescript
|
|
1095
|
+
import { Vault } from 'pwc-wallet-sdk';
|
|
1096
|
+
|
|
1097
|
+
// Import wallet from existing mnemonic phrase
|
|
1098
|
+
const existingMnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
|
|
1099
|
+
|
|
1100
|
+
// For EVM chains (Ethereum, BSC, Polygon, etc.)
|
|
1101
|
+
const { vault, encryptedVault } = await Vault.createFromMnemonic(
|
|
1102
|
+
existingMnemonic,
|
|
1103
|
+
'your-secure-password',
|
|
1104
|
+
'evm'
|
|
1105
|
+
);
|
|
1106
|
+
|
|
1107
|
+
// For Solana
|
|
1108
|
+
const { vault, encryptedVault } = await Vault.createFromMnemonic(
|
|
1109
|
+
existingMnemonic,
|
|
1110
|
+
'your-secure-password',
|
|
1111
|
+
'solana'
|
|
1112
|
+
);
|
|
1113
|
+
|
|
1114
|
+
// Get wallet accounts
|
|
1115
|
+
const accounts = vault.getAccounts();
|
|
1116
|
+
console.log('Imported wallet addresses:', accounts.map(acc => acc.address));
|
|
1117
|
+
|
|
1118
|
+
// Validate mnemonic before importing (optional)
|
|
1119
|
+
import { EncryptionService } from 'pwc-wallet-sdk';
|
|
1120
|
+
|
|
1121
|
+
const isValid = EncryptionService.validateMnemonic(existingMnemonic);
|
|
1122
|
+
if (!isValid) {
|
|
1123
|
+
throw new Error('Invalid mnemonic phrase');
|
|
1124
|
+
}
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
### 2. Vanity Wallet Generation
|
|
1128
|
+
|
|
1129
|
+
```typescript
|
|
1130
|
+
// Generate wallet with custom address prefix
|
|
1131
|
+
const { vault, encryptedVault, attempts, foundAddress } =
|
|
1132
|
+
await Vault.generateVanityHDWallet('your-password', (attempts, currentAddress) => {
|
|
1133
|
+
console.log(`Attempt ${attempts}: ${currentAddress}`);
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
console.log(`Found address with prefix after ${attempts} attempts: ${foundAddress}`);
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
#### Mobile-Optimized Vanity Wallet Generation
|
|
1140
|
+
|
|
1141
|
+
For mobile applications, use the mobile-optimized version for better performance:
|
|
1142
|
+
|
|
1143
|
+
```typescript
|
|
1144
|
+
// Mobile-optimized vanity wallet generation
|
|
1145
|
+
const { vault, encryptedVault, attempts, foundAddress } =
|
|
1146
|
+
await Vault.generateVanityHDWalletMobile('your-password', (attempts, currentAddress) => {
|
|
1147
|
+
console.log(`Mobile attempt ${attempts}: ${currentAddress}`);
|
|
1148
|
+
}, {
|
|
1149
|
+
prefix: 'a', // Single character prefix (much faster)
|
|
1150
|
+
maxAttempts: 50000, // Lower limit for mobile
|
|
1151
|
+
timeout: 30000, // 30 seconds timeout
|
|
1152
|
+
caseSensitive: false
|
|
1153
|
+
});
|
|
1154
|
+
|
|
1155
|
+
console.log(`Mobile vanity wallet generated in ${attempts} attempts: ${foundAddress}`);
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
**Mobile Optimizations:**
|
|
1159
|
+
- ✅ Batch processing (100 attempts per batch)
|
|
1160
|
+
- ✅ Shorter default prefix (1 character vs 3)
|
|
1161
|
+
- ✅ Lower max attempts (50K vs 1M)
|
|
1162
|
+
- ✅ Timeout protection (30 seconds)
|
|
1163
|
+
- ✅ More frequent progress updates
|
|
1164
|
+
- ✅ More frequent non-blocking yields
|
|
1165
|
+
|
|
1166
|
+
### 3. Custom Chain Configuration
|
|
1167
|
+
|
|
1168
|
+
```typescript
|
|
1169
|
+
import { setupChainConfigs, registerCustomChain, overrideChain } from 'pwc-wallet-sdk';
|
|
1170
|
+
|
|
1171
|
+
// Setup custom chains and overrides (call once when app starts)
|
|
1172
|
+
setupChainConfigs({
|
|
1173
|
+
// Override built-in chains
|
|
1174
|
+
overrides: {
|
|
1175
|
+
'1': { rpcUrl: 'https://my-eth-rpc.com' }, // Use custom Ethereum RPC
|
|
1176
|
+
'56': { rpcUrl: 'https://my-bsc-rpc.com' }, // Use custom BSC RPC
|
|
1177
|
+
},
|
|
1178
|
+
// Add custom chains
|
|
1179
|
+
customChains: {
|
|
1180
|
+
'custom-1': {
|
|
1181
|
+
name: 'My Custom Chain',
|
|
1182
|
+
rpcUrl: 'https://my-custom-rpc.com',
|
|
1183
|
+
explorerUrl: 'https://my-explorer.com',
|
|
1184
|
+
nativeCurrency: { name: 'Token', symbol: 'TKN', decimals: 18 },
|
|
1185
|
+
type: 'evm'
|
|
1186
|
+
},
|
|
1187
|
+
'custom-solana': {
|
|
1188
|
+
name: 'My Solana Chain',
|
|
1189
|
+
rpcUrl: 'https://my-solana-rpc.com',
|
|
1190
|
+
explorerUrl: 'https://my-solana-explorer.com',
|
|
1191
|
+
nativeCurrency: { name: 'SOL', symbol: 'SOL', decimals: 9 },
|
|
1192
|
+
type: 'solana'
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
// Load vault
|
|
1198
|
+
const vault = await Vault.load(password, encryptedVault);
|
|
1199
|
+
|
|
1200
|
+
// Use custom chains normally
|
|
1201
|
+
await vault.sendToken(from, to, amount, tokenAddress, 'custom-1');
|
|
1202
|
+
await vault.getNativeBalance(address, 'custom-solana');
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
## React Native Usage
|
|
1206
|
+
|
|
1207
|
+
### Simple Wallet Component
|
|
1208
|
+
|
|
1209
|
+
```typescript
|
|
1210
|
+
import React, { useState, useEffect } from 'react';
|
|
1211
|
+
import { Vault, setupChainConfigs } from 'pwc-wallet-sdk';
|
|
1212
|
+
|
|
1213
|
+
const WalletComponent = () => {
|
|
1214
|
+
const [vault, setVault] = useState(null);
|
|
1215
|
+
const [balance, setBalance] = useState('0');
|
|
1216
|
+
|
|
1217
|
+
useEffect(() => {
|
|
1218
|
+
// Setup custom chains when component mounts
|
|
1219
|
+
setupChainConfigs({
|
|
1220
|
+
overrides: {
|
|
1221
|
+
'1': { rpcUrl: 'https://my-eth-rpc.com' }
|
|
1222
|
+
},
|
|
1223
|
+
customChains: {
|
|
1224
|
+
'custom-1': {
|
|
1225
|
+
name: 'My Chain',
|
|
1226
|
+
rpcUrl: 'https://my-rpc.com',
|
|
1227
|
+
type: 'evm'
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
loadWallet();
|
|
1233
|
+
}, []);
|
|
1234
|
+
|
|
1235
|
+
const loadWallet = async () => {
|
|
1236
|
+
try {
|
|
1237
|
+
const loadedVault = await Vault.load(password, encryptedVault);
|
|
1238
|
+
setVault(loadedVault);
|
|
1239
|
+
|
|
1240
|
+
// Get balance using custom chain
|
|
1241
|
+
const balance = await loadedVault.getNativeBalance(address, 'custom-1');
|
|
1242
|
+
setBalance(ethers.formatEther(balance));
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
console.error('Failed to load wallet:', error);
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
const sendTransaction = async () => {
|
|
1249
|
+
if (!vault) return;
|
|
1250
|
+
|
|
1251
|
+
try {
|
|
1252
|
+
// Send using custom chain
|
|
1253
|
+
const tx = await vault.sendToken(from, to, amount, tokenAddress, 'custom-1');
|
|
1254
|
+
console.log('Transaction sent:', tx.hash);
|
|
1255
|
+
} catch (error) {
|
|
1256
|
+
console.error('Transaction failed:', error);
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
|
|
1260
|
+
return (
|
|
1261
|
+
<View>
|
|
1262
|
+
<Text>Balance: {balance}</Text>
|
|
1263
|
+
<Button title="Send Transaction" onPress={sendTransaction} />
|
|
1264
|
+
</View>
|
|
1265
|
+
);
|
|
1266
|
+
};
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
### Custom Hook for Wallet Management
|
|
1270
|
+
|
|
1271
|
+
```typescript
|
|
1272
|
+
import { useState, useEffect } from 'react';
|
|
1273
|
+
import { Vault, setupChainConfigs } from 'pwc-wallet-sdk';
|
|
1274
|
+
|
|
1275
|
+
export const useWallet = (password: string, encryptedVault: EncryptedData) => {
|
|
1276
|
+
const [vault, setVault] = useState(null);
|
|
1277
|
+
const [loading, setLoading] = useState(true);
|
|
1278
|
+
const [error, setError] = useState(null);
|
|
1279
|
+
|
|
1280
|
+
useEffect(() => {
|
|
1281
|
+
initializeWallet();
|
|
1282
|
+
}, []);
|
|
1283
|
+
|
|
1284
|
+
const initializeWallet = async () => {
|
|
1285
|
+
try {
|
|
1286
|
+
setLoading(true);
|
|
1287
|
+
|
|
1288
|
+
// Setup chains
|
|
1289
|
+
setupChainConfigs({
|
|
1290
|
+
overrides: {
|
|
1291
|
+
'1': { rpcUrl: 'https://my-eth-rpc.com' }
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
const loadedVault = await Vault.load(password, encryptedVault);
|
|
1296
|
+
setVault(loadedVault);
|
|
1297
|
+
} catch (err) {
|
|
1298
|
+
setError(err.message);
|
|
1299
|
+
} finally {
|
|
1300
|
+
setLoading(false);
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
const sendToken = async (from: string, to: string, amount: string, tokenAddress: string, chainId: string) => {
|
|
1305
|
+
if (!vault) throw new Error('Wallet not loaded');
|
|
1306
|
+
return vault.sendToken(from, to, amount, tokenAddress, chainId);
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
const getBalance = async (address: string, chainId: string) => {
|
|
1310
|
+
if (!vault) throw new Error('Wallet not loaded');
|
|
1311
|
+
return vault.getNativeBalance(address, chainId);
|
|
1312
|
+
};
|
|
1313
|
+
|
|
1314
|
+
return {
|
|
1315
|
+
vault,
|
|
1316
|
+
loading,
|
|
1317
|
+
error,
|
|
1318
|
+
sendToken,
|
|
1319
|
+
getBalance
|
|
1320
|
+
};
|
|
1321
|
+
};
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
## Configuration
|
|
1325
|
+
|
|
1326
|
+
### Vanity Wallet Settings
|
|
1327
|
+
|
|
1328
|
+
```typescript
|
|
1329
|
+
import { VANITY_WALLET_CONFIG } from 'pwc-wallet-sdk';
|
|
1330
|
+
|
|
1331
|
+
// Default settings
|
|
1332
|
+
console.log(VANITY_WALLET_CONFIG.DEFAULT_PREFIX); // 'aaa'
|
|
1333
|
+
console.log(VANITY_WALLET_CONFIG.DEFAULT_MAX_ATTEMPTS); // 1000000
|
|
1334
|
+
console.log(VANITY_WALLET_CONFIG.DEFAULT_CASE_SENSITIVE); // false
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
### Supported Chains
|
|
1338
|
+
|
|
1339
|
+
```typescript
|
|
1340
|
+
import { SUPPORTED_CHAINS } from 'pwc-wallet-sdk';
|
|
1341
|
+
|
|
1342
|
+
// View all supported chains
|
|
1343
|
+
Object.entries(SUPPORTED_CHAINS).forEach(([chainId, config]) => {
|
|
1344
|
+
console.log(`${chainId}: ${config.name} (${config.type})`);
|
|
1345
|
+
});
|
|
1346
|
+
```
|
|
1347
|
+
|
|
1348
|
+
## Core Wallet Functions
|
|
1349
|
+
|
|
1350
|
+
### Account Management
|
|
1351
|
+
|
|
1352
|
+
#### Add New HD Account
|
|
1353
|
+
```typescript
|
|
1354
|
+
// Add a new HD account to the vault
|
|
1355
|
+
const newAccount = vault.addHDAccount();
|
|
1356
|
+
console.log('New account address:', newAccount.address);
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
#### Add New Solana Account
|
|
1360
|
+
```typescript
|
|
1361
|
+
// Add a new Solana account
|
|
1362
|
+
const newSolanaAccount = vault.addSolanaAccount();
|
|
1363
|
+
console.log('New Solana account:', newSolanaAccount.address);
|
|
1364
|
+
```
|
|
1365
|
+
|
|
1366
|
+
#### Import Account
|
|
1367
|
+
```typescript
|
|
1368
|
+
// Import an existing account with private key
|
|
1369
|
+
const importedAccount = vault.importAccount('private-key-without-0x-prefix');
|
|
1370
|
+
console.log('Imported account:', importedAccount.address);
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1373
|
+
#### Get Accounts
|
|
1374
|
+
```typescript
|
|
1375
|
+
// Get all accounts in the vault
|
|
1376
|
+
const accounts = vault.getAccounts();
|
|
1377
|
+
console.log('All accounts:', accounts.map(acc => acc.address));
|
|
1378
|
+
```
|
|
1379
|
+
|
|
1380
|
+
### Balance & Token Functions
|
|
1381
|
+
|
|
1382
|
+
#### Get Native Balance
|
|
1383
|
+
```typescript
|
|
1384
|
+
// Get native token balance (ETH, BNB, MATIC, etc.)
|
|
1385
|
+
const balance = await vault.getNativeBalance(address, '1'); // Ethereum
|
|
1386
|
+
console.log('ETH Balance:', ethers.formatEther(balance));
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
#### Get Token Balance
|
|
1390
|
+
```typescript
|
|
1391
|
+
// Get ERC-20 token balance
|
|
1392
|
+
const tokenBalance = await vault.getTokenBalance(address, tokenAddress, '1');
|
|
1393
|
+
console.log('Token Balance:', ethers.formatUnits(tokenBalance, 18));
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
#### Get Token Info
|
|
1397
|
+
```typescript
|
|
1398
|
+
// Get token information
|
|
1399
|
+
const tokenInfo = await vault.getTokenInfo(tokenAddress, '1');
|
|
1400
|
+
console.log('Token:', tokenInfo.name, '(', tokenInfo.symbol, ')');
|
|
1401
|
+
```
|
|
1402
|
+
|
|
1403
|
+
### Transaction Functions
|
|
1404
|
+
|
|
1405
|
+
#### Send Native Token
|
|
1406
|
+
```typescript
|
|
1407
|
+
// Send native tokens (ETH, BNB, etc.)
|
|
1408
|
+
const tx = await vault.sendNativeToken(from, to, amount, '1');
|
|
1409
|
+
console.log('Transaction hash:', tx.hash);
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
#### Send Token
|
|
1413
|
+
```typescript
|
|
1414
|
+
// Send ERC-20 tokens
|
|
1415
|
+
const tx = await vault.sendToken(from, to, amount, tokenAddress, '1');
|
|
1416
|
+
console.log('Transaction hash:', tx.hash);
|
|
1417
|
+
```
|
|
1418
|
+
|
|
1419
|
+
#### Export Mnemonic
|
|
1420
|
+
```typescript
|
|
1421
|
+
// Export the mnemonic phrase (requires password)
|
|
1422
|
+
const mnemonic = await vault.exportMnemonic(password);
|
|
1423
|
+
console.log('Mnemonic:', mnemonic);
|
|
1424
|
+
```
|
|
1425
|
+
|
|
1426
|
+
## Multi-Transfer Operations
|
|
1427
|
+
|
|
1428
|
+
### Batch Send Native Tokens
|
|
1429
|
+
```typescript
|
|
1430
|
+
import { MultiTransferService } from 'pwc-wallet-sdk';
|
|
1431
|
+
|
|
1432
|
+
const multiTransferService = new MultiTransferService(vault, chainService, '1'); // '1' là chainId cho Ethereum mainnet
|
|
1433
|
+
const recipients = [
|
|
1434
|
+
{ address: '0x1111...', amount: '0.01' },
|
|
1435
|
+
{ address: '0x2222...', amount: '0.02' },
|
|
1436
|
+
{ address: '0x3333...', amount: '0.005' }
|
|
1437
|
+
];
|
|
1438
|
+
|
|
1439
|
+
const result = await multiTransferService.transferNativeTokens(
|
|
1440
|
+
fromAddress,
|
|
1441
|
+
recipients,
|
|
1442
|
+
'1', // chainId
|
|
1443
|
+
{ batchSize: 5, onProgress: (progress) => console.log('Progress:', progress) }
|
|
1444
|
+
);
|
|
1445
|
+
|
|
1446
|
+
console.log('Successful:', result.successfulCount);
|
|
1447
|
+
console.log('Failed:', result.failedCount);
|
|
1448
|
+
console.log('Total gas used:', result.totalGasUsed.toString());
|
|
1449
|
+
```
|
|
1450
|
+
|
|
1451
|
+
### Batch Send ERC-20 Tokens
|
|
1452
|
+
```typescript
|
|
1453
|
+
const result = await multiTransferService.transferTokens(
|
|
1454
|
+
fromAddress,
|
|
1455
|
+
tokenAddress, // USDT, USDC, etc.
|
|
1456
|
+
recipients,
|
|
1457
|
+
'1', // chainId
|
|
1458
|
+
{ batchSize: 10 }
|
|
1459
|
+
);
|
|
1460
|
+
|
|
1461
|
+
console.log('Token transfers completed:', result.successfulCount);
|
|
1462
|
+
```
|
|
1463
|
+
|
|
1464
|
+
## Configuration
|
|
1465
|
+
|
|
1466
|
+
### ⚡️ Hybrid Configuration (Mobile App & SDK)
|
|
1467
|
+
|
|
1468
|
+
> **New in vX.X.X:** You can now override all important config (RPC, explorer, gas, network gas, feature flags, etc.) directly from your app code, not just via environment variables. This enables full control for mobile/web apps and advanced use cases.
|
|
1469
|
+
|
|
1470
|
+
#### How Hybrid Config Works
|
|
1471
|
+
- **Priority:**1*Mobile App Config** (passed to SDK at runtime)
|
|
1472
|
+
2ironment Variables** (process.env)
|
|
1473
|
+
3. **SDK Defaults** (hardcoded fallback)
|
|
1474
|
+
|
|
1475
|
+
#### VaultConfig Interface
|
|
1476
|
+
```typescript
|
|
1477
|
+
import { Vault, type VaultConfig } from 'pwc-wallet-sdk';
|
|
1478
|
+
|
|
1479
|
+
const config: VaultConfig = [object Object] rpcUrls:[object Object] 1https://your-eth-rpc.com',
|
|
1480
|
+
56:https://your-bsc-rpc.com, },
|
|
1481
|
+
explorerUrls:[object Object]1https://etherscan.io',
|
|
1482
|
+
56: 'https://bscscan.com',
|
|
1483
|
+
},
|
|
1484
|
+
gasConfig:[object Object] ERC20_TRANSFER:700,
|
|
1485
|
+
NATIVE_TRANSFER: 2200,
|
|
1486
|
+
BATCH_MULTIPLIER: 12
|
|
1487
|
+
DEFAULT_PRIORITY_FEE: 200
|
|
1488
|
+
},
|
|
1489
|
+
networkGasConfig: {
|
|
1490
|
+
1: { maxFeePerGas:400000000 maxPriorityFeePerGas: 150000},
|
|
1491
|
+
56: { maxFeePerGas: 30000000 maxPriorityFeePerGas: 500 },
|
|
1492
|
+
},
|
|
1493
|
+
defaultChainId: '1
|
|
1494
|
+
features: [object Object]
|
|
1495
|
+
enableEIP1559: true,
|
|
1496
|
+
enableBatchProcessing: true,
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
```
|
|
1500
|
+
|
|
1501
|
+
#### Usage Example (Recommended for Mobile Apps)
|
|
1502
|
+
```typescript
|
|
1503
|
+
import { Vault, type VaultConfig } from 'pwc-wallet-sdk;// Define your app config once
|
|
1504
|
+
const appConfig: VaultConfig =[object Object]
|
|
1505
|
+
rpcUrls: { 1https://your-eth-rpc.com' },
|
|
1506
|
+
gasConfig: { ERC20RANSFER: 7000 networkGasConfig: { '1: { maxFeePerGas: 400000n } },
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1509
|
+
// Pass config when creating new vault
|
|
1510
|
+
const [object Object] vault, encryptedVault } = await Vault.createNew(password', 'evm, appConfig);
|
|
1511
|
+
|
|
1512
|
+
// Pass config when loading existing vault
|
|
1513
|
+
const vault = await Vault.load('password, encryptedVault, appConfig);
|
|
1514
|
+
|
|
1515
|
+
// All operations will use the config automatically
|
|
1516
|
+
await vault.sendToken(from, to, amount, tokenAddress, '1');
|
|
1517
|
+
```
|
|
1518
|
+
|
|
1519
|
+
#### Alternative: Global Config (Advanced)
|
|
1520
|
+
You can also set config globally for all vaults:
|
|
1521
|
+
```typescript
|
|
1522
|
+
import { setGlobalRPCConfig, setGlobalGasConfig, setGlobalNetworkGasConfig } from 'pwc-wallet-sdk';
|
|
1523
|
+
|
|
1524
|
+
setGlobalRPCConfig([object Object]1:https://my-eth-rpc.com });setGlobalGasConfig({ ERC20ANSFER: 70;
|
|
1525
|
+
setGlobalNetworkGasConfig({ '1: { maxFeePerGas: 4000 });
|
|
1526
|
+
```
|
|
1527
|
+
|
|
1528
|
+
#### Why Use Hybrid Config?
|
|
1529
|
+
- **Security:** Use your own RPC endpoints, not public ones
|
|
1530
|
+
- **Performance:** Optimize gas and network for your users
|
|
1531
|
+
- **Flexibility:** Switch between testnet/mainnet, or use custom chains
|
|
1532
|
+
- **Mobile/Web Ready:** No need to rely on process.env in mobile/web
|
|
1533
|
+
- **Simple:** Just pass config when creating/loading vault - no need to call global functions repeatedly
|
|
1534
|
+
|
|
1535
|
+
### Built-in Chains
|
|
1536
|
+
The SDK supports multiple blockchain networks out of the box:
|
|
1537
|
+
|
|
1538
|
+
```typescript
|
|
1539
|
+
import { SUPPORTED_CHAINS } from 'pwc-wallet-sdk';
|
|
1540
|
+
|
|
1541
|
+
// View all supported chains
|
|
1542
|
+
Object.entries(SUPPORTED_CHAINS).forEach(([chainId, config]) => {
|
|
1543
|
+
console.log(`${chainId}: ${config.name} (${config.type})`);
|
|
1544
|
+
});
|
|
1545
|
+
```
|
|
1546
|
+
|
|
1547
|
+
### Custom Chain Management
|
|
1548
|
+
|
|
1549
|
+
#### Override Built-in Chains
|
|
1550
|
+
```typescript
|
|
1551
|
+
import { overrideChain } from 'pwc-wallet-sdk';
|
|
1552
|
+
|
|
1553
|
+
// Override Ethereum RPC URL
|
|
1554
|
+
overrideChain('1', {
|
|
1555
|
+
rpcUrl: 'https://my-eth-rpc.com'
|
|
1556
|
+
});
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
#### Add Custom Chains
|
|
1560
|
+
```typescript
|
|
1561
|
+
import { registerCustomChain } from 'pwc-wallet-sdk';
|
|
1562
|
+
|
|
1563
|
+
registerCustomChain('custom-1', {
|
|
1564
|
+
name: 'My Custom Chain',
|
|
1565
|
+
rpcUrl: 'https://my-custom-rpc.com',
|
|
1566
|
+
explorerUrl: 'https://my-explorer.com',
|
|
1567
|
+
nativeCurrency: { name: 'Token', symbol: 'TKN', decimals: 18 },
|
|
1568
|
+
type: 'evm'
|
|
1569
|
+
});
|
|
1570
|
+
```
|
|
1571
|
+
|
|
1572
|
+
#### Setup All Chains at Once
|
|
1573
|
+
```typescript
|
|
1574
|
+
import { setupChainConfigs } from 'pwc-wallet-sdk';
|
|
1575
|
+
|
|
1576
|
+
setupChainConfigs({
|
|
1577
|
+
overrides: {
|
|
1578
|
+
'1': { rpcUrl: 'https://my-eth-rpc.com' },
|
|
1579
|
+
'56': { rpcUrl: 'https://my-bsc-rpc.com' }
|
|
1580
|
+
},
|
|
1581
|
+
customChains: {
|
|
1582
|
+
'custom-1': {
|
|
1583
|
+
name: 'My Chain',
|
|
1584
|
+
rpcUrl: 'https://my-rpc.com',
|
|
1585
|
+
explorerUrl: 'https://my-explorer.com',
|
|
1586
|
+
nativeCurrency: { name: 'Token', symbol: 'TKN', decimals: 18 },
|
|
1587
|
+
type: 'evm'
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
});
|
|
1591
|
+
```
|
|
1592
|
+
|
|
1593
|
+
#### Chain Configuration Priority
|
|
1594
|
+
1. **Custom chains** (highest priority)
|
|
1595
|
+
2. **Overrides** (modify built-in chains)
|
|
1596
|
+
3. **Built-in chains** (default configuration)
|
|
1597
|
+
|
|
1598
|
+
### Utility Functions
|
|
1599
|
+
```typescript
|
|
1600
|
+
import {
|
|
1601
|
+
getChainConfig,
|
|
1602
|
+
getAllAvailableChains,
|
|
1603
|
+
clearCustomChains,
|
|
1604
|
+
clearOverrides
|
|
1605
|
+
} from 'pwc-wallet-sdk';
|
|
1606
|
+
|
|
1607
|
+
// Get chain configuration
|
|
1608
|
+
const config = getChainConfig('1');
|
|
1609
|
+
|
|
1610
|
+
// Get all available chains
|
|
1611
|
+
const allChains = getAllAvailableChains();
|
|
1612
|
+
|
|
1613
|
+
// Clear custom configurations
|
|
1614
|
+
clearCustomChains();
|
|
1615
|
+
clearOverrides();
|
|
1616
|
+
```
|
|
1617
|
+
|
|
1618
|
+
### Vanity Wallet Settings
|
|
1619
|
+
```typescript
|
|
1620
|
+
import { VANITY_WALLET_CONFIG } from 'pwc-wallet-sdk';
|
|
1621
|
+
|
|
1622
|
+
// Default settings
|
|
1623
|
+
console.log(VANITY_WALLET_CONFIG.DEFAULT_PREFIX); // 'aaa'
|
|
1624
|
+
console.log(VANITY_WALLET_CONFIG.DEFAULT_MAX_ATTEMPTS); // 1000000
|
|
1625
|
+
console.log(VANITY_WALLET_CONFIG.DEFAULT_CASE_SENSITIVE); // false
|
|
1626
|
+
```
|
|
1627
|
+
|
|
1628
|
+
### Supported Chains
|
|
1629
|
+
```typescript
|
|
1630
|
+
import { SUPPORTED_CHAINS } from 'pwc-wallet-sdk';
|
|
1631
|
+
|
|
1632
|
+
// View all supported chains
|
|
1633
|
+
Object.entries(SUPPORTED_CHAINS).forEach(([chainId, config]) => {
|
|
1634
|
+
console.log(`${chainId}: ${config.name} (${config.type})`);
|
|
1635
|
+
});
|
|
1636
|
+
```
|
|
1637
|
+
|
|
1638
|
+
## Advanced Features
|
|
1639
|
+
|
|
1640
|
+
### Gas Estimation
|
|
1641
|
+
|
|
1642
|
+
### Estimate Native Transfer Gas
|
|
1643
|
+
```typescript
|
|
1644
|
+
const gasEstimate = await vault.estimateNativeTransferGas(
|
|
1645
|
+
fromAddress,
|
|
1646
|
+
toAddress,
|
|
1647
|
+
amount,
|
|
1648
|
+
'1'
|
|
1649
|
+
);
|
|
1650
|
+
console.log('Estimated gas:', gasEstimate.toString());
|
|
1651
|
+
console.log('Estimated cost (in ETH):', ethers.formatEther(gasEstimate * gasPrice));
|
|
1652
|
+
```
|
|
1653
|
+
|
|
1654
|
+
### Estimate Token Transfer Gas
|
|
1655
|
+
```typescript
|
|
1656
|
+
const gasEstimate = await vault.estimateTokenTransferGas(
|
|
1657
|
+
fromAddress,
|
|
1658
|
+
tokenAddress,
|
|
1659
|
+
toAddress,
|
|
1660
|
+
amount,
|
|
1661
|
+
'1'
|
|
1662
|
+
);
|
|
1663
|
+
console.log('Estimated gas for token transfer:', gasEstimate.toString());
|
|
1664
|
+
```
|
|
1665
|
+
|
|
1666
|
+
### Estimate Multi-Transfer Gas
|
|
1667
|
+
```typescript
|
|
1668
|
+
const recipients = [
|
|
1669
|
+
{ address: '0x1111...', amount: '0.01' },
|
|
1670
|
+
{ address: '0x2222...', amount: '0.02' },
|
|
1671
|
+
{ address: '0x3333...', amount: '0.005' }
|
|
1672
|
+
];
|
|
1673
|
+
|
|
1674
|
+
// Estimate for native token multi-transfer
|
|
1675
|
+
const nativeGasEstimate = await multiTransferService.estimateGasCost(
|
|
1676
|
+
recipients,
|
|
1677
|
+
'1', // chainId
|
|
1678
|
+
true // Native tokens
|
|
1679
|
+
);
|
|
1680
|
+
|
|
1681
|
+
// Estimate for token multi-transfer
|
|
1682
|
+
const tokenGasEstimate = await multiTransferService.estimateGasCost(
|
|
1683
|
+
recipients,
|
|
1684
|
+
'1', // chainId
|
|
1685
|
+
false, // ERC-20 tokens
|
|
1686
|
+
tokenAddress // USDC
|
|
1687
|
+
);
|
|
1688
|
+
|
|
1689
|
+
console.log('Native multi-transfer gas:', nativeGasEstimate.toString());
|
|
1690
|
+
console.log('Token multi-transfer gas:', tokenGasEstimate.toString());
|
|
1691
|
+
```
|
|
1692
|
+
|
|
1693
|
+
### Estimate NFT Transfer Gas
|
|
1694
|
+
```typescript
|
|
1695
|
+
import { NFTService } from 'pwc-wallet-sdk';
|
|
1696
|
+
|
|
1697
|
+
const nftService = new NFTService('1'); // Ethereum mainnet
|
|
1698
|
+
|
|
1699
|
+
// Estimate gas for ERC-721 transfer
|
|
1700
|
+
const erc721Gas = await nftService.estimateGasForTransfer(
|
|
1701
|
+
'0xSender...',
|
|
1702
|
+
'0xRecipient...',
|
|
1703
|
+
'0xContract...',
|
|
1704
|
+
'123'
|
|
1705
|
+
);
|
|
1706
|
+
|
|
1707
|
+
// Estimate gas for ERC-1155 transfer
|
|
1708
|
+
const erc1155Gas = await nftService.estimateGasForTransfer(
|
|
1709
|
+
'0xSender...',
|
|
1710
|
+
'0xRecipient...',
|
|
1711
|
+
'0xContract...',
|
|
1712
|
+
'123',
|
|
1713
|
+
'5' // transfer 5 ERC-1155 NFTs
|
|
1714
|
+
);
|
|
1715
|
+
|
|
1716
|
+
// Estimate gas for ERC-721 approve
|
|
1717
|
+
const approveGas = await nftService.estimateGas('approve', '0xContract...', {
|
|
1718
|
+
toAddress: '0xSpender...',
|
|
1719
|
+
tokenId: '123'
|
|
1720
|
+
});
|
|
1721
|
+
|
|
1722
|
+
console.log('ERC-721 transfer gas:', erc721Gas.toString());
|
|
1723
|
+
console.log('ERC-1155 transfer gas:', erc1155Gas.toString());
|
|
1724
|
+
console.log('ERC-721 approve gas:', approveGas.toString());
|
|
1725
|
+
```
|
|
1726
|
+
|
|
1727
|
+
### ERC-1155 Gas Estimation Notes
|
|
1728
|
+
For ERC-1155 tokens, gas estimation requires the sender's private key to pass the "caller is not owner nor approved" check. The SDK uses the vault to securely access the private key:
|
|
1729
|
+
|
|
1730
|
+
```typescript
|
|
1731
|
+
// With vault (recommended) - accurate gas estimation
|
|
1732
|
+
const nftService = new NFTService('1', vault);
|
|
1733
|
+
const gasEstimate = await nftService.estimateGasForTransfer(
|
|
1734
|
+
'0xSender...',
|
|
1735
|
+
'0xRecipient...',
|
|
1736
|
+
'0xERC1155Contract...',
|
|
1737
|
+
'123',
|
|
1738
|
+
'5' // amount
|
|
1739
|
+
);
|
|
1740
|
+
|
|
1741
|
+
// Without vault - returns conservative estimate
|
|
1742
|
+
const nftService = new NFTService('1');
|
|
1743
|
+
const gasEstimate = await nftService.estimateGasForTransfer(
|
|
1744
|
+
'0xSender...',
|
|
1745
|
+
'0xRecipient...',
|
|
1746
|
+
'0xERC1155Contract...',
|
|
1747
|
+
'123'
|
|
1748
|
+
);
|
|
1749
|
+
// Returns ~65,000 gas (conservative estimate)
|
|
1750
|
+
```
|
|
1751
|
+
|
|
1752
|
+
**Why use vault?** The vault securely manages private keys and provides them only when needed for gas estimation, ensuring your private keys are never exposed in plain text.
|
|
1753
|
+
|
|
1754
|
+
### Check ERC-1155 Transfer Permissions
|
|
1755
|
+
Check if an address can transfer an ERC-1155 token:
|
|
1756
|
+
|
|
1757
|
+
```typescript
|
|
1758
|
+
const canTransfer = await nftService.canTransferERC1155(
|
|
1759
|
+
'0xAddress...',
|
|
1760
|
+
'0xERC1155Contract...',
|
|
1761
|
+
'123' // token ID
|
|
1762
|
+
);
|
|
1763
|
+
|
|
1764
|
+
if (canTransfer) {
|
|
1765
|
+
console.log('Address can transfer this token');
|
|
1766
|
+
} else {
|
|
1767
|
+
console.log('Address cannot transfer this token (not owner or approved)');
|
|
1768
|
+
}
|
|
1769
|
+
```
|
|
1770
|
+
|
|
1771
|
+
## Security Considerations
|
|
1772
|
+
|
|
1773
|
+
- **Password Strength**: Use strong passwords for vault encryption
|
|
1774
|
+
- **Private Key Storage**: Private keys are never stored in plain text
|
|
1775
|
+
- **Memory Safety**: Sensitive data is cleared from memory when possible
|
|
1776
|
+
- **Encryption**: All vault data is encrypted using AES-256
|
|
1777
|
+
- **Validation**: Input validation prevents common attack vectors
|
|
1778
|
+
|
|
1779
|
+
## Error Handling
|
|
1780
|
+
|
|
1781
|
+
```typescript
|
|
1782
|
+
try {
|
|
1783
|
+
const vault = await Vault.load(password, encryptedVault);
|
|
1784
|
+
await vault.sendToken(from, to, amount, tokenAddress, '1');
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
if (error.message.includes('incorrect password')) {
|
|
1787
|
+
// Handle password error
|
|
1788
|
+
} else if (error.message.includes('insufficient balance')) {
|
|
1789
|
+
// Handle balance error
|
|
1790
|
+
} else {
|
|
1791
|
+
// Handle other errors
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
```
|
|
1795
|
+
|
|
1796
|
+
## Contributing
|
|
1797
|
+
|
|
1798
|
+
1. Fork the repository
|
|
1799
|
+
2. Create a feature branch
|
|
1800
|
+
3. Make your changes
|
|
1801
|
+
4. Add tests
|
|
1802
|
+
5. Submit a pull request
|
|
1803
|
+
|
|
1804
|
+
## License
|
|
1805
|
+
|
|
1806
|
+
MIT License - see LICENSE file for details.
|
|
1807
|
+
|
|
1808
|
+
## 🔥 New API: Simple chainId-based usage
|
|
1809
|
+
|
|
1810
|
+
All read-only and write operations now only require `chainId`, `address`, `token`, ...
|
|
1811
|
+
No need to manage or pass provider from your app. The SDK manages providers internally.
|
|
1812
|
+
|
|
1813
|
+
### Example: Get native balance
|
|
1814
|
+
```ts
|
|
1815
|
+
import { getNativeBalance } from 'pwc-wallet-sdk';
|
|
1816
|
+
const balance = await getNativeBalance('0x123...', '1'); // Ethereum mainnet
|
|
1817
|
+
```
|
|
1818
|
+
|
|
1819
|
+
### Example: Get ERC-20 token balance
|
|
1820
|
+
```ts
|
|
1821
|
+
import { getTokenBalance } from 'pwc-wallet-sdk';
|
|
1822
|
+
const balance = await getTokenBalance('0xToken...', '0x123...', '1');
|
|
1823
|
+
```
|
|
1824
|
+
|
|
1825
|
+
### Example: MultiTransfer
|
|
1826
|
+
```ts
|
|
1827
|
+
import { MultiTransferService } from 'pwc-wallet-sdk';
|
|
1828
|
+
const service = new MultiTransferService(vault, chainService, '1'); // truyền chainId rõ ràng
|
|
1829
|
+
await service.transferNativeTokens('0x123...', [{ address: '0xabc...', amount: '0.1' }], '1');
|
|
1830
|
+
```
|
|
1831
|
+
|
|
1832
|
+
### Example: NFTService
|
|
1833
|
+
```ts
|
|
1834
|
+
import { NFTService } from 'pwc-wallet-sdk';
|
|
1835
|
+
|
|
1836
|
+
// Read-only operations
|
|
1837
|
+
const nftService = new NFTService('1'); // chainId = '1' for Ethereum
|
|
1838
|
+
const nftDetail = await nftService.getNFTDetail('0xContract...', '123');
|
|
1839
|
+
|
|
1840
|
+
// Write operations (transfer)
|
|
1841
|
+
const nftService = new NFTService('1', vault, fromAddress);
|
|
1842
|
+
await nftService.transferNFTWithVault(fromAddress, toAddress, contractAddress, tokenId);
|
|
1843
|
+
|
|
1844
|
+
// Estimate gas for NFT operations
|
|
1845
|
+
const transferGas = await nftService.estimateGasForTransfer(
|
|
1846
|
+
fromAddress,
|
|
1847
|
+
toAddress,
|
|
1848
|
+
contractAddress,
|
|
1849
|
+
tokenId
|
|
1850
|
+
);
|
|
1851
|
+
const approveGas = await nftService.estimateGas('approve', contractAddress, {
|
|
1852
|
+
toAddress: '0xSpender...',
|
|
1853
|
+
tokenId: tokenId
|
|
1854
|
+
});
|
|
1855
|
+
console.log('NFT transfer gas:', transferGas.toString());
|
|
1856
|
+
console.log('NFT approve gas:', approveGas.toString());
|
|
1857
|
+
```
|
|
1858
|
+
|
|
1859
|
+
## Advanced: Override RPC URLs
|
|
1860
|
+
You can override RPC URLs for any chain via config if needed.
|
|
1861
|
+
|
|
1862
|
+
### 📱 QR Code Functionality
|
|
1863
|
+
|
|
1864
|
+
#### Generate Address QR
|
|
1865
|
+
Generates QR code data for a wallet address.
|
|
1866
|
+
|
|
1867
|
+
**Parameters:**
|
|
1868
|
+
- `address` - The wallet address to encode
|
|
1869
|
+
- `label` - Optional label for the address
|
|
1870
|
+
|
|
1871
|
+
```typescript
|
|
1872
|
+
import { QRCodeService } from 'pwc-wallet-sdk';
|
|
1873
|
+
|
|
1874
|
+
// Generate QR for any address
|
|
1875
|
+
const qrData = QRCodeService.generateAddressQR('0x1234...', 'My Wallet');
|
|
1876
|
+
|
|
1877
|
+
// Generate QR from Vault account
|
|
1878
|
+
const qrData = QRCodeService.generateAddressQRFromVault(vault, 0, 'My Wallet');
|
|
1879
|
+
```
|
|
1880
|
+
|
|
1881
|
+
#### Generate Mnemonic QR
|
|
1882
|
+
Generates encrypted QR code data for mnemonic backup.
|
|
1883
|
+
|
|
1884
|
+
**Parameters:**
|
|
1885
|
+
- `mnemonic` - The mnemonic phrase to encrypt
|
|
1886
|
+
- `password` - Password for encryption
|
|
1887
|
+
- `chainType` - Type of blockchain (evm, solana, etc.) - defaults to 'evm'
|
|
1888
|
+
- `accountCount` - Number of accounts to import - defaults to 1
|
|
1889
|
+
|
|
1890
|
+
```typescript
|
|
1891
|
+
import { QRCodeService } from 'pwc-wallet-sdk';
|
|
1892
|
+
|
|
1893
|
+
// Generate QR for mnemonic
|
|
1894
|
+
const qrData = await QRCodeService.generateMnemonicQR(
|
|
1895
|
+
'abandon abandon abandon...',
|
|
1896
|
+
'my-password',
|
|
1897
|
+
'evm',
|
|
1898
|
+
3
|
|
1899
|
+
);
|
|
1900
|
+
|
|
1901
|
+
// Generate QR from Vault
|
|
1902
|
+
const qrData = await QRCodeService.generateMnemonicQRFromVault(
|
|
1903
|
+
vault,
|
|
1904
|
+
'my-password',
|
|
1905
|
+
3
|
|
1906
|
+
);
|
|
1907
|
+
```
|
|
1908
|
+
|
|
1909
|
+
#### Generate Transaction QR
|
|
1910
|
+
Generates QR code data for transaction signing.
|
|
1911
|
+
|
|
1912
|
+
**Parameters:**
|
|
1913
|
+
- `transactionData` - Transaction details object with required fields:
|
|
1914
|
+
- `txType` - 'native', 'token', or 'nft'
|
|
1915
|
+
- `chainId` - Chain ID (e.g., '1' for Ethereum mainnet)
|
|
1916
|
+
- `to` - Recipient address
|
|
1917
|
+
- `amount` - Amount to send
|
|
1918
|
+
- `tokenAddress` - Optional: Token contract address (for token transfers)
|
|
1919
|
+
- `tokenId` - Optional: Token ID (for NFT transfers)
|
|
1920
|
+
- `gasLimit` - Optional: Gas limit
|
|
1921
|
+
- `gasPrice` - Optional: Gas price
|
|
1922
|
+
|
|
1923
|
+
```typescript
|
|
1924
|
+
import { QRCodeService } from 'pwc-wallet-sdk';
|
|
1925
|
+
|
|
1926
|
+
// Native token transfer
|
|
1927
|
+
const nativeTxData = {
|
|
1928
|
+
txType: 'native',
|
|
1929
|
+
chainId: '1',
|
|
1930
|
+
to: '0x1234...',
|
|
1931
|
+
amount: '0.1',
|
|
1932
|
+
gasLimit: '21000'
|
|
1933
|
+
};
|
|
1934
|
+
|
|
1935
|
+
// ERC-20 token transfer
|
|
1936
|
+
const tokenTxData = {
|
|
1937
|
+
txType: 'token',
|
|
1938
|
+
chainId: '1',
|
|
1939
|
+
to: '0x1234...',
|
|
1940
|
+
amount: '100',
|
|
1941
|
+
tokenAddress: '0xA0b86a33E6441b8c4C8C8C8C8C8C8C8C8C8C8C8C8',
|
|
1942
|
+
gasLimit: '65000'
|
|
1943
|
+
};
|
|
1944
|
+
|
|
1945
|
+
const qrData = QRCodeService.generateTransactionQR(nativeTxData);
|
|
1946
|
+
```
|
|
1947
|
+
|
|
1948
|
+
#### Parse and Extract QR Data
|
|
1949
|
+
Parse QR code data and extract specific information.
|
|
1950
|
+
|
|
1951
|
+
```typescript
|
|
1952
|
+
import { QRCodeService } from 'pwc-wallet-sdk';
|
|
1953
|
+
|
|
1954
|
+
// Parse any QR code
|
|
1955
|
+
const qrData = QRCodeService.parseQRData(qrString);
|
|
1956
|
+
|
|
1957
|
+
// Extract specific data types
|
|
1958
|
+
const address = QRCodeService.extractAddress(qrString);
|
|
1959
|
+
const walletData = QRCodeService.extractWalletImportData(qrString);
|
|
1960
|
+
const txData = QRCodeService.extractTransactionData(qrString);
|
|
1961
|
+
|
|
1962
|
+
// Validate address types
|
|
1963
|
+
const addressType = QRCodeService.getAddressType('0x1234...'); // 'ethereum'
|
|
1964
|
+
const isValidEth = QRCodeService.isValidEthereumAddress('0x1234...');
|
|
1965
|
+
const isValidSol = QRCodeService.isValidSolanaAddress('ABC123...');
|
|
1966
|
+
```
|
|
1967
|
+
|
|
1968
|
+
#### Import Wallet from QR
|
|
1969
|
+
Imports wallet from QR code data (requires Vault).
|
|
1970
|
+
|
|
1971
|
+
**Parameters:**
|
|
1972
|
+
- `qrString` - QR code string to parse
|
|
1973
|
+
- `password` - Password to decrypt the mnemonic
|
|
1974
|
+
|
|
1975
|
+
```typescript
|
|
1976
|
+
// Import wallet from scanned QR code
|
|
1977
|
+
const accounts = await vault.importFromQR(qrString, 'my-password');
|
|
1978
|
+
console.log('Imported accounts:', accounts);
|
|
1979
|
+
```
|
|
1980
|
+
|
|
1981
|
+
#### Process Transaction from QR
|
|
1982
|
+
Processes transaction from QR code data (requires Vault).
|
|
1983
|
+
|
|
1984
|
+
**Parameters:**
|
|
1985
|
+
- `qrString` - QR code string to parse
|
|
1986
|
+
- `fromAddress` - Sender's address
|
|
1987
|
+
|
|
1988
|
+
```typescript
|
|
1989
|
+
// Process transaction from scanned QR code
|
|
1990
|
+
const result = await vault.processTransactionFromQR(qrString, '0x1234...');
|
|
1991
|
+
console.log('Transaction hash:', result.hash);
|
|
1992
|
+
```
|
|
1993
|
+
|
|
1994
|
+
#### Validate QR Code
|
|
1995
|
+
Validates QR code data without processing it.
|
|
1996
|
+
|
|
1997
|
+
**Parameters:**
|
|
1998
|
+
- `qrString` - QR code string to validate
|
|
1999
|
+
|
|
2000
|
+
**Returns:**
|
|
2001
|
+
- `isValid` - Boolean indicating if QR is valid
|
|
2002
|
+
- `type` - Type of QR code ('address', 'wallet-import', 'transaction', or 'unknown')
|
|
2003
|
+
- `data` - Parsed data if valid, null if invalid
|
|
2004
|
+
|
|
2005
|
+
```typescript
|
|
2006
|
+
import { QRCodeService } from 'pwc-wallet-sdk';
|
|
2007
|
+
|
|
2008
|
+
// Validate QR code before processing
|
|
2009
|
+
const validation = QRCodeService.validateQRCode(qrString);
|
|
2010
|
+
console.log('QR type:', validation.type);
|
|
2011
|
+
console.log('Is valid:', validation.isValid);
|
|
2012
|
+
if (validation.isValid) {
|
|
2013
|
+
console.log('QR data:', validation.data);
|
|
2014
|
+
}
|
|
2015
|
+
```
|
|
2016
|
+
|
|
2017
|
+
### Multi-Transfer (Batch Send) - Simple Usage
|
|
2018
|
+
```typescript
|
|
2019
|
+
import { MultiTransferService } from 'pwc-wallet-sdk';
|
|
2020
|
+
|
|
2021
|
+
// Create the service easily (no need to handle privateKey or chainService)
|
|
2022
|
+
const multiTransferService = await MultiTransferService.fromVault(vault, fromAddress, '1');
|
|
2023
|
+
|
|
2024
|
+
// Batch send native tokens
|
|
2025
|
+
const recipients = [
|
|
2026
|
+
{ address: '0x1111...', amount: '0.01' },
|
|
2027
|
+
{ address: '0x2222...', amount: '0.02' }
|
|
2028
|
+
];
|
|
2029
|
+
const result = await multiTransferService.transferNativeTokens(
|
|
2030
|
+
fromAddress,
|
|
2031
|
+
recipients,
|
|
2032
|
+
'1',
|
|
2033
|
+
{ batchSize: 2, onProgress: (completed, total, txHash) => console.log(completed, total, txHash) }
|
|
2034
|
+
);
|
|
2035
|
+
console.log('Batch result:', result);
|
|
2036
|
+
|
|
2037
|
+
// Batch send ERC-20 tokens
|
|
2038
|
+
const tokenResult = await multiTransferService.transferTokens(
|
|
2039
|
+
fromAddress,
|
|
2040
|
+
'0xTokenContractAddress...',
|
|
2041
|
+
recipients,
|
|
2042
|
+
'1',
|
|
2043
|
+
{ batchSize: 2 }
|
|
2044
|
+
);
|
|
2045
|
+
console.log('Token batch result:', tokenResult);
|
|
2046
|
+
```
|
|
2047
|
+
|
|
2048
|
+
#### Generate EIP-681 Compatible Address QR (for Metamask, Binance, Trust Wallet)
|
|
2049
|
+
Generates a QR code string in EIP-681 format, which is compatible with most popular wallets.
|
|
2050
|
+
|
|
2051
|
+
**Parameters:**
|
|
2052
|
+
- `address` - The wallet address to encode
|
|
2053
|
+
|
|
2054
|
+
```typescript
|
|
2055
|
+
import { QRCodeService } from 'pwc-wallet-sdk';
|
|
2056
|
+
|
|
2057
|
+
// Generate EIP-681 QR string (recommended for wallet compatibility)
|
|
2058
|
+
const qrString = QRCodeService.generateEIP681AddressQR('0x1234abcd...');
|
|
2059
|
+
// Pass this string to your QR code generator (e.g., react-native-qrcode-svg, qrcode.react, etc.)
|
|
2060
|
+
```
|
|
2061
|
+
|
|
2062
|
+
> **Tip:** Use this format if you want users to scan your QR code with Metamask, Binance, Trust Wallet, or other EVM wallets. If you use the default generateAddressQR, it will only work with your own app.
|