From 37c163d501acba1fb17d5604f0ef7a82ed07e5fe Mon Sep 17 00:00:00 2001 From: yudho Date: Thu, 24 Oct 2024 19:07:58 +0530 Subject: [PATCH] feat(app): show access key for transaction --- .../src/components/Transactions/Execution.tsx | 11 +- .../src/components/Transactions/Receipt.tsx | 9 +- .../Transactions/Receipts/ReceiptInfo.tsx | 169 ++++++++++++------ .../Transactions/Receipts/ReceiptRow.tsx | 137 ++++++++++++-- .../Receipts/TransactionReceipt.tsx | 12 +- apps/app/src/hooks/useRpc.ts | 54 ++++-- apps/app/src/pages/txns/[hash].tsx | 6 +- apps/app/src/utils/types.ts | 6 + 8 files changed, 313 insertions(+), 91 deletions(-) diff --git a/apps/app/src/components/Transactions/Execution.tsx b/apps/app/src/components/Transactions/Execution.tsx index 4a0b65ec6..10dedcbf3 100644 --- a/apps/app/src/components/Transactions/Execution.tsx +++ b/apps/app/src/components/Transactions/Execution.tsx @@ -18,10 +18,15 @@ import { isEmpty } from 'lodash'; interface Props { txn: TransactionInfo; rpcTxn: RPCTransactionInfo; + statsData: { + stats: Array<{ + near_price: string; + }>; + }; } const Execution = (props: Props) => { - const { rpcTxn, txn } = props; + const { rpcTxn, txn, statsData } = props; const [receipt, setReceipt] = useState< NestedReceiptWithOutcome | FailedToFindReceipt | any @@ -69,7 +74,9 @@ const Execution = (props: Props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [rpcTxn, receipt?.block_hash]); + const txnsPending = txn?.outcomes?.status === null; + return (
{txnsPending ? ( @@ -132,6 +139,8 @@ const Execution = (props: Props) => { fellowOutgoingReceipts={[]} convertionReceipt={true} className="" + statsData={statsData} + rpcTxn={rpcTxn} /> )}
diff --git a/apps/app/src/components/Transactions/Receipt.tsx b/apps/app/src/components/Transactions/Receipt.tsx index d8f00d9e2..8278af63a 100644 --- a/apps/app/src/components/Transactions/Receipt.tsx +++ b/apps/app/src/components/Transactions/Receipt.tsx @@ -88,7 +88,9 @@ const Receipt = (props: Props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [rpcTxn]); + const txnsPending = txn?.outcomes?.status === null; + return (
{txnsPending ? ( @@ -104,7 +106,12 @@ const Receipt = (props: Props) => {
) : ( - + )} ); diff --git a/apps/app/src/components/Transactions/Receipts/ReceiptInfo.tsx b/apps/app/src/components/Transactions/Receipts/ReceiptInfo.tsx index de45270b3..b92be86c0 100644 --- a/apps/app/src/components/Transactions/Receipts/ReceiptInfo.tsx +++ b/apps/app/src/components/Transactions/Receipts/ReceiptInfo.tsx @@ -1,12 +1,20 @@ import TxnsReceiptStatus from '@/components/common/TxnsReceiptStatus'; import Question from '@/components/Icons/Question'; import useRpc from '@/hooks/useRpc'; +import { networkId } from '@/utils/config'; import { hexy } from '@/utils/hexy'; -import { convertToMetricPrefix, localFormat, yoctoToNear } from '@/utils/libs'; +import { + convertToMetricPrefix, + fiatValue, + localFormat, + shortenAddress, + yoctoToNear, +} from '@/utils/libs'; import { Action, FunctionCallActionView, ReceiptsPropsInfo, + RPCTransactionInfo, } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; import Big from 'big.js'; @@ -17,12 +25,19 @@ import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; interface Props { receipt: ReceiptsPropsInfo | any; + statsData: { + stats: Array<{ + near_price: string; + }>; + }; + rpcTxn: RPCTransactionInfo; } -const ReceiptInfo = ({ receipt }: Props) => { +const ReceiptInfo = ({ receipt, statsData, rpcTxn }: Props) => { const hashes = ['output', 'inspect']; const [pageHash, setHash] = useState('output'); const [tabIndex, setTabIndex] = useState(0); + const [receiptKey, setReceiptKey] = useState(null); const { t } = useTranslation(); const onTab = (index: number) => { setHash(hashes[index]); @@ -33,6 +48,8 @@ const ReceiptInfo = ({ receipt }: Props) => { const [loading, setLoading] = useState(false); const { getBlockDetails } = useRpc(); + const currentPrice = statsData?.stats?.[0]?.near_price || 0; + useEffect(() => { const index = hashes.indexOf(pageHash as string); @@ -183,6 +200,23 @@ const ReceiptInfo = ({ receipt }: Props) => { status !== undefined) || status === 'successReceiptId'; + useEffect(() => { + if (rpcTxn && rpcTxn?.receipts?.length > 0) { + const receiptToFind: any = rpcTxn?.receipts?.find( + (item: any) => item?.receipt_id === receipt?.id, + ); + if (receiptToFind) { + setReceiptKey(receiptToFind); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [rpcTxn, receipt]); + + const deposit = + Array.isArray(receipt?.actions) && receipt.actions.length > 0 + ? receipt.actions[0]?.args?.deposit ?? 0 + : 0; + return (
onTab(index)}> @@ -336,13 +370,38 @@ const ReceiptInfo = ({ receipt }: Props) => { From - - - {receipt?.predecessorId} - + +
+ + {receipt?.predecessorId} + + {!loading && + receiptKey && + receiptKey?.receipt?.Action?.signer_public_key && + receiptKey?.receipt?.Action?.signer_id && ( + + +  ( + + {shortenAddress( + receiptKey?.receipt?.Action + ?.signer_public_key, + )} + + ) + + + )} +
@@ -366,6 +425,36 @@ const ReceiptInfo = ({ receipt }: Props) => { + + + +
+ +
+
+ Burnt Gas & Tokens + + +
+
+ 🔥 + {`${ + !loading && receipt?.outcome?.gasBurnt + ? convertToMetricPrefix(receipt?.outcome?.gasBurnt) + : receipt?.outcome?.gasBurnt ?? '' + }gas`} + |{' '} + {!loading && receipt?.outcome?.tokensBurnt + ? yoctoToNear(receipt?.outcome?.tokensBurnt, true) + : receipt?.outcome?.tokensBurnt ?? ''} +  â“ƒ +
+
+ + { -
- -
-
- Burnt Gas - - - - 🔥 - {`${ - !loading && receipt?.outcome?.gasBurnt - ? convertToMetricPrefix(receipt?.outcome?.gasBurnt) - : receipt?.outcome?.gasBurnt ?? '' - }gas`} - - - - - -
- Burnt Tokens + Refund - - - 🔥 - {!loading && receipt?.outcome?.tokensBurnt - ? yoctoToNear(receipt?.outcome?.tokensBurnt, true) - : receipt?.outcome?.tokensBurnt ?? ''} - Ⓝ - + + {!loading && + receipt?.outcome?.nestedReceipts && + yoctoToNear( + getRefund(receipt?.outcome?.nestedReceipts) || '0', + true, + )} +  â“ƒ
- Refund + Value - {!loading && - receipt?.outcome?.nestedReceipts && - yoctoToNear( - getRefund(receipt?.outcome?.nestedReceipts) || '0', - true, - )} + {!loading && receipt && deposit + ? yoctoToNear(deposit, true) + : deposit ?? '0'}{' '} Ⓝ + {currentPrice && networkId === 'mainnet' + ? ` ($${fiatValue( + yoctoToNear(deposit ?? 0, false), + currentPrice, + )})` + : ''} diff --git a/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx b/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx index b83af627d..11fe7261d 100644 --- a/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx +++ b/apps/app/src/components/Transactions/Receipts/ReceiptRow.tsx @@ -3,9 +3,10 @@ import { convertToMetricPrefix, fiatValue, localFormat, + shortenAddress, yoctoToNear, } from '@/utils/libs'; -import { ReceiptsPropsInfo } from '@/utils/types'; +import { ReceiptsPropsInfo, RPCTransactionInfo } from '@/utils/types'; import { Tooltip } from '@reach/tooltip'; import useTranslation from 'next-translate/useTranslation'; import Link from 'next/link'; @@ -16,11 +17,13 @@ import useRpc from '@/hooks/useRpc'; import TxnsReceiptStatus from '@/components/common/TxnsReceiptStatus'; import useHash from '@/hooks/useHash'; import { networkId } from '@/utils/config'; +import Big from 'big.js'; interface Props { receipt: ReceiptsPropsInfo | any; borderFlag?: boolean; loading: boolean; + rpcTxn: RPCTransactionInfo; statsData: { stats: Array<{ near_price: string; @@ -29,22 +32,57 @@ interface Props { } const ReceiptRow = (props: Props) => { - const { receipt, borderFlag, loading, statsData } = props; + const { receipt, borderFlag, loading, statsData, rpcTxn } = props; const { t } = useTranslation(); const [block, setBlock] = useState<{ height: string } | null>(null); const { getBlockDetails } = useRpc(); const [pageHash] = useHash(); - const currentPrice = statsData?.stats?.[0]?.near_price || 0; + const currentPrice = + Array.isArray(statsData?.stats) && statsData?.stats?.length > 0 + ? statsData?.stats[0]?.near_price ?? 0 + : 0; const lastBlockHash = useRef(null); const rowRef = useRef(null); + const getDeposit = (actions: any[]): string => + (actions || []) + .map((action) => (action?.args?.deposit ? action?.args?.deposit : '0')) + .reduce( + (acc, deposit) => + Big(acc) + .plus(deposit || '0') + .toString(), + '0', + ); + + const getRefund = (receipts: any[]): string => + (receipts || []) + .filter( + (receipt) => + receipt?.predecessor_id === 'system' && 'outcome' in receipt, + ) + .reduce( + (acc, receipt) => + Big(acc || '0') + .plus(getDeposit(receipt?.actions) || '0') + .toString(), + '0', + ); + + const getPreCharged = (receipt: any): string => + receipt + ? Big(receipt?.outcome?.tokens_burnt || '0') + .plus(getRefund(receipt?.outcome?.outgoing_receipts || [])) + .toString() + : '0'; + useEffect(() => { - if (receipt?.block_hash && receipt.block_hash !== lastBlockHash.current) { - lastBlockHash.current = receipt.block_hash; + if (receipt?.block_hash && receipt?.block_hash !== lastBlockHash?.current) { + lastBlockHash.current = receipt?.block_hash; - getBlockDetails(receipt.block_hash) + getBlockDetails(receipt?.block_hash) .then((resp: any) => { setBlock(resp?.header); }) @@ -70,7 +108,6 @@ const ReceiptRow = (props: Props) => { const handleScroll = () => { if (typeof window === 'undefined') return; - const hash = window.location.hash; const parts = hash.split('#'); const id = parts.length > 2 ? parts[2] : null; @@ -96,7 +133,10 @@ const ReceiptRow = (props: Props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [receipt?.receipt_id, pageHash]); - const deposit = receipt?.actions?.[0]?.args?.deposit ?? 0; + const deposit = + Array.isArray(receipt?.actions) && receipt.actions.length > 0 + ? receipt.actions[0]?.args?.deposit ?? 0 + : 0; return (
@@ -205,12 +245,34 @@ const ReceiptRow = (props: Props) => {
) : receipt?.predecessor_id ? (
- - {receipt?.predecessor_id} - +
+ + {receipt?.predecessor_id} + + {receipt?.receipt?.Action?.signer_public_key && + receipt?.receipt?.Action?.signer_id && ( + + +  ( + + {shortenAddress( + receipt?.receipt?.Action?.signer_public_key, + )} + + ) + + + )} +
) : ( '' @@ -265,7 +327,7 @@ const ReceiptRow = (props: Props) => {
) : receipt?.outcome?.gas_burnt ? ( -
+
🔥 {receipt?.outcome?.gas_burnt @@ -316,7 +378,44 @@ const ReceiptRow = (props: Props) => { '' )}
- +
+
+ +
+ +
+
+ Pre-charged Fee & Refund +
+ {!receipt || loading ? ( +
+ + + +
+ ) : ( +
+
+ {`${ + receipt && yoctoToNear(getPreCharged(receipt) || '0', true) + } Ⓝ`} + |{' '} + {`${ + Array.isArray(receipt?.outcome?.outgoing_receipts) && + receipt.outcome.outgoing_receipts.length > 0 + ? yoctoToNear( + getRefund(receipt.outcome.outgoing_receipts), + true, + ) + : '0' + } Ⓝ`} +
+
+ )} +
{
)}
-
{
) : (
- {receipt?.outcome?.logs?.length > 0 ? ( + {receipt && receipt?.outcome?.logs?.length > 0 ? (