@explorins/pers-sdk-react-native 2.3.6 → 2.3.8
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/LICENSE +21 -0
- package/README.md +1266 -1244
- package/dist/__tests__/PersSDKProvider.test.js +33 -0
- package/dist/hooks/useBusiness.d.ts +2 -2
- package/dist/hooks/useBusiness.d.ts.map +1 -1
- package/dist/hooks/useBusiness.js +2 -2
- package/dist/hooks/useIPFSUrl.d.ts +3 -3
- package/dist/hooks/useIPFSUrl.d.ts.map +1 -1
- package/dist/hooks/useIPFSUrl.js +7 -7
- package/dist/hooks/useTransactions.d.ts.map +1 -1
- package/dist/hooks/useTransactions.js +13 -5
- package/dist/hooks/useWeb3.js +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2412 -492
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +4 -0
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +14 -0
- package/dist/providers/react-native-http-client.d.ts +2 -0
- package/dist/providers/react-native-http-client.d.ts.map +1 -1
- package/dist/providers/react-native-http-client.js +5 -2
- package/dist/storage/rn-secure-storage.d.ts.map +1 -1
- package/dist/storage/rn-secure-storage.js +21 -8
- package/package.json +3 -3
- package/src/__tests__/PersSDKProvider.test.tsx +484 -420
- package/src/__tests__/setup.ts +40 -40
- package/src/hooks/index.ts +60 -60
- package/src/hooks/useAnalytics.ts +327 -327
- package/src/hooks/useAuth.ts +265 -265
- package/src/hooks/useBookings.ts +191 -191
- package/src/hooks/useBusiness.ts +251 -251
- package/src/hooks/useCampaigns.ts +500 -500
- package/src/hooks/useDonations.ts +66 -66
- package/src/hooks/useEvents.ts +372 -372
- package/src/hooks/useFiles.ts +155 -155
- package/src/hooks/useIPFSUrl.ts +192 -192
- package/src/hooks/usePurchases.ts +65 -65
- package/src/hooks/useRedemptions.ts +467 -467
- package/src/hooks/useTenants.ts +72 -72
- package/src/hooks/useTokenBalances.ts +385 -385
- package/src/hooks/useTokens.ts +313 -313
- package/src/hooks/useTransactionSigner.ts +611 -611
- package/src/hooks/useTransactions.ts +299 -290
- package/src/hooks/useTriggerSources.ts +301 -301
- package/src/hooks/useUserStatus.ts +61 -61
- package/src/hooks/useUsers.ts +167 -167
- package/src/hooks/useWeb3.ts +355 -355
- package/src/index.ts +777 -774
- package/src/polyfills/index.ts +160 -160
- package/src/polyfills/web3-polyfills.ts +97 -97
- package/src/providers/PersSDKProvider.tsx +393 -374
- package/src/providers/react-native-auth-provider.ts +110 -110
- package/src/providers/react-native-http-client.ts +150 -145
- package/src/providers/rn-dpop-provider.ts +190 -190
- package/src/storage/async-storage-token-storage.ts +185 -185
- package/src/storage/rn-secure-storage.ts +182 -170
- package/src/types/react-native-globals.d.ts +45 -45
- package/src/utils/index.ts +8 -8
- package/src/utils/platform-detection.ts +86 -86
- package/dist/index-CzLxqePZ.js +0 -7717
- package/dist/index-CzLxqePZ.js.map +0 -1
package/src/hooks/useWeb3.ts
CHANGED
|
@@ -1,356 +1,356 @@
|
|
|
1
|
-
import { useCallback, useMemo } from 'react';
|
|
2
|
-
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
|
-
import { Web3Manager } from '@explorins/pers-sdk/web3';
|
|
4
|
-
import type {
|
|
5
|
-
TokenBalance,
|
|
6
|
-
TokenBalanceRequest,
|
|
7
|
-
TokenCollectionRequest,
|
|
8
|
-
TokenCollection,
|
|
9
|
-
TokenMetadata,
|
|
10
|
-
AccountOwnedTokensResult
|
|
11
|
-
} from '@explorins/pers-sdk/web3';
|
|
12
|
-
import type { TokenDTO } from '@explorins/pers-sdk/token';
|
|
13
|
-
|
|
14
|
-
// ChainData type - matches what Web3Manager.getChainDataById returns
|
|
15
|
-
type ChainData = Awaited<ReturnType<Web3Manager['getChainDataById']>>;
|
|
16
|
-
|
|
17
|
-
// Re-export for convenience
|
|
18
|
-
export type { AccountOwnedTokensResult } from '@explorins/pers-sdk/web3';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* React hook for Web3 operations in the PERS SDK
|
|
22
|
-
*
|
|
23
|
-
* Provides comprehensive Web3 functionality including token balance queries,
|
|
24
|
-
* metadata retrieval, collection management, IPFS resolution, and blockchain
|
|
25
|
-
* explorer integration. Supports multi-chain operations.
|
|
26
|
-
*
|
|
27
|
-
* Note: Wallet addresses should be obtained from `user.wallets` via `usePersSDK()`.
|
|
28
|
-
*
|
|
29
|
-
* @returns Web3 hook with methods for blockchain operations
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```typescript
|
|
33
|
-
* function Web3Component() {
|
|
34
|
-
* const { user } = usePersSDK();
|
|
35
|
-
* const { getTokenBalance, getTokenMetadata } = useWeb3();
|
|
36
|
-
*
|
|
37
|
-
* // Get wallet address from user
|
|
38
|
-
* const walletAddress = user?.wallets?.[0]?.address;
|
|
39
|
-
*
|
|
40
|
-
* const loadTokenData = async () => {
|
|
41
|
-
* if (!walletAddress) {
|
|
42
|
-
* console.log('No wallet connected');
|
|
43
|
-
* return;
|
|
44
|
-
* }
|
|
45
|
-
*
|
|
46
|
-
* const balance = await getTokenBalance({
|
|
47
|
-
* walletAddress,
|
|
48
|
-
* contractAddress: '0x123...',
|
|
49
|
-
* chainId: 1
|
|
50
|
-
* });
|
|
51
|
-
*
|
|
52
|
-
* console.log('Token balance:', balance);
|
|
53
|
-
* };
|
|
54
|
-
*
|
|
55
|
-
* return (
|
|
56
|
-
* <View>
|
|
57
|
-
* {walletAddress ? (
|
|
58
|
-
* <View>
|
|
59
|
-
* <Text>Wallet: {walletAddress}</Text>
|
|
60
|
-
* <Button onPress={loadTokenData} title="Load Tokens" />
|
|
61
|
-
* </View>
|
|
62
|
-
* ) : (
|
|
63
|
-
* <Text>No wallet connected</Text>
|
|
64
|
-
* )}
|
|
65
|
-
* </View>
|
|
66
|
-
* );
|
|
67
|
-
* }
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
export const useWeb3 = () => {
|
|
71
|
-
const { sdk, isInitialized, isAuthenticated } = usePersSDK();
|
|
72
|
-
|
|
73
|
-
if (!isAuthenticated && isInitialized) {
|
|
74
|
-
console.warn('SDK not authenticated. Some web3 operations may fail.');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Create Web3Manager instance lazily
|
|
79
|
-
* Web3Manager is now separate from PersSDK since v2.0.11+
|
|
80
|
-
*/
|
|
81
|
-
const web3 = useMemo(() => {
|
|
82
|
-
if (!sdk) return null;
|
|
83
|
-
return new Web3Manager(sdk.api());
|
|
84
|
-
}, [sdk]);
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Retrieves token balance for a specific wallet and contract
|
|
88
|
-
*
|
|
89
|
-
* @param request - Token balance request containing wallet address, contract, and chain info
|
|
90
|
-
* @returns Promise resolving to token balance data
|
|
91
|
-
* @throws Error if SDK is not initialized
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```typescript
|
|
95
|
-
* const { getTokenBalance } = useWeb3();
|
|
96
|
-
* const balance = await getTokenBalance({
|
|
97
|
-
* walletAddress: '0x123...',
|
|
98
|
-
* contractAddress: '0x456...',
|
|
99
|
-
* chainId: 1,
|
|
100
|
-
* tokenId: '1' // For NFTs
|
|
101
|
-
* });
|
|
102
|
-
* console.log('Balance:', balance.balance);
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
|
-
const getTokenBalance = useCallback(async (request: TokenBalanceRequest): Promise<TokenBalance> => {
|
|
106
|
-
if (!isInitialized || !web3) {
|
|
107
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const result = await web3.getTokenBalance(request);
|
|
112
|
-
return result;
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error('Failed to fetch token balance:', error);
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
}, [web3, isInitialized]);
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Retrieves metadata for a specific token (useful for NFTs)
|
|
121
|
-
*
|
|
122
|
-
* @param request - Token balance request containing contract and token info
|
|
123
|
-
* @returns Promise resolving to token metadata or null if not available
|
|
124
|
-
* @throws Error if SDK is not initialized
|
|
125
|
-
*
|
|
126
|
-
* @example
|
|
127
|
-
* ```typescript
|
|
128
|
-
* const { getTokenMetadata } = useWeb3();
|
|
129
|
-
* const metadata = await getTokenMetadata({
|
|
130
|
-
* contractAddress: '0x123...',
|
|
131
|
-
* tokenId: '1',
|
|
132
|
-
* chainId: 1
|
|
133
|
-
* });
|
|
134
|
-
* console.log('NFT name:', metadata?.name);
|
|
135
|
-
* console.log('NFT image:', metadata?.imageUrl); // IPFS URLs auto-resolved to HTTPS
|
|
136
|
-
* ```
|
|
137
|
-
*/
|
|
138
|
-
const getTokenMetadata = useCallback(async (request: TokenBalanceRequest): Promise<TokenMetadata | null> => {
|
|
139
|
-
if (!isInitialized || !web3) {
|
|
140
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
const result = await web3.getTokenMetadata(request);
|
|
145
|
-
return result;
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error('Failed to fetch token metadata:', error);
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
150
|
-
}, [web3, isInitialized]);
|
|
151
|
-
|
|
152
|
-
const getTokenCollection = useCallback(async (request: TokenCollectionRequest): Promise<TokenCollection> => {
|
|
153
|
-
if (!isInitialized || !web3) {
|
|
154
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
const result = await web3.getTokenCollection(request);
|
|
159
|
-
return result;
|
|
160
|
-
} catch (error) {
|
|
161
|
-
console.error('Failed to fetch token collection:', error);
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
}, [web3, isInitialized]);
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Resolve IPFS URL to HTTP gateway URL
|
|
168
|
-
*
|
|
169
|
-
* Converts an ipfs:// URL to an HTTPS URL using the tenant's configured IPFS gateway.
|
|
170
|
-
* Non-IPFS URLs are returned unchanged.
|
|
171
|
-
*
|
|
172
|
-
* Note: Uses sdk.
|
|
173
|
-
*
|
|
174
|
-
* @param url - IPFS URL to resolve (ipfs://...)
|
|
175
|
-
* @returns Promise resolving to HTTP gateway URL
|
|
176
|
-
*
|
|
177
|
-
* @example
|
|
178
|
-
* ```typescript
|
|
179
|
-
* const { resolveIPFSUrl } = useWeb3();
|
|
180
|
-
* const httpsUrl = await resolveIPFSUrl('ipfs://QmHash...');
|
|
181
|
-
* // Returns: 'https://gateway.pinata.cloud/ipfs/QmHash...'
|
|
182
|
-
* ```
|
|
183
|
-
*/
|
|
184
|
-
const resolveIPFSUrl = useCallback(async (url: string): Promise<string> => {
|
|
185
|
-
if (!isInitialized || !sdk) {
|
|
186
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
const result = await sdk.
|
|
191
|
-
return result;
|
|
192
|
-
} catch (error) {
|
|
193
|
-
console.error('Failed to resolve IPFS URL:', error);
|
|
194
|
-
throw error;
|
|
195
|
-
}
|
|
196
|
-
}, [sdk, isInitialized]);
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Fetch and process token metadata from a URI
|
|
200
|
-
*
|
|
201
|
-
* Note: Uses sdk.
|
|
202
|
-
*
|
|
203
|
-
* @param tokenUri - Token URI to fetch metadata from
|
|
204
|
-
* @returns Promise resolving to processed metadata or null
|
|
205
|
-
*/
|
|
206
|
-
const fetchAndProcessMetadata = useCallback(async (tokenUri: string): Promise<TokenMetadata | null> => {
|
|
207
|
-
if (!isInitialized || !sdk) {
|
|
208
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
const result = await sdk.
|
|
213
|
-
return result;
|
|
214
|
-
} catch (error) {
|
|
215
|
-
console.error('Failed to fetch and process metadata:', error);
|
|
216
|
-
throw error;
|
|
217
|
-
}
|
|
218
|
-
}, [sdk, isInitialized]);
|
|
219
|
-
|
|
220
|
-
const getChainDataById = useCallback(async (chainId: number): Promise<ChainData> => {
|
|
221
|
-
if (!isInitialized || !web3) {
|
|
222
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
const result = await web3.getChainDataById(chainId);
|
|
227
|
-
return result;
|
|
228
|
-
} catch (error) {
|
|
229
|
-
console.error('Failed to fetch chain data:', error);
|
|
230
|
-
throw error;
|
|
231
|
-
}
|
|
232
|
-
}, [web3, isInitialized]);
|
|
233
|
-
|
|
234
|
-
const getExplorerUrl = useCallback(async (chainId: number, address: string, type: 'address' | 'tx'): Promise<string> => {
|
|
235
|
-
if (!isInitialized || !web3) {
|
|
236
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
try {
|
|
240
|
-
const result = await web3.getExplorerUrl(chainId, address, type);
|
|
241
|
-
return result;
|
|
242
|
-
} catch (error) {
|
|
243
|
-
console.error('Failed to generate explorer URL:', error);
|
|
244
|
-
throw error;
|
|
245
|
-
}
|
|
246
|
-
}, [web3, isInitialized]);
|
|
247
|
-
|
|
248
|
-
// ==========================================
|
|
249
|
-
// HELPER METHODS (delegating to core SDK)
|
|
250
|
-
// ==========================================
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Extract tokenIds from a TokenDTO's metadata.
|
|
254
|
-
*
|
|
255
|
-
* Extracts `tokenMetadataIncrementalId` from each metadata entry. This is
|
|
256
|
-
* particularly useful for ERC-1155 tokens which require specific tokenIds
|
|
257
|
-
* to query balances, but works with any token that has metadata.
|
|
258
|
-
*
|
|
259
|
-
* **Note:** For most use cases, prefer `getAccountOwnedTokensFromContract()`
|
|
260
|
-
* which handles tokenId extraction automatically.
|
|
261
|
-
*
|
|
262
|
-
* @param token - Token definition containing metadata array
|
|
263
|
-
* @returns Array of tokenId strings, or undefined if no metadata
|
|
264
|
-
*
|
|
265
|
-
* @see {@link getAccountOwnedTokensFromContract} - Recommended helper that handles this automatically
|
|
266
|
-
*/
|
|
267
|
-
const extractTokenIds = useCallback((token: TokenDTO): string[] | undefined => {
|
|
268
|
-
// Pure function - delegates to Web3Manager (no initialization required)
|
|
269
|
-
return web3?.extractTokenIds(token);
|
|
270
|
-
}, [web3]);
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Get owned tokens from a specific token contract for any blockchain address.
|
|
274
|
-
*
|
|
275
|
-
* **Recommended method** for querying token balances. Automatically handles:
|
|
276
|
-
* - Token type detection (ERC-20, ERC-721, ERC-1155)
|
|
277
|
-
* - TokenId extraction from metadata (uses `extractTokenIds()` internally for ERC-1155)
|
|
278
|
-
* - Building the collection request
|
|
279
|
-
* - Filtering to only tokens with balance > 0
|
|
280
|
-
*
|
|
281
|
-
* Works with any valid blockchain address - can query user wallets, external
|
|
282
|
-
* wallets, contract addresses, or any other address holding tokens.
|
|
283
|
-
*
|
|
284
|
-
* @param accountAddress - Any valid blockchain address (wallet, contract, etc.)
|
|
285
|
-
* @param token - Token definition (from getRewardTokens, getStatusTokens, etc.)
|
|
286
|
-
* @param maxTokens - Maximum tokens to retrieve (default: 100, max: 100)
|
|
287
|
-
* @returns Promise resolving to result with owned tokens
|
|
288
|
-
* @throws Error if SDK is not initialized
|
|
289
|
-
*
|
|
290
|
-
* @example Query user's wallet
|
|
291
|
-
* ```typescript
|
|
292
|
-
* const { user } = usePersSDK();
|
|
293
|
-
* const { getAccountOwnedTokensFromContract } = useWeb3();
|
|
294
|
-
* const { getRewardTokens } = useTokens();
|
|
295
|
-
*
|
|
296
|
-
* const userWallet = user?.wallets?.[0]?.address;
|
|
297
|
-
* const rewardTokens = await getRewardTokens();
|
|
298
|
-
* const result = await getAccountOwnedTokensFromContract(userWallet, rewardTokens[0]);
|
|
299
|
-
* console.log(`User owns ${result.totalOwned} tokens`);
|
|
300
|
-
* ```
|
|
301
|
-
*
|
|
302
|
-
* @see {@link extractTokenIds} - Low-level helper used internally for ERC-1155
|
|
303
|
-
* @see {@link buildCollectionRequest} - For manual request building
|
|
304
|
-
*/
|
|
305
|
-
const getAccountOwnedTokensFromContract = useCallback(async (
|
|
306
|
-
accountAddress: string,
|
|
307
|
-
token: TokenDTO,
|
|
308
|
-
maxTokens: number = 100
|
|
309
|
-
): Promise<AccountOwnedTokensResult> => {
|
|
310
|
-
if (!isInitialized || !web3) {
|
|
311
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return web3.getAccountOwnedTokensFromContract(accountAddress, token, maxTokens);
|
|
315
|
-
}, [web3, isInitialized]);
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Build a TokenCollectionRequest from a TokenDTO.
|
|
319
|
-
*
|
|
320
|
-
* Automatically handles ERC-1155 tokenId extraction from metadata.
|
|
321
|
-
* Use this when you need more control over the request than
|
|
322
|
-
* `getAccountOwnedTokensFromContract` provides.
|
|
323
|
-
*
|
|
324
|
-
* @param accountAddress - Any valid blockchain address (wallet, contract, etc.)
|
|
325
|
-
* @param token - Token definition
|
|
326
|
-
* @param maxTokens - Maximum tokens to retrieve (default: 100, max: 100)
|
|
327
|
-
* @returns TokenCollectionRequest ready for getTokenCollection()
|
|
328
|
-
*/
|
|
329
|
-
const buildCollectionRequest = useCallback((
|
|
330
|
-
accountAddress: string,
|
|
331
|
-
token: TokenDTO,
|
|
332
|
-
maxTokens: number = 100
|
|
333
|
-
): TokenCollectionRequest => {
|
|
334
|
-
if (!web3) {
|
|
335
|
-
throw new Error('SDK not initialized. Call initialize() first.');
|
|
336
|
-
}
|
|
337
|
-
return web3.buildCollectionRequest(accountAddress, token, maxTokens);
|
|
338
|
-
}, [web3]);
|
|
339
|
-
|
|
340
|
-
return {
|
|
341
|
-
getTokenBalance,
|
|
342
|
-
getTokenMetadata,
|
|
343
|
-
getTokenCollection,
|
|
344
|
-
resolveIPFSUrl,
|
|
345
|
-
fetchAndProcessMetadata,
|
|
346
|
-
getChainDataById,
|
|
347
|
-
getExplorerUrl,
|
|
348
|
-
// Helper methods
|
|
349
|
-
extractTokenIds,
|
|
350
|
-
getAccountOwnedTokensFromContract,
|
|
351
|
-
buildCollectionRequest,
|
|
352
|
-
isAvailable: isInitialized && !!web3,
|
|
353
|
-
};
|
|
354
|
-
};
|
|
355
|
-
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
|
+
import { Web3Manager } from '@explorins/pers-sdk/web3';
|
|
4
|
+
import type {
|
|
5
|
+
TokenBalance,
|
|
6
|
+
TokenBalanceRequest,
|
|
7
|
+
TokenCollectionRequest,
|
|
8
|
+
TokenCollection,
|
|
9
|
+
TokenMetadata,
|
|
10
|
+
AccountOwnedTokensResult
|
|
11
|
+
} from '@explorins/pers-sdk/web3';
|
|
12
|
+
import type { TokenDTO } from '@explorins/pers-sdk/token';
|
|
13
|
+
|
|
14
|
+
// ChainData type - matches what Web3Manager.getChainDataById returns
|
|
15
|
+
type ChainData = Awaited<ReturnType<Web3Manager['getChainDataById']>>;
|
|
16
|
+
|
|
17
|
+
// Re-export for convenience
|
|
18
|
+
export type { AccountOwnedTokensResult } from '@explorins/pers-sdk/web3';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* React hook for Web3 operations in the PERS SDK
|
|
22
|
+
*
|
|
23
|
+
* Provides comprehensive Web3 functionality including token balance queries,
|
|
24
|
+
* metadata retrieval, collection management, IPFS resolution, and blockchain
|
|
25
|
+
* explorer integration. Supports multi-chain operations.
|
|
26
|
+
*
|
|
27
|
+
* Note: Wallet addresses should be obtained from `user.wallets` via `usePersSDK()`.
|
|
28
|
+
*
|
|
29
|
+
* @returns Web3 hook with methods for blockchain operations
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* function Web3Component() {
|
|
34
|
+
* const { user } = usePersSDK();
|
|
35
|
+
* const { getTokenBalance, getTokenMetadata } = useWeb3();
|
|
36
|
+
*
|
|
37
|
+
* // Get wallet address from user
|
|
38
|
+
* const walletAddress = user?.wallets?.[0]?.address;
|
|
39
|
+
*
|
|
40
|
+
* const loadTokenData = async () => {
|
|
41
|
+
* if (!walletAddress) {
|
|
42
|
+
* console.log('No wallet connected');
|
|
43
|
+
* return;
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* const balance = await getTokenBalance({
|
|
47
|
+
* walletAddress,
|
|
48
|
+
* contractAddress: '0x123...',
|
|
49
|
+
* chainId: 1
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* console.log('Token balance:', balance);
|
|
53
|
+
* };
|
|
54
|
+
*
|
|
55
|
+
* return (
|
|
56
|
+
* <View>
|
|
57
|
+
* {walletAddress ? (
|
|
58
|
+
* <View>
|
|
59
|
+
* <Text>Wallet: {walletAddress}</Text>
|
|
60
|
+
* <Button onPress={loadTokenData} title="Load Tokens" />
|
|
61
|
+
* </View>
|
|
62
|
+
* ) : (
|
|
63
|
+
* <Text>No wallet connected</Text>
|
|
64
|
+
* )}
|
|
65
|
+
* </View>
|
|
66
|
+
* );
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export const useWeb3 = () => {
|
|
71
|
+
const { sdk, isInitialized, isAuthenticated } = usePersSDK();
|
|
72
|
+
|
|
73
|
+
if (!isAuthenticated && isInitialized) {
|
|
74
|
+
console.warn('SDK not authenticated. Some web3 operations may fail.');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create Web3Manager instance lazily
|
|
79
|
+
* Web3Manager is now separate from PersSDK since v2.0.11+
|
|
80
|
+
*/
|
|
81
|
+
const web3 = useMemo(() => {
|
|
82
|
+
if (!sdk) return null;
|
|
83
|
+
return new Web3Manager(sdk.api());
|
|
84
|
+
}, [sdk]);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Retrieves token balance for a specific wallet and contract
|
|
88
|
+
*
|
|
89
|
+
* @param request - Token balance request containing wallet address, contract, and chain info
|
|
90
|
+
* @returns Promise resolving to token balance data
|
|
91
|
+
* @throws Error if SDK is not initialized
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const { getTokenBalance } = useWeb3();
|
|
96
|
+
* const balance = await getTokenBalance({
|
|
97
|
+
* walletAddress: '0x123...',
|
|
98
|
+
* contractAddress: '0x456...',
|
|
99
|
+
* chainId: 1,
|
|
100
|
+
* tokenId: '1' // For NFTs
|
|
101
|
+
* });
|
|
102
|
+
* console.log('Balance:', balance.balance);
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
const getTokenBalance = useCallback(async (request: TokenBalanceRequest): Promise<TokenBalance> => {
|
|
106
|
+
if (!isInitialized || !web3) {
|
|
107
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const result = await web3.getTokenBalance(request);
|
|
112
|
+
return result;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('Failed to fetch token balance:', error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}, [web3, isInitialized]);
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Retrieves metadata for a specific token (useful for NFTs)
|
|
121
|
+
*
|
|
122
|
+
* @param request - Token balance request containing contract and token info
|
|
123
|
+
* @returns Promise resolving to token metadata or null if not available
|
|
124
|
+
* @throws Error if SDK is not initialized
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const { getTokenMetadata } = useWeb3();
|
|
129
|
+
* const metadata = await getTokenMetadata({
|
|
130
|
+
* contractAddress: '0x123...',
|
|
131
|
+
* tokenId: '1',
|
|
132
|
+
* chainId: 1
|
|
133
|
+
* });
|
|
134
|
+
* console.log('NFT name:', metadata?.name);
|
|
135
|
+
* console.log('NFT image:', metadata?.imageUrl); // IPFS URLs auto-resolved to HTTPS
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
const getTokenMetadata = useCallback(async (request: TokenBalanceRequest): Promise<TokenMetadata | null> => {
|
|
139
|
+
if (!isInitialized || !web3) {
|
|
140
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const result = await web3.getTokenMetadata(request);
|
|
145
|
+
return result;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error('Failed to fetch token metadata:', error);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}, [web3, isInitialized]);
|
|
151
|
+
|
|
152
|
+
const getTokenCollection = useCallback(async (request: TokenCollectionRequest): Promise<TokenCollection> => {
|
|
153
|
+
if (!isInitialized || !web3) {
|
|
154
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const result = await web3.getTokenCollection(request);
|
|
159
|
+
return result;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('Failed to fetch token collection:', error);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}, [web3, isInitialized]);
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Resolve IPFS URL to HTTP gateway URL
|
|
168
|
+
*
|
|
169
|
+
* Converts an ipfs:// URL to an HTTPS URL using the tenant's configured IPFS gateway.
|
|
170
|
+
* Non-IPFS URLs are returned unchanged.
|
|
171
|
+
*
|
|
172
|
+
* Note: Uses sdk.ipfs for IPFS resolution (chain-agnostic).
|
|
173
|
+
*
|
|
174
|
+
* @param url - IPFS URL to resolve (ipfs://...)
|
|
175
|
+
* @returns Promise resolving to HTTP gateway URL
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const { resolveIPFSUrl } = useWeb3();
|
|
180
|
+
* const httpsUrl = await resolveIPFSUrl('ipfs://QmHash...');
|
|
181
|
+
* // Returns: 'https://gateway.pinata.cloud/ipfs/QmHash...'
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
const resolveIPFSUrl = useCallback(async (url: string): Promise<string> => {
|
|
185
|
+
if (!isInitialized || !sdk) {
|
|
186
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
const result = await sdk.ipfs.resolveUrl(url);
|
|
191
|
+
return result;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('Failed to resolve IPFS URL:', error);
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}, [sdk, isInitialized]);
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Fetch and process token metadata from a URI
|
|
200
|
+
*
|
|
201
|
+
* Note: Uses sdk.ipfs for metadata fetching (chain-agnostic IPFS).
|
|
202
|
+
*
|
|
203
|
+
* @param tokenUri - Token URI to fetch metadata from
|
|
204
|
+
* @returns Promise resolving to processed metadata or null
|
|
205
|
+
*/
|
|
206
|
+
const fetchAndProcessMetadata = useCallback(async (tokenUri: string): Promise<TokenMetadata | null> => {
|
|
207
|
+
if (!isInitialized || !sdk) {
|
|
208
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const result = await sdk.ipfs.fetchMetadata(tokenUri);
|
|
213
|
+
return result;
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.error('Failed to fetch and process metadata:', error);
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}, [sdk, isInitialized]);
|
|
219
|
+
|
|
220
|
+
const getChainDataById = useCallback(async (chainId: number): Promise<ChainData> => {
|
|
221
|
+
if (!isInitialized || !web3) {
|
|
222
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const result = await web3.getChainDataById(chainId);
|
|
227
|
+
return result;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error('Failed to fetch chain data:', error);
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}, [web3, isInitialized]);
|
|
233
|
+
|
|
234
|
+
const getExplorerUrl = useCallback(async (chainId: number, address: string, type: 'address' | 'tx'): Promise<string> => {
|
|
235
|
+
if (!isInitialized || !web3) {
|
|
236
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
const result = await web3.getExplorerUrl(chainId, address, type);
|
|
241
|
+
return result;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error('Failed to generate explorer URL:', error);
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}, [web3, isInitialized]);
|
|
247
|
+
|
|
248
|
+
// ==========================================
|
|
249
|
+
// HELPER METHODS (delegating to core SDK)
|
|
250
|
+
// ==========================================
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Extract tokenIds from a TokenDTO's metadata.
|
|
254
|
+
*
|
|
255
|
+
* Extracts `tokenMetadataIncrementalId` from each metadata entry. This is
|
|
256
|
+
* particularly useful for ERC-1155 tokens which require specific tokenIds
|
|
257
|
+
* to query balances, but works with any token that has metadata.
|
|
258
|
+
*
|
|
259
|
+
* **Note:** For most use cases, prefer `getAccountOwnedTokensFromContract()`
|
|
260
|
+
* which handles tokenId extraction automatically.
|
|
261
|
+
*
|
|
262
|
+
* @param token - Token definition containing metadata array
|
|
263
|
+
* @returns Array of tokenId strings, or undefined if no metadata
|
|
264
|
+
*
|
|
265
|
+
* @see {@link getAccountOwnedTokensFromContract} - Recommended helper that handles this automatically
|
|
266
|
+
*/
|
|
267
|
+
const extractTokenIds = useCallback((token: TokenDTO): string[] | undefined => {
|
|
268
|
+
// Pure function - delegates to Web3Manager (no initialization required)
|
|
269
|
+
return web3?.extractTokenIds(token);
|
|
270
|
+
}, [web3]);
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get owned tokens from a specific token contract for any blockchain address.
|
|
274
|
+
*
|
|
275
|
+
* **Recommended method** for querying token balances. Automatically handles:
|
|
276
|
+
* - Token type detection (ERC-20, ERC-721, ERC-1155)
|
|
277
|
+
* - TokenId extraction from metadata (uses `extractTokenIds()` internally for ERC-1155)
|
|
278
|
+
* - Building the collection request
|
|
279
|
+
* - Filtering to only tokens with balance > 0
|
|
280
|
+
*
|
|
281
|
+
* Works with any valid blockchain address - can query user wallets, external
|
|
282
|
+
* wallets, contract addresses, or any other address holding tokens.
|
|
283
|
+
*
|
|
284
|
+
* @param accountAddress - Any valid blockchain address (wallet, contract, etc.)
|
|
285
|
+
* @param token - Token definition (from getRewardTokens, getStatusTokens, etc.)
|
|
286
|
+
* @param maxTokens - Maximum tokens to retrieve (default: 100, max: 100)
|
|
287
|
+
* @returns Promise resolving to result with owned tokens
|
|
288
|
+
* @throws Error if SDK is not initialized
|
|
289
|
+
*
|
|
290
|
+
* @example Query user's wallet
|
|
291
|
+
* ```typescript
|
|
292
|
+
* const { user } = usePersSDK();
|
|
293
|
+
* const { getAccountOwnedTokensFromContract } = useWeb3();
|
|
294
|
+
* const { getRewardTokens } = useTokens();
|
|
295
|
+
*
|
|
296
|
+
* const userWallet = user?.wallets?.[0]?.address;
|
|
297
|
+
* const rewardTokens = await getRewardTokens();
|
|
298
|
+
* const result = await getAccountOwnedTokensFromContract(userWallet, rewardTokens[0]);
|
|
299
|
+
* console.log(`User owns ${result.totalOwned} tokens`);
|
|
300
|
+
* ```
|
|
301
|
+
*
|
|
302
|
+
* @see {@link extractTokenIds} - Low-level helper used internally for ERC-1155
|
|
303
|
+
* @see {@link buildCollectionRequest} - For manual request building
|
|
304
|
+
*/
|
|
305
|
+
const getAccountOwnedTokensFromContract = useCallback(async (
|
|
306
|
+
accountAddress: string,
|
|
307
|
+
token: TokenDTO,
|
|
308
|
+
maxTokens: number = 100
|
|
309
|
+
): Promise<AccountOwnedTokensResult> => {
|
|
310
|
+
if (!isInitialized || !web3) {
|
|
311
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return web3.getAccountOwnedTokensFromContract(accountAddress, token, maxTokens);
|
|
315
|
+
}, [web3, isInitialized]);
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Build a TokenCollectionRequest from a TokenDTO.
|
|
319
|
+
*
|
|
320
|
+
* Automatically handles ERC-1155 tokenId extraction from metadata.
|
|
321
|
+
* Use this when you need more control over the request than
|
|
322
|
+
* `getAccountOwnedTokensFromContract` provides.
|
|
323
|
+
*
|
|
324
|
+
* @param accountAddress - Any valid blockchain address (wallet, contract, etc.)
|
|
325
|
+
* @param token - Token definition
|
|
326
|
+
* @param maxTokens - Maximum tokens to retrieve (default: 100, max: 100)
|
|
327
|
+
* @returns TokenCollectionRequest ready for getTokenCollection()
|
|
328
|
+
*/
|
|
329
|
+
const buildCollectionRequest = useCallback((
|
|
330
|
+
accountAddress: string,
|
|
331
|
+
token: TokenDTO,
|
|
332
|
+
maxTokens: number = 100
|
|
333
|
+
): TokenCollectionRequest => {
|
|
334
|
+
if (!web3) {
|
|
335
|
+
throw new Error('SDK not initialized. Call initialize() first.');
|
|
336
|
+
}
|
|
337
|
+
return web3.buildCollectionRequest(accountAddress, token, maxTokens);
|
|
338
|
+
}, [web3]);
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
getTokenBalance,
|
|
342
|
+
getTokenMetadata,
|
|
343
|
+
getTokenCollection,
|
|
344
|
+
resolveIPFSUrl,
|
|
345
|
+
fetchAndProcessMetadata,
|
|
346
|
+
getChainDataById,
|
|
347
|
+
getExplorerUrl,
|
|
348
|
+
// Helper methods
|
|
349
|
+
extractTokenIds,
|
|
350
|
+
getAccountOwnedTokensFromContract,
|
|
351
|
+
buildCollectionRequest,
|
|
352
|
+
isAvailable: isInitialized && !!web3,
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
|
|
356
356
|
export type Web3Hook = ReturnType<typeof useWeb3>;
|