tiwiflix-wallet-connector 1.6.8 → 1.6.9
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/dist/index.d.ts +0 -6
- package/dist/index.esm.js +126 -248
- package/dist/index.js +126 -248
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -418,8 +418,6 @@ declare class WalletConnector {
|
|
|
418
418
|
* Get TWC token balance for EVM wallets
|
|
419
419
|
* TWC is ONLY available on BSC (chainId 56)
|
|
420
420
|
*/
|
|
421
|
-
private twcBalanceCache;
|
|
422
|
-
private readonly TWC_CACHE_TTL;
|
|
423
421
|
private balanceFetchErrors;
|
|
424
422
|
getTWCBalance(): Promise<{
|
|
425
423
|
amount: string;
|
|
@@ -492,10 +490,6 @@ declare class WalletConnector {
|
|
|
492
490
|
* Can optionally filter by collection addresses
|
|
493
491
|
*/
|
|
494
492
|
private queryAllTONNFTs;
|
|
495
|
-
/**
|
|
496
|
-
* Query TON API for NFTs owned by an address in a specific collection
|
|
497
|
-
*/
|
|
498
|
-
private queryTONNFTs;
|
|
499
493
|
}
|
|
500
494
|
|
|
501
495
|
/**
|
package/dist/index.esm.js
CHANGED
|
@@ -1907,7 +1907,7 @@ const defaultMultiChainConfig = {
|
|
|
1907
1907
|
{
|
|
1908
1908
|
chainId: 56,
|
|
1909
1909
|
name: 'BNB Smart Chain',
|
|
1910
|
-
rpcUrl: 'https://bsc
|
|
1910
|
+
rpcUrl: 'https://bsc.publicnode.com',
|
|
1911
1911
|
blockExplorerUrl: 'https://bscscan.com',
|
|
1912
1912
|
nativeCurrency: {
|
|
1913
1913
|
name: 'BNB',
|
|
@@ -2312,6 +2312,7 @@ class WalletConnector {
|
|
|
2312
2312
|
error: null,
|
|
2313
2313
|
twcBalance: null,
|
|
2314
2314
|
usdValue: null,
|
|
2315
|
+
chainId: null,
|
|
2315
2316
|
};
|
|
2316
2317
|
// Performance monitoring
|
|
2317
2318
|
this.performanceMetrics = {
|
|
@@ -2325,8 +2326,6 @@ class WalletConnector {
|
|
|
2325
2326
|
* TWC is ONLY available on BSC (chainId 56)
|
|
2326
2327
|
*/
|
|
2327
2328
|
// Cache for TWC balance to avoid redundant fetches
|
|
2328
|
-
this.twcBalanceCache = null;
|
|
2329
|
-
this.TWC_CACHE_TTL = 30000; // 30 seconds cache
|
|
2330
2329
|
// Error tracking for balance fetching
|
|
2331
2330
|
this.balanceFetchErrors = [];
|
|
2332
2331
|
this.config = config;
|
|
@@ -2693,7 +2692,7 @@ class WalletConnector {
|
|
|
2693
2692
|
clearTimeout(safetyTimeout);
|
|
2694
2693
|
clearTimeout(connectionTimeout);
|
|
2695
2694
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
2696
|
-
|
|
2695
|
+
// removed unused errorMsg
|
|
2697
2696
|
this.debugTools.error('WALLET_CONNECTOR', 'Connection error caught', error);
|
|
2698
2697
|
// Reset state on connection error
|
|
2699
2698
|
this.updateState({
|
|
@@ -2775,7 +2774,7 @@ class WalletConnector {
|
|
|
2775
2774
|
}
|
|
2776
2775
|
else {
|
|
2777
2776
|
// Connection failed - reset state properly
|
|
2778
|
-
|
|
2777
|
+
// removed unused errorMsg
|
|
2779
2778
|
this.debugTools.error('WALLET_CONNECTOR', 'Connection failed', result.error);
|
|
2780
2779
|
this.updateState({
|
|
2781
2780
|
status: ConnectionStatus.DISCONNECTED,
|
|
@@ -3151,154 +3150,29 @@ class WalletConnector {
|
|
|
3151
3150
|
this.sdkLoader.clearCache();
|
|
3152
3151
|
}
|
|
3153
3152
|
async getTWCBalance() {
|
|
3154
|
-
if (!this.state.account) {
|
|
3155
|
-
|
|
3156
|
-
window.showDebugLog?.('[getTWCBalance] No wallet connected');
|
|
3157
|
-
throw new Error('No wallet connected');
|
|
3153
|
+
if (!this.state.account || this.state.account.chainType !== 'evm') {
|
|
3154
|
+
throw new Error('No EVM account connected');
|
|
3158
3155
|
}
|
|
3159
3156
|
const accountAddress = this.state.account.address;
|
|
3160
|
-
const chainId = this.state.chainId;
|
|
3161
|
-
performance.now();
|
|
3162
|
-
if (typeof window !== 'undefined')
|
|
3163
|
-
window.showDebugLog?.(`[getTWCBalance] Called for account=${accountAddress}, chainId=${chainId}`);
|
|
3164
|
-
// Check cache first
|
|
3165
|
-
if (this.twcBalanceCache &&
|
|
3166
|
-
this.twcBalanceCache.address === accountAddress &&
|
|
3167
|
-
Date.now() - this.twcBalanceCache.timestamp < this.TWC_CACHE_TTL) {
|
|
3168
|
-
if (typeof window !== 'undefined')
|
|
3169
|
-
window.showDebugLog?.(`[getTWCBalance] Using cache for ${accountAddress}: ${JSON.stringify(this.twcBalanceCache)}`);
|
|
3170
|
-
return {
|
|
3171
|
-
amount: this.twcBalanceCache.balance,
|
|
3172
|
-
symbol: 'TWC',
|
|
3173
|
-
usdValue: this.twcBalanceCache.usdValue,
|
|
3174
|
-
usdFormatted: priceService.formatUSDValue(this.twcBalanceCache.usdValue)
|
|
3175
|
-
};
|
|
3176
|
-
}
|
|
3177
|
-
// TWC contract on BSC
|
|
3178
3157
|
const TWC_CONTRACT = '0xDA1060158F7D593667cCE0a15DB346BB3FfB3596';
|
|
3179
3158
|
const TWC_DECIMALS = 9;
|
|
3180
3159
|
const TWC_SYMBOL = 'TWC';
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
if (typeof window !== 'undefined') {
|
|
3198
|
-
window.showDebugLog?.(`[getTWCBalance] Using adapter: ${adapter.constructor?.name || typeof adapter}`);
|
|
3199
|
-
window.showDebugLog?.(`[getTWCBalance] Adapter keys: ${Object.keys(adapter).join(', ')}`);
|
|
3200
|
-
window.showDebugLog?.(`[getTWCBalance] typeof getTokenBalance: ${typeof adapter.getTokenBalance}`);
|
|
3201
|
-
}
|
|
3202
|
-
let balance;
|
|
3203
|
-
// Always use ethers fallback if EVM is connected, regardless of chainId
|
|
3204
|
-
if (this.state.chainId !== 56) {
|
|
3205
|
-
if (typeof window !== 'undefined')
|
|
3206
|
-
window.showDebugLog?.(`[getTWCBalance] Warning: Not on BSC (chainId=${this.state.chainId}), but fetching TWC balance using ethers fallback.`);
|
|
3207
|
-
// Fallback: use ethers.js to fetch balance from chain
|
|
3208
|
-
let provider = adapter.provider || this.getProvider();
|
|
3209
|
-
if (!provider) {
|
|
3210
|
-
if (typeof window !== 'undefined')
|
|
3211
|
-
window.showDebugLog?.('[getTWCBalance] No provider available for ethers fallback');
|
|
3212
|
-
throw new Error('No provider available for ethers fallback');
|
|
3213
|
-
}
|
|
3214
|
-
// Use ethers.BrowserProvider for ethers v6 compatibility
|
|
3215
|
-
if (!provider._isProvider) {
|
|
3216
|
-
provider = new ethers.BrowserProvider(provider);
|
|
3217
|
-
}
|
|
3218
|
-
const erc20Abi = ["function balanceOf(address) view returns (uint256)"];
|
|
3219
|
-
const contract = new ethers.Contract(TWC_CONTRACT, erc20Abi, provider);
|
|
3220
|
-
const rawBalance = await contract.balanceOf(accountAddress);
|
|
3221
|
-
if (typeof window !== 'undefined')
|
|
3222
|
-
window.showDebugLog?.(`[getTWCBalance] [ethers fallback] rawBalance (BigInt) for ${accountAddress}: ${rawBalance?.toString?.()}`);
|
|
3223
|
-
balance = ethers.formatUnits(rawBalance, TWC_DECIMALS);
|
|
3224
|
-
if (typeof window !== 'undefined')
|
|
3225
|
-
window.showDebugLog?.(`[getTWCBalance] Raw balance for ${accountAddress} (ethers): ${balance}`);
|
|
3226
|
-
}
|
|
3227
|
-
else if (typeof adapter.getTokenBalance === 'function') {
|
|
3228
|
-
// Use adapter method if available and on BSC
|
|
3229
|
-
const balancePromise = adapter.getTokenBalance(TWC_CONTRACT, TWC_DECIMALS, true);
|
|
3230
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
3231
|
-
setTimeout(() => reject(new Error('Balance fetch timeout after 10 seconds')), 10000);
|
|
3232
|
-
});
|
|
3233
|
-
balance = await Promise.race([balancePromise, timeoutPromise]);
|
|
3234
|
-
if (typeof window !== 'undefined')
|
|
3235
|
-
window.showDebugLog?.(`[getTWCBalance] Raw balance for ${accountAddress} (adapter): ${balance}`);
|
|
3236
|
-
}
|
|
3237
|
-
else {
|
|
3238
|
-
// Fallback: use ethers.js to fetch balance from chain (should not happen, but for safety)
|
|
3239
|
-
if (typeof window !== 'undefined')
|
|
3240
|
-
window.showDebugLog?.('[getTWCBalance] Fallback to ethers.js for TWC balance (on BSC)');
|
|
3241
|
-
let provider = adapter.provider || this.getProvider();
|
|
3242
|
-
if (!provider) {
|
|
3243
|
-
if (typeof window !== 'undefined')
|
|
3244
|
-
window.showDebugLog?.('[getTWCBalance] No provider available for ethers fallback');
|
|
3245
|
-
throw new Error('No provider available for ethers fallback');
|
|
3246
|
-
}
|
|
3247
|
-
if (!provider._isProvider) {
|
|
3248
|
-
provider = new ethers.BrowserProvider(provider);
|
|
3249
|
-
}
|
|
3250
|
-
const erc20Abi = ["function balanceOf(address) view returns (uint256)"];
|
|
3251
|
-
const contract = new ethers.Contract(TWC_CONTRACT, erc20Abi, provider);
|
|
3252
|
-
const rawBalance = await contract.balanceOf(accountAddress);
|
|
3253
|
-
if (typeof window !== 'undefined')
|
|
3254
|
-
window.showDebugLog?.(`[getTWCBalance] [ethers fallback] rawBalance (BigInt) for ${accountAddress}: ${rawBalance?.toString?.()}`);
|
|
3255
|
-
balance = ethers.formatUnits(rawBalance, TWC_DECIMALS);
|
|
3256
|
-
if (typeof window !== 'undefined')
|
|
3257
|
-
window.showDebugLog?.(`[getTWCBalance] Raw balance for ${accountAddress} (ethers): ${balance}`);
|
|
3258
|
-
}
|
|
3259
|
-
// Calculate USD value with 5 second timeout
|
|
3260
|
-
const usdPromise = priceService.calculateTWCValue(balance);
|
|
3261
|
-
const usdTimeoutPromise = new Promise((resolve) => {
|
|
3262
|
-
setTimeout(() => resolve(0), 5000); // Default to 0 on timeout
|
|
3263
|
-
});
|
|
3264
|
-
const usdValue = await Promise.race([usdPromise, usdTimeoutPromise]);
|
|
3265
|
-
if (typeof window !== 'undefined')
|
|
3266
|
-
window.showDebugLog?.(`[getTWCBalance] USD value for ${accountAddress}: ${usdValue}`);
|
|
3267
|
-
// Update cache
|
|
3268
|
-
this.twcBalanceCache = {
|
|
3269
|
-
balance,
|
|
3270
|
-
usdValue,
|
|
3271
|
-
timestamp: Date.now(),
|
|
3272
|
-
address: accountAddress
|
|
3273
|
-
};
|
|
3274
|
-
const result = {
|
|
3275
|
-
amount: balance,
|
|
3276
|
-
symbol: TWC_SYMBOL,
|
|
3277
|
-
usdValue,
|
|
3278
|
-
usdFormatted: priceService.formatUSDValue(usdValue)
|
|
3279
|
-
};
|
|
3280
|
-
// Keep state in sync
|
|
3281
|
-
this.updateState({ twcBalance: result.amount, usdValue: result.usdValue ?? null });
|
|
3282
|
-
if (typeof window !== 'undefined')
|
|
3283
|
-
window.showDebugLog?.(`[getTWCBalance] Final result for ${accountAddress}: ${JSON.stringify(result)}`);
|
|
3284
|
-
return result;
|
|
3285
|
-
}
|
|
3286
|
-
catch (error) {
|
|
3287
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3288
|
-
if (typeof window !== 'undefined')
|
|
3289
|
-
window.showDebugLog?.(`[getTWCBalance] ERROR: ${errorMsg}`);
|
|
3290
|
-
// Track error
|
|
3291
|
-
this.balanceFetchErrors.push({
|
|
3292
|
-
endpoint: 'wallet-provider',
|
|
3293
|
-
error: errorMsg,
|
|
3294
|
-
timestamp: Date.now()
|
|
3295
|
-
});
|
|
3296
|
-
// Keep only last 10 errors
|
|
3297
|
-
if (this.balanceFetchErrors.length > 10) {
|
|
3298
|
-
this.balanceFetchErrors = this.balanceFetchErrors.slice(-10);
|
|
3299
|
-
}
|
|
3300
|
-
throw error;
|
|
3301
|
-
}
|
|
3160
|
+
let provider = this.getProvider();
|
|
3161
|
+
// If provider is missing or not a valid ethers.js provider, use a public BSC provider
|
|
3162
|
+
if (!provider || typeof provider.call !== 'function') {
|
|
3163
|
+
provider = new ethers.JsonRpcProvider('https://bsc.publicnode.com', 56);
|
|
3164
|
+
}
|
|
3165
|
+
const erc20Abi = ["function balanceOf(address) view returns (uint256)"];
|
|
3166
|
+
const contract = new ethers.Contract(TWC_CONTRACT, erc20Abi, provider);
|
|
3167
|
+
const rawBalance = await contract.balanceOf(accountAddress);
|
|
3168
|
+
const balance = ethers.formatUnits(rawBalance, TWC_DECIMALS);
|
|
3169
|
+
const usdValue = await priceService.calculateTWCValue(balance);
|
|
3170
|
+
return {
|
|
3171
|
+
amount: balance,
|
|
3172
|
+
symbol: TWC_SYMBOL,
|
|
3173
|
+
usdValue,
|
|
3174
|
+
usdFormatted: priceService.formatUSDValue(usdValue)
|
|
3175
|
+
};
|
|
3302
3176
|
}
|
|
3303
3177
|
/**
|
|
3304
3178
|
* Get balance fetch error history (for debugging)
|
|
@@ -3560,73 +3434,6 @@ class WalletConnector {
|
|
|
3560
3434
|
return [];
|
|
3561
3435
|
}
|
|
3562
3436
|
}
|
|
3563
|
-
/**
|
|
3564
|
-
* Query TON API for NFTs owned by an address in a specific collection
|
|
3565
|
-
*/
|
|
3566
|
-
async queryTONNFTs(ownerAddress, collectionAddress) {
|
|
3567
|
-
// TON API endpoints to try
|
|
3568
|
-
const endpoints = [
|
|
3569
|
-
'https://tonapi.io/v1',
|
|
3570
|
-
'https://testnet.tonapi.io/v1'
|
|
3571
|
-
];
|
|
3572
|
-
for (const baseUrl of endpoints) {
|
|
3573
|
-
try {
|
|
3574
|
-
// First, get NFT items for the collection
|
|
3575
|
-
const collectionResponse = await fetch(`${baseUrl}/nft/getItems?collection=${collectionAddress}&limit=1000`, {
|
|
3576
|
-
method: 'GET',
|
|
3577
|
-
headers: {
|
|
3578
|
-
'Accept': 'application/json'
|
|
3579
|
-
}
|
|
3580
|
-
});
|
|
3581
|
-
if (!collectionResponse.ok) {
|
|
3582
|
-
continue; // Try next endpoint
|
|
3583
|
-
}
|
|
3584
|
-
const collectionData = await collectionResponse.json();
|
|
3585
|
-
const nftItems = collectionData.nft_items || [];
|
|
3586
|
-
// Filter NFTs owned by the specified address
|
|
3587
|
-
const ownedNFTs = [];
|
|
3588
|
-
for (const nft of nftItems) {
|
|
3589
|
-
if (nft.owner?.address === ownerAddress) {
|
|
3590
|
-
ownedNFTs.push({
|
|
3591
|
-
collection: collectionAddress,
|
|
3592
|
-
nftAddress: nft.address,
|
|
3593
|
-
name: nft.metadata?.name,
|
|
3594
|
-
description: nft.metadata?.description
|
|
3595
|
-
});
|
|
3596
|
-
}
|
|
3597
|
-
}
|
|
3598
|
-
return ownedNFTs;
|
|
3599
|
-
}
|
|
3600
|
-
catch (error) {
|
|
3601
|
-
this.debugTools.warn('WALLET_CONNECTOR', `TON API call failed for ${baseUrl}`, error);
|
|
3602
|
-
continue; // Try next endpoint
|
|
3603
|
-
}
|
|
3604
|
-
}
|
|
3605
|
-
// If all endpoints fail, try a simpler approach using getAccountNftItems
|
|
3606
|
-
try {
|
|
3607
|
-
const accountResponse = await fetch(`${endpoints[0]}/account/getNftItems?account=${ownerAddress}&collection=${collectionAddress}&limit=100`, {
|
|
3608
|
-
method: 'GET',
|
|
3609
|
-
headers: {
|
|
3610
|
-
'Accept': 'application/json'
|
|
3611
|
-
}
|
|
3612
|
-
});
|
|
3613
|
-
if (accountResponse.ok) {
|
|
3614
|
-
const accountData = await accountResponse.json();
|
|
3615
|
-
const nftItems = accountData.nft_items || [];
|
|
3616
|
-
return nftItems.map((nft) => ({
|
|
3617
|
-
collection: collectionAddress,
|
|
3618
|
-
nftAddress: nft.address,
|
|
3619
|
-
name: nft.metadata?.name,
|
|
3620
|
-
description: nft.metadata?.description
|
|
3621
|
-
}));
|
|
3622
|
-
}
|
|
3623
|
-
}
|
|
3624
|
-
catch (error) {
|
|
3625
|
-
this.debugTools.warn('WALLET_CONNECTOR', 'Fallback NFT query also failed', error);
|
|
3626
|
-
}
|
|
3627
|
-
// Return empty array if all queries fail
|
|
3628
|
-
return [];
|
|
3629
|
-
}
|
|
3630
3437
|
}
|
|
3631
3438
|
|
|
3632
3439
|
/**
|
|
@@ -7677,8 +7484,41 @@ function showDebugLog(msg) {
|
|
|
7677
7484
|
const tonApiCache = new Map();
|
|
7678
7485
|
const CACHE_DURATION = 30000; // 30 seconds
|
|
7679
7486
|
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', getExplorerUrl, }) => {
|
|
7487
|
+
// Move all state hooks that are referenced early to the top to avoid use-before-init errors
|
|
7488
|
+
const [isInitializing, setIsInitializing] = useState(true);
|
|
7489
|
+
const [isConnecting, setIsConnecting] = useState(false);
|
|
7490
|
+
const [balanceLoading, setBalanceLoading] = useState(false);
|
|
7680
7491
|
// Always fetch balance automatically when wallet is connected
|
|
7681
7492
|
// Balance is always fetched automatically from the chain
|
|
7493
|
+
// Helper: get the best available TWC balance (cached or real)
|
|
7494
|
+
const getDisplayBalance = () => {
|
|
7495
|
+
// Prefer real fetched balance if available and non-zero
|
|
7496
|
+
if (twcBalance && twcBalance !== '0' && twcBalance !== '0.00')
|
|
7497
|
+
return twcBalance;
|
|
7498
|
+
// Fallback to cached balance if available and non-zero
|
|
7499
|
+
if (account?.address) {
|
|
7500
|
+
const cached = loadTWCBalanceFromCache(account.address);
|
|
7501
|
+
if (cached?.balance && cached.balance !== '0' && cached.balance !== '0.00')
|
|
7502
|
+
return cached.balance;
|
|
7503
|
+
}
|
|
7504
|
+
// If loading, keep showing last known value (even if zero)
|
|
7505
|
+
if (isInitializing || isConnecting) {
|
|
7506
|
+
if (twcBalance)
|
|
7507
|
+
return twcBalance;
|
|
7508
|
+
if (account?.address) {
|
|
7509
|
+
const cached = loadTWCBalanceFromCache(account.address);
|
|
7510
|
+
if (cached?.balance)
|
|
7511
|
+
return cached.balance;
|
|
7512
|
+
}
|
|
7513
|
+
}
|
|
7514
|
+
// Otherwise, show 0
|
|
7515
|
+
return '0';
|
|
7516
|
+
};
|
|
7517
|
+
// ...existing code...
|
|
7518
|
+
// ...existing code...
|
|
7519
|
+
// Helper: show spinner if loading/connecting
|
|
7520
|
+
// Show spinner if initializing, connecting, or balance is loading
|
|
7521
|
+
const showSpinner = Boolean(isInitializing || isConnecting || balanceLoading);
|
|
7682
7522
|
// Detect dark mode
|
|
7683
7523
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
7684
7524
|
useEffect(() => {
|
|
@@ -7696,7 +7536,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7696
7536
|
}, [theme]);
|
|
7697
7537
|
const [account, setAccount] = useState(null);
|
|
7698
7538
|
const [status, setStatus] = useState(ConnectionStatus.DISCONNECTED);
|
|
7699
|
-
const [isInitializing, setIsInitializing] = useState(true);
|
|
7700
7539
|
const [showModal, setShowModal] = useState(false);
|
|
7701
7540
|
// Preload Reown SDK when modal opens for faster connection
|
|
7702
7541
|
React.useEffect(() => {
|
|
@@ -7718,7 +7557,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7718
7557
|
const [showActivityModal, setShowActivityModal] = useState(false);
|
|
7719
7558
|
const [showTWCBalanceModal, setShowTWCBalanceModal] = useState(false);
|
|
7720
7559
|
const [availableWallets, setAvailableWallets] = useState([]);
|
|
7721
|
-
const [isConnecting, setIsConnecting] = useState(false);
|
|
7722
7560
|
const [error, setError] = useState(null);
|
|
7723
7561
|
const [nftCount, setNftCount] = useState(0);
|
|
7724
7562
|
const [nftLoading, setNftLoading] = useState(false);
|
|
@@ -7729,7 +7567,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7729
7567
|
const [txsLoading, setTxsLoading] = useState(false);
|
|
7730
7568
|
const [txsError, setTxsError] = useState(null);
|
|
7731
7569
|
const [balance, setBalance] = useState({ amount: '', symbol: '' });
|
|
7732
|
-
const [balanceLoading, setBalanceLoading] = useState(false);
|
|
7733
7570
|
const [currentChainId, setCurrentChainId] = useState(null);
|
|
7734
7571
|
const [isWrongNetwork, setIsWrongNetwork] = useState(false);
|
|
7735
7572
|
// TWC Balance cache key prefix
|
|
@@ -8907,8 +8744,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8907
8744
|
}, [connector, account]);
|
|
8908
8745
|
// Render button based on connection status
|
|
8909
8746
|
const renderButton = () => {
|
|
8910
|
-
//
|
|
8911
|
-
if (!
|
|
8747
|
+
// Always show connect button for first-time visitors or when not connected
|
|
8748
|
+
if (!account && status === ConnectionStatus.DISCONNECTED) {
|
|
8912
8749
|
// Wallet icon SVG component
|
|
8913
8750
|
const WalletIcon = () => (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block' }, children: [jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }), jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })] }));
|
|
8914
8751
|
return (jsxs("button", { onClick: () => handleOpenModal(), style: {
|
|
@@ -9082,34 +8919,75 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
9082
8919
|
}
|
|
9083
8920
|
// Wallet icon SVG component
|
|
9084
8921
|
const WalletIcon = () => (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block' }, children: [jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }), jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })] }));
|
|
9085
|
-
//
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
8922
|
+
// Always show the button, but change content based on connection state
|
|
8923
|
+
const displayBalance = getDisplayBalance();
|
|
8924
|
+
const isConnected = !!account && status === ConnectionStatus.CONNECTED;
|
|
8925
|
+
// Helper for details modal open
|
|
8926
|
+
const handleOpenDetailsModal = () => setShowDetailsModal(true);
|
|
8927
|
+
// Wallet icon for display
|
|
8928
|
+
const walletIcon = account ? getWalletIcon(connector.getState().wallet || '') : jsx("span", { children: "\uD83D\uDCBC" });
|
|
8929
|
+
// Current wallet type
|
|
8930
|
+
const currentWalletType = connector.getState().wallet;
|
|
8931
|
+
return (jsxs(React.Fragment, { children: [jsx("style", { children: `
|
|
8932
|
+
@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap');
|
|
8933
|
+
.tiwiflix-scrollbar-hide::-webkit-scrollbar {
|
|
8934
|
+
display: none;
|
|
8935
|
+
}
|
|
8936
|
+
.twc-balance-spinner {
|
|
8937
|
+
display: inline-block;
|
|
8938
|
+
width: 16px;
|
|
8939
|
+
height: 16px;
|
|
8940
|
+
border: 2px solid #FF9814;
|
|
8941
|
+
border-top: 2px solid #fff;
|
|
8942
|
+
border-radius: 50%;
|
|
8943
|
+
animation: spin 0.7s linear infinite;
|
|
8944
|
+
margin-left: 6px;
|
|
8945
|
+
vertical-align: middle;
|
|
8946
|
+
}
|
|
8947
|
+
@keyframes spin {
|
|
8948
|
+
0% { transform: rotate(0deg); }
|
|
8949
|
+
100% { transform: rotate(360deg); }
|
|
8950
|
+
}
|
|
8951
|
+
` }), jsxs("button", { onClick: () => (isConnected ? handleOpenDetailsModal() : handleOpenModal()), style: {
|
|
8952
|
+
display: 'flex',
|
|
8953
|
+
alignItems: 'center',
|
|
8954
|
+
gap: '10px',
|
|
8955
|
+
padding: '12px 12px',
|
|
8956
|
+
borderRadius: '12px',
|
|
8957
|
+
border: 'none',
|
|
8958
|
+
backgroundColor: isConnected ? '#0A0A0A' : '#FF9814',
|
|
8959
|
+
color: isConnected ? '#FF9814' : '#000000',
|
|
8960
|
+
fontWeight: '700',
|
|
8961
|
+
fontSize: '15px',
|
|
8962
|
+
cursor: showSpinner ? 'wait' : 'pointer',
|
|
8963
|
+
transition: 'all 0.15s ease',
|
|
8964
|
+
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
8965
|
+
boxShadow: isConnected ? '0 2px 8px rgba(10,10,10,0.3)' : '0 2px 8px rgba(255, 152, 20, 0.3)',
|
|
8966
|
+
opacity: showSpinner ? 0.85 : 1,
|
|
8967
|
+
pointerEvents: showSpinner ? 'none' : 'auto',
|
|
8968
|
+
...style,
|
|
8969
|
+
}, className: className, disabled: showSpinner, onMouseEnter: (e) => {
|
|
8970
|
+
if (!isConnected) {
|
|
8971
|
+
e.currentTarget.style.backgroundColor = '#E8870F';
|
|
8972
|
+
e.currentTarget.style.transform = 'translateY(-1px)';
|
|
8973
|
+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(255, 152, 20, 0.4)';
|
|
8974
|
+
}
|
|
8975
|
+
}, onMouseLeave: (e) => {
|
|
8976
|
+
if (!isConnected) {
|
|
8977
|
+
e.currentTarget.style.backgroundColor = '#FF9814';
|
|
8978
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
8979
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(255, 152, 20, 0.3)';
|
|
8980
|
+
}
|
|
8981
|
+
}, children: [jsx("span", { style: { color: isConnected ? '#FF9814' : '#000000', display: 'flex', alignItems: 'center' }, children: jsx(WalletIcon, {}) }), jsx("span", { style: { color: isConnected ? '#FF9814' : '#000000', fontWeight: '500', fontSize: '14px' }, children: isConnected ? (jsxs(Fragment, { children: [twcIconMemoized, jsx("span", { style: { marginLeft: 6, fontWeight: 600, fontFamily: 'SF Mono, Monaco, Inconsolata, Roboto Mono, monospace' }, children: displayBalance }), showSpinner && jsx("span", { className: "twc-balance-spinner" })] })) : (jsxs(Fragment, { children: [buttonText, showSpinner && jsx("span", { className: "twc-balance-spinner" })] })) })] }), jsx(AccountDetailsModal, { isOpen: showDetailsModal, onClose: () => setShowDetailsModal(false), account: account, onDisconnect: handleDisconnect, onCopyAddress: handleCopyAddress, onOpenSwap: () => setShowSwapModal(true), onOpenSend: () => setShowSendModal(true), onOpenActivity: () => setShowActivityModal(true), balance: balance, balanceLoading: balanceLoading, twcBalance: twcBalance, usdValue: usdValue, nftCount: nftCount, nftLoading: nftLoading, tonBalance: balance.amount || tonBalance, tonUsdValue: balance.usdValue ?? tonUsdValue, walletIcon: walletIcon, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition,
|
|
8982
|
+
// Add a Switch Wallet button to allow explicit wallet switching
|
|
8983
|
+
onSwitchWallet: () => handleOpenModal(true) }), jsx(ActivityModal, { isOpen: showActivityModal, onClose: () => setShowActivityModal(false), transactions: txs, loading: txsLoading, error: txsError, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsx(SwapModal, { isOpen: showSwapModal && account?.chainType !== 'ton', onClose: () => setShowSwapModal(false), colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsx(SendModal, { isOpen: showSendModal, onClose: () => setShowSendModal(false), balance: balance, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onSend: async () => {
|
|
8984
|
+
alert('Send functionality coming soon');
|
|
8985
|
+
setShowSendModal(false);
|
|
8986
|
+
} }), jsx(TWCBalanceModal, { isOpen: showTWCBalanceModal, onClose: () => setShowTWCBalanceModal(false), twcBalance: twcBalance, usdValue: usdValue, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onBuyTWC: () => {
|
|
8987
|
+
// Handle Buy TWC action
|
|
8988
|
+
}, onLearnMore: () => {
|
|
8989
|
+
// Handle Learn More action
|
|
8990
|
+
} }), jsx(WalletSelectModal, { isOpen: showModal, onClose: () => setShowModal(false), onSelectWallet: handleConnect, availableWallets: availableWallets, currentWalletType: currentWalletType, isConnecting: isConnecting, error: error, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition })] }));
|
|
9113
8991
|
};
|
|
9114
8992
|
// Group wallets by chain
|
|
9115
8993
|
availableWallets.reduce((acc, wallet) => {
|
package/dist/index.js
CHANGED
|
@@ -1909,7 +1909,7 @@ const defaultMultiChainConfig = {
|
|
|
1909
1909
|
{
|
|
1910
1910
|
chainId: 56,
|
|
1911
1911
|
name: 'BNB Smart Chain',
|
|
1912
|
-
rpcUrl: 'https://bsc
|
|
1912
|
+
rpcUrl: 'https://bsc.publicnode.com',
|
|
1913
1913
|
blockExplorerUrl: 'https://bscscan.com',
|
|
1914
1914
|
nativeCurrency: {
|
|
1915
1915
|
name: 'BNB',
|
|
@@ -2314,6 +2314,7 @@ class WalletConnector {
|
|
|
2314
2314
|
error: null,
|
|
2315
2315
|
twcBalance: null,
|
|
2316
2316
|
usdValue: null,
|
|
2317
|
+
chainId: null,
|
|
2317
2318
|
};
|
|
2318
2319
|
// Performance monitoring
|
|
2319
2320
|
this.performanceMetrics = {
|
|
@@ -2327,8 +2328,6 @@ class WalletConnector {
|
|
|
2327
2328
|
* TWC is ONLY available on BSC (chainId 56)
|
|
2328
2329
|
*/
|
|
2329
2330
|
// Cache for TWC balance to avoid redundant fetches
|
|
2330
|
-
this.twcBalanceCache = null;
|
|
2331
|
-
this.TWC_CACHE_TTL = 30000; // 30 seconds cache
|
|
2332
2331
|
// Error tracking for balance fetching
|
|
2333
2332
|
this.balanceFetchErrors = [];
|
|
2334
2333
|
this.config = config;
|
|
@@ -2695,7 +2694,7 @@ class WalletConnector {
|
|
|
2695
2694
|
clearTimeout(safetyTimeout);
|
|
2696
2695
|
clearTimeout(connectionTimeout);
|
|
2697
2696
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
2698
|
-
|
|
2697
|
+
// removed unused errorMsg
|
|
2699
2698
|
this.debugTools.error('WALLET_CONNECTOR', 'Connection error caught', error);
|
|
2700
2699
|
// Reset state on connection error
|
|
2701
2700
|
this.updateState({
|
|
@@ -2777,7 +2776,7 @@ class WalletConnector {
|
|
|
2777
2776
|
}
|
|
2778
2777
|
else {
|
|
2779
2778
|
// Connection failed - reset state properly
|
|
2780
|
-
|
|
2779
|
+
// removed unused errorMsg
|
|
2781
2780
|
this.debugTools.error('WALLET_CONNECTOR', 'Connection failed', result.error);
|
|
2782
2781
|
this.updateState({
|
|
2783
2782
|
status: exports.ConnectionStatus.DISCONNECTED,
|
|
@@ -3153,154 +3152,29 @@ class WalletConnector {
|
|
|
3153
3152
|
this.sdkLoader.clearCache();
|
|
3154
3153
|
}
|
|
3155
3154
|
async getTWCBalance() {
|
|
3156
|
-
if (!this.state.account) {
|
|
3157
|
-
|
|
3158
|
-
window.showDebugLog?.('[getTWCBalance] No wallet connected');
|
|
3159
|
-
throw new Error('No wallet connected');
|
|
3155
|
+
if (!this.state.account || this.state.account.chainType !== 'evm') {
|
|
3156
|
+
throw new Error('No EVM account connected');
|
|
3160
3157
|
}
|
|
3161
3158
|
const accountAddress = this.state.account.address;
|
|
3162
|
-
const chainId = this.state.chainId;
|
|
3163
|
-
performance.now();
|
|
3164
|
-
if (typeof window !== 'undefined')
|
|
3165
|
-
window.showDebugLog?.(`[getTWCBalance] Called for account=${accountAddress}, chainId=${chainId}`);
|
|
3166
|
-
// Check cache first
|
|
3167
|
-
if (this.twcBalanceCache &&
|
|
3168
|
-
this.twcBalanceCache.address === accountAddress &&
|
|
3169
|
-
Date.now() - this.twcBalanceCache.timestamp < this.TWC_CACHE_TTL) {
|
|
3170
|
-
if (typeof window !== 'undefined')
|
|
3171
|
-
window.showDebugLog?.(`[getTWCBalance] Using cache for ${accountAddress}: ${JSON.stringify(this.twcBalanceCache)}`);
|
|
3172
|
-
return {
|
|
3173
|
-
amount: this.twcBalanceCache.balance,
|
|
3174
|
-
symbol: 'TWC',
|
|
3175
|
-
usdValue: this.twcBalanceCache.usdValue,
|
|
3176
|
-
usdFormatted: priceService.formatUSDValue(this.twcBalanceCache.usdValue)
|
|
3177
|
-
};
|
|
3178
|
-
}
|
|
3179
|
-
// TWC contract on BSC
|
|
3180
3159
|
const TWC_CONTRACT = '0xDA1060158F7D593667cCE0a15DB346BB3FfB3596';
|
|
3181
3160
|
const TWC_DECIMALS = 9;
|
|
3182
3161
|
const TWC_SYMBOL = 'TWC';
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
if (typeof window !== 'undefined') {
|
|
3200
|
-
window.showDebugLog?.(`[getTWCBalance] Using adapter: ${adapter.constructor?.name || typeof adapter}`);
|
|
3201
|
-
window.showDebugLog?.(`[getTWCBalance] Adapter keys: ${Object.keys(adapter).join(', ')}`);
|
|
3202
|
-
window.showDebugLog?.(`[getTWCBalance] typeof getTokenBalance: ${typeof adapter.getTokenBalance}`);
|
|
3203
|
-
}
|
|
3204
|
-
let balance;
|
|
3205
|
-
// Always use ethers fallback if EVM is connected, regardless of chainId
|
|
3206
|
-
if (this.state.chainId !== 56) {
|
|
3207
|
-
if (typeof window !== 'undefined')
|
|
3208
|
-
window.showDebugLog?.(`[getTWCBalance] Warning: Not on BSC (chainId=${this.state.chainId}), but fetching TWC balance using ethers fallback.`);
|
|
3209
|
-
// Fallback: use ethers.js to fetch balance from chain
|
|
3210
|
-
let provider = adapter.provider || this.getProvider();
|
|
3211
|
-
if (!provider) {
|
|
3212
|
-
if (typeof window !== 'undefined')
|
|
3213
|
-
window.showDebugLog?.('[getTWCBalance] No provider available for ethers fallback');
|
|
3214
|
-
throw new Error('No provider available for ethers fallback');
|
|
3215
|
-
}
|
|
3216
|
-
// Use ethers.BrowserProvider for ethers v6 compatibility
|
|
3217
|
-
if (!provider._isProvider) {
|
|
3218
|
-
provider = new ethers.ethers.BrowserProvider(provider);
|
|
3219
|
-
}
|
|
3220
|
-
const erc20Abi = ["function balanceOf(address) view returns (uint256)"];
|
|
3221
|
-
const contract = new ethers.ethers.Contract(TWC_CONTRACT, erc20Abi, provider);
|
|
3222
|
-
const rawBalance = await contract.balanceOf(accountAddress);
|
|
3223
|
-
if (typeof window !== 'undefined')
|
|
3224
|
-
window.showDebugLog?.(`[getTWCBalance] [ethers fallback] rawBalance (BigInt) for ${accountAddress}: ${rawBalance?.toString?.()}`);
|
|
3225
|
-
balance = ethers.ethers.formatUnits(rawBalance, TWC_DECIMALS);
|
|
3226
|
-
if (typeof window !== 'undefined')
|
|
3227
|
-
window.showDebugLog?.(`[getTWCBalance] Raw balance for ${accountAddress} (ethers): ${balance}`);
|
|
3228
|
-
}
|
|
3229
|
-
else if (typeof adapter.getTokenBalance === 'function') {
|
|
3230
|
-
// Use adapter method if available and on BSC
|
|
3231
|
-
const balancePromise = adapter.getTokenBalance(TWC_CONTRACT, TWC_DECIMALS, true);
|
|
3232
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
3233
|
-
setTimeout(() => reject(new Error('Balance fetch timeout after 10 seconds')), 10000);
|
|
3234
|
-
});
|
|
3235
|
-
balance = await Promise.race([balancePromise, timeoutPromise]);
|
|
3236
|
-
if (typeof window !== 'undefined')
|
|
3237
|
-
window.showDebugLog?.(`[getTWCBalance] Raw balance for ${accountAddress} (adapter): ${balance}`);
|
|
3238
|
-
}
|
|
3239
|
-
else {
|
|
3240
|
-
// Fallback: use ethers.js to fetch balance from chain (should not happen, but for safety)
|
|
3241
|
-
if (typeof window !== 'undefined')
|
|
3242
|
-
window.showDebugLog?.('[getTWCBalance] Fallback to ethers.js for TWC balance (on BSC)');
|
|
3243
|
-
let provider = adapter.provider || this.getProvider();
|
|
3244
|
-
if (!provider) {
|
|
3245
|
-
if (typeof window !== 'undefined')
|
|
3246
|
-
window.showDebugLog?.('[getTWCBalance] No provider available for ethers fallback');
|
|
3247
|
-
throw new Error('No provider available for ethers fallback');
|
|
3248
|
-
}
|
|
3249
|
-
if (!provider._isProvider) {
|
|
3250
|
-
provider = new ethers.ethers.BrowserProvider(provider);
|
|
3251
|
-
}
|
|
3252
|
-
const erc20Abi = ["function balanceOf(address) view returns (uint256)"];
|
|
3253
|
-
const contract = new ethers.ethers.Contract(TWC_CONTRACT, erc20Abi, provider);
|
|
3254
|
-
const rawBalance = await contract.balanceOf(accountAddress);
|
|
3255
|
-
if (typeof window !== 'undefined')
|
|
3256
|
-
window.showDebugLog?.(`[getTWCBalance] [ethers fallback] rawBalance (BigInt) for ${accountAddress}: ${rawBalance?.toString?.()}`);
|
|
3257
|
-
balance = ethers.ethers.formatUnits(rawBalance, TWC_DECIMALS);
|
|
3258
|
-
if (typeof window !== 'undefined')
|
|
3259
|
-
window.showDebugLog?.(`[getTWCBalance] Raw balance for ${accountAddress} (ethers): ${balance}`);
|
|
3260
|
-
}
|
|
3261
|
-
// Calculate USD value with 5 second timeout
|
|
3262
|
-
const usdPromise = priceService.calculateTWCValue(balance);
|
|
3263
|
-
const usdTimeoutPromise = new Promise((resolve) => {
|
|
3264
|
-
setTimeout(() => resolve(0), 5000); // Default to 0 on timeout
|
|
3265
|
-
});
|
|
3266
|
-
const usdValue = await Promise.race([usdPromise, usdTimeoutPromise]);
|
|
3267
|
-
if (typeof window !== 'undefined')
|
|
3268
|
-
window.showDebugLog?.(`[getTWCBalance] USD value for ${accountAddress}: ${usdValue}`);
|
|
3269
|
-
// Update cache
|
|
3270
|
-
this.twcBalanceCache = {
|
|
3271
|
-
balance,
|
|
3272
|
-
usdValue,
|
|
3273
|
-
timestamp: Date.now(),
|
|
3274
|
-
address: accountAddress
|
|
3275
|
-
};
|
|
3276
|
-
const result = {
|
|
3277
|
-
amount: balance,
|
|
3278
|
-
symbol: TWC_SYMBOL,
|
|
3279
|
-
usdValue,
|
|
3280
|
-
usdFormatted: priceService.formatUSDValue(usdValue)
|
|
3281
|
-
};
|
|
3282
|
-
// Keep state in sync
|
|
3283
|
-
this.updateState({ twcBalance: result.amount, usdValue: result.usdValue ?? null });
|
|
3284
|
-
if (typeof window !== 'undefined')
|
|
3285
|
-
window.showDebugLog?.(`[getTWCBalance] Final result for ${accountAddress}: ${JSON.stringify(result)}`);
|
|
3286
|
-
return result;
|
|
3287
|
-
}
|
|
3288
|
-
catch (error) {
|
|
3289
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3290
|
-
if (typeof window !== 'undefined')
|
|
3291
|
-
window.showDebugLog?.(`[getTWCBalance] ERROR: ${errorMsg}`);
|
|
3292
|
-
// Track error
|
|
3293
|
-
this.balanceFetchErrors.push({
|
|
3294
|
-
endpoint: 'wallet-provider',
|
|
3295
|
-
error: errorMsg,
|
|
3296
|
-
timestamp: Date.now()
|
|
3297
|
-
});
|
|
3298
|
-
// Keep only last 10 errors
|
|
3299
|
-
if (this.balanceFetchErrors.length > 10) {
|
|
3300
|
-
this.balanceFetchErrors = this.balanceFetchErrors.slice(-10);
|
|
3301
|
-
}
|
|
3302
|
-
throw error;
|
|
3303
|
-
}
|
|
3162
|
+
let provider = this.getProvider();
|
|
3163
|
+
// If provider is missing or not a valid ethers.js provider, use a public BSC provider
|
|
3164
|
+
if (!provider || typeof provider.call !== 'function') {
|
|
3165
|
+
provider = new ethers.ethers.JsonRpcProvider('https://bsc.publicnode.com', 56);
|
|
3166
|
+
}
|
|
3167
|
+
const erc20Abi = ["function balanceOf(address) view returns (uint256)"];
|
|
3168
|
+
const contract = new ethers.ethers.Contract(TWC_CONTRACT, erc20Abi, provider);
|
|
3169
|
+
const rawBalance = await contract.balanceOf(accountAddress);
|
|
3170
|
+
const balance = ethers.ethers.formatUnits(rawBalance, TWC_DECIMALS);
|
|
3171
|
+
const usdValue = await priceService.calculateTWCValue(balance);
|
|
3172
|
+
return {
|
|
3173
|
+
amount: balance,
|
|
3174
|
+
symbol: TWC_SYMBOL,
|
|
3175
|
+
usdValue,
|
|
3176
|
+
usdFormatted: priceService.formatUSDValue(usdValue)
|
|
3177
|
+
};
|
|
3304
3178
|
}
|
|
3305
3179
|
/**
|
|
3306
3180
|
* Get balance fetch error history (for debugging)
|
|
@@ -3562,73 +3436,6 @@ class WalletConnector {
|
|
|
3562
3436
|
return [];
|
|
3563
3437
|
}
|
|
3564
3438
|
}
|
|
3565
|
-
/**
|
|
3566
|
-
* Query TON API for NFTs owned by an address in a specific collection
|
|
3567
|
-
*/
|
|
3568
|
-
async queryTONNFTs(ownerAddress, collectionAddress) {
|
|
3569
|
-
// TON API endpoints to try
|
|
3570
|
-
const endpoints = [
|
|
3571
|
-
'https://tonapi.io/v1',
|
|
3572
|
-
'https://testnet.tonapi.io/v1'
|
|
3573
|
-
];
|
|
3574
|
-
for (const baseUrl of endpoints) {
|
|
3575
|
-
try {
|
|
3576
|
-
// First, get NFT items for the collection
|
|
3577
|
-
const collectionResponse = await fetch(`${baseUrl}/nft/getItems?collection=${collectionAddress}&limit=1000`, {
|
|
3578
|
-
method: 'GET',
|
|
3579
|
-
headers: {
|
|
3580
|
-
'Accept': 'application/json'
|
|
3581
|
-
}
|
|
3582
|
-
});
|
|
3583
|
-
if (!collectionResponse.ok) {
|
|
3584
|
-
continue; // Try next endpoint
|
|
3585
|
-
}
|
|
3586
|
-
const collectionData = await collectionResponse.json();
|
|
3587
|
-
const nftItems = collectionData.nft_items || [];
|
|
3588
|
-
// Filter NFTs owned by the specified address
|
|
3589
|
-
const ownedNFTs = [];
|
|
3590
|
-
for (const nft of nftItems) {
|
|
3591
|
-
if (nft.owner?.address === ownerAddress) {
|
|
3592
|
-
ownedNFTs.push({
|
|
3593
|
-
collection: collectionAddress,
|
|
3594
|
-
nftAddress: nft.address,
|
|
3595
|
-
name: nft.metadata?.name,
|
|
3596
|
-
description: nft.metadata?.description
|
|
3597
|
-
});
|
|
3598
|
-
}
|
|
3599
|
-
}
|
|
3600
|
-
return ownedNFTs;
|
|
3601
|
-
}
|
|
3602
|
-
catch (error) {
|
|
3603
|
-
this.debugTools.warn('WALLET_CONNECTOR', `TON API call failed for ${baseUrl}`, error);
|
|
3604
|
-
continue; // Try next endpoint
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
// If all endpoints fail, try a simpler approach using getAccountNftItems
|
|
3608
|
-
try {
|
|
3609
|
-
const accountResponse = await fetch(`${endpoints[0]}/account/getNftItems?account=${ownerAddress}&collection=${collectionAddress}&limit=100`, {
|
|
3610
|
-
method: 'GET',
|
|
3611
|
-
headers: {
|
|
3612
|
-
'Accept': 'application/json'
|
|
3613
|
-
}
|
|
3614
|
-
});
|
|
3615
|
-
if (accountResponse.ok) {
|
|
3616
|
-
const accountData = await accountResponse.json();
|
|
3617
|
-
const nftItems = accountData.nft_items || [];
|
|
3618
|
-
return nftItems.map((nft) => ({
|
|
3619
|
-
collection: collectionAddress,
|
|
3620
|
-
nftAddress: nft.address,
|
|
3621
|
-
name: nft.metadata?.name,
|
|
3622
|
-
description: nft.metadata?.description
|
|
3623
|
-
}));
|
|
3624
|
-
}
|
|
3625
|
-
}
|
|
3626
|
-
catch (error) {
|
|
3627
|
-
this.debugTools.warn('WALLET_CONNECTOR', 'Fallback NFT query also failed', error);
|
|
3628
|
-
}
|
|
3629
|
-
// Return empty array if all queries fail
|
|
3630
|
-
return [];
|
|
3631
|
-
}
|
|
3632
3439
|
}
|
|
3633
3440
|
|
|
3634
3441
|
/**
|
|
@@ -7679,8 +7486,41 @@ function showDebugLog(msg) {
|
|
|
7679
7486
|
const tonApiCache = new Map();
|
|
7680
7487
|
const CACHE_DURATION = 30000; // 30 seconds
|
|
7681
7488
|
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', getExplorerUrl, }) => {
|
|
7489
|
+
// Move all state hooks that are referenced early to the top to avoid use-before-init errors
|
|
7490
|
+
const [isInitializing, setIsInitializing] = React.useState(true);
|
|
7491
|
+
const [isConnecting, setIsConnecting] = React.useState(false);
|
|
7492
|
+
const [balanceLoading, setBalanceLoading] = React.useState(false);
|
|
7682
7493
|
// Always fetch balance automatically when wallet is connected
|
|
7683
7494
|
// Balance is always fetched automatically from the chain
|
|
7495
|
+
// Helper: get the best available TWC balance (cached or real)
|
|
7496
|
+
const getDisplayBalance = () => {
|
|
7497
|
+
// Prefer real fetched balance if available and non-zero
|
|
7498
|
+
if (twcBalance && twcBalance !== '0' && twcBalance !== '0.00')
|
|
7499
|
+
return twcBalance;
|
|
7500
|
+
// Fallback to cached balance if available and non-zero
|
|
7501
|
+
if (account?.address) {
|
|
7502
|
+
const cached = loadTWCBalanceFromCache(account.address);
|
|
7503
|
+
if (cached?.balance && cached.balance !== '0' && cached.balance !== '0.00')
|
|
7504
|
+
return cached.balance;
|
|
7505
|
+
}
|
|
7506
|
+
// If loading, keep showing last known value (even if zero)
|
|
7507
|
+
if (isInitializing || isConnecting) {
|
|
7508
|
+
if (twcBalance)
|
|
7509
|
+
return twcBalance;
|
|
7510
|
+
if (account?.address) {
|
|
7511
|
+
const cached = loadTWCBalanceFromCache(account.address);
|
|
7512
|
+
if (cached?.balance)
|
|
7513
|
+
return cached.balance;
|
|
7514
|
+
}
|
|
7515
|
+
}
|
|
7516
|
+
// Otherwise, show 0
|
|
7517
|
+
return '0';
|
|
7518
|
+
};
|
|
7519
|
+
// ...existing code...
|
|
7520
|
+
// ...existing code...
|
|
7521
|
+
// Helper: show spinner if loading/connecting
|
|
7522
|
+
// Show spinner if initializing, connecting, or balance is loading
|
|
7523
|
+
const showSpinner = Boolean(isInitializing || isConnecting || balanceLoading);
|
|
7684
7524
|
// Detect dark mode
|
|
7685
7525
|
const [isDarkMode, setIsDarkMode] = React.useState(false);
|
|
7686
7526
|
React.useEffect(() => {
|
|
@@ -7698,7 +7538,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7698
7538
|
}, [theme]);
|
|
7699
7539
|
const [account, setAccount] = React.useState(null);
|
|
7700
7540
|
const [status, setStatus] = React.useState(exports.ConnectionStatus.DISCONNECTED);
|
|
7701
|
-
const [isInitializing, setIsInitializing] = React.useState(true);
|
|
7702
7541
|
const [showModal, setShowModal] = React.useState(false);
|
|
7703
7542
|
// Preload Reown SDK when modal opens for faster connection
|
|
7704
7543
|
React.useEffect(() => {
|
|
@@ -7720,7 +7559,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7720
7559
|
const [showActivityModal, setShowActivityModal] = React.useState(false);
|
|
7721
7560
|
const [showTWCBalanceModal, setShowTWCBalanceModal] = React.useState(false);
|
|
7722
7561
|
const [availableWallets, setAvailableWallets] = React.useState([]);
|
|
7723
|
-
const [isConnecting, setIsConnecting] = React.useState(false);
|
|
7724
7562
|
const [error, setError] = React.useState(null);
|
|
7725
7563
|
const [nftCount, setNftCount] = React.useState(0);
|
|
7726
7564
|
const [nftLoading, setNftLoading] = React.useState(false);
|
|
@@ -7731,7 +7569,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7731
7569
|
const [txsLoading, setTxsLoading] = React.useState(false);
|
|
7732
7570
|
const [txsError, setTxsError] = React.useState(null);
|
|
7733
7571
|
const [balance, setBalance] = React.useState({ amount: '', symbol: '' });
|
|
7734
|
-
const [balanceLoading, setBalanceLoading] = React.useState(false);
|
|
7735
7572
|
const [currentChainId, setCurrentChainId] = React.useState(null);
|
|
7736
7573
|
const [isWrongNetwork, setIsWrongNetwork] = React.useState(false);
|
|
7737
7574
|
// TWC Balance cache key prefix
|
|
@@ -8909,8 +8746,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8909
8746
|
}, [connector, account]);
|
|
8910
8747
|
// Render button based on connection status
|
|
8911
8748
|
const renderButton = () => {
|
|
8912
|
-
//
|
|
8913
|
-
if (!
|
|
8749
|
+
// Always show connect button for first-time visitors or when not connected
|
|
8750
|
+
if (!account && status === exports.ConnectionStatus.DISCONNECTED) {
|
|
8914
8751
|
// Wallet icon SVG component
|
|
8915
8752
|
const WalletIcon = () => (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block' }, children: [jsxRuntime.jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }), jsxRuntime.jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })] }));
|
|
8916
8753
|
return (jsxRuntime.jsxs("button", { onClick: () => handleOpenModal(), style: {
|
|
@@ -9084,34 +8921,75 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
9084
8921
|
}
|
|
9085
8922
|
// Wallet icon SVG component
|
|
9086
8923
|
const WalletIcon = () => (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block' }, children: [jsxRuntime.jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }), jsxRuntime.jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })] }));
|
|
9087
|
-
//
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
8924
|
+
// Always show the button, but change content based on connection state
|
|
8925
|
+
const displayBalance = getDisplayBalance();
|
|
8926
|
+
const isConnected = !!account && status === exports.ConnectionStatus.CONNECTED;
|
|
8927
|
+
// Helper for details modal open
|
|
8928
|
+
const handleOpenDetailsModal = () => setShowDetailsModal(true);
|
|
8929
|
+
// Wallet icon for display
|
|
8930
|
+
const walletIcon = account ? getWalletIcon(connector.getState().wallet || '') : jsxRuntime.jsx("span", { children: "\uD83D\uDCBC" });
|
|
8931
|
+
// Current wallet type
|
|
8932
|
+
const currentWalletType = connector.getState().wallet;
|
|
8933
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("style", { children: `
|
|
8934
|
+
@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap');
|
|
8935
|
+
.tiwiflix-scrollbar-hide::-webkit-scrollbar {
|
|
8936
|
+
display: none;
|
|
8937
|
+
}
|
|
8938
|
+
.twc-balance-spinner {
|
|
8939
|
+
display: inline-block;
|
|
8940
|
+
width: 16px;
|
|
8941
|
+
height: 16px;
|
|
8942
|
+
border: 2px solid #FF9814;
|
|
8943
|
+
border-top: 2px solid #fff;
|
|
8944
|
+
border-radius: 50%;
|
|
8945
|
+
animation: spin 0.7s linear infinite;
|
|
8946
|
+
margin-left: 6px;
|
|
8947
|
+
vertical-align: middle;
|
|
8948
|
+
}
|
|
8949
|
+
@keyframes spin {
|
|
8950
|
+
0% { transform: rotate(0deg); }
|
|
8951
|
+
100% { transform: rotate(360deg); }
|
|
8952
|
+
}
|
|
8953
|
+
` }), jsxRuntime.jsxs("button", { onClick: () => (isConnected ? handleOpenDetailsModal() : handleOpenModal()), style: {
|
|
8954
|
+
display: 'flex',
|
|
8955
|
+
alignItems: 'center',
|
|
8956
|
+
gap: '10px',
|
|
8957
|
+
padding: '12px 12px',
|
|
8958
|
+
borderRadius: '12px',
|
|
8959
|
+
border: 'none',
|
|
8960
|
+
backgroundColor: isConnected ? '#0A0A0A' : '#FF9814',
|
|
8961
|
+
color: isConnected ? '#FF9814' : '#000000',
|
|
8962
|
+
fontWeight: '700',
|
|
8963
|
+
fontSize: '15px',
|
|
8964
|
+
cursor: showSpinner ? 'wait' : 'pointer',
|
|
8965
|
+
transition: 'all 0.15s ease',
|
|
8966
|
+
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
8967
|
+
boxShadow: isConnected ? '0 2px 8px rgba(10,10,10,0.3)' : '0 2px 8px rgba(255, 152, 20, 0.3)',
|
|
8968
|
+
opacity: showSpinner ? 0.85 : 1,
|
|
8969
|
+
pointerEvents: showSpinner ? 'none' : 'auto',
|
|
8970
|
+
...style,
|
|
8971
|
+
}, className: className, disabled: showSpinner, onMouseEnter: (e) => {
|
|
8972
|
+
if (!isConnected) {
|
|
8973
|
+
e.currentTarget.style.backgroundColor = '#E8870F';
|
|
8974
|
+
e.currentTarget.style.transform = 'translateY(-1px)';
|
|
8975
|
+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(255, 152, 20, 0.4)';
|
|
8976
|
+
}
|
|
8977
|
+
}, onMouseLeave: (e) => {
|
|
8978
|
+
if (!isConnected) {
|
|
8979
|
+
e.currentTarget.style.backgroundColor = '#FF9814';
|
|
8980
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
8981
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(255, 152, 20, 0.3)';
|
|
8982
|
+
}
|
|
8983
|
+
}, children: [jsxRuntime.jsx("span", { style: { color: isConnected ? '#FF9814' : '#000000', display: 'flex', alignItems: 'center' }, children: jsxRuntime.jsx(WalletIcon, {}) }), jsxRuntime.jsx("span", { style: { color: isConnected ? '#FF9814' : '#000000', fontWeight: '500', fontSize: '14px' }, children: isConnected ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [twcIconMemoized, jsxRuntime.jsx("span", { style: { marginLeft: 6, fontWeight: 600, fontFamily: 'SF Mono, Monaco, Inconsolata, Roboto Mono, monospace' }, children: displayBalance }), showSpinner && jsxRuntime.jsx("span", { className: "twc-balance-spinner" })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [buttonText, showSpinner && jsxRuntime.jsx("span", { className: "twc-balance-spinner" })] })) })] }), jsxRuntime.jsx(AccountDetailsModal, { isOpen: showDetailsModal, onClose: () => setShowDetailsModal(false), account: account, onDisconnect: handleDisconnect, onCopyAddress: handleCopyAddress, onOpenSwap: () => setShowSwapModal(true), onOpenSend: () => setShowSendModal(true), onOpenActivity: () => setShowActivityModal(true), balance: balance, balanceLoading: balanceLoading, twcBalance: twcBalance, usdValue: usdValue, nftCount: nftCount, nftLoading: nftLoading, tonBalance: balance.amount || tonBalance, tonUsdValue: balance.usdValue ?? tonUsdValue, walletIcon: walletIcon, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition,
|
|
8984
|
+
// Add a Switch Wallet button to allow explicit wallet switching
|
|
8985
|
+
onSwitchWallet: () => handleOpenModal(true) }), jsxRuntime.jsx(ActivityModal, { isOpen: showActivityModal, onClose: () => setShowActivityModal(false), transactions: txs, loading: txsLoading, error: txsError, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsxRuntime.jsx(SwapModal, { isOpen: showSwapModal && account?.chainType !== 'ton', onClose: () => setShowSwapModal(false), colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsxRuntime.jsx(SendModal, { isOpen: showSendModal, onClose: () => setShowSendModal(false), balance: balance, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onSend: async () => {
|
|
8986
|
+
alert('Send functionality coming soon');
|
|
8987
|
+
setShowSendModal(false);
|
|
8988
|
+
} }), jsxRuntime.jsx(TWCBalanceModal, { isOpen: showTWCBalanceModal, onClose: () => setShowTWCBalanceModal(false), twcBalance: twcBalance, usdValue: usdValue, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onBuyTWC: () => {
|
|
8989
|
+
// Handle Buy TWC action
|
|
8990
|
+
}, onLearnMore: () => {
|
|
8991
|
+
// Handle Learn More action
|
|
8992
|
+
} }), jsxRuntime.jsx(WalletSelectModal, { isOpen: showModal, onClose: () => setShowModal(false), onSelectWallet: handleConnect, availableWallets: availableWallets, currentWalletType: currentWalletType, isConnecting: isConnecting, error: error, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition })] }));
|
|
9115
8993
|
};
|
|
9116
8994
|
// Group wallets by chain
|
|
9117
8995
|
availableWallets.reduce((acc, wallet) => {
|
package/package.json
CHANGED