diff --git a/explorer/package-lock.json b/explorer/package-lock.json index d229007cd3..97939e79d1 100644 --- a/explorer/package-lock.json +++ b/explorer/package-lock.json @@ -4747,6 +4747,11 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", diff --git a/explorer/package.json b/explorer/package.json index 1898547066..f188be8dc9 100644 --- a/explorer/package.json +++ b/explorer/package.json @@ -22,6 +22,7 @@ "@types/react-router-dom": "^5.1.7", "@types/react-select": "^3.1.2", "@types/socket.io-client": "^1.4.35", + "bignumber.js": "^9.0.1", "bn.js": "^5.1.3", "bootstrap": "^4.6.0", "bs58": "^4.0.1", diff --git a/explorer/src/components/common/BalanceDelta.tsx b/explorer/src/components/common/BalanceDelta.tsx new file mode 100644 index 0000000000..45981dac73 --- /dev/null +++ b/explorer/src/components/common/BalanceDelta.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import { BigNumber } from "bignumber.js"; +import { lamportsToSolString } from "utils"; + +export function BalanceDelta({ + delta, + isSol = false, +}: { + delta: BigNumber; + isSol?: boolean; +}) { + let sols; + + if (isSol) { + sols = lamportsToSolString(delta.toNumber()); + } + + if (delta.gt(0)) { + return ( + + +{isSol ? sols : delta.toString()} + + ); + } else if (delta.lt(0)) { + return ( + + {isSol ? <>-{sols}> : delta.toString()} + + ); + } + + return 0; +} diff --git a/explorer/src/components/transaction/TokenBalancesCard.tsx b/explorer/src/components/transaction/TokenBalancesCard.tsx new file mode 100644 index 0000000000..10e7e14e18 --- /dev/null +++ b/explorer/src/components/transaction/TokenBalancesCard.tsx @@ -0,0 +1,157 @@ +import React from "react"; +import { + ParsedMessageAccount, + PublicKey, + TokenAmount, + TokenBalance, +} from "@solana/web3.js"; +import { BigNumber } from "bignumber.js"; +import { Address } from "components/common/Address"; +import { BalanceDelta } from "components/common/BalanceDelta"; +import { SignatureProps } from "pages/TransactionDetailsPage"; +import { useCluster } from "providers/cluster"; +import { useTransactionDetails } from "providers/transactions"; +import { TokenRegistry } from "tokenRegistry"; + +type TokenBalanceRow = { + account: PublicKey; + mint: string; + balance: TokenAmount; + delta: BigNumber; + accountIndex: number; +}; + +export function TokenBalancesCard({ signature }: SignatureProps) { + const details = useTransactionDetails(signature); + const { cluster } = useCluster(); + + if (!details) { + return null; + } + + const preTokenBalances = details.data?.transaction?.meta?.preTokenBalances; + const postTokenBalances = details.data?.transaction?.meta?.postTokenBalances; + + const accountKeys = + details.data?.transaction?.transaction.message.accountKeys; + + if (!preTokenBalances || !postTokenBalances || !accountKeys) { + return null; + } + + const rows = generateTokenBalanceRows( + preTokenBalances, + postTokenBalances, + accountKeys + ); + + if (rows.length < 1) { + return null; + } + + const accountRows = rows.map(({ account, delta, balance, mint }) => { + const key = account.toBase58() + mint; + const units = TokenRegistry.get(mint, cluster)?.symbol || "tokens"; + + return ( +
Address | +Token | +Change | +Post Balance | +
---|