diff --git a/.env b/.env index c5e3bd1bb..78d5ac8dd 100644 --- a/.env +++ b/.env @@ -1,7 +1,6 @@ # NEXT_PUBLIC_NETWORK_NAME=mainnet # NEXT_PUBLIC_NETWORK_NAME=testnet # NEXT_PUBLIC_NETWORK_NAME=devnet -# NEXT_PUBLIC_NETWORK_NAME=alphanet # NEXT_PUBLIC_NETWORK_NAME=xahau # NEXT_PUBLIC_NETWORK_NAME=xahau-testnet # NEXT_PUBLIC_NETWORK_NAME=xahau-jshooks diff --git a/README.md b/README.md index 7d1997d6a..6d33f9e25 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ In the project directory, you can run: `NEXT_PUBLIC_NETWORK_NAME=mainnet yarn dev` -mainnet | staging | testnet | devnet | alphanet | xahau | xahau-testnet | xahau-jshooks +mainnet | staging | testnet | devnet | xahau | xahau-testnet | xahau-jshooks Runs the app in the development mode.\ Open [http://localhost:3000](http://localhost:3000) to view it in your browser. @@ -64,7 +64,7 @@ Runs the app in production `yarn build` -`PORT=3300 pm2 start /usr/bin/yarn --name alphanet-frontend-react -- start` // from inside the frontend-react directory +`pm2 start yarn --name "frontend-react" -- start` // otherwise: `-- start:next` or `PORT=3400 pm2 start /usr/bin/yarn --name "jshooks.xahau-frontend-react" -- start` `pm2 logs frontend-react --lines 1000` //verify it runs properly diff --git a/components/Account/AccountWithTag.js b/components/Account/AccountWithTag.js deleted file mode 100644 index 9f6bdbc3f..000000000 --- a/components/Account/AccountWithTag.js +++ /dev/null @@ -1,242 +0,0 @@ -import { useTranslation } from 'next-i18next' -import { useState, useEffect } from 'react' -import axios from 'axios' -import SEO from '../SEO' -import SearchBlock from '../Layout/SearchBlock' -import { - FaFacebook, - FaInstagram, - FaLinkedin, - FaMedium, - FaReddit, - FaTelegram, - FaYoutube, - FaXTwitter -} from 'react-icons/fa6' -import { accountWithTag } from '../../styles/components/Account/AccountWithTag.module.scss' - -export default function AccountWithTag({ data }) { - const { t } = useTranslation() - const [accountData, setAccountData] = useState(null) - const [loading, setLoading] = useState(true) - const [errorMessage, setErrorMessage] = useState(null) - const [address, setAddress] = useState(null) - const [tag, setTag] = useState(null) - - useEffect(() => { - const fetchData = async () => { - if (!data) return - const address = data.address - setTag(data.tag) - setAddress(data.address) - setLoading(true) - setErrorMessage(null) - try { - const response = await axios( - '/v2/address/' + address + '?username=true&service=true&verifiedDomain=true&bithomp=true' - ) - const accountData = response?.data - if (accountData?.error) { - setErrorMessage(accountData.error) - setLoading(false) - return - } - if (accountData?.address) { - setAccountData(accountData) - } else { - setErrorMessage('Failed to resolve address') - } - } catch (error) { - setErrorMessage(error?.message || 'Failed to load account data') - } finally { - setLoading(false) - } - } - fetchData() - }, [data]) - - // Function to render social links dynamically based on account data - const renderSocialLinks = (socialAccounts) => { - if (!socialAccounts) return null - - return ( -
- {socialAccounts.twitter && ( - - - - )} - {socialAccounts.youtube && ( - - - - )} - {socialAccounts.linkedin && ( - - - - )} - {socialAccounts.instagram && ( - - - - )} - {socialAccounts.telegram && ( - - - - )} - {socialAccounts.facebook && ( - - - - )} - {socialAccounts.medium && ( - - - - )} - {socialAccounts.reddit && ( - - - - )} -
- ) - } - - if (loading) { - return ( - <> - - -
-
- -
- {t('general.loading')} -
-
- - ) - } - - if (errorMessage) { - return ( - <> - - -
-
- {errorMessage} -
-
- - ) - } - - if (!address || !accountData) { - return ( - <> - - -
-
- Invalid address or missing data -
-
- - ) - } - - return ( -
- - - {/* add tab="account" to show transactions link */} - -
-
-
{data?.payId ? 'PAYSTRING ' : 'X-ADDRESS'} DETAILS
- -
- {data.xAddress} -
- -
- This address belongs to{' '} - - {accountData?.service?.domain} - {' '} - ({accountData?.service?.name}). -
- - {accountData?.bithomp?.avatar && ( -
- {accountData.bithomp.name} -
- )} - - {renderSocialLinks(accountData?.service?.socialAccounts)} - - {data?.payId && ( -
-
- PayString: -
-
{data.payId}
-
- )} - -
-
- Service address: -
- -
- {tag && ( -
-
- User destination tag: -
-
{tag}
-
- )} -
-
-
- ) -} diff --git a/components/Account/DexOrdersData.js b/components/Account/DexOrdersData.js index 06d100978..3732cb054 100644 --- a/components/Account/DexOrdersData.js +++ b/components/Account/DexOrdersData.js @@ -65,11 +65,11 @@ export default function DexOrdersData({ account, offerList, ledgerTimestamp, set {sell ? 'Selling ' : 'Buying '} - {amountFormat(sell ? offer.TakerGets : offer.TakerPays, { short: true, icon: true })} + {amountFormat(sell ? offer.TakerGets : offer.TakerPays, { precise: 'nice', icon: true })} {' for '} - {amountFormat(sell ? offer.TakerPays : offer.TakerGets, { short: true, icon: true })} + {amountFormat(sell ? offer.TakerPays : offer.TakerGets, { precise: 'nice', icon: true })} {sell ? ( @@ -210,7 +210,7 @@ export default function DexOrdersData({ account, offerList, ledgerTimestamp, set The last 5 DEX orders{historicalTitle} [ View all ({offerList.length} total) - + {' '} ] ) : ( @@ -224,7 +224,7 @@ export default function DexOrdersData({ account, offerList, ledgerTimestamp, set )}
- +
diff --git a/components/Account/EscrowData.js b/components/Account/EscrowData.js index 1f82f23f4..a3d6fe785 100644 --- a/components/Account/EscrowData.js +++ b/components/Account/EscrowData.js @@ -179,7 +179,7 @@ export default function EscrowData({ setSignRequest, address, escrowList, ledger {historicalTitle}
-
#
+
{escrowListNode(receivedEscrowList, { type: 'received', mobile: true })}
@@ -205,7 +205,7 @@ export default function EscrowData({ setSignRequest, address, escrowList, ledger {historicalTitle}
- +
{escrowListNode(sentEscrowList, { type: 'sent', mobile: true })}
@@ -231,7 +231,7 @@ export default function EscrowData({ setSignRequest, address, escrowList, ledger {historicalTitle}
- +
{escrowListNode(selfEscrowList, { type: 'self', mobile: true })}
diff --git a/components/Account/IOUData.js b/components/Account/IOUData.js index 16c5fbfaf..d91f6fb3c 100644 --- a/components/Account/IOUData.js +++ b/components/Account/IOUData.js @@ -4,7 +4,7 @@ import { shortNiceNumber, amountFormat, fullNiceNumber, - CurrencyWithIcon + AddressWithIconFilled } from '../../utils/format' import { objectsCountText, useWidth } from '../../utils' import { FaSnowflake, FaLock, FaIcicles, FaShieldAlt, FaInfoCircle } from 'react-icons/fa' @@ -246,7 +246,12 @@ export default function IOUData({ {i + 1} - + {type === 'lp' ? ( @@ -414,7 +419,7 @@ export default function IOUData({
) : ( - {tokenTbody(list, type)}
+ {tokenTbody(list, type)}
)}
diff --git a/components/Account/IssuedTokensData.js b/components/Account/IssuedTokensData.js index 696587d75..6a29b3403 100644 --- a/components/Account/IssuedTokensData.js +++ b/components/Account/IssuedTokensData.js @@ -5,9 +5,9 @@ import { fullDateAndTime, shortNiceNumber, fullNiceNumber, + CurrencyWithIcon, niceCurrency, - niceNumber, - CurrencyWithIcon + niceNumber } from '../../utils/format' import { nativeCurrency } from '../../utils' @@ -74,7 +74,8 @@ export default function IssuedTokensData({ data, selectedCurrency, pageFiatRate {mobile ? ( - + +
Price: {fullNiceNumber(stats.priceNativeCurrency * pageFiatRate, selectedCurrency)}
@@ -102,7 +103,7 @@ export default function IssuedTokensData({ data, selectedCurrency, pageFiatRate ) : ( <> - + @@ -246,7 +247,7 @@ export default function IssuedTokensData({ data, selectedCurrency, pageFiatRate ) : error ? (
{error}
) : issuedTokens.length > 0 ? ( - +
diff --git a/components/Account/LedgerData.js b/components/Account/LedgerData.js index d2001663f..5b87d0cf3 100644 --- a/components/Account/LedgerData.js +++ b/components/Account/LedgerData.js @@ -15,7 +15,7 @@ import { import { devNet, getCoinsUrl, isDomainValid, nativeCurrency, stripDomain, xahauNetwork } from '../../utils' import CopyButton from '../UI/CopyButton' -import { LinkAmm, LinkObject, LinkTx } from '../../utils/links' +import { LinkAmm, LinkTx } from '../../utils/links' import { MdDeleteForever, MdVerified } from 'react-icons/md' import { FiEdit } from 'react-icons/fi' @@ -405,17 +405,13 @@ export default function LedgerData({ ) : account?.address === data?.address ? ( <> - You don't have any NFTs. You can [Mint NFT] or [ - Buy NFT]. + You don't have any NFTs. You can Mint NFT or + Buy NFT ) : ( "This account doesn't hold NFTs." ) - const showObjectSection = (objects) => { - return !objects || objects?.length > 0 || account?.address === data?.address - } - const dexOrdersNode = !objects?.offerList ? ( 'Loading...' ) : objects?.offerList?.length > 0 ? ( @@ -450,27 +446,6 @@ export default function LedgerData({ "This account doesn't have Escrows." ) - let noObjectsNode = '' - if (account?.address !== data?.address) { - const missing = [] - - if (objects?.rippleStateList?.length === 0) missing.push('Tokens') - if (objects?.nftList?.length === 0) missing.push('NFTs') - if (objects?.escrowList?.length === 0) missing.push('Escrows') - if (objects?.offerList?.length === 0) missing.push('DEX orders') - if (objects?.mptList?.length === 0 && objects?.mptIssuanceList?.length === 0) missing.push('Multi Purpose Tokens') - - if (missing.length > 0) { - noObjectsNode = {`This account doesn't have ${missing.join(', ')}.`} - } - } - - let cronNode = null - - if (xahauNetwork && data?.ledgerInfo?.cron) { - cronNode = - } - return ( <>
#
@@ -514,36 +489,26 @@ export default function LedgerData({ )} {data?.ledgerInfo?.activated && !gateway && ( <> - {showObjectSection(objects?.rippleStateList) && ( - - - - - )} - {showObjectSection(objects?.mptList) && ( - - - - - )} - {showObjectSection(objects?.nftList) && ( - - - - - )} - {showObjectSection(objects?.offerList) && ( - - - - - )} - {showObjectSection(objects?.escrowList) && ( - - - - - )} + + + + + + + + + + + + + + + + + + + + )} {data.ledgerInfo?.domain && ( @@ -591,12 +556,6 @@ export default function LedgerData({ )} - {data.ledgerInfo?.cron && ( - - - - - )} ) : ( <> @@ -794,11 +753,6 @@ export default function LedgerData({ ))} )} - {noObjectsNode && ( - - - - )}
{t('menu.tokens')}{tokensNode}
MP Tokens{mptNode}
NFTs{nftNode}
DEX orders{dexOrdersNode}
Escrows{escrowNode}
{t('menu.tokens')}{tokensNode}
MP Tokens{mptNode}
NFTs{nftNode}
DEX orders{dexOrdersNode}
Escrows{escrowNode}
{data.ledgerInfo?.hookStateCount}
Cron{cronNode}
{noObjectsNode}
@@ -830,34 +784,25 @@ export default function LedgerData({

)} - {data?.ledgerInfo?.activated && !gateway && ( + {data?.ledgerInfo?.activated && ( <> - {showObjectSection(objects?.rippleStateList) && ( -

- {objects?.rippleStateList?.length > 0 && {t('explorer.menu.tokens')}}{' '} - {tokensNode} -

- )} - {showObjectSection(objects?.nftList) && ( -

- {objects?.nftList?.length > 0 && NFTs} {nftNode} -

- )} - {showObjectSection(objects?.offerList) && ( -

- {objects?.offerList?.length > 0 && DEX orders} {dexOrdersNode} -

- )} - {showObjectSection(objects?.escrowList) && ( -

- {objects?.escrowList?.length > 0 && Escrows} {escrowNode} -

- )} - {showObjectSection(objects?.mptList) && ( -

- {objects?.mptList?.length > 0 && MP Tokens} {mptNode} -

- )} +

+ {objects?.rippleStateList?.length > 0 && ( + <> + {t('explorer.menu.tokens')}{' '} + + )} + {tokensNode} +

+

+ {objects?.mptList?.length > 0 && MP Tokens} {mptNode} +

+

+ {objects?.offerList?.length > 0 && DEX orders} {dexOrdersNode} +

+

+ {objects?.escrowList?.length > 0 && Escrows} {escrowNode} +

)} {data.ledgerInfo?.domain && ( @@ -902,11 +847,6 @@ export default function LedgerData({ Hook state count {data.ledgerInfo?.hookStateCount}

)} - {data.ledgerInfo?.cron && ( -

- Cron {cronNode} -

- )} ) : ( <> @@ -1078,7 +1018,6 @@ export default function LedgerData({ ))} )} - {noObjectsNode &&

{noObjectsNode}

}
) diff --git a/components/Account/MPTData.js b/components/Account/MPTData.js index 5b250415d..aed51f0a9 100644 --- a/components/Account/MPTData.js +++ b/components/Account/MPTData.js @@ -1,8 +1,45 @@ import { objectsCountText } from '../../utils' import { scaleAmount } from '../../utils/calc' -import { CurrencyWithIcon, fullDateAndTime, shortNiceNumber } from '../../utils/format' +import { AddressWithIconFilled, fullDateAndTime, shortNiceNumber } from '../../utils/format' import CopyButton from '../UI/CopyButton' +const mptCurrency = (data) => { + if (!data) return 'N/A' + let meta = data.metadata + // MPT tokens + if (data.mptokenCurrencyDetails) { + const details = data.mptokenCurrencyDetails + if (details.currency) return details.currency + if (!meta) meta = details.metadata + } + // Issued mpttokens + if (meta) { + return meta.currency || meta.c || 'N/A' + } + return 'N/A' +} + +const mptName = (data) => { + if (!data) return 'N/A' + // Issued mpttokens + let meta = data.metadata + // MPT tokens + if (!meta && data.mptokenCurrencyDetails) { + meta = data.mptokenCurrencyDetails.metadata + } + + if (!meta) return 'N/A' + return meta.name || meta.n || 'N/A' +} + +const issuerDetails = (data) => { + if (!data) return null + return { + issuer: data.mptokenCurrencyDetails?.account || data.Issuer || null, + issuerDetails: data.mptokenCurrencyDetails?.accountDetails || data.issuerDetails || null + } +} + const mptId = (data) => { if (!data) return null return data.MPTokenIssuanceID || data.mpt_issuance_id @@ -135,7 +172,12 @@ const showMPTs = ({ list, ledgerTimestamp, isIssued = false }) => { {i + 1} - + @@ -165,7 +207,7 @@ const showMPTs = ({ list, ledgerTimestamp, isIssued = false }) => { {historicalTitle}
- +
@@ -186,22 +228,30 @@ const showMPTs = ({ list, ledgerTimestamp, isIssued = false }) => { {isIssued ? ( <> - + ) : ( - + )} ) diff --git a/components/Account/ObjectsData.js b/components/Account/ObjectsData.js index 3d5849cd0..33b9ba026 100644 --- a/components/Account/ObjectsData.js +++ b/components/Account/ObjectsData.js @@ -372,7 +372,7 @@ export default function ObjectsData({

{payChannelList.map((c, i) => ( -
#
{i + 1} - + {shortNiceNumber(scaleAmount(c.OutstandingAmount || 0, c.AssetScale))}{scaleAmount(c.OutstandingAmount || 0, c.AssetScale)} - {c.MaximumAmount ? shortNiceNumber(scaleAmount(c.MaximumAmount, c.AssetScale)) : 'not set'} + {c.MaximumAmount ? scaleAmount(c.MaximumAmount, c.AssetScale) : 'not set'} - {shortNiceNumber(scaleAmount(c.MPTAmount || 0, c.mptokenCurrencyDetails?.scale))} - {scaleAmount(c.MPTAmount || 0, c.mptokenCurrencyDetails?.scale)}
+
@@ -477,7 +477,7 @@ export default function ObjectsData({
{checkList.length > 0 && ( -
{i + 1}
+
{checkListNode(checkList, { mobile: true })}
)} @@ -514,7 +514,7 @@ export default function ObjectsData({ {historicalTitle}
- +
{checkListNode(issuedCheckList, { type: 'issued', mobile: true })}
@@ -560,7 +560,7 @@ export default function ObjectsData({
{depositPreauthList.map((c, i) => ( - +
diff --git a/components/Account/PublicData.js b/components/Account/PublicData.js index 01397bd46..e3c7a9e1f 100644 --- a/components/Account/PublicData.js +++ b/components/Account/PublicData.js @@ -259,6 +259,8 @@ export default function PublicData({ data }) { ) + + return ( <>
{i + 1}
@@ -329,14 +331,13 @@ export default function PublicData({ data }) { ) )} - {!data.genesis && data.initialBalance ? ( + {!data.genesis && data.initialBalance && ( - ) : ( - '' )} +
Activated with {activatedWithNode}
@@ -401,6 +402,7 @@ export default function PublicData({ data }) { ) )} +
) diff --git a/components/Account/RecentTransactions.js b/components/Account/RecentTransactions.js index 16b660dda..014f4592d 100644 --- a/components/Account/RecentTransactions.js +++ b/components/Account/RecentTransactions.js @@ -3,10 +3,8 @@ import { fullDateAndTime, timeOrDate, amountFormat, nftIdLink, shortAddress } fr import { LinkTx } from '../../utils/links' import axios from 'axios' import { addressBalanceChanges } from '../../utils/transaction' -import { xls14NftValue } from '../../utils' +import { isNativeCurrency, xls14NftValue } from '../../utils' import Link from 'next/link' -import { isRipplingOnIssuer } from '../../utils/transaction/payment' -import { add } from '../../utils/calc' export default function RecentTransactions({ userData, ledgerTimestamp }) { const [transactions, setTransactions] = useState([]) @@ -39,6 +37,46 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) {
) + // Function to detect spam transactions (incoming payments for 0.000001/0.0001 XRP) + const skipTx = (txdata) => { + //check if no balance, nft changes and if addres is not a sender/receiver - skip + const balanceChanges = addressBalanceChanges(txdata, address) + const { specification, outcome } = txdata + const senderOrReceiver = + specification?.destination?.address === address || specification?.source?.address === address + + if (!balanceChanges?.length && !senderOrReceiver) { + // if not sender and not receiver and balance is not effected.. + //shall we check for burned nfts, so for nft changes? + return true + } + + // discard payments with 1 drop (spamm) + + if (txdata.tx?.TransactionType !== 'Payment') { + return false + } + + // Check if it's an incoming payment to the user + const isIncoming = specification?.destination?.address === address + + if (!isIncoming) { + return false + } + + const deliveredAmount = outcome?.deliveredAmount + + if ( + deliveredAmount && + isNativeCurrency(deliveredAmount) && + (deliveredAmount === '1' || deliveredAmount.value === '0.000001' || deliveredAmount.value === '0.0001') + ) { + return true + } + + return false + } + // Function to get transaction status const getTransactionStatus = (txdata) => { const outcome = txdata.outcome @@ -52,51 +90,22 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) { } // Function to get all transaction changes - const getAllTransactionChanges = (balanceChanges, rippling) => { - if (!balanceChanges || balanceChanges.length === 0) return null - - if (rippling) { - const total = balanceChanges.reduce((sum, change) => { - return add(sum, Number(change.value || 0)) - }, 0) - - const totalChange = { - ...balanceChanges[0], - value: total - } - - return ( - - 0 ? 'green' : total < 0 ? 'red' : ''}> + const getAllTransactionChanges = (txdata) => { + // Check for balance changes first + const balanceChanges = addressBalanceChanges(txdata, address) + if (balanceChanges && balanceChanges.length > 0) { + return balanceChanges.map((change, index) => ( + + 0 ? 'green' : 'red'}> - {total > 0 ? '+' : ''} - - {amountFormat(totalChange, { - short: true, - maxFractionDigits: 2, - noSpace: true - })} - - {amountFormat(totalChange, { precise: 'nice' })} + {Number(change.value) > 0 ? '+' : ''} + {amountFormat(change, { short: true, maxFractionDigits: 2, noSpace: true })} + {amountFormat(change, { precise: 'nice' })} + {index < balanceChanges.length - 1 && ', '} - ) - } else { - if (balanceChanges && balanceChanges.length > 0) { - return balanceChanges.map((change, index) => ( - - 0 ? 'green' : 'red'}> - - {Number(change.value) > 0 ? '+' : ''} - {amountFormat(change, { short: true, maxFractionDigits: 2, noSpace: true })} - {amountFormat(change, { precise: 'nice' })} - - - {index < balanceChanges.length - 1 && ', '} - - )) - } + )) } // Check for NFTokenMint transactions @@ -343,17 +352,13 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) { } // Function to get specific payment type - const getPaymentType = (txdata, rippling) => { + const getPaymentType = (txdata) => { if (txdata.tx?.TransactionType !== 'Payment') { return txdata.tx?.TransactionType } const { outcome, specification } = txdata - if (rippling) { - return 'Rippling' - } - // Check if it's a conversion payment (same source and destination) const isConversion = specification?.source?.address === specification?.destination?.address && @@ -376,13 +381,18 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) { setLoading(true) setError(null) const res = await axios( - `/v3/transactions/${address}?limit=15&relevantOnly=true&filterSpam=true` + + `/v3/transactions/${address}?limit=15` + (ledgerTimestamp ? '&toDate=' + new Date(ledgerTimestamp).toISOString() : '') ).catch((error) => { setError(error.message) setLoading(false) }) - setTransactions((res?.data?.transactions || [])?.slice(0, 5)) + const allTransactions = Array.isArray(res?.data) ? res.data : res?.data?.transactions + + // Filter out spam transactions and take the latest 5 + const filteredTransactions = (allTransactions || []).filter((txdata) => !skipTx(txdata)).slice(0, 5) + + setTransactions(filteredTransactions) setLoading(false) } @@ -404,7 +414,7 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) { - {title} [View all]{historicalTitle} + {title} [View all]{historicalTitle} @@ -432,19 +442,17 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) { {transactions.map((txdata, i) => { const status = getTransactionStatus(txdata) - const balanceChanges = addressBalanceChanges(txdata, address) - const rippling = isRipplingOnIssuer(balanceChanges, address) return ( {status.status} {txdata.tx?.date ? timeOrDate(txdata.tx.date, 'ripple') : '-'} - {getPaymentType(txdata, rippling)} + {getPaymentType(txdata)} - {getAllTransactionChanges(balanceChanges, rippling)} + {getAllTransactionChanges(txdata, address)} ) })} @@ -455,13 +463,13 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) {

- {title.toUpperCase()} [View all]{historicalTitle} + {title.toUpperCase()} [View all]{historicalTitle}

{loading && Loading recent transactions...} {error && Error: {error}} {!loading && !error && transactions.length > 0 && ( - +
@@ -472,19 +480,17 @@ export default function RecentTransactions({ userData, ledgerTimestamp }) { {transactions.map((txdata, i) => { const status = getTransactionStatus(txdata) - const balanceChanges = addressBalanceChanges(txdata, address) - const rippling = isRipplingOnIssuer(balanceChanges, address) return ( - + - + ) })} diff --git a/components/Account/RelatedLinks.js b/components/Account/RelatedLinks.js index f645cbc22..43e1612db 100644 --- a/components/Account/RelatedLinks.js +++ b/components/Account/RelatedLinks.js @@ -28,14 +28,6 @@ export default function RelatedLinks({ data }) { |{' '} )} - {network !== 'alphanet' && ( - <> - - XRPL AlphaNet - {' '} - |{' '} - - )} {network !== 'xahau' && ( <> @@ -65,6 +57,10 @@ export default function RelatedLinks({ data }) { <> {network === 'mainnet' && ( <> + + Bithomp + {' '} + (old view) |{' '} XRPL.org {' '} @@ -83,11 +79,23 @@ export default function RelatedLinks({ data }) { |{' '} Blockchair + {' '} + |{' '} + + Gatehub + {' '} + |{' '} + + BitQuery )} {network === 'testnet' && ( <> + + Bithomp + {' '} + (old view) |{' '} XRPL.org {' '} @@ -99,14 +107,21 @@ export default function RelatedLinks({ data }) { )} {network === 'devnet' && ( <> + + Bithomp + {' '} + (old view) |{' '} XRPL.org )} - {network === 'alphanet' && <>} {network === 'xahau' && ( <> + + Xahau Explorer + {' '} + (old view) |{' '} XRPL.org {' '} @@ -118,6 +133,10 @@ export default function RelatedLinks({ data }) { )} {network === 'xahau-testnet' && ( <> + + Xahau Explorer + {' '} + (old view) | XRPL.org {' '} @@ -129,6 +148,10 @@ export default function RelatedLinks({ data }) { )} {network === 'xahau-jshooks' && ( <> + + Xahau Explorer + {' '} + (old view) | XRPLF diff --git a/components/Account/Transactions/Elements/RipplingChanges.js b/components/Account/Transactions/Elements/RipplingChanges.js deleted file mode 100644 index a9b32b2f0..000000000 --- a/components/Account/Transactions/Elements/RipplingChanges.js +++ /dev/null @@ -1,54 +0,0 @@ -import { amountFormat } from '../../../../utils/format' -import { add } from '../../../../utils/calc' - -export const RipplingChanges = ({ balanceChanges }) => { - if (!balanceChanges || balanceChanges.length === 0) return null - - const gatewayAmountChange = balanceChanges.reduce((sum, item) => { - return add(sum, Number(item.value || 0)) - }, 0) - - return ( -
- Affected accounts: -
- {balanceChanges.map((change, index) => { - //if rippling, use counterparty as issuer - const formattedChange = { - ...change, - issuer: change.counterparty, - issuerDetails: change.counterpartyDetails - } - return ( -
- {amountFormat(formattedChange, { - icon: true, - showPlus: true, - withIssuer: true, - bold: true, - color: 'direction', - precise: 'nice', - issuerShort: false - })} -
- ) - })} - {gatewayAmountChange !== null && ( -
- Total gateway change: - - {amountFormat( - { ...balanceChanges[0], value: gatewayAmountChange }, - { - icon: true, - bold: true, - color: 'direction', - precise: 'nice' - } - )} - -
- )} -
- ) -} diff --git a/components/Account/Transactions/FiatRateContext.js b/components/Account/Transactions/FiatRateContext.js new file mode 100644 index 000000000..f89c8e5fa --- /dev/null +++ b/components/Account/Transactions/FiatRateContext.js @@ -0,0 +1,7 @@ +import { createContext, useContext } from 'react' + +export const TxFiatRateContext = createContext(0) + +export const useTxFiatRate = () => { + return useContext(TxFiatRateContext) +} diff --git a/components/Account/Transactions/TransactionRowAMM.js b/components/Account/Transactions/TransactionRowAMM.js index 5050ebea8..453aac847 100644 --- a/components/Account/Transactions/TransactionRowAMM.js +++ b/components/Account/Transactions/TransactionRowAMM.js @@ -1,78 +1,9 @@ -import { amountFormat } from '../../../utils/format' -import { addressBalanceChanges } from '../../../utils/transaction' -import { isRipplingOnIssuer } from '../../../utils/transaction/payment' -import { RipplingChanges } from './Elements/RipplingChanges' import { TransactionRowCard } from './TransactionRowCard' export const TransactionRowAMM = ({ data, address, index, selectedCurrency }) => { - const { tx } = data - - const ammTypeLabels = { - AMMCreate: 'AMM create', - AMMDeposit: 'AMM deposit', - AMMWithdraw: 'AMM withdraw', - AMMVote: 'AMM vote' - } - - const sourceBalanceChangesList = addressBalanceChanges(data, address) || [] - const depositedList = sourceBalanceChangesList.filter((c) => Number(c?.value) < 0) - const receivedList = sourceBalanceChangesList.filter((c) => Number(c?.value) > 0) - - const rippling = isRipplingOnIssuer(sourceBalanceChangesList, address) - const ripplingTitle = rippling ? 'Rippling through ' : '' - const txTypeSpecial = ( - {ripplingTitle + (ammTypeLabels[tx?.TransactionType] || tx?.TransactionType)} - ) - return ( - - {rippling ? ( - - ) : ( - <> - {(tx.TradingFee || tx.TradingFee === 0) && ( - <> - Trading fee: {tx.TradingFee / 100000}% -
- - )} - {depositedList.length > 0 && ( - <> - {depositedList.map((change, index) => ( -
- Deposited Asset{depositedList.length > 1 ? ' ' + (index + 1) : ''}:{' '} - {amountFormat(change, { - icon: true, - bold: true, - precise: 'nice', - absolute: true - })} -
- ))} - - )} - {receivedList.length > 0 && ( - <> - {receivedList.map((change, index) => ( -
- Received Asset{receivedList.length > 1 ? ' ' + (index + 1) : ''}:{' '} - {amountFormat(change, { - icon: true, - bold: true, - precise: 'nice' - })} -
- ))} - - )} - - )} + + {/* AMM */} ) } diff --git a/components/Account/Transactions/TransactionRowAccountDelete.js b/components/Account/Transactions/TransactionRowAccountDelete.js index 5d78faba3..e35b8d8f6 100644 --- a/components/Account/Transactions/TransactionRowAccountDelete.js +++ b/components/Account/Transactions/TransactionRowAccountDelete.js @@ -1,36 +1,39 @@ import { TransactionRowCard } from './TransactionRowCard' import { addressUsernameOrServiceLink, amountFormat, nativeCurrencyToFiat } from '../../../utils/format' import { FiDownload, FiUpload } from 'react-icons/fi' +import { useTxFiatRate } from './FiatRateContext' export const TransactionRowAccountDelete = ({ data, address, index, selectedCurrency }) => { - const { outcome, specification, fiatRates } = data - const fiatRate = fiatRates?.[selectedCurrency] + const pageFiatRate = useTxFiatRate() + const { outcome, specification } = data return ( -
- {specification?.destination?.address === address ? ( - <> - - {addressUsernameOrServiceLink(specification?.source, 'address')} - - ) : ( - <> - - {addressUsernameOrServiceLink(specification?.destination, 'address')} - - )} -
- {outcome?.deliveredAmount && ( -
- Delivered amount: - {amountFormat(outcome?.deliveredAmount, { icon: true })} - {nativeCurrencyToFiat({ - amount: outcome?.deliveredAmount, - selectedCurrency, - fiatRate - })} + <> +
+ {specification?.destination?.address === address ? ( + <> + + {addressUsernameOrServiceLink(specification?.source, 'address')} + + ) : ( + <> + + {addressUsernameOrServiceLink(specification?.destination, 'address')} + + )}
- )} + {outcome?.deliveredAmount && ( +
+ Delivered amount: + {amountFormat(outcome?.deliveredAmount, { icon: true })} + {nativeCurrencyToFiat({ + amount: outcome?.deliveredAmount, + selectedCurrency, + fiatRate: pageFiatRate + })} +
+ )} + ) } diff --git a/components/Account/Transactions/TransactionRowAccountSet.js b/components/Account/Transactions/TransactionRowAccountSet.js index c1448532b..2e5cf18d0 100644 --- a/components/Account/Transactions/TransactionRowAccountSet.js +++ b/components/Account/Transactions/TransactionRowAccountSet.js @@ -4,133 +4,108 @@ import { nativeCurrency } from '../../../utils' export const TransactionRowAccountSet = ({ data, address, index, selectedCurrency }) => { const { specification, tx } = data - const txTypeSpecial = Account settings update - return ( - - {tx.MessageKey !== undefined && ( -
- Message key: {specification.messageKey || removed} -
- )} - - {tx.Domain !== undefined && ( -
- Domain: {specification.domain || 'removed'} -
- )} - + {specification.defaultRipple !== undefined && ( -
- Default ripple: {specification.defaultRipple ? 'enabled' : 'disabled'} +
+ Default ripple: + {specification.defaultRipple ? 'enabled' : 'disabled'}
)} - {specification.disallowXRP !== undefined && ( -
- Incoming {nativeCurrency}: {specification.disallowXRP ? 'disallow' : 'allow'} +
+ Incoming {nativeCurrency}: + {specification.disallowXRP ? 'disallow' : 'allow'}
)} - {specification.requireDestTag !== undefined && ( -
- Destination tag: {specification.requireDestTag ? 'require' : "don't require"} +
+ Destination tag: + {specification.requireDestTag ? 'require' : "don't require"}
)} - - {specification.depositAuth !== undefined && ( -
- Deposit authorization: {specification.depositAuth ? 'enabled' : 'disabled'} -
- )} - {specification.disableMaster !== undefined && ( -
- Master key: {specification.disableMaster ? 'disabled' : 'enabled'} +
+ Master key: + {specification.disableMaster ? 'disabled' : 'enabled'}
)} - {specification.noFreeze && ( -
- No freeze: enabled +
+ No freeze: + enabled +
+ )} + {specification.depositAuth !== undefined && ( +
+ Deposit authorization: + {specification.depositAuth ? 'enabled' : 'disabled'}
)} - {specification.requireAuth !== undefined && ( -
- Require authorization: {specification.requireAuth ? 'enabled' : 'disabled'} +
+ Require authorization: + {specification.requireAuth ? 'enabled' : 'disabled'}
)} - {specification.disallowIncomingCheck !== undefined && ( -
- Incoming check: {specification.disallowIncomingCheck ? 'disallow' : 'allow'} +
+ Incoming check: + {specification.disallowIncomingCheck ? 'disallow' : 'allow'}
)} - {specification.disallowIncomingPayChan !== undefined && ( -
- Incoming payment channel:{' '} - {specification.disallowIncomingPayChan ? 'disallow' : 'allow'} +
+ Incoming payment channel: + {specification.disallowIncomingPayChan ? 'disallow' : 'allow'}
)} - {specification.disallowIncomingNFTokenOffer !== undefined && ( -
- Incoming NFT offer:{' '} - {specification.disallowIncomingNFTokenOffer ? 'disallow' : 'allow'} +
+ Incoming NFT offer: + {specification.disallowIncomingNFTokenOffer ? 'disallow' : 'allow'}
)} - {specification.disallowIncomingTrustline !== undefined && ( -
- Incoming trust line:{' '} - {specification.disallowIncomingTrustline ? 'disallow' : 'allow'} +
+ Incoming trust line: + {specification.disallowIncomingTrustline ? 'disallow' : 'allow'}
)} - {specification.enableTransactionIDTracking !== undefined && ( -
- Transaction ID tracking:{' '} - {specification.enableTransactionIDTracking ? 'enabled' : 'disabled'} +
+ Transaction ID tracking: + {specification.enableTransactionIDTracking ? 'enabled' : 'disabled'}
)} - {specification.globalFreeze !== undefined && ( -
- Global freeze: {specification.globalFreeze ? 'enabled' : 'disabled'} +
+ Global freeze: + {specification.globalFreeze ? 'enabled' : 'disabled'}
)} - {specification.authorizedMinter !== undefined && ( -
- Authorized minter: {specification.authorizedMinter ? 'enabled' : 'disabled'} +
+ Authorized minter: + {specification.authorizedMinter ? 'enabled' : 'disabled'}
)} - - {specification.nftokenMinter !== undefined && ( -
- NFT minter:{' '} - {specification.nftokenMinter || removed} + {tx.NFTokenMinter !== undefined && ( +
+ NFT minter: + {specification.nftokenMinter || removed}
)} - {specification.allowTrustLineClawback !== undefined && ( -
- Trustline Clawback:{' '} - {specification.allowTrustLineClawback ? 'allowed' : 'disallow'} +
+ Trust line Clawback: + {specification.allowTrustLineClawback ? 'allowed' : 'disallow'}
)} - {specification.disallowIncomingRemit !== undefined && ( -
- Incoming Remit: {specification.disallowIncomingRemit ? 'disallow' : 'allow'} +
+ Incoming Remit: + {specification.disallowIncomingRemit ? 'disallow' : 'allow'}
)} diff --git a/components/Account/Transactions/TransactionRowCard.js b/components/Account/Transactions/TransactionRowCard.js index 8f03bde31..98cb2a08e 100644 --- a/components/Account/Transactions/TransactionRowCard.js +++ b/components/Account/Transactions/TransactionRowCard.js @@ -1,119 +1,63 @@ -import { - amountFormat, - dateFormat, - fullDateAndTime, - nativeCurrencyToFiat, - shortHash, - timeFormat, - timeFromNow -} from '../../../utils/format' +import { amountFormat, dateFormat, nativeCurrencyToFiat, timeFormat } from '../../../utils/format' +import { useEffect, useState } from 'react' +import { fetchHistoricalRate } from '../../../utils/common' +import { TxFiatRateContext } from './FiatRateContext' import { LinkTx } from '../../../utils/links' -import { - errorCodeDescription, - shortErrorCode, - dappBySourceTag, - isConvertionTx, - addressBalanceChanges, - memoNode -} from '../../../utils/transaction' -import { isTagValid, useWidth } from '../../../utils' -import { i18n } from 'next-i18next' -import CopyButton from '../../UI/CopyButton' -import { useIsMobile } from '../../../utils/mobile' -import { isRipplingOnIssuer } from '../../../utils/transaction/payment' -import Link from 'next/link' +import { errorCodeDescription, shortErrorCode, dappBySourceTag } from '../../../utils/transaction' +import { useWidth } from '../../../utils' +import { FiCalendar, FiClock } from 'react-icons/fi' -/* - { - "result": "tesSUCCESS", - "timestamp": "2025-11-21T17:20:10.000Z", - "fee": "0.000011", - "ledgerIndex": 100363821, - "indexInLedger": 51, - "deliveredAmount": { - "currency": "XRP", - "value": "0.000001", - "valueInConvertCurrencies": { - "eur": "0.00000169979" - } - }, - "ledgerTimestamp": 1763745610, - "feeInFiats": { - "eur": "0.00001869769" - }, - "balanceChanges": [ - { - "currency": "XRP", - "value": "0.000001", - "valueInConvertCurrencies": { - "eur": "0.00000169979" - } - } - ] - } -*/ - -export const TransactionRowCard = ({ data, address, index, txTypeSpecial, children, selectedCurrency }) => { +export const TransactionRowCard = ({ data, index, txTypeSpecial, children, selectedCurrency }) => { const width = useWidth() - const { specification, tx, outcome, fiatRates } = data + const { specification, tx, outcome } = data + const memos = specification?.memos const isSuccessful = outcome?.result == 'tesSUCCESS' - const isConvertion = isConvertionTx(specification) - const sourceBalanceChangesList = addressBalanceChanges(data, address) - const pageFiatRate = fiatRates?.[selectedCurrency] - - //don't show sourcetag if it's the tag of a known dapp - const dapp = dappBySourceTag(tx.SourceTag) - const sequence = tx.TicketSequence || tx.Sequence + const [pageFiatRate, setPageFiatRate] = useState(0) - const addressIsSource = specification?.source?.address === address + useEffect(() => { + if (!selectedCurrency || !outcome?.ledgerTimestamp) return + fetchHistoricalRate({ + timestamp: outcome.ledgerTimestamp * 1000, + selectedCurrency, + setPageFiatRate + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedCurrency, outcome?.ledgerTimestamp]) - const isMobile = useIsMobile(600) - - const typeNode = txTypeSpecial || {tx?.TransactionType} - - const rippling = isRipplingOnIssuer(sourceBalanceChangesList, address) + //don't show sourcetag if it's the tag of a known dapp + const dapp = dappBySourceTag(tx.SourceTag) return (
- - {!isMobile && ( - - )} - + - {!isMobile && ( - - )} ) } diff --git a/components/Account/Transactions/TransactionRowCheck.js b/components/Account/Transactions/TransactionRowCheck.js index 0c8f67e82..db50722e4 100644 --- a/components/Account/Transactions/TransactionRowCheck.js +++ b/components/Account/Transactions/TransactionRowCheck.js @@ -1,55 +1,41 @@ import { TransactionRowCard } from './TransactionRowCard' -import { AddressWithIconInline, amountFormat, nativeCurrencyToFiat } from '../../../utils/format' +import { amountFormat, nativeCurrencyToFiat } from '../../../utils/format' +import { useTxFiatRate } from './FiatRateContext' +import { dappBySourceTag } from '../../../utils/transaction' export const TransactionRowCheck = ({ data, address, index, selectedCurrency }) => { - const { outcome, specification, tx, fiatRates } = data + const pageFiatRate = useTxFiatRate() - const fiatRate = fiatRates?.[selectedCurrency] + const { outcome, specification } = data - const checkTypeLabels = { - CheckCreate: 'Check creation', - CheckCash: 'Check cashing', - CheckCancel: 'Check cancelation' - } - - const txTypeSpecial = ( - - {tx?.Destination === address ? ( - <> - Incoming check from -
- - - ) : ( - checkTypeLabels[tx?.TransactionType] || tx?.TransactionType - )} -
- ) + const checkChanges = outcome?.checkChanges + //don't show sourcetag if it's the tag of a known dapp + const dapp = dappBySourceTag(specification.source.tag) return ( - - {outcome?.deliveredAmount && ( -
- {tx?.Account === address ? 'Received' : 'Amount'}:{' '} - {amountFormat(outcome?.deliveredAmount, { - icon: true, - bold: true, - color: 'direction', - precise: 'nice' - })} - {nativeCurrencyToFiat({ - amount: outcome?.deliveredAmount, - selectedCurrency, - fiatRate - })} -
- )} + + <> + {checkChanges?.sendMax && ( +
+ Max amount: + + {amountFormat(checkChanges.sendMax, { icon: true, withIssuer: true, bold: true, color: 'orange' })} + {nativeCurrencyToFiat({ + amount: checkChanges.sendMax, + selectedCurrency, + fiatRate: pageFiatRate + })} + +
+ )} + + {checkChanges?.source?.tag !== undefined && !dapp && ( + <> + Source tag: + {checkChanges.source.tag} + + )} +
) } diff --git a/components/Account/Transactions/TransactionRowImport.js b/components/Account/Transactions/TransactionRowImport.js index 629310178..86007468a 100644 --- a/components/Account/Transactions/TransactionRowImport.js +++ b/components/Account/Transactions/TransactionRowImport.js @@ -1,25 +1,9 @@ -import { amountFormat, nativeCurrencyToFiat } from '../../../utils/format' import { TransactionRowCard } from './TransactionRowCard' export const TransactionRowImport = ({ data, address, index, selectedCurrency }) => { - const { outcome, fiatRates } = data - const fiatRate = fiatRates?.[selectedCurrency] return ( -
- Received:{' '} - {amountFormat(outcome?.deliveredAmount, { - icon: true, - bold: true, - color: 'green', - precise: true - })} - {nativeCurrencyToFiat({ - amount: outcome?.deliveredAmount, - selectedCurrency, - fiatRate - })} -
+ {/* Import */}
) } diff --git a/components/Account/Transactions/TransactionRowNFToken.js b/components/Account/Transactions/TransactionRowNFToken.js index 0f1f6871f..19bc329fc 100644 --- a/components/Account/Transactions/TransactionRowNFToken.js +++ b/components/Account/Transactions/TransactionRowNFToken.js @@ -5,21 +5,29 @@ import { nftOfferLink, amountFormat, addressUsernameOrServiceLink, - nativeCurrencyToFiat, - AddressWithIconInline + nativeCurrencyToFiat } from '../../../utils/format' import { addressBalanceChanges } from '../../../utils/transaction' -import { useIsMobile } from '../../../utils/mobile' +import { useTxFiatRate } from './FiatRateContext' -const nftData = (change, nftInfo, txType, amountChange) => { +const nftData = (change, nftInfo, txType) => { const flagsAsString = flagList(nftInfo.flags) return ( <> -
- {txType === 'NFTokenBurn' && 'Burned '}NFT: {nftIdLink(change.nftokenID)} -
- {nftInfo.transferFee !== undefined && txType !== 'NFTokenBurn' && amountChange && ( + {txType === 'NFTokenBurn' ? ( +
+ Change: + removed NFT {nftIdLink(change.nftokenID)} +
+ ) : ( +
+ NFT: + {nftIdLink(change.nftokenID)} +
+ )} + + {nftInfo.transferFee !== undefined && txType !== 'NFTokenBurn' && (
Royalty: {nftInfo.transferFee / 1000}% @@ -73,77 +81,18 @@ const showAllOfferLinks = (changes) => { } export const TransactionRowNFToken = ({ data, address, index, selectedCurrency }) => { - const { specification, outcome, tx, fiatRates } = data - const fiatRate = fiatRates?.[selectedCurrency] + const { specification, outcome, tx } = data const txType = tx?.TransactionType - let txTypeSpecial = txType - const isMobile = useIsMobile(600) + const direction = specification.flags ? (specification.flags.sellToken ? 'Sell' : 'Buy') : null + const txTypeSpecial = + txType + + (direction && (txType === 'NFTokenAcceptOffer' || txType === 'NFTokenCreateOffer') + ? ' - ' + direction + ' Offer' + : '') + const pageFiatRate = useTxFiatRate() const amountChange = addressBalanceChanges(data, address)?.[0] - const nftSource = - outcome?.nftokenChanges?.length === 2 - ? outcome.nftokenChanges.find((change) => change.nftokenChanges[0]?.status === 'removed') - : null - - const nftDestination = - outcome?.nftokenChanges?.length === 2 - ? outcome.nftokenChanges.find((change) => change.nftokenChanges[0]?.status === 'added') - : null - - if (txType === 'NFTokenAcceptOffer') { - if (!amountChange) { - txTypeSpecial = ( - <> - NFT{' '} - {nftDestination?.address === address - ? 'received from' - : nftSource?.address === address - ? 'transfer to' - : 'transfer by'} - {isMobile ? ' ' :
} - - - ) - } else if (amountChange?.value < 0) { - txTypeSpecial = 'NFT purchase' - } else { - txTypeSpecial = 'NFT offer accept' - } - } else if (txType === 'NFTokenCreateOffer') { - const direction = specification.flags ? (specification.flags.sellToken ? 'Sell' : 'Buy') : null - if (direction) { - txTypeSpecial = 'Create NFT ' + direction + ' offer' - - if (direction === 'Sell' && tx?.Account !== address) { - txTypeSpecial = ( - <> - {tx?.Amount === '0' ? 'Free NFT offer' : 'NFT Sell offer'} from - {isMobile ? ' ' :
} - - - ) - } - } - } else if (txType === 'NFTokenCancelOffer') { - txTypeSpecial = 'Cancel NFT offer' - } else if (txType === 'NFTokenMint') { - txTypeSpecial = 'Mint NFT' - } else if (txType === 'NFTokenBurn') { - txTypeSpecial = 'Burn NFT' - } - - txTypeSpecial = {txTypeSpecial} - return ( - {outcome?.nftokenChanges?.length > 0 && ( - <> - {/* For NFTokenAcceptOffer, show NFT info only once */} - {txType === 'NFTokenAcceptOffer' - ? (() => { - const firstChange = outcome.nftokenChanges[0]?.nftokenChanges[0] - const nftInfo = firstChange ? outcome?.affectedObjects?.nftokens?.[firstChange.nftokenID] : null - return firstChange && nftInfo ? ( - {nftData(firstChange, nftInfo, txType, amountChange)} - ) : null - })() - : /* For other transaction types, show NFT info for each change */ - outcome.nftokenChanges.map((change, i) => { - const nftChanges = change.nftokenChanges - return nftChanges.map((nftChange, j) => { - const nftInfo = outcome?.affectedObjects?.nftokens?.[nftChange.nftokenID] - return ( - - {nftData(nftChange, nftInfo, txType, amountChange)} - - ) - }) - })} - - )} + <> + {outcome?.nftokenChanges?.length > 0 && ( + <> + {/* For NFTokenAcceptOffer, show NFT info only once */} + {txType === 'NFTokenAcceptOffer' + ? (() => { + const firstChange = outcome.nftokenChanges[0]?.nftokenChanges[0] + const nftInfo = firstChange ? outcome?.affectedObjects?.nftokens?.[firstChange.nftokenID] : null + return firstChange && nftInfo ? ( + {nftData(firstChange, nftInfo, txType)} + ) : null + })() + : /* For other transaction types, show NFT info for each change */ + outcome.nftokenChanges.map((change, i) => { + const nftChanges = change.nftokenChanges + return nftChanges.map((nftChange, j) => { + const nftInfo = outcome?.affectedObjects?.nftokens?.[nftChange.nftokenID] + return ( + {nftData(nftChange, nftInfo, txType)} + ) + }) + })} + + )} - {txType === 'NFTokenCancelOffer' && ( - <> - {/* For cancel offers not initiated by this account, show who initiated the cancel */} - {tx?.Account !== address && ( - <> - NFT offer Canceled by: - {addressUsernameOrServiceLink(specification?.source, 'address')} -
- - )} - - )} + {/* For sell offers, show NFT owner, NFT ID, and destination */} + {txType === 'NFTokenCreateOffer' && ( + <> + {/* For sell offers not initiated by this account, show who created the offer */} + {specification?.flags?.sellToken && specification?.source?.address !== address && ( + <> + Sell Offer by: + {addressUsernameOrServiceLink(specification?.source, 'address')} +
+ + )} + + )} - {outcome?.nftokenOfferChanges?.length > 0 && txType !== 'NFTokenAcceptOffer' && ( -
- Offer: - {showAllOfferLinks(outcome?.nftokenOfferChanges)} -
- )} + {txType === 'NFTokenCancelOffer' && ( + <> + {/* For cancel offers not initiated by this account, show who initiated the cancel */} + {specification?.source?.address !== address && ( + <> + NFTokenCancelOffer by + {addressUsernameOrServiceLink(specification?.source, 'address')} +
+ + )} + + )} - {txType === 'NFTokenCreateOffer' && ( - <> - {tx?.Owner && ( - <> - NFT Owner: - {addressUsernameOrServiceLink(specification, 'owner')} -
- - )} - {tx?.NFTokenID && ( - <> - NFT: - {nftIdLink(tx?.NFTokenID)} -
- - )} - {tx?.Destination && tx?.Destination !== address && ( - <> - Destination: - {addressUsernameOrServiceLink(specification?.destination, 'address')} -
- - )} - - )} + {/* For buy offers, show NFT owner, NFT ID, and destination */} + {txType === 'NFTokenCreateOffer' && !specification?.flags?.sellToken && ( + <> + {tx?.Owner && ( + <> + NFT Owner: + {addressUsernameOrServiceLink(specification, 'owner')} +
+ + )} + {tx?.NFTokenID && ( + <> + NFT: + {nftIdLink(tx?.NFTokenID)} +
+ + )} + {tx?.Destination && ( + <> + Destination: + {addressUsernameOrServiceLink(specification?.destination, 'address')} +
+ + )} + + )} - {txType === 'NFTokenAcceptOffer' && ( - <> - {tx?.NFTokenSellOffer && ( - <> - {amountChange ? 'Sell' : 'Transfer'} offer: - {nftOfferLink(tx?.NFTokenSellOffer)} -
- - )} - {tx?.NFTokenBuyOffer && ( - <> - Buy offer: - {nftOfferLink(tx?.NFTokenBuyOffer)} -
- - )} - {/* Show amount spent for the NFT */} - {amountChange && ( - <> - Amount: - {amountFormat(amountChange, { icon: true })} - - {nativeCurrencyToFiat({ - amount: amountChange, - selectedCurrency, - fiatRate - })} - -
- - )} - {tx?.NFTokenBrokerFee && tx?.NFTokenBrokerFee !== '0' && ( - <> - Broker fee: - - {amountFormat(specification.nftokenBrokerFee, { tooltip: 'right', icon: true })} - -
- - )} - {outcome?.nftokenChanges?.length === 2 && ( - <> - {nftSource.address !== address &&
Sender: {addressUsernameOrServiceLink(nftSource, 'address')}
} - {nftDestination.address !== address && ( -
Sent to: {addressUsernameOrServiceLink(nftDestination, 'address')}
- )} - - )} - - )} + {txType === 'NFTokenAcceptOffer' && ( + <> + {tx?.NFTokenSellOffer && ( + <> + Sell offer: + {nftOfferLink(tx?.NFTokenSellOffer)} +
+ + )} + {tx?.NFTokenBuyOffer && ( + <> + Buy offer: + {nftOfferLink(tx?.NFTokenBuyOffer)} +
+ + )} + {/* Show amount spent for the NFT */} + {amountChange && ( + <> + Amount: + {amountFormat(amountChange, { icon: true })} + + {nativeCurrencyToFiat({ + amount: amountChange, + selectedCurrency, + fiatRate: pageFiatRate + })} + +
+ + )} + {/* Show broker fee for broker sells */} + {tx?.NFTokenBrokerFee && tx?.NFTokenBrokerFee !== '0' && ( + <> + Broker fee: + + {amountFormat(specification.nftokenBrokerFee, { tooltip: 'right', icon: true })} + +
+ + )} + {/* Show NFT transfer details */} + {outcome?.nftokenChanges?.length === 2 && ( + <> + Transfer From: + + {addressUsernameOrServiceLink( + outcome.nftokenChanges.find((change) => change.nftokenChanges[0]?.status === 'removed'), + 'address' + )} + +
+ Transfer To: + + {addressUsernameOrServiceLink( + outcome.nftokenChanges.find((change) => change.nftokenChanges[0]?.status === 'added'), + 'address' + )} + +
+ + )} + + )} - {specification.amount !== undefined && ( -
- {txType === 'NFTokenMint' ? 'Price: ' : 'Amount: '} - {amountFormat(specification.amount, { tooltip: 'right', icon: true })} - - {nativeCurrencyToFiat({ - amount: specification.amount, - selectedCurrency, - fiatRate - })} - -
- )} + {outcome?.nftokenOfferChanges?.length > 0 && txType !== 'NFTokenAcceptOffer' && ( +
+ Offer: + {showAllOfferLinks(outcome?.nftokenOfferChanges)} +
+ )} + + {/* show 0 Amounts */} + {specification.amount !== undefined && ( +
+ {txType === 'NFTokenMint' ? 'Price: ' : 'Amount: '} + {amountFormat(specification.amount, { tooltip: 'right', icon: true })} + + {nativeCurrencyToFiat({ + amount: specification.amount, + selectedCurrency, + fiatRate: pageFiatRate + })} + +
+ )} +
) } diff --git a/components/Account/Transactions/TransactionRowOffer.js b/components/Account/Transactions/TransactionRowOffer.js index 8e6366ecc..9aa118457 100644 --- a/components/Account/Transactions/TransactionRowOffer.js +++ b/components/Account/Transactions/TransactionRowOffer.js @@ -1,12 +1,26 @@ import { TransactionRowCard } from './TransactionRowCard' +import { useTxFiatRate } from './FiatRateContext' import { addressBalanceChanges } from '../../../utils/transaction' -import { amountFormat, nativeCurrencyToFiat, showFlags } from '../../../utils/format' -import { isRipplingOnIssuer } from '../../../utils/transaction/payment' -import { RipplingChanges } from './Elements/RipplingChanges' +import { amountFormat, nativeCurrencyToFiat } from '../../../utils/format' +import { nativeCurrency } from '../../../utils' + +const flagList = (flags) => { + let flagsString = '' + + if (!flags) return flagsString + + for (let key in flags) { + if (flags[key]) { + flagsString += key + ', ' + } + } + flagsString = flagsString.slice(0, -2) // remove the last comma + + return flagsString +} export const TransactionRowOffer = ({ data, address, index, selectedCurrency }) => { - const { specification, outcome, tx, fiatRates } = data - const fiatRate = fiatRates?.[selectedCurrency] + const { specification, outcome, tx } = data const myOrderbookChange = outcome?.orderbookChanges ?.filter((entry) => entry.address === address)?.[0] @@ -16,20 +30,16 @@ export const TransactionRowOffer = ({ data, address, index, selectedCurrency }) const myBalanceChangesList = addressBalanceChanges(data, address) - const flags = showFlags(specification?.flags) - - const myOrder = tx?.Account === address - - const rippling = isRipplingOnIssuer(myBalanceChangesList, address) - let orderStatus = '' - if (tx?.TransactionType === 'OfferCancel') { - orderStatus = 'canceled' - } else if (myBalanceChangesList?.length === 0 && myOrder) { + if ( + myBalanceChangesList?.length === 1 && + myBalanceChangesList[0].currency === nativeCurrency && + myBalanceChangesList[0].value === -tx.Fee + ) { orderStatus = 'placed' } else { - if (!myOrder) { + if (address !== tx?.Account) { orderStatus = 'fullfilled' const seq = specification.sequence || specification.ticketSequence if (seq) { @@ -40,11 +50,12 @@ export const TransactionRowOffer = ({ data, address, index, selectedCurrency }) } } - const ripplingTitle = rippling ? 'Rippling through ' : '' - const txTypeSpecial = {ripplingTitle + direction + ' order ' + orderStatus} + const txTypeSpecial = tx?.TransactionType + ' - ' + direction + ' Order ' + orderStatus + const pageFiatRate = useTxFiatRate() const takerGets = specification.takerGets || myOrderbookChange?.takerGets const takerPays = specification.takerPays || myOrderbookChange?.takerPays + const flagsAsString = flagList(specification?.flags) return ( - {rippling ? ( - - ) : ( - <> - {myOrder && ( - <> - Order specification: -
- {takerGets && ( -
- {direction === 'Sell' ? 'Sell exactly' : 'Pay up to'}: - {amountFormat(takerGets, { icon: true, withIssuer: true, bold: true })} -
- )} - {takerPays && ( -
- {direction === 'Sell' ? 'Receive at least' : 'Receive exactly'}: - {amountFormat(takerPays, { icon: true, withIssuer: true, bold: true })} -
- )} - - )} - {myOrder && myBalanceChangesList?.length === 2 &&
} - {myBalanceChangesList?.length === 2 && ( - <> -
- Exchanged: -
- - {myBalanceChangesList.map((change, index) => { - return ( -
- {amountFormat(change, { - icon: true, - showPlus: true, - withIssuer: true, - bold: true, - color: 'direction', - precise: 'nice', - issuerShort: false - })} - {nativeCurrencyToFiat({ amount: change, selectedCurrency, fiatRate })} -
- ) - })} -
-
-
-
- Rates: -
- + <> + {takerGets && ( +
+ Taker Gets: + {amountFormat(takerGets, { icon: true, withIssuer: true, bold: true })} +
+ )} + {takerPays && ( +
+ Taker Pays: + {amountFormat(takerPays, { icon: true, withIssuer: true, bold: true })} +
+ )} + {myBalanceChangesList.length === 2 && ( + <> +
+ Exchanged: + + {myBalanceChangesList.map((change, index) => ( +
+ {amountFormat(change, { + icon: true, + showPlus: true, + withIssuer: true, + bold: true, + color: 'direction' + })} + {nativeCurrencyToFiat({ amount: change, selectedCurrency, fiatRate: pageFiatRate })} +
+ ))} +
+
+
+ Rate: + + {amountFormat( + { + currency: myBalanceChangesList[0].currency, + issuer: myBalanceChangesList[0].issuer, + value: 1 + }, + { icon: true } + )}{' '} + ={' '} + {amountFormat( { - currency: myBalanceChangesList[0].currency, - issuer: myBalanceChangesList[0].issuer, - value: 1 + ...myBalanceChangesList[1], + value: Math.abs(myBalanceChangesList[1].value / myBalanceChangesList[0].value) }, { icon: true } - )}{' '} - ={' '} - - {amountFormat( - { - ...myBalanceChangesList[1], - value: Math.abs(myBalanceChangesList[1].value / myBalanceChangesList[0].value) - }, - { icon: true, precise: 'nice' } - )} - -
+ )} +
+
+ {amountFormat( + { + currency: myBalanceChangesList[1].currency, + issuer: myBalanceChangesList[1].issuer, + value: 1 + }, + { icon: true } + )}{' '} + ={' '} + {amountFormat( { - currency: myBalanceChangesList[1].currency, - issuer: myBalanceChangesList[1].issuer, - value: 1 + ...myBalanceChangesList[0], + value: Math.abs(myBalanceChangesList[0].value / myBalanceChangesList[1].value) }, { icon: true } - )}{' '} - ={' '} - - {amountFormat( - { - ...myBalanceChangesList[0], - value: Math.abs(myBalanceChangesList[0].value / myBalanceChangesList[1].value) - }, - { icon: true } - )} - + )} -
-
-
- - )} - {flags &&
Flags: {flags}
} - - )} +
+
+ + )} + {flagsAsString && ( +
+ Flag{flagsAsString.includes(',') ? 's' : ''}: + {flagsAsString} +
+ )} +
) } diff --git a/components/Account/Transactions/TransactionRowPayment.js b/components/Account/Transactions/TransactionRowPayment.js index 0e6aa1b80..80a9f77e9 100644 --- a/components/Account/Transactions/TransactionRowPayment.js +++ b/components/Account/Transactions/TransactionRowPayment.js @@ -1,51 +1,55 @@ import { TransactionRowCard } from './TransactionRowCard' -import { AddressWithIconInline, amountFormat, nativeCurrencyToFiat } from '../../../utils/format' -import { addressBalanceChanges, isConvertionTx } from '../../../utils/transaction' -import { - isIOUpayment, - isRipplingOnIssuer, - optionalAbsPaymentAmount, - paymentTypeName -} from '../../../utils/transaction/payment' -import { useIsMobile } from '../../../utils/mobile' -import { RipplingChanges } from './Elements/RipplingChanges' +import { xls14NftValue } from '../../../utils' +import { addressUsernameOrServiceLink, amountFormat, nativeCurrencyToFiat } from '../../../utils/format' +import { addressBalanceChanges, dappBySourceTag } from '../../../utils/transaction' +import { FiDownload, FiUpload } from 'react-icons/fi' +import { useTxFiatRate } from './FiatRateContext' +import { FaArrowRightArrowLeft } from 'react-icons/fa6' export const TransactionRowPayment = ({ data, address, index, selectedCurrency }) => { - const { outcome, specification, tx, fiatRates } = data - const fiatRate = fiatRates?.[selectedCurrency] + const { outcome, specification } = data - let txTypeSpecial = paymentTypeName(data) - const isConvertion = isConvertionTx(specification) - const sourceBalanceChangesList = addressBalanceChanges(data, address) - const iouPayment = isIOUpayment(data) + let txTypeSpecial = 'Payment' + const isConvertion = + specification?.source?.address === specification?.destination?.address && + (specification?.source?.tag === specification?.destination?.tag || !specification?.destination?.tag) - const isMobile = useIsMobile(600) + if (isConvertion) { + txTypeSpecial = 'Conversion payment' + } + + if (xls14NftValue(outcome?.deliveredAmount?.value)) { + txTypeSpecial = 'NFT transfer (XLS-14)' + } + + const pageFiatRate = useTxFiatRate() + + //for payments executor is always the sender, so we can check executor's balance changes. + const sourceBalanceChangesList = addressBalanceChanges(data, specification.source.address) - const rippling = isRipplingOnIssuer(sourceBalanceChangesList, address) + //don't show sourcetag if it's the tag of a known dapp + const dapp = dappBySourceTag(specification.source.tag) - if (rippling) { - txTypeSpecial = Rippling through payment - } else { - if (!isConvertion) { - txTypeSpecial = ( - <> - {txTypeSpecial} - {tx?.Destination === address ? 'from' : tx?.Account === address ? 'to' : 'by'} - {isMobile ? ' ' :
} - - - ) - } else { - txTypeSpecial = {txTypeSpecial} + let iouPayment = false + + if (!isConvertion) { + //check if iou involved (pathfinding or iou with fee) + if ( + !outcome?.deliveredAmount?.mpt_issuance_id && + sourceBalanceChangesList?.[0]?.value !== '-' + outcome?.deliveredAmount?.value + ) { + iouPayment = true } } - const balancesTitle = isConvertion ? 'Exchanged' : 'Sender spent' + const optionalAbsAmount = (change) => { + return !isConvertion && (change?.value ? change.value.toString()[0] === '-' : change?.toString()[0] === '-') + ? { + ...change, + value: change?.value ? change?.value.toString().slice(1) : change?.toString().slice(1) + } + : change + } return ( - {rippling ? ( - - ) : ( - <> - {!isConvertion && outcome?.deliveredAmount && ( -
- {specification?.source?.address === address ? 'Sent' : 'Received'}:{' '} - {amountFormat(outcome?.deliveredAmount, { - icon: true, - withIssuer: true, - bold: true, - precise: 'nice', - issuerShort: false - })} - {nativeCurrencyToFiat({ - amount: outcome?.deliveredAmount, - selectedCurrency, - fiatRate - })} -
- )} - {(isConvertion || iouPayment) && sourceBalanceChangesList?.length > 0 && ( - <> -
- {balancesTitle}: {sourceBalanceChangesList.length > 1 &&
} + <> + {!isConvertion && ( +
+ {specification?.destination?.address === address ? ( + <> + + {addressUsernameOrServiceLink(specification.source, 'address')} + + ) : specification?.source?.address === address ? ( + <> + + {addressUsernameOrServiceLink(specification.destination, 'address')} + + ) : ( + <> + Payment By {addressUsernameOrServiceLink(specification.source, 'address')} + + )} +
+ )} + {specification.source?.tag !== undefined && !dapp && ( + <> + Source tag: + {specification.source.tag} + + )} + + {(isConvertion || iouPayment) && sourceBalanceChangesList?.length > 0 && ( + <> +
+ + {isConvertion ? ( + <> + {' '} + Exchanged:{' '} + + ) : ( + <> Sender spent: + )} {sourceBalanceChangesList.map((change, index) => { - return ( -
- {amountFormat(optionalAbsPaymentAmount(change, isConvertion), { - icon: true, - withIssuer: true, - bold: true, - color: 'direction', - precise: 'nice', - issuerShort: false - })} - {nativeCurrencyToFiat({ - amount: optionalAbsPaymentAmount(change, isConvertion), - selectedCurrency, - fiatRate - })} -
- ) + return
})} +
+ + {sourceBalanceChangesList.map((change, index) => ( +
+ {amountFormat(optionalAbsAmount(change), { + icon: true, + withIssuer: true, + bold: true, + color: 'direction' + })} + {nativeCurrencyToFiat({ + amount: optionalAbsAmount(change), + selectedCurrency, + fiatRate: pageFiatRate + })} +
+ ))} +
+
+ {sourceBalanceChangesList.length === 2 && ( +
+ Exchange rate: + + {amountFormat( + { + currency: sourceBalanceChangesList[0].currency, + issuer: sourceBalanceChangesList[0].issuer, + value: 1 + }, + { icon: true } + )}{' '} + ={' '} + {amountFormat( + { + ...sourceBalanceChangesList[1], + value: Math.abs(sourceBalanceChangesList[1].value / sourceBalanceChangesList[0].value) + }, + { icon: true, withIssuer: true, bold: true } + )} +
- {sourceBalanceChangesList.length === 2 && ( -
- Exchange rate: - - {amountFormat( - { - currency: sourceBalanceChangesList[0].currency, - issuer: sourceBalanceChangesList[0].issuer, - value: 1 - }, - { icon: true } - )}{' '} - ={' '} - {amountFormat( - { - ...sourceBalanceChangesList[1], - value: Math.abs(sourceBalanceChangesList[1].value / sourceBalanceChangesList[0].value) - }, - { icon: true, withIssuer: true, bold: true } - )} - -
- )} - - )} - - )} + )} + + )} + {!isConvertion && outcome?.deliveredAmount && ( +
+ Delivered amount: + {amountFormat(outcome?.deliveredAmount, { icon: true, withIssuer: true, bold: true, color: 'green' })} + {nativeCurrencyToFiat({ + amount: outcome?.deliveredAmount, + selectedCurrency, + fiatRate: pageFiatRate + })} +
+ )} + ) } diff --git a/components/Account/Transactions/TransactionRowTrustSet.js b/components/Account/Transactions/TransactionRowTrustSet.js index 97755fb2b..a9604c2b2 100644 --- a/components/Account/Transactions/TransactionRowTrustSet.js +++ b/components/Account/Transactions/TransactionRowTrustSet.js @@ -1,73 +1,9 @@ -import { - fullNiceNumber, - showFlags, - userOrServiceName, - CurrencyWithIconInline, - amountFormat -} from '../../../utils/format' -import CopyButton from '../../UI/CopyButton' import { TransactionRowCard } from './TransactionRowCard' -import { useIsMobile } from '../../../utils/mobile' export const TransactionRowTrustSet = ({ data, address, index, selectedCurrency }) => { - const { specification } = data - const serviceOruser = userOrServiceName(specification?.counterpartyDetails) - const isMobile = useIsMobile(600) - const txTypeSpecial = ( - <> - - Trust {specification?.limit === '0' ? removed : 'set'} - - {!isMobile ? ( - <> -
-
- - ) : ( - ' ' - )} - {specification?.limit !== '0' ? ( - <> - {amountFormat( - { - currency: specification?.currency, - issuer: specification?.counterparty, - issuerDetails: specification?.counterpartyDetails, - value: specification?.limit - }, - { icon: true, bold: true, color: 'orange', short: true } - )} - - ) : ( - - - - )} - - ) return ( - - {serviceOruser && ( - <> - {specification.counterpartyDetails?.service ? 'Issuer' : 'User'}: {serviceOruser} -
- - )} - {serviceOruser ? 'Address' : 'Counterparty'}: {specification.counterparty}{' '} - -
- Currency code: {specification.currency}{' '} - -
- Limit: {fullNiceNumber(specification.limit)} -
- Flags: {showFlags(specification.flags)} + + {/* Trust Set */} ) } diff --git a/components/Faucet.js b/components/Faucet.js index 3f11f681e..d1838cbf1 100644 --- a/components/Faucet.js +++ b/components/Faucet.js @@ -24,7 +24,6 @@ import { addressLink, amountFormat, capitalize, duration, fullNiceNumber } from import { LedgerLink, LinkTx } from '../utils/links' import Link from 'next/link' import Image from 'next/image' -import { errorCodeDescription } from '../utils/transaction' const convertToDrops = (amount) => { return parseInt(amount * 1000000).toString() @@ -208,9 +207,7 @@ export default function Faucet({ account, type, sessionTokenData }) { } else if (response?.data?.state === 'tecNO_DST_INSUF_XRP') { setErrorMessage('The destination address is not activated, send a larger amount to activate it!') } else { - setErrorMessage( - response?.data?.message || errorCodeDescription(response?.data?.state) || t('error-occured', { ns: 'faucet' }) - ) + setErrorMessage(response?.data?.message || response?.data?.state || t('error-occured', { ns: 'faucet' })) } } } diff --git a/components/Layout/Footer.js b/components/Layout/Footer.js index a18b114db..e1c539611 100644 --- a/components/Layout/Footer.js +++ b/components/Layout/Footer.js @@ -14,8 +14,6 @@ export default function Footer({ countryCode }) { const { t, i18n } = useTranslation() const footerRef = useRef() - const lang = i18n.language === 'default' ? 'en' : i18n.language - return (
@@ -37,7 +35,7 @@ export default function Footer({ countryCode }) { {network === 'mainnet' && ( <> {t('menu.developers.account-generation')} - {t('menu.developers.faucet')} + {t('menu.developers.faucet')} Bithomp tools )} diff --git a/components/Layout/Header/MobileMenu.js b/components/Layout/Header/MobileMenu.js index 1085c39e5..eb578ccd4 100644 --- a/components/Layout/Header/MobileMenu.js +++ b/components/Layout/Header/MobileMenu.js @@ -1,7 +1,7 @@ import Link from 'next/link' import { useTranslation } from 'next-i18next' -import { devNet, xahauNetwork, nativeCurrency, avatarServer } from '../../../utils' +import { devNet, xahauNetwork, nativeCurrency, server, avatarServer } from '../../../utils' import Image from 'next/image' @@ -61,13 +61,9 @@ export default function MobileMenu({ {t('signin.actions.view')} - + {t('signin.actions.my-transactions')} - + Send payment @@ -166,9 +162,6 @@ export default function MobileMenu({ Account Settings - - Account Delete - {t('menu.services.nft-mint')} @@ -208,12 +201,7 @@ export default function MobileMenu({ )} diff --git a/components/Layout/Header/NetworkTable.js b/components/Layout/Header/NetworkTable.js index 23c5602f7..3e4e5a626 100644 --- a/components/Layout/Header/NetworkTable.js +++ b/components/Layout/Header/NetworkTable.js @@ -37,7 +37,6 @@ export default function NetworkTable({ close }) { { value: 'xahau', label: networks['xahau'].explorerName }, { value: 'testnet', label: networks['testnet'].explorerName }, { value: 'devnet', label: networks['devnet'].explorerName }, - { value: 'alphanet', label: networks['alphanet'].explorerName }, { value: 'xahau-testnet', label: networks['xahau-testnet'].explorerName }, { value: 'xahau-jshooks', label: networks['xahau-jshooks'].explorerName } ] diff --git a/components/Layout/Header/index.js b/components/Layout/Header/index.js index ecd2d88d2..a806eacd6 100644 --- a/components/Layout/Header/index.js +++ b/components/Layout/Header/index.js @@ -159,8 +159,6 @@ export default function Header({ const bithomp = server.includes('bithomp') - const lang = i18n.language === 'default' ? 'en' : i18n.language - return (
@@ -198,7 +196,6 @@ export default function Header({ Create Escrow {!xahauNetwork && AMM Services} Account Settings - Account Delete {t('menu.services.nft-mint')} {t('menu.usernames')} {t('menu.services.tax-reports')} @@ -216,14 +213,7 @@ export default function Header({ > {t('menu.tokens')} {!xahauNetwork && Multi-Purpose {t('menu.tokens')}} - + TOP Holders Set Trust (Trustline) @@ -325,7 +315,7 @@ export default function Header({ {network === 'mainnet' && ( <> {t('menu.developers.account-generation')} - {t('menu.developers.faucet')} + {t('menu.developers.faucet')} Bithomp tools )} @@ -467,7 +457,7 @@ export default function Header({ {isCopied ? t('button.copied') : t('button.copy-my-address')} {t('signin.actions.view')} - {t('signin.actions.my-transactions')} + {t('signin.actions.my-transactions')} Send payment Account Settings {t('signin.actions.my-nfts')} @@ -592,7 +582,7 @@ export default function Header({ - Loading more data is available to{' '} - openEmailLogin()}> - logged-in - {' '} - Bithomp Pro subscribers. + Loading more data is available to openEmailLogin()}>logged-in Bithomp Pro subscribers. {noSessionTokenMessage && ( <> @@ -72,7 +68,7 @@ export default function InfiniteScrolling({

) } - endMessage={

{errorMessage || endMessage || 'End of list.'}

} + endMessage={

{endMessage || 'End of list'}

} > {children} diff --git a/components/Layout/LeftFilters.js b/components/Layout/LeftFilters.js index f146f0f2f..ceec0bee5 100644 --- a/components/Layout/LeftFilters.js +++ b/components/Layout/LeftFilters.js @@ -43,8 +43,7 @@ export default function LeftFilters({ data={data} headers={csvHeaders} filename={'export ' + dateAndTimeNow + '.csv'} - className={'button-action narrow' + (!(data?.length > 0) ? ' disabled' : '')} - style={{ height: 34, display: 'flex', alignItems: 'center', padding: '0 12px', gap: 5, marginTop: -2 }} + className={'button-action thin narrow' + (!(data?.length > 0) ? ' disabled' : '')} > CSV @@ -60,9 +59,8 @@ export default function LeftFilters({ ) : (
-
diff --git a/components/Layout/SearchBlock.js b/components/Layout/SearchBlock.js index 71ba05b92..5ce3453b8 100644 --- a/components/Layout/SearchBlock.js +++ b/components/Layout/SearchBlock.js @@ -17,6 +17,7 @@ import { networksIds, isValidNftXls20, isCurrencyHashValid, + server, isValidPayString, isValidXAddress, performIdSearch, @@ -76,7 +77,6 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat const windowWidth = useWidth() const { id } = router.query - const [searchItem, setSearchItem] = useState(id || userData?.address || '') const [searching, setSearching] = useState(false) const [searchSuggestions, setSearchSuggestions] = useState([]) @@ -117,8 +117,9 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat typingTimer = setTimeout(async () => { if (value && value.length > 2) { setSearchingSuggestions(true) - const suggestionsResponse = await axios('v2/address/search/' + value).catch(() => { + const suggestionsResponse = await axios('v2/address/search/' + value).catch((error) => { setSearchingSuggestions(false) + console.log(error.message) }) if (suggestionsResponse) { const suggestions = suggestionsResponse.data @@ -153,11 +154,7 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat const searchOnChange = (option) => { if (!option) return - if (option.payString) { - onSearch(option.payString) - } else if (option.xAddress) { - onSearch(option.xAddress) - } else if (option.username && !option.username.includes('-')) { + if (option.username && !option.username.includes('-')) { onSearch(option.username) } else { onSearch(option.address) @@ -260,15 +257,19 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat return } - if (isLedgerIndexValid(searchFor)) { - router.push('/ledger/' + searchFor) + if (isValidPayString(searchFor) || isValidXAddress(searchFor)) { + // the check for paystring/xAddress should be before the check for addressOrUsername, + // as if there is no destination tag, we will treat it as an address or username + + // we need to resolve paystring and x-address first before redirecting! + // if there is a tag - + // get the new page which we can show an address and a tag + router.push('/account/' + encodeURI(searchFor) + addParams) //replace with a new page to show a tag return } - if (isValidPayString(searchFor) || isValidXAddress(searchFor)) { - // the check for paystring/xAddress should be before the check for addressOrUsername - // as if there is no destination tag, we will treat it as an address or username - router.push('/account/' + encodeURI(searchFor) + addParams) + if (isLedgerIndexValid(searchFor)) { + router.push('/ledger/' + searchFor) return } @@ -310,6 +311,25 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat return } + /* + PayID + searchItem.indexOf("$") > -1 + + username + <18 + + CurrencyCode, XLS14 + searchItem.length == 40 + + TX, NFT, NFT Offer + searchItem.length == 64 + + X-address + searchItem.length > 36 + searchItem.charAt(0) == "T" + searchItem.charAt(0) == "X" + */ + const showTabs = tab && ['nfts', 'nft-offers', 'nft-volumes', 'account', 'transactions', 'dex'].includes(tab) const searchOnInputChange = (inputValue, action) => { @@ -414,8 +434,7 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat option.xaman + option.verifiedDomain + option.serviceDomain + - option.xAddress + - option.tag + option.xAddress } inputValue={searchItem} onInputChange={searchOnInputChange} @@ -461,6 +480,12 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat {errorMessage}
)} + {/* + + + {t("home.scan-qr")} + + */}
{showTabs && ( @@ -475,7 +500,7 @@ export default function SearchBlock({ searchPlaceholderText, tab = null, userDat {tab == 'transactions' ? ( {t('explorer.menu.transactions')} ) : ( - {t('explorer.menu.transactions')} + {t('explorer.menu.transactions')} )}
diff --git a/components/Layout/TopLinks.js b/components/Layout/TopLinks.js index befa86b82..c12441d46 100644 --- a/components/Layout/TopLinks.js +++ b/components/Layout/TopLinks.js @@ -38,6 +38,7 @@ export default function TopLinks({ countryCode }) { ) } + //explorer links //includes /address and /tx if (pathname.includes('/transaction') || pathname.includes('/account')) { return ( @@ -64,12 +65,7 @@ export default function TopLinks({ countryCode }) { {t('sponsored.sponsored')} {' '} - 💰 |{' '} - - Tax reports - {' '} - 🧾 - {isMobile ?
: ' | '} + 💰 {isMobile ?
: ' | '} {stakeAd} {isMobile ?
: ' | '} diff --git a/components/NftsComponent.js b/components/NftsComponent.js index 9c5cc8e0a..339d1a47c 100644 --- a/components/NftsComponent.js +++ b/components/NftsComponent.js @@ -29,7 +29,6 @@ import AddressInput from './UI/AddressInput' import NftTabs from './Tabs/NftTabs' import FiltersFrame from './Layout/FiltersFrame' import InfiniteScrolling from './Layout/InfiniteScrolling' -import SimpleSelect from './UI/SimpleSelect' export default function NftsComponent({ collectionQuery, @@ -100,14 +99,10 @@ export default function NftsComponent({ const [issuerTaxonUrlPart, setIssuerTaxonUrlPart] = useState('?view=' + activeView) const [collectionUrlPart, setCollectionUrlPart] = useState(collectionQuery ? '&collection=' + collectionQuery : '') const [filtersHide, setFiltersHide] = useState(false) - const [selectedToken, setSelectedToken] = useState( - saleCurrency && saleCurrencyIssuer - ? { - currency: saleCurrency, - issuer: saleCurrencyIssuer - } - : { currency: nativeCurrency } - ) + const [selectedToken, setSelectedToken] = useState({ + currency: saleCurrency, + issuer: saleCurrencyIssuer + }) const controller = new AbortController() @@ -145,10 +140,7 @@ export default function NftsComponent({ } else { saleDestinationTabList = [ { value: 'buyNow', label: t('tabs.buyNow') }, - { value: 'publicAndKnownBrokers', label: t('tabs.publicAndKnownBrokers') }, - { value: 'public', label: t('tabs.public') }, - { value: 'knownBrokers', label: t('tabs.marketplaces') }, - { value: 'all', label: t('tabs.all') } + { value: 'publicAndKnownBrokers', label: t('tabs.publicAndKnownBrokers') } ] } @@ -538,11 +530,6 @@ export default function NftsComponent({ setTab: setOrder, paramName: 'order' }) - - if (!selectedToken?.issuer) { - queryRemoveList.push('saleCurrency') - queryRemoveList.push('saleCurrencyIssuer') - } } else { queryRemoveList.push('saleDestination') queryRemoveList.push('saleCurrency') @@ -576,7 +563,7 @@ export default function NftsComponent({ setTabParams(router, tabsToSet, queryAddList, queryRemoveList) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [order, rawData, listTab, saleDestinationTab, includeBurned, includeWithoutMediaData, selectedToken]) + }, [order, rawData, listTab, saleDestinationTab, includeBurned, includeWithoutMediaData]) const onTaxonInput = (value) => { if (/^\d+$/.test(value) && issuer && isValidTaxon(value)) { @@ -693,7 +680,7 @@ export default function NftsComponent({ {nftExplorer && ( <>

{t('nft-explorer.header') + ' '}

- + )} @@ -724,11 +711,11 @@ export default function NftsComponent({

- {t('tabs.onSale')}{' '} -
)} @@ -742,37 +729,34 @@ export default function NftsComponent({ hideButton={true} /> )} - {collectionQuery ? ( + {collectionQuery && ( - ) : ( - <> - - {!xahauNetwork && ( - - )} - )} {serialQuery && ( )} + + {!xahauNetwork && ( + + )} { setScreen('ledgerwallet') setStatus( - 'Please, connect your Ledger Wallet and open the ' + - nativeCurrency + - ' app. Note: Nano S does not support some transactions.' + 'Please, connect your Ledger Wallet and open the XRP app. Note: Nano S does not support some transactions.' ) ledgerwalletTxSend({ tx, signRequest, afterSubmitExe, afterSigning, onSignIn, setStatus, setAwaiting, t }) } @@ -907,18 +904,13 @@ export default function SignForm({ const xls35Sell = signRequest?.request?.TransactionType === 'URITokenCreateSellOffer' const checkBoxText = (screen, signRequest) => { - if (screen === 'nftTransfer') { - if (signRequest.request?.TransactionType === 'Remit') { - return "I'm sending this NFT for FREE." - } else { - return ( - - I'm offering that NFT for FREE to the Destination account,{' '} - the destination account would need to accept the NFT transfer. - - ) - } - } + if (screen === 'nftTransfer') + return ( + + I'm offering that NFT for FREE to the Destination account,{' '} + the destination account would need to accept the NFT transfer. + + ) if (screen === 'NFTokenBurn') return t('signin.confirm.nft-burn') if (screen === 'NFTokenModify') return 'I understand that URI will be updated for this NFT.' diff --git a/components/SignForms/NftTransfer.js b/components/SignForms/NftTransfer.js index 19dd37983..2eba233d2 100644 --- a/components/SignForms/NftTransfer.js +++ b/components/SignForms/NftTransfer.js @@ -1,96 +1,23 @@ import { useTranslation } from 'next-i18next' -import { useState, useEffect } from 'react' -import { isAddressValid, xahauNetwork } from '../../utils' +import { isAddressValid } from '../../utils' import AddressInput from '../UI/AddressInput' -import CheckBox from '../UI/CheckBox' -import axios from 'axios' export default function NftTransfer({ setSignRequest, signRequest, setStatus, setFormError }) { const { t } = useTranslation() - const [useRemit, setUseRemit] = useState(false) - const [destinationRemitDisabled, setDestinationRemitDisabled] = useState(false) - const [touched, setTouched] = useState(false) - - useEffect(() => { - // Check if destination allows incoming remit when address changes - const checkDestinationRemit = async () => { - if (!signRequest.request?.Destination) { - setDestinationRemitDisabled(false) - return - } - - try { - const response = await axios(`/v2/address/${signRequest.request.Destination}?ledgerInfo=true`) - const accountData = response?.data - - if (accountData?.ledgerInfo?.flags) { - const flags = accountData.ledgerInfo.flags - const disallowIncomingRemit = flags.disallowIncomingRemit - setDestinationRemitDisabled(disallowIncomingRemit) - } else { - setDestinationRemitDisabled(false) - } - } catch (error) { - console.error('Error checking destination remit status:', error) - setDestinationRemitDisabled(false) - } - } - - if (xahauNetwork) { - // check only on xahau network - checkDestinationRemit() - } - //eslint-disable-next-line react-hooks/exhaustive-deps - }, [signRequest.request?.Destination]) - - useEffect(() => { - if (xahauNetwork) { - const newRequest = { ...signRequest.request } - if (useRemit) { - newRequest.TransactionType = 'Remit' - if (newRequest.URITokenID) { - newRequest.URITokenIDs = [newRequest.URITokenID] - delete newRequest.URITokenID - } - delete newRequest.Amount - } else { - newRequest.TransactionType = 'URITokenCreateSellOffer' - newRequest.Amount = '0' - if (newRequest.URITokenIDs?.[0]) { - newRequest.URITokenID = newRequest.URITokenIDs[0] - delete newRequest.URITokenIDs - } - } - setSignRequest({ ...signRequest, request: newRequest }) - } - //eslint-disable-next-line react-hooks/exhaustive-deps - }, [useRemit]) const onAddressChange = (value) => { - if (!touched && !value) return - - setTouched(true) - - const newRequest = { ...signRequest, request: { ...signRequest.request } } - - if (!value) { - delete newRequest.request.Destination - setFormError(false) - setStatus('') - setSignRequest(newRequest) - return - } - + let newRequest = signRequest if (isAddressValid(value)) { newRequest.request.Destination = value setFormError(false) setStatus('') } else { - delete newRequest.request.Destination + if (newRequest.request.Destination) { + delete newRequest.request.Destination + } setStatus(t('form.error.address-invalid')) setFormError(true) } - setSignRequest(newRequest) } @@ -106,18 +33,6 @@ export default function NftTransfer({ setSignRequest, signRequest, setStatus, se hideButton={true} /> - - {/* Remit option for Xahau network */} - {xahauNetwork && ( -
- - Pay the NFT reserve for the destination (immediate NFT transfer). - {destinationRemitDisabled && ( - (Disabled - destination has incoming Remit disabled) - )} - -
- )}
) } diff --git a/components/Tabs/NetworkTabs.js b/components/Tabs/NetworkTabs.js index 1502d6bec..ab1c4ceab 100644 --- a/components/Tabs/NetworkTabs.js +++ b/components/Tabs/NetworkTabs.js @@ -10,7 +10,6 @@ export default function NetworkTabs() { { value: 'mainnet', label: networks['mainnet'].explorerName }, { value: 'testnet', label: networks['testnet'].explorerName }, { value: 'devnet', label: networks['devnet'].explorerName }, - { value: 'alphanet', label: networks['alphanet'].explorerName }, { value: 'xahau', label: networks['xahau'].explorerName }, { value: 'xahau-testnet', label: networks['xahau-testnet'].explorerName }, { value: 'xahau-jshooks', label: networks['xahau-jshooks'].explorerName } diff --git a/components/Tabs/NftCollectionTabs.js b/components/Tabs/NftCollectionTabs.js deleted file mode 100644 index b8a4fb3b2..000000000 --- a/components/Tabs/NftCollectionTabs.js +++ /dev/null @@ -1,63 +0,0 @@ -import { useRouter } from 'next/router' -import Tabs from '.' -import { useEffect, useState } from 'react' - -export default function NftCollectionTabs({ tab, collectionPart }) { - const router = useRouter() - - const [rendered, setRendered] = useState(false) - - useEffect(() => { - setRendered(true) - }, []) - - let mainTabs = [ - { value: 'collections', label: 'NFT collections' }, - { value: 'nfts', label: 'View All NFTs' }, - { value: 'sold', label: 'Last Sold NFTs' }, - { value: 'listed', label: 'Listed NFTs' }, - { value: 'holders', label: 'NFT Holders' } - ] - - if (tab === 'holders' && collectionPart) { - //mainTabs = mainTabs.filter((t) => t.value !== 'holders') - mainTabs.unshift({ value: 'collection', label: 'NFT collection' }) - } - - const remapCollectionPart = (collectionPart) => { - const params = new URLSearchParams(collectionPart) - - const issuer = params.get('issuer') - const taxon = params.get('taxon') - - if (!issuer || !taxon) return collectionPart // fallback - - return `${issuer}:${taxon}` - } - - const changePage = (tab) => { - let url = '/nft-volumes?period=week' - if (tab === 'nfts') url = `/nft-explorer?${collectionPart}&includeWithoutMediaData=true` - else if (tab === 'sold') - url = `/nft-sales?${collectionPart}&sale=primaryAndSecondary&includeWithoutMediaData=true&period=all&order=soldNew` - else if (tab === 'listed') - url = `/nft-explorer?${collectionPart}&list=onSale&includeWithoutMediaData=true&saleDestination=publicAndKnownBrokers` - else if (tab === 'holders') url = `/nft-distribution?${collectionPart}` - else if (tab === 'collection') url = `/nft-collection/${remapCollectionPart(collectionPart)}` - router.push(url) - } - - if (!rendered) return
- - return ( -
- -
- ) -} diff --git a/components/Tabs/NftTabs.js b/components/Tabs/NftTabs.js index e1df88ed3..c0a32a9f8 100644 --- a/components/Tabs/NftTabs.js +++ b/components/Tabs/NftTabs.js @@ -3,7 +3,7 @@ import Tabs from '.' import { useTranslation } from 'next-i18next' import { useEffect, useState } from 'react' -export default function NftTabs({ tab, params }) { +export default function NftTabs({ tab, url }) { const router = useRouter() const { t } = useTranslation() @@ -15,12 +15,11 @@ export default function NftTabs({ tab, params }) { const mainTabs = [ { value: 'nft-explorer', label: t('nft-explorer.header') }, - { value: 'nft-sales', label: t('nft-sales.header') }, - { value: 'nft-volumes', label: 'NFT collections' } + { value: 'nft-sales', label: t('nft-sales.header') } ] - const changePage = (tab) => { - router.push('/' + tab + (params ? params : '')) + const changePage = () => { + router.push(url) } if (!rendered) return
diff --git a/components/Tabs/index.js b/components/Tabs/index.js index 34918c15a..75ac66e99 100644 --- a/components/Tabs/index.js +++ b/components/Tabs/index.js @@ -6,7 +6,7 @@ export default function Tabs({ tabList, tab, setTab, name = 'radio', style = {} return (
- {tabList?.map((tabItem) => ( + {tabList.map((tabItem) => ( {type === 'name' ? nftName(nft, { maxLength: 18 }) : saleData(nft.sellOffers)}
- {!disabled && ( + {!disabled &&
{nftName(nft) ? ( <> @@ -127,7 +127,7 @@ export default function Tiles({ nftList, type = 'name', convertCurrency, account {addressName(nft.issuerDetails, t('table.issuer'))} {addressName(nft.ownerDetails, t('table.owner'))}
- )} + }
@@ -159,10 +159,9 @@ export default function Tiles({ nftList, type = 'name', convertCurrency, account
{convertedAmount(nft, convertCurrency, { short: true }) || amountFormat(nft.amount)}
-
{!disabled && timeOrDate(nft.acceptedAt)}
- {!disabled && ( + {!disabled &&
{nftName(nft.nftoken) ? ( <> @@ -181,7 +180,7 @@ export default function Tiles({ nftList, type = 'name', convertCurrency, account )}
- )} + } diff --git a/components/Transaction/TransactionAccountSet.js b/components/Transaction/TransactionAccountSet.js index 1dc53cb49..329be32cc 100644 --- a/components/Transaction/TransactionAccountSet.js +++ b/components/Transaction/TransactionAccountSet.js @@ -52,6 +52,14 @@ export const TransactionAccountSet = ({ data, pageFiatRate, selectedCurrency }) + {tx.ClearFlag !== undefined && ( +
+ + Clear flag + + {tx.ClearFlag} + + )} {tx.Domain !== undefined && ( Domain @@ -238,7 +246,7 @@ export const TransactionAccountSet = ({ data, pageFiatRate, selectedCurrency }) {specification.authorizedMinter ? 'enabled' : 'disabled'} )} - {specification.nftokenMinter !== undefined && ( + {tx.NFTokenMinter !== undefined && ( NFT minter diff --git a/components/Transaction/TransactionAmm.js b/components/Transaction/TransactionAmm.js index 227fd92ae..0c93f334a 100644 --- a/components/Transaction/TransactionAmm.js +++ b/components/Transaction/TransactionAmm.js @@ -411,7 +411,7 @@ export const TransactionAMM = ({ data, pageFiatRate, selectedCurrency }) => { )} - {tradingFee || tradingFee === 0 ? ( + {tradingFee ? ( Trading fee{divide(tradingFee, 100000)}% diff --git a/components/Transaction/TransactionCard/ExchangeTable.js b/components/Transaction/TransactionCard/ExchangeTable.js index d8cf47f70..d13d17d80 100644 --- a/components/Transaction/TransactionCard/ExchangeTable.js +++ b/components/Transaction/TransactionCard/ExchangeTable.js @@ -1,29 +1,6 @@ import { amountFormat, AddressWithIconInline } from '../../../utils/format' import { LinkAmm, LinkObject } from '../../../utils/links' -const rates = (a, b) => { - return ( - <> - {amountFormat( - { - currency: a.currency, - issuer: a?.issuer || undefined, - value: 1 - }, - { icon: true, bold: true, noSpace: true } - )}{' '} - ={' '} - {amountFormat( - { - ...b, - value: Math.abs((b.value || b / 1000000) / (a.value || a / 1000000)) - }, - { icon: true, bold: true, noSpace: true } - )} - - ) -} - export default function ExchangesTable({ exchanges = [], ledgerIndex = null }) { const keyOf = (e, i) => e.offer_id || e.amm_id || `${e.type}-${e.address1}-${e.address2}-${i}` @@ -59,8 +36,7 @@ export default function ExchangesTable({ exchanges = [], ledgerIndex = null }) { exchanged{' '} {sent} for {received} with{' '} - {by}.
- Rates: {rates(e.asset1, e.asset2)}, {rates(e.asset2, e.asset1)}. + {by}. ) })} diff --git a/components/Transaction/TransactionCard/index.js b/components/Transaction/TransactionCard/index.js index 8b096de38..63a0fff1e 100644 --- a/components/Transaction/TransactionCard/index.js +++ b/components/Transaction/TransactionCard/index.js @@ -10,6 +10,7 @@ import { AddressWithIconFilled, amountFormat, codeHighlight, + decodeJsonMemo, fullDateAndTime, nativeCurrencyToFiat, niceCurrency, @@ -17,7 +18,7 @@ import { timeFromNow } from '../../../utils/format' import { decodeCTID, isValidCTID, networksIds, server, xahauNetwork } from '../../../utils' -import { dappBySourceTag, errorCodeDescription, memoNode, shortErrorCode } from '../../../utils/transaction' +import { dappBySourceTag, errorCodeDescription, shortErrorCode } from '../../../utils/transaction' import { add } from '../../../utils/calc' import ExchangesTable from './ExchangeTable' @@ -105,6 +106,120 @@ export const TransactionCard = ({ const txLink = server + '/tx/' + (tx?.ctid || tx?.hash) + const memoNode = (memos) => { + let output = [] + if (memos && Array.isArray(memos)) { + for (let j = 0; j < memos.length; j++) { + const memo = memos[j] + let memotype = memo?.type + let memopiece = memo?.data + let memoformat = memo?.format + + if (!memopiece && memoformat?.slice(0, 2) === 'rt') { + memopiece = memoformat + } + + let clientname = '' + + if (memopiece) { + if (memopiece.slice(0, 16) === 'xrplexplorer.com' || memopiece.slice(0, 11) === 'bithomp.com') { + memopiece = '' + clientname = 'bithomp.com' + } + + if (memopiece.slice(0, 17) === 'xahauexplorer.com') { + memopiece = '' + clientname = 'xahauexplorer.com' + } + + if (memotype) { + if (memotype.slice(0, 25) === '[https://xumm.community]-') { + memotype = memotype.slice(25) + clientname = 'xumm.community' + } else if (memotype.slice(0, 24) === '[https://xrpl.services]-') { + memotype = memotype.slice(24) + clientname = 'xrpl.services' + } else { + memotype = memotype.charAt(0).toUpperCase() + memotype.slice(1) + } + } + + if (decodeJsonMemo(memopiece)) { + output.push( +
+ Memo {memos.length > 1 ? j + 1 : ''} + + {memotype && ( + <> + {memotype} +
+ + )} + {decodeJsonMemo(memopiece)} +
+ + ) + } else { + if (memopiece.length > 100 && memopiece.split(' ').length === 1 && memopiece.includes('.')) { + //jwt + memopiece = memopiece.replace('"', '') + const pieces = memopiece.split('.') + output.push( + + + JWT Header + {decodeJsonMemo(pieces[0], { code: 'base64' })} + + + JWT Payload + {decodeJsonMemo(pieces[1], { code: 'base64' })} + + + JWT Signature + +
{pieces[2]}
+
+ + + ) + } else { + if (memopiece) { + output.push( + + Memo {memos.length > 1 ? j + 1 : ''} + + {memotype && memotype.toLowerCase() !== 'memo' && ( + + {memotype} +
+
+ )} + {memopiece} +
+ + ) + } + } + } + + if (clientname) { + output.push( + + Client web + + + {clientname} + + + + ) + } + } + } + } + return output + } + const filteredBalanceChanges = outcome?.balanceChanges?.filter((change) => !noBalanceChange(change)) let emitTX = null @@ -309,7 +424,7 @@ export const TransactionCard = ({ Affected accounts - {filteredBalanceChanges?.length > 1 && ( + {filteredBalanceChanges.length > 1 && ( <> There are {filteredBalanceChanges.length} accounts that were affected by this transaction. @@ -368,7 +483,7 @@ export const TransactionCard = ({ })} )} - {!tx?.TransactionType.includes('AMM') && outcome?.exchanges?.length > 0 && ( + {outcome?.exchanges?.length > 0 && ( <> Exchange{outcome?.exchanges?.length > 1 && 's'} @@ -431,12 +546,6 @@ export const TransactionCard = ({ {tx.Flags} )} - {tx.ClearFlag !== undefined && ( - - Clear flag - {tx.ClearFlag} - - )} {tx?.TransactionType !== 'UNLReport' && ( <> {tx.TicketSequence ? ( diff --git a/components/Transaction/TransactionCron.js b/components/Transaction/TransactionCron.js deleted file mode 100644 index eae6b50bd..000000000 --- a/components/Transaction/TransactionCron.js +++ /dev/null @@ -1,60 +0,0 @@ -import { TData } from '../Table' -import { useTranslation } from 'next-i18next' -import { TransactionCard } from './TransactionCard' -import { AddressWithIconFilled, duration, fullDateAndTime, showFlags } from '../../utils/format' - -export const TransactionCron = ({ data, pageFiatRate, selectedCurrency }) => { - const { t } = useTranslation() - if (!data) return null - const { specification, tx } = data - - const flags = showFlags(specification?.flags) - - return ( - - - - Hook account - - - - - - {tx?.Owner && ( - - Owner - - - - - )} - {tx?.StartTime !== undefined && ( - - Start time - {tx.StartTime ? fullDateAndTime(tx.StartTime, 'ripple') : 'immediate execution'} - - )} - {tx?.RepeatCount !== undefined && ( - - Repeat count - {tx.RepeatCount} - - )} - {tx?.DelaySeconds && ( - - Delay seconds - - {tx.DelaySeconds}{' '} - {tx.DelaySeconds > 59 && ({duration(t, tx.DelaySeconds, { seconds: true })})} - - - )} - {flags && ( - - Flags - {flags} - - )} - - ) -} diff --git a/components/Transaction/TransactionDetails.js b/components/Transaction/TransactionDetails.js index 724f82455..41219f26c 100644 --- a/components/Transaction/TransactionDetails.js +++ b/components/Transaction/TransactionDetails.js @@ -6,7 +6,6 @@ import { AddressWithIconFilled, showFlags } from '../../utils/format' export const TransactionDetails = ({ data, pageFiatRate, selectedCurrency }) => { if (!data) return null const { specification } = data - const flags = showFlags(specification?.flags) return ( - {flags && ( + {specification?.flags && ( Flags - {flags} + {showFlags(specification?.flags)} )} diff --git a/components/Transaction/TransactionEnableAmendment.js b/components/Transaction/TransactionEnableAmendment.js index 94cde332c..3a07c7da3 100644 --- a/components/Transaction/TransactionEnableAmendment.js +++ b/components/Transaction/TransactionEnableAmendment.js @@ -1,14 +1,14 @@ import { TData } from '../Table' import { TransactionCard } from './TransactionCard' -import { AddressWithIconFilled, capitalize } from '../../utils/format' +import { AddressWithIconFilled } from '../../utils/format' import CopyButton from '../UI/CopyButton' import { xahauNetwork } from '../../utils' import Link from 'next/link' export const TransactionEnableAmendment = ({ data, pageFiatRate, selectedCurrency }) => { if (!data) return null - const { specification, outcome } = data + const { specification } = data return ( @@ -40,12 +40,6 @@ export const TransactionEnableAmendment = ({ data, pageFiatRate, selectedCurrenc )} - {outcome?.amendmentChanges?.amendment === specification.amendment && ( - - New status - {capitalize(outcome?.amendmentChanges.status)} - - )} Amendment hash diff --git a/components/Transaction/TransactionOffer.js b/components/Transaction/TransactionOffer.js index 95c3572f3..3fddd6940 100644 --- a/components/Transaction/TransactionOffer.js +++ b/components/Transaction/TransactionOffer.js @@ -42,7 +42,7 @@ export const TransactionOffer = ({ data, pageFiatRate, selectedCurrency }) => { txTypeSpecial={txTypeSpecial} > - Offer maker + Offer Maker @@ -57,14 +57,14 @@ export const TransactionOffer = ({ data, pageFiatRate, selectedCurrency }) => { {takerGets && ( - Taker gets - {amountFormat(takerGets, { precise: 'nice', withIssuer: true, bold: true })} + Taker Gets + {amountFormat(takerGets, { precise: true, withIssuer: true, bold: true })} )} {takerPays && ( - Taker pays - {amountFormat(takerPays, { precise: 'nice', withIssuer: true, bold: true })} + Taker Pays + {amountFormat(takerPays, { precise: true, withIssuer: true, bold: true })} )} diff --git a/components/Transaction/TransactionPayment/index.js b/components/Transaction/TransactionPayment/index.js index e96de7b65..cdb106542 100644 --- a/components/Transaction/TransactionPayment/index.js +++ b/components/Transaction/TransactionPayment/index.js @@ -9,13 +9,12 @@ import { } from '../../../utils/format' import { TransactionCard } from '../TransactionCard' -import { isNativeCurrency } from '../../../utils' +import { isNativeCurrency, xls14NftValue } from '../../../utils' import CopyButton from '../../UI/CopyButton' -import { addressBalanceChanges, dappBySourceTag, isConvertionTx } from '../../../utils/transaction' +import { addressBalanceChanges, dappBySourceTag } from '../../../utils/transaction' import DestinationTagProblemSolving from './DestinationTagProblemSolving' import PaymentInstructions from './PaymentInstructions' import { LinkTx } from '../../../utils/links' -import { isIOUpayment, optionalAbsPaymentAmount, paymentTypeName } from '../../../utils/transaction/payment' export const TransactionPayment = ({ data, pageFiatRate, selectedCurrency }) => { if (!data) return null @@ -24,12 +23,35 @@ export const TransactionPayment = ({ data, pageFiatRate, selectedCurrency }) => //for payments executor is always the sender, so we can check executor's balance changes. const sourceBalanceChangesList = addressBalanceChanges(data, specification.source.address) - const txTypeSpecial = paymentTypeName(data) - const isConvertion = isConvertionTx(specification) + + let txTypeSpecial = 'Payment' + + // sourse address and destination address is the same + // sometimes source tag is added to show the dapp + // so if there is no destintaion tag, no need the source tag to be the same + const isConvertion = + specification?.source?.address === specification?.destination?.address && + (specification?.source?.tag === specification?.destination?.tag || !specification?.destination?.tag) + const isSuccessful = outcome?.result == 'tesSUCCESS' - const iouPayment = isIOUpayment(data) - //don't show sourcetag if it's the tag of a known dapp - const dapp = dappBySourceTag(specification.source.tag) + + let iouPayment = false + + if (isConvertion) { + txTypeSpecial = 'Conversion payment' + } else { + //check if iou involved (pathfinding or iou with fee) + if ( + !outcome?.deliveredAmount?.mpt_issuance_id && + sourceBalanceChangesList?.[0]?.value !== '-' + outcome?.deliveredAmount?.value + ) { + iouPayment = true + } + } + + if (xls14NftValue(outcome?.deliveredAmount?.value)) { + txTypeSpecial = 'NFT transfer (XLS-14)' + } /* { @@ -86,6 +108,18 @@ export const TransactionPayment = ({ data, pageFiatRate, selectedCurrency }) => } */ + const optionalAbsAmount = (change) => { + return !isConvertion && (change?.value ? change.value.toString()[0] === '-' : change?.toString()[0] === '-') + ? { + ...change, + value: change?.value ? change?.value.toString().slice(1) : change?.toString().slice(1) + } + : change + } + + //don't show sourcetag if it's the tag of a known dapp + const dapp = dappBySourceTag(specification.source.tag) + return ( {sourceBalanceChangesList.map((change, index) => (
- {amountFormat(optionalAbsPaymentAmount(change, isConvertion), { - withIssuer: true, - bold: true, - color: 'direction' - })} + {amountFormat(optionalAbsAmount(change), { withIssuer: true, bold: true, color: 'direction' })} {nativeCurrencyToFiat({ - amount: optionalAbsPaymentAmount(change, isConvertion), + amount: optionalAbsAmount(change), selectedCurrency, fiatRate: pageFiatRate })} diff --git a/components/Transaction/TransactionSignerListSet.js b/components/Transaction/TransactionSignerListSet.js deleted file mode 100644 index bb012bbb7..000000000 --- a/components/Transaction/TransactionSignerListSet.js +++ /dev/null @@ -1,36 +0,0 @@ -import { TData } from '../Table' - -import { TransactionCard } from './TransactionCard' -import { AddressWithIconFilled } from '../../utils/format' - -export const TransactionSignerListSet = ({ data, pageFiatRate, selectedCurrency }) => { - if (!data) return null - const { specification } = data - - return ( - -
- Initiated by - - - - - - Signer quorum - {specification.signerQuorum} - - {specification?.signerEntries?.map((entry, index) => ( - - - Signer {index + 1} -
- Weight: {entry.signerWeight} -
- - - - - ))} - - ) -} diff --git a/components/Transaction/index.js b/components/Transaction/index.js index f5e0cb5b4..6fd59d7af 100644 --- a/components/Transaction/index.js +++ b/components/Transaction/index.js @@ -3,7 +3,6 @@ export { TransactionDetails } from './TransactionDetails' export { TransactionAccountDelete } from './TransactionAccountDelete' export { TransactionAccountSet } from './TransactionAccountSet' -export { TransactionSignerListSet } from './TransactionSignerListSet' export { TransactionCheck } from './TransactionCheck' export { TransactionCredential } from './TransactionCredential' export { TransactionDelegateSet } from './TransactionDelegateSet' @@ -24,4 +23,3 @@ export { TransactionDID } from './TransactionDID' export { TransactionImport } from './TransactionImport' export { TransactionURIToken } from './TransactionURIToken' export { TransactionRemit } from './TransactionRemit' -export { TransactionCron } from './TransactionCron' diff --git a/components/UI/AddressInput.js b/components/UI/AddressInput.js index c5443e061..5c96428ae 100644 --- a/components/UI/AddressInput.js +++ b/components/UI/AddressInput.js @@ -235,11 +235,9 @@ export default function AddressInput({ return (
- {(title || link) && ( - - {title} {link} - - )} + + {title} {link} +
{isMounted ? (
diff --git a/components/UI/CopyButton.js b/components/UI/CopyButton.js index 2828ad1ff..8b45e1294 100644 --- a/components/UI/CopyButton.js +++ b/components/UI/CopyButton.js @@ -9,7 +9,7 @@ const copyTextToClipboard = async (text) => { } } -export default function CopyButton({ text, copyText }) { +export default function CopyButton({ text }) { const { t } = useTranslation() const [isCopied, setIsCopied] = useState(false) @@ -69,9 +69,7 @@ export default function CopyButton({ text, copyText }) { /> - {isTooltipEnabled && ( - {isCopied ? t('button.copied') : copyText || t('button.copy')} - )} + {isTooltipEnabled && {isCopied ? t('button.copied') : t('button.copy')}} ) } diff --git a/components/UI/CountrySelect.js b/components/UI/CountrySelect.js index 7d5d418c7..ee2e33bc7 100644 --- a/components/UI/CountrySelect.js +++ b/components/UI/CountrySelect.js @@ -22,12 +22,7 @@ export default function CountrySelect({ countryCode, setCountryCode, type }) { }, [i18n.language]) async function fetchData() { - let response - try { - response = await axios('client/info') - } catch (error) { - return - } + const response = await axios('client/info') const json = response.data if (json && json.country) { const countryCode = json.country.toUpperCase() diff --git a/components/UI/SimpleSelect.js b/components/UI/SimpleSelect.js index 599654f44..e146a8c5a 100644 --- a/components/UI/SimpleSelect.js +++ b/components/UI/SimpleSelect.js @@ -3,55 +3,41 @@ import Select from 'react-select' export default function SimpleSelect({ value, setValue, optionsList, className }) { const [rendered, setRendered] = useState(false) - const [choosenOption, setChoosenOption] = useState(undefined) + const [choosenOption, setChoosenOption] = useState() - // Ensure we only render on client (avoid SSR/hydration issues) useEffect(() => { setRendered(true) - }, []) - - useEffect(() => { - if (!rendered) return - - if (!Array.isArray(optionsList) || optionsList.length === 0) { - setChoosenOption(undefined) - return + if (optionsList?.length === 0) return + let found = false + if (value) { + for (let i = 0; i < optionsList.length; i++) { + if (optionsList[i].value.toLowerCase() === value.toLowerCase()) { + setChoosenOption(optionsList[i]) + found = true + break + } + } } - - const targetValue = value ?? optionsList[0].value - - const match = optionsList.find((opt) => String(opt.value).toLowerCase() === String(targetValue).toLowerCase()) - - const finalOption = match || optionsList[0] - - setChoosenOption(finalOption) - - if (value !== finalOption.value) { - setValue(finalOption.value) + if (!found) { + setValue(optionsList?.[0].value) + setChoosenOption(optionsList?.[0]) } - }, [rendered, value, optionsList, setValue]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [value]) - if (!rendered) return null + if (!rendered) return '' return (
Status
{status.status} {txdata.tx?.date ? timeOrDate(txdata.tx.date, 'ripple') : '-'}{getPaymentType(txdata, rippling)}{getPaymentType(txdata)} {getAllTransactionChanges(balanceChanges, rippling)}{getAllTransactionChanges(txdata, address)}
+ {index + 1} - {typeNode} -
-
- {!rippling && - sourceBalanceChangesList?.map((change, index) => ( -
- {amountFormat(change, { - icon: true, - bold: true, - color: 'direction', - showPlus: true, - short: true - })} -
- ))} -
- {isMobile && ( - <> - {typeNode} -
- {timeFromNow(tx.date, i18n, 'ripple')}, {fullDateAndTime(tx.date, 'ripple')} -
- - )} +
+ + {dateFormat(tx.date, {}, { type: 'ripple' })} + + + {timeFormat(tx.date, 'ripple')} + + 800 ? 800 : '100%', wordBreak: 'break-word' }}> + + Transaction hash: 800 ? 32 : 10} /> + + Type: + {txTypeSpecial || tx?.TransactionType} +
+ {children} + {/* show SourceBalanceChanges like payments for all tx types */} {outcome && !isSuccessful && ( <> Failure: @@ -124,77 +68,52 @@ export const TransactionRowCard = ({ data, address, index, txTypeSpecial, childr
)} - {!rippling && !isConvertion && specification?.destination?.address && ( - <> - {specification?.source?.address === address ? ( - <> - To:{' '} - - {specification?.destination?.address} - {' '} - {' '} - - ) : ( - <> - {specification?.destination?.address === address ? 'From' : 'Submitter'}:{' '} - - {specification?.source?.address} - {' '} - - - )} -
- - )} - {!rippling && isTagValid(tx.DestinationTag) && ( + Fee: + {amountFormat(tx.Fee, { icon: true })} + {nativeCurrencyToFiat({ amount: tx.Fee, selectedCurrency, fiatRate: pageFiatRate })} +
+ {tx.DestinationTag !== undefined && tx.DestinationTag !== null && ( <> - Destination tag: {tx.DestinationTag} + Destination tag: {tx.DestinationTag}
)} - {!rippling && isTagValid(tx.SourceTag) && !dapp && ( + + {tx.TicketSequence && 'Ticket '}Sequence: {tx.Sequence || tx.TicketSequence} + +
+ {(dapp || + (tx?.SourceTag !== undefined && + tx.TransactionType !== 'Payment' && + !tx.TransactionType?.includes('Check'))) && ( <> - Source tag: {tx.SourceTag} -
+ Source tag: + {tx?.SourceTag} )} - {children} - {addressIsSource && ( + {memos && memos.length > 0 && ( <> - {sequence ? ( - <> - {tx.TicketSequence && 'Ticket '}Sequence: {tx.Sequence || tx.TicketSequence} -
- - ) : ( - '' - )} - Fee: {amountFormat(tx.Fee, { icon: true, precise: 'nice' })} - {nativeCurrencyToFiat({ - amount: tx.Fee, - selectedCurrency, - fiatRate: pageFiatRate - })} -
+ {memos.map((memo, idx) => ( +
+ {memo.data ? ( + <> + Memo{memos.length > 1 ? ` (${idx + 1})` : ''}: + {memo.data} + + ) : ( + <> + + {memo.type} + {memos.length > 1 ? ` (${idx + 1})` : ''}: + + {memo.format} + + )} +
+ ))} )} - {memoNode(specification?.memos, 'div')} - Tx hash:{' '} - - {width > 800 ? tx.hash : shortHash(tx.hash, 12)} -
- {timeFromNow(tx.date, i18n, 'ripple')} -
- - {dateFormat(tx.date, {}, { type: 'ripple' })} -
- {timeFormat(tx.date, 'ripple')} -
-
+
diff --git a/pages/account/[id]/transactions.js b/pages/account/[id]/transactions.js index b61a4d840..6ba08e976 100644 --- a/pages/account/[id]/transactions.js +++ b/pages/account/[id]/transactions.js @@ -7,9 +7,9 @@ import { IoMdClose } from 'react-icons/io' import axios from 'axios' import DatePicker from 'react-datepicker' import 'react-datepicker/dist/react-datepicker.css' -import { getIsSsrMobile, useIsMobile } from '../../../utils/mobile' -import { axiosServer, currencyServer, passHeaders } from '../../../utils/axios' -import { addAndRemoveQueryParams, avatarSrc, errorT, isAddressOrUsername, isAddressValid } from '../../../utils' +import { getIsSsrMobile } from '../../../utils/mobile' +import { axiosServer, passHeaders } from '../../../utils/axios' +import { useWidth, addAndRemoveQueryParams, isAddressOrUsername } from '../../../utils' import SEO from '../../../components/SEO' import SearchBlock from '../../../components/Layout/SearchBlock' @@ -37,95 +37,22 @@ import { TransactionRowEnableAmendment, TransactionRowDelegateSet } from '../../../components/Account/Transactions' -import CheckBox from '../../../components/UI/CheckBox' - -const apiUrl = ({ - address, - marker, - order, - type, - initiated, - excludeFailures, - counterparty, - fromDate, - toDate, - filterSpam, - convertCurrency -}) => { - const limit = 20 - let url = `v3/transactions/${address}?limit=${limit}&relevantOnly=true&convertCurrencies=${convertCurrency}` - - if (filterSpam === 'false' || filterSpam === false) { - url += `&filterSpam=false` - } else { - url += `&filterSpam=true` - } - - // pagination marker - if (marker) { - const markerString = typeof marker === 'object' ? JSON.stringify(marker) : marker - url += `&marker=${encodeURIComponent(markerString)}` - } - // sorting - url += `&forward=${order === 'oldest'}` - // filters - if (type && type !== 'all') { - url += `&type=${type}` - } - if (initiated !== undefined && initiated !== null) { - url += `&initiated=${initiated}` - } - if (excludeFailures) { - url += `&excludeFailures=true` - } - if (counterparty) { - url += `&counterparty=${counterparty}` - } - if (fromDate) { - url += `&fromDate=${encodeURIComponent(new Date(fromDate).toISOString())}` - } - if (toDate) { - url += `&toDate=${encodeURIComponent(new Date(toDate).toISOString())}` - } - return url -} export async function getServerSideProps(context) { const { locale, query, req } = context - const { id, fromDate, toDate, type, initiated, excludeFailures, counterparty, order, filterSpam } = query + const { id, fromDate, toDate, txType, initiated, excludeFailures, counterparty, order } = query + const limit = 20 let initialErrorMessage = '' let initialData = null - let initialNoRelevantTransactions = false - const selectedCurrencyServer = currencyServer(req) || 'usd' if (isAddressOrUsername(id)) { - let url = apiUrl({ - address: id, - order, - type, - initiated, - excludeFailures, - counterparty, - fromDate, - toDate, - filterSpam, - convertCurrency: selectedCurrencyServer - }) - try { const res = await axiosServer({ method: 'get', - url, + url: `v3/transactions/${id}?limit=${limit}`, headers: passHeaders(req) }) initialData = res?.data - if (isAddressValid(id) && initialData?.transactions?.length === 0) { - if (!initialData?.marker) { - initialErrorMessage = 'No transactions found for the specified filters.' - } else { - initialNoRelevantTransactions = true - } - } } catch (e) { initialErrorMessage = e?.message || 'Failed to load transactions' } @@ -135,47 +62,38 @@ export async function getServerSideProps(context) { return { props: { - id: id || null, initialData: initialData || null, initialErrorMessage, - initialNoRelevantTransactions, isSsrMobile: getIsSsrMobile(context), fromDateQuery: fromDate || '', toDateQuery: toDate || '', - typeQuery: type || 'all', - initiatedQuery: initiated || null, - excludeFailuresQuery: excludeFailures || null, + txTypeQuery: txType || 'tx', + initiatedQuery: initiated || '0', + excludeFailuresQuery: excludeFailures || '0', counterpartyQuery: counterparty || '', orderQuery: order || 'newest', - filterSpamQuery: filterSpam || 'true', - selectedCurrencyServer, ...(await serverSideTranslations(locale, ['common'])) } } } export default function AccountTransactions({ - id, initialData, initialErrorMessage, - initialNoRelevantTransactions, - selectedCurrency: selectedCurrencyApp, - selectedCurrencyServer, + selectedCurrency, fromDateQuery, toDateQuery, - typeQuery, + txTypeQuery, initiatedQuery, excludeFailuresQuery, counterpartyQuery, - orderQuery, - filterSpamQuery + orderQuery }) { const { t } = useTranslation() + const width = useWidth() const router = useRouter() const firstRenderRef = useRef(true) - const selectedCurrency = selectedCurrencyApp || selectedCurrencyServer - const address = initialData?.address // State management @@ -183,16 +101,14 @@ export default function AccountTransactions({ const [marker, setMarker] = useState(initialData?.marker || null) const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState(initialErrorMessage || '') - const [noRelevantTransactions, setNoRelevantTransactions] = useState(initialNoRelevantTransactions) const [order, setOrder] = useState(orderQuery) // newest | oldest const [filtersHide, setFiltersHide] = useState(false) - const [type, setType] = useState(typeQuery) - const [initiated, setInitiated] = useState(initiatedQuery) // null = both, 'true' = initiated, 'false' = non-initiated - const [excludeFailures, setExcludeFailures] = useState(excludeFailuresQuery) // false = include, true = exclude + const [txType, setTxType] = useState(txTypeQuery) // tx = all types + const [initiated, setInitiated] = useState(initiatedQuery) // 0 = both, 1 = outgoing, 2 = incoming + const [excludeFailures, setExcludeFailures] = useState(excludeFailuresQuery) // 0 = include, 1 = exclude const [counterparty, setCounterparty] = useState(counterpartyQuery) const [fromDate, setFromDate] = useState(fromDateQuery ? new Date(fromDateQuery) : '') const [toDate, setToDate] = useState(toDateQuery ? new Date(toDateQuery) : '') - const [filterSpam, setFilterSpam] = useState(filterSpamQuery) // true = exclude spam, false = include spam // Refresh transactions when order changes useEffect(() => { @@ -204,120 +120,129 @@ export default function AccountTransactions({ setLoading(true) setTransactions([]) setMarker(null) - setNoRelevantTransactions(false) fetchTransactions({ restart: true }) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [order, id]) + }, [order]) // Sync filter changes to URL useEffect(() => { if (router.isReady) { updateURL({ order, - type, + txType, initiated, excludeFailures, counterparty, fromDate: fromDate ? fromDate.toISOString() : '', - toDate: toDate ? toDate.toISOString() : '', - filterSpam: filterSpam ? '' : 'false' + toDate: toDate ? toDate.toISOString() : '' }) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [order, type, initiated, excludeFailures, counterparty, fromDate, toDate, router.isReady, filterSpam]) + }, [order, txType, initiated, excludeFailures, counterparty, fromDate, toDate, router.isReady]) + // Helpers const orderList = [ - { value: 'newest', label: 'Newest first' }, - { value: 'oldest', label: 'Oldest first' } + { value: 'newest', label: 'Newest First' }, + { value: 'oldest', label: 'Oldest First' } ] // transaction type options - const typeOptions = [ - { value: 'all', label: 'All types' }, + const txTypeOptions = [ + { value: 'tx', label: 'All types' }, { value: 'payment', label: 'Payment' }, { value: 'nft', label: 'NFT' }, { value: 'amm', label: 'AMM' }, - { value: 'order', label: 'DEX' }, + { value: 'order', label: 'Order' }, { value: 'escrow', label: 'Escrow' }, { value: 'channel', label: 'Channel' }, { value: 'check', label: 'Check' }, { value: 'trustline', label: 'Trustline' }, { value: 'settings', label: 'Settings' }, - { value: 'accountDelete', label: 'Account delete' } + { value: 'accountDelete', label: 'Account Delete' } ] const initiatedOptions = [ - { value: null, label: 'Incoming & outgoing' }, - { value: true, label: 'Outgoing only' }, - { value: false, label: 'Incoming only' } + { value: '0', label: 'Both directions' }, + { value: '1', label: 'Outgoing' }, + { value: '2', label: 'Incoming' } ] const failuresOptions = [ - { value: null, label: 'Include failed' }, - { value: true, label: 'Exclude failed' } + { value: '0', label: 'Include failed' }, + { value: '1', label: 'Exclude failed' } ] - const fetchTransactions = async (options = {}) => { + // Build API url + const apiUrl = (opts = {}) => { + const limit = 20 + let url = `v3/transactions/${address}?limit=${limit}` + // pagination marker + if (opts.marker) { + const markerString = typeof opts.marker === 'object' ? JSON.stringify(opts.marker) : opts.marker + url += `&marker=${encodeURIComponent(markerString)}` + } + // sorting + url += `&forward=${order === 'oldest'}` + // filters + if (txType && txType !== 'tx') { + url += `&type=${txType}` + } + if (initiated === '1') { + url += `&initiated=true` + } else if (initiated === '2') { + url += `&initiated=false` + } + + if (excludeFailures === '1') { + url += `&excludeFailures=1` + } + if (counterparty) { + url += `&counterparty=${encodeURIComponent(counterparty.trim())}` + } + if (fromDate) { + url += `&fromDate=${encodeURIComponent(fromDate.toISOString())}` + } + if (toDate) { + url += `&toDate=${encodeURIComponent(toDate.toISOString())}` + } + return url + } + + const fetchTransactions = async (opts = {}) => { if (loading) return let markerToUse = undefined - if (!options.restart) { - markerToUse = options.marker || marker + if (!opts.restart) { + markerToUse = opts.marker || marker } try { - const response = await axios.get( - apiUrl({ - marker: markerToUse, - address, - order, - type, - initiated, - excludeFailures, - counterparty, - fromDate, - toDate, - filterSpam, - convertCurrency: selectedCurrency - }) - ) + const response = await axios.get(apiUrl({ marker: markerToUse })) if (response?.data?.status === 'error') { setErrorMessage(response?.data?.error) setLoading(false) return } - const newData = response?.data?.transactions || [] + const newData = response?.data?.transactions || response?.data || [] const newMarker = response?.data?.marker || null - if (newData?.length === 0 && newMarker) { - setNoRelevantTransactions(true) - } - if (markerToUse && transactions.length > 0) { - // adding data to existing list - if (newData.length > 0) { - const combined = [...transactions, ...newData] - setTransactions(combined) - } + // pagination – append + const combined = [...transactions, ...newData] + setTransactions(combined) } else { - if (newData.length === 0 && !newMarker) { - setErrorMessage('Account has no transactions with the specified filters.') - setMarker(null) - setLoading(false) - return - } else { - setTransactions(newData) - } + setTransactions(newData) } setMarker(newMarker) setErrorMessage('') } catch (e) { - setErrorMessage(t('error.' + e?.message) || 'Failed to load transactions') + setErrorMessage(e?.message || 'Failed to load transactions') } setLoading(false) } + // CSV headers (basic) const csvHeaders = [ { label: 'Date', key: 'date' }, { label: 'Time', key: 'time' }, @@ -351,14 +276,7 @@ export default function AccountTransactions({ // Process each filter Object.keys(newFilters).forEach((key) => { const value = newFilters[key] - if ( - value !== undefined && - value !== null && - value !== '' && - value !== '0' && - value !== 'all' && - value !== 'newest' - ) { + if (value && value !== '' && value !== '0' && value !== 'tx' && value !== 'newest') { addList.push({ name: key, value }) } else { removeList.push(key) @@ -368,21 +286,19 @@ export default function AccountTransactions({ addAndRemoveQueryParams(router, addList, removeList) } - const isMobile = useIsMobile(600) - return ( <> + { let dateObj = new Date() if (item.outcome.timestamp) { @@ -409,15 +326,33 @@ export default function AccountTransactions({ filtersHide={filtersHide} setFiltersHide={setFiltersHide} > + {/* Left filters placeholder – can be extended later */} <>
- +
+ Type + +

- +
+ Direction + +

- +
+ Failures + +

- +
+ Counterparty + +

From @@ -463,12 +398,8 @@ export default function AccountTransactions({ )}
- - Exclude spam transactions - -
-
@@ -476,86 +407,65 @@ export default function AccountTransactions({ {/* Main content */} <> + {errorMessage &&
{errorMessage}
} { - if (marker && marker !== 'first' && !noRelevantTransactions) { + if (marker && marker !== 'first') { fetchTransactions({ marker }) } }} - hasMore={marker && !noRelevantTransactions} - errorMessage={ - noRelevantTransactions ? ( - <> - It takes too long to find relevant transactions. Searched up to ledger{' '} - {marker?.ledger}. -
-
- - - ) : ( - errorT(t, errorMessage) - ) - } + hasMore={marker} + errorMessage={errorMessage} subscriptionExpired={false} sessionToken={true} > -
#
+
600 ? 'table-large' : 'table-mobile'}> - {loading && (!marker || marker === 'first') ? ( + {loading ? ( ) : ( - transactions.map((tx, index) => { + transactions?.map((tx, index) => { let TransactionRowComponent = null - const type = tx?.tx?.TransactionType + const txType = tx?.tx?.TransactionType - if (type === 'AccountDelete') { + if (txType === 'AccountDelete') { TransactionRowComponent = TransactionRowAccountDelete - } else if (type === 'AccountSet') { + } else if (txType === 'AccountSet') { TransactionRowComponent = TransactionRowAccountSet - } else if (type?.includes('AMM')) { + } else if (txType?.includes('AMM')) { TransactionRowComponent = TransactionRowAMM - } else if (type?.includes('Check')) { + } else if (txType?.includes('Check')) { TransactionRowComponent = TransactionRowCheck - } else if (type?.includes('Escrow')) { + } else if (txType?.includes('Escrow')) { TransactionRowComponent = TransactionRowEscrow - } else if (type === 'Import') { + } else if (txType === 'Import') { TransactionRowComponent = TransactionRowImport - } else if (type?.includes('NFToken')) { + } else if (txType?.includes('NFToken')) { TransactionRowComponent = TransactionRowNFToken - } else if (type === 'OfferCreate' || type === 'OfferCancel') { + } else if (txType === 'OfferCreate' || txType === 'OfferCancel') { TransactionRowComponent = TransactionRowOffer - } else if (type === 'Payment') { + } else if (txType === 'Payment') { TransactionRowComponent = TransactionRowPayment - } else if (type === 'SetRegularKey') { + } else if (txType === 'SetRegularKey') { TransactionRowComponent = TransactionRowSetRegularKey - } else if (type === 'DelegateSet') { + } else if (txType === 'DelegateSet') { TransactionRowComponent = TransactionRowDelegateSet - } else if (type === 'TrustSet') { + } else if (txType === 'TrustSet') { TransactionRowComponent = TransactionRowTrustSet - } else if (type?.includes('DID')) { + } else if (txType?.includes('DID')) { TransactionRowComponent = TransactionRowDID - } else if (type?.includes('URIToken')) { + } else if (txType?.includes('URIToken')) { TransactionRowComponent = TransactionRowURIToken - } else if (type === 'Remit') { + } else if (txType === 'Remit') { TransactionRowComponent = TransactionRowRemit - } else if (type === 'EnableAmendment') { + } else if (txType === 'EnableAmendment') { TransactionRowComponent = TransactionRowEnableAmendment } else { TransactionRowComponent = TransactionRowDetails @@ -563,7 +473,7 @@ export default function AccountTransactions({ return ( { setErrorMessage(t('error.' + error.message)) }) - const data = response?.data + const data = response.data if (data) { updateBid(data) } diff --git a/pages/amendments.js b/pages/amendments.js index a4052f354..bcadf4fa8 100644 --- a/pages/amendments.js +++ b/pages/amendments.js @@ -25,7 +25,7 @@ export const getServerSideProps = async (context) => { const amendmentLink = (a, options) => { let name = options?.short ? shortName(a.name, { maxLength: xahauNetwork ? 12 : 18 }) : a.name - return {name || shortHash(a.amendment)} + return {name || shortHash(a.amendment)} } export default function Amendment() { diff --git a/pages/amm/[id].js b/pages/amm/[id].js index 2a1bd1e69..a0fd7b832 100644 --- a/pages/amm/[id].js +++ b/pages/amm/[id].js @@ -15,8 +15,7 @@ import { trAmountWithGateway, showAmmPercents, timeFromNow, - AddressWithIconFilled, - CurrencyWithIcon + AddressWithIconFilled } from '../../utils/format' import { LinkTx } from '../../utils/links' import DatePicker from 'react-datepicker' @@ -259,11 +258,12 @@ export default function Amm({ id, initialData, initialErrorMessage, ledgerTimest - - - - diff --git a/pages/amms.js b/pages/amms.js index daac6aadb..ac989fc88 100644 --- a/pages/amms.js +++ b/pages/amms.js @@ -17,8 +17,8 @@ import { amountFormat, nativeCurrencyToFiat, AddressWithIcon, - niceCurrency, - CurrencyWithIcon + AddressWithIconFilled, + niceCurrency } from '../utils/format' import TokenSelector from '../components/UI/TokenSelector' @@ -122,9 +122,7 @@ export default function Amms({ const [rawData, setRawData] = useState(initialData || {}) const [order, setOrder] = useState(orderQuery) const [loading, setLoading] = useState(false) - const [errorMessage, setErrorMessage] = useState( - t(`error.${initialErrorMessage}`, { defaultValue: initialErrorMessage }) || '' - ) + const [errorMessage, setErrorMessage] = useState(initialErrorMessage || '') const [marker, setMarker] = useState(initialData?.marker) const [filtersHide, setFiltersHide] = useState(false) const [token, setToken] = useState({ @@ -164,7 +162,6 @@ export default function Amms({ let markerPart = '' if (loadMoreRequest) { - if (!rawData?.marker) return markerPart = '&marker=' + rawData?.marker } @@ -264,9 +261,12 @@ export default function Amms({ const LPToken = ({ a }) => { return ( - { - if (token?.currency === currencyQuery && token?.issuer === currencyIssuerQuery) { - return - } - setToken({ - currency: currencyQuery || nativeCurrency, - issuer: currencyIssuerQuery || null, - currencyDetails: null - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currencyQuery, currencyIssuerQuery]) const [data, setData] = useState(initialData || []) const [rawData, setRawData] = useState(initialRawData || {}) @@ -316,7 +298,12 @@ export default function Distribution({ selectedCurrency, fiatRate, initialRawDat t('general.loading') ) : token?.issuer ? ( <> - +
Total supply: {niceNumber(rawData?.summary?.totalCoins || 0)} {currency}
diff --git a/pages/explorer/[slug].js b/pages/explorer/[slug].js deleted file mode 100644 index 187309fd5..000000000 --- a/pages/explorer/[slug].js +++ /dev/null @@ -1,102 +0,0 @@ -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import { useTranslation, Trans } from 'next-i18next' -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' -import Link from 'next/link' -import { isAddressOrUsername, isIdValid, isLedgerIndexValid, isValidCTID, performIdSearch } from '../../utils' - -const slugRegex = /^[~]{0,1}[a-zA-Z0-9-_.]*[+]{0,1}[a-zA-Z0-9-_.]*[$]{0,1}[a-zA-Z0-9-.]*[a-zA-Z0-9]*$/i -const forbiddenSlugsRegex = /^.((?!\$).)*.?\.(7z|gz|rar|tar)$/i - -export async function getStaticProps({ locale }) { - return { - props: { - ...(await serverSideTranslations(locale, ['common'])) - } - } -} - -export const getStaticPaths = async () => { - return { - paths: [], - fallback: 'blocking' - } -} - -export default function ExplorerRedirect() { - const router = useRouter() - const { t } = useTranslation() - const { slug } = router.query - const [errorMessage, setErrorMessage] = useState('') - const [processing, setProcessing] = useState(true) - - useEffect(() => { - if (!router.isReady) return - if (typeof slug !== 'string') { - setProcessing(false) - return - } - - const performIdSearching = async ({ searchFor }) => { - await performIdSearch({ searchFor, router, setErrorMessage }) - } - - if (slugRegex.test(slug)) { - if (forbiddenSlugsRegex.test(slug)) { - window.location.href = '/404' - return - } - - if (isIdValid(slug)) { - performIdSearching({ searchFor: slug }) - return - } - - if (isValidCTID(slug)) { - router.replace('/tx/' + slug) - return - } - - if (isLedgerIndexValid(slug)) { - router.replace('/ledger/' + slug) - return - } - - if (isAddressOrUsername(slug)) { - router.replace('/account/' + encodeURI(slug)) - return - } - } - - setProcessing(false) - }, [router.isReady, slug, router]) - - if (processing) { - return ( -
-
- -
- {t('general.loading')} -
-
-
- ) - } - - return ( -
-

{t('page-not-found.header')}

- {errorMessage &&

{errorMessage}

} -

- - Click{' '} - - here - {' '} - to check our landing page. - -

-
- ) -} diff --git a/pages/explorer/index.js b/pages/explorer2.js similarity index 76% rename from pages/explorer/index.js rename to pages/explorer2.js index ef2bd79be..50f08ceda 100644 --- a/pages/explorer/index.js +++ b/pages/explorer2.js @@ -3,14 +3,14 @@ import { useTranslation } from 'next-i18next' import Head from 'next/head' import Link from 'next/link' -import { server, explorerName, nativeCurrency, network } from '../../utils' -import { getIsSsrMobile } from '../../utils/mobile' +import { server, explorerName, nativeCurrency, network } from '../utils' +import { getIsSsrMobile } from '../utils/mobile' -import SEO from '../../components/SEO' -import SearchBlock from '../../components/Layout/SearchBlock' -import Ads from '../../components/Layout/Ads' -import CopyButton from '../../components/UI/CopyButton' -import { shortHash } from '../../utils/format' +import SEO from '../components/SEO' +import SearchBlock from '../components/Layout/SearchBlock' +import Ads from '../components/Layout/Ads' +import CopyButton from '../components/UI/CopyButton' +import { shortHash } from '../utils/format' export async function getServerSideProps(context) { const { locale } = context @@ -87,18 +87,6 @@ const examples = { object: null }, - alphanet: { - nft: '000900007CDA3D523C8D4CA25F55439D447FBF4D4F26AC3B82C9E47C005429E1', - amm: '33072CA199E75633CD9C174D9DC731C773303A834AF4B3FF8EB28BE30EAA0AE1', - txHash: '100D2346C65FF4C681B5AD805EC54419FF38ECDD824006D0E050D2A68808475B', - txCTID: 'C0546A8800120002', - account: 'rh1HPuRVsYYvThxG2Bs1MfjmrVC73S16Fb', - payString: ['gemtesting$dev.bithomp.com', 'mainfortesting$dev.bithomp.com'], - xAddress: null, - username: ['xrpdomains'], - object: null - }, - xahau: { nft: 'CE67EA90A55AACD603B5B44C56B44A56D9FA792EB8E872638FF570B31F0ED143', amm: null, // not enabled on xahau @@ -187,46 +175,36 @@ export default function Explorer({ isSsrMobile, showAds }) { with such domains) Verify your domain.

- {examples[network]?.xAddress && ( - <> - X-Address example: {shortingHash(examples[network]?.xAddress)} - -
-
- - )} - {examples[network]?.payString?.[0] && ( - <> - PayString example: {examples[network]?.payString?.[0]}{' '} - , {examples[network]?.payString?.[1]}{' '} - Get your PayString. -
-
- - )} + X-Address example: {shortingHash(examples[network]?.xAddress)}{' '} + +
+
+ PayString example: {examples[network]?.payString?.[0]}{' '} + , {examples[network]?.payString?.[1]}{' '} + Get your PayString. +
+

Transaction

CTID (compact transaction ID) example: {examples[network]?.txCTID}{' '}

- Transaction Hash example: {shortingHash(examples[network]?.txHash)} + Transaction Hash example: {shortingHash(examples[network]?.txHash)}{' '}

NFT, {examples[network]?.amm && 'AMM, '}Object

- NFT example: {shortingHash(examples[network]?.nft)} - + NFT example: {shortingHash(examples[network]?.nft)}

{examples[network]?.amm && ( <> - AMM example: {shortingHash(examples[network]?.amm)} - + AMM example: {shortingHash(examples[network]?.amm)}

)} - Object example: {shortingHash(examples[network]?.object)} + Object example: {shortingHash(examples[network]?.object)}{' '}

diff --git a/pages/faucet.js b/pages/faucet.js index 1ecceb936..4c256de1a 100644 --- a/pages/faucet.js +++ b/pages/faucet.js @@ -51,7 +51,7 @@ export default function FaucetPage({ account, showAds, sessionTokenData }) { return ( <> diff --git a/pages/learn/guide-for-token-issuers.js b/pages/learn/guide-for-token-issuers.js index 86419eca4..1bdf2aa59 100644 --- a/pages/learn/guide-for-token-issuers.js +++ b/pages/learn/guide-for-token-issuers.js @@ -1,7 +1,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import SEO from '../../components/SEO' import { getIsSsrMobile } from '../../utils/mobile' -import { network, server, siteName } from '../../utils' +import { network, server } from '../../utils' import { explorerName, xahauNetwork } from '../../utils' import Link from 'next/link' import Image from 'next/image' @@ -51,8 +51,9 @@ export default function GuideForTokenIssuers() {

So, you’ve successfully created your token on the {explorerName}. What’s next? If you want your token to - look professional, gain more trust from users, and be discoverable on {siteName} or other platforms which - are using our API, there are several important steps the issuer should take: + look professional, gain more trust from users, and be discoverable on{' '} + {xahauNetwork ? 'Xahau Explorer' : 'Bithomp'} or other platforms which are using our API, there are{' '} + several important steps the issuer should take:

A public username makes it easier for users to recognize your project.

diff --git a/pages/learn/index.js b/pages/learn/index.js index 3000387b2..3a6a5b1ca 100644 --- a/pages/learn/index.js +++ b/pages/learn/index.js @@ -28,7 +28,8 @@ const buildLearnContent = () => { items: [ { title: 'Blackholed Address', slug: 'blackholed-address' }, { title: 'Blacklisted Address', slug: 'blacklisted-address' }, - { title: 'Verified Domain', slug: 'verified-domain' } + { title: 'Verified Domain', slug: 'verified-domain' }, + { title: 'PayStrings', slug: 'paystrings' } ] }, { @@ -44,9 +45,7 @@ const buildLearnContent = () => { title: 'Guide for Token Issuers: Username, Toml file, Project Registration', slug: 'guide-for-token-issuers' }, - { title: 'Bithomp Image Services', slug: 'image-services' }, - { title: 'Understanding Trustlines', slug: 'trustlines' }, - { title: 'NFT Explorer', slug: 'nft-explorer' } + { title: 'Bithomp Image Services', slug: 'image-services' } ] } ] diff --git a/pages/learn/nft-explorer.js b/pages/learn/nft-explorer.js deleted file mode 100644 index 4fadb4bc2..000000000 --- a/pages/learn/nft-explorer.js +++ /dev/null @@ -1,237 +0,0 @@ -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' -import SEO from '../../components/SEO' -import { getIsSsrMobile } from '../../utils/mobile' -import { network } from '../../utils' -import { nativeCurrency, explorerName, xahauNetwork } from '../../utils' -import Link from 'next/link' -import Image from 'next/image' -import Breadcrumbs from '../../components/Breadcrumbs' - -export async function getServerSideProps(context) { - const { locale } = context - return { - props: { - isSsrMobile: getIsSsrMobile(context), - ...(await serverSideTranslations(locale, ['common'])) - } - } -} - -export default function NftExplorer() { - return ( - <> - -

- -
-

- {' '} - {xahauNetwork ? 'Xahau Explorer' : 'Bithomp'} — The Best Way to Explore {explorerName} NFTs{' '} -

-
-
- -
{explorerName} NFT Explorer
-
-
-

- We started Bithomp to make the {explorerName} more open and easy to explore. Over time, NFTs became an - important part of that story — and we wanted to give them the same level of visibility and detail. That’s - how our {xahauNetwork ? 'Xahau' : 'XRPL'} NFT Explorer came to life — - built for everyone who creates, collects, or just loves {explorerName} NFTs - built for the community. -

-

What we offer and what makes our {explorerName} NFT explorer unique

-

One place for every type of NFT

-

- No matter where an NFT was minted or which marketplace it belongs to, you can find it on Bithomp. We - showcase all types of {xahauNetwork ? 'Xahau' : 'XRPL'} NFTs — with or without images, including music, - videos, animated 3D models, panoramic views, and more. -

- {!xahauNetwork && ( -
-

- NFT with music and video -
- - View NFT - -

- -

- 360° panoramic NFTs -
- - View NFT - -

- -

- Animated NFTs -
- - View NFT - -

-
- )} -

Sales History and Validated Offers

-

- Every NFT has a story, and we make it easy to follow. You can explore the complete sales history — including - when and where it was minted, sold, or transferred — and view validated buy and sell offers showing where - and at what price it can be purchased. Whether you’re tracking price trends or simply curious about a - specific NFT or collection, all the information is just one click away. -

-
-
- -
{explorerName} NFT sales history and offers
-
-
-

Instant Media Display

-

- Browsing NFTs should be quick and effortless. We cache images and video files to make viewing almost - instantaneous — even when you open large collections or high-resolution assets. It feels quick and - responsive, just as it should. -

-

Find Any {explorerName} NFT in Seconds

-

- Looking for a specific NFT on {xahauNetwork ? 'Xahau' : 'XRPL'}? With our {xahauNetwork ? 'Xahau' : 'XRPL'}{' '} - NFT Explorer, it’s incredibly easy. Our advanced filters and sorting tools help you find exactly what you - need — fast. -

-
-
- -
{explorerName} NFT Explorer
-
-
-

You can:

-
    -
  • Search NFTs by name across all NFTs ever minted on the {explorerName}
  • -
  • Search NFTs by issuer or owner
  • -
  • Filter NFTs by the minting date or a specific time period
  • -
  • Sort by listing time — from the oldest to the newest offers
  • -
  • Exclude or include burned NFTs or NFTs without media
  • -
  • Discover the most viewed NFTs on our explorer
  • -
-

- Whether you’re hunting for a particular collection, exploring new listings, or analyzing popular NFTs, our - explorer makes the search effortless and intuitive. -

-

Data Transparency and Exports

-

- If you enjoy digging deeper, we’ve got you covered. You can export NFT metadata and all related attributes - to CSV, making it easy to analyze, track, or build on top of {explorerName} NFT data. For developers, our - API includes dedicated NFT-related endpoints. -

-
-

- - 👉 - {' '} - Learn more in our documentation -

-
-

Manage Your {xahauNetwork ? 'Xahau' : 'XRPL'} NFTs — All in One Place

-

- With {xahauNetwork ? 'Xahau Explorer' : 'Bithomp'}, you can do much more than explore. Our NFT tools let you - mint, trade, and manage your {explorerName} NFTs directly from the same interface — quickly, securely, and - without intermediaries. -

-

Here’s what you can do right on {xahauNetwork ? 'Xahau Explorer' : 'Bithomp'}:

-
-
- -
{explorerName} Manage your NFTs
-
-
-
    -
  • - Mint new NFTs on {explorerName} — including mint and list for sale in one transaction - {xahauNetwork && ', or mint and send with Remit'} -
  • -
    -

    - - 👉 - {' '} - Mint {explorerName} NFTs here -

    -
    - -
  • Buy NFTs from existing offers
  • -
  • List your NFTs for sale — for {nativeCurrency} or tokens
  • -
  • Make, accept, or cancel offers
  • -
  • Transfer NFTs between wallets
  • - - {!xahauNetwork && ( - <> -
  • Modify the URI if the NFT is mutable (Dynamic NFTs have the "mutable" flag enabled")
  • - - )} - -
  • Burn NFTs you no longer need
  • -
  • Set your NFT as your avatar on your {xahauNetwork ? 'Xahau Explorer' : 'Bithomp'} profile
  • -
-

- 🔥 And the best part — you’re not limited to one wallet. You can connect using Ledger, Xaman, Gem Wallet, - MetaMask, Crossmark, and more. -

- ❤️ Explore {xahauNetwork ? 'Xahau' : 'XRPL'} NFTs the smart way — with{' '} - {xahauNetwork ? 'Xahau Explorer' : 'Bithomp'} -
-
-
-
- - ) -} diff --git a/pages/learn/paystrings.js b/pages/learn/paystrings.js new file mode 100644 index 000000000..52efb5d75 --- /dev/null +++ b/pages/learn/paystrings.js @@ -0,0 +1,85 @@ +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' +import SEO from '../../components/SEO' +import { getIsSsrMobile } from '../../utils/mobile' +import { network } from '../../utils' +import { nativeCurrency, explorerName, xahauNetwork } from '../../utils' +import Link from 'next/link' +import Image from 'next/image' +import Breadcrumbs from '../../components/Breadcrumbs' + +export async function getServerSideProps(context) { + const { locale } = context + return { + props: { + isSsrMobile: getIsSsrMobile(context), + ...(await serverSideTranslations(locale, ['common'])) + } + } +} + +const pagePath = '/images/' + (xahauNetwork ? 'xahau' : 'xrpl') + 'explorer/learn/paystrings/' + +export default function Paystrings() { + return ( + <> + +
+ +
+

PayStrings on {explorerName}.

+
+
+ +
PayStrings on {explorerName}
+
+
+

+ If you’ve ever tried sending crypto, you know how confusing wallet addresses can be — long strings of random + letters and numbers that are easy to mistype. PayString solves this problem by replacing those complex + addresses with simple, human-readable names. +

+

What is Paystring and how it works on {explorerName}

+

+ When someone sends {nativeCurrency} or tokens to your PayString, it automatically routes the payment to your + linked {explorerName} address. This makes transactions faster, safer, and easier to share. Your PayString + becomes your universal identity on {explorerName} — the name that connects to your wallet. +

+

+ Instead of sending {nativeCurrency} to a long address, you can use something like{' '} + {xahauNetwork ? 'mainfortesting$xahauexplorer.com' : 'love0139$bithomp.com'} or{' '} + {xahauNetwork ? 'drewrobertslive$xahauexplorer.com' : 'kingkong$bithomp.com'}. +

+

Get your PayString on Bithomp

+
+

+ + 👉 + {' '} + Here, you can easily register your PayString (Bithomp username) +

+
+ Once registered, your PayString is linked to your {explorerName} address, allowing you to: +
    +
  • Receive {nativeCurrency} with a name instead of a long wallet address
  • +
  • Make deposits and withdrawals on exchanges that support PayString
  • +
+

Make your {explorerName} payments easy and personal.

+
+
+
+
+ + ) +} diff --git a/pages/learn/the-bithomp-explorer-advantages.js b/pages/learn/the-bithomp-explorer-advantages.js index 2fa695725..74177e89b 100644 --- a/pages/learn/the-bithomp-explorer-advantages.js +++ b/pages/learn/the-bithomp-explorer-advantages.js @@ -123,7 +123,7 @@ export default function UnderstandingTheBithompExplorer() {
  • Live balance updates
  • Instant offer and NFT listing tracking
  • -

    5. Support for Mainnet, Devnet, AlphaNet and Testnet

    +

    5. Support for Mainnet, Devnet, and Testnet

    Developers working on new tools or testing integrations often need to switch between networks. Many explorers only support mainnet, limiting their usefulness. @@ -150,11 +150,6 @@ export default function UnderstandingTheBithompExplorer() { XRPL Devnet -

  • - - XRPL AlphaNet - -
  • XAHAU Testnet diff --git a/pages/learn/trustlines.js b/pages/learn/trustlines.js deleted file mode 100644 index 6fd6e4f17..000000000 --- a/pages/learn/trustlines.js +++ /dev/null @@ -1,254 +0,0 @@ -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' -import SEO from '../../components/SEO' -import { getIsSsrMobile } from '../../utils/mobile' -import { ledgerName, network, siteName } from '../../utils' -import { nativeCurrency, explorerName, xahauNetwork } from '../../utils' -import Link from 'next/link' -import Image from 'next/image' -import Breadcrumbs from '../../components/Breadcrumbs' - -export async function getServerSideProps(context) { - const { locale } = context - return { - props: { - isSsrMobile: getIsSsrMobile(context), - ...(await serverSideTranslations(locale, ['common'])) - } - } -} - -export default function IssueAToken() { - const imagePath = '/images/' + (xahauNetwork ? 'xahau' : 'xrpl') + 'explorer/learn/trustlines/' - return ( - <> - -
    - -
    -

    Trustlines on {explorerName}

    -
    -
    - -
    Set Trustline on {explorerName}
    -
    -
    -

    - In the {ledgerName} ecosystem, trustlines are one of the most important concepts — especially for anyone - working with issued tokens (IOUs). If you want to hold tokens on {explorerName}, you must first create a - trustline. In this guide, we’ll explain what a trustline is, why trustlines matter, and how to add it in - just a few clicks using {siteName}. -

    -

    What Is a Trustline on {ledgerName} ?

    -

    - A trustline on the {ledgerName} is a connection between two accounts that specifies the maximum amount of an - issued asset (IOU) one account is willing to hold from a particular issuer. -

    -
      - A trustline tells the ledger two things: -
    • Which issuer you trust to hold IOUs from
    • -
    • How much of that issued token you are willing to hold
    • -
    -

    - Trustlines protect you by preventing anyone from sending you ‘spam’ tokens. Without an approved trustline, - issued tokens cannot appear on your balance. -

    -

    Why Trustlines Are Important

    -
      - Trustlines help maintain: -
    • Control — you define limits for how much of a token you’re willing to accept.
    • -
    • Transparency — you always know which assets your wallet interacts with.
    • -
    • Stability — they prevent “token flooding” and wallet spam common in other networks.
    • -
    -

    Setting Up {ledgerName} Trustlines

    -
    -

    - - 👉 - {' '} - Here you can add a trustline to any {ledgerName} token -

    -
    -

    - In this simple mode you just need to choose the required token from the drop-down list and sign the - transaction. The Limit will be set to the total supply.{' '} -

    -
    -
    - -
    Set Trustline on {explorerName}
    -
    -
    - If you need more control over your trustline settings — for example, changing the limit or enabling/disabling - specific flags such as Rippling, Freeze, Deep Freeze, and others — you can switch to our Advanced Mode. -

    - In Advanced Mode, you can customize your trustline and - even create a trustline for a token that doesn’t exist yet. This is useful if you're willing to issue a new - token on {ledgerName}. -

    -
    -
    - -
    Customize Trustline on {explorerName}
    -
    -
    -

    - If you're planning to launch your own token, you can follow our{' '} - step-by-step guide on how to issue a token on {explorerName}. -

    -

    Trustline Flags Explained

    -

    - When setting a trustline through Advanced Mode, you may need to adjust specific trustline flags or - parameters. These flags control how your issued tokens behave and how other accounts can interact with them. - Here’s a clear explanation of each option: -

    -

    Rippling

    -

    Controls the indirect movement of funds across trustlines.

    -

    - Recommended: Disable unless you are a token issuer managing liquidity or advanced routing. -

    -

    - When disabled, your balance cannot be used to “ripple through” to facilitate exchanges between other - trustlines. -

    -

    Freeze

    -

    - Prevents the counterparty from sending the frozen currency to other users, but they can still return the - tokens to the issuer. -

    -

    Useful for controlling misuse or suspicious activity.

    -

    Can be reversed.

    -

    Deep Freeze

    -

    A stronger version of Freeze.

    -

    The counterparty cannot receive any additional funds until the trustline is unfrozen.

    -

    Requires a standard Freeze to be applied first.

    -

    - Cannot be used if the issuer has enabled No Freeze on their account. -

    -

    Authorize

    -

    Grants explicit permission for a counterparty to hold the currency issued by your account.

    -

    Required for authorized tokens, often used by financial institutions or compliance-focused projects.

    -

    Once authorization is enabled on a trustline, it cannot be revoked.

    -

    Quality Settings (QualityIn and QualityOut)

    -

    - Quality settings define the exchange rate for a trustline and determine how much of the asset is transferred - during incoming or outgoing transactions. -

    -
    QualityIn
    -

    Percentage of incoming funds retained by the sender.

    -

    - Example: If QualityIn is set to 1%, then when someone sends you 100 units, 1 unit is kept and you - receive 99. -

    -
    QualityOut
    -

    Percentage of outgoing funds kept by the issuer.

    -

    - Example: If QualityOut is set to 1%, sending 100 units results in the recipient receiving 99, while - 1 unit is retained. -

    -

    - These are not token transfer fees — they are part of {ledgerName}'s built-in trustline - quality mechanics and affect exchange rates rather than applying a fee to the transaction. A default value - of 0 means the token is exchanged at face value, with no percentage retained. -

    -

    Share Button — Send Ready-to-Use Trustline Links

    -

    Share Trustlines Easily

    -

    - If you’re a token issuer, community manager, developer, or simply helping someone set up a wallet, the{' '} - Share button will save you time. -

    -

    With one click, you can:

    -
      -
    • Generate a link to a prefilled trustline,
    • -
    • Share it with a user,
    • -
    • And they’ll open a ready-to-submit trustline form instantly.
    • -
    -

    No manual typing, no mistakes — just fast and accurate onboarding.

    -

    Why Use {siteName} for Trustlines?

    -
      -
    • Fast trustline creation for any token
    • -
    • Sign transactions with Ledger, Xaman, Gem Wallet, MetaMask, and more
    • -
    • Beginner-friendly interface
    • -
    • Advanced settings for experienced users
    • -
    • Easy sharing with auto-generated links
    • -
    -

    - {siteName} offers the fastest and most user-friendly way to add trustlines on {explorerName} — from simple - mode to advanced flag settings and shareable trustline links. Whether you're a beginner or an experienced - issuer, {siteName} gives you all the tools you need to manage trustlines securely. -

    -

    FAQ

    -

    Do I need a trustline to hold any {explorerName} token on my account?

    -

    Yes. Without a trustline, your wallet can't hold any incoming issued token (IOU).

    -

    Can I remove or edit a trustline later?

    -

    Yes.

    -
      -
    • You can update the trustline limit or enable/disable flags at any time.
    • -
    • - To completely remove a trustline, the balance must be 0 and the settings reset to - default. -
    • -
    • - If the balance is not 0, you can still “burn” remaining tokens by sending them back to the issuer. Once - the balance reaches 0 and the settings are reset, the trustline can be removed. -
    • -
    • - When a trustline is removed, the reserved {nativeCurrency} is released back to your available balance. -
    • -
    -

    Does creating a trustline cost {nativeCurrency}?

    -

    Yes.

    -
      -
    • - Each trustline requires an owner reserve of 0.2 {nativeCurrency}. -
    • -
    • This amount is not spent — it is simply locked while the trustline exists.
    • -
    • - For new accounts, {xahauNetwork ? 'Xahau' : 'XRPL'} provides a “trustline credit”: your first two - trustlines do not immediately require additional {nativeCurrency} from your balance. -
    • -
    • - Note: this is a credit, not a free gift — when you create a third trustline, the reserve must be paid - upfront. -
    • -
    • - When you delete a trustline, the 0.2 {nativeCurrency} reserve is released back to your usable balance. -
    • -
    -
    -
    -
    -
    - - ) -} diff --git a/pages/mpts.js b/pages/mpts.js index 410ac1f62..b9369c351 100644 --- a/pages/mpts.js +++ b/pages/mpts.js @@ -12,10 +12,11 @@ import { fullNiceNumber, niceNumber, shortNiceNumber, + AddressWithIconFilled, dateFormat, timeFormat, timeFromNow, - CurrencyWithIcon + showFlags } from '../utils/format' import { axiosServer, passHeaders } from '../utils/axios' import { getIsSsrMobile } from '../utils/mobile' @@ -142,7 +143,17 @@ const orderList = [ // Helper component to render token with icon const TokenCell = ({ token }) => { if (!token) return 'N/A' - return + return ( + + ) } export default function Mpts({ @@ -162,11 +173,9 @@ export default function Mpts({ const [data, setData] = useState(initialData?.issuances || []) const [rawData, setRawData] = useState(initialData || {}) - const [marker, setMarker] = useState(initialData?.marker || '') + const [marker, setMarker] = useState(initialData?.marker) const [loading, setLoading] = useState(false) - const [errorMessage, setErrorMessage] = useState( - t(`error.${initialErrorMessage}`, { defaultValue: initialErrorMessage }) || '' - ) + const [errorMessage, setErrorMessage] = useState(initialErrorMessage || '') const [order, setOrder] = useState(orderQuery || 'holdersHight') //'rating const [filtersHide, setFiltersHide] = useState(false) const [issuer, setIssuer] = useState(issuerQuery) @@ -213,8 +222,7 @@ export default function Mpts({ let markerPart = '' if (loadMoreRequest) { - if (!rawData?.marker) return - markerPart = '&marker=' + rawData.marker + markerPart = '&marker=' + rawData?.marker } if (!markerPart) { @@ -502,6 +510,8 @@ export default function Mpts({
  • -
    -

    -
    + {t('general.loading')}
    LP Token - -
    AMM address -
    {i + 1} +
    + {showFlags(token.flags)}
    @@ -553,7 +563,7 @@ export default function Mpts({
    - +
    {loading ? ( @@ -582,6 +592,8 @@ export default function Mpts({

    + {showFlags(token.flags)} +
    MPT ID:
    Holders:{' '} @@ -621,6 +633,26 @@ export default function Mpts({ ) : ( '' )} + {token.metadata?.weblinks && token.metadata?.weblinks.length > 0 ? ( + <> +
    + {token.metadata.weblinks.map((link, index) => ( + + + {link} + +
    +
    + ))} + + ) : ( + '' + )}
    Transfer fee: {token.transferFee ? token.transferFee / 1000 + '%' : 'none'}
    diff --git a/pages/nft-collection/[id].js b/pages/nft-collection/[id].js index 36154bcd3..634874404 100644 --- a/pages/nft-collection/[id].js +++ b/pages/nft-collection/[id].js @@ -13,15 +13,14 @@ import { timeFromNow, AddressWithIconInline } from '../../utils/format' -import { getIsSsrMobile, useIsMobile } from '../../utils/mobile' -import { nftName, NftImage, assetUrl, collectionNameText, isValidTaxon } from '../../utils/nft' +import { getIsSsrMobile } from '../../utils/mobile' +import { nftName, NftImage, assetUrl, collectionNameText } from '../../utils/nft' import SEO from '../../components/SEO' import { nftClass } from '../../styles/pages/nft.module.scss' -import { nativeCurrency } from '../../utils' +import { useWidth } from '../../utils' import { axiosServer, passHeaders } from '../../utils/axios' -import { LinkListedNfts, LinkTx } from '../../utils/links' -import NftCollectionTabs from '../../components/Tabs/NftCollectionTabs' +import { LinkTx } from '../../utils/links' export async function getServerSideProps(context) { const { locale, query, req } = context @@ -62,8 +61,9 @@ export async function getServerSideProps(context) { } } -export default function NftCollection({ id, nftList, selectedCurrency, fiatRate, errorMessage, data }) { +export default function NftCollection({ id, nftList, selectedCurrency, isSsrMobile, fiatRate, errorMessage, data }) { const { t } = useTranslation() + const width = useWidth() const collection = data?.collection const statistics = collection?.statistics const [activityData, setActivityData] = useState({ @@ -73,7 +73,7 @@ export default function NftCollection({ id, nftList, selectedCurrency, fiatRate, }) const [activityLoading, setActivityLoading] = useState(false) - const isMobile = useIsMobile(1000) + const isMobile = width !== undefined ? width <= 1000 : isSsrMobile useEffect(() => { fetchActivityData() @@ -343,11 +343,6 @@ export default function NftCollection({ id, nftList, selectedCurrency, fiatRate, const privateFloors = collection?.floorPrices?.map((item) => item.private).filter(Boolean) const openFloors = collection?.floorPrices?.map((item) => item.open).filter(Boolean) - const collectionPart = - collection?.issuer && isValidTaxon(collection?.taxon) - ? `issuer=${collection.issuer}&taxon=${collection.taxon}` - : 'collection=' + collection?.collection - return (
    +

    NFT collection: {collectionName}

    - +
    {id && !data?.error ? ( <> {!data && !errorMessage ? ( @@ -466,7 +462,12 @@ export default function NftCollection({ id, nftList, selectedCurrency, fiatRate,
    )} @@ -486,59 +487,39 @@ export default function NftCollection({ id, nftList, selectedCurrency, fiatRate, @@ -588,16 +569,7 @@ export default function NftCollection({ id, nftList, selectedCurrency, fiatRate, On the open market:{' '} {openFloors.map((floor, i) => ( - - {amountFormat(floor.amount, { presice: true, icon: true, noSpace: true })} - + {amountFormat(floor.amount, { presice: true, icon: true, noSpace: true })} {openFloors.length - 1 !== i && ', '} ))} @@ -610,18 +582,8 @@ export default function NftCollection({ id, nftList, selectedCurrency, fiatRate, On the marketplaces:{' '} {privateFloors.map((floor, i) => ( - - {amountFormat(floor.amount, { presice: true, icon: true })} ( - {floor?.destinationDetails?.service}) - - {privateFloors.length - 1 !== i && ', '} + {amountFormat(floor.amount, { presice: true, icon: true })} ( + {floor?.destinationDetails?.service}){privateFloors.length - 1 !== i && ', '} ))} diff --git a/pages/nft-distribution/[[...id]].js b/pages/nft-distribution/[[...id]].js index f994e53ae..cc777af03 100644 --- a/pages/nft-distribution/[[...id]].js +++ b/pages/nft-distribution/[[...id]].js @@ -16,7 +16,7 @@ import { } from '../../utils' import { getIsSsrMobile } from '../../utils/mobile' import { isValidTaxon } from '../../utils/nft' -import { nftsExplorerLink, niceNumber, AddressWithIconFilled, percentFormat } from '../../utils/format' +import { nftsExplorerLink, niceNumber, AddressWithIconFilled } from '../../utils/format' import FiltersFrame from '../../components/Layout/FiltersFrame' @@ -44,7 +44,6 @@ import SEO from '../../components/SEO' import AddressInput from '../../components/UI/AddressInput' import FormInput from '../../components/UI/FormInput' import InfiniteScrolling from '../../components/Layout/InfiniteScrolling' -import NftCollectionTabs from '../../components/Tabs/NftCollectionTabs' export default function NftDistribution({ issuerQuery, @@ -124,7 +123,6 @@ export default function NftDistribution({ let markerPart = '' if (loadMoreRequest) { - if (!data?.marker) return markerPart = '&marker=' + data?.marker } else { marker = 'first' @@ -259,8 +257,6 @@ export default function NftDistribution({ } } - const collectionPart = issuer && isValidTaxon(taxon) ? `issuer=${issuer}&taxon=${taxon}` : 'collection=' + collection - return ( <>

    {t('header', { ns: 'nft-distribution' })}

    - )}
    } {listTab === 'issuers' && } {(listTab === 'issuers' || listTab === 'collections') && extendedStats && ( - + )} {(listTab === 'issuers' || listTab === 'collections') && extendedStats && ( - + )} {(listTab === 'issuers' || listTab === 'collections') && extendedStats && ( )} {(listTab === 'issuers' || listTab === 'collections') && extendedStats && ( - + )} {listTab === 'brokers' && } {listTab === 'currencies' && } - + {(listTab === 'issuers' || listTab === 'collections') && extendedStats && ( - + )} {(listTab === 'currencies' || selectedToken) && } @@ -1420,19 +1511,6 @@ export default function NftVolumes({
    Owners - {statistics.owners} + {/* + {statistics.owners} + */} + {statistics.owners}
    - {statistics.day.tradedNfts > 0 ? ( - - {statistics.day.tradedNfts} - - ) : ( - 0 - )} + + {statistics.day.tradedNfts} + - {statistics.week.tradedNfts > 0 ? ( - - {statistics.week.tradedNfts} - - ) : ( - 0 - )} + + {statistics.week.tradedNfts} + - {statistics.month.tradedNfts > 0 ? ( - - {statistics.month.tradedNfts} - - ) : ( - 0 - )} + + {statistics.month.tradedNfts} + - {statistics.year.tradedNfts > 0 ? ( - - {statistics.year.tradedNfts} - - ) : ( - 0 - )} + + {statistics.year.tradedNfts} + - {statistics.all.tradedNfts > 0 ? ( - - {statistics.all.tradedNfts} - - ) : ( - 0 - )} + + {statistics.all.tradedNfts} +
    - {niceNumber(user.total)} {percentFormat(user.total, data?.summary?.totalNfts)}{' '} + {niceNumber(user.total)}{' '} {nftsExplorerLink({ owner: user.address, ownerDetails: user.addressDetails, @@ -475,7 +470,7 @@ export default function NftDistribution({ )}

    {issuer ? t('table.nfts') : t('table.total', { ns: 'nft-distribution' })}:{' '} - {niceNumber(user.total)} {percentFormat(user.total, data?.summary?.totalNfts)}{' '} + {niceNumber(user.total)}{' '} {nftsExplorerLink({ owner: user.address, ownerDetails: user.addressDetails, diff --git a/pages/nft-explorer.js b/pages/nft-explorer.js index e39d8bc8a..3f9822e1c 100644 --- a/pages/nft-explorer.js +++ b/pages/nft-explorer.js @@ -35,7 +35,7 @@ export const getServerSideProps = async (context) => { view: view || 'tiles', list: list || 'nfts', saleDestination: saleDestination || (xahauNetwork ? 'public' : 'buyNow'), - saleCurrency: saleCurrency || '', + saleCurrency: saleCurrency || 'xrp', saleCurrencyIssuer: saleCurrencyIssuer || '', searchQuery: search || '', issuerQuery: issuer || '', diff --git a/pages/nft-sales.js b/pages/nft-sales.js index ff003ef77..1c4d3146a 100644 --- a/pages/nft-sales.js +++ b/pages/nft-sales.js @@ -144,7 +144,7 @@ export default function NftSales({ const controller = new AbortController() - const sortCurrency = sortCurrencyQuery?.toLowerCase() || selectedCurrency + const sortCurrency = sortCurrencyQuery.toLowerCase() || selectedCurrency const orderList = [ { value: 'priceHigh', label: t('dropdown.priceHigh', { ns: 'nft-sort' }) }, @@ -404,7 +404,7 @@ export default function NftSales({ search, includeWithoutMediaData, selectedToken, - sessionToken + sessionToken, ]) useEffect(() => { @@ -588,7 +588,7 @@ export default function NftSales({ {t('nft-sales.header')} {data?.issuer ? <>, {addressUsernameOrServiceLink(data, 'issuer', { short: true })} : ''} - + <> - {collectionQuery ? ( - - ) : ( - <> - - {!xahauNetwork && ( - - )} - + + {!xahauNetwork && ( + )} - { if (!convertCurrency) return checkApi() + setSortConfig({}) return () => { controller.abort() @@ -703,6 +704,50 @@ export default function NftVolumes({ } } + const sortTable = (key) => { + if (!data || !data[0] || !(data[0][key] || data[0].volumesInConvertCurrencies[convertCurrency])) return + let direction = 'descending' + let sortA = 1 + let sortB = -1 + + if (sortConfig.key === key && sortConfig.direction === direction) { + direction = 'ascending' + sortA = -1 + sortB = 1 + } + setSortConfig({ key, direction }) + if (key === 'amount') { + setData( + data.sort(function (a, b) { + if ( + a.volumesInConvertCurrencies[convertCurrency] === '' || + a.volumesInConvertCurrencies[convertCurrency] === null + ) + return 1 + if ( + b.volumesInConvertCurrencies[convertCurrency] === '' || + b.volumesInConvertCurrencies[convertCurrency] === null + ) + return -1 + if (a.volumesInConvertCurrencies[convertCurrency] === b.volumesInConvertCurrencies[convertCurrency]) return 0 + return parseFloat(a.volumesInConvertCurrencies[convertCurrency]) < + parseFloat(b.volumesInConvertCurrencies[convertCurrency]) + ? sortA + : sortB + }) + ) + } else if (sortConfig.key?.includes('.')) { + const keys = sortConfig.key.split('.') + setData( + data.sort(function (a, b) { + return parseFloat(a[keys[0]]?.[keys[1]]) < parseFloat(b[keys[0]]?.[keys[1]]) ? sortA : sortB + }) + ) + } else { + setData(data.sort((a, b) => (parseFloat(a[key]) < parseFloat(b[key]) ? sortA : sortB))) + } + } + const bestFloor = (priceFloor) => { if (!priceFloor) return {} let open = null @@ -828,8 +873,6 @@ export default function NftVolumes({ if (!data.collectionDetails) return data.collection const { name, family, description, issuer, taxon } = data.collectionDetails - const nameLink = nftCollectionLink(data) - if (type === 'mobile') { return ( <> @@ -840,7 +883,7 @@ export default function NftVolumes({ )} {name && (

    - {t('table.name')}: {nameLink} + {t('table.name')}: {name}

    )} {!family && !name && ( @@ -867,6 +910,8 @@ export default function NftVolumes({ ) } + let nameLink = nftCollectionLink(data) + if (family) { if ( name && @@ -1110,26 +1155,72 @@ export default function NftVolumes({ {listTab === 'marketplaces' &&
    {t('table.minted')}{t('table.issuer')}{t('table.nfts-now')} + {t('table.nfts-now')}{' '} + sortTable('nfts')} + > + ⇅ + + {t('table.owners-now')} + {t('table.owners-now')}{' '} + sortTable('owners')} + > + ⇅ + + {t('table.floor-now')}{t('table.traded-nfts')} + {t('table.traded-nfts')}{' '} + sortTable('tradedNfts')} + > + ⇅ + + {t('table.broker')}{t('table.issuers')}{t('table.sales')} + {t('table.sales')}{' '} + sortTable('sales')} + > + ⇅ + + {t('table.buyers')} + {t('table.buyers')}{' '} + sortTable('buyers')} + > + ⇅ + + {t('table.volume')} - {t('table.volume')} ({convertCurrency?.toUpperCase()}) + {t('table.volume')} ({convertCurrency?.toUpperCase()}){' '} + sortTable('amount')} + > + ⇅ +
    - {listTab === 'collections' && ( - <> -
    - -
    -
    - - )} )) diff --git a/pages/nft/[[...id]].js b/pages/nft/[[...id]].js index 9ccd0e0c7..94e7ce19e 100644 --- a/pages/nft/[[...id]].js +++ b/pages/nft/[[...id]].js @@ -16,17 +16,7 @@ import { usernameOrAddress } from '../../utils/format' import { getIsSsrMobile } from '../../utils/mobile' -import { - nftName, - mpUrl, - bestNftOffer, - nftUrl, - partnerMarketplaces, - ipfsUrl, - isNftExplicit, - collectionNameText, - isValidTaxon -} from '../../utils/nft' +import { nftName, mpUrl, bestNftOffer, nftUrl, partnerMarketplaces, ipfsUrl, isNftExplicit } from '../../utils/nft' import { shortHash, trWithFlags, @@ -57,7 +47,7 @@ export async function getServerSideProps(context) { //const selectedCurrency = req.cookies['selectedCurrency'] const res = await axiosServer({ method: 'get', - url: 'v2/nft/' + nftId + '?uri=true&metadata=true&collectionDetails=true', //&history=true&sellOffers=true&buyOffers=true&offersValidate=true&offersHistory=true&convertCurrencies=' + + url: 'v2/nft/' + nftId + '?uri=true&metadata=true', //&history=true&sellOffers=true&buyOffers=true&offersValidate=true&offersHistory=true&convertCurrencies=' + //selectedCurrency?.toLowerCase(), headers: passHeaders(req) }) @@ -144,7 +134,7 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur const response = await axios( '/v2/nft/' + id + - '?uri=true&metadata=true&collectionDetails=true&history=true&sellOffers=true&buyOffers=true&offersValidate=true&offersHistory=true' + + '?uri=true&metadata=true&history=true&sellOffers=true&buyOffers=true&offersValidate=true&offersHistory=true' + noCache + '&convertCurrencies=' + selectedCurrency?.toLowerCase() + @@ -1245,7 +1235,7 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur {nftName(data) && ( {t('table.name')} - {nftName(data)} + {nftName(data)} )} {nftDescription(data.metadata) && ( @@ -1254,6 +1244,23 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur {nftDescription(data.metadata)} )} + {!!data.metadata.collection && ( + <> + {!!data.metadata.collection.name && ( + + {t('table.collection')} + {stripText(data.metadata.collection.name)} + + )} + {!!data.metadata.collection.description && + data.metadata.collection.description !== data.metadata.description && ( + + {t('table.description')} + {stripText(data.metadata.collection.description)} + + )} + + )} {externalUrl(data.metadata) && ( {t('table.external-url')} @@ -1275,81 +1282,6 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur
    {codeHighlight(data.metadata)}
    - {data.collectionDetails && ( - - - - - - - - - - - - {data.collectionDetails?.description && ( - - - - - )} - {data.collectionDetails?.family && - data.collectionDetails?.family !== collectionNameText(data.collectionDetails) && ( - - - - - )} - - {data.type === 'xls20' && isValidTaxon(data?.collectionDetails?.taxon) && ( - - - - - )} - -
    {t('table.collection')}
    {t('table.name')} - {collectionNameText(data.collectionDetails)} - {data.collection && ( - <> - {' '} - ( - - View collection - - ) - - )} -
    {t('table.description')}{stripText(data.collectionDetails.description)}
    Family{stripText(data.collectionDetails?.family)}
    View more - - ,{' '} - - ,{' '} - - ,{' '} - - {t('table.listed')} - -
    - )} @@ -1421,7 +1353,7 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur {!notFoundInTheNetwork && ( - @@ -1569,7 +1501,7 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur <> ,{' '} - {t('table.listed')} + {t('table.on-sale')} ,{' '} @@ -1587,14 +1519,8 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur {data.type === 'xls20' && ( <> ,{' '} - - {t('table.listed')} + + {t('table.on-sale')} )} diff --git a/pages/nfts/[[...id]].js b/pages/nfts/[[...id]].js index 163b957be..7df8af350 100644 --- a/pages/nfts/[[...id]].js +++ b/pages/nfts/[[...id]].js @@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => { view: view || 'tiles', list: list || 'nfts', saleDestination: saleDestination || (xahauNetwork ? 'public' : 'buyNow'), - saleCurrency: saleCurrency || '', + saleCurrency: saleCurrency || 'xrp', saleCurrencyIssuer: saleCurrencyIssuer || '', searchQuery: search || '', issuerQuery: issuer || '', diff --git a/pages/object/[id].js b/pages/object/[id].js index d2dde6979..c8ae7e735 100644 --- a/pages/object/[id].js +++ b/pages/object/[id].js @@ -131,9 +131,9 @@ export default function LedgerObject({ const [ledgerDateInput, setLedgerDateInput] = useState(qsDate) const isFirstRender = useRef(true) - const addressFields = ['Account', 'Owner', 'Destination', 'Issuer', 'RegularKey'] + const addressFields = ['Account', 'Owner', 'Destination', 'Issuer', 'SendMax', 'RegularKey'] - const amountFields = ['Balance', 'LowLimit', 'HighLimit', 'SendMax'] + const amountFields = ['Balance', 'LowLimit', 'HighLimit'] const txIdFields = ['PreviousTxnID'] const ledgerSeqFields = ['PreviousTxnLgrSeq'] @@ -206,7 +206,7 @@ export default function LedgerObject({ } // Amount-like fields (objects with value/currency/issuer) - if (amountFields.includes(key)) { + if (amountFields.includes(key) && typeof value === 'object') { return ( @@ -227,7 +227,7 @@ export default function LedgerObject({ if (key === 'previousTxAt') { return ( - + ) diff --git a/pages/services/account-delete.js b/pages/services/account-delete.js deleted file mode 100644 index 74de51150..000000000 --- a/pages/services/account-delete.js +++ /dev/null @@ -1,651 +0,0 @@ -import { i18n, useTranslation } from 'next-i18next' -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' -import SEO from '../../components/SEO' -import { addAndRemoveQueryParams, explorerName } from '../../utils' -import { getIsSsrMobile } from '../../utils/mobile' -import CheckBox from '../../components/UI/CheckBox' -import AddressInput from '../../components/UI/AddressInput' -import FormInput from '../../components/UI/FormInput' -import CopyButton from '../../components/UI/CopyButton' -import { LinkTx, LinkAccount } from '../../utils/links' -import { multiply } from '../../utils/calc' -import { typeNumberOnly, isAddressValid, isTagValid, nativeCurrency, encode, decode } from '../../utils' -import { fullDateAndTime, timeFromNow, amountFormat } from '../../utils/format' -import { useState, useEffect } from 'react' -import { useRouter } from 'next/router' -import Link from 'next/link' -import axios from 'axios' -import { errorCodeDescription } from '../../utils/transaction' - -export const getServerSideProps = async (context) => { - const { query, locale } = context - const { address, destinationTag, memo, fee, sourceTag } = query - - return { - props: { - addressQuery: address || '', - destinationTagQuery: destinationTag || '', - memoQuery: memo || '', - feeQuery: fee || '', - sourceTagQuery: sourceTag || '', - isSsrMobile: getIsSsrMobile(context), - ...(await serverSideTranslations(locale, ['common'])) - } - } -} - -export default function AccountDelete({ - account, - setSignRequest, - addressQuery, - destinationTagQuery, - memoQuery, - feeQuery, - sourceTagQuery, - sessionToken, - subscriptionExpired, - openEmailLogin, - signOut -}) { - const { t } = useTranslation() - const router = useRouter() - - const [accountData, setAccountData] = useState(null) - const [address, setAddress] = useState(isAddressValid(addressQuery) ? addressQuery : null) - const [destinationTag, setDestinationTag] = useState(isTagValid(destinationTagQuery) ? destinationTagQuery : null) - const [memo, setMemo] = useState(memoQuery) - const [showAdvanced, setShowAdvanced] = useState(Number(feeQuery) > 0 || isTagValid(sourceTagQuery)) - const [fee, setFee] = useState( - Number(feeQuery) > 0 && Number(feeQuery) <= 1 && sessionToken && !subscriptionExpired ? feeQuery : null - ) - const [feeError, setFeeError] = useState('') - const [sourceTag, setSourceTag] = useState( - isTagValid(sourceTagQuery) && sessionToken && !subscriptionExpired ? sourceTagQuery : null - ) - const [errorMessage, setErrorMessage] = useState('') - const [txResult, setTxResult] = useState(null) - const [agreeToSiteTerms, setAgreeToSiteTerms] = useState(false) - const [isNonActive, setIsNonActive] = useState(false) - const [agreeToSendToFlagged, setAgreeToSendToFlagged] = useState(false) - const [requireDestTag, setRequireDestTag] = useState(false) - const [requiredFee, setRequiredFee] = useState('200000') // default fee if network info is not loaded - const [destinationStatus, setDestinationStatus] = useState(0) - - // Fetch network info for reserve amounts - useEffect(() => { - const fetchNetworkInfo = async () => { - try { - const response = await axios('/v2/server') - if (response?.data?.reserveIncrement) { - setRequiredFee(response.data.reserveIncrement) - } - } catch (error) { - console.error('Error fetching network info:', error) - } - } - - fetchNetworkInfo() - }, []) - - useEffect(() => { - const fetchAccountData = async () => { - try { - const response = await axios(`/v2/address/${account.address}?ledgerInfo=true`) - setAccountData(response?.data) - } catch (error) { - setErrorMessage('Error fetching account data') - } - } - - if (account?.address) { - fetchAccountData() - } else { - setAccountData(null) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [account]) - - useEffect(() => { - let queryAddList = [] - let queryRemoveList = [] - - if (isAddressValid(address)) { - queryAddList.push({ name: 'address', value: address }) - } else { - queryRemoveList.push('address') - } - - if (isTagValid(destinationTag)) { - queryAddList.push({ name: 'destinationTag', value: destinationTag }) - } else { - queryRemoveList.push('destinationTag') - } - - if (memo) { - queryAddList.push({ name: 'memo', value: memo }) - } else { - queryRemoveList.push('memo') - } - - if (fee && Number(fee) > requiredFee / 1000000 && Number(fee) <= 1) { - queryAddList.push({ name: 'fee', value: fee }) - } else { - queryRemoveList.push('fee') - } - - if (isTagValid(sourceTag)) { - queryAddList.push({ name: 'sourceTag', value: sourceTag }) - } else { - queryRemoveList.push('sourceTag') - } - - addAndRemoveQueryParams(router, queryAddList, queryRemoveList) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address, destinationTag, memo, fee, sourceTag, requiredFee]) - - // Fetch destination account data when address changes - useEffect(() => { - const fetchDestinationAccountData = async () => { - if (!address || !isAddressValid(address)) { - setDestinationStatus(0) - setAgreeToSendToFlagged(false) - setRequireDestTag(false) - setIsNonActive(false) - return - } - - try { - const response = await axios(`/v2/address/${address}?blacklist=true&ledgerInfo=true`) - const data = response?.data - - if (data?.address) { - const status = data.blacklist?.status ?? 0 - setDestinationStatus(status) - const isNonActivated = data.ledgerInfo && data.ledgerInfo.activated === false - setIsNonActive(isNonActivated) - // Reset agreements if account status changes - if (status === 0) { - setAgreeToSendToFlagged(false) - } - } else { - setDestinationStatus(0) - setAgreeToSendToFlagged(false) - setIsNonActive(false) - } - - // Fetch destination tag requirement from new endpoint - const accountResponse = await axios(`/xrpl/accounts/${address}`) - const accountData = accountResponse?.data - if (accountData?.account_data?.require_dest_tag) { - setRequireDestTag(accountData?.account_data?.require_dest_tag) - } else { - setRequireDestTag(false) - } - } catch (error) { - setError('Error fetching destination account data') - setDestinationStatus(0) - setAgreeToSendToFlagged(false) - setRequireDestTag(false) - setIsNonActive(false) - } - } - - fetchDestinationAccountData() - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]) - - const handleFeeChange = (value) => { - setFee(value) - - if (Number(value) > 1) { - setFeeError('Maximum fee is 1 ' + nativeCurrency) - } else if (Number(value) < requiredFee / 1000000) { - setFeeError('Minimum fee is ' + requiredFee / 1000000 + ' ' + nativeCurrency) - } else { - setFeeError('') - } - } - - const handleSend = async () => { - setErrorMessage('') - setTxResult(null) - - if (!address || !isAddressValid(address)) { - setErrorMessage('Please enter a valid Destination address.') - return - } - - // Check if destination requires a tag but none is provided - if (requireDestTag && !destinationTag) { - setErrorMessage('This destination account requires a destination tag. Please enter a destination tag.') - return - } - - // Check if advanced options are being used without proper subscription - if ((fee || sourceTag || destinationTag) && (!sessionToken || subscriptionExpired)) { - setErrorMessage( - 'Advanced options (fee, source tag, invoice ID) are available only to logged-in Bithomp Pro subscribers.' - ) - return - } - - if (Number(fee) < requiredFee / 1000000) { - setErrorMessage('Minimum fee is ' + requiredFee / 1000000 + ' ' + nativeCurrency) - return - } - - if (Number(fee) > 1) { - setErrorMessage('Maximum fee is 1 ' + nativeCurrency) - return - } - - if (destinationTag && !isTagValid(destinationTag)) { - setErrorMessage('Please enter a valid destination tag.') - return - } - - if (sourceTag && !isTagValid(sourceTag)) { - setErrorMessage('Please enter a valid source tag.') - return - } - - if (!agreeToSiteTerms) { - setErrorMessage('Please agree to the Terms and conditions') - return - } - - if (isNonActive) { - setErrorMessage('You can send funds only to already activated account.') - return - } - - if (destinationStatus === 3) { - setErrorMessage('This account has been flagged as FRAUD. Sending is not allowed.') - return - } - - try { - let tx = {} - - tx = { - TransactionType: 'AccountDelete', - Destination: address - } - - if (account?.address) { - tx.Account = account.address - } - - if (destinationTag) { - tx.DestinationTag = parseInt(destinationTag) - } - - if (memo) { - tx.Memos = [ - { - Memo: { - MemoData: encode(memo) - } - } - ] - } - - if (fee && Number(fee) > requiredFee / 1000000) { - tx.Fee = multiply(fee, 1000000) - } else { - tx.Fee = requiredFee - } - - if (sourceTag) { - tx.SourceTag = parseInt(sourceTag) - } - - setSignRequest({ - request: tx, - callback: (result) => { - const status = result.meta?.TransactionResult - if (status !== 'tesSUCCESS') { - setError(errorCodeDescription(status)) - } else { - setTxResult({ - status, - date: result.date, - destination: result.Destination, - destinationTag: result.DestinationTag, - sourceTag: result.SourceTag, - fee: amountFormat(result.Fee), - sequence: result.Sequence, - memo: result.Memos?.[0]?.Memo?.MemoData ? decode(result.Memos[0].Memo.MemoData) : undefined, - hash: result.hash, - validated: result.validated, - ledgerIndex: result.ledger_index, - transactionType: 'AccountDelete' - }) - } - } - }) - } catch (err) { - setError(err.message) - } - } - - return ( - <> - -
    -

    Account delete

    - - {!txResult && accountData?.ledgerInfo?.deleted ? ( - <> - The account {account?.address} has already been deleted on the {explorerName}{' '} - Ledger. -
    -
    -
    - -
    - - ) : ( - <> -

    - An Account delete transaction permanently deletes an account and any objects it owns on the {explorerName}{' '} - Ledger, if possible, and transfers the account’s remaining {nativeCurrency} to a specified destination - account. -

    -

    - The fee to execute this transaction is{' '} - {amountFormat(requiredFee, { noSpace: true })}. This is a protocol - requirement of the {explorerName} Ledger, and the {amountFormat(requiredFee, { noSpace: true })} is - permanently burned as part of the process. -

    - -

    - ⚠️ Attention: Do NOT use an exchange or custodial wallet as the destination address. You may permanently - lose your funds. -

    - -
    - {account?.address && ( - <> - - Deleting account [ - - {t('signin.signout')} - - ] - - } - disabled={true} - /> -
    - - )} - - { - setAddress(value) - }} - setInnerValue={setAddress} - rawData={isAddressValid(address) ? { address } : {}} - type="address" - /> - - {/* Show warning if destination account is flagged (status 1,2,3) */} - {(destinationStatus === 1 || destinationStatus === 2 || destinationStatus === 3) && ( -
    -
    -
    - - ⚠️{' '} - {destinationStatus === 1 - ? 'Spam Alert' - : destinationStatus === 2 - ? 'Potential Fraud Alert' - : 'Fraud Alert'} - -
    - {destinationStatus === 1 && ( - <> - This account has been flagged for spam. Proceed with caution. -
    - - )} - {destinationStatus === 2 && ( - <> - This account has been flagged as potentially involved in fraud, scams, or phishing.{' '} - Proceed with caution. -
    - - )} - {destinationStatus === 3 && ( - <> - This account has been flagged as FRAUD. Sending is not allowed. -
    - - )} - - Learn more about flagged accounts - -
    -
    - )} - - {/* Show warning if destination account is non-activated */} - {isNonActive && ( -
    -
    -
    - ⚠️ Non-activated account -
    - You can not send funds to a non-activated account. -
    -
    - )} -
    - - {t('table.memo')} (It will be public) - - } - placeholder="Enter a memo (optional)" - setInnerValue={setMemo} - hideButton={true} - defaultValue={memo} - maxLength={100} - type="text" - /> - - { - setShowAdvanced(!showAdvanced) - setFee(null) - setSourceTag(null) - }} - name="advanced-options" - > - Advanced options - {!sessionToken ? ( - <> - {' '} - - (available to{' '} - openEmailLogin()}> - logged-in - {' '} - Bithomp Pro subscribers) - - - ) : ( - subscriptionExpired && ( - <> - {' '} - - Your Bithomp Pro subscription has expired.{' '} - Renew your subscription - - - ) - )} - - - {showAdvanced && ( - <> -
    - - {t('table.destination-tag')} -
    - - I acknowledge that the destination account MUST NOT be an exchange or custodial wallet, as - this may lead to a loss of funds. - - {requireDestTag ? ( - <> - {' '} - (required) - - ) : ( - '' - )} - - } - placeholder={t('form.placeholder.destination-tag')} - setInnerValue={setDestinationTag} - hideButton={true} - onKeyPress={typeNumberOnly} - defaultValue={destinationTag} - disabled={!sessionToken || subscriptionExpired} - /> -
    - - {feeError &&
    {feeError}
    } -
    - - - )} - -
    - - I agree with the{' '} - - Terms and conditions - - . - - - {/* Show additional checkbox for flagged accounts (only for status 1 and 2) */} - {(destinationStatus === 1 || destinationStatus === 2 || isNonActive) && ( -
    - - I understand the risks and I want to proceed with sending funds to this flagged account - -
    - )} - -
    - {errorMessage && ( - <> -
    {errorMessage}
    -
    - - )} -
    - -
    - {txResult?.status === 'tesSUCCESS' && ( - <> -
    -
    -

    Transaction Successful

    -
    -

    - {t('table.date')}: {timeFromNow(txResult.date, i18n, 'ripple')} ( - {fullDateAndTime(txResult.date, 'ripple')}) -

    -

    - {t('table.destination')}: {' '} - -

    - {txResult.destinationTag && ( -

    - {t('table.destination-tag')}: {txResult.destinationTag} -

    - )} - {txResult.sourceTag && ( -

    - Source Tag: {txResult.sourceTag} -

    - )} -

    - Fee: {txResult.fee} -

    -

    - {t('table.sequence')}: #{txResult.sequence} -

    - {txResult.memo && ( -

    - {t('table.memo')}: {txResult.memo} -

    - )} -

    - {t('table.hash')}: - -

    -
    -
    - - )} -
    - - )} -
    - - ) -} diff --git a/pages/services/check.js b/pages/services/check.js index 7769668f8..d020251ba 100644 --- a/pages/services/check.js +++ b/pages/services/check.js @@ -222,7 +222,8 @@ export default function IssueCheck({ hash: result.hash, invoiceID: result.InvoiceID, expiration: result.Expiration, - ledgerIndex: result.ledger_index + ledgerIndex: result.ledger_index, + balanceChanges: result.balanceChanges }) } else { setError(errorCodeDescription(status)) diff --git a/pages/services/escrow.js b/pages/services/escrow.js index 2a0fa5ebf..4b5893e0f 100644 --- a/pages/services/escrow.js +++ b/pages/services/escrow.js @@ -270,7 +270,8 @@ export default function CreateEscrow({ finishAfter: result.FinishAfter, cancelAfter: result.CancelAfter, condition: result.Condition, - ledgerIndex: result.ledger_index + ledgerIndex: result.ledger_index, + balanceChanges: result.balanceChanges }) } else { setError(errorCodeDescription(status)) diff --git a/pages/services/send.js b/pages/services/send.js index 51924c212..93d64d9c4 100644 --- a/pages/services/send.js +++ b/pages/services/send.js @@ -413,6 +413,7 @@ export default function Send({ hash: result.hash, validated: result.validated, ledgerIndex: result.ledger_index, + balanceChanges: result.balanceChanges, invoiceId: result.InvoiceID, transactionType: xahauNetwork && useRemit ? 'Remit' : 'Payment' }) @@ -426,16 +427,7 @@ export default function Send({ return ( <> - +

    Send payment

    @@ -809,7 +801,7 @@ export default function Send({ )} {txResult.transactionType === 'Remit' && (

    - Transaction Type: Remit + Transaction Type: Remit (Xahau)

    )}
    diff --git a/pages/services/trustline.js b/pages/services/trustline.js index 55430f2fa..6d2ea3e21 100644 --- a/pages/services/trustline.js +++ b/pages/services/trustline.js @@ -416,16 +416,7 @@ export default function TrustSet({ return ( <> - +

    Set/Update Trust (Trustlines)

    Create or modify a Trustline linking two accounts.

    diff --git a/pages/sitemap.xml.js b/pages/sitemap.xml.js index e316e7335..cf26deec2 100644 --- a/pages/sitemap.xml.js +++ b/pages/sitemap.xml.js @@ -17,7 +17,6 @@ const pages = [ { loc: 'services/check', changefreq: 'monthly', priority: '0.8' }, { loc: 'services/escrow', changefreq: 'monthly', priority: '0.9' }, { loc: 'services/account-settings', changefreq: 'monthly', priority: '0.9' }, - { loc: 'services/account-delete', changefreq: 'monthly', priority: '0.5' }, { loc: 'whales/receivers', changefreq: 'always', priority: '0.9' }, { loc: 'whales/senders', changefreq: 'always', priority: '0.9' }, @@ -101,8 +100,7 @@ if (network === 'mainnet') { { loc: 'learn/issue-a-token', changefreq: 'monthly', priority: '0.9' }, { loc: 'learn/guide-for-token-issuers', changefreq: 'monthly', priority: '0.9' }, { loc: 'learn/image-services', changefreq: 'monthly', priority: '0.6' }, - { loc: 'learn/trustlines', changefreq: 'monthly', priority: '0.6' }, - { loc: 'learn/nft-explorer', changefreq: 'monthly', priority: '0.7' } + { loc: 'learn/paystrings', changefreq: 'monthly', priority: '0.5' } ) } @@ -131,7 +129,6 @@ function generateSiteMap(posts) { 'services/check', 'services/escrow', 'services/account-settings', - 'services/account-delete', 'services/amm/deposit', 'services/amm/create', 'services/amm/withdraw', @@ -147,8 +144,7 @@ function generateSiteMap(posts) { 'learn/issue-a-token', 'learn/guide-for-token-issuers', 'learn/image-services', - 'learn/trustlines', - 'learn/nft-explorer' + 'learn/paystrings' ] const oldPages = ['explorer/'] const pagesWithoutTranslation = [...noTranslatedPages, ...oldPages] diff --git a/pages/token/[[...id]].js b/pages/token/[[...id]].js index ceac0780d..009d7370e 100644 --- a/pages/token/[[...id]].js +++ b/pages/token/[[...id]].js @@ -11,7 +11,7 @@ import { shortNiceNumber, fullNiceNumber, AddressWithIconFilled, - addressUsernameOrServiceLink + userOrServiceLink } from '../../utils/format' import { axiosServer, getFiatRateServer, passHeaders } from '../../utils/axios' import { getIsSsrMobile } from '../../utils/mobile' @@ -168,17 +168,18 @@ export default function TokenPage({ {price < 0.0001 ? ( <> - 1M {token?.currencyDetails?.currency} = {niceNumber(price * 1000000, 6)}{' '} + 1M {token?.currencyDetails?.currency} = {niceNumber(price * 1000000, 6)}{' '} - {nativeCurrency},{' '} + {nativeCurrency},{' '} ) : ( - {niceNumber(price, 6)} {nativeCurrency},{' '} + {niceNumber(price, 6)} {nativeCurrency},{' '} )} - 1 {nativeCurrency} = {niceNumber(1 / price, 6)} {token?.currencyDetails?.currency} + 1 {nativeCurrency} = {niceNumber(1 / price, 6)}{' '} + {token?.currencyDetails?.currency} {!isSsrMobile && ')'} @@ -282,7 +283,7 @@ export default function TokenPage({ const title = ( <> - {token?.currencyDetails?.currency} issued by {addressUsernameOrServiceLink(token, 'issuer', { short: true })} + {token?.currencyDetails?.currency} issued by {userOrServiceLink(token, 'issuer') || token?.issuer} ) @@ -365,7 +366,7 @@ export default function TokenPage({
    - + @@ -522,15 +523,15 @@ export default function TokenPage({ - + - + - + @@ -538,7 +539,7 @@ export default function TokenPage({ - + @@ -554,11 +555,11 @@ export default function TokenPage({ - + - + @@ -566,19 +567,19 @@ export default function TokenPage({ - + - + - + - + @@ -587,7 +588,7 @@ export default function TokenPage({ {!xahauNetwork && ( - + - + - + - + {!xahauNetwork && ( - + )} diff --git a/pages/tokens.js b/pages/tokens.js index 7aa0b3c90..de5c51a9d 100644 --- a/pages/tokens.js +++ b/pages/tokens.js @@ -10,7 +10,7 @@ import InfiniteScrolling from '../components/Layout/InfiniteScrolling' import IssuerSearchSelect from '../components/UI/IssuerSearchSelect' import CurrencySearchSelect from '../components/UI/CurrencySearchSelect' import SortingArrow from '../components/Tables/SortingArrow' -import { fullNiceNumber, niceCurrency, niceNumber, shortNiceNumber, CurrencyWithIcon } from '../utils/format' +import { fullNiceNumber, niceCurrency, niceNumber, shortNiceNumber, AddressWithIconFilled } from '../utils/format' import { axiosServer, getFiatRateServer, passHeaders } from '../utils/axios' import { getIsSsrMobile } from '../utils/mobile' import { isAddressOrUsername, nativeCurrency, setTabParams, validateCurrencyCode, xahauNetwork } from '../utils' @@ -143,7 +143,14 @@ const orderList = [ // Helper component to render token with icon const TokenCell = ({ token }) => { - return + return ( + + ) } export default function Tokens({ @@ -177,11 +184,9 @@ export default function Tokens({ // States const [data, setData] = useState(initialData?.tokens || []) const [rawData, setRawData] = useState(initialData || {}) - const [marker, setMarker] = useState(initialData?.marker || '') + const [marker, setMarker] = useState(initialData?.marker) const [loading, setLoading] = useState(false) - const [errorMessage, setErrorMessage] = useState( - t(`error.${initialErrorMessage}`, { defaultValue: initialErrorMessage }) || '' - ) + const [errorMessage, setErrorMessage] = useState(initialErrorMessage || '') const [order, setOrder] = useState(orderQuery || 'rating') const [filtersHide, setFiltersHide] = useState(false) const [issuer, setIssuer] = useState(issuerQuery) @@ -225,7 +230,7 @@ export default function Tokens({ const oldOrder = rawData?.order const oldCurrency = rawData?.currency const oldIssuer = rawData?.issuer - const oldSelectedCurrency = rawData?.convertCurrencies?.[0] + const oldSelectedCurrency = rawData?.convertCurrencies[0] if (!oldOrder || !order) return let loadMoreRequest = @@ -241,7 +246,6 @@ export default function Tokens({ let markerPart = '' if (loadMoreRequest) { - if (!rawData?.marker) return markerPart = '&marker=' + rawData?.marker } @@ -539,15 +543,7 @@ export default function Tokens({ return ( <> - +

    Tokens

    {!xahauNetwork && } @@ -787,7 +783,7 @@ export default function Tokens({ {/* Mobile table */}
    -
    {t('table.uri')} + {data.uri ? ( <> {isValidJson(decodedUri) ? ( @@ -1549,10 +1481,10 @@ export default function Nft({ setSignRequest, account, pageMeta, id, selectedCur data.issuer + '&taxon=' + data.nftokenTaxon + - '&list=onSale&saleDestination=publicAndKnownBrokers' + '&list=onSale' } > - {t('table.listed')} + {t('table.on-sale')}
    {key}
    PreviousTxnAtPrevious Tx at {fullDateAndTime(value)}
    Currency codeCurrency Code {token.currencyDetails?.currencyCode}
    Volume (total)Volume (Total) {volumeLine({ token, type: 'total' })}
    Volume (buy)Volume (Buy) {volumeLine({ token, type: 'buy' })}
    Volume (sell)Volume (Sell) {volumeLine({ token, type: 'sell' })}
    {fullNiceNumber(statistics?.dexes || 0)}
    DEX txsDEX TXs {fullNiceNumber(statistics?.dexTxs || 0)}
    {fullNiceNumber(statistics?.uniqueDexAccounts || 0)}
    Transfer volumeTransfer Volume {volumeLine({ token, type: 'transfer' })}
    Transfer transactionsTransfer Transactions {niceNumber(statistics?.transferTxs || 0)}
    {fullNiceNumber(statistics?.ripplingTxs || 0)}
    Mint volumeMint Volume {volumeLine({ token, type: 'mint' })}
    Mint transactionsMint Transactions {shortNiceNumber(statistics?.mintTxs || 0, 0, 1)}
    Burn volumeBurn Volume {volumeLine({ token, type: 'burn' })}
    Burn transactionsBurn Transactions {shortNiceNumber(statistics?.burnTxs || 0, 0, 1)}
    AMM poolsAMM Pools {statistics?.ammPools || 0} @@ -607,20 +608,20 @@ export default function TokenPage({
    Trading pairsTrading Pairs {fullNiceNumber(statistics?.activeCounters || 0)}
    Active holdersActive Holders {fullNiceNumber(statistics?.activeHolders || 0)}
    Active offersActive Offers {fullNiceNumber(statistics?.activeOffers || 0)}
    Active AMM poolsActive AMM Pools {niceNumber(statistics?.activeAmmPools || 0)}
    +
    {loading ? ( diff --git a/pages/transaction/[id].js b/pages/transaction/[id].js index 9f80aa693..ca557ff53 100644 --- a/pages/transaction/[id].js +++ b/pages/transaction/[id].js @@ -25,9 +25,7 @@ import { TransactionRemit, TransactionEnableAmendment, TransactionDelegateSet, - TransactionBatch, - TransactionSignerListSet, - TransactionCron + TransactionBatch } from '../../components/Transaction' import { useEffect, useState } from 'react' import { fetchHistoricalRate } from '../../utils/common' @@ -36,39 +34,31 @@ export async function getServerSideProps(context) { const { locale, query, req } = context let data = null const { id } = query - - let initialErrorMessage = null - try { const res = await axiosServer({ method: 'get', url: 'v3/transaction/' + id, headers: passHeaders(req) - }).catch((error) => { - initialErrorMessage = error.message }) data = res?.data } catch (r) { data = r?.response?.data } - if (typeof data === 'object') { + if (data) { data.id = id - } else { - initialErrorMessage = data } return { props: { data: data || null, - initialErrorMessage: initialErrorMessage || null, isSsrMobile: getIsSsrMobile(context), ...(await serverSideTranslations(locale, ['common'])) } } } -export default function Transaction({ data, selectedCurrency, initialErrorMessage }) { +export default function Transaction({ data, selectedCurrency }) { const { t } = useTranslation() const [pageFiatRate, setPageFiatRate] = useState(0) @@ -82,11 +72,11 @@ export default function Transaction({ data, selectedCurrency, initialErrorMessag // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedCurrency, data]) - if (!data || initialErrorMessage) + if (!data) return (

    - {initialErrorMessage || 'No data received. Are you online?'} + No data received. Are you online?

    @@ -106,12 +96,7 @@ export default function Transaction({ data, selectedCurrency, initialErrorMessag TransactionComponent = TransactionAMM } else if (txType?.includes('Check')) { TransactionComponent = TransactionCheck - } else if ( - txType === 'CredentialCreate' || - txType === 'CredentialAccept' || - txType === 'CredentialDelete' || - txType === 'DepositPreauth' - ) { + } else if (txType === 'CredentialCreate' || txType === 'CredentialAccept' || txType === 'CredentialDelete' || txType === 'DepositPreauth') { TransactionComponent = TransactionCredential } else if (txType?.includes('Escrow')) { TransactionComponent = TransactionEscrow @@ -139,10 +124,6 @@ export default function Transaction({ data, selectedCurrency, initialErrorMessag TransactionComponent = TransactionEnableAmendment } else if (txType === 'Batch') { TransactionComponent = TransactionBatch - } else if (txType === 'SignerListSet') { - TransactionComponent = TransactionSignerListSet - } else if (txType?.includes('Cron')) { - TransactionComponent = TransactionCron } else { TransactionComponent = TransactionDetails } diff --git a/pages/username.js b/pages/username.js index 1443bbc21..7b4d1fca5 100644 --- a/pages/username.js +++ b/pages/username.js @@ -427,7 +427,7 @@ export default function Username({ setSignRequest, account, signOut, addressQuer const response = await axios( 'v1/bithompid/' + username + '/status?address=' + address + '&dt=' + destinationTag ).catch((error) => { - setErrorMessage(t(`error.${error.message}`, { defaultValue: error.message })) + setErrorMessage(t('error.' + error.message)) }) const data = response.data if (data) { diff --git a/pages/validators.js b/pages/validators.js index d9ea6aa01..8dd83b59f 100644 --- a/pages/validators.js +++ b/pages/validators.js @@ -117,10 +117,6 @@ export default function Validators({ amendment, initialData, initialErrorMessage //in the negative UNL if (a.nUnl && !b.nUnl) return -1 if (!a.nUnl && b.nUnl) return 1 - - //without baseFee - offline - if (!a.baseFee && b.baseFee) return -1 - if (a.baseFee && !b.baseFee) return 1 } //in the UNL @@ -823,9 +819,7 @@ export default function Validators({ amendment, initialData, initialErrorMessage {v.domain ? (

    {t('table.domain')}:
    - - {v.domain} - + {v.domain} {verifiedSign(v.domainVerified, v.domain, { tooltip: false })}

    ) : ( @@ -840,74 +834,71 @@ export default function Validators({ amendment, initialData, initialErrorMessage )} )} - {v.unl && v.baseFee &&

    UNL: ✅

    } - {(v.nUnl || !v.baseFee) &&

    nUNL: ❌

    } + {v.unl &&

    UNL: ✅

    } + {v.nUnl &&

    nUNL: ❌

    } +

    + {t('table.votes-for', { ns: 'validators' })}: +
    + {listAmendments(v.amendments)} +

    {t('table.public-key')}:
    {shortHash(v.publicKey)}

    - {!v.amendments && !v.baseFee ? ( -

    Offline

    - ) : ( - <> -

    - {t('table.votes-for', { ns: 'validators' })}: -
    - {listAmendments(v.amendments)} -

    -

    - {t('last-ledger-information.base-fee')}: {v.baseFee ? amountFormat(v.baseFee) : 'N/A'} -

    -

    - {t('last-ledger-information.base-reserve')}:{' '} - {v.reserveBase ? amountFormat(v.reserveBase) : 'N/A'} -

    -

    - {t('last-ledger-information.increment-reserve')}:{' '} - {v.reserveIncrement ? amountFormat(v.reserveIncrement) : 'N/A'} -

    - {v.serverCountry?.length === 2 && ( -

    - {t('table.server-country', { ns: 'validators' })}:{' '} - {countries?.getNameTranslated(fixCountry(v.serverCountry))}{' '} - -

    - )} - - {v.serverLocation && ( -

    - {t('table.server-location', { ns: 'validators' })}: {v.serverLocation} -

    - )} +

    + {t('table.sequence')}: {v.sequence} +

    +

    + {t('last-ledger-information.base-fee')}: {v.baseFee ? amountFormat(v.baseFee) : 'N/A'} +

    +

    + {t('last-ledger-information.base-reserve')}:{' '} + {v.reserveBase ? amountFormat(v.reserveBase) : 'N/A'} +

    +

    + {t('last-ledger-information.increment-reserve')}:{' '} + {v.reserveIncrement ? amountFormat(v.reserveIncrement) : 'N/A'} +

    + {v.serverCountry?.length === 2 && ( +

    + {t('table.server-country', { ns: 'validators' })}:{' '} + {countries?.getNameTranslated(fixCountry(v.serverCountry))}{' '} + +

    + )} - {v.serverCloud?.toString() && ( -

    - {t('table.cloud-private', { ns: 'validators' })}: - {v.serverCloud === true && ☁️} - {v.serverCloud === false && 🏠} -

    - )} + {v.serverLocation && ( +

    + {t('table.server-location', { ns: 'validators' })}: {v.serverLocation} +

    + )} - {v.serverLocation && ( -

    - {t('table.network-asn', { ns: 'validators' })}: {v.networkASN} -

    - )} + {v.serverCloud?.toString() && ( +

    + {t('table.cloud-private', { ns: 'validators' })}: + {v.serverCloud === true && ☁️} + {v.serverCloud === false && 🏠} +

    + )} -

    - {t('table.version')}: {v.serverVersion ? v.serverVersion : 'N/A'} -

    -

    - {t('table.last-seen', { ns: 'validators' })}: -

    - + {v.serverLocation && ( +

    + {t('table.network-asn', { ns: 'validators' })}: {v.networkASN} +

    )} + +

    + {t('table.version')}: {v.serverVersion ? v.serverVersion : 'N/A'} +

    +

    + {t('table.last-seen', { ns: 'validators' })}: +

    {xahauNetwork && (

    {t('table.address')} @@ -915,9 +906,6 @@ export default function Validators({ amendment, initialData, initialErrorMessage {addressUsernameOrServiceLink(v, 'address')}

    )} -

    - {t('table.sequence')}: {v.sequence} -

    )) @@ -990,23 +978,16 @@ export default function Validators({ amendment, initialData, initialErrorMessage )}
    - {!v.baseFee && !v.reserveBase && !v.reserveIncrement && !v.amendments ? ( - Offline - ) : ( - <> - {listAmendments(v.amendments)} -
    - {t('last-ledger-information.base-fee')} {v.baseFee ? amountFormat(v.baseFee) : 'N/A'}|{' '} - {t('last-ledger-information.base-reserve')}{' '} - {v.reserveBase ? amountFormat(v.reserveBase) : 'N/A'}|{' '} - {t('last-ledger-information.increment-reserve')}{' '} - {v.reserveIncrement ? amountFormat(v.reserveIncrement) : 'N/A'} - - )} + {listAmendments(v.amendments)} +
    + {t('last-ledger-information.base-fee')} {v.baseFee ? amountFormat(v.baseFee) : 'N/A'}|{' '} + {t('last-ledger-information.base-reserve')} {v.reserveBase ? amountFormat(v.reserveBase) : 'N/A'}|{' '} + {t('last-ledger-information.increment-reserve')}{' '} + {v.reserveIncrement ? amountFormat(v.reserveIncrement) : 'N/A'} {(xahauNetwork || (developerMode && windowWidth > 1560)) && (
    {v.unl ? ( - v.nUnl || (!v.baseFee && !v.reserveBase && !v.reserveIncrement && !v.amendments) ? ( + v.nUnl ? ( @@ -1049,11 +1030,7 @@ export default function Validators({ amendment, initialData, initialErrorMessage )} - {v.lastSeenTime ? ( - - ) : ( - Long time ago - )} + diff --git a/public/images/xahauexplorer/learn/nft-explorer/cover.jpg b/public/images/xahauexplorer/learn/nft-explorer/cover.jpg deleted file mode 100644 index e01fa57a5..000000000 Binary files a/public/images/xahauexplorer/learn/nft-explorer/cover.jpg and /dev/null differ diff --git a/public/images/xahauexplorer/learn/nft-explorer/history-screen.png b/public/images/xahauexplorer/learn/nft-explorer/history-screen.png deleted file mode 100644 index d89415694..000000000 Binary files a/public/images/xahauexplorer/learn/nft-explorer/history-screen.png and /dev/null differ diff --git a/public/images/xahauexplorer/learn/nft-explorer/nft-options.png b/public/images/xahauexplorer/learn/nft-explorer/nft-options.png deleted file mode 100644 index 36adf36da..000000000 Binary files a/public/images/xahauexplorer/learn/nft-explorer/nft-options.png and /dev/null differ diff --git a/public/images/xahauexplorer/learn/nft-explorer/screen.png b/public/images/xahauexplorer/learn/nft-explorer/screen.png deleted file mode 100644 index 0b71a3f29..000000000 Binary files a/public/images/xahauexplorer/learn/nft-explorer/screen.png and /dev/null differ diff --git a/public/images/xahauexplorer/learn/paystrings/cover.jpg b/public/images/xahauexplorer/learn/paystrings/cover.jpg new file mode 100644 index 000000000..698e8239f Binary files /dev/null and b/public/images/xahauexplorer/learn/paystrings/cover.jpg differ diff --git a/public/images/xahauexplorer/learn/trustlines/cover.jpg b/public/images/xahauexplorer/learn/trustlines/cover.jpg deleted file mode 100644 index f082ca995..000000000 Binary files a/public/images/xahauexplorer/learn/trustlines/cover.jpg and /dev/null differ diff --git a/public/images/xahauexplorer/learn/trustlines/screen-advanced.png b/public/images/xahauexplorer/learn/trustlines/screen-advanced.png deleted file mode 100644 index 42fdbd6d8..000000000 Binary files a/public/images/xahauexplorer/learn/trustlines/screen-advanced.png and /dev/null differ diff --git a/public/images/xahauexplorer/learn/trustlines/screen-simple.png b/public/images/xahauexplorer/learn/trustlines/screen-simple.png deleted file mode 100644 index 81ca2b10d..000000000 Binary files a/public/images/xahauexplorer/learn/trustlines/screen-simple.png and /dev/null differ diff --git a/public/images/xahauexplorer/previews/1200x630/services/send.png b/public/images/xahauexplorer/previews/1200x630/services/send.png deleted file mode 100644 index 9a3ef2c01..000000000 Binary files a/public/images/xahauexplorer/previews/1200x630/services/send.png and /dev/null differ diff --git a/public/images/xahauexplorer/previews/1200x630/services/trustline.png b/public/images/xahauexplorer/previews/1200x630/services/trustline.png deleted file mode 100644 index 8bff68375..000000000 Binary files a/public/images/xahauexplorer/previews/1200x630/services/trustline.png and /dev/null differ diff --git a/public/images/xahauexplorer/previews/1200x630/tokens.png b/public/images/xahauexplorer/previews/1200x630/tokens.png deleted file mode 100644 index 12989b782..000000000 Binary files a/public/images/xahauexplorer/previews/1200x630/tokens.png and /dev/null differ diff --git a/public/images/xahauexplorer/previews/630x630/services/send.png b/public/images/xahauexplorer/previews/630x630/services/send.png deleted file mode 100644 index acf87d658..000000000 Binary files a/public/images/xahauexplorer/previews/630x630/services/send.png and /dev/null differ diff --git a/public/images/xahauexplorer/previews/630x630/services/trustline.png b/public/images/xahauexplorer/previews/630x630/services/trustline.png deleted file mode 100644 index 1d790fa0c..000000000 Binary files a/public/images/xahauexplorer/previews/630x630/services/trustline.png and /dev/null differ diff --git a/public/images/xahauexplorer/previews/630x630/tokens.png b/public/images/xahauexplorer/previews/630x630/tokens.png deleted file mode 100644 index 123c14dd3..000000000 Binary files a/public/images/xahauexplorer/previews/630x630/tokens.png and /dev/null differ diff --git a/public/images/xrplexplorer/learn/nft-explorer/cover.jpg b/public/images/xrplexplorer/learn/nft-explorer/cover.jpg deleted file mode 100644 index b9354e985..000000000 Binary files a/public/images/xrplexplorer/learn/nft-explorer/cover.jpg and /dev/null differ diff --git a/public/images/xrplexplorer/learn/nft-explorer/history-screen.png b/public/images/xrplexplorer/learn/nft-explorer/history-screen.png deleted file mode 100644 index 9d478aae8..000000000 Binary files a/public/images/xrplexplorer/learn/nft-explorer/history-screen.png and /dev/null differ diff --git a/public/images/xrplexplorer/learn/nft-explorer/nft-options.png b/public/images/xrplexplorer/learn/nft-explorer/nft-options.png deleted file mode 100644 index 9e772ba84..000000000 Binary files a/public/images/xrplexplorer/learn/nft-explorer/nft-options.png and /dev/null differ diff --git a/public/images/xrplexplorer/learn/nft-explorer/screen.png b/public/images/xrplexplorer/learn/nft-explorer/screen.png deleted file mode 100644 index b184e0ab0..000000000 Binary files a/public/images/xrplexplorer/learn/nft-explorer/screen.png and /dev/null differ diff --git a/public/images/xrplexplorer/learn/paystrings/cover.jpg b/public/images/xrplexplorer/learn/paystrings/cover.jpg new file mode 100644 index 000000000..f0ccfb133 Binary files /dev/null and b/public/images/xrplexplorer/learn/paystrings/cover.jpg differ diff --git a/public/images/xrplexplorer/learn/trustlines/cover.jpg b/public/images/xrplexplorer/learn/trustlines/cover.jpg deleted file mode 100644 index 48ae2a4f8..000000000 Binary files a/public/images/xrplexplorer/learn/trustlines/cover.jpg and /dev/null differ diff --git a/public/images/xrplexplorer/learn/trustlines/screen-advanced.png b/public/images/xrplexplorer/learn/trustlines/screen-advanced.png deleted file mode 100644 index 969d60835..000000000 Binary files a/public/images/xrplexplorer/learn/trustlines/screen-advanced.png and /dev/null differ diff --git a/public/images/xrplexplorer/learn/trustlines/screen-simple.png b/public/images/xrplexplorer/learn/trustlines/screen-simple.png deleted file mode 100644 index eca15775b..000000000 Binary files a/public/images/xrplexplorer/learn/trustlines/screen-simple.png and /dev/null differ diff --git a/public/images/xrplexplorer/previews/1200x630/services/send.png b/public/images/xrplexplorer/previews/1200x630/services/send.png deleted file mode 100644 index 3e770da25..000000000 Binary files a/public/images/xrplexplorer/previews/1200x630/services/send.png and /dev/null differ diff --git a/public/images/xrplexplorer/previews/1200x630/services/trustline.png b/public/images/xrplexplorer/previews/1200x630/services/trustline.png deleted file mode 100644 index a394d7916..000000000 Binary files a/public/images/xrplexplorer/previews/1200x630/services/trustline.png and /dev/null differ diff --git a/public/images/xrplexplorer/previews/1200x630/tokens.png b/public/images/xrplexplorer/previews/1200x630/tokens.png deleted file mode 100644 index 8e8214cf2..000000000 Binary files a/public/images/xrplexplorer/previews/1200x630/tokens.png and /dev/null differ diff --git a/public/images/xrplexplorer/previews/630x630/services/send.png b/public/images/xrplexplorer/previews/630x630/services/send.png deleted file mode 100644 index f67ef58e3..000000000 Binary files a/public/images/xrplexplorer/previews/630x630/services/send.png and /dev/null differ diff --git a/public/images/xrplexplorer/previews/630x630/services/trustline.png b/public/images/xrplexplorer/previews/630x630/services/trustline.png deleted file mode 100644 index c3730a390..000000000 Binary files a/public/images/xrplexplorer/previews/630x630/services/trustline.png and /dev/null differ diff --git a/public/images/xrplexplorer/previews/630x630/tokens.png b/public/images/xrplexplorer/previews/630x630/tokens.png deleted file mode 100644 index 242a0cb2a..000000000 Binary files a/public/images/xrplexplorer/previews/630x630/tokens.png and /dev/null differ diff --git a/public/locales/de/common.json b/public/locales/de/common.json index 5cb8fde35..a35ca6c04 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -161,6 +161,7 @@ "description": "{{nativeCurrency}} Preisdiagramm | {{explorerName}} Statistiken | NFT Explorer | Wallet Adresssuche | {{explorerName}} NFT Volumen | NFT kaufen und verkaufen | {{explorerName}} Services", "search-placeholder": "Suche nach Adresse / Transaktion / NFT / Benutzername / PayString / Angebot", "search-placeholder-short": "Suche nach Adresse / Transaktion", + "scan-qr": "CODE SCANNEN", "price": { "header": "{{nativeCurrency}} Live Preis & Konverter" }, @@ -310,7 +311,7 @@ "error": "Fehler", "no-data": "Keine Daten verfügbar", "loading": "Lade...", - "login-to-bithomp-pro": "Das Laden weiterer Daten ist für <2>eingeloggte Bithomp Pro-Abonnenten verfügbar.", + "login-to-bithomp-pro": "Das Laden weiterer Daten ist für <1>eingeloggte Bithomp Pro-Abonnenten verfügbar.", "renew-bithomp-pro": "Your Bithomp Pro subscription has expired. <1>Renew your subscription.", "load-failed": "Laden fehlgeschlagen", "all-issuers": "Alle Emittenten", @@ -348,12 +349,10 @@ "error": { "payment-partly": "Bitte überweisen Sie den Rest des Betrages. Bis jetzt haben wir erst {{received}} {{currency}} erhalten, obwohl {{required}} {{currency}} erwartet wird.", "Network Error": "Es scheint keine Internetverbindung zu bestehen ;(", - "Request failed with status code 522": "Der Server ist momentan nicht erreichbar, versuchen Sie es später erneut.", "Request failed with status code 429": "Sie senden uns zu viele Anfragen. Versuchen Sie es später erneut!", "Request failed with status code 404": "Dieser API Aufruf ist auf diesem Netzwerk nicht erlaubt", "Request failed with status code 403": "Es sieht so aus, als wären Sie abgemeldet. Bitte loggen Sie sich erneut ein", - "Request aborted": "Anfrage abgebrochen", - "read ECONNRESET": "Die Anfrage hat zu lange gedauert. Versuchen Sie, Ihre Filter zu ändern oder es später erneut." + "Request aborted": "Anfrage abgebrochen" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "nach Besitzer", "by-taxon": "nach Taxon", "all-nfts": "Alle NFTs", - "listed": "Zum Verkauf", + "on-sale": "Zum Verkauf", "social-share": "Teilen ist Kümmern", "marketplace": "Marktplatz", "public-key": "Public Key", @@ -553,10 +552,8 @@ "all": "Alle", "buy": "Kaufen", "sell": "Verkaufen", - "buyNow": "Jetzt kaufen (Öffentlich + integrierte Marktplätze)", - "publicAndKnownBrokers": "Öffentlich & Marktplätze", - "public": "Öffentlich", - "knownBrokers": "Marktplätze", + "buyNow": "Jetzt kaufen", + "publicAndKnownBrokers": "Öffentlich & MP", "onSale": "Gelistet", "all-tokens": "Alle Tokens", "single-token": "Einzelner Token", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 18d419452..74781010e 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -29,7 +29,7 @@ "volumes": "Volumes", "sales": "Sales", "minters": "Minters", - "distribution": "Holders", + "distribution": "Distribution (holders)", "statistics": "Live statistics", "nfts": "Account's NFTs", "offers": "Account's Offers", @@ -161,6 +161,7 @@ "description": "Bithomp - The best {{nativeCurrency}} Explorer. Track Ripple USD (RLUSD), {{nativeCurrency}} accounts. Search {{nativeCurrency}} transactions. NFTs on {{explorerName}}. Validators, Amendments and much more.", "search-placeholder": "Search by Address / Transaction / NFT / Username / PayString / Offer / Currency hash", "search-placeholder-short": "Address / Transaction / Username", + "scan-qr": "SCAN A CODE", "price": { "header": "{{nativeCurrency}} Live Price & Converter" }, @@ -310,7 +311,7 @@ "error": "Error", "no-data": "No data available", "loading": "Loading...", - "login-to-bithomp-pro": "Loading more data is available to <2>logged-in Bithomp Pro subscribers.", + "login-to-bithomp-pro": "Loading more data is available to <1>logged-in Bithomp Pro subscribers.", "renew-bithomp-pro": "Your Bithomp Pro subscription has expired. <1>Renew your subscription.", "load-failed": "Failed to load", "all-issuers": "All issuers", @@ -348,12 +349,10 @@ "error": { "payment-partly": "Please send the rest of the amount, so far we only received {{received}} {{currency}} when {{required}} {{currency}} is required.", "Network Error": "It seems there is no internet connection ;(", - "Request failed with status code 522": "The server is currently unreachable, try again later.", "Request failed with status code 429": "You are sending us too many requests, try later!", "Request failed with status code 404": "Such API call is not allowed on that network", "Request failed with status code 403": "It seems you're logged out, please log in again", - "Request aborted": "Request aborted", - "read ECONNRESET": "The request timed out. Try changing your filters or try again later." + "Request aborted": "Request aborted" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "By owner", "by-taxon": "By taxon", "all-nfts": "All NFTs", - "listed": "Listed", + "on-sale": "On sale", "social-share": "Sharing is caring", "marketplace": "Marketplace", "public-key": "Public key", @@ -553,10 +552,8 @@ "all": "All", "buy": "Buy", "sell": "Sell", - "buyNow": "Buy now (Public + integrated MPs)", - "publicAndKnownBrokers": "Public & Marketplaces", - "public": "Public", - "knownBrokers": "Marketplaces", + "buyNow": "Buy now", + "publicAndKnownBrokers": "Public & MP", "onSale": "Listed", "all-tokens": "All tokens", "single-token": "Single token", diff --git a/public/locales/en/nft.json b/public/locales/en/nft.json index 5f3621b83..6aa58496d 100644 --- a/public/locales/en/nft.json +++ b/public/locales/en/nft.json @@ -1,7 +1,7 @@ { "desc": "Here you can search for NFTs, enter an NFT ID and press the search button.", "enter-nft-id": "Enter an NFT ID", - "holders": "Holders", + "holders": "Distribution (Holders)", "nft-id-decoded-data": "NFT ID decoded data", "nft-not-found-on-that-network": "This NFT wasn't found on the <1>{{network}} network.", "table": { diff --git a/public/locales/es/common.json b/public/locales/es/common.json index e2ffe3dc8..6d1747285 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -161,6 +161,7 @@ "description": "Gráfica de precio {{nativeCurrency}} | Estadísticas | Explorador NFT | Buscar dirección de cartera", "search-placeholder": "Buscar por Dirección / Transacción / NFT / Nombre de usuario / PayString / Oferta", "search-placeholder-short": "Dirección / Transacción / Usuario", + "scan-qr": "ESCANEA UN CÓDIGO", "price": { "header": "Precio en Vivo de {{nativeCurrency}} & Convertidor" }, @@ -310,7 +311,7 @@ "error": "Error", "no-data": "Datos no disponibles", "loading": "Cargando...", - "login-to-bithomp-pro": "Cargar más datos está disponible para los suscriptores de Bithomp Pro <2>con sesión iniciada.", + "login-to-bithomp-pro": "Cargar más datos está disponible para los suscriptores de Bithomp Pro <1>con sesión iniciada.", "renew-bithomp-pro": "Tu suscripción a Bithomp Pro ha expirado. <1>Renueva tu suscripción.", "load-failed": "Fallo al cargar", "all-issuers": "Todos los emisores", @@ -348,12 +349,10 @@ "error": { "payment-partly": "Por favor envia el resto de la cantidad, por el momento solo hemos recibido {{received}} {{currency}} de {{required}} {{currency}} requeridos.", "Network Error": "Parece que no hay conexión a internet ;(", - "Request failed with status code 522": "El servidor no está disponible en este momento, inténtalo de nuevo más tarde.", "Request failed with status code 429": "¡Nos estáis mandando demasiadas peticiones, prueba más tarde!", "Request failed with status code 404": "Este tipo de llamada a la API no está permitida en esa red.", "Request failed with status code 403": "Parece que has cerrado sesión, por favor, inicia sesión nuevamente.", - "Request aborted": "Solicitud abortada", - "read ECONNRESET": "La solicitud ha caducado. Intenta cambiar tus filtros o inténtalo de nuevo más tarde." + "Request aborted": "Solicitud abortada" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "Por dueño", "by-taxon": "Por taxon", "all-nfts": "Todos los NFTs", - "listed": "En venta", + "on-sale": "En venta", "social-share": "Compartir es vivir", "marketplace": "Mercado", "public-key": "Clave pública", @@ -553,10 +552,8 @@ "all": "Todo", "buy": "Compra", "sell": "Venta", - "buyNow": "Comprar ahora (Público + mercados integrados)", - "publicAndKnownBrokers": "Público y mercados", - "public": "Público", - "knownBrokers": "Mercados", + "buyNow": "Comprar ya", + "publicAndKnownBrokers": "Público Y Mercado", "onSale": "Listado", "all-tokens": "Todos los tokens", "single-token": "Token único", diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 3119a10b8..c14a6d305 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -161,6 +161,7 @@ "description": "Scannez le Registre {{nativeCurrency}}", "search-placeholder": "Rechercher par Adresse / Transaction / NFT / Nom d'utilisateur / PayString / Offre / Hash", "search-placeholder-short": "Adresse / Transaction / Nom d'utilisateur", + "scan-qr": "SCANNER UN CODE", "price": { "header": "Prix en direct {{nativeCurrency}} & Convertisseur" }, @@ -310,7 +311,7 @@ "error": "Erreur", "no-data": "Aucune donnée disponible", "loading": "Chargement...", - "login-to-bithomp-pro": "Charger plus de données est disponible pour les <2>abonnés connectés à Bithomp Pro.", + "login-to-bithomp-pro": "Charger plus de données est disponible pour les abonnés connectés à Bithomp Pro.", "renew-bithomp-pro": "Votre abonnement Bithomp Pro a expiré. <1>Renouveler votre abonnement.", "load-failed": "Échec du chargement", "all-issuers": "Tous les émetteurs", @@ -348,12 +349,10 @@ "error": { "payment-partly": "Veuillez envoyer le reste du montant, jusqu'à présent nous n'avons reçu que {{received}} {{currency}} alors que {{required}} {{currency}} est requis.", "Network Error": "Il semble qu'il n'y ait pas de connexion Internet ;(", - "Request failed with status code 522": "Le serveur est actuellement inaccessible, essayez de nouveau plus tard.", "Request failed with status code 429": "Vous nous envoyez trop de demandes, essayez plus tard !", "Request failed with status code 404": "Cet appel API n'est pas autorisé sur ce réseau", "Request failed with status code 403": "Il semble que vous soyez déconnecté, veuillez vous reconnecter", - "Request aborted": "Demande annulée", - "read ECONNRESET": "La demande a expiré. Essayez de modifier vos filtres ou réessayez plus tard." + "Request aborted": "Demande annulée" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "Par propriétaire", "by-taxon": "Par taxon", "all-nfts": "Tous les NFTs", - "listed": "En vente", + "on-sale": "En vente", "social-share": "Le partage, c'est bien", "marketplace": "Marché", "public-key": "Clé publique", @@ -553,10 +552,8 @@ "all": "Tout", "buy": "Acheter", "sell": "Vendre", - "buyNow": "Acheter maintenant (Public + places de marché intégrées)", - "publicAndKnownBrokers": "Public et places de marché", - "public": "Public", - "knownBrokers": "Places de marché", + "buyNow": "Acheter maintenant", + "publicAndKnownBrokers": "Public & MP", "onSale": "Sont en vente", "all-tokens": "Tous les tokens", "single-token": "Token unique", diff --git a/public/locales/id/common.json b/public/locales/id/common.json index 09e11b2f7..5aabc62cb 100644 --- a/public/locales/id/common.json +++ b/public/locales/id/common.json @@ -161,6 +161,7 @@ "description": "Grafik harga {{nativeCurrency}} | Statistik {{explorerName}} | Penjelajah NFT | Pencarian alamat dompet | Volume NFT {{explorerName}} | Beli dan Jual NFT | Layanan {{explorerName}}", "search-placeholder": "Cari berdasarkan Alamat / Transaksi / NFT / Username / PayString / Penawaran", "search-placeholder-short": "Cari berdasarkan Alamat / Transaksi", + "scan-qr": "PINDAI KODE", "price": { "header": "Harga {{nativeCurrency}} Langsung & Konverter" }, @@ -310,7 +311,7 @@ "error": "Kesalahan", "no-data": "Tidak ada data tersedia", "loading": "Memuat...", - "login-to-bithomp-pro": "Memuat lebih banyak data tersedia untuk pelanggan Bithomp Pro yang <2>termasuk login.", + "login-to-bithomp-pro": "Memuat lebih banyak data tersedia untuk pelanggan Bithomp Pro yang <1>termasuk login.", "renew-bithomp-pro": "Langganan Bithomp Pro Anda telah kedaluwarsa. <1>Perbarui langganan Anda.", "load-failed": "Gagal memuat", "all-issuers": "Semua penerbit", @@ -348,12 +349,10 @@ "error": { "payment-partly": "Silahkan kirim sisa jumlahnya, sejauh ini kami hanya menerima {{received}} {{currency}} saat {{required}} {{currency}} dibutuhkan.", "Network Error": "Sepertinya tidak ada koneksi internet ;(", - "Request failed with status code 522": "Server saat ini tidak dapat dijangkau, coba lagi nanti.", "Request failed with status code 429": "Anda mengirimkan terlalu banyak permintaan kepada kami, coba lagi nanti!", "Request failed with status code 404": "Panggilan API seperti itu tidak diizinkan di jaringan tersebut.", "Request failed with status code 403": "Sepertinya Anda telah keluar, silakan masuk kembali.", - "Request aborted": "Permintaan dibatalkan", - "read ECONNRESET": "Permintaan telah habis waktu. Coba ubah filter Anda atau coba lagi nanti." + "Request aborted": "Permintaan dibatalkan" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "Menurut Pemilik", "by-taxon": "Menurut Taksonomi", "all-nfts": "Semua NFT", - "listed": "Sedang Dijual", + "on-sale": "Sedang Dijual", "social-share": "Berbagi adalah Peduli", "marketplace": "Pasar", "public-key": "Kunci Publik", @@ -553,10 +552,8 @@ "all": "Semua", "buy": "Beli", "sell": "Jual", - "buyNow": "Beli sekarang (Publik + pasar terintegrasi)", - "publicAndKnownBrokers": "Publik & pasar", - "public": "Publik", - "knownBrokers": "Pasar", + "buyNow": "Buy now", + "publicAndKnownBrokers": "Publik & Broker Terkenal", "onSale": "Sedang dijual", "all-tokens": "Semua Token", "single-token": "Token Tunggal", diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index 5bbbf2a48..fb3bdfbf2 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -161,6 +161,7 @@ "description": "{{nativeCurrency}}価格アラート | {{explorerName}}統計情報 | NFTエクスプローラ | ウォレットアドレス検索 | {{explorerName}} NFT 情報 | NFTのトレード | {{explorerName}}サービス", "search-placeholder": "アドレス/トランザクション/NFT/ユーザネーム/PayString/オファー/通貨のハッシュで検索", "search-placeholder-short": "アドレス/トランザクション/ユーザで検索", + "scan-qr": "QRコードをスキャン", "price": { "header": "{{nativeCurrency}} 価格 & 変換" }, @@ -310,7 +311,7 @@ "error": "エラー", "no-data": "データがありません", "loading": "読み込み中...", - "login-to-bithomp-pro": "Bithomp Proの<2>サブスクリプション加入者は、さらに多くのデータを読み込むことができます。", + "login-to-bithomp-pro": "Bithomp Proの<1>サブスクリプション加入者は、さらに多くのデータを読み込むことができます。", "renew-bithomp-pro": "Bithomp Proのサブスクリプション期間が終了しました。<1>サブスクリプションを更新してください。.", "load-failed": "読み込みに失敗しました", "all-issuers": "全ての発行者", @@ -348,12 +349,10 @@ "error": { "payment-partly": "{{currency}} {{required}}が必要ですが、{{received}} {{currency}}しか受け取っていません。残りの金額を送金してください。", "Network Error": "インターネットに接続していないようです ;(", - "Request failed with status code 522": "サーバーに現在アクセスできません。後ほど再試行してください。", "Request failed with status code 429": "リクエストの送信数が多すぎます、後ほどお試しください!", "Request failed with status code 404": "そのようなAPIコールはそのネットワークでは許可されていません", "Request failed with status code 403": "ログアウトしています。再度ログインしてください。", - "Request aborted": "リクエストが中止されました", - "read ECONNRESET": "リクエストのタイムアウト。フィルターを変更するか、後で再試行してください。" + "Request aborted": "リクエストが中止されました" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "保有者情報", "by-taxon": "Taxon情報", "all-nfts": "全てのNFT", - "listed": "販売中", + "on-sale": "販売中", "social-share": "共有", "marketplace": "マーケットプレイス", "public-key": "公開鍵", @@ -553,10 +552,8 @@ "all": "全て", "buy": "購入", "sell": "売却", - "buyNow": "今すぐ購入(公開+統合マーケットプレイス)", - "publicAndKnownBrokers": "公開およびマーケットプレイス", - "public": "公開", - "knownBrokers": "マーケットプレイス", + "buyNow": "今すぐ購入", + "publicAndKnownBrokers": "パブリック & MP", "onSale": "販売中です", "all-tokens": "全トークン", "single-token": "単一トークン", diff --git a/public/locales/ko/common.json b/public/locales/ko/common.json index 4978dfb3a..066230ab7 100644 --- a/public/locales/ko/common.json +++ b/public/locales/ko/common.json @@ -161,6 +161,7 @@ "description": "{{nativeCurrency}} 가격 차트 | {{nativeCurrency}} 통계 | NFT 탐색기 | 지갑 주소 조회 | {{explorerName}} NFT 거래량 | NFT 구매 및 판매 | {{explorerName}} 서비스", "search-placeholder": "주소/거래/NFT/사용자명/페이스트링/제안/통화 해시로 검색하기", "search-placeholder-short": "주소/거래/사용자별 검색", + "scan-qr": "QR코드를 스캔하세요", "price": { "header": "{{nativeCurrency}} 실시간 가격 & 변환" }, @@ -310,7 +311,7 @@ "error": "오류", "no-data": "데이터를 찾을 수 없습니다", "loading": "대기 중", - "login-to-bithomp-pro": "더 많은 데이터를 로드하려면 <2>로그인한 Bithomp Pro 구독자가 필요합니다.", + "login-to-bithomp-pro": "더 많은 데이터를 로드하려면 <1>로그인한 Bithomp Pro 구독자가 필요합니다.", "renew-bithomp-pro": "귀하의 Bithomp Pro 구독이 만료되었습니다. <1>구독을 갱신하세요", "load-failed": "로딩에 실패했습니다", "all-issuers": "모든 발행자", @@ -348,12 +349,10 @@ "error": { "payment-partly": "{{currency}} {{required}}가 필요하지만 {{received}} {{currency}}만 받았습니다. 나머지 금액을 송금해 주세요.", "Network Error": "인터넷이 연결되어 있지 않습니다;", - "Request failed with status code 522": "서버에 현재 접속할 수 없습니다. 나중에 다시 시도하세요.", "Request failed with status code 429": "요청사항이 너무 많습니다. 나중에 다시 시도하세요", "Request failed with status code 404": "해당 네트워크에서는 이 API 호출이 허용되지 않습니다", "Request failed with status code 403": "로그아웃된 것 같습니다. 다시 로그인해주세요.", - "Request aborted": "요청이 취소되었습니다", - "read ECONNRESET": "요청이 시간 초과되었습니다. 필터를 변경하거나 나중에 다시 시도하세요." + "Request aborted": "요청이 취소되었습니다" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "소유자에 의한", "by-taxon": "분류군에 의한", "all-nfts": "모든 NFT", - "listed": "판매 중", + "on-sale": "판매 중", "social-share": "공유하기", "marketplace": "마켓 플레이스", "public-key": "공개 키", @@ -553,10 +552,8 @@ "all": "전체", "buy": "구매", "sell": "판매", - "buyNow": "지금 구매 (공개 + 통합 마켓플레이스)", - "publicAndKnownBrokers": "공개 및 마켓플레이스", - "public": "공개", - "knownBrokers": "마켓플레이스", + "buyNow": "Buy now", + "publicAndKnownBrokers": "공공 & MP", "onSale": "판매되고 있습니다", "all-tokens": "모든 토큰", "single-token": "단일 토큰", diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index d69bd46df..40778098e 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -161,6 +161,7 @@ "description": "Курс {{nativeCurrency}}, график цены {{nativeCurrency}}, статистика по {{nativeCurrency}} леджеру, NFT эксплорер, проверка адреса {{nativeCurrency}} кошелька, объёмы продаж {{explorerName}} NFT, покупка и продажа NFT, {{explorerName}} сервисы", "search-placeholder": "Поиск по Адресу / Транзакции / Псевдониму / PayString / NFT / Offer ID", "search-placeholder-short": "Адрес / Транзакция / Псевдоним", + "scan-qr": "СКАНИРОВАТЬ КОД", "price": { "header": "{{nativeCurrency}} Текущий курс & Конвертер" }, @@ -310,7 +311,7 @@ "error": "Ошибка", "no-data": "Данных нет", "loading": "Загрузка...", - "login-to-bithomp-pro": "Загрузка дополнительных данных доступна для <2>авторизованных пользователей с Bithomp Pro подпиской.", + "login-to-bithomp-pro": "Загрузка дополнительных данных доступна для <1>авторизованных пользователей с Bithomp Pro подпиской.", "renew-bithomp-pro": "Ваша Bithomp Pro подписка истекла. <1>Возобновить подписку.", "load-failed": "Ошибка загрузки", "all-issuers": "Все эмитенты", @@ -348,12 +349,10 @@ "error": { "payment-partly": "Нам пришло лишь {{received}} {{currency}}, когда мы ожидали {{required}} {{currency}}. Дошлите оставшееся, чтобы завершить регистрацию.", "Network Error": "Похоже, что у вас пропал интернет :(", - "Request failed with status code 522": "Сервер в данный момент недоступен, попробуйте позже.", "Request failed with status code 429": "Вы нам шлете слишком много запросов, попробуйте вернуться позже.", "Request failed with status code 404": "Этот API запрос не разрешен в этой сети", "Request failed with status code 403": "Похоже, что вышли из аккаунта, пожалуйста, войдите снова.", - "Request aborted": "Запрос отменен", - "read ECONNRESET": "Время запроса истекло. Попробуйте изменить фильтры или повторите попытку позже." + "Request aborted": "Запрос отменен" }, "errors": { "token": { @@ -487,7 +486,7 @@ "by-owner": "По владельцу", "by-taxon": "По таксону", "all-nfts": "Все NFT", - "listed": "На продаже", + "on-sale": "На продаже", "social-share": "Поделиться", "marketplace": "Маркетплейс", "public-key": "Публичный ключ", @@ -553,10 +552,8 @@ "all": "Все", "buy": "Покупка", "sell": "Продажа", - "buyNow": "Купить сейчас (Публичные + интегрированные маркетплейсы)", - "publicAndKnownBrokers": "Публичные и маркетплейсы", - "public": "Публичные предложения", - "knownBrokers": "Маркетплейсы", + "buyNow": "Купить сейчас", + "publicAndKnownBrokers": "Публичные и на MП", "onSale": "На продаже", "all-tokens": "Все токены", "single-token": "Один токен", diff --git a/styles/components/Account/AccountWithTag.module.scss b/styles/components/Account/AccountWithTag.module.scss deleted file mode 100644 index 7a7f25d9f..000000000 --- a/styles/components/Account/AccountWithTag.module.scss +++ /dev/null @@ -1,167 +0,0 @@ -.accountWithTag :global { - .account-tag-container { - max-width: 600px; - margin: 0 auto; - padding: 0px 20px 40px; - text-align: center; - box-shadow: 0px 0px 0px 5px rgba(0, 0, 0, 0.15); - - .dark & { - box-shadow: 0px 0px 0px 5px rgba(255, 255, 255, 0.1); - } - } - - .account-tag-title { - font-size: 18px; - font-weight: bold; - color: var(--text-main); - margin: 0px 0px 10px; - padding: 10px 0px; - border-bottom: 1.5px solid var(--text-secondary); - - .dark & { - border-bottom-color: var(--text-secondary); - } - } - - .account-tag-xaddress { - text-align: center; - margin-bottom: 10px; - color: var(--text-main); - word-break: break-all; - padding: 0 10px; - } - - .account-tag-service-description { - font-size: 14px; - margin-bottom: 20px; - color: var(--text-main); - } - - .account-tag-service-link { - color: var(--green); - text-decoration: none; - font-weight: bold; - - .dark & { - color: var(--green); - } - } - - .account-tag-service-link:hover { - text-decoration: underline; - } - - .account-tag-logo-container { - margin-bottom: 20px; - } - - .account-tag-logo { - width: 100px; - height: 100px; - object-fit: contain; - } - - .account-tag-details { - display: flex; - justify-content: space-between; - text-align: left; - font-size: 14px; - margin-top: 12px; - } - - .account-tag-detail-label { - width: 25%; - text-align: right; - } - - .account-tag-detail-label span { - color: var(--text-main); - } - - .account-tag-detail-value { - width: 70%; - color: var(--text-main); - word-break: break-all; - } - - .account-tag-address-link { - font-weight: bold; - font-size: 16px; - color: var(--text-main); - text-decoration: underline; - word-break: break-all; - - &:hover { - color: var(--accent-link); - } - - .dark & { - color: var(--text-main); - - &:hover { - color: var(--accent-link); - } - } - } - - .account-tag-destination-tag { - font-weight: bold; - color: var(--text-main); - } - - .account-tag-header { - margin-bottom: 30px; - } - - .account-tag-page-title { - color: var(--text-main); - margin-bottom: 10px; - } - - /* Mobile Responsive */ - @media (max-width: 767px) { - .account-tag-container { - padding: 20px 15px; - } - - .account-tag-title { - font-size: 16px; - } - - .account-tag-xaddress { - font-size: 12px; - padding: 0 5px; - } - - .account-tag-service-description { - font-size: 13px; - } - - .account-tag-details { - flex-direction: column; - font-size: 13px; - gap: 5px; - } - - .account-tag-detail-label { - width: 100%; - text-align: left; - margin-bottom: 5px; - - span { - font-weight: 600; - } - } - - .account-tag-detail-value { - width: 100%; - text-align: left; - font-size: 12px; - } - - .account-tag-address-link { - font-size: 12px; - } - } -} diff --git a/styles/components/filters.scss b/styles/components/filters.scss index 411e79107..5f4acbae9 100644 --- a/styles/components/filters.scss +++ b/styles/components/filters.scss @@ -133,6 +133,7 @@ $width: 340px; td { @media (max-width: 1550px) { padding: 5px; + font-size: 12px; } } } @@ -158,7 +159,7 @@ $width: 340px; .filter-header-title { @media (min-width: 1300px) { - margin-left: 98px; + margin-left: 55px; width: calc(100% - 140px); text-align: center; } @@ -217,57 +218,42 @@ $width: 340px; } } } -} - -.filters-toggle { - position: absolute; - top: 20px; - left: 15px; - - display: flex; - align-items: center; - gap: 8px; - - background: var(--background-input); - color: var(--text-main); - border: 1px solid var(--unaccent-icon); - - font-size: 15px; - padding: 8px 12px; - - cursor: pointer; - transition: all 0.25s ease; - &:hover { - background: var(--hover-bg, rgba(255,255,255,0.08)); - border-color: var(--text-main); - } - - .filters-icon { - font-size: 18px; - opacity: 0.9; - } - - @media (max-width: 440px) { - padding: 6px 8px; - } + &__toggle { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + top: 20px; + left: 15px; + background-color: var(--background-input); + margin: 0; + font-size: 20px; + padding: 4px; + border: 1px solid var(--unaccent-icon); + cursor: pointer; + color: var(--text-main); + + @media (min-width: 440px) { + width: 38px; + height: 38px; + } - @media (min-width: 440px) { - padding: 8px 14px; - } + @media (max-width: 440px) { + padding: 5px; + } - @media (max-width: 1300px) { - position: sticky; - top: 95px; - pointer-events: all; + @media (max-width: 1300px) { + position: sticky; + top: 95px; + pointer-events: all; + } } + } .filters-nav { & ~ .content-text { margin-top: 64px; - @media (max-width: 440px) { - margin-top: 56px; - } } } \ No newline at end of file diff --git a/styles/components/tiles.module.scss b/styles/components/tiles.module.scss index 81e213536..76933faf6 100644 --- a/styles/components/tiles.module.scss +++ b/styles/components/tiles.module.scss @@ -96,7 +96,7 @@ align-items: center; width: 48%; left: 26%; - bottom: 9%; + bottom: 10%; height: 16%; color: var(--text-main); font-size: 0.9em; diff --git a/styles/ui.scss b/styles/ui.scss index 9c7424306..38c0fff3e 100644 --- a/styles/ui.scss +++ b/styles/ui.scss @@ -317,7 +317,7 @@ table { tr { td, th { padding: 5px; - > &:nth-child(2) { + &:nth-child(2) { word-break: break-word; } hr { @@ -352,9 +352,6 @@ table { &.expand { width: calc(100% - 30px); } - > thead > tr > th { - font-size: 12px; - } > tbody > tr { &:hover { background-color: var(--unaccent-icon); @@ -395,7 +392,9 @@ table { &.table-mobile { margin: auto; font-size: 12px; - width: calc(100% - 30px); + &.wide { + width: 100%; + } tr { border: 1px solid var(--accent-link); > td:last-child, @@ -418,6 +417,9 @@ table { min-width: 100%; } } + &.table-mobile { + width: 100%; + } } } @@ -465,7 +467,7 @@ table { } .no-brake { - white-space: nowrap !important; + white-space: nowrap; } .uppercase { @@ -657,8 +659,7 @@ table { } .tooltiptext { - font-size: 12px; - display: none; + visibility: hidden; top: -5px; right: 120%; padding: 5px 10px; @@ -667,12 +668,8 @@ table { text-align: center; position: absolute; z-index: 1; - - white-space: normal; - pointer-events: none; - - opacity: 1; - transition: opacity 0.7s ease; + opacity: 0; + transition: opacity 0.7s; &:after { content: ""; position: absolute; @@ -712,8 +709,9 @@ table { } &:hover { .tooltiptext { - display: inline-block; + visibility: visible; opacity: 1; + word-break: normal; } } } @@ -762,7 +760,7 @@ pre { transition: max-height 0.5s ease-out; } &.opened { - max-height: 30000px; + max-height: 20000px; transition: max-height 0.5s ease-in; } } @@ -825,8 +823,7 @@ body.dark { font-size: 11px; font-weight: 500; border: 1px solid #008000; - margin-right: 5px; - cursor: default; + margin: 0; } //common ui diff --git a/utils/format.js b/utils/format.js index 76d803307..ea4a9bb85 100644 --- a/utils/format.js +++ b/utils/format.js @@ -18,29 +18,16 @@ import { stripText, xls14NftValue, tokenImageSrc, - mptokenImageSrc + mptokenImageSrc, + isNativeCurrency, + shortName } from '.' import { scaleAmount } from './calc' -import { LinkAmm, LinkToken } from './links' +import { LinkAmm } from './links' dayjs.extend(durationPlugin) dayjs.extend(relativeTimePlugin) -export const serviceUsernameOrAddressText = (data, name = 'address', options) => { - if (!data || !data[name]) return '' - const address = data[name] - const { service, username } = data[name + 'Details'] || {} - if (service) { - return service - } else if (username) { - return username - } else if (options?.fullAddress) { - return address - } else { - return shortHash(address) - } -} - export const NiceNativeBalance = ({ amount }) => { return ( @@ -52,174 +39,22 @@ export const NiceNativeBalance = ({ amount }) => { ) } -const TokenImage = ({ token }) => { - return ( -
    - token { - e.target.onerror = null - e.target.src = placeholder - }} - /> -
    - ) -} - -export const CurrencyWithIcon = ({ token, copy, hideIssuer, options }) => { - if (!token) return '' - - if (!token?.mptId) token.mptId = token.mptokenIssuanceID || token.MPTokenIssuanceID || token.mpt_issuance_id - - if (token.mptId) { - if (!token.issuer) { - token.issuer = token.mptokenCurrencyDetails?.account || token.Issuer || null - token.issuerDetails = token.mptokenCurrencyDetails?.accountDetails || token.issuerDetails || null - } - if (!token.metadata) { - token.metadata = token.mptokenCurrencyDetails?.metadata || null - } - } - - const { currencyDetails, issuer, mptId, currency } = token - - let imageUrl = avatarServer + issuer - - if (mptId) { - imageUrl = mptokenImageSrc(mptId) - } else { - imageUrl = tokenImageSrc(token) - } - - if (!issuer) { - imageUrl = nativeCurrenciesImages[nativeCurrency] - } - - let doubleIcon = false - let assetImageUrl, asset2ImageUrl - - // LP token - show 2 icons - if (currencyDetails?.asset && currencyDetails?.asset2) { - doubleIcon = true - assetImageUrl = tokenImageSrc(currencyDetails.asset) - asset2ImageUrl = tokenImageSrc(currencyDetails.asset2) - } - - return ( - <> - - - - - - - -
    - {doubleIcon ? ( -
    - {/* back coin */} - asset - {/* front coin */} - asset 2 -
    - ) : ( - avatar - )} -
    - - {copy && ( - <> - {' '} - - - )} - {!doubleIcon && !hideIssuer && ( - <> -
    - {mptId ? ( - <>{addressUsernameOrServiceLink(token, 'issuer', options)} - ) : ( - {serviceUsernameOrAddressText(token, 'issuer')} - )} - - )} -
    - {token?.flags &&
    {showFlags(token.flags)}
    } - - ) -} - -export const CurrencyWithIconInline = ({ token, copy, link }) => { +export const CurrencyWithIcon = ({ token }) => { if (!token) return '' const { lp_token, currencyDetails } = token - const currencyText = lp_token ? currencyDetails?.currency : niceCurrency(token.currency) + let imageUrl = tokenImageSrc(token) return ( <> - - {link && !lp_token ? : currencyText} - {copy && ( - <> - {' '} - - - )} + avatar + {lp_token ? currencyDetails?.currency : niceCurrency(token.currency)} ) } export const AddressWithIconInline = ({ data, name = 'address', options }) => { - if (!data || !data[name]) return '' const address = data[name] - const size = 16 + const size = 20 const placeholder = `data:image/svg+xml;utf8,${encodeURIComponent( ` @@ -232,49 +67,92 @@ export const AddressWithIconInline = ({ data, name = 'address', options }) => { return ( -
    { + e.target.onerror = null + e.target.src = placeholder }} - > - {data?.[name?.toLowerCase() { - e.target.onerror = null - e.target.src = placeholder - }} - /> -
    + /> {addressUsernameOrServiceLink(data, name, options)}
    ) } -export const AddressWithIcon = ({ children, address }) => { +export const AddressWithIcon = ({ children, address, currency, options }) => { let imageUrl = avatarServer + address + + if (currency) { + if (options?.mptId) { + imageUrl = mptokenImageSrc(options.mptId) + } else { + imageUrl = tokenImageSrc({ issuer: address, currency }) + } + } + if (!address) { imageUrl = nativeCurrenciesImages[nativeCurrency] } + + let doubleIcon = false + let assetImageUrl, asset2ImageUrl + + // LP token - show 2 icons + if (options?.currencyDetails?.asset && options?.currencyDetails?.asset2) { + doubleIcon = true + assetImageUrl = tokenImageSrc(options.currencyDetails.asset) + asset2ImageUrl = tokenImageSrc(options.currencyDetails.asset2) + } + return ( @@ -283,21 +161,48 @@ export const AddressWithIcon = ({ children, address }) => { ) } -export const AddressWithIconFilled = ({ data, name, copyButton, options }) => { +export const AddressWithIconFilled = ({ data, name, copyButton, options, currency }) => { if (!data) return '' if (!name) { name = 'address' } - const link = userOrServiceLink(data, name) + + const fullUrl = currency && !options?.mptId ? '/token/' + data[name] + '/' + currency : null + const link = userOrServiceLink(data, name, { fullUrl }) + + const ammId = options?.currencyDetails?.ammID + const lpToken = options?.currencyDetails?.type === 'lp_token' + + const textCurrency = options?.mptId + ? currency + : lpToken && options?.currencyDetails?.currency + ? options.currencyDetails.currency + : niceCurrency(currency) + return ( - - {link && ( + + {currency && ( <> - {link} -
    + {textCurrency}{' '} )} - {addressLink(data[name], options)} {copyButton && } + {options?.currencyName && + options.currencyName.length > 10 && + currency.length > 10 && + options.currencyName !== currency &&
    } + {options?.currencyName && options.currencyName !== currency && ( + {shortName(options.currencyName, { maxLength: 10 })} + )}{' '} + {link} + {(currency || options?.currencyName || link) &&
    } + {ammId ? ( + <> + AMM pool: + + ) : ( + <>{options?.flags ? showFlags(options.flags) : addressLink(data[name], { ...options, fullUrl })} + )}{' '} + {copyButton && }
    ) } @@ -312,31 +217,18 @@ export const amountToFiat = (params) => { const { amount, selectedCurrency, fiatRate } = params if (!amount || amount === '0' || !selectedCurrency || !fiatRate) return '' + let calculatedAmount = null let currency = '' - let initialAmount - let calculatedAmount if (!amount?.currency) { // drops - initialAmount = amount / 1000000 + calculatedAmount = shortNiceNumber((amount / 1000000) * fiatRate, 2, 1, selectedCurrency) currency = nativeCurrency } else { - initialAmount = amount.value + calculatedAmount = shortNiceNumber(amount.value * fiatRate, 2, 1, selectedCurrency) currency = niceCurrency(amount.currency) } - const absolute = Math.abs(initialAmount) - - if (params.absolute) { - initialAmount = absolute - } - - if (absolute > 1) { - calculatedAmount = shortNiceNumber(initialAmount * fiatRate, 2, 1, selectedCurrency) - } else { - calculatedAmount = niceNumber(initialAmount * fiatRate, null, selectedCurrency, 6) - } - if (params.asText) { return '≈' + calculatedAmount } @@ -345,10 +237,7 @@ export const amountToFiat = (params) => { {' '} ≈ {calculatedAmount} - + 1 {currency} = {shortNiceNumber(fiatRate, 2, 1, selectedCurrency)} @@ -560,7 +449,7 @@ export const nftIdLink = (nftId, chars = 10) => { export const nftLink = (nft, type, options = {}) => { if (!nft || !type || !nft[type]) return '' - let link = '/account/' + let link = '/explorer/' if (type === 'issuer') { link = '/nft-explorer?issuer=' } else if (type === 'owner' || type === 'seller' || type === 'buyer') { @@ -596,11 +485,19 @@ export const nftLink = (nft, type, options = {}) => { } } const showName = userOrServiceName(nft[type + 'Details']) - return ( - {showName ? showName : defaultContent} - ) + if (link === '/explorer/') { + return {showName ? showName : defaultContent} + } else { + return ( + {showName ? showName : defaultContent} + ) + } + } + if (link === '/explorer/') { + return {defaultContent} + } else { + return {defaultContent} } - return {defaultContent} } export const nftsExplorerLink = ({ owner, ownerDetails, issuer, issuerDetails, taxon }) => { @@ -650,29 +547,54 @@ export const userOrServiceLink = (data, type, options = {}) => { const { username, service } = data[typeDetails] let link = username ? username : data[type] - let buildLink = options?.url + link + let buildLink = options?.fullUrl || options?.url + link if (service) { let serviceName = service if (options.short && serviceName.length > 18) { serviceName = service.substring(0, 15).trim() + '...' } - return ( - - {serviceName} - - ) + if (options.url === '/explorer/') { + return ( + + {serviceName} + + ) + } else { + return ( + + {serviceName} + + ) + } } if (username) { - return ( - - {username} - - ) + if (options.url === '/explorer/') { + return ( + + {username} + + ) + } else { + return ( + + {username} + + ) + } } } return '' } +const oldExplorerLink = (address, options = {}) => { + if (!address) return '' + return ( + + {options.short ? shortAddress(address, options.short) : address} + + ) +} + export const addressUsernameOrServiceLink = (data, type, options = {}) => { if (!options.url) { options.url = '/account/' @@ -684,15 +606,23 @@ export const addressUsernameOrServiceLink = (data, type, options = {}) => { return userOrServiceLink(data, type, options) } if (options.short) { - return {shortAddress(data?.[type], options.short)} + if (options.url === '/explorer/') { + return oldExplorerLink(data?.[type], { short: options.short }) + } else { + return {shortAddress(data?.[type], options.short)} + } + } + if (options.url === '/explorer/') { + return oldExplorerLink(data[type]) + } else { + return {data?.[type]} } - return {data?.[type]} } export const addressLink = (address, options = {}) => { if (!address) return '' return ( - + {options?.short ? shortAddress(address, options.short) : address} ) @@ -809,30 +739,42 @@ export const amountFormat = (amount, options = {}) => { let showValue = value - if (options.absolute) { - showValue = Math.abs(showValue) - } - if (options.precise) { if (options.precise === 'nice') { - showValue = niceNumber(showValue, 0, null, 15) + showValue = niceNumber(value, 0, null, 15) } - } else if (options.short) { - showValue = shortNiceNumber(showValue) } else { - showValue = niceNumber(showValue, options.minFractionDigits, null, options.maxFractionDigits || 6) + if (Math.abs(value) >= 100) { + if (options.short) { + showValue = shortNiceNumber(value, 0, 1) + } else { + if (options.minFractionDigits) { + showValue = niceNumber(value, options.minFractionDigits) + } else { + showValue = niceNumber(value) + } + } + } else if (options.maxFractionDigits) { + showValue = niceNumber(value, 0, null, options.maxFractionDigits) + } } - let showIcon = options?.icon || false - // do not show icons for native currency - if (showIcon && originalCurrency === nativeCurrency) { - showIcon = false + if (options?.icon && originalCurrency === nativeCurrency) { + options.icon = false } let tokenImage = '' - if (showIcon) { - tokenImage = + if (options?.icon) { + tokenImage = ( + + ) } if (options.showPlus && value > 0) { @@ -871,9 +813,7 @@ export const amountFormat = (amount, options = {}) => { {amount.currencyDetails?.type === 'lp_token' ? ( ) : ( - addressUsernameOrServiceLink({ issuer, issuerDetails }, 'issuer', { - short: options?.issuerShort !== undefined ? options.issuerShort : true - }) + addressUsernameOrServiceLink({ issuer, issuerDetails }, 'issuer', { short: true }) )} ) @@ -882,12 +822,10 @@ export const amountFormat = (amount, options = {}) => { )} ) - } else if (options?.icon) { - // keep options?.icon as showIcon is false for native currency + } else if (options.icon) { return ( - {tokenImage} - {showValue + ' ' + valuePrefix + ' ' + textCurrency} + {tokenImage} {showValue + ' ' + valuePrefix + ' ' + textCurrency} ) } else { @@ -1161,7 +1099,7 @@ export const duration = (t, seconds, options) => { } //need to make dynamic fraction digits -export const niceNumber = (n, fractionDigits = null, currency = null, maxFractionDigits = null) => { +export const niceNumber = (n, fractionDigits = 0, currency = null, maxFractionDigits = 0) => { if (typeof n === 'string') { if (n.includes('x')) { //in case of placeholders xxx @@ -1172,8 +1110,8 @@ export const niceNumber = (n, fractionDigits = null, currency = null, maxFractio } if (n || n === 0 || n === '0') { let options = { - maximumFractionDigits: maxFractionDigits || fractionDigits || 0, - minimumFractionDigits: fractionDigits || 0 + maximumFractionDigits: maxFractionDigits || fractionDigits, + minimumFractionDigits: fractionDigits } if (currency) { options.style = 'currency' @@ -1310,16 +1248,15 @@ export const showAmmPercents = (x) => { } export const showFlags = (flags) => { - if (!flags || Object.keys(flags).length === 0) return null - const trueFlags = Object.entries(flags).filter(([, flagValue]) => flagValue === true) - if (!trueFlags?.length) return null return ( - <> - {trueFlags.map(([flag]) => ( - - {flag} - - ))} - +
    + {Object.entries(flags) + .filter(([, flagValue]) => flagValue === true) + .map(([flag]) => ( + + {flag} + + ))} +
    ) } diff --git a/utils/index.js b/utils/index.js index b1b886679..3bf0b7852 100644 --- a/utils/index.js +++ b/utils/index.js @@ -5,14 +5,6 @@ import Cookies from 'universal-cookie' import axios from 'axios' import SparkMD5 from 'spark-md5' -export const errorT = (t, errorMessage, defaultMessage) => { - const translation = t(`error.${errorMessage}`) - if (translation === `error.${errorMessage}`) { - return defaultMessage || errorMessage - } - return translation -} - export const forbid18Plus = async () => { //check if we have a saved country for the user let savedCountry = localStorage.getItem('country') @@ -553,9 +545,8 @@ export const networks = { server: 'https://bithomp.com', nativeCurrency: 'XRP', getCoinsUrl: '/go/buy-first-xrp', - explorerName: 'XRPL', + explorerName: 'XRP Ledger', ledgerName: 'XRPL', - siteName: 'Bithomp', minLedger: 32570, subname: '' }, @@ -566,7 +557,6 @@ export const networks = { getCoinsUrl: '/faucet', explorerName: 'XRPL Staging', ledgerName: 'XRPL', - siteName: 'Bithomp', minLedger: 32570, subname: '' }, @@ -577,7 +567,6 @@ export const networks = { getCoinsUrl: '/faucet', explorerName: 'XRPL Testnet', ledgerName: 'XRPL', - siteName: 'Bithomp', minLedger: 1, subname: 'Testnet' }, @@ -588,21 +577,9 @@ export const networks = { getCoinsUrl: '/faucet', explorerName: 'XRPL Devnet', ledgerName: 'XRPL', - siteName: 'Bithomp', minLedger: 1, subname: 'Devnet' }, - alphanet: { - id: 21465, - server: 'https://alphanet.bithomp.com', - nativeCurrency: 'XRP', - getCoinsUrl: '/faucet', - explorerName: 'XRPL AlphaNet', - ledgerName: 'XRPL', - siteName: 'Bithomp', - minLedger: 1, - subname: 'AlphaNet' - }, xahau: { id: 21337, server: 'https://xahauexplorer.com', @@ -610,7 +587,6 @@ export const networks = { getCoinsUrl: null, explorerName: 'Xahau', ledgerName: 'Xahau', - siteName: 'Xahau Explorer', minLedger: 1, subname: '' }, @@ -621,7 +597,6 @@ export const networks = { getCoinsUrl: '/faucet', explorerName: 'Xahau Testnet', ledgerName: 'Xahau', - siteName: 'Xahau Explorer', minLedger: 3, subname: 'Testnet' }, @@ -632,7 +607,6 @@ export const networks = { getCoinsUrl: '/faucet', explorerName: 'Xahau JS Hooks', ledgerName: 'Xahau', - siteName: 'Xahau Explorer', minLedger: 12, subname: 'JS Hooks' } @@ -653,7 +627,6 @@ export const nativeCurrency = networks[network]?.nativeCurrency export const getCoinsUrl = networks[network]?.getCoinsUrl export const explorerName = networks[network]?.explorerName export const ledgerName = networks[network]?.ledgerName -export const siteName = networks[network]?.siteName export const ledgerSubName = networks[network]?.subname export const minLedger = networks[network]?.minLedger const webAddressParts = server?.replace('http://', '').replace('https://', '').split('.') @@ -690,7 +663,6 @@ export const networksIds = { 0: { server: 'https://bithomp.com', name: 'mainnet' }, 1: { server: 'https://test.bithomp.com', name: 'testnet' }, 2: { server: 'https://dev.bithomp.com', name: 'devnet' }, - 21465: { server: 'https://alphanet.bithomp.com', name: 'alphanet' }, 21337: { server: 'https://xahauexplorer.com', name: 'xahau' }, 21338: { server: 'https://test.xahauexplorer.com', name: 'xahau-testnet' }, 31338: { server: 'https://jshooks.xahauexplorer.com', name: 'xahau-jshooks' } @@ -721,8 +693,6 @@ export const networkMinimumDate = (type = 'ledger') => { minDate = new Date('2023-08-09T01:53:41.000Z') // first nft in history for the testnet } else if (network === 'devnet') { minDate = new Date('2023-09-19T20:36:40.000Z') // first nft in history for the devnet - } else if (network === 'alphanet') { - minDate = new Date('2025-11-01T00:00:00.000Z') // first nft in history for the alpanet // update later } else { minDate = new Date('2013-01-01T03:21:10.000Z') // ledger 32570 } @@ -776,7 +746,6 @@ export const isAddressValid = (x) => { } export const isTagValid = (x) => { - if (x === 0 || x === '0') return true if (!x) return false if (!/^[0-9]{1,10}$/.test(x)) return false if (parseInt(x) > 4294967295) return false diff --git a/utils/koinly.js b/utils/koinly.js index 6553f6f4b..23a5d11a4 100644 --- a/utils/koinly.js +++ b/utils/koinly.js @@ -90,14 +90,7 @@ export const koinly = { 'rPUNKXyoE6zZB3nRSTuU7DoUKiQfi8KeK8:XSP': 'ID:6218301', 'rh5jzTCdMRCVjQ7LT6zucjezC47KATkuvv:7853504543544152000000000000000000000000': 'ID:4794440', 'rLC88EkvQUmVM3PVzDejTBzRGx1hKwBsUf:5857415253000000000000000000000000000000': 'ID:5437658', - 'rsxkrpsYaeTUdciSFJwvto7MKSrgGnvYvA:5A52505900000000000000000000000000000000': 'ID:10593439', - 'rhCAT4hRdi2Y9puNdkpMzxrdKa5wkppR62:46555A5A59000000000000000000000000000000': 'ID:32618189', - 'rnh3kiVFSBJxhwa7RJmmafQrqhyn9SKyCj:57494E4400000000000000000000000000000000': 'ID:42257888', - 'rM2LZ53PobDBpEWZJp9cCAZhViRyy1TbyL:524F434B00000000000000000000000000000000': 'ID:46243281', - 'rGKbEcq5yy77oxQPznc7ui2sAV8C5wE1f2:0365EC16A1AE9A9BDD7E07B91E4540293F1746AA': 'ID:50614770', - 'rsharravubinb5h1j17zb5vopeqmlpdypd:46494D5000000000000000000000000000000000': 'ID:46411321', - 'rKpX8Mo1HJmiAFjq7offhAdFg1XgtyfsZZ:50484E5800000000000000000000000000000000': 'ID:45579585', - 'rg7jt6d4fhsipvvmpsbcnvdtfzxwwsr4qx:524942424C450000000000000000000000000000': 'ID:32245396' + 'rsxkrpsYaeTUdciSFJwvto7MKSrgGnvYvA:5A52505900000000000000000000000000000000': 'ID:10593439' }, xahau: { 'rK8rYUs6gFH4QJ9JS814EF9112gKuYZZT:CLV': 'ID:9511442', diff --git a/utils/ledgerwallet.js b/utils/ledgerwallet.js index f3e6b531e..025951456 100644 --- a/utils/ledgerwallet.js +++ b/utils/ledgerwallet.js @@ -2,85 +2,36 @@ import TransportWebHID from '@ledgerhq/hw-transport-webhid' import Xrp from '@ledgerhq/hw-app-xrp' import { broadcastTransaction, getNextTransactionParams } from './user' import { encode } from 'xrpl-binary-codec-prerelease' -import { nativeCurrency, xahauNetwork } from '.' -import { xahauDefinitions } from './xahau' const errorHandle = (error) => { - const msg = String(error?.message || error) - const statusCode = error?.statusCode - - // App-level status from Ledger (e.g. 0x650f when app is not open) - if (error?.name === 'TransportStatusError' && typeof statusCode === 'number') { - console.error('Ledger TransportStatusError:', statusCode, error.statusText) - - if (statusCode === 0x650f) { - throw new Error('Please unlock your Ledger device and open the ' + nativeCurrency + ' app, then try again.') - } - - // CLA_NOT_SUPPORTED - if (statusCode === 0x6e00) { - throw new Error( - 'This Ledger app does not support the requested command. Make sure the ' + nativeCurrency + ' app is open.' - ) - } - - if (statusCode === 0x6985) { - throw new Error('Signing cancelled on your Ledger device.') - } - - throw new Error(`Ledger error: ${error.statusText || 'Unknown status'} (0x${statusCode.toString(16)})`) - } - - // Device already in use (other tab/app) - if (msg.includes('already open') || error?.name === 'InvalidStateError') { - console.warn('Ledger WebHID: device is already open somewhere else.') - throw new Error('Ledger device is already in use. Close other Ledger apps or browser tabs and try again.') + // Handle specific errors based on the message or error type + if (error.message.includes('already open')) { + throw new Error('Something went wrong connecting to your Ledger. Please refresh your page and try again.') } - if (msg.includes('Locked device')) { + // Handle LockedDeviceError: Device requires PIN entry + if (error.message.includes('Locked device')) { console.error('Ledger device is locked. Please enter your PIN.') throw new Error('Ledger device is locked. Please unlock it by entering your PIN.') } - if (msg.includes('TransportError')) { + // Handle TransportError (WebHID issues) + if (error.message.includes('TransportError')) { console.error('Transport error: Unable to communicate with Ledger device.') throw new Error('Transport error. Ensure your device is connected properly.') } + // General fallback for other errors console.error('An unexpected error occurred:', error) throw new Error('An unexpected error occurred while connecting to the Ledger device.') } -// 🔒 one instance for module -let xrpAppPromise = null -let xrpAppInstance = null - const connectLedgerHID = async () => { - // if already connected - reuse it - if (xrpAppPromise) return xrpAppPromise - - xrpAppPromise = TransportWebHID.create() - .then((transport) => { - const app = new Xrp(transport) - xrpAppInstance = app - - // if transport supports 'on' method - listen for disconnect event - if (typeof transport.on === 'function') { - transport.on('disconnect', () => { - xrpAppPromise = null - xrpAppInstance = null - }) - } - - return app - }) + return TransportWebHID.create() + .then((transport) => new Xrp(transport)) .catch((error) => { - xrpAppPromise = null - xrpAppInstance = null errorHandle(error) }) - - return xrpAppPromise } const getLedgerAddress = async (xrpApp, path = "44'/144'/0'/0/0") => { @@ -92,17 +43,14 @@ const getLedgerAddress = async (xrpApp, path = "44'/144'/0'/0/0") => { } } -// one helper for both XRPL & Xahau -const encodeTx = (tx) => (xahauNetwork ? encode(tx, xahauDefinitions) : encode(tx)) - const signTransactionWithLedger = async (xrpApp, tx, path = "44'/144'/0'/0/0") => { try { - const encodetx = encodeTx(tx) + const encodetx = encode(tx) //, DEFAULT_DEFINITIONS const signature = await xrpApp.signTransaction(path, encodetx) return signature.toUpperCase() } catch (error) { console.error('Failed to sign transaction:', error) - throw new Error('Unable to sign transaction with Ledger via WebHID.') + throw new Error('Unable to sign transaction with Ledger via WebHID.', error) } } @@ -120,12 +68,14 @@ const ledgerwalletSign = async ({ }) => { const signRequestData = signRequest.data + // If the transaction field Account is not set, the account of the user's wallet will be used. + if (signRequestData?.signOnly) { setStatus('Sign the transaction in Ledger Wallet.') try { const signature = await signTransactionWithLedger(xrpApp, tx) tx.TxnSignature = signature - const blob = encodeTx(tx) + const blob = encode(tx) afterSigning({ signRequestData, blob, address }) } catch (err) { setStatus(err.message) @@ -136,7 +86,7 @@ const ledgerwalletSign = async ({ if (!tx || tx?.TransactionType === 'SignIn') { onSignIn({ address, wallet, redirectName: signRequest.redirect }) - // keep afterSubmitExe here to close the dialog form when signed in + //keept afterSubmitExe here to close the dialog form when signedin afterSubmitExe({}) return } @@ -157,10 +107,8 @@ const ledgerwalletSign = async ({ try { const signature = await signTransactionWithLedger(xrpApp, tx) tx.TxnSignature = signature - - // use same encoding as for signing - const blob = encodeTx(tx) - + const blob = encode(tx) // , DEFAULT_DEFINITIONS + //now submit transaction setStatus('Submitting transaction to the network...') setAwaiting(true) broadcastTransaction({ @@ -214,17 +162,3 @@ export const ledgerwalletTxSend = async ({ setStatus(err.message) } } - -// 🔌 explicit disconnect for sign-out -export const ledgerwalletDisconnect = async () => { - if (!xrpAppInstance) return - - try { - await xrpAppInstance.transport.close() - } catch (e) { - console.warn('Error while closing Ledger transport', e) - } finally { - xrpAppInstance = null - xrpAppPromise = null - } -} diff --git a/utils/links.js b/utils/links.js index 47ac7a336..4c6919061 100644 --- a/utils/links.js +++ b/utils/links.js @@ -1,79 +1,10 @@ import Link from 'next/link' import LinkIcon from '../public/images/link.svg' -import { niceCurrency, shortHash } from './format' +import { shortHash } from './format' import CopyButton from '../components/UI/CopyButton' -import { isValidTaxon } from './nft' -import { shortName } from '.' -export const LinkToken = ({ token, icon, copy, children }) => { - if (!token) return '' - const { currencyDetails, issuer, mptId, currency, metadata } = token - - const tokenUrl = '/token/' + issuer + '/' + currency - const lpToken = currencyDetails?.type === 'lp_token' - const mptCurrency = metadata?.currency || metadata?.c || currency || 'N/A' - - const textCurrency = mptId - ? mptCurrency - : lpToken && currencyDetails?.currency - ? currencyDetails.currency - : niceCurrency(currency) - - const ammId = currencyDetails?.ammID - - const linkAmm = lpToken && ammId - - let currencyName = metadata?.name - if (currencyName) { - currencyName = currencyName !== textCurrency ? shortName(currencyName, { maxLength: 10 }) : null - } - - return ( - <> - {!linkAmm && !mptId ? ( - - {children || icon ? : textCurrency} - - ) : ( - <> - {linkAmm ? ( - - - - ) : ( - <> - {textCurrency} - {mptId && <> {currencyName}} - - )} - - )} - {copy && ( - <> - {' '} - - - )} - - ) -} - -export const LinkTx = ({ tx, icon, short, children, copy }) => - tx ? ( - <> - {children || (icon ? : shortHash(tx, short || 10))} - {copy ? ( - <> - {' '} - - - ) : ( - '' - )} - - ) : ( - '' - ) +export const LinkTx = ({ tx, icon, short, children }) => + tx ? {children || (icon ? : shortHash(tx, short || 10))} : '' export const LedgerLink = ({ version, text, style, onClick }) => version ? ( @@ -167,41 +98,3 @@ export const LinkObject = ({ objectId, ledgerIndex, hash, icon, copy, text, styl ) : ( '' ) - -export const LinkListedNfts = ({ - children, - issuer, - taxon, - collection, - saleCurrency, - saleCurrencyIssuer, - saleDestination -}) => { - let collectionPart = '' - if (issuer && isValidTaxon(taxon)) { - collectionPart = '&issuer=' + issuer + '&taxon=' + taxon - } else if (collection) { - collectionPart = '&collection=' + collection - } - - let currencyPart = '' - if (saleCurrency) { - currencyPart = '&saleCurrency=' + saleCurrency - if (saleCurrencyIssuer) currencyPart += '&saleCurrencyIssuer=' + saleCurrencyIssuer - } - - return ( - { } } //image from animation - if (meta.animation) return assetUrl(meta.animation, type, gateway, flags) - if (meta.animation_url) return assetUrl(meta.animation_url, type, gateway, flags) + if (meta.animation) return assetUrl(meta.animation, 'preview', gateway, flags) + if (meta.animation_url) return assetUrl(meta.animation_url, 'preview', gateway, flags) } if (type === 'video' || type === 'thumbnail' || type === 'preview') { if (meta.video) return assetUrl(meta.video, type, gateway, flags) diff --git a/utils/transaction/index.js b/utils/transaction.js similarity index 79% rename from utils/transaction/index.js rename to utils/transaction.js index 233c1b375..ba27e55f2 100644 --- a/utils/transaction/index.js +++ b/utils/transaction.js @@ -1,23 +1,8 @@ -import React from 'react' -import { nativeCurrency, safeClone } from '..' -import { TData } from '../../components/Table' -import { add } from '../calc' -import { decodeJsonMemo } from '../format' - -// sourse address and destination address is the same -// sometimes source tag is added to show the dapp -// so if there is no destintaion tag, no need the source tag to be the same -export const isConvertionTx = (specification) => { - if (!specification) return false - return ( - specification?.source?.address === specification?.destination?.address && - (specification?.source?.tag === specification?.destination?.tag || !specification?.destination?.tag) - ) -} +import { nativeCurrency, safeClone } from '.' +import { add } from './calc' // Function to get balance changes for a specific address const getBalanceChanges = (data, address) => { - if (!data || !address) return null const balanceChange = data.filter((entry) => entry.address === address) return balanceChange[0]?.balanceChanges } @@ -44,7 +29,6 @@ export const addressBalanceChanges = (data, address) => { balanceChanges.push(change) } } - return balanceChanges } @@ -110,7 +94,7 @@ export const errorCodeDescription = (code) => { tecINSUFFICIENT_PAYMENT: 'The amount specified is not enough to pay all fees involved in the transaction. For example, when trading a non-fungible token, the buy amount may not be enough to pay both the broker fee and the sell amount.', tecINSUFFICIENT_RESERVE: - "The transaction would increase the reserve requirement higher than the sending account's balance.", + "The transaction would increase the reserve requirement higher than the sending account's balance. SignerListSet, PaymentChannelCreate, PaymentChannelFund, and EscrowCreate can return this error code. See Signer Lists and Reserves for more information.", tecINTERNAL: 'Unspecified internal error, with transaction cost applied. This error code should not normally be returned. If you can reproduce this error, please report an issue .', tecINVARIANT_FAILED: @@ -313,7 +297,6 @@ export const dappBySourceTag = (sourceTag) => { 5523279: 'Things Go Online', 10000001: 'MetaTV', 10011001: 'Myrkle', - 10011010: 'Magnetic', 10102021: 'Junction', 10509910: 'xLux', 11782013: 'Anodos', @@ -400,188 +383,3 @@ export const dappBySourceTag = (sourceTag) => { //max sourceTag is 4294967295, more than that are invalid. return dapps[sourceTag] || null } - -export const memoNode = (memos, type = 'tr') => { - let output = [] - if (memos && Array.isArray(memos)) { - for (let j = 0; j < memos.length; j++) { - const memo = memos[j] - let memotype = memo?.type - let memopiece = memo?.data - let memoformat = memo?.format - - const redFlags = ['airdrop', 'claim'] - - const memop = memopiece?.toString().toLowerCase() || '' - - if (redFlags.some((flag) => memop.includes(flag)) && type !== 'tr') { - continue - } - - if (!memopiece && memoformat?.slice(0, 2) === 'rt') { - memopiece = memoformat - } - - let clientname = '' - - if (memopiece) { - if (memopiece.includes('xrplexplorer.com') || memopiece.includes('bithomp.com')) { - clientname = memopiece.replace(/xrplexplorer\.com/g, 'bithomp.com') - memopiece = '' - } else if (memopiece.includes('xahauexplorer.com')) { - clientname = memopiece - memopiece = '' - } else if (memopiece.includes('initiated via xmagnetic.org')) { - clientname = 'xmagnetic.org' - memopiece = '' - } - - if (memotype) { - if (memotype.slice(0, 25) === '[https://xumm.community]-') { - memotype = memotype.slice(25) - clientname = 'xumm.community' - } else if (memotype.slice(0, 24) === '[https://xrpl.services]-') { - memotype = memotype.slice(24) - clientname = 'xrpl.services' - } else { - memotype = memotype.charAt(0).toUpperCase() + memotype.slice(1) - } - } - - if (decodeJsonMemo(memopiece)) { - if (type === 'tr') { - output.push( -
    - Memo{memos.length > 1 ? ' ' + (j + 1) : ''} - - {memotype && ( - <> - {memotype} -
    - - )} - {decodeJsonMemo(memopiece)} -
    - - ) - } else { - output.push( - - Memo{memos.length > 1 ? ' ' + (j + 1) : ''}: -
    - {memotype && ( - <> - {memotype} -
    - - )} - {decodeJsonMemo(memopiece)} -
    -
    - ) - } - } else { - if (memopiece.length > 100 && memopiece.split(' ').length === 1 && memopiece.includes('.')) { - //jwt - memopiece = memopiece.replace('"', '') - const pieces = memopiece.split('.') - if (type === 'tr') { - output.push( - - - JWT Header - {decodeJsonMemo(pieces[0], { code: 'base64' })} - - - JWT Payload - {decodeJsonMemo(pieces[1], { code: 'base64' })} - - - JWT Signature - -
    {pieces[2]}
    -
    - - - ) - } else { - output.push( - - JWT Header: -
    - {decodeJsonMemo(pieces[0], { code: 'base64' })} -
    - JWT Payload: -
    - {decodeJsonMemo(pieces[1], { code: 'base64' })} -
    - JWT Signature: -
    -
    {pieces[2]}
    -
    -
    - ) - } - } else { - if (memopiece) { - if (type === 'tr') { - output.push( - - Memo{memos.length > 1 ? ' ' + (j + 1) : ''} - - {memotype && memotype.toLowerCase() !== 'memo' && ( - - {memotype} -
    -
    - )} - {memopiece} -
    - - ) - } else { - output.push( - - Memo{memos.length > 1 ? ' ' + (j + 1) : ''}:{' '} - {memotype && memotype.toLowerCase() !== 'memo' && <>{memotype + ': '}} - {memopiece} -
    -
    - ) - } - } - } - } - - if (clientname) { - if (type === 'tr') { - output.push( - - Client web - - - {clientname} - - - - ) - } else { - output.push( - - Client web:{' '} - - {clientname} - -
    -
    - ) - } - } - } - } - } - if (output.length === 0) { - return null - } - return output -} diff --git a/utils/transaction/payment.js b/utils/transaction/payment.js deleted file mode 100644 index b616812f0..000000000 --- a/utils/transaction/payment.js +++ /dev/null @@ -1,45 +0,0 @@ -import { addressBalanceChanges, isConvertionTx } from '.' -import { xls14NftValue } from '..' - -export const isRipplingOnIssuer = (sourceBalanceChangesList, address) => { - return sourceBalanceChangesList?.length > 1 && sourceBalanceChangesList.every((item) => item.issuer === address) -} - -export const paymentTypeName = (data) => { - if (!data) return 'Payment' - const { outcome, specification } = data - let type = 'Payment' - if (isConvertionTx(specification)) { - type = 'Currency exchange' - } - if (xls14NftValue(outcome?.deliveredAmount?.value)) { - type = 'NFT transfer (XLS-14)' - } - return type -} - -export const isIOUpayment = (data) => { - if (!data) return false - const { outcome, specification } = data - let iouPayment = false - const sourceBalanceChangesList = addressBalanceChanges(data, specification.source.address) - if (!isConvertionTx(specification)) { - //check if iou involved (pathfinding or iou with fee) - if ( - !outcome?.deliveredAmount?.mpt_issuance_id && - sourceBalanceChangesList?.[0]?.value !== '-' + outcome?.deliveredAmount?.value - ) { - iouPayment = true - } - } - return iouPayment -} - -export const optionalAbsPaymentAmount = (change, isConvertion) => { - return !isConvertion && (change?.value ? change.value.toString()[0] === '-' : change?.toString()[0] === '-') - ? { - ...change, - value: change?.value ? change?.value.toString().slice(1) : change?.toString().slice(1) - } - : change -} diff --git a/utils/xahau.js b/utils/xahau.js deleted file mode 100644 index 80ddea0ad..000000000 --- a/utils/xahau.js +++ /dev/null @@ -1,1126 +0,0 @@ -import { XrplDefinitions, nativeAsset } from 'xrpl-binary-codec-prerelease' - -const rawXahauDefs = { - result: { - FIELDS: [ - ['Generic', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 0, type: 'Unknown' }], - ['Invalid', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: -1, type: 'Unknown' }], - ['ObjectEndMarker', { isSerialized: false, isSigningField: true, isVLEncoded: false, nth: 1, type: 'STObject' }], - ['ArrayEndMarker', { isSerialized: false, isSigningField: true, isVLEncoded: false, nth: 1, type: 'STArray' }], - ['hash', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 257, type: 'Hash256' }], - ['index', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 258, type: 'Hash256' }], - [ - 'taker_gets_funded', - { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 258, type: 'Amount' } - ], - [ - 'taker_pays_funded', - { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 259, type: 'Amount' } - ], - ['LedgerEntryType', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'UInt16' }], - ['TransactionType', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'UInt16' }], - ['SignerWeight', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'UInt16' }], - ['TransferFee', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'UInt16' }], - ['Version', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'UInt16' }], - [ - 'HookStateChangeCount', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'UInt16' } - ], - ['HookEmitCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'UInt16' }], - ['HookExecutionIndex', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'UInt16' }], - ['HookApiVersion', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 20, type: 'UInt16' }], - ['HookStateScale', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 21, type: 'UInt16' }], - ['NetworkID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'UInt32' }], - ['Flags', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'UInt32' }], - ['SourceTag', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'UInt32' }], - ['Sequence', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'UInt32' }], - ['PreviousTxnLgrSeq', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 5, type: 'UInt32' }], - ['LedgerSequence', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 6, type: 'UInt32' }], - ['CloseTime', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 7, type: 'UInt32' }], - ['ParentCloseTime', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 8, type: 'UInt32' }], - ['SigningTime', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 9, type: 'UInt32' }], - ['Expiration', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 10, type: 'UInt32' }], - ['TransferRate', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 11, type: 'UInt32' }], - ['WalletSize', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 12, type: 'UInt32' }], - ['OwnerCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 13, type: 'UInt32' }], - ['DestinationTag', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 14, type: 'UInt32' }], - ['HighQualityIn', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'UInt32' }], - ['HighQualityOut', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'UInt32' }], - ['LowQualityIn', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'UInt32' }], - ['LowQualityOut', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'UInt32' }], - ['QualityIn', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 20, type: 'UInt32' }], - ['QualityOut', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 21, type: 'UInt32' }], - ['StampEscrow', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 22, type: 'UInt32' }], - ['BondAmount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 23, type: 'UInt32' }], - ['LoadFee', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 24, type: 'UInt32' }], - ['OfferSequence', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 25, type: 'UInt32' }], - [ - 'FirstLedgerSequence', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 26, type: 'UInt32' } - ], - ['LastLedgerSequence', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 27, type: 'UInt32' }], - ['TransactionIndex', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 28, type: 'UInt32' }], - ['OperationLimit', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 29, type: 'UInt32' }], - ['ReferenceFeeUnits', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 30, type: 'UInt32' }], - ['ReserveBase', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 31, type: 'UInt32' }], - ['ReserveIncrement', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 32, type: 'UInt32' }], - ['SetFlag', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 33, type: 'UInt32' }], - ['ClearFlag', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 34, type: 'UInt32' }], - ['SignerQuorum', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 35, type: 'UInt32' }], - ['CancelAfter', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 36, type: 'UInt32' }], - ['FinishAfter', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 37, type: 'UInt32' }], - ['SignerListID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 38, type: 'UInt32' }], - ['SettleDelay', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 39, type: 'UInt32' }], - ['TicketCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 40, type: 'UInt32' }], - ['TicketSequence', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 41, type: 'UInt32' }], - ['NFTokenTaxon', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 42, type: 'UInt32' }], - ['MintedNFTokens', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 43, type: 'UInt32' }], - ['BurnedNFTokens', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 44, type: 'UInt32' }], - ['HookStateCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 45, type: 'UInt32' }], - ['EmitGeneration', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 46, type: 'UInt32' }], - ['LockCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 49, type: 'UInt32' }], - [ - 'FirstNFTokenSequence', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 50, type: 'UInt32' } - ], - ['StartTime', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 93, type: 'UInt32' }], - ['RepeatCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 94, type: 'UInt32' }], - ['DelaySeconds', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 95, type: 'UInt32' }], - [ - 'XahauActivationLgrSeq', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 96, type: 'UInt32' } - ], - ['ImportSequence', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 97, type: 'UInt32' }], - ['RewardTime', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 98, type: 'UInt32' }], - ['RewardLgrFirst', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 99, type: 'UInt32' }], - ['RewardLgrLast', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 100, type: 'UInt32' }], - ['IndexNext', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'UInt64' }], - ['IndexPrevious', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'UInt64' }], - ['BookNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'UInt64' }], - ['OwnerNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'UInt64' }], - ['BaseFee', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 5, type: 'UInt64' }], - ['ExchangeRate', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 6, type: 'UInt64' }], - ['LowNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 7, type: 'UInt64' }], - ['HighNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 8, type: 'UInt64' }], - ['DestinationNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 9, type: 'UInt64' }], - ['Cookie', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 10, type: 'UInt64' }], - ['ServerVersion', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 11, type: 'UInt64' }], - ['NFTokenOfferNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 12, type: 'UInt64' }], - ['EmitBurden', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 13, type: 'UInt64' }], - [ - 'HookInstructionCount', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'UInt64' } - ], - ['HookReturnCode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'UInt64' }], - ['ReferenceCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'UInt64' }], - ['TouchCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 97, type: 'UInt64' }], - ['AccountIndex', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 98, type: 'UInt64' }], - ['AccountCount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 99, type: 'UInt64' }], - ['RewardAccumulator', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 100, type: 'UInt64' }], - ['EmailHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'Hash128' }], - ['LedgerHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'Hash256' }], - ['ParentHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'Hash256' }], - ['TransactionHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'Hash256' }], - ['AccountHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'Hash256' }], - ['PreviousTxnID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 5, type: 'Hash256' }], - ['LedgerIndex', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 6, type: 'Hash256' }], - ['WalletLocator', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 7, type: 'Hash256' }], - ['RootIndex', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 8, type: 'Hash256' }], - ['AccountTxnID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 9, type: 'Hash256' }], - ['NFTokenID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 10, type: 'Hash256' }], - ['EmitParentTxnID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 11, type: 'Hash256' }], - ['EmitNonce', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 12, type: 'Hash256' }], - ['EmitHookHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 13, type: 'Hash256' }], - ['ObjectID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 14, type: 'Hash256' }], - ['BookDirectory', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'Hash256' }], - ['InvoiceID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'Hash256' }], - ['Nickname', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'Hash256' }], - ['Amendment', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'Hash256' }], - ['HookOn', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 20, type: 'Hash256' }], - ['Digest', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 21, type: 'Hash256' }], - ['Channel', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 22, type: 'Hash256' }], - ['ConsensusHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 23, type: 'Hash256' }], - ['CheckID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 24, type: 'Hash256' }], - ['ValidatedHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 25, type: 'Hash256' }], - ['PreviousPageMin', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 26, type: 'Hash256' }], - ['NextPageMin', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 27, type: 'Hash256' }], - ['NFTokenBuyOffer', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 28, type: 'Hash256' }], - ['NFTokenSellOffer', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 29, type: 'Hash256' }], - ['HookStateKey', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 30, type: 'Hash256' }], - ['HookHash', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 31, type: 'Hash256' }], - ['HookNamespace', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 32, type: 'Hash256' }], - ['HookSetTxnID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 33, type: 'Hash256' }], - ['OfferID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 34, type: 'Hash256' }], - ['EscrowID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 35, type: 'Hash256' }], - ['URITokenID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 36, type: 'Hash256' }], - ['Cron', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 95, type: 'Hash256' }], - ['HookCanEmit', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 96, type: 'Hash256' }], - ['EmittedTxnID', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 97, type: 'Hash256' }], - ['GovernanceMarks', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 98, type: 'Hash256' }], - ['GovernanceFlags', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 99, type: 'Hash256' }], - ['hash', { isSerialized: true, isSigningField: false, isVLEncoded: false, nth: 1, type: 'Hash256' }], - ['index', { isSerialized: true, isSigningField: false, isVLEncoded: false, nth: 2, type: 'Hash256' }], - ['Amount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'Amount' }], - ['Balance', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'Amount' }], - ['LimitAmount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'Amount' }], - ['TakerPays', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'Amount' }], - ['TakerGets', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 5, type: 'Amount' }], - ['LowLimit', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 6, type: 'Amount' }], - ['HighLimit', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 7, type: 'Amount' }], - ['Fee', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 8, type: 'Amount' }], - ['SendMax', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 9, type: 'Amount' }], - ['DeliverMin', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 10, type: 'Amount' }], - ['MinimumOffer', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'Amount' }], - ['RippleEscrow', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'Amount' }], - ['DeliveredAmount', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'Amount' }], - ['NFTokenBrokerFee', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'Amount' }], - ['HookCallbackFee', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 20, type: 'Amount' }], - ['LockedBalance', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 21, type: 'Amount' }], - ['BaseFeeDrops', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 22, type: 'Amount' }], - ['ReserveBaseDrops', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 23, type: 'Amount' }], - [ - 'ReserveIncrementDrops', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 24, type: 'Amount' } - ], - ['PublicKey', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 1, type: 'Blob' }], - ['MessageKey', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 2, type: 'Blob' }], - ['SigningPubKey', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 3, type: 'Blob' }], - ['TxnSignature', { isSerialized: true, isSigningField: false, isVLEncoded: true, nth: 4, type: 'Blob' }], - ['URI', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 5, type: 'Blob' }], - ['Signature', { isSerialized: true, isSigningField: false, isVLEncoded: true, nth: 6, type: 'Blob' }], - ['Domain', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 7, type: 'Blob' }], - ['FundCode', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 8, type: 'Blob' }], - ['RemoveCode', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 9, type: 'Blob' }], - ['ExpireCode', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 10, type: 'Blob' }], - ['CreateCode', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 11, type: 'Blob' }], - ['MemoType', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 12, type: 'Blob' }], - ['MemoData', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 13, type: 'Blob' }], - ['MemoFormat', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 14, type: 'Blob' }], - ['Fulfillment', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 16, type: 'Blob' }], - ['Condition', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 17, type: 'Blob' }], - ['MasterSignature', { isSerialized: true, isSigningField: false, isVLEncoded: true, nth: 18, type: 'Blob' }], - ['UNLModifyValidator', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 19, type: 'Blob' }], - ['ValidatorToDisable', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 20, type: 'Blob' }], - ['ValidatorToReEnable', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 21, type: 'Blob' }], - ['HookStateData', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 22, type: 'Blob' }], - ['HookReturnString', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 23, type: 'Blob' }], - ['HookParameterName', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 24, type: 'Blob' }], - ['HookParameterValue', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 25, type: 'Blob' }], - ['Blob', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 26, type: 'Blob' }], - ['RemarkValue', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 98, type: 'Blob' }], - ['RemarkName', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 99, type: 'Blob' }], - ['Account', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 1, type: 'AccountID' }], - ['Owner', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 2, type: 'AccountID' }], - ['Destination', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 3, type: 'AccountID' }], - ['Issuer', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 4, type: 'AccountID' }], - ['Authorize', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 5, type: 'AccountID' }], - ['Unauthorize', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 6, type: 'AccountID' }], - ['RegularKey', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 8, type: 'AccountID' }], - ['NFTokenMinter', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 9, type: 'AccountID' }], - ['EmitCallback', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 10, type: 'AccountID' }], - ['HookAccount', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 16, type: 'AccountID' }], - ['Inform', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 99, type: 'AccountID' }], - [ - 'TransactionMetaData', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'STObject' } - ], - ['CreatedNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'STObject' }], - ['DeletedNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'STObject' }], - ['ModifiedNode', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 5, type: 'STObject' }], - ['PreviousFields', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 6, type: 'STObject' }], - ['FinalFields', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 7, type: 'STObject' }], - ['NewFields', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 8, type: 'STObject' }], - ['TemplateEntry', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 9, type: 'STObject' }], - ['Memo', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 10, type: 'STObject' }], - ['SignerEntry', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 11, type: 'STObject' }], - ['NFToken', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 12, type: 'STObject' }], - ['EmitDetails', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 13, type: 'STObject' }], - ['Hook', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 14, type: 'STObject' }], - ['Signer', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'STObject' }], - ['Majority', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'STObject' }], - [ - 'DisabledValidator', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'STObject' } - ], - ['EmittedTxn', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 20, type: 'STObject' }], - ['HookExecution', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 21, type: 'STObject' }], - ['HookDefinition', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 22, type: 'STObject' }], - ['HookParameter', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 23, type: 'STObject' }], - ['HookGrant', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 24, type: 'STObject' }], - ['AmountEntry', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 91, type: 'STObject' }], - ['MintURIToken', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 92, type: 'STObject' }], - ['HookEmission', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 93, type: 'STObject' }], - ['ImportVLKey', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 94, type: 'STObject' }], - ['ActiveValidator', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 95, type: 'STObject' }], - ['GenesisMint', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 96, type: 'STObject' }], - ['Remark', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 97, type: 'STObject' }], - ['Signers', { isSerialized: true, isSigningField: false, isVLEncoded: false, nth: 3, type: 'STArray' }], - ['SignerEntries', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'STArray' }], - ['Template', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 5, type: 'STArray' }], - ['Necessary', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 6, type: 'STArray' }], - ['Sufficient', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 7, type: 'STArray' }], - ['AffectedNodes', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 8, type: 'STArray' }], - ['Memos', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 9, type: 'STArray' }], - ['NFTokens', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 10, type: 'STArray' }], - ['Hooks', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 11, type: 'STArray' }], - ['Majorities', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'STArray' }], - [ - 'DisabledValidators', - { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'STArray' } - ], - ['HookExecutions', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'STArray' }], - ['HookParameters', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 19, type: 'STArray' }], - ['HookGrants', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 20, type: 'STArray' }], - ['Amounts', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 92, type: 'STArray' }], - ['HookEmissions', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 93, type: 'STArray' }], - ['ImportVLKeys', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 94, type: 'STArray' }], - ['ActiveValidators', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 95, type: 'STArray' }], - ['GenesisMints', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 96, type: 'STArray' }], - ['Remarks', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 97, type: 'STArray' }], - ['CloseResolution', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'UInt8' }], - ['Method', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'UInt8' }], - ['TransactionResult', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'UInt8' }], - ['TickSize', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 16, type: 'UInt8' }], - ['UNLModifyDisabling', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 17, type: 'UInt8' }], - ['HookResult', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 18, type: 'UInt8' }], - ['TakerPaysCurrency', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'Hash160' }], - ['TakerPaysIssuer', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 2, type: 'Hash160' }], - ['TakerGetsCurrency', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 3, type: 'Hash160' }], - ['TakerGetsIssuer', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 4, type: 'Hash160' }], - ['Paths', { isSerialized: true, isSigningField: true, isVLEncoded: false, nth: 1, type: 'PathSet' }], - ['Indexes', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 1, type: 'Vector256' }], - ['Hashes', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 2, type: 'Vector256' }], - ['Amendments', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 3, type: 'Vector256' }], - ['NFTokenOffers', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 4, type: 'Vector256' }], - ['HookNamespaces', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 5, type: 'Vector256' }], - ['URITokenIDs', { isSerialized: true, isSigningField: true, isVLEncoded: true, nth: 99, type: 'Vector256' }], - ['Transaction', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 1, type: 'Transaction' }], - ['LedgerEntry', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 1, type: 'LedgerEntry' }], - ['Validation', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 1, type: 'Validation' }], - ['Metadata', { isSerialized: false, isSigningField: false, isVLEncoded: false, nth: 1, type: 'Metadata' }] - ], - LEDGER_ENTRY_TYPES: { - AccountRoot: 97, - Amendments: 102, - Any: 0, - Check: 67, - Contract: 99, - Cron: 65, - DepositPreauth: 112, - DirectoryNode: 100, - EmittedTxn: 69, - Escrow: 117, - FeeSettings: 115, - GeneratorMap: 103, - Hook: 72, - HookDefinition: 68, - HookState: 118, - ImportVLSequence: 73, - Invalid: -1, - LedgerHashes: 104, - NFTokenOffer: 55, - NFTokenPage: 80, - NegativeUNL: 78, - Nickname: 110, - Offer: 111, - PayChannel: 120, - RippleState: 114, - SignerList: 83, - Ticket: 84, - UNLReport: 82, - URIToken: 85 - }, - TRANSACTION_FLAGS: { - AccountSet: { - tfAllowXRP: 2097152, - tfDisallowXRP: 1048576, - tfOptionalAuth: 524288, - tfOptionalDestTag: 131072, - tfRequireAuth: 262144, - tfRequireDestTag: 65536 - }, - ClaimReward: { tfOptOut: 1 }, - CronSet: { tfCronUnset: 1 }, - EnableAmendment: { tfGotMajority: 65536, tfLostMajority: 131072, tfTestSuite: 2147483648 }, - NFTokenCreateOffer: { tfSellNFToken: 1 }, - NFTokenMint: { tfBurnable: 1, tfOnlyXRP: 2, tfStrongTSH: 32768, tfTransferable: 8, tfTrustLine: 4 }, - OfferCreate: { tfFillOrKill: 262144, tfImmediateOrCancel: 131072, tfPassive: 65536, tfSell: 524288 }, - Payment: { tfLimitQuality: 262144, tfNoRippleDirect: 65536, tfPartialPayment: 131072 }, - PaymentChannelClaim: { tfClose: 131072, tfRenew: 65536 }, - TrustSet: { - tfClearDeepFreeze: 8388608, - tfClearFreeze: 2097152, - tfClearNoRipple: 262144, - tfSetDeepFreeze: 4194304, - tfSetFreeze: 1048576, - tfSetNoRipple: 131072, - tfSetfAuth: 65536 - }, - URITokenMint: { tfBurnable: 1 }, - Universal: { tfFullyCanonicalSig: 2147483648 } - }, - TRANSACTION_FLAGS_INDICES: { - AccountSet: { - asfAccountTxnID: 5, - asfAllowTrustLineClawback: 17, - asfAuthorizedNFTokenMinter: 10, - asfDefaultRipple: 8, - asfDepositAuth: 9, - asfDisableMaster: 4, - asfDisallowIncomingCheck: 13, - asfDisallowIncomingNFTokenOffer: 12, - asfDisallowIncomingPayChan: 14, - asfDisallowIncomingRemit: 16, - asfDisallowIncomingTrustline: 15, - asfDisallowXRP: 3, - asfGlobalFreeze: 7, - asfNoFreeze: 6, - asfRequireAuth: 2, - asfRequireDest: 1, - asfTshCollect: 11 - } - }, - TRANSACTION_RESULTS: { - tecAMM_BALANCE: 163, - tecAMM_FAILED_BID: 167, - tecAMM_FAILED_DEPOSIT: 164, - tecAMM_FAILED_VOTE: 168, - tecAMM_FAILED_WITHDRAW: 165, - tecAMM_INVALID_TOKENS: 166, - tecAMM_UNFUNDED: 162, - tecBAD_XCHAIN_TRANSFER_ISSUE: 171, - tecCANT_ACCEPT_OWN_NFTOKEN_OFFER: 158, - tecCLAIM: 100, - tecCRYPTOCONDITION_ERROR: 146, - tecDIR_FULL: 121, - tecDST_TAG_NEEDED: 143, - tecDUPLICATE: 149, - tecEXPIRED: 148, - tecFAILED_PROCESSING: 105, - tecFROZEN: 137, - tecHAS_HOOK_STATE: 190, - tecHAS_OBLIGATIONS: 151, - tecHOOK_REJECTED: 153, - tecIMMUTABLE: 188, - tecINSUFFICIENT_FUNDS: 159, - tecINSUFFICIENT_PAYMENT: 161, - tecINSUFFICIENT_RESERVE: 141, - tecINSUFF_FEE: 136, - tecINSUF_RESERVE_LINE: 122, - tecINSUF_RESERVE_OFFER: 123, - tecINSUF_RESERVE_SELLER: 187, - tecINTERNAL: 144, - tecINVARIANT_FAILED: 147, - tecKILLED: 150, - tecLAST_POSSIBLE_ENTRY: 255, - tecMAX_SEQUENCE_REACHED: 154, - tecNEED_MASTER_KEY: 142, - tecNFTOKEN_BUY_SELL_MISMATCH: 156, - tecNFTOKEN_OFFER_TYPE_MISMATCH: 157, - tecNO_ALTERNATIVE_KEY: 130, - tecNO_AUTH: 134, - tecNO_DST: 124, - tecNO_DST_INSUF_NATIVE: 125, - tecNO_ENTRY: 140, - tecNO_ISSUER: 133, - tecNO_LINE: 135, - tecNO_LINE_INSUF_RESERVE: 126, - tecNO_LINE_REDUNDANT: 127, - tecNO_PERMISSION: 139, - tecNO_REGULAR_KEY: 131, - tecNO_SUITABLE_NFTOKEN_PAGE: 155, - tecNO_TARGET: 138, - tecOBJECT_NOT_FOUND: 160, - tecOVERSIZE: 145, - tecOWNERS: 132, - tecPATH_DRY: 128, - tecPATH_PARTIAL: 101, - tecPRECISION_LOSS: 170, - tecREQUIRES_FLAG: 169, - tecTOO_MANY_REMARKS: 189, - tecTOO_SOON: 152, - tecUNFUNDED: 129, - tecUNFUNDED_ADD: 102, - tecUNFUNDED_OFFER: 103, - tecUNFUNDED_PAYMENT: 104, - tecXCHAIN_ACCOUNT_CREATE_PAST: 182, - tecXCHAIN_ACCOUNT_CREATE_TOO_MANY: 183, - tecXCHAIN_BAD_CLAIM_ID: 173, - tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR: 186, - tecXCHAIN_CLAIM_NO_QUORUM: 174, - tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE: 176, - tecXCHAIN_INSUFF_CREATE_AMOUNT: 181, - tecXCHAIN_NO_CLAIM_ID: 172, - tecXCHAIN_NO_SIGNERS_LIST: 179, - tecXCHAIN_PAYMENT_FAILED: 184, - tecXCHAIN_PROOF_UNKNOWN_KEY: 175, - tecXCHAIN_REWARD_MISMATCH: 178, - tecXCHAIN_SELF_COMMIT: 185, - tecXCHAIN_SENDING_ACCOUNT_MISMATCH: 180, - tecXCHAIN_WRONG_CHAIN: 177, - tefALREADY: -198, - tefBAD_ADD_AUTH: -197, - tefBAD_AUTH: -196, - tefBAD_AUTH_MASTER: -183, - tefBAD_LEDGER: -195, - tefBAD_QUORUM: -185, - tefBAD_SIGNATURE: -186, - tefCREATED: -194, - tefEXCEPTION: -193, - tefFAILURE: -199, - tefIMPORT_BLACKHOLED: -175, - tefINTERNAL: -192, - tefINVARIANT_FAILED: -182, - tefMASTER_DISABLED: -188, - tefMAX_LEDGER: -187, - tefNFTOKEN_IS_NOT_TRANSFERABLE: -179, - tefNONDIR_EMIT: -176, - tefNOT_MULTI_SIGNING: -184, - tefNO_AUTH_REQUIRED: -191, - tefNO_TICKET: -180, - tefPAST_IMPORT_SEQ: -178, - tefPAST_IMPORT_VL_SEQ: -177, - tefPAST_SEQ: -190, - tefTOO_BIG: -181, - tefWRONG_PRIOR: -189, - telBAD_DOMAIN: -398, - telBAD_PATH_COUNT: -397, - telBAD_PUBLIC_KEY: -396, - telCAN_NOT_QUEUE: -392, - telCAN_NOT_QUEUE_BALANCE: -391, - telCAN_NOT_QUEUE_BLOCKED: -389, - telCAN_NOT_QUEUE_BLOCKS: -390, - telCAN_NOT_QUEUE_FEE: -388, - telCAN_NOT_QUEUE_FULL: -387, - telCAN_NOT_QUEUE_IMPORT: -381, - telFAILED_PROCESSING: -395, - telIMPORT_VL_KEY_NOT_RECOGNISED: -382, - telINSUF_FEE_P: -394, - telLOCAL_ERROR: -399, - telNETWORK_ID_MAKES_TX_NON_CANONICAL: -384, - telNON_LOCAL_EMITTED_TXN: -383, - telNO_DST_PARTIAL: -393, - telREQUIRES_NETWORK_ID: -385, - telWRONG_NETWORK: -386, - temAMM_BAD_TOKENS: -261, - temBAD_AMOUNT: -298, - temBAD_CURRENCY: -297, - temBAD_EXPIRATION: -296, - temBAD_FEE: -295, - temBAD_ISSUER: -294, - temBAD_LIMIT: -293, - temBAD_NFTOKEN_TRANSFER_FEE: -262, - temBAD_OFFER: -292, - temBAD_PATH: -291, - temBAD_PATH_LOOP: -290, - temBAD_QUORUM: -271, - temBAD_REGKEY: -289, - temBAD_SEND_NATIVE_LIMIT: -288, - temBAD_SEND_NATIVE_MAX: -287, - temBAD_SEND_NATIVE_NO_DIRECT: -286, - temBAD_SEND_NATIVE_PARTIAL: -285, - temBAD_SEND_NATIVE_PATHS: -284, - temBAD_SEQUENCE: -283, - temBAD_SIGNATURE: -282, - temBAD_SIGNER: -272, - temBAD_SRC_ACCOUNT: -281, - temBAD_TICK_SIZE: -269, - temBAD_TRANSFER_RATE: -280, - temBAD_WEIGHT: -270, - temCANNOT_PREAUTH_SELF: -267, - temDISABLED: -273, - temDST_IS_SRC: -279, - temDST_NEEDED: -278, - temHOOK_DATA_TOO_LARGE: -253, - temINVALID: -277, - temINVALID_ACCOUNT_ID: -268, - temINVALID_COUNT: -266, - temINVALID_FLAG: -276, - temMALFORMED: -299, - temREDUNDANT: -275, - temRIPPLE_EMPTY: -274, - temSEQ_AND_TICKET: -263, - temUNCERTAIN: -265, - temUNKNOWN: -264, - temXCHAIN_BAD_PROOF: -259, - temXCHAIN_BRIDGE_BAD_ISSUES: -258, - temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT: -256, - temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT: -255, - temXCHAIN_BRIDGE_NONDOOR_OWNER: -257, - temXCHAIN_EQUAL_DOOR_ACCOUNTS: -260, - temXCHAIN_TOO_MANY_ATTESTATIONS: -254, - terFUNDS_SPENT: -98, - terINSUF_FEE_B: -97, - terLAST: -91, - terNO_ACCOUNT: -96, - terNO_AMM: -87, - terNO_AUTH: -95, - terNO_HOOK: -86, - terNO_LINE: -94, - terNO_RIPPLE: -90, - terOWNERS: -93, - terPRE_SEQ: -92, - terPRE_TICKET: -88, - terQUEUED: -89, - terRETRY: -99, - tesPARTIAL: 1, - tesSUCCESS: 0 - }, - TRANSACTION_TYPES: { - AccountDelete: 21, - AccountSet: 3, - Amendment: 100, - CheckCancel: 18, - CheckCash: 17, - CheckCreate: 16, - ClaimReward: 98, - Clawback: 30, - Contract: 9, - Cron: 92, - CronSet: 93, - DepositPreauth: 19, - EmitFailure: 103, - EscrowCancel: 4, - EscrowCreate: 1, - EscrowFinish: 2, - Fee: 101, - GenesisMint: 96, - Import: 97, - Invalid: -1, - Invoke: 99, - NFTokenAcceptOffer: 29, - NFTokenBurn: 26, - NFTokenCancelOffer: 28, - NFTokenCreateOffer: 27, - NFTokenMint: 25, - NicknameSet: 6, - OfferCancel: 8, - OfferCreate: 7, - Payment: 0, - PaymentChannelClaim: 15, - PaymentChannelCreate: 13, - PaymentChannelFund: 14, - Remit: 95, - SetHook: 22, - SetRegularKey: 5, - SetRemarks: 94, - SignerListSet: 12, - SpinalTap: 11, - TicketCreate: 10, - TrustSet: 20, - UNLModify: 102, - UNLReport: 104, - URITokenBurn: 46, - URITokenBuy: 47, - URITokenCancelSellOffer: 49, - URITokenCreateSellOffer: 48, - URITokenMint: 45 - }, - TYPES: { - AccountID: 8, - Amount: 6, - Blob: 7, - Done: -1, - Hash128: 4, - Hash160: 17, - Hash256: 5, - LedgerEntry: 10002, - Metadata: 10004, - NotPresent: 0, - PathSet: 18, - STArray: 15, - STObject: 14, - Transaction: 10001, - UInt16: 1, - UInt192: 21, - UInt32: 2, - UInt384: 22, - UInt512: 23, - UInt64: 3, - UInt8: 16, - UInt96: 20, - Unknown: -2, - Validation: 10003, - Vector256: 19 - }, - features: { - '00C1FC4A53E60AB02C864641002B3172F38677E29C26C5406685179B37E1EDAC': { - enabled: true, - name: 'RequireFullyCanonicalSig', - supported: true - }, - '0134BEED89A1A1D8B2663CF9DFCDB9024A060706FDFF147AA4D203749AFD5932': { - enabled: true, - name: 'IOUIssuerWeakTSH', - supported: true - }, - '0285B7E5E08E1A8E4C15636F0591D87F73CB6A7B6452A932AD72BBC8E5D1CBE3': { - enabled: false, - name: 'fixNFTokenDirV1', - supported: true, - vetoed: 'Obsolete' - }, - '07D43DCE529B15A10827E5E04943B496762F9A88E3268269D69C44BE49E21104': { - enabled: false, - name: 'Escrow', - supported: true, - vetoed: 'Obsolete' - }, - '08DE7D96082187F6E6578530258C77FAABABE4C20474BDB82F04B021F1A68647': { - enabled: false, - name: 'PayChan', - supported: true, - vetoed: 'Obsolete' - }, - '0D8BF22FF7570D58598D1EF19EBB6E142AD46E59A223FD3816262FBB69345BEA': { - enabled: true, - name: 'Remit', - supported: true - }, - '1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C4805C902B514399146': { - enabled: false, - name: 'CryptoConditions', - supported: true, - vetoed: 'Obsolete' - }, - '157D2D480E006395B76F948E3E07A45A05FE10230D88A7993C71F97AE4B1F2D1': { - enabled: true, - name: 'Checks', - supported: true - }, - '17C342EA7EFA25D809FC0DD7BC885190DAF54582E5A683ED0BBA200877A0BFDE': { - enabled: false, - name: 'fixHookAPI20251128', - supported: true, - vetoed: false - }, - '1D3463A5891F9E589C5AE839FFAC4A917CE96197098A1EF22304E1BC5B98A454': { - enabled: false, - name: 'fix1528', - supported: true, - vetoed: 'Obsolete' - }, - '1F4AFA8FA1BC8827AD4C0F682C03A8B671DCDF6B5C4DE36D44243A684103EF88': { - enabled: true, - name: 'HardenedValidations', - supported: true - }, - '215181D23BF5C173314B5FDB9C872C92DE6CC918483727DE037C0C13E7E6EE9D': { - enabled: true, - name: 'fixXahauV2', - supported: true - }, - '22DD15A56DFD886A7B7D37B656DC4F974BB0FE4BECB83055B01AE8B5A8466D34': { - enabled: true, - name: 'fixProvisionalDoubleThreading', - supported: true - }, - '25BA44241B3BD880770BFA4DA21C7180576831855368CBEC6A3154FDE4A7676E': { - enabled: true, - name: 'fix1781', - supported: true - }, - '2CD5286D8D687E98B41102BDD797198E81EA41DF7BD104E6561FEB104EFF2561': { - enabled: true, - name: 'fixTakerDryOfferRemoval', - supported: true - }, - '2E2FB9CF8A44EB80F4694D38AADAE9B8B7ADAFD2F092E10068E61C98C4F092B0': { - enabled: false, - name: 'fixUniversalNumber', - supported: true, - vetoed: true - }, - '3012E8230864E95A58C60FD61430D7E1B4D3353195F2981DC12B0C7C0950FFAC': { - enabled: true, - name: 'FlowCross', - supported: true - }, - '30CD365592B8EE40489BA01AE2F7555CAC9C983145871DC82A42A31CF5BAE7D9': { - enabled: false, - name: 'DeletableAccounts', - supported: true, - vetoed: true - }, - '32A122F1352A4C7B3A6D790362CC34749C5E57FCE896377BFDC6CCD14F6CD627': { - enabled: false, - name: 'NonFungibleTokensV1_1', - supported: true, - vetoed: true - }, - '36799EA497B1369B170805C078AEFE6188345F9B3E324C21E9CA3FF574E3C3D6': { - enabled: false, - name: 'fixNFTokenNegOffer', - supported: true, - vetoed: 'Obsolete' - }, - '3C43D9A973AA4443EF3FC38E42DD306160FBFFDAB901CD8BAA15D09F2597EB87': { - enabled: false, - name: 'NonFungibleTokensV1', - supported: true, - vetoed: 'Obsolete' - }, - '3CBC5C4E630A1B82380295CDA84B32B49DD066602E74E39B85EF64137FA65194': { - enabled: true, - name: 'DepositPreauth', - supported: true - }, - '42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE': { - enabled: false, - name: 'FeeEscalation', - supported: true, - vetoed: 'Obsolete' - }, - '42EEA5E28A97824821D4EF97081FE36A54E9593C6E4F20CBAE098C69D2E072DC': { - enabled: false, - name: 'fix1373', - supported: true, - vetoed: 'Obsolete' - }, - '42F8B586B357ABBAAAA1C733C3E7D3B75761395340D0CDF600179E8737E22478': { - enabled: true, - name: 'BalanceRewards', - supported: true - }, - '452F5906C46D46F407883344BFDD90E672B672C5E9943DB4891E3A34FEEEB9DB': { - enabled: true, - name: 'fixSTAmountCanonicalize', - supported: true - }, - '47C3002ABA31628447E8E9A8B315FAA935CE30183F9A9B86845E469CA2CDC3DF': { - enabled: true, - name: 'DisallowIncoming', - supported: true - }, - '4B8466415FAB32FFA89D9DCBE166A42340115771DF611A7160F8D7439C87ECD8': { - enabled: true, - name: 'fixNSDelete', - supported: true - }, - '4C499D17719BB365B69010A436B64FD1A82AAB199FC1CEB06962EBD01059FB09': { - enabled: true, - name: 'fixXahauV1', - supported: true - }, - '4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373': { - enabled: false, - name: 'MultiSign', - supported: true, - vetoed: 'Obsolete' - }, - '4F46DF03559967AC60F2EB272FEFE3928A7594A45FF774B87A7E540DB0F8F068': { - enabled: true, - name: 'fixAmendmentMajorityCalc', - supported: true - }, - '532651B4FD58DF8922A49BA101AB3E996E5BFBF95A913B3E392504863E63B164': { - enabled: false, - name: 'TickSize', - supported: true, - vetoed: 'Obsolete' - }, - '56B241D7A43D40354D02A9DC4C8DF5C7A1F930D92A9035C4E12291B3CA3E1C2B': { - enabled: true, - name: 'Clawback', - supported: true - }, - '586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF1FC07EFE41D': { - enabled: true, - name: 'MultiSignReserve', - supported: true - }, - '58BE9B5968C4DA7C59BA900961828B113E5490699B21877DEF9A31E9D0FE5D5F': { - enabled: true, - name: 'fix1623', - supported: true - }, - '5B8E5D8F3D8687D3CE567FB5BDAED152204D195ED2EAEC346E3AA0607D51752A': { - enabled: true, - name: 'fixRewardClaimFlags', - supported: true - }, - '5D08145F0A4983F23AFFFF514E83FAD355C5ABFBB6CAB76FB5BC8519FF5F33BE': { - enabled: true, - name: 'fix1515', - supported: true - }, - '621A0B264970359869E3C0363A899909AAB7A887C8B73519E4ECF952D33258A8': { - enabled: true, - name: 'fixPayChanRecipientOwnerDir', - supported: true - }, - '6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC': { - enabled: false, - name: 'TrustSetAuth', - supported: true, - vetoed: 'Obsolete' - }, - '67A34F2CF55BFC0F93AACD5B281413176FEE195269FA6D95219A2DF738671172': { - enabled: true, - name: 'fix1513', - supported: true - }, - '6C92211186613F9647A89DFFBAB8F94C99D4C7E956D495270789128569177DA1': { - enabled: false, - name: 'fix1512', - supported: true, - vetoed: 'Obsolete' - }, - '6E739F4F8B07BED29FC9FF440DA3C301CD14A180DF45819F658FEC2F7DE31427': { - enabled: true, - name: 'XahauGenesis', - supported: true - }, - '7117E2EC2DBF119CA55181D69819F1999ECEE1A0225A7FD2B9ED47940968479C': { - enabled: true, - name: 'fix1571', - supported: true - }, - '717F060C0C237F122F8065781528B1CA047D82B4E787022984F26D7B997E3D9C': { - enabled: true, - name: 'fix20250131', - supported: true - }, - '73761231F7F3D94EC3D8C63D91BDD0D89045C6F71B917D1925C01253515A6669': { - enabled: false, - name: 'fixNonFungibleTokensV1_2', - supported: true, - vetoed: true - }, - '740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11': { - enabled: true, - name: 'Flow', - supported: true - }, - '75A7E01C505DD5A179DFE3E000A9B6F1EDDEB55A12F95579A23E15B15DC8BE5A': { - enabled: true, - name: 'ImmediateOfferKilled', - supported: true - }, - '7CA0426E7F411D39BB014E57CD9E08F61DE1750F0D41FCD428D9FB80BB7596B0': { - enabled: true, - name: 'ZeroB2M', - supported: true - }, - '7FE392C21A2880B3223A2CAF8DC59ADDAE5B03BD4B0500A1F63DF9893E852DBA': { - enabled: true, - name: 'ExtendedHookState', - supported: true - }, - '8063140E9260799D6716756B891CEC3E7006C4E4F277AB84670663A88F94B9C4': { - enabled: true, - name: 'fixPageCap', - supported: true - }, - '86E83A7D2ECE3AD5FA87AB2195AE015C950469ABF0B72EAACED318F74886AE90': { - enabled: false, - name: 'CryptoConditionsSuite', - supported: true, - vetoed: 'Obsolete' - }, - '88693F108C3CD8A967F3F4253A32DEF5E35F9406ACD2A11B88B11D90865763A9': { - enabled: true, - name: 'fix240911', - supported: true - }, - '88FEC10C8272D690124E923FBB47A95013C6AA20D9B27B871A99790D05055421': { - enabled: true, - name: 'fixXahauV3', - supported: true - }, - '89308AF3B8B10B7192C4E613E1D2E4D9BA64B2EE2D5232402AE82A6A7220D953': { - enabled: true, - name: 'fixQualityUpperBound', - supported: true - }, - '8EC4304A06AF03BE953EA6EDA494864F6F3F30AA002BABA35869FBB8C6AE5D52': { - enabled: true, - name: 'fixInvalidTxFlags', - supported: true - }, - '8F81B066ED20DAECA20DF57187767685EEF3980B228E0667A650BAF24426D3B4': { - enabled: true, - name: 'fixCheckThreading', - supported: true - }, - '9000B5F96F9E129D1CB42F2B07AF4CEFEFBFDF49CFCD8B6FF46E719A3F19B436': { - enabled: true, - name: 'HookCanEmit', - supported: true - }, - '919857E4B902A20216E4819B9BD9FD1FD19A66ECF63151C18A4C48C873DB9578': { - enabled: true, - name: 'PaychanAndEscrowForTokens', - supported: true - }, - '93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515A7': { - enabled: true, - name: 'XRPFees', - supported: true - }, - '94312150FFBA0E21B46244D7C4C6D66219C53C5F82FB7949F0832A6B56FB9631': { - enabled: true, - name: 'Touch', - supported: true - }, - '955DF3FA5891195A9DAEFA1DDC6BB244B545DDE1BAA84CBB25D5F12A8DA68A0C': { - enabled: true, - name: 'TicketBatch', - supported: true - }, - '98DECF327BF79997AEC178323AD51A830E457BFC6D454DAF3E46E5EC42DC619F': { - enabled: true, - name: 'CheckCashMakesTrustLine', - supported: true - }, - AE35ABDEFBDE520372B31C957020B34A7A4A9DC3115A69803A44016477C84D6E: { - enabled: false, - name: 'fixNFTokenRemint', - supported: true, - vetoed: true - }, - AF8DF7465C338AE64B1E937D6C8DA138C0D63AD5134A68792BBBE1F63356C422: { - enabled: true, - name: 'FlowSortStrands', - supported: true - }, - B2A4DB846F0891BF2C76AB2F2ACC8F5B4EC64437135C6E56F3F859DE5FFD5856: { - enabled: true, - name: 'ExpandedSignerList', - supported: true - }, - B4D44CC3111ADD964E846FC57760C8B50FFCD5A82C86A72756F6B058DDDF96AD: { - enabled: false, - name: 'fix1201', - supported: true, - vetoed: 'Obsolete' - }, - B4E4F5D2D6FB84DF7399960A732309C9FD530EAE5941838160042833625A6076: { - enabled: true, - name: 'NegativeUNL', - supported: true - }, - B6B3EEDC0267AB50491FDC450A398AF30DBCD977CECED8BEF2499CAB5DAC19E2: { - enabled: true, - name: 'fixRmSmallIncreasedQOffers', - supported: true - }, - B9E739B8296B4A1BB29BE990B17D66E21B62A300A909F25AC55C22D6C72E1F9D: { - enabled: false, - name: 'fix1523', - supported: true, - vetoed: 'Obsolete' - }, - BA993DF6058701246DAF748BDE237B0C980164D0034CEB1D831C089A90D9000D: { - enabled: true, - name: 'fixFloatDivide', - supported: true - }, - C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD37: { - enabled: true, - name: 'fixMasterKeyAsRegularKey', - supported: true - }, - C962119A75111083D118901B0D331959C620157FDEABA044398B992B829938C5: { - enabled: true, - name: 'fixReduceImport', - supported: true - }, - CA7C02118BA27599528543DFE77BA6838D1B0F43B447D4D7F53523CE6A0E9AC2: { - enabled: true, - name: 'fix1543', - supported: true - }, - CC5ABAE4F3EC92E94A59B1908C2BE82D2228B6485C00AFF8F22DF930D89C194E: { - enabled: false, - name: 'SortedDirectories', - supported: true, - vetoed: 'Obsolete' - }, - D686F2538F410C9D0D856788E98E3579595DAF7B38D38887F81ECAC934B06040: { - enabled: true, - name: 'HooksUpdate1', - supported: true - }, - DAF3A6EB04FA5DC51E8E4F23E9B7022B693EFA636F23F22664746C77B5786B23: { - enabled: true, - name: 'DeepFreeze', - supported: true - }, - DC9CA96AEA1DCF83E527D1AFC916EFAF5D27388ECA4060A88817C1238CAEE0BF: { - enabled: false, - name: 'EnforceInvariants', - supported: true, - vetoed: 'Obsolete' - }, - DD6ABC68C1F37392E521EF6FF1475A11576D87C1BC36D9C9E4F0E6C09D18C120: { - enabled: false, - name: 'Cron', - supported: true, - vetoed: true - }, - DF8B4536989BDACE3F934F29423848B9F1D76D09BE6A1FCFE7E7F06AA26ABEAD: { - enabled: false, - name: 'fixRemoveNFTokenAutoTrustLine', - supported: true, - vetoed: true - }, - E2E6F2866106419B88C50045ACE96368558C345566AC8F2BDF5A5B5587F0E6FA: { - enabled: false, - name: 'fix1368', - supported: true, - vetoed: 'Obsolete' - }, - E331BED1F9C4F5F6B6E307D40323D81C3AAAD093A61AB8CFAC7BCFBEBE31F758: { - enabled: false, - name: 'fixCronStacking', - supported: true, - vetoed: false - }, - ECE6819DBA5DB528F1A241695F5A9811EF99467CDE22510954FD357780BBD078: { - enabled: true, - name: 'Hooks', - supported: true - }, - ECF412BE0964EC2E71DCF807EEEA6EA8470D3DB15173D46F28AB6E234860AC32: { - enabled: true, - name: 'URIToken', - supported: true - }, - EDB4EE4C524E16BDD91D9A529332DED08DCAAA51CC6DC897ACFA1A0ED131C5B6: { - enabled: true, - name: 'fix240819', - supported: true - }, - F5751842D26FC057B92CAA435ABF4F1428C2BCC4180D18775ADE92CB2643BBA3: { - enabled: true, - name: 'Import', - supported: true - }, - F64E1EABBE79D55B3BB82020516CEC2C582A98A6BFE20FBE9BB6A0D233418064: { - enabled: true, - name: 'DepositAuth', - supported: true - }, - FA4E4881FDB038DCD8D7DFD850A304546E0B2844CACC3AB97CA41136A03E49F5: { - enabled: true, - name: 'Remarks', - supported: true - }, - FBD513F1B893AC765B78F250E6FFA6A11B573209D1842ADC787C850696741288: { - enabled: true, - name: 'fix1578', - supported: true - } - }, - hash: '321D5C9837702808BEB7D4F8BF7345C013E3689952100988FB76677721D2B609', - native_currency_code: 'XAH', - status: 'success' - } -} - -const defsJson = rawXahauDefs.result - -nativeAsset.set('XAH') - -export const xahauDefinitions = new XrplDefinitions(defsJson) diff --git a/yarn.lock b/yarn.lock index d633c69f8..1fbf3e792 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2087,21 +2087,16 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz#75dce8e972f90bba488e2b0cc677fb233aa357ab" integrity sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ== -"@scure/base@^1.1.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" - integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== +"@scure/base@^1.1.3", "@scure/base@~1.2.2", "@scure/base@~1.2.4", "@scure/base@~1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.5.tgz#f9d1b232425b367d0dcb81c96611dcc651d58671" + integrity sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw== "@scure/base@~1.1.6": version "1.1.9" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== -"@scure/base@~1.2.2", "@scure/base@~1.2.4", "@scure/base@~1.2.5": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.5.tgz#f9d1b232425b367d0dcb81c96611dcc651d58671" - integrity sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw== - "@scure/bip32@1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" @@ -4314,12 +4309,7 @@ big-integer@^1.6.48: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== -bignumber.js@^9.0.0: - version "9.3.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.1.tgz#759c5aaddf2ffdc4f154f7b493e1c8770f88c4d7" - integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== - -bignumber.js@^9.1.2: +bignumber.js@^9.0.0, bignumber.js@^9.1.2: version "9.3.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.0.tgz#bdba7e2a4c1a2eba08290e8dcad4f36393c92acd" integrity sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA== @@ -4545,9 +4535,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001716: - version "1.0.30001754" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz" - integrity sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg== + version "1.0.30001718" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz#dae13a9c80d517c30c6197515a96131c194d8f82" + integrity sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw== cashaddrjs@0.4.4: version "0.4.4" @@ -9071,12 +9061,7 @@ ws@^7.3.1, ws@^7.5.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.13.0: - version "8.18.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" - integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== - -ws@^8.18.0, ws@^8.2.2: +ws@^8.13.0, ws@^8.18.0, ws@^8.2.2: version "8.18.2" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== @@ -9092,9 +9077,9 @@ xmlhttprequest-ssl@~2.1.1: integrity sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ== xrpl-binary-codec-prerelease@^8.0.1: - version "8.4.0" - resolved "https://registry.yarnpkg.com/xrpl-binary-codec-prerelease/-/xrpl-binary-codec-prerelease-8.4.0.tgz#4cbc5d974c67238cd01d45989e8de87253079965" - integrity sha512-v6lMTiQyGw8MGARc1amwYG/dh9L/3wLz7refQb7JcOFMxb7qxlkrNFZdjc+sfF0iDXG6id60ODO8zvbeDFiNFw== + version "8.3.0" + resolved "https://registry.yarnpkg.com/xrpl-binary-codec-prerelease/-/xrpl-binary-codec-prerelease-8.3.0.tgz#05c6792dc381c6a231ae9fd684c83dfc5fb475d7" + integrity sha512-C1ZWJ6bwZlf+RofGfZshshMgHpzzBH6DiVAtX0pA3u7SHZvPeAM9d7iXNt776EgAPRVd8U7245w2JGVggkF0EA== dependencies: "@xrplf/isomorphic" "^1.0.1" bignumber.js "^9.0.0"
    - avatar + {doubleIcon ? ( +
    + {/* back coin */} + asset + {/* front coin */} + asset 2 +
    + ) : ( + avatar + )}
    {children}