From 57bc5cba3b375d65a314f3e5096c280e889b3b92 Mon Sep 17 00:00:00 2001 From: kvhnuke <10602065+kvhnuke@users.noreply.github.com> Date: Mon, 13 Mar 2023 11:17:20 -0700 Subject: [PATCH 01/22] devop: better gas price handling --- .../ethereum/libs/transaction/gas-utils.ts | 83 +++++++++++----- .../ethereum/libs/transaction/index.ts | 99 ++++++++++++------- .../ethereum/libs/transaction/types.ts | 15 +++ .../components/transaction-fee-item.vue | 2 +- 4 files changed, 139 insertions(+), 60 deletions(-) diff --git a/packages/extension/src/providers/ethereum/libs/transaction/gas-utils.ts b/packages/extension/src/providers/ethereum/libs/transaction/gas-utils.ts index 8fbbcc700..6f9c1071e 100644 --- a/packages/extension/src/providers/ethereum/libs/transaction/gas-utils.ts +++ b/packages/extension/src/providers/ethereum/libs/transaction/gas-utils.ts @@ -2,6 +2,8 @@ import BigNumber from "bignumber.js"; import { BN } from "ethereumjs-util"; import { toBN, toWei } from "web3-utils"; import { GasPriceTypes } from "@/providers/common/types"; +import { FeeHistoryResult } from "web3-eth"; +import { FormattedFeeHistory } from "./types"; const MED_CONST = 21428571428.571; const MED_MULTIPLIER = 1.0714285714286; @@ -62,35 +64,65 @@ const getGasBasedOnType = ( const getMinPriorityFee = (): BN => { return toBN(toWei("1.25", "gwei")); }; +const getFeeAvg = (arr: BN[]): BN => { + const sum = arr.reduce((a, v) => a.add(v)); + return sum.divn(arr.length); +}; const getPriorityFeeBasedOnType = ( - baseFeePerGas: string, - gasPrice: string, + gasFeeHistory: FormattedFeeHistory, gasPriceType: GasPriceTypes ): BN => { - const priorityFee = toBN(gasPrice).sub(toBN(baseFeePerGas)); - const minFee = getMinPriorityFee(); - const mediumTip = priorityFee; - let returnVal; + if (gasFeeHistory.blocks.length === 0) return getMinPriorityFee(); switch (gasPriceType) { case GasPriceTypes.ECONOMY: - returnVal = mediumTip.muln(0.8); - break; + return getFeeAvg(gasFeeHistory.blocks.map((b) => b.priorityFeePerGas[0])); case GasPriceTypes.REGULAR: - returnVal = mediumTip; - break; + return getFeeAvg(gasFeeHistory.blocks.map((b) => b.priorityFeePerGas[1])); case GasPriceTypes.FAST: - returnVal = mediumTip.muln(1.25); - break; + return getFeeAvg(gasFeeHistory.blocks.map((b) => b.priorityFeePerGas[2])); case GasPriceTypes.FASTEST: - returnVal = mediumTip.muln(1.5); - break; + return getFeeAvg(gasFeeHistory.blocks.map((b) => b.priorityFeePerGas[3])); default: - returnVal = minFee; + return getMinPriorityFee(); + } +}; + +const formatFeeHistory = ( + feeHistory: FeeHistoryResult +): FormattedFeeHistory => { + const historicalBlocks = feeHistory.baseFeePerGas.length - 1; + let blockNum = toBN(feeHistory.oldestBlock).toNumber(); + let index = 0; + let blocks = []; + let highestBaseFee = toBN(0); + while (blockNum < Number(feeHistory.oldestBlock) + historicalBlocks) { + const blockBaseFee = toBN(feeHistory.baseFeePerGas[index]); + if (blockBaseFee.gt(highestBaseFee)) highestBaseFee = blockBaseFee; + blocks.push({ + number: blockNum, + baseFeePerGas: blockBaseFee, + gasUsedRatio: feeHistory.gasUsedRatio[index], + priorityFeePerGas: feeHistory.reward[index].map((x) => toBN(x)), + }); + blockNum += 1; + index += 1; } - if (returnVal.lt(minFee)) return minFee; - return returnVal; + blocks = blocks.filter((b) => b.gasUsedRatio !== 0); + const pendingBaseFee = toBN(feeHistory.baseFeePerGas[historicalBlocks]); + if (pendingBaseFee.gt(highestBaseFee)) highestBaseFee = pendingBaseFee; + return { + blocks, + pendingBlock: { + number: "pending", + baseFeePerGas: pendingBaseFee, + gasUsedRatio: 0, + priorityFeePerGas: [], + }, + highestBaseFee, + }; }; + const getBaseFeeBasedOnType = ( baseFee: string, gasPriceType: GasPriceTypes @@ -98,13 +130,13 @@ const getBaseFeeBasedOnType = ( const baseFeeBN = toBN(baseFee); switch (gasPriceType) { case GasPriceTypes.ECONOMY: - return baseFeeBN.muln(1.25); + return baseFeeBN.muln(1.15); case GasPriceTypes.REGULAR: - return baseFeeBN.muln(1.5); + return baseFeeBN.muln(1.25); case GasPriceTypes.FAST: - return baseFeeBN.muln(1.75); + return baseFeeBN.muln(1.35); case GasPriceTypes.FASTEST: - return baseFeeBN.muln(2); + return baseFeeBN.muln(1.45); default: return baseFeeBN; } @@ -113,22 +145,22 @@ const FeeDescriptions = { [GasPriceTypes.ECONOMY]: { title: "Economy", description: "Will likely go through unless activity increases", - eta: "15 mins", + eta: "5 mins", }, [GasPriceTypes.REGULAR]: { title: "Recommended", description: "Will reliably go through in most scenarios", - eta: "5 min", + eta: "2 mins", }, [GasPriceTypes.FAST]: { title: "Higher priority", description: "Will go through even if there is a sudden activity increase", - eta: "2 mins", + eta: "1 mins", }, [GasPriceTypes.FASTEST]: { title: "Highest priority", description: "Will go through, fast, in 99.99% of the cases", - eta: "1 min", + eta: "30 secs", }, }; export { @@ -136,4 +168,5 @@ export { getPriorityFeeBasedOnType, getGasBasedOnType, FeeDescriptions, + formatFeeHistory, }; diff --git a/packages/extension/src/providers/ethereum/libs/transaction/index.ts b/packages/extension/src/providers/ethereum/libs/transaction/index.ts index ea53e8231..70fad7aec 100644 --- a/packages/extension/src/providers/ethereum/libs/transaction/index.ts +++ b/packages/extension/src/providers/ethereum/libs/transaction/index.ts @@ -3,12 +3,14 @@ import { EthereumTransaction, FinalizedFeeMarketEthereumTransaction, FinalizedLegacyEthereumTransaction, + FormattedFeeHistory, GasCosts, TransactionOptions, } from "./types"; import { GasPriceTypes } from "@/providers/common/types"; import { numberToHex, toBN } from "web3-utils"; import { + formatFeeHistory, getBaseFeeBasedOnType, getGasBasedOnType, getPriorityFeeBasedOnType, @@ -18,6 +20,7 @@ import { FeeMarketEIP1559Transaction, Transaction as LegacyTransaction, } from "@ethereumjs/tx"; + class Transaction { tx: EthereumTransaction; web3: Web3Eth; @@ -34,6 +37,26 @@ class Transaction { value: this.tx.value || "0x0", }); } + private getFeeMarketGasInfo = ( + baseFeePerGas: string, + formattedFeeHistory: FormattedFeeHistory, + priceType: GasPriceTypes + ) => { + const adjustedBaseFeePerGas = getBaseFeeBasedOnType( + baseFeePerGas, + priceType + ); + const maxPriorityFeePerGas = getPriorityFeeBasedOnType( + formattedFeeHistory, + priceType + ); + const maxFeePerGas = adjustedBaseFeePerGas.add(maxPriorityFeePerGas); + return { + adjustedBaseFeePerGas, + maxPriorityFeePerGas, + maxFeePerGas, + }; + }; async finalizeTransaction(options: TransactionOptions): Promise<{ transaction: | FinalizedFeeMarketEthereumTransaction @@ -43,19 +66,19 @@ class Transaction { maxPriorityFeePerGas?: string; maxFeePerGas?: string; gasLimit: string; + formattedFeeHistory?: FormattedFeeHistory; }> { const { isFeeMarketNetwork, baseFeePerGas } = await this.web3 - .getBlockNumber() - .then((blockNum) => { - return this.web3.getBlock(blockNum, false).then((block) => { - return { - isFeeMarketNetwork: !!block.baseFeePerGas, - baseFeePerGas: block.baseFeePerGas, - }; - }); + .getBlock("pending", false) + .then((block) => { + return { + isFeeMarketNetwork: !!block.baseFeePerGas, + baseFeePerGas: block.baseFeePerGas?.toString(), + }; }); const gasPrice = await this.web3.getGasPrice(); const nonce = await this.web3.getTransactionCount(this.tx.from, "pending"); + console.log(nonce); if (!isFeeMarketNetwork) { const legacyTx: FinalizedLegacyEthereumTransaction = { to: this.tx.to || undefined, @@ -77,18 +100,17 @@ class Transaction { gasLimit: legacyTx.gasLimit, }; } else { - let maxFeePerGas = getBaseFeeBasedOnType( - baseFeePerGas?.toString() as string, - options.gasPriceType + const feeHistory = await this.web3.getFeeHistory( + 12, + "pending", + [10, 25, 50, 80] ); - const maxPriorityFeePerGas = getPriorityFeeBasedOnType( - baseFeePerGas?.toString() as string, - gasPrice.toString(), + const formattedFeeHistory = formatFeeHistory(feeHistory); + const feeMarket = this.getFeeMarketGasInfo( + baseFeePerGas!, + formattedFeeHistory, options.gasPriceType ); - if (maxPriorityFeePerGas.gt(maxFeePerGas)) { - maxFeePerGas = maxPriorityFeePerGas; - } const feeMarketTx: FinalizedFeeMarketEthereumTransaction = { to: this.tx.to || undefined, chainId: this.tx.chainId, @@ -99,9 +121,9 @@ class Transaction { (numberToHex(await this.estimateGas()) as `0x${string}`), nonce: this.tx.nonce || (numberToHex(nonce) as `0x${string}`), value: this.tx.value || "0x0", - maxFeePerGas: numberToHex(maxFeePerGas) as `0x${string}`, + maxFeePerGas: numberToHex(feeMarket.maxFeePerGas) as `0x${string}`, maxPriorityFeePerGas: numberToHex( - maxPriorityFeePerGas + feeMarket.maxPriorityFeePerGas ) as `0x${string}`, type: "0x02", accessList: this.tx.accessList || [], @@ -110,8 +132,9 @@ class Transaction { transaction: feeMarketTx, gasLimit: feeMarketTx.gasLimit, baseFeePerGas: numberToHex(baseFeePerGas!), - maxFeePerGas: numberToHex(maxFeePerGas), - maxPriorityFeePerGas: numberToHex(maxPriorityFeePerGas), + maxFeePerGas: numberToHex(feeMarket.maxFeePerGas), + maxPriorityFeePerGas: numberToHex(feeMarket.maxPriorityFeePerGas), + formattedFeeHistory, }; } } @@ -148,7 +171,7 @@ class Transaction { return tx.getMessageToSign(true); } async getGasCosts(): Promise { - const { gasLimit, gasPrice, baseFeePerGas } = + const { gasLimit, gasPrice, baseFeePerGas, formattedFeeHistory } = await this.finalizeTransaction({ gasPriceType: GasPriceTypes.ECONOMY, }); @@ -170,24 +193,32 @@ class Transaction { } else { return { [GasPriceTypes.ECONOMY]: numberToHex( - getBaseFeeBasedOnType(baseFeePerGas!, GasPriceTypes.ECONOMY).mul( - toBN(gasLimit) - ) + this.getFeeMarketGasInfo( + baseFeePerGas!, + formattedFeeHistory!, + GasPriceTypes.ECONOMY + ).maxFeePerGas.mul(toBN(gasLimit)) ), [GasPriceTypes.REGULAR]: numberToHex( - getBaseFeeBasedOnType(baseFeePerGas!, GasPriceTypes.REGULAR).mul( - toBN(gasLimit) - ) + this.getFeeMarketGasInfo( + baseFeePerGas!, + formattedFeeHistory!, + GasPriceTypes.REGULAR + ).maxFeePerGas.mul(toBN(gasLimit)) ), [GasPriceTypes.FAST]: numberToHex( - getBaseFeeBasedOnType(baseFeePerGas!, GasPriceTypes.FAST).mul( - toBN(gasLimit) - ) + this.getFeeMarketGasInfo( + baseFeePerGas!, + formattedFeeHistory!, + GasPriceTypes.FAST + ).maxFeePerGas.mul(toBN(gasLimit)) ), [GasPriceTypes.FASTEST]: numberToHex( - getBaseFeeBasedOnType(baseFeePerGas!, GasPriceTypes.FASTEST).mul( - toBN(gasLimit) - ) + this.getFeeMarketGasInfo( + baseFeePerGas!, + formattedFeeHistory!, + GasPriceTypes.FASTEST + ).maxFeePerGas.mul(toBN(gasLimit)) ), }; } diff --git a/packages/extension/src/providers/ethereum/libs/transaction/types.ts b/packages/extension/src/providers/ethereum/libs/transaction/types.ts index 998195c71..2308983b2 100644 --- a/packages/extension/src/providers/ethereum/libs/transaction/types.ts +++ b/packages/extension/src/providers/ethereum/libs/transaction/types.ts @@ -1,9 +1,24 @@ import { GasPriceTypes } from "@/providers/common/types"; +import { BN } from "ethereumjs-util"; export interface AccessList { address: `0x${string}`; storageKeys: `0x${string}`[]; } + +interface FormattedBlockFees { + number: number | string; + baseFeePerGas: BN; + gasUsedRatio: number; + priorityFeePerGas: BN[]; +} + +export interface FormattedFeeHistory { + blocks: FormattedBlockFees[]; + highestBaseFee: BN; + pendingBlock: FormattedBlockFees; +} + export interface EthereumTransaction { from: `0x${string}`; data?: `0x${string}`; diff --git a/packages/extension/src/ui/action/views/transaction-fee/components/transaction-fee-item.vue b/packages/extension/src/ui/action/views/transaction-fee/components/transaction-fee-item.vue index faf9194a3..ce1913f29 100644 --- a/packages/extension/src/ui/action/views/transaction-fee/components/transaction-fee-item.vue +++ b/packages/extension/src/ui/action/views/transaction-fee/components/transaction-fee-item.vue @@ -57,7 +57,7 @@ const diff = computed(() => { const curVal = props.allFees[props.type]; return new BigNumber(curVal.fiatValue) .minus(selectedVal.fiatValue) - .toFixed(2); + .toFixed(4); } else { return "0"; } From 6bfda87f7369f315959debead520baf814d45eee Mon Sep 17 00:00:00 2001 From: kvhnuke <10602065+kvhnuke@users.noreply.github.com> Date: Tue, 14 Mar 2023 18:18:41 -0700 Subject: [PATCH 02/22] devop: add evm network check for existing ones --- .../methods/wallet_addEthereumChain.ts | 19 ++++++++++++++----- .../ethereum/ui/eth-verify-transaction.vue | 7 ++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/extension/src/providers/ethereum/methods/wallet_addEthereumChain.ts b/packages/extension/src/providers/ethereum/methods/wallet_addEthereumChain.ts index 8cd90656f..5e25fb163 100644 --- a/packages/extension/src/providers/ethereum/methods/wallet_addEthereumChain.ts +++ b/packages/extension/src/providers/ethereum/methods/wallet_addEthereumChain.ts @@ -10,8 +10,10 @@ import Web3 from "web3-eth"; import { CustomEvmNetworkOptions } from "../types/custom-evm-network"; import { numberToHex } from "web3-utils"; import { WindowPromise } from "@/libs/window-promise"; +import { getAllNetworks } from "@/libs/utils/networks"; import CustomNetworksState from "@/libs/custom-networks-state"; import NetworksState from "@/libs/networks-state"; +import { EvmNetwork } from "../types/evm-network"; interface AddEthereumChainPayload { chainId: string; @@ -110,8 +112,15 @@ const setExistingCustomNetwork = async ( ): Promise => { const customNetworksState = new CustomNetworksState(); const customNetworks = await customNetworksState.getAllCustomEVMNetworks(); - const existingNetwork: CustomEvmNetworkOptions | undefined = + + let existingNetwork: CustomEvmNetworkOptions | undefined = customNetworks.find((net) => net.chainID === chainId); + if (!existingNetwork) { + const allNetworks = await getAllNetworks(); + existingNetwork = allNetworks.find( + (net) => (net as EvmNetwork).chainID === chainId + ) as EvmNetwork | undefined; + } if (existingNetwork) { return sendToBackgroundFromBackground({ message: JSON.stringify({ @@ -123,16 +132,16 @@ const setExistingCustomNetwork = async ( }).then(() => { const domainState = new DomainState(); const networksState = new NetworksState(); - networksState.setNetworkStatus(existingNetwork.name, true); + networksState.setNetworkStatus(existingNetwork!.name, true); return domainState.getSelectedNetWork().then(async (curNetwork) => { - if (curNetwork !== existingNetwork.name) { + if (curNetwork !== existingNetwork!.name) { await sendToBackgroundFromBackground({ message: JSON.stringify({ method: InternalMethods.sendToTab, params: [ { method: MessageMethod.changeChainId, - params: [existingNetwork.chainID], + params: [existingNetwork!.chainID], }, ], }), @@ -140,7 +149,7 @@ const setExistingCustomNetwork = async ( tabId, }); await domainState - .setSelectedNetwork(existingNetwork.name) + .setSelectedNetwork(existingNetwork!.name) .then(() => res(null, null)); } return true; diff --git a/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue b/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue index e5f536631..3d5d8349c 100644 --- a/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue +++ b/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue @@ -148,7 +148,7 @@ import BigNumber from "bignumber.js"; import { GasFeeType, GasPriceTypes } from "@/providers/common/types"; import MarketData from "@/libs/market-data"; import { defaultGasCostVals } from "@/providers/common/libs/default-vals"; -import { EnkryptAccount, NetworkNames } from "@enkryptcom/types"; +import { EnkryptAccount } from "@enkryptcom/types"; import { TransactionSigner } from "./libs/signer"; import { Activity, ActivityStatus, ActivityType } from "@/types/activity"; import { generateAddress } from "ethereumjs-util"; @@ -274,10 +274,7 @@ onBeforeMount(async () => { fiatSymbol: "USD", }, }; - selectedFee.value = - network.value.name === NetworkNames.Matic - ? GasPriceTypes.FASTEST - : GasPriceTypes.REGULAR; + selectedFee.value = GasPriceTypes.REGULAR; }); }); From 55937c1b023a2dec5775ecb98766a54f48306895 Mon Sep 17 00:00:00 2001 From: kvhnuke <10602065+kvhnuke@users.noreply.github.com> Date: Wed, 15 Mar 2023 13:17:05 -0700 Subject: [PATCH 03/22] devop: cleanup activity handler --- .../src/libs/activity-state/index.ts | 29 +++++++++++- .../activity-state/wrap-activity-handler.ts | 2 +- .../extension/src/libs/cache-fetch/index.ts | 14 +++--- .../providers/bitcoin/libs/message-router.ts | 1 - .../providers/etherscan/index.ts | 1 + .../providers/rivet/index.ts | 1 + .../libs/assets-handlers/assetinfo-mew.ts | 1 - .../ethereum/libs/transaction/index.ts | 1 - .../ethereum/ui/eth-verify-transaction.vue | 21 ++++++--- .../verify-transaction/index.vue | 45 +++++++++++-------- .../swap/types/ChangellySwapProvider.ts | 6 ++- .../providers/swap/types/EvmSwapProvider.ts | 8 ++-- packages/extension/src/types/activity.ts | 1 + 13 files changed, 93 insertions(+), 38 deletions(-) diff --git a/packages/extension/src/libs/activity-state/index.ts b/packages/extension/src/libs/activity-state/index.ts index eeea954ce..d15636e80 100644 --- a/packages/extension/src/libs/activity-state/index.ts +++ b/packages/extension/src/libs/activity-state/index.ts @@ -1,8 +1,9 @@ import { InternalStorageNamespace } from "@/types/provider"; import BrowserStorage from "@/libs/common/browser-storage"; import { ActivityOptions } from "./types"; -import { Activity } from "@/types/activity"; +import { Activity, ActivityStatus } from "@/types/activity"; const STORAGE_KEY = "activity"; +const MAX_PENDING_TIME = 12 * 60 * 60 * 1000; // 12 hours class ActivityState { #storage: BrowserStorage; constructor() { @@ -21,8 +22,32 @@ class ActivityState { const activities = await this.getActivitiesById( this.getActivityId(options) ); + const combined = activity.concat(activities); + combined.sort((a, b) => { + return b.timestamp - a.timestamp; + }); + const existingHashes: string[] = []; + const cleanArr: Activity[] = []; + const currentTime = new Date().getTime(); + const minedNonces = cleanArr + .filter((item) => item.status === ActivityStatus.success && item.nonce) + .map((item) => item.nonce); + for (let i = 0; i < combined.length; i++) { + if ( + !existingHashes.includes(combined[i].transactionHash) && + combined[i].timestamp > currentTime - MAX_PENDING_TIME + ) { + if ( + combined[i].status !== ActivityStatus.pending || + !combined[i].nonce || + !minedNonces.includes(combined[i].nonce) + ) + cleanArr.push(combined[i]); + } + existingHashes.push(combined[i].transactionHash); + } await this.setActivitiesById( - activity.concat(activities), + cleanArr.slice(0, 50), this.getActivityId(options) ); } diff --git a/packages/extension/src/libs/activity-state/wrap-activity-handler.ts b/packages/extension/src/libs/activity-state/wrap-activity-handler.ts index 6294f3f1b..3584fc2dc 100644 --- a/packages/extension/src/libs/activity-state/wrap-activity-handler.ts +++ b/packages/extension/src/libs/activity-state/wrap-activity-handler.ts @@ -32,7 +32,7 @@ export default (activityHandler: ActivityHandlerType): ActivityHandlerType => { const newSet = stillPendingActivities.concat(liveActivities); await activityState.addActivities(newSet, options); await activityState.setCacheTime(options); - return newSet; + return activityState.getAllActivities(options); } } else { return activities; diff --git a/packages/extension/src/libs/cache-fetch/index.ts b/packages/extension/src/libs/cache-fetch/index.ts index 03416bdd8..39eb517ac 100644 --- a/packages/extension/src/libs/cache-fetch/index.ts +++ b/packages/extension/src/libs/cache-fetch/index.ts @@ -27,11 +27,15 @@ const cacheFetch = async ( return fetch(options.url) .then((res) => res.json()) .then((json) => { - const store: StoredData = { - timestamp: new Date().getTime(), - data: JSON.stringify(json), - }; - return storage.set(hash, store).then(() => json); + const jsonstring = JSON.stringify(json); + if (!jsonstring.includes("error")) { + const store: StoredData = { + timestamp: new Date().getTime(), + data: jsonstring, + }; + return storage.set(hash, store).then(() => json); + } + return json; }); } }; diff --git a/packages/extension/src/providers/bitcoin/libs/message-router.ts b/packages/extension/src/providers/bitcoin/libs/message-router.ts index b55b5eec0..58be3c4d6 100644 --- a/packages/extension/src/providers/bitcoin/libs/message-router.ts +++ b/packages/extension/src/providers/bitcoin/libs/message-router.ts @@ -11,7 +11,6 @@ const handleIncomingMessage: handleIncomingMessageType = ( provider, message ): void => { - console.log(provider, message); try { const _provider = provider as BitcoinProvider; const jsonMsg = JSON.parse(message) as ProviderMessage; diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts index 8a2c6c8f4..d5ec170c9 100644 --- a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts @@ -71,6 +71,7 @@ export default async ( value: txData.tokenValue, transactionHash: activity.transactionHash, type: ActivityType.transaction, + nonce: activity.nonce, token: { decimals: txData.tokenDecimals, icon: txData.tokenImage, diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/rivet/index.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/rivet/index.ts index 05d0e4613..812489b01 100644 --- a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/rivet/index.ts +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/rivet/index.ts @@ -84,6 +84,7 @@ export default async ( value: txData.tokenValue, transactionHash: activity.transactionHash, type: ActivityType.transaction, + nonce: activity.nonce, token: { decimals: txData.tokenDecimals, icon: txData.tokenImage, diff --git a/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts b/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts index 559f58a03..0a8e9f861 100644 --- a/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts +++ b/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts @@ -118,7 +118,6 @@ const getTokens = ( balance: "0x0", }); } - console.log(retVal); return retVal; } }); diff --git a/packages/extension/src/providers/ethereum/libs/transaction/index.ts b/packages/extension/src/providers/ethereum/libs/transaction/index.ts index 70fad7aec..d160707b2 100644 --- a/packages/extension/src/providers/ethereum/libs/transaction/index.ts +++ b/packages/extension/src/providers/ethereum/libs/transaction/index.ts @@ -78,7 +78,6 @@ class Transaction { }); const gasPrice = await this.web3.getGasPrice(); const nonce = await this.web3.getTransactionCount(this.tx.from, "pending"); - console.log(nonce); if (!isFeeMarketNetwork) { const legacyTx: FinalizedLegacyEthereumTransaction = { to: this.tx.to || undefined, diff --git a/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue b/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue index 3d5d8349c..6c83956cc 100644 --- a/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue +++ b/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue @@ -153,7 +153,7 @@ import { TransactionSigner } from "./libs/signer"; import { Activity, ActivityStatus, ActivityType } from "@/types/activity"; import { generateAddress } from "ethereumjs-util"; import ActivityState from "@/libs/activity-state"; -import { bigIntToBuffer } from "@enkryptcom/utils"; +import { bigIntToBuffer, bigIntToHex } from "@enkryptcom/utils"; import broadcastTx from "../libs/tx-broadcaster"; import TokenSigs from "../libs/transaction/lists/tokenSigs"; import AlertIcon from "@action/icons/send/alert-icon.vue"; @@ -319,10 +319,21 @@ const approve = async () => { }; const onHash = (hash: string) => { activityState - .addActivities([{ ...txActivity, ...{ transactionHash: hash } }], { - address: txActivity.from, - network: network.value.name, - }) + .addActivities( + [ + { + ...txActivity, + ...{ + transactionHash: hash, + nonce: bigIntToHex(finalizedTx.nonce), + }, + }, + ], + { + address: txActivity.from, + network: network.value.name, + } + ) .then(() => { Resolve.value({ result: JSON.stringify(hash), diff --git a/packages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vue b/packages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vue index 697021c11..06d6f088a 100644 --- a/packages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vue +++ b/packages/extension/src/providers/ethereum/ui/send-transaction/verify-transaction/index.vue @@ -97,6 +97,7 @@ import { EnkryptAccount } from "@enkryptcom/types"; import CustomScrollbar from "@action/components/custom-scrollbar/index.vue"; import broadcastTx from "@/providers/ethereum/libs/tx-broadcaster"; import { BaseNetwork } from "@/types/base-network"; +import { bigIntToHex } from "@ethereumjs/util"; const KeyRing = new PublicKeyRing(); const route = useRoute(); @@ -152,27 +153,35 @@ const sendAction = async () => { transactionHash: "", }; const activityState = new ActivityState(); - const onHash = (hash: string) => { - activityState.addActivities( - [{ ...txActivity, ...{ transactionHash: hash } }], - { address: txData.fromAddress, network: network.value.name } - ); - isSendDone.value = true; - if (getCurrentContext() === "popup") { - setTimeout(() => { - isProcessing.value = false; - router.go(-2); - }, 4500); - } else { - setTimeout(() => { - isProcessing.value = false; - window.close(); - }, 1500); - } - }; await tx .getFinalizedTransaction({ gasPriceType: txData.gasPriceType }) .then(async (finalizedTx) => { + const onHash = (hash: string) => { + activityState.addActivities( + [ + { + ...txActivity, + ...{ + transactionHash: hash, + nonce: bigIntToHex(finalizedTx.nonce), + }, + }, + ], + { address: txData.fromAddress, network: network.value.name } + ); + isSendDone.value = true; + if (getCurrentContext() === "popup") { + setTimeout(() => { + isProcessing.value = false; + router.go(-2); + }, 4500); + } else { + setTimeout(() => { + isProcessing.value = false; + window.close(); + }, 1500); + } + }; TransactionSigner({ account: account.value!, network: network.value, diff --git a/packages/extension/src/providers/swap/types/ChangellySwapProvider.ts b/packages/extension/src/providers/swap/types/ChangellySwapProvider.ts index 53f99f618..51906812a 100644 --- a/packages/extension/src/providers/swap/types/ChangellySwapProvider.ts +++ b/packages/extension/src/providers/swap/types/ChangellySwapProvider.ts @@ -33,6 +33,7 @@ import { Activity, ActivityStatus, ActivityType } from "@/types/activity"; import { ChangellyToken, ChangellyTokenOptions } from "./changelly-token"; import BigNumber from "bignumber.js"; import broadcastTx from "@/providers/ethereum/libs/tx-broadcaster"; +import { bigIntToHex } from "@enkryptcom/utils"; const CHANGELLY_TOKEN_INFO = [ { @@ -750,7 +751,10 @@ export class ChangellySwapProvider extends SwapProvider { [ { ...JSON.parse(JSON.stringify(txActivity)), - ...{ transactionHash: hash }, + ...{ + transactionHash: hash, + nonce: bigIntToHex(finalizedTx.nonce), + }, }, ], { address: fromAccount.address, network: network.name } diff --git a/packages/extension/src/providers/swap/types/EvmSwapProvider.ts b/packages/extension/src/providers/swap/types/EvmSwapProvider.ts index 3078ea502..de518582b 100644 --- a/packages/extension/src/providers/swap/types/EvmSwapProvider.ts +++ b/packages/extension/src/providers/swap/types/EvmSwapProvider.ts @@ -26,6 +26,7 @@ import { TradeStatus, TransactionInfo, } from "./SwapProvider"; +import { bigIntToHex } from "@enkryptcom/utils"; const HOST_URL = "https://mainnet.mewwallet.dev/v4"; const REQUEST_CACHER = "https://requestcache.mewapi.io/?url="; @@ -296,8 +297,6 @@ export class EvmSwapProvider extends SwapProvider { controller.abort(); console.error("Request timedout"); }, REQUEST_TIMEOUT); - - console.log(`${HOST_URL}${GET_TRADE}?${params.toString()}`); const res = await fetch(`${HOST_URL}${GET_TRADE}?${params.toString()}`, { signal: controller.signal, }); @@ -420,7 +419,10 @@ export class EvmSwapProvider extends SwapProvider { [ { ...JSON.parse(JSON.stringify(activity)), - ...{ transactionHash: hash }, + ...{ + transactionHash: hash, + nonce: bigIntToHex(finalizedTx.nonce), + }, }, ], { address: fromAccount.address, network: network.name } diff --git a/packages/extension/src/types/activity.ts b/packages/extension/src/types/activity.ts index 8d7bf9edc..cc41e2114 100644 --- a/packages/extension/src/types/activity.ts +++ b/packages/extension/src/types/activity.ts @@ -73,6 +73,7 @@ interface Activity { to: string; value: string; timestamp: number; + nonce?: string; isIncoming: boolean; transactionHash: string; token: BaseTokenOptions; From 7493ea345080251b26ccbac8bc5aafc1a3af43c6 Mon Sep 17 00:00:00 2001 From: kvhnuke <10602065+kvhnuke@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:16:00 -0700 Subject: [PATCH 04/22] devop: improved sparkline --- packages/extension/package.json | 2 + .../extension/src/libs/sparkline/index.ts | 187 +----------------- .../bitcoin/types/bitcoin-network.ts | 2 +- .../libs/assets-handlers/assetinfo-mew.ts | 2 +- .../ethereum/networks/skale/skale-base.ts | 2 +- .../providers/ethereum/types/evm-network.ts | 4 +- .../polkadot/types/substrate-network.ts | 2 +- .../action/views/asset-detail-view/index.vue | 64 +++++- .../components/custom-evm-token.vue | 2 +- .../components/network-assets-item.vue | 57 +++++- 10 files changed, 120 insertions(+), 204 deletions(-) diff --git a/packages/extension/package.json b/packages/extension/package.json index 827498095..b600c9975 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -45,6 +45,7 @@ "chai": "^4.3.7", "concurrently": "^7.6.0", "core-js": "^3.27.2", + "echarts": "^5.4.1", "ethereumjs-abi": "^0.6.8", "ethereumjs-util": "^7.1.5", "ethereumjs-wallet": "^1.0.2", @@ -59,6 +60,7 @@ "url-parse": "^1.5.10", "uuid": "^9.0.0", "vue": "^3.2.47", + "vue-echarts": "^6.5.4", "vue-router": "4.1.6", "vue3-lottie": "^2.4.0", "vuedraggable": "^4.1.0", diff --git a/packages/extension/src/libs/sparkline/index.ts b/packages/extension/src/libs/sparkline/index.ts index eb7e7c0fe..efc8b484e 100644 --- a/packages/extension/src/libs/sparkline/index.ts +++ b/packages/extension/src/libs/sparkline/index.ts @@ -1,64 +1,11 @@ -import memoizeOne from "memoize-one"; - -type DGetter = ( - values: number[], - viewBoxWidth: number, - viewBoxHeight: number, - decimals: number -) => string; - -const round = (n: number, decimals: number): number => { - const power: number = 10 ** decimals; - return Math.round(n * power) / power; -}; const normalize = (val: number, max: number, min: number): number => { return (val - min) / (max - min); }; -const getD: DGetter = ( - values: number[], - viewBoxWidth: number, - viewBoxHeight: number, - decimals: number -): string => { - const l: string[] = []; - const maxX: number = values.length - 1; - const maxY: number = Math.max(...values); - for (let i = 0; i <= maxX; i++) { - l.push( - round((i / maxX) * viewBoxWidth, decimals) + - "," + - round(viewBoxHeight - (values[i] / maxY) * viewBoxHeight, decimals) - ); - } - return `M ${l.join(" L ")}`; -}; export default class Sparkline { - private _decimals: number; - private _desc: string; - private _fill: string; - private _getD: DGetter; - private _height: string; - private _preserveAspectRatio: string; - private _stroke: string; - private _strokeWidth: number | string; - private _title: string; private _values: number[]; - private _viewBoxHeight: number; - private _viewBoxWidth: number; - private _width: string; public constructor(values: number[] = [], maxValues: number) { - this._decimals = 10; - this._desc = "A line graph representation of a value's change over time."; - this._fill = "transparent"; - this._getD = memoizeOne(getD); - this._height = "100%"; - this._preserveAspectRatio = "none"; - this._stroke = "currentColor"; - this._strokeWidth = "1.5%"; - this._title = "Sparkline"; - this._width = "100%"; this._values = values.filter( (val, idx) => idx % parseInt((values.length / maxValues).toString()) === 0 ); @@ -69,139 +16,9 @@ export default class Sparkline { 100 ); }); - this._viewBoxHeight = 100; - this._viewBoxWidth = 100; - } - - public get d(): string { - return this._getD( - this._values, - this._viewBoxWidth, - this._viewBoxHeight, - this._decimals - ); - } - - public get dataUri(): string { - return `data:image/svg+xml;base64,${Buffer.from(this.outerHTML).toString( - "base64" - )}`; - } - - public get outerHTML(): string { - let fillPath = ""; - let strokePath = ""; - - // If values exist, - if (this._values.length !== 0) { - strokePath = ` - - `; - - // If a fill color exists, - if (this._fill !== "transparent") { - const d: string = - `L ${this._viewBoxWidth},${this._viewBoxHeight} ` + - `L 0,${this._viewBoxHeight} Z`; - fillPath = ` - - `; - } - } - - return ` - - ${this._title} - ${this._desc} - ${fillPath} - ${strokePath} - - `; - } - - public setDecimals(decimals: number): this { - this._decimals = decimals; - return this; - } - - public setDesc(desc: string): this { - this._desc = desc; - return this; - } - - public setDescription(desc: string): this { - this._desc = desc; - return this; - } - - public setFill(fill: string): this { - this._fill = fill; - return this; - } - - public setHeight(height: string): this { - this._height = height; - return this; - } - - public setPreserveAspectRatio(preserveAspectRatio: string): this { - this._preserveAspectRatio = preserveAspectRatio; - return this; - } - - public setStroke(stroke: string): this { - this._stroke = stroke; - return this; - } - - public setStrokeWidth(strokeWidth: number | string): this { - this._strokeWidth = strokeWidth; - return this; - } - - public setTitle(title: string): this { - this._title = title; - return this; - } - - public setValues(values: number[]): this { - this._values = values; - return this; - } - - public setViewBoxHeight(viewBoxHeight: number): this { - this._viewBoxHeight = viewBoxHeight; - return this; - } - - public setViewBoxWidth(viewBoxWidth: number): this { - this._viewBoxWidth = viewBoxWidth; - return this; } - public setWidth(width: string): this { - this._width = width; - return this; + public get dataValues(): string { + return JSON.stringify(this._values); } } diff --git a/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts b/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts index 826dc7d24..f6b7a2e3b 100644 --- a/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts +++ b/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts @@ -118,7 +118,7 @@ export class BitcoinNetwork extends BaseNetwork { contract: "", decimals: this.decimals, sparkline: marketData.length - ? new Sparkline(marketData[0]!.sparkline_in_7d.price, 25).dataUri + ? new Sparkline(marketData[0]!.sparkline_in_7d.price, 25).dataValues : "", priceChangePercentage: marketData.length ? marketData[0]!.price_change_percentage_7d_in_currency diff --git a/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts b/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts index 0a8e9f861..e89d93fad 100644 --- a/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts +++ b/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts @@ -228,7 +228,7 @@ export default ( valuef: formatFiatValue(market.current_price.toString()).value, contract: address, decimals: tokenInfo[address].decimals, - sparkline: new Sparkline(market.sparkline_in_7d.price, 25).dataUri, + sparkline: new Sparkline(market.sparkline_in_7d.price, 25).dataValues, priceChangePercentage: market.price_change_percentage_7d_in_currency || 0, }; diff --git a/packages/extension/src/providers/ethereum/networks/skale/skale-base.ts b/packages/extension/src/providers/ethereum/networks/skale/skale-base.ts index 86daf391e..37f344a61 100644 --- a/packages/extension/src/providers/ethereum/networks/skale/skale-base.ts +++ b/packages/extension/src/providers/ethereum/networks/skale/skale-base.ts @@ -161,7 +161,7 @@ async function getPreconfiguredTokens( decimals: assetDecimals, sparkline: nativeAssetMarketData[index] ? new Sparkline(nativeAssetMarketData[index]?.sparkline_in_7d.price, 25) - .dataUri + .dataValues : "", priceChangePercentage: nativeAssetMarketData[index]?.price_change_percentage_7d_in_currency ?? diff --git a/packages/extension/src/providers/ethereum/types/evm-network.ts b/packages/extension/src/providers/ethereum/types/evm-network.ts index bda02e31c..af2177128 100644 --- a/packages/extension/src/providers/ethereum/types/evm-network.ts +++ b/packages/extension/src/providers/ethereum/types/evm-network.ts @@ -156,7 +156,7 @@ export class EvmNetwork extends BaseNetwork { ).value, decimals: this.decimals, sparkline: nativeMarketData - ? new Sparkline(nativeMarketData.sparkline_in_7d.price, 25).dataUri + ? new Sparkline(nativeMarketData.sparkline_in_7d.price, 25).dataValues : "", priceChangePercentage: nativeMarketData?.price_change_percentage_7d_in_currency ?? 0, @@ -275,7 +275,7 @@ export class EvmNetwork extends BaseNetwork { asset.sparkline = new Sparkline( marketInfo.sparkline_in_7d.price, 25 - ).dataUri; + ).dataValues; asset.priceChangePercentage = marketInfo.price_change_percentage_7d_in_currency || 0; } diff --git a/packages/extension/src/providers/polkadot/types/substrate-network.ts b/packages/extension/src/providers/polkadot/types/substrate-network.ts index e37c9d2a8..c80f7d197 100644 --- a/packages/extension/src/providers/polkadot/types/substrate-network.ts +++ b/packages/extension/src/providers/polkadot/types/substrate-network.ts @@ -170,7 +170,7 @@ export class SubstrateNetwork extends BaseNetwork { priceChangePercentage: market[idx]?.price_change_percentage_7d_in_currency || 0, sparkline: market[idx] - ? new Sparkline(market[idx]?.sparkline_in_7d.price, 25).dataUri + ? new Sparkline(market[idx]?.sparkline_in_7d.price, 25).dataValues : "", value: market[idx]?.current_price.toString() || "0", valuef: formatFloatingPointValue( diff --git a/packages/extension/src/ui/action/views/asset-detail-view/index.vue b/packages/extension/src/ui/action/views/asset-detail-view/index.vue index c28602827..6dbd2c5c5 100644 --- a/packages/extension/src/ui/action/views/asset-detail-view/index.vue +++ b/packages/extension/src/ui/action/views/asset-detail-view/index.vue @@ -22,7 +22,7 @@ v-if="token.priceChangePercentage !== 0" class="asset-detail-view__token-sparkline" > - +

${{ token.balanceUSDf }}

- -