From 59fa0bba48a3ab95b8dd8b549f0033cf14dd5f2a Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Fri, 10 Jun 2022 15:57:52 +0800 Subject: [PATCH 1/4] feat: remove confluxportal support --- src/app/components/ConnectWallet/Modal.tsx | 11 ++------ src/locales/en/translation.json | 1 - src/locales/zh_cn/translation.json | 1 - src/setupProxy.js | 8 +++--- src/utils/hooks/usePortal.ts | 31 ++++++++++++++-------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/app/components/ConnectWallet/Modal.tsx b/src/app/components/ConnectWallet/Modal.tsx index 2cf802179..a9547ca81 100644 --- a/src/app/components/ConnectWallet/Modal.tsx +++ b/src/app/components/ConnectWallet/Modal.tsx @@ -18,7 +18,6 @@ import { CopyButton } from './../CopyButton'; import { useCheckHook } from './useCheckHook'; import { NETWORK_ID, NETWORK_TYPE, NETWORK_TYPES } from 'utils/constants'; -import iconLogo from './assets/logo.png'; import iconFluent from './assets/fluent.svg'; import iconClose from './assets/close.svg'; import iconLoading from './assets/loading.svg'; @@ -82,14 +81,8 @@ export const Modal = ({ login().finally(() => onClose()); }; - let walletText = t(translations.connectWallet.modal.confluxportal); - let walletLogo = iconLogo; - - // @ts-ignore - if (window.conflux?.isFluent) { - walletText = t(translations.connectWallet.modal.fluentWallet); - walletLogo = iconFluent; - } + let walletText = t(translations.connectWallet.modal.fluentWallet); + let walletLogo = iconFluent; let title: string = t(translations.connectWallet.modal.title); let portal: React.ReactNode = walletText; diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index b49fba1a8..912a6c80b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -1550,7 +1550,6 @@ "modal": { "title": "Connect to a wallet", "installFluentWallet": "Install Fluent Wallet", - "confluxportal": "ConfluxPortal", "fluentWallet": "Fluent Wallet", "initializing": "Initializing...", "errorConnecting": "Error connecting...", diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index a2c39d6d3..16fbbcbe7 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -1548,7 +1548,6 @@ "modal": { "title": "请连接您的钱包", "installFluentWallet": "安装 Fluent Wallet", - "confluxportal": "ConfluxPortal", "fluentWallet": "Fluent Wallet", "initializing": "正在初始化...", "errorConnecting": "连接错误...", diff --git a/src/setupProxy.js b/src/setupProxy.js index 91b831b46..393e0500f 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -3,8 +3,8 @@ const { createProxyMiddleware } = require('http-proxy-middleware'); // cra doc https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually // http-proxy-middleware doc https://www.npmjs.com/package/http-proxy-middleware#example -const url = 'https://www-stage.confluxscan.net'; -// const url = 'https://confluxscan.net/'; +// const url = 'https://www-stage.confluxscan.net'; +const url = 'https://confluxscan.net/'; let stat = `${url}`; let v1 = `${url}`; let rpc = `${url}/rpc`; @@ -12,8 +12,8 @@ let rpcv2 = `${url}/rpcv2`; let confluxDag = `${url}`; if (process.env.REACT_APP_TestNet === 'true') { - const testnet = 'https://testnet-stage.confluxscan.net'; - // const testnet = 'https://testnet.confluxscan.net/'; + // const testnet = 'https://testnet-stage.confluxscan.net'; + const testnet = 'https://testnet.confluxscan.net/'; stat = `${testnet}`; v1 = `${testnet}`; rpc = `${testnet}/rpc`; diff --git a/src/utils/hooks/usePortal.ts b/src/utils/hooks/usePortal.ts index 061839165..460b40bdc 100644 --- a/src/utils/hooks/usePortal.ts +++ b/src/utils/hooks/usePortal.ts @@ -1,12 +1,23 @@ -import { - useStatus, - useAccount, - useChainId, - useBalance, - connect, - sendTransaction, - provider, -} from '@cfxjs/use-wallet'; +import Wallet from '@cfxjs/use-wallet'; +export { Unit } from '@cfxjs/use-wallet'; +// @ts-ignore +const FluentWallet = new Wallet('conflux', { mustBeFluent: true }); + +export const store = FluentWallet.store; +export const provider = FluentWallet.provider; +export const completeDetect = FluentWallet.completeDetect; +export const connect = FluentWallet.connect; +export const sendTransaction = FluentWallet.sendTransaction; +export const addChain = FluentWallet.addChain; +export const switchChain = FluentWallet.switchChain; +export const watchAsset = FluentWallet.watchAsset; +export const personalSign = FluentWallet.personalSign; +export const typedSign = FluentWallet.typedSign; +export const trackBalanceChangeOnce = FluentWallet.trackBalanceChangeOnce; +export const useStatus = FluentWallet.useStatus; +export const useAccount = FluentWallet.useAccount; +export const useChainId = FluentWallet.useChainId; +export const useBalance = FluentWallet.useBalance; // @todo 是否应该和 @cfxjs/react-hooks 合并到一起? export const usePortal = () => { @@ -41,5 +52,3 @@ export const usePortal = () => { sendTransaction, }; }; - -export { provider, sendTransaction }; From 257647d5bdc5d1795274c1d0b36438a7f18422ad Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Mon, 13 Jun 2022 11:41:10 +0800 Subject: [PATCH 2/4] feat: SCAN-4077 --- src/app/containers/NFTAsset/index.tsx | 43 +++++++++++++++++++++------ src/locales/en/translation.json | 5 ++++ src/locales/zh_cn/translation.json | 5 ++++ src/utils/constants.ts | 3 ++ 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/app/containers/NFTAsset/index.tsx b/src/app/containers/NFTAsset/index.tsx index 9aeeaa62f..95c2a3145 100644 --- a/src/app/containers/NFTAsset/index.tsx +++ b/src/app/containers/NFTAsset/index.tsx @@ -22,10 +22,11 @@ import { reqNFT1155Tokens, } from 'utils/httpRequest'; import qs from 'query-string'; +import { TABLE_LIST_LIMIT } from 'utils/constants'; type NFTBalancesType = { - type: string; contract: string; + type: string; name: any; balance: number; index: number; @@ -49,11 +50,10 @@ export function NFTAsset({ const { address } = useParams<{ address?: string; }>(); - const { t, i18n } = useTranslation(); + const { t } = useTranslation(); const history = useHistory(); const { pathname, search } = useLocation(); const { NFTAddress, skip = '0', limit = '12', ...others } = qs.parse(search); - const lang = i18n.language.includes('zh') ? 'zh' : 'en'; const [loading, setLoading] = useState(false); const [hasSearched, setHasSearched] = useState(false); const [NFTs, setNFTs] = useState([]); @@ -64,6 +64,7 @@ export function NFTAsset({ type, }); const [total, setTotal] = useState(0); + const [listLimit, setListLimit] = useState(TABLE_LIST_LIMIT); const pageSize = Number(limit); const page = Math.floor((Number(skip) || 0) / pageSize) + 1; @@ -90,6 +91,7 @@ export function NFTAsset({ total: 0, }; let total = 0; + let listLimit = 0; setLoading(true); setHasSearched(true); @@ -115,6 +117,7 @@ export function NFTAsset({ // @ts-ignore total = NFTs.total; + listLimit = NFTs.listLimit; } else { if (await validateAddress(address)) { const data = await reqNFTBalance({ @@ -137,6 +140,7 @@ export function NFTAsset({ } total = selectedNFT.balance; + listLimit = selectedNFT.balance; if (selectedNFT.type.includes('1155')) { NFTs = await reqNFT1155Tokens({ @@ -169,6 +173,10 @@ export function NFTAsset({ setNFTs(NFTs.list); setTotal(total); setLoading(false); + + if (listLimit) { + setListLimit(listLimit); + } }; const handlePaginationChange = (page, pageSize) => { @@ -205,6 +213,27 @@ export function NFTAsset({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [address, NFTAddress, skip, limit, contract, type]); + // 721 and 1155 show different tip + let totalTip = ''; + let paginationTotal = total; + const tip = + translations.NFTAsset[ + (type || selectedNFT.type).includes('721') ? 'totalOf721' : 'totalOf1155' + ]; + + if (!listLimit || listLimit >= total) { + totalTip = t(tip, { + amount: toThousands(total), + }); + } else { + paginationTotal = listLimit; + totalTip = `${t(tip, { + amount: toThousands(listLimit), + })} ${t(translations.NFTAsset.listLimit, { + total: toThousands(total), + })}`; + } + return ( @@ -245,9 +274,7 @@ export function NFTAsset({ ) : ( <>
- {t(translations.blocks.tipCountBefore)} {toThousands(total)}{' '} - {lang === 'zh' ? '个 ' : ''} - {selectedNFT.name || ''} NFT{' '} + {totalTip} {t(translations.contract.address)}:{' '} @@ -274,9 +301,7 @@ export function NFTAsset({ hideOnSinglePage={true} current={page} defaultPageSize={pageSize} - total={total} - // showSizeChanger={false} - // showQuickJumper={false} + total={paginationTotal} pageSizeOptions={['12', '24', '60', '120']} onChange={handlePaginationChange} /> diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 912a6c80b..f04f5bab7 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -3,6 +3,11 @@ "title": "Conflux BlockChain Explorer", "description": "BlockChain Explorer for Conflux Network" }, + "NFTAsset": { + "totalOf721": "Latest {{amount}} active tokens", + "totalOf1155": "Latest {{amount}} unique tokens", + "listLimit": "(From a total of {{total}} tokens)" + }, "nftDetail": { "title": "NFT Detail", "details": "Details", diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index 16fbbcbe7..da3efe7c0 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -3,6 +3,11 @@ "title": "树图区块链浏览器", "description": "树图区块链浏览器" }, + "NFTAsset": { + "totalOf721": "最新的 {{amount}} 个活跃代币", + "totalOf1155": "最新的 {{amount}} 个代币", + "listLimit": "(共计 {{total}} 个代币)" + }, "nftDetail": { "title": "NFT 详情", "details": "详情", diff --git a/src/utils/constants.ts b/src/utils/constants.ts index c7caa8a9b..8b7dcded2 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -268,3 +268,6 @@ OPEN_API_URLS.PoSDailyParticipationRate = '/stat/pos-daily-participation-rate'; // Cross Space OPEN_API_URLS.CrossSpaceDailyCFXTransfer = '/stat/cross-space-cfx'; + +// table list list limit, max query items is 10,000, exceed will cause backend error +export const TABLE_LIST_LIMIT = 10000; From ea92fac3268f5c2604b6b4db45f1775d66b3e5fc Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Tue, 14 Jun 2022 15:01:52 +0800 Subject: [PATCH 3/4] feat: support open api host config to net8888cfx --- src/utils/constants.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 8b7dcded2..b37aecdfb 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -225,9 +225,14 @@ export const CROSS_SPACE_ADDRESS = IS_TESTNET ? CROSS_SPACE_ADDRESSES.testnet : CROSS_SPACE_ADDRESSES.mainnet; -export const OPEN_API_HOST = IS_TESTNET +let APIHost = IS_TESTNET ? 'api-testnet.confluxscan.net' : 'api.confluxscan.net'; +if (window.location.host.startsWith('net')) { + APIHost = window.location.host.replace(/cfx|eth/, 'api'); +} + +export const OPEN_API_HOST = APIHost; export const OPEN_API_URLS = Object.entries({ // charts From 522340c5723fac46007a96e3ba2762bf442d9dd9 Mon Sep 17 00:00:00 2001 From: tangxuezhi <0x74616e67@gmail.com> Date: Thu, 16 Jun 2022 17:30:22 +0800 Subject: [PATCH 4/4] feat: SCAN-4084, update pending tx reason track --- src/app/components/TxnComponents/Overview.tsx | 1 + src/app/components/TxnComponents/Status.tsx | 19 +- src/app/containers/Transaction/Detail.tsx | 1 + .../containers/Transactions/PendingTxns.tsx | 23 +- src/locales/en/translation.json | 47 +++- src/locales/zh_cn/translation.json | 47 +++- src/setupProxy.js | 4 +- src/utils/httpRequest.ts | 7 + src/utils/rpcRequest.ts | 14 +- src/utils/tableColumns/PendingReason.tsx | 264 ++++++++++++++++++ src/utils/tableColumns/transaction.tsx | 25 +- 11 files changed, 395 insertions(+), 57 deletions(-) create mode 100644 src/utils/tableColumns/PendingReason.tsx diff --git a/src/app/components/TxnComponents/Overview.tsx b/src/app/components/TxnComponents/Overview.tsx index 215cd598e..d696a92d3 100644 --- a/src/app/components/TxnComponents/Overview.tsx +++ b/src/app/components/TxnComponents/Overview.tsx @@ -45,6 +45,7 @@ export const Overview = ({ data }) => { type={status} txExecErrorInfo={txExecErrorInfo} address={from} + hash={hash} >
diff --git a/src/app/components/TxnComponents/Status.tsx b/src/app/components/TxnComponents/Status.tsx index 1eaf31a11..8a1c869f8 100644 --- a/src/app/components/TxnComponents/Status.tsx +++ b/src/app/components/TxnComponents/Status.tsx @@ -12,8 +12,7 @@ import { Popover } from '@cfxjs/react-ui'; import { PopoverProps } from '@cfxjs/react-ui/dist/popover/popover'; import { useBreakpoint } from 'styles/media'; import _ from 'lodash'; -import { Link } from 'app/components/Link/Loadable'; -import { formatAddress } from 'utils'; +import { PendingReason } from 'utils/tableColumns/PendingReason'; import imgSuccess from 'images/status/success.svg'; import imgError from 'images/status/error.svg'; @@ -32,6 +31,7 @@ interface Props { message: string; }; address?: string; + hash?: string; } type NativeAttrs = Omit, keyof Props>; @@ -47,6 +47,7 @@ const StatusComponent = ({ showTooltip, txExecErrorInfo, address, + hash, ...others }: StatusProps) => { const breakpoint = useBreakpoint(); @@ -118,13 +119,10 @@ const StatusComponent = ({ <> {name}{' '} {address ? ( - - {t(translations.transaction.pendingReasonLink)} - + <> + + + ) : null} ); @@ -251,6 +249,9 @@ const StyledStatusWrapper = styled.span` color: #97a3b4; margin-left: 0.5714rem; } + .split { + margin-left: 10px; + } `; const StyledPopoverWrapper = styled.div` diff --git a/src/app/containers/Transaction/Detail.tsx b/src/app/containers/Transaction/Detail.tsx index 39d612994..56d961e2c 100644 --- a/src/app/containers/Transaction/Detail.tsx +++ b/src/app/containers/Transaction/Detail.tsx @@ -723,6 +723,7 @@ export const Detail = () => { type={status} txExecErrorInfo={txExecErrorInfo} address={from} + hash={routeHash} > diff --git a/src/app/containers/Transactions/PendingTxns.tsx b/src/app/containers/Transactions/PendingTxns.tsx index a6ebbe403..18c5d26e0 100644 --- a/src/app/containers/Transactions/PendingTxns.tsx +++ b/src/app/containers/Transactions/PendingTxns.tsx @@ -2,13 +2,11 @@ import React, { useEffect, useState } from 'react'; import { tokenColunms, transactionColunms } from 'utils/tableColumns'; import { TablePanel as TablePanelNew } from 'app/components/TablePanelNew'; import { useTranslation } from 'react-i18next'; -import SDK from 'js-conflux-sdk/dist/js-conflux-sdk.umd.min.js'; import { translations } from 'locales/i18n'; import BigNumber from 'bignumber.js'; -// import { toThousands } from 'utils'; import { TxnSwitcher, Title } from './components'; import { isAccountAddress } from 'utils'; -import { getAccountPendingTransactions } from 'utils/rpcRequest'; +import { reqPendingTxs } from 'utils/httpRequest'; interface Props { address: string; @@ -34,19 +32,26 @@ export const PendingTxns = ({ address }: Props) => { ...state, loading: true, }); - getAccountPendingTransactions( - address, - undefined, - SDK.format.hex(10), // default limit - ) + + reqPendingTxs({ + query: { + accountAddress: address, + }, + }) .then(resp => { if (resp) { try { - const { firstTxStatus, pendingCount, pendingTransactions } = resp; + const { + firstTxStatus, + pendingCount, + pendingTransactions, + pendingDetail, + } = resp; const list = pendingTransactions.slice(0, 10).map((p, index) => { p.status = '4'; if (!index) { p.reason = firstTxStatus; + p.pendingDetail = pendingDetail; } return p; }); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index f04f5bab7..1d2638a02 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -304,11 +304,6 @@ "pendingTotal": "Showing the last 10 pending txns (A total of {{total}} pending txns)", "pendingTip": "Only pending transactions with a confirmation time of more than 5 minutes are shown.", "pendingReasonTip": "; the reason of pending txn: ", - "pendingReason": { - "futureNonce": "Wrong nonce", - "notEnoughCash": "Insufficient balance", - "ready": "Ready to pack" - }, "viewTxn": "View {{type}}" }, "cfxTransfers": { @@ -1354,6 +1349,48 @@ "hex": "Hex", "text": "Text", "number": "Number" + }, + "pending": { + "view": "View detail", + "detail": "Detail: ", + "tip": "Tip: ", + "reference": "Reference: ", + "link": "https://developer.confluxnetwork.org/sending-tx/en/why_tx_is_pending" + }, + "pendingDetails": { + "futrueNonce": { + "summary": "Discontinuous nonce", + "detail": "Discontinuous nonce, the account nonce is {{stateNonce}}, current transaction config nonce is {{txNonce}}.", + "tip": "Supplement transactions with missing nonces." + }, + "notEnoughCash": { + "summary": "Insufficient balance", + "contractCreateAndToEOA": { + "detail": "Insufficient balance. Total needs: {{total}} CFX = value ({{value}}) + gas ({{gas}}) * gasPrice ({{gasPrice}}) + storageLimit ({{storageLimit}}) * storagePrice (10^18/1024). Balance: {{balance}} CFX.", + "tip": "1. Increase balance 2. gasPrice or storageLimit is too large, please update gas fee, gas price" + }, + "toContract": { + "detail": "Insufficient balance. Total needs: {{total}} CFX = value ({{value}}) + gas ({{gas}}) * gasPrice ({{gasPrice}}) + storageLimit ({{storageLimit}}) * storagePrice (10^18/1024){{gasSponsor}}{{storageSponsor}}{{reason}}. Balance: {{balance}} CFX.", + "tip": "1. Increase balance 2. gasPrice or storageLimit is too large, please update gas fee, gas price", + "reason": { + "notSponsored": ", not sponsored", + "exceedUpperBound": "; gas fee sponsored failed, exceed sponsor upperbound ({{sponsorGasBound}})", + "exceedGasFeeBalance": "; gas fee sponsored failed, exceed sponsor balance ({{sponsorBalanceForGas}})", + "exceedStorageFeeBalance": "; storage fee sponsored failed, exceed sponsor balance ({{sponsorBalanceForCollateral}})" + } + } + }, + "readyToPack": { + "summary": "Ready to pack", + "epochExceed": { + "detail": "The gap of transaction config epoch and latest epoch is more than 100000. Transaction config epoch is {{proposedEpoch}},latest epoch is {{confirmedEpoch}}.", + "tip": "Resend transaction with latest epoch." + }, + "lowGasPrice": { + "detail": "Gas price is too low. Transaction config gas price is {{txGasPrice}}.", + "tip": "Increase gas price to speedup transaction." + } + } } }, "block": { diff --git a/src/locales/zh_cn/translation.json b/src/locales/zh_cn/translation.json index da3efe7c0..38b6a5902 100644 --- a/src/locales/zh_cn/translation.json +++ b/src/locales/zh_cn/translation.json @@ -304,11 +304,6 @@ "pendingTotalLt10": "共计 {{total}} 条待处理记录", "pendingTip": "仅展示确认时间超过 5 分钟的待处理交易。", "pendingReasonTip": ";待处理交易原因:", - "pendingReason": { - "futureNonce": "错误随机数", - "notEnoughCash": "余额不足", - "ready": "待打包" - }, "viewTxn": "查看{{type}}" }, "cfxTransfers": { @@ -1352,6 +1347,48 @@ "hex": "十六进制", "text": "文字", "number": "数字" + }, + "pending": { + "view": "查看详情", + "detail": "详情:", + "tip": "提示:", + "reference": "参考:", + "link": "http://wiki.conflux123.xyz/books/faqs/chapter/pending-tx" + }, + "pendingDetails": { + "futrueNonce": { + "summary": "随机数不连续", + "detail": "随机数不连续,发送账户随机数为 {{stateNonce}},当前交易随机数为 {{txNonce}}。", + "tip": "补充缺失的随机数的交易。" + }, + "notEnoughCash": { + "summary": "余额不足", + "contractCreateAndToEOA": { + "detail": "余额不足。完成交易共需要:{{total}} CFX = value ({{value}}) + gas ({{gas}}) * gasPrice ({{gasPrice}}) + storageLimit ({{storageLimit}}) * storagePrice (10^18/1024)。账户余额:{{balance}} CFX。", + "tip": "1. 增加账户余额 2. gasPrice 或 storageLimit 可能设置过大,请重新设置燃气费,燃气价格。" + }, + "toContract": { + "detail": "余额不足。完成交易共需要:{{total}} CFX = value ({{value}}) + gas ({{gas}}) * gasPrice ({{gasPrice}}) + storageLimit ({{storageLimit}}) * storagePrice (10^18/1024){{gasSponsor}}{{storageSponsor}}{{reason}}。账户余额:{{balance}} CFX。", + "tip": "1. 增加账户余额 2. gasPrice 或 storageLimit 可能设置过大,请重新设置燃气费,燃气价格。", + "reason": { + "notSponsored": ",交易未被代付", + "exceedUpperBound": ";燃气费代付失败,超过上限({{sponsorGasBound}})", + "exceedGasFeeBalance": ";燃气费代付失败,超过余额({{sponsorBalanceForGas}})", + "exceedStorageFeeBalance": ";存储费代付失败,超过余额({{sponsorBalanceForCollateral}})" + } + } + }, + "readyToPack": { + "summary": "交易待打包", + "epochExceed": { + "detail": "发送交易的纪元和当前纪元跨度大于 100000,交易纪元为 {{proposedEpoch}},当前纪元为 {{confirmedEpoch}}。", + "tip": "重新发送交易,使用最新的纪元。" + }, + "lowGasPrice": { + "detail": "燃气价格太低,当前燃气价格为 {{txGasPrice}}。", + "tip": "提高燃气价格加速交易。" + } + } } }, "block": { diff --git a/src/setupProxy.js b/src/setupProxy.js index 393e0500f..7418097fb 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -12,8 +12,8 @@ let rpcv2 = `${url}/rpcv2`; let confluxDag = `${url}`; if (process.env.REACT_APP_TestNet === 'true') { - // const testnet = 'https://testnet-stage.confluxscan.net'; - const testnet = 'https://testnet.confluxscan.net/'; + const testnet = 'https://testnet-stage.confluxscan.net'; + // const testnet = 'https://testnet.confluxscan.net/'; stat = `${testnet}`; v1 = `${testnet}`; rpc = `${testnet}/rpc`; diff --git a/src/utils/httpRequest.ts b/src/utils/httpRequest.ts index 64c32796f..cb9d63219 100644 --- a/src/utils/httpRequest.ts +++ b/src/utils/httpRequest.ts @@ -321,3 +321,10 @@ export const reqNFTBalance = (extra?: object) => { }; /** open api, end */ + +export const reqPendingTxs = (extra?: object) => { + return sendRequest({ + url: `/stat/transaction/pending`, + ...extra, + }); +}; diff --git a/src/utils/rpcRequest.ts b/src/utils/rpcRequest.ts index c46a083bc..78b586141 100644 --- a/src/utils/rpcRequest.ts +++ b/src/utils/rpcRequest.ts @@ -328,12 +328,12 @@ export const getSponsorInfo = async (...args) => { } }; -export const getAccountPendingTransactions = async (...args) => { - try { - return request('cfx_getAccountPendingTransactions', ...args); - } catch (e) { - throw e; - } -}; +// export const getAccountPendingTransactions = async (...args) => { +// try { +// return request('cfx_getAccountPendingTransactions', ...args); +// } catch (e) { +// throw e; +// } +// }; export default request; diff --git a/src/utils/tableColumns/PendingReason.tsx b/src/utils/tableColumns/PendingReason.tsx new file mode 100644 index 000000000..39dae9562 --- /dev/null +++ b/src/utils/tableColumns/PendingReason.tsx @@ -0,0 +1,264 @@ +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { translations } from 'locales/i18n'; +import styled from 'styled-components/macro'; +import { Popover } from '@cfxjs/antd'; +import { reqPendingTxs } from 'utils/httpRequest'; +import { Link } from 'app/components/Link/Loadable'; +import { formatAddress, formatBalance } from 'utils'; +import BigNumber from 'bignumber.js'; + +interface Props { + detail?: any; + account?: string; + hash?: string; +} + +export const PendingReason = ({ + detail: _detail, + account, + hash: _hash, +}: Props) => { + const { t } = useTranslation(); + const [detail, setDetail] = useState(_detail || {}); + + useEffect(() => { + async function main() { + if (account) { + const data = await reqPendingTxs({ + query: { + accountAddress: account, + }, + }); + + if (data) { + const { pendingDetail, pendingTransactions } = data; + + // not current tx pending reason + if (pendingTransactions[0]?.hash === _hash) { + setDetail(pendingDetail); + } + } + } + } + + main().catch(console.log); + }, [_hash, account]); + + const codeMap = useMemo(() => { + const { + futrueNonce, + notEnoughCash, + readyToPack, + } = translations.transaction.pendingDetails; + return { + '11': { + summary: futrueNonce.summary, + detail: futrueNonce.detail, + tip: futrueNonce.tip, + }, + '21': { + summary: notEnoughCash.summary, + detail: notEnoughCash.contractCreateAndToEOA.detail, + tip: notEnoughCash.contractCreateAndToEOA.tip, + }, + '22': { + summary: notEnoughCash.summary, + detail: notEnoughCash.contractCreateAndToEOA.detail, + tip: notEnoughCash.contractCreateAndToEOA.tip, + }, + '23': { + summary: notEnoughCash.summary, + detail: notEnoughCash.toContract.detail, + tip: notEnoughCash.toContract.tip, + reason: notEnoughCash.toContract.reason, + }, + '31': { + summary: readyToPack.summary, + detail: readyToPack.epochExceed.detail, + tip: readyToPack.epochExceed.tip, + }, + '32': { + summary: readyToPack.summary, + detail: readyToPack.lowGasPrice.detail, + tip: readyToPack.lowGasPrice.tip, + }, + }; + }, []); + + const getDetail = useCallback(() => { + const { notEnoughCash } = translations.transaction.pendingDetails; + const i18n = codeMap[detail.code]; + + let params = {}; + + if (detail.code === 11 || detail.code === 31 || detail.code === 32) { + params = detail.params; + } else if (detail.code === 21 || detail.code === 22) { + const { value, gas, gasPrice, storageLimit, balance } = detail.params; + + params = { + total: formatBalance( + new BigNumber(value) + .plus(new BigNumber(gas).multipliedBy(gasPrice)) + .plus(new BigNumber(storageLimit).multipliedBy(1e18).div(1024)), + 18, + false, + { + precision: 18, + }, + ), + value: detail.params.value, + gas: detail.params.gas, + gasPrice: detail.params.gasPrice, + storageLimit: detail.params.storageLimit, + balance: formatBalance(balance), + }; + } else if (detail.code === 23) { + const { + value, + gas, + gasPrice, + storageLimit, + balance, + isWhitelisted, + isGasFeeSponsored, + isColFeeSponsored, + sponsorInfo: { + sponsorGasBound, + sponsorBalanceForGas, + sponsorBalanceForCollateral, + }, + } = detail.params; + + const gasFee = new BigNumber(gas).multipliedBy(gasPrice); + const storageFee = new BigNumber(storageLimit) + .multipliedBy(1e18) + .div(1024); + let total = new BigNumber(value).plus(gasFee).plus(storageFee); + let gasSponsorStr = ''; + let storageSponsorStr = ''; + let reason = ''; + + if (isWhitelisted) { + if (isGasFeeSponsored) { + total = total.minus(gasFee); + gasSponsorStr = ` - gasFee sponsored (${gasFee.toNumber()})`; + } else { + if (gasFee.isGreaterThan(sponsorGasBound)) { + reason = t(notEnoughCash.toContract.reason.exceedUpperBound, { + sponsorGasBound, + }); + } else if (gasFee.isGreaterThan(sponsorBalanceForGas)) { + reason = t(notEnoughCash.toContract.reason.exceedGasFeeBalance, { + sponsorBalanceForGas, + }); + } + } + if (isColFeeSponsored) { + total = total.minus(storageFee); + gasSponsorStr = ` - storageFee sponsored (${storageFee.toNumber()})`; + } else { + if (storageFee.isGreaterThan(sponsorBalanceForCollateral)) { + reason = t( + notEnoughCash.toContract.reason.exceedStorageFeeBalance, + { + sponsorBalanceForCollateral, + }, + ); + } + } + } else { + reason = t(notEnoughCash.toContract.reason.notSponsored); + } + + params = { + total: formatBalance(total, 18, false, { + precision: 18, + }), + value: detail.params.value, + gas: detail.params.gas, + gasPrice: detail.params.gasPrice, + storageLimit: detail.params.storageLimit, + balance: formatBalance(balance), + gasSponsor: gasSponsorStr, + storageSponsor: storageSponsorStr, + reason, + }; + } + + const content = ( + +
+ {t(translations.transaction.pending.detail)} + {t(i18n.detail, { ...params })} +
+
+ {t(translations.transaction.pending.tip)} {t(i18n.tip)} +
+
+ {t(translations.transaction.pending.reference)}{' '} + + {t(translations.transaction.pending.link)} + +
+
+ ); + + return ( + +
{t(i18n.summary)}
+ +
+ {t(translations.transaction.pending.view)} +
+
+
+ ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [detail]); + + if (account) { + if (detail.code) { + return getDetail(); + } else { + return ( + + {t(translations.transaction.pendingReasonLink)} + + ); + } + } else { + if (detail.code) { + return getDetail(); + } else { + return <>--; + } + } +}; + +const StyledPendingReasonWrapper = styled.div` + display: inline-flex; + color: #333; + + .summary { + padding-right: 10px; + } + + .detail { + color: var(--theme-color-blue2); + display: inline; + } +`; + +const StyledPendingContentWrapper = styled.div` + max-width: 450px; + + b { + color: var(--theme-color-blue0); + } +`; diff --git a/src/utils/tableColumns/transaction.tsx b/src/utils/tableColumns/transaction.tsx index afa9dc39c..cfb78ab25 100644 --- a/src/utils/tableColumns/transaction.tsx +++ b/src/utils/tableColumns/transaction.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Translation, useTranslation } from 'react-i18next'; +import { Translation } from 'react-i18next'; import { translations } from 'locales/i18n'; import styled from 'styled-components/macro'; import clsx from 'clsx'; @@ -14,7 +14,7 @@ import { Popover } from '@cfxjs/antd'; import { Overview } from 'app/components/TxnComponents'; import SkeletonContainer from 'app/components/SkeletonContainer/Loadable'; import { useBreakpoint } from 'styles/media'; -import SDK from 'js-conflux-sdk/dist/js-conflux-sdk.umd.min.js'; +import { PendingReason } from './PendingReason'; import iconViewTxn from 'images/view-txn.png'; import iconViewTxnActive from 'images/view-txn-active.svg'; @@ -97,6 +97,7 @@ export const TxnHashRenderComponent = ({ variant="dot" txExecErrorInfo={txExecErrorInfo} address={txnDetail.address} + hash={hash} > ) : null} @@ -276,20 +277,6 @@ export const method = { }, }; -export const PendingReasonText = ({ value }) => { - const { t } = useTranslation(); - let reason = value; - if (reason === 'ready') { - reason = t(translations.transactions.pendingReason.ready); - } else if (reason === SDK.CONST.PENDING_TX_STATUS.FUTURE_NONCE) { - reason = t(translations.transactions.pendingReason.futureNonce); - } else if (reason === SDK.CONST.PENDING_TX_STATUS.NOT_ENOUGH_CASH) { - reason = t(translations.transactions.pendingReason.notEnoughCash); - } else { - reason = --; - } - return reason; -}; export const pendingReason = { title: ( @@ -299,10 +286,8 @@ export const pendingReason = { dataIndex: 'reason', key: 'reason', width: 1, - render: value => ( - + render: (_, row) => ( + ), };