diff --git a/CHANGELOG.md b/CHANGELOG.md index b840cea..7135d0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### v5.0.0 + +- [feat] Supports Solana scans +- [feat] Added local label functionality +- [feat] Supports Arkham local label functionality and Phalcon quick link, Debank local label functionality +- [feat] Supports Merlin Scan +- [feat] BTC Explorer supports local label functionality +- [feat] Etherscan supports quick opening of transaction lists in the Phalcon explorer + ### v4.8.0 - [fix] Fix bug causing style conflicts diff --git a/manifest.config.ts b/manifest.config.ts index 4687f74..f2e7923 100644 --- a/manifest.config.ts +++ b/manifest.config.ts @@ -48,9 +48,16 @@ export default defineManifest((env: ConfigEnv) => { { matches: isDev ? [ - '*://explorer.btc.com/*', + '*://*.btc.com/*', '*://*.opensea.io/*', - '*://*.tronscan.org/*' + '*://*.tronscan.org/*', + '*://scan.merlinchain.io/*', + '*://solscan.io/*', + '*://*.solana.fm/*', + '*://*.metasleuth.io/*', + '*://explorer.solana.com/*', + '*://debank.com/*', + '*://platform.arkhamintelligence.com/*' ] : [''], js: ['src/content/index.ts'], diff --git a/package.json b/package.json index 159dcdb..5cff9de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metasuites", - "version": "4.8.1", + "version": "5.0.0", "repository": { "type": "git", "url": "https://github.com/blocksecteam/metasuites.git" @@ -31,6 +31,7 @@ "buffer": "^6.0.3", "chrome-extension-core": "0.1.8", "classnames": "^2.3.2", + "colorjs.io": "^0.5.0", "copy-to-clipboard": "^3.3.3", "d3": "^5.0.0", "d3-graphviz": "2.6.1", @@ -45,6 +46,8 @@ "ky": "^0.33.3", "lodash-es": "^4.17.21", "normalize.css": "^8.0.1", + "papaparse": "^5.4.1", + "qs": "^6.12.1", "react": "18.2.0", "react-dom": "18.2.0", "save-svg-as-png": "^1.4.17", @@ -62,6 +65,8 @@ "@types/json-bigint": "^1.0.1", "@types/lodash-es": "^4.17.6", "@types/node": "^18.11.8", + "@types/papaparse": "^5.3.14", + "@types/qs": "^6.9.15", "@types/react": "^18.0.24", "@types/react-dom": "^18.0.8", "@types/webextension-polyfill": "^0.10.0", diff --git a/src/assets/images/analyze.png b/src/assets/images/analyze.png index 4919d46..15796c4 100644 Binary files a/src/assets/images/analyze.png and b/src/assets/images/analyze.png differ diff --git a/src/assets/images/edit-private-label-button-full.png b/src/assets/images/edit-private-label-button-full.png new file mode 100644 index 0000000..1994d01 Binary files /dev/null and b/src/assets/images/edit-private-label-button-full.png differ diff --git a/src/assets/images/edit-private-label-button.png b/src/assets/images/edit-private-label-button.png new file mode 100644 index 0000000..9ad002f Binary files /dev/null and b/src/assets/images/edit-private-label-button.png differ diff --git a/src/assets/images/oops-no-auth.png b/src/assets/images/oops-no-auth.png new file mode 100644 index 0000000..c3a5f37 Binary files /dev/null and b/src/assets/images/oops-no-auth.png differ diff --git a/src/assets/images/oops-service-error.png b/src/assets/images/oops-service-error.png index c7b60a8..e53a6ad 100644 Binary files a/src/assets/images/oops-service-error.png and b/src/assets/images/oops-service-error.png differ diff --git a/src/assets/images/oops-unauthorized-error.png b/src/assets/images/oops-unauthorized-error.png new file mode 100644 index 0000000..9c3c83b Binary files /dev/null and b/src/assets/images/oops-unauthorized-error.png differ diff --git a/src/assets/images/tab-bg-settings.png b/src/assets/images/tab-bg-settings.png deleted file mode 100644 index 7bb4ee3..0000000 Binary files a/src/assets/images/tab-bg-settings.png and /dev/null differ diff --git a/src/assets/images/tab-bg-shortcuts.png b/src/assets/images/tab-bg-shortcuts.png deleted file mode 100644 index bef5aec..0000000 Binary files a/src/assets/images/tab-bg-shortcuts.png and /dev/null differ diff --git a/src/background/index.ts b/src/background/index.ts index 9d84fff..9092e0b 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -10,7 +10,12 @@ import { TRONSCAN_TABS_CHANGED, LOAD_TRON_APPROVALS, TRONSCAN_MULTI_SEARCH, - URL_UPDATED + URL_UPDATED, + GET_SOLSCAN_ACCOUNT_INFO, + GET_SOLANAFM_ACCOUNT_INFO, + GET_SOLANAFM_ACCOUNT_TRANSFERS, + GET_SOLSCAN_ACCOUNT_TAB_DATA, + GET_SOLSCAN_TRANSACTION } from '@common/constants' import { initBackgroundRequest } from './listeners' @@ -132,4 +137,82 @@ browser.webRequest.onCompleted.addListener( } ) +browser.webRequest.onCompleted.addListener( + async details => { + const { tabId, method } = details + if (tabId && method === 'GET') { + browser.tabs + .sendMessage(tabId, GET_SOLSCAN_ACCOUNT_INFO) + .catch(() => void 0) + } + }, + { + urls: ['https://api.solscan.io/v2/account?*'] + } +) + +browser.webRequest.onCompleted.addListener( + async details => { + const { tabId, method } = details + if (tabId && method === 'GET') { + browser.tabs + .sendMessage(tabId, GET_SOLSCAN_ACCOUNT_TAB_DATA) + .catch(() => void 0) + } + }, + { + urls: [ + 'https://api.solscan.io/v2/account/soltransfer/txs?*', + 'https://api.solscan.io/v2/account/transaction?*', + 'https://api.solscan.io/v2/account/v2/tokenaccounts?*', + 'https://api.solscan.io/v2/account/stake?*', + 'https://api-v2.solscan.io/v2/account/activity/dextrading?*' + ] + } +) + +browser.webRequest.onCompleted.addListener( + async details => { + const { tabId, method } = details + if (tabId && method === 'GET') { + browser.tabs + .sendMessage(tabId, GET_SOLSCAN_TRANSACTION) + .catch(() => void 0) + } + }, + { + urls: ['https://api.solscan.io/v2/transaction-v2?tx=*'] + } +) + +browser.webRequest.onCompleted.addListener( + async details => { + const { tabId, method } = details + if (tabId && method === 'GET') { + browser.tabs + .sendMessage(tabId, GET_SOLANAFM_ACCOUNT_INFO) + .catch(() => void 0) + } + }, + { + urls: ['https://api.solana.fm/v0/accounts/*'] + } +) + +browser.webRequest.onCompleted.addListener( + async details => { + const { tabId, method } = details + if (tabId && method === 'GET') { + browser.tabs + .sendMessage(tabId, GET_SOLANAFM_ACCOUNT_TRANSFERS) + .catch(() => void 0) + } + }, + { + urls: [ + 'https://api.solana.fm/v0/accounts/BNLtpXLqsjDGxzB1Mmcv3NmEiQhSSWFq8JViKrrrQ8Do/transfers?*' + ] + } +) + initBackgroundRequest() diff --git a/src/background/listeners/explore.ts b/src/background/listeners/explore.ts index 975eae1..974d533 100644 --- a/src/background/listeners/explore.ts +++ b/src/background/listeners/explore.ts @@ -24,7 +24,8 @@ import { GET_LATEST_BLOCK, GET_CREATION_BLOCK, GET_CONTRACT_VARIABLE_LOGS, - GET_CONTRACT_VARIABLE_LIST + GET_CONTRACT_VARIABLE_LIST, + GET_SIMULATION_FEES } from '@common/constants' import commonApi from '@common/api' @@ -109,4 +110,7 @@ export default function initExploreRequest() { chromeEvent.on(GET_CONTRACT_VARIABLE_LIST, async params => { return await commonApi.getContractVariableList(params) }) + chromeEvent.on(GET_SIMULATION_FEES, async params => { + return await commonApi.getSimulationFees(params) + }) } diff --git a/src/common/api/index.ts b/src/common/api/index.ts index d66f07b..856f1ed 100644 --- a/src/common/api/index.ts +++ b/src/common/api/index.ts @@ -1,3 +1,5 @@ +import qs from 'qs' + import request, { type BscResponse } from './request' import type { AddressMethodsReq, @@ -39,7 +41,8 @@ import type { CreationBlock, PostContractVariableLogsReq, ContractVariableLog, - ContractVariableListItem + ContractVariableListItem, + SimulationFeesParams } from './types' export default { @@ -190,5 +193,20 @@ export default { .post('api/v1/source-code/hash', { json: { code } }) - .json>() + .json>(), + getSimulationFees: ({ + chain, + isPrerun = true, + blockNumber + }: SimulationFeesParams) => { + const queryString = qs.stringify( + { isPrerun, blockNumber: isPrerun ? null : blockNumber }, + { + skipNulls: true + } + ) + return request + .get(`api/v1/simulation/${chain}/base-fee?${queryString}`) + .json>() + } } diff --git a/src/common/api/types.ts b/src/common/api/types.ts index 4951f39..41fc9f6 100644 --- a/src/common/api/types.ts +++ b/src/common/api/types.ts @@ -28,6 +28,10 @@ export interface PostAddressParams { address: string } +export interface FundFlowParams extends PostAddressParams { + token?: string +} + export interface PostPrivateVariablesParams extends PostAddressParams { implAddress?: string } @@ -39,6 +43,9 @@ export interface AddressLabel { implementAddress?: string implementLabel?: string implementLogo?: string + chain: string + chainId: number + isLocal?: boolean } export interface MethodLabel { @@ -58,6 +65,8 @@ export interface AddressRiskScoreReq extends PostAddressParams { export interface FundFlowRes { nodes: FundFlowNode[] edges: FundFlowEdge[] + code?: number + message?: string } export interface FundFlowNode extends Record { id: string @@ -67,6 +76,7 @@ export interface FundFlowNode extends Record { type: number isContract: boolean url: string + color: string /** used for filter */ selected?: boolean index?: number @@ -204,7 +214,7 @@ export interface PrivateVariableArgument { export interface PrivateVariable { name: string - inputs: { name: string; type: string }[] + inputs: { name: string; type: string; id: number }[] outputs: { name: string; type: string }[] value?: PrivateVariableArgument mutability: ContractVariableMutability @@ -364,3 +374,9 @@ export interface ContractVariableListItem { mutability: ContractVariableMutability visibility: ContractVariableVisibility } + +export interface SimulationFeesParams { + chain: string + blockNumber?: number + isPrerun: boolean +} diff --git a/src/common/components/BscModal/index.module.less b/src/common/components/BscModal/index.module.less index b438bbb..4cf0427 100644 --- a/src/common/components/BscModal/index.module.less +++ b/src/common/components/BscModal/index.module.less @@ -8,7 +8,7 @@ padding-left: 20px; .justify-between; .items-center; - .flex; + .md-flex; .closeIcon { padding: 20px; cursor: pointer; @@ -17,19 +17,19 @@ } :global { - .ant-modal-content { + .metadock-modal-content { border-radius: 2px !important; padding: 0 !important; - .ant-modal-body { + .metadock-modal-body { padding: 20px; } - .ant-modal-header { + .metadock-modal-header { padding: 0; border-bottom: 1px solid #f0f0f0; margin-bottom: 0; } - .ant-modal-footer { + .metadock-modal-footer { padding: 20px; border-top: 1px solid #f0f0f0; text-align: left; diff --git a/src/common/components/BscModal/index.tsx b/src/common/components/BscModal/index.tsx index 98ce477..fd0820e 100644 --- a/src/common/components/BscModal/index.tsx +++ b/src/common/components/BscModal/index.tsx @@ -1,4 +1,4 @@ -import { Modal, type ModalProps } from 'antd' +import { Modal, type ModalProps, ConfigProvider } from 'antd' import React, { type FC } from 'react' import cls from 'classnames' @@ -16,34 +16,39 @@ const BscModal: FC = ({ ...rest }) => { return ( - - {title} -
- onCancel?.( - e as unknown as React.MouseEvent - ) - } - > - + + + {title} +
+ onCancel?.( + e as unknown as React.MouseEvent< + HTMLButtonElement, + MouseEvent + > + ) + } + > + +
- - } - centered - onCancel={onCancel} - className={cls(styles.bscModal, className)} - style={style} - footer={null} - closable={false} - {...rest} - > - {children} -
+ } + centered + onCancel={onCancel} + className={cls(styles.bscModal, className)} + style={style} + footer={null} + closable={false} + {...rest} + > + {children} + + ) } diff --git a/src/common/components/Cell/cell.tsx b/src/common/components/Cell/cell.tsx index 9227fbe..f518b19 100644 --- a/src/common/components/Cell/cell.tsx +++ b/src/common/components/Cell/cell.tsx @@ -38,7 +38,7 @@ const Cell: FC = props => { style={style} onClick={onClick} > -
+
{icon && }
{title} diff --git a/src/common/components/Cell/index.module.less b/src/common/components/Cell/index.module.less index 95bf17d..8407972 100644 --- a/src/common/components/Cell/index.module.less +++ b/src/common/components/Cell/index.module.less @@ -20,7 +20,7 @@ } .title { .flex-column; - .flex; + .md-flex; span { font-size: 14px; &:nth-of-type(1) { diff --git a/src/common/components/ComplianceRadarPlot/index.module.less b/src/common/components/ComplianceRadarPlot/index.module.less index f8db9ff..fb83fa5 100644 --- a/src/common/components/ComplianceRadarPlot/index.module.less +++ b/src/common/components/ComplianceRadarPlot/index.module.less @@ -7,7 +7,7 @@ border: 2px solid #e6e8eb; overflow: hidden; .flex-column; - .flex; + .md-flex; .graph { width: fit-content; height: calc(100% - 30px); diff --git a/src/common/components/CopyButton/index.module.less b/src/common/components/CopyButton/index.module.less index f50cde8..66fa176 100644 --- a/src/common/components/CopyButton/index.module.less +++ b/src/common/components/CopyButton/index.module.less @@ -12,9 +12,6 @@ } .iconContainer { visibility: hidden; - @media (max-width: 575px) { - visibility: visible !important; - } } } @@ -25,6 +22,7 @@ svg { margin: 0; + fill: none !important; } &.copied { diff --git a/src/common/components/Drawer/index.module.less b/src/common/components/Drawer/index.module.less index a83b4b8..f176492 100644 --- a/src/common/components/Drawer/index.module.less +++ b/src/common/components/Drawer/index.module.less @@ -32,19 +32,20 @@ background-color: #ffffff; border-radius: 20px 20px 0 0; .flex-column; - .flex; + .md-flex; &.show { bottom: 0; } .title { - padding: 30px 0; + padding: 30px 0 30px 24px; position: relative; - font-family: OpenSauceOne-Bold, sans-serif; - font-size: 20px; - line-height: 25px; - .flex-center; + font-size: 14px; + line-height: 20px; + font-weight: 600; + .md-flex; + .items-center; .iconContainer { width: 35px; diff --git a/src/common/components/DrawerSimulation/index.tsx b/src/common/components/DrawerSimulation/index.tsx index 9ca6b85..35dd1f6 100644 --- a/src/common/components/DrawerSimulation/index.tsx +++ b/src/common/components/DrawerSimulation/index.tsx @@ -11,7 +11,7 @@ import { notification } from 'antd' import cls from 'classnames' -import { debounce, isObject } from 'lodash-es' +import { debounce, isObject, intersection } from 'lodash-es' import isMobile from 'is-mobile' import { ethers } from 'ethers' import { QuestionCircleOutlined } from '@ant-design/icons' @@ -25,7 +25,8 @@ import { GET_CONTRACT_BY_ADDRESS, GET_CONTRACT_BY_ABI, GET_LATEST_BLOCK, - SIMULATE_TRANSACTION + SIMULATE_TRANSACTION, + GET_SIMULATION_FEES } from '@common/constants' import { CopyButton, IconClose } from '@common/components' import { chromeEvent } from '@common/event' @@ -86,6 +87,7 @@ const DrawerSimulation: FC = ({ SIMULATE_SUPPORT_LIST.find(i => i.chain === chain)?.nativeCurrency.name ) const [latestBlockNum, setLatestBlockNum] = useState(123455) + const [baseFee, setBaseFee] = useState('') const [formattedContractData, setFormattedContractData] = useState({ methodsOptions: [], @@ -96,10 +98,6 @@ const DrawerSimulation: FC = ({ } }) - const estimatedGas = Number.isNaN(gasPrice) - ? '100' - : Math.ceil(Number(gasPrice) * (1 + 0.2)).toString() - const handleOk = debounce(() => { form.validateFields().then(values => { const params: SimulateTxParams = { @@ -109,7 +107,7 @@ const DrawerSimulation: FC = ({ inputData: values.inputData, value: values.value || '0', gasLimit: Number(values.gasLimit) || 1000000, - gasPrice: values.gasPrice || estimatedGas, + gasPrice: values.gasPrice || baseFee, receiver: values.receiver || '' } if (!values.isPrerun) { @@ -144,6 +142,12 @@ const DrawerSimulation: FC = ({ if (Object.keys(changedValues).includes('function')) { form.resetFields(['parameters']) } + if ( + intersection(Object.keys(changedValues), ['isPrerun', 'blockNumber']) + .length + ) { + getSimulationFees(values.isPrerun, values.blockNumber || latestBlockNum) + } }, 300) const getContractByABI = async () => { @@ -183,6 +187,26 @@ const DrawerSimulation: FC = ({ } } + const getSimulationFees = async (isPrerun = true, blockNumber?: number) => { + const res = await chromeEvent.emit< + typeof GET_SIMULATION_FEES, + { baseFee: string } + >(GET_SIMULATION_FEES, { + chain, + isPrerun, + blockNumber + }) + if (res?.success) { + setBaseFee(ethers.formatUnits(res.data.baseFee, 'gwei')) + } else { + setBaseFee( + Number.isNaN(gasPrice) + ? '100' + : Math.ceil(Number(gasPrice) * (1 + 0.2)).toString() + ) + } + } + const handleSimulate = async (params: SimulateTxParams) => { setLoading(true) const res = await chromeEvent.emit< @@ -314,6 +338,7 @@ const DrawerSimulation: FC = ({ }) getContractByAddress() getLatestBlock() + getSimulationFees() }, []) return ( @@ -324,7 +349,7 @@ const DrawerSimulation: FC = ({ width={isMobile() ? '100%' : 530} closable={false} title={ -
+
setVisible(false)} /> Simulator = ({ destroyOnClose extra={
+ } + open={visible} + onCancel={onClose} + > + +
+
{address}
+
+ + + +
+
Choose the local label color
+
    + setSelectedColor('')} + > + + + {LABEL_COLORS.map(color => ( +
  • setSelectedColor(color)} + /> + ))} +
+ +
    +
  • Local storage, exportable anytime, truly private.
  • +
  • Edit once, apply across multiple websites.
  • +
+
+
+ + ) +} + +export default ModalAddPrivateLabel diff --git a/src/common/components/ModalContractVariableLogs/index.module.less b/src/common/components/ModalContractVariableLogs/index.module.less index 0a84266..197e03f 100644 --- a/src/common/components/ModalContractVariableLogs/index.module.less +++ b/src/common/components/ModalContractVariableLogs/index.module.less @@ -5,7 +5,7 @@ .title { overflow: hidden; .items-center; - .flex; + .md-flex; .contract { font-weight: normal; .text-ellipsis; @@ -14,10 +14,10 @@ .container { .tablePanel { .justify-between; - .flex; + .md-flex; .metadata { .items-center; - .flex; + .md-flex; .variableName { margin-right: 0.5rem; } @@ -32,7 +32,7 @@ font-size: 14px; border-radius: 12px; .items-center; - .flex; + .md-flex; } } .filter { @@ -52,7 +52,7 @@ } &.mobile { .flex-column; - .flex; + .md-flex; .metadata { margin-bottom: 8px; } diff --git a/src/common/components/ModalContractVariableLogs/index.tsx b/src/common/components/ModalContractVariableLogs/index.tsx index 88e9ec3..3e992a3 100644 --- a/src/common/components/ModalContractVariableLogs/index.tsx +++ b/src/common/components/ModalContractVariableLogs/index.tsx @@ -161,7 +161,7 @@ const ModalContractVariableLogs: FC = ({ } footer={ list.length > 0 ? ( -
+