Skip to content

Commit

Permalink
Fix UI issues
Browse files Browse the repository at this point in the history
- Fix explorer URL
- Fix token balance display
- Fix refresh balance when switching account
- Fix deploy success page
- Fix mint success page
  • Loading branch information
impredmet committed Feb 14, 2025
1 parent cbae62c commit e145568
Show file tree
Hide file tree
Showing 8 changed files with 21,834 additions and 15,450 deletions.
11 changes: 0 additions & 11 deletions src/shared/constant/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@


/* constants pool */
import { AddressType, NetworkType, RestoreWalletType } from '../types';


export enum CHAINS_ENUM {
BTC = 'BTC'
}
Expand Down Expand Up @@ -208,7 +205,6 @@ interface TypeChain<T extends ChainType> {
mempoolSpaceUrl: string;
unisatUrl: string;
ordinalsUrl: string;
unisatExplorerUrl: string;
faucetUrl: string;
okxExplorerUrl: string;
isViewTxHistoryInternally?: boolean;
Expand All @@ -231,7 +227,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
unisatUrl: 'https://unisat.io',
ordinalsUrl: 'https://ordinals.com',
faucetUrl: '',
unisatExplorerUrl: '',
okxExplorerUrl: '',
disable: true,
showPrice: true,
Expand All @@ -249,7 +244,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
unisatUrl: 'https://testnet.unisat.io',
ordinalsUrl: 'https://testnet.ordinals.com',
faucetUrl: '',
unisatExplorerUrl: '',
okxExplorerUrl: '',
disable: true,
showPrice: false,
Expand All @@ -267,7 +261,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
unisatUrl: 'https://testnet4.unisat.io',
ordinalsUrl: 'https://testnet4.ordinals.com',
faucetUrl: '',
unisatExplorerUrl: '',
okxExplorerUrl: '',
disable: true,
showPrice: false,
Expand All @@ -285,7 +278,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
unisatUrl: 'https://unisat.io',
ordinalsUrl: 'https://ordinals.com',
faucetUrl: 'https://faucet.opnet.org/',
unisatExplorerUrl: '',
okxExplorerUrl: '',
showPrice: false,
defaultExplorer: 'mempool-space'
Expand All @@ -302,7 +294,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
unisatUrl: 'https://signet.unisat.io',
ordinalsUrl: 'https://signet.ordinals.com',
faucetUrl: '',
unisatExplorerUrl: '',
okxExplorerUrl: '',
disable: true,
showPrice: false,
Expand All @@ -319,7 +310,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
mempoolSpaceUrl: 'https://mempool.fractalbitcoin.io',
unisatUrl: 'https://fractal.unisat.io',
ordinalsUrl: 'https://ordinals.fractalbitcoin.io',
unisatExplorerUrl: 'https://explorer.unisat.io/fractal-mainnet',
faucetUrl: '',
okxExplorerUrl: '',
isViewTxHistoryInternally: false,
Expand All @@ -339,7 +329,6 @@ export const CHAINS_MAP: { [key in ChainType]: TypeChain<key> } = {
mempoolSpaceUrl: 'https://fractal-mempool.opnet.org',
unisatUrl: 'https://fractal-testnet.unisat.io',
ordinalsUrl: 'https://ordinals-testnet.fractalbitcoin.io',
unisatExplorerUrl: 'https://explorer.unisat.io/fractal-testnet',
faucetUrl: 'https://fractal-faucet.opnet.org/',
okxExplorerUrl: '',
isViewTxHistoryInternally: true,
Expand Down
53 changes: 38 additions & 15 deletions src/ui/components/OpNetBalanceCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,60 @@
import BigNumber from 'bignumber.js';

import { OPTokenInfo } from '@/shared/types';
import { bigIntToDecimal } from '@/shared/web3/Web3API';
import { fontSizes } from '@/ui/theme/font';
import BigNumber from 'bignumber.js';

import { faTrashCan } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Card } from '../Card';
import { Column } from '../Column';
import { Image } from '../Image';
import { Row } from '../Row';
import { RunesTicker } from '../RunesTicker';
import { Text } from '../Text';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTrashCan } from '@fortawesome/free-solid-svg-icons';

export interface OpNetBalanceCardProps {
tokenInfo: OPTokenInfo;
onClick?: () => void;
handleRemoveToken: (address: string) => void;
}

function formatTruncated(bn: BigNumber, sigDigits = 3): string {
if (bn.isZero()) return '0';

if (bn.isGreaterThanOrEqualTo(1)) {
return bn.decimalPlaces(sigDigits, BigNumber.ROUND_DOWN).toFixed(sigDigits);
} else {
let fixed = bn.toFixed(20);
fixed = fixed.replace(/0+$/, '');
const parts = fixed.split('.');
if (parts.length < 2) return fixed;
const decimals = parts[1];
const leadingZerosMatch = decimals.match(/^0*/);
const zerosCount = leadingZerosMatch ? leadingZerosMatch[0].length : 0;
const requiredDecimals = zerosCount + sigDigits;
let result = bn.decimalPlaces(requiredDecimals, BigNumber.ROUND_DOWN).toFixed(requiredDecimals);
result = result.replace(/(\.\d*?[1-9])0+$/, '$1').replace(/\.$/, '');
return result;
}
}

function formatBalance(balance: BigNumber, sigDigits = 3): string {
const units = ['', 'K', 'M', 'B', 'T'];
let unitIndex = 0;
let value = new BigNumber(balance);
while (value.isGreaterThanOrEqualTo(1000) && unitIndex < units.length - 1) {
value = value.dividedBy(1000);
unitIndex++;
}
const formatted = formatTruncated(value, sigDigits);
return formatted + units[unitIndex];
}

export default function OpNetBalanceCard(props: OpNetBalanceCardProps) {
const { tokenInfo, handleRemoveToken, onClick } = props;
const balance = new BigNumber(bigIntToDecimal(tokenInfo.amount, tokenInfo.divisibility)); //runesUtils.toDecimalNumber(tokenBalance.amount, tokenBalance.divisibility);
const truncatedBalance = Math.floor(Number(balance) * 1e5) / 1e5;
const str =
Number(balance) > 0
? truncatedBalance.toLocaleString('en-US', { minimumFractionDigits: 5, maximumFractionDigits: 5 })
: '0';
const balance = new BigNumber(bigIntToDecimal(tokenInfo.amount, tokenInfo.divisibility));

let finalBal = str.slice(0, 16);
if (finalBal !== str) {
finalBal += '...';
}
const finalBal = formatBalance(balance, 3);

return (
<Card
Expand Down Expand Up @@ -67,7 +90,7 @@ export default function OpNetBalanceCard(props: OpNetBalanceCardProps) {
handleRemoveToken(tokenInfo.address);
}}
icon={faTrashCan}
style={{ height: '1rem', cursor: 'pointer', zIndex: '100000' }}
style={{ height: '1rem', cursor: 'pointer' }}
/>
</Card>
);
Expand Down
157 changes: 76 additions & 81 deletions src/ui/pages/Main/WalletTabScreen/OPNetList.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
import BigNumber from 'bignumber.js';
import { CloseOutlined, LoadingOutlined } from '@ant-design/icons';
import { Modal } from 'antd';
import BigNumber from 'bignumber.js';
import { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
import browser from 'webextension-polyfill';

import { getContract, IOP_20Contract, OP_20_ABI } from 'opnet';
import Web3API, { getOPNetChainType, getOPNetNetwork } from '@/shared/web3/Web3API';
import { getContract, IOP_20Contract, OP_20_ABI } from 'opnet';

import { ChainType } from '@/shared/constant';
import { NetworkType, OPTokenInfo } from '@/shared/types';
import { ContractInformation } from '@/shared/web3/interfaces/ContractInformation';
import { Address, OPNetMetadata } from '@btc-vision/transaction';

import { Button, Column, Row, Text } from '@/ui/components';
import { useTools } from '@/ui/components/ActionComponent';
import { BaseView } from '@/ui/components/BaseView';
import { Button, Column, Row, Text } from '@/ui/components';
import OpNetBalanceCard from '@/ui/components/OpNetBalanceCard';
import { useCurrentAccount } from '@/ui/state/accounts/hooks';
import { useChainType } from '@/ui/state/settings/hooks';
Expand Down Expand Up @@ -159,78 +159,71 @@ export function OPNetList() {
* Fetch the balances for the current page of tokens.
* If forceRefresh = true, skip the cache for these tokens and re-fetch from chain.
*/
const fetchTokenBalances = useCallback(
async (forceRefresh = false) => {
if (skipBalancesRef.current) return;
if (!tokens.length) {
setTokenBalances([]);
return;
}

try {
tools.showLoading(true);

const startIndex = (currentPage - 1) * TOKENS_PER_PAGE;
const endIndex = Math.min(startIndex + TOKENS_PER_PAGE, tokens.length);
const currentTokens = tokens.slice(startIndex, endIndex);
const fetchTokenBalances = useCallback(async () => {
if (skipBalancesRef.current) return;
if (!tokens.length) {
setTokenBalances([]);
return;
}

const balances = await Promise.all(
currentTokens.map(async (tokenAddress) => {
// If we have cache and not force-refreshing, use cached info
if (balanceCache.has(tokenAddress) && !forceRefresh) {
return balanceCache.get(tokenAddress) as OPTokenInfo;
}
try {
tools.showLoading(true);

try {
const contractInfo: ContractInformation | OPTokenInfo | false | undefined =
balanceCache.get(tokenAddress)
? balanceCache.get(tokenAddress)
: await Web3API.queryContractInformation(tokenAddress);
const startIndex = (currentPage - 1) * TOKENS_PER_PAGE;
const endIndex = Math.min(startIndex + TOKENS_PER_PAGE, tokens.length);
const currentTokens = tokens.slice(startIndex, endIndex);

if (!contractInfo || contractInfo.name === 'Generic Contract') {
setFailedTokens((prev) => [...prev, tokenAddress]);
return null;
}
const balances = await Promise.all(
currentTokens.map(async (tokenAddress) => {
try {
const contractInfo: ContractInformation | OPTokenInfo | false | undefined = balanceCache.get(
tokenAddress
)
? balanceCache.get(tokenAddress)
: await Web3API.queryContractInformation(tokenAddress);

const contract: IOP_20Contract = getContract<IOP_20Contract>(
tokenAddress,
OP_20_ABI,
Web3API.provider,
Web3API.network
);

const balance = await contract.balanceOf(Address.fromString(currentAccount.pubkey));
const tokenDetails: OPTokenInfo = {
address: tokenAddress,
name: contractInfo?.name || '',
amount: balance.properties.balance,
divisibility:
'divisibility' in contractInfo
? contractInfo.divisibility
: contractInfo?.decimals || 8,
symbol: contractInfo.symbol,
logo: contractInfo?.logo
};

balanceCache.set(tokenAddress, tokenDetails);
return tokenDetails;
} catch (err) {
console.error('Error fetching balance:', tokenAddress, err);
if (!contractInfo || contractInfo.name === 'Generic Contract') {
setFailedTokens((prev) => [...prev, tokenAddress]);
return null;
}
})
);

setTokenBalances(balances.filter(Boolean) as OPTokenInfo[]);
} catch (err) {
tools.toastError(`Failed to load token balances: ${(err as Error).message}`);
} finally {
tools.showLoading(false);
}
},
[currentAccount, currentPage, tokens, tools]
);
const contract: IOP_20Contract = getContract<IOP_20Contract>(
tokenAddress,
OP_20_ABI,
Web3API.provider,
Web3API.network
);

const balance = await contract.balanceOf(Address.fromString(currentAccount.pubkey));
const tokenDetails: OPTokenInfo = {
address: tokenAddress,
name: contractInfo?.name || '',
amount: balance.properties.balance,
divisibility:
'divisibility' in contractInfo
? contractInfo.divisibility
: contractInfo?.decimals || 8,
symbol: contractInfo.symbol,
logo: contractInfo?.logo
};

balanceCache.set(tokenAddress, tokenDetails);
return tokenDetails;
} catch (err) {
console.error('Error fetching balance:', tokenAddress, err);
setFailedTokens((prev) => [...prev, tokenAddress]);
return null;
}
})
);

setTokenBalances(balances.filter(Boolean) as OPTokenInfo[]);
} catch (err) {
tools.toastError(`Failed to load token balances: ${(err as Error).message}`);
} finally {
tools.showLoading(false);
}
}, [currentAccount, currentPage, tokens, tools]);

// Fetch tokens once on mount (and whenever importTokenBool changes),
// not every time tokens state changes
Expand All @@ -240,8 +233,8 @@ export function OPNetList() {

// Fetch balances whenever tokens or page changes, unless skipping
useEffect(() => {
void fetchTokenBalances();
}, [fetchTokenBalances, tokens, currentPage]);
fetchTokenBalances();
}, [fetchTokenBalances, tokens, currentPage, currentAccount]);

// If new failures appear, display them one by one
useEffect(() => {
Expand Down Expand Up @@ -475,7 +468,7 @@ export function OPNetList() {
icon="history"
// ----- IMPORTANT CHANGE: ONLY REFRESH BALANCES -----
onClick={() => {
fetchTokenBalances(true).catch((err: unknown) => console.error(err));
fetchTokenBalances().catch((err: unknown) => console.error(err));
}}
/>
<Button
Expand Down Expand Up @@ -563,19 +556,21 @@ export function OPNetList() {
disabled={currentPage === totalPages}
/>
</Row>

{/* Show Hidden Tokens */}
<Row style={{ marginTop: '12px' }}>
<Button
style={{ width: '100%', fontSize: '10px' }}
text="Show Hidden Tokens"
preset="fontsmall"
onClick={showHiddenTokens}
/>
</Row>
</BaseView>
)}

<BaseView style={$opnet}>
{/* Show Hidden Tokens */}
<Row style={{ marginTop: '12px' }}>
<Button
style={{ width: '100%', fontSize: '10px' }}
text="Show Hidden Tokens"
preset="fontsmall"
onClick={showHiddenTokens}
/>
</Row>
</BaseView>

{/* Import Token Modal */}
{importTokenBool && (
<AddOpNetToken
Expand Down
Loading

0 comments on commit e145568

Please sign in to comment.