From 8fd0bb9d23ac3365e0d1c14ae38fe5578a1d2866 Mon Sep 17 00:00:00 2001 From: Matthew Maxwell Date: Tue, 5 Sep 2023 11:20:22 -0500 Subject: [PATCH 1/6] Add rough gas price polling logic to send flow --- .../send-flow/SendFlowRouterView.svelte | 10 +++++ .../views/SelectRecipientView.svelte | 45 ++++++++++++++----- .../send-flow/views/SelectTokenView.svelte | 19 ++++---- .../actions/canAccountMakeEvmTransaction.ts | 12 ++--- .../getGasFeesForLayer1ToLayer2Transaction.ts | 4 +- ...iceInWei.ts => getGasPriceFromProvider.ts} | 2 +- .../src/lib/core/layer-2/actions/index.ts | 3 +- .../layer-2/actions/pollEvmChainGasPrices.ts | 40 +++++++++++++++++ .../stores/evm-chain-gas-prices.store.ts | 23 ++++++++++ .../src/lib/core/layer-2/stores/index.ts | 1 + .../types/evm-chain-gas-prices.type.ts | 5 +++ .../src/lib/core/layer-2/types/index.ts | 1 + 12 files changed, 136 insertions(+), 29 deletions(-) rename packages/shared/src/lib/core/layer-2/actions/{getGasPriceInWei.ts => getGasPriceFromProvider.ts} (80%) create mode 100644 packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts create mode 100644 packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts create mode 100644 packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts diff --git a/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte b/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte index 583c682f69..ed256f0c0b 100644 --- a/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte +++ b/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte @@ -4,12 +4,22 @@ import { SendFlowRoute } from './send-flow-route.enum' import { sendFlowRoute } from './send-flow.router' import { InputTokenAmountView, SelectRecipientView, SelectTokenView, TransactionSummaryView } from './views' + import { onDestroy } from 'svelte' + import { stopPollingEvmChainGasPrices } from '@core/layer-2/actions' export let onTransactionSummaryMount: (..._: any[]) => Promise = async () => {} $: if (features.analytics.dashboardRoute.wallet.sendFlow.enabled && $sendFlowRoute) { Platform.trackEvent('send-flow-route', { route: $sendFlowRoute }) } + + import { evmChainGasPrices } from 'shared/src/lib/core/layer-2/stores' + /* eslint-disable no-console */ + $: console.log('GAS PRICES UPDATED: ', $evmChainGasPrices) + + onDestroy(() => { + stopPollingEvmChainGasPrices() + }) diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte index a8b5704e01..afbc384d45 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte @@ -3,7 +3,15 @@ import { selectedAccountIndex } from '@core/account/stores' import { ContactManager } from '@core/contact/classes' import { localize } from '@core/i18n' - import { IChain, IIscpChainConfiguration, INetwork, NetworkId, getActiveNetworkId, network } from '@core/network' + import { + IChain, + IIscpChainConfiguration, + INetwork, + NetworkId, + getActiveNetworkId, + network, + isEvmChain, + } from '@core/network' import { visibleActiveAccounts } from '@core/profile/stores' import { SendFlowType, @@ -16,13 +24,17 @@ import { closePopup } from '@desktop/auxiliary/popup' import features from '@features/features' import { INetworkRecipientSelectorOption, NetworkRecipientSelector } from '@ui' - import { onMount } from 'svelte' + import { onDestroy, onMount } from 'svelte' import { sendFlowRouter } from '../send-flow.router' import SendFlowTemplate from './SendFlowTemplate.svelte' import { getTokenStandardFromSendFlowParameters } from '@core/wallet/utils' import { TokenStandard } from '@core/token' - import { canAccountMakeEvmTransaction } from 'shared/src/lib/core/layer-2/actions' - import { handleError } from 'shared/src/lib/core/error/handlers' + import { + canAccountMakeEvmTransaction, + pollEvmChainGasPrices, + stopPollingEvmChainGasPrices, + } from '@core/layer-2/actions' + import { handleError } from '@core/error/handlers' let selector: NetworkRecipientSelector let selectorOptions: INetworkRecipientSelectorOption[] = [] @@ -33,6 +45,8 @@ const assetName = getAssetName() $: selectedRecipient = selectorOptions[selectedIndex]?.selectedRecipient + + let selectedNetworkId: NetworkId $: selectedNetworkId = selectorOptions[selectedIndex]?.networkId function getAssetName(): string | undefined { @@ -158,7 +172,7 @@ } else if (sourceChain) { // if we are on layer 2 networkRecipientOptions = [ - ...(features.wallet.assets.unwrapToken && [getLayer1RecipientOption($network)]), + ...(features.wallet.assets.unwrapToken.enabled && [getLayer1RecipientOption($network)]), getRecipientOptionFromChain(sourceChain, $selectedAccountIndex), ] } @@ -173,15 +187,19 @@ return networkRecipientOptions } - async function onNetworkClick(): Promise { + function startPollingEvmChainGasPrices(): void { + const activeNetworkId = getActiveNetworkId() + const networkIdsToPoll = selectorOptions + .filter((option) => option.networkId !== activeNetworkId) + .map((option) => option.networkId) + pollEvmChainGasPrices(networkIdsToPoll) + } + + function onNetworkClick(): void { try { const originNetworkId = getNetworkIdFromSendFlowParameters($sendFlowParameters) hasNetworkRecipientError = - (await canAccountMakeEvmTransaction( - $selectedAccountIndex, - originNetworkId, - $sendFlowParameters.type - )) ?? false + canAccountMakeEvmTransaction($selectedAccountIndex, originNetworkId, $sendFlowParameters.type) ?? false } catch (err) { handleError(err) } @@ -220,6 +238,11 @@ } onMount(() => { buildNetworkRecipientOptions() + startPollingEvmChainGasPrices() + }) + onDestroy(() => { + const chainsToIgnore = isEvmChain(selectedNetworkId) ? [selectedNetworkId] : [] + stopPollingEvmChainGasPrices(chainsToIgnore) }) diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte index 600dbc0b2c..27c09cdcf1 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte @@ -4,9 +4,9 @@ import { selectedAccountIndex } from '@core/account/stores' import { handleError } from '@core/error/handlers' import { localize } from '@core/i18n' - import { canAccountMakeEvmTransaction } from '@core/layer-2/actions' + import { canAccountMakeEvmTransaction, pollEvmChainGasPrice } from '@core/layer-2/actions' import { marketCoinPrices } from '@core/market/stores' - import { getNetwork } from '@core/network' + import { getNetwork, isEvmChain } from '@core/network' import { AccountTokens, BASE_TOKEN_ID, IToken, ITokenWithBalance, TokenStandard } from '@core/token' import { getAccountTokensForSelectedAccount, getTokenBalance } from '@core/token/actions' import { selectedAccountTokens } from '@core/token/stores' @@ -32,7 +32,11 @@ let tokenList: ITokenWithBalance[] function getTokenList(): ITokenWithBalance[] { const list = [] - for (const tokensPerNetwork of Object.values(accountTokens)) { + for (const [networkId, tokensPerNetwork] of Object.entries(accountTokens)) { + if (isEvmChain(networkId)) { + pollEvmChainGasPrice(networkId) + } + if (tokensPerNetwork?.baseCoin) { list.push(tokensPerNetwork.baseCoin) } @@ -62,15 +66,12 @@ ) } - async function onTokenClick(token: ITokenWithBalance): Promise { + function onTokenClick(token: ITokenWithBalance): void { try { selectedToken = token hasTokenError = - (await canAccountMakeEvmTransaction( - $selectedAccountIndex, - token.networkId, - SendFlowType.BaseCoinTransfer - )) ?? false + canAccountMakeEvmTransaction($selectedAccountIndex, token.networkId, SendFlowType.BaseCoinTransfer) ?? + false } catch (err) { handleError(err) } diff --git a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts index ac9d4dab5f..c315a58602 100644 --- a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts @@ -2,17 +2,16 @@ import { NetworkId } from '@core/network/types' import { isEvmChain } from '@core/network/utils' import { SendFlowType } from '@core/wallet/stores' -import { getLayer2AccountBalanceForToken } from '../stores' -import { getGasPriceInWei } from './getGasPriceInWei' +import { getEvmChainGasPrice, getLayer2AccountBalanceForToken } from '../stores' import { FALLBACK_ESTIMATED_GAS, GAS_LIMIT_MULTIPLIER } from '../constants' import { calculateGasFeeInGlow } from '../helpers' -export async function canAccountMakeEvmTransaction( +export function canAccountMakeEvmTransaction( accountIndex: number, networkId: NetworkId, sendFlowType: SendFlowType -): Promise { +): boolean | undefined { if (!isEvmChain(networkId)) { return undefined } @@ -21,7 +20,10 @@ export async function canAccountMakeEvmTransaction( const gasLimit = Math.floor( FALLBACK_ESTIMATED_GAS[sendFlowType ?? SendFlowType.BaseCoinTransfer] * GAS_LIMIT_MULTIPLIER ) - const gasPrice = await getGasPriceInWei(networkId) + const gasPrice = getEvmChainGasPrice(networkId) + if (gasPrice === undefined) { + return undefined + } const minimumGasFee = calculateGasFeeInGlow(gasLimit, gasPrice) return BigInt(baseTokenAccountBalance) < BigInt(minimumGasFee.toString()) } diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts b/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts index ddae720aad..fc3d681ae6 100644 --- a/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts @@ -3,7 +3,7 @@ import { BigIntLike } from '@ethereumjs/util' import { GAS_LIMIT_MULTIPLIER } from '../constants' import { calculateGasFeeInGlow } from '../helpers' import { estimateGasForLayer1ToLayer2Transaction } from './estimateGasForLayer1ToLayer2Transaction' -import { getGasPriceInWei } from './getGasPriceInWei' +import { getGasPriceFromProvider } from './getGasPriceFromProvider' export async function getGasFeesForLayer1ToLayer2Transaction( sendFlowParameters: SendFlowParameters @@ -12,7 +12,7 @@ export async function getGasFeesForLayer1ToLayer2Transaction( if (sendFlowParameters.destinationNetworkId) { const estimatedGas = await estimateGasForLayer1ToLayer2Transaction(sendFlowParameters) const gasLimit = Math.floor(estimatedGas * GAS_LIMIT_MULTIPLIER) - const gasPrice = await getGasPriceInWei(sendFlowParameters.destinationNetworkId) + const gasPrice = await getGasPriceFromProvider(sendFlowParameters.destinationNetworkId) const estimatedGasFee = calculateGasFeeInGlow(estimatedGas, gasPrice) const maxGasFee = calculateGasFeeInGlow(gasLimit, gasPrice) return { estimatedGasFee, maxGasFee } diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasPriceInWei.ts b/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts similarity index 80% rename from packages/shared/src/lib/core/layer-2/actions/getGasPriceInWei.ts rename to packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts index 2500a5f3ab..9a2835671f 100644 --- a/packages/shared/src/lib/core/layer-2/actions/getGasPriceInWei.ts +++ b/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts @@ -2,7 +2,7 @@ import { NetworkId } from '@core/network/types' import { getNetwork } from '@core/network/stores' import { Converter } from '@core/utils' -export async function getGasPriceInWei(networkId: NetworkId): Promise { +export async function getGasPriceFromProvider(networkId: NetworkId): Promise { const chain = getNetwork()?.getChain(networkId) const provider = chain?.getProvider() diff --git a/packages/shared/src/lib/core/layer-2/actions/index.ts b/packages/shared/src/lib/core/layer-2/actions/index.ts index 231a398e07..7a2ce1e085 100644 --- a/packages/shared/src/lib/core/layer-2/actions/index.ts +++ b/packages/shared/src/lib/core/layer-2/actions/index.ts @@ -5,11 +5,12 @@ export * from './canAccountMakeEvmTransaction' export * from './estimateGasForLayer1ToLayer2Transaction' export * from './fetchSelectedAccountLayer2Balance' export * from './generateAndStoreEvmAddressForAccount' +export * from './getGasPriceFromProvider' export * from './getNetworkIdFromAddress' export * from './getGasFeesForLayer1ToLayer2Transaction' -export * from './getGasPriceInWei' export * from './getIscpTransferSmartContractData' export * from './getLayer2MetadataForTransfer' export * from './getLayer2NetworkFromAddress' +export * from './pollEvmChainGasPrices' export * from './pollLayer2Tokens' export * from './signEvmTransactionWithStronghold' diff --git a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts new file mode 100644 index 0000000000..57081ebc1e --- /dev/null +++ b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts @@ -0,0 +1,40 @@ +import { EvmChainId } from '@core/network/enums' +import { NetworkId } from '@core/network/types' +import { getGasPriceFromProvider } from '../actions' +import { setEvmChainGasPrice } from '../stores' + +const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 30_000 + +const pollIntervalMap: { [key in EvmChainId]?: number } = {} + +export function pollEvmChainGasPrices(chainIds: NetworkId[]): void { + stopPollingEvmChainGasPrices() + for (const chainId of chainIds) { + pollEvmChainGasPrice(chainId) + } +} + +export function pollEvmChainGasPrice(chainId: NetworkId): void { + if (!chainId || typeof pollIntervalMap[chainId] === 'number') { + return + } + void updateEvmChainGasPrice(chainId) + pollIntervalMap[chainId] = window.setInterval(() => { + void updateEvmChainGasPrice(chainId) + }, EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL) +} + +export async function updateEvmChainGasPrice(chainId: NetworkId): Promise { + const gasPrice = await getGasPriceFromProvider(chainId) + if (gasPrice) { + setEvmChainGasPrice(BigInt(gasPrice), chainId) + } +} + +export function stopPollingEvmChainGasPrices(chainIdsToIgnore?: NetworkId[]): void { + for (const chainId of Object.keys(pollIntervalMap)) { + if (!chainIdsToIgnore?.includes(chainId as NetworkId)) { + clearInterval(pollIntervalMap[chainId]) + } + } +} diff --git a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts b/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts new file mode 100644 index 0000000000..7556e28e58 --- /dev/null +++ b/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts @@ -0,0 +1,23 @@ +import { get, writable } from 'svelte/store' +import { NetworkId } from '@core/network/types' +import { isEvmChain } from '@core/network/utils' +import { EvmChainGasPrices } from '../types' + +export const evmChainGasPrices = writable({}) + +export function getEvmChainGasPrice(networkId: NetworkId): bigint | undefined { + return get(evmChainGasPrices)[networkId] +} + +export function setEvmChainGasPrice(price: bigint, networkId: NetworkId): void { + evmChainGasPrices.update((_evmChainGasPrices) => { + if (typeof price === 'bigint' && isEvmChain(networkId)) { + return { + ..._evmChainGasPrices, + [networkId]: price, + } + } else { + return _evmChainGasPrices + } + }) +} diff --git a/packages/shared/src/lib/core/layer-2/stores/index.ts b/packages/shared/src/lib/core/layer-2/stores/index.ts index 7c15aa4d3f..2c59ed1ce6 100644 --- a/packages/shared/src/lib/core/layer-2/stores/index.ts +++ b/packages/shared/src/lib/core/layer-2/stores/index.ts @@ -1 +1,2 @@ +export * from './evm-chain-gas-prices.store' export * from './layer2-balances.store' diff --git a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts b/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts new file mode 100644 index 0000000000..1394f84c9c --- /dev/null +++ b/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts @@ -0,0 +1,5 @@ +import { EvmChainId } from '@core/network' + +export type EvmChainGasPrices = { + [key in EvmChainId]?: bigint +} diff --git a/packages/shared/src/lib/core/layer-2/types/index.ts b/packages/shared/src/lib/core/layer-2/types/index.ts index 57eb6baa5a..4a0f1b1fe7 100644 --- a/packages/shared/src/lib/core/layer-2/types/index.ts +++ b/packages/shared/src/lib/core/layer-2/types/index.ts @@ -1,5 +1,6 @@ export * from './abi.type' export * from './contract.type' +export * from './evm-chain-gas-prices.type' export * from './evm-transaction-options.type' export * from './evm-transaction-data.type' export * from './layer2-account-balance.interface' From 8fb9dc5932ae7c33e5f025fe6f166cbc66a08240 Mon Sep 17 00:00:00 2001 From: Matthew Maxwell Date: Tue, 5 Sep 2023 11:28:44 -0500 Subject: [PATCH 2/6] Cleanup logic --- .../src/lib/core/layer-2/actions/index.ts | 1 + .../layer-2/actions/pollEvmChainGasPrices.ts | 21 +++++++------------ .../layer-2/actions/updateEvmChainGasPrice.ts | 15 +++++++++++++ 3 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts diff --git a/packages/shared/src/lib/core/layer-2/actions/index.ts b/packages/shared/src/lib/core/layer-2/actions/index.ts index 7a2ce1e085..53863b368b 100644 --- a/packages/shared/src/lib/core/layer-2/actions/index.ts +++ b/packages/shared/src/lib/core/layer-2/actions/index.ts @@ -14,3 +14,4 @@ export * from './getLayer2NetworkFromAddress' export * from './pollEvmChainGasPrices' export * from './pollLayer2Tokens' export * from './signEvmTransactionWithStronghold' +export * from './updateEvmChainGasPrice' diff --git a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts index 57081ebc1e..51f037a2c5 100644 --- a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts +++ b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts @@ -1,19 +1,12 @@ import { EvmChainId } from '@core/network/enums' import { NetworkId } from '@core/network/types' -import { getGasPriceFromProvider } from '../actions' -import { setEvmChainGasPrice } from '../stores' +import { MILLISECONDS_PER_SECOND } from '@core/utils' +import { updateEvmChainGasPrice } from './updateEvmChainGasPrice' -const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 30_000 +const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 15 * MILLISECONDS_PER_SECOND const pollIntervalMap: { [key in EvmChainId]?: number } = {} -export function pollEvmChainGasPrices(chainIds: NetworkId[]): void { - stopPollingEvmChainGasPrices() - for (const chainId of chainIds) { - pollEvmChainGasPrice(chainId) - } -} - export function pollEvmChainGasPrice(chainId: NetworkId): void { if (!chainId || typeof pollIntervalMap[chainId] === 'number') { return @@ -24,10 +17,10 @@ export function pollEvmChainGasPrice(chainId: NetworkId): void { }, EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL) } -export async function updateEvmChainGasPrice(chainId: NetworkId): Promise { - const gasPrice = await getGasPriceFromProvider(chainId) - if (gasPrice) { - setEvmChainGasPrice(BigInt(gasPrice), chainId) +export function pollEvmChainGasPrices(chainIds: NetworkId[]): void { + stopPollingEvmChainGasPrices() + for (const chainId of chainIds) { + pollEvmChainGasPrice(chainId) } } diff --git a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts new file mode 100644 index 0000000000..05a88ea22b --- /dev/null +++ b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts @@ -0,0 +1,15 @@ +import { handleError } from '@core/error/handlers' +import { NetworkId } from '@core/network/types' +import { setEvmChainGasPrice } from '../stores' +import { getGasPriceFromProvider } from './getGasPriceFromProvider' + +export async function updateEvmChainGasPrice(chainId: NetworkId): Promise { + try { + const gasPrice = await getGasPriceFromProvider(chainId) + if (gasPrice) { + setEvmChainGasPrice(BigInt(gasPrice), chainId) + } + } catch (err) { + handleError(err) + } +} From ed3c7fd73196187d4cd298559b809858f5349b6e Mon Sep 17 00:00:00 2001 From: Matthew Maxwell Date: Tue, 5 Sep 2023 11:56:38 -0500 Subject: [PATCH 3/6] Fix reactivity around gas prices --- .../views/SelectRecipientView.svelte | 31 +++++++++---------- .../send-flow/views/SelectTokenView.svelte | 13 ++++++-- .../molecules/NetworkRecipientSelector.svelte | 5 +-- .../actions/canAccountMakeEvmTransaction.ts | 2 +- .../getGasFeesForLayer1ToLayer2Transaction.ts | 6 ++-- .../core/network/utils/getSplitNetworkId.ts | 2 +- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte index afbc384d45..fdc9e67f05 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte @@ -34,20 +34,30 @@ pollEvmChainGasPrices, stopPollingEvmChainGasPrices, } from '@core/layer-2/actions' - import { handleError } from '@core/error/handlers' let selector: NetworkRecipientSelector let selectorOptions: INetworkRecipientSelectorOption[] = [] let selectedIndex = -1 - let hasNetworkRecipientError: boolean = false - const assetName = getAssetName() - $: selectedRecipient = selectorOptions[selectedIndex]?.selectedRecipient - let selectedNetworkId: NetworkId $: selectedNetworkId = selectorOptions[selectedIndex]?.networkId + $: selectedRecipient = selectorOptions[selectedIndex]?.selectedRecipient + + let hasNetworkRecipientError: boolean = false + $: { + const originNetworkId = getNetworkIdFromSendFlowParameters($sendFlowParameters) + if (isEvmChain(originNetworkId)) { + hasNetworkRecipientError = !canAccountMakeEvmTransaction( + $selectedAccountIndex, + originNetworkId, + $sendFlowParameters?.type + ) + } else { + hasNetworkRecipientError = false + } + } function getAssetName(): string | undefined { if ($sendFlowParameters?.type === SendFlowType.BaseCoinTransfer) { @@ -195,16 +205,6 @@ pollEvmChainGasPrices(networkIdsToPoll) } - function onNetworkClick(): void { - try { - const originNetworkId = getNetworkIdFromSendFlowParameters($sendFlowParameters) - hasNetworkRecipientError = - canAccountMakeEvmTransaction($selectedAccountIndex, originNetworkId, $sendFlowParameters.type) ?? false - } catch (err) { - handleError(err) - } - } - function onContinueClick(): void { if (validate()) { updateSendFlowParameters({ @@ -261,7 +261,6 @@ }} > import { NetworkRecipientItem } from '@ui' import { INetworkRecipientSelectorOption } from '../interfaces' - import { UiEventFunction } from '../../lib/core/utils' export let options: INetworkRecipientSelectorOption[] export let selectedIndex = -1 - export let onNetworkSelected: UiEventFunction export let hasError: boolean = false const reipientItems: Record = {} @@ -14,9 +12,8 @@ reipientItems[selectedIndex]?.validate() } - function onItemClick(index: number) { + function onItemClick(index: number): void { selectedIndex = index - onNetworkSelected && onNetworkSelected() } diff --git a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts index c315a58602..8e10a077c7 100644 --- a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts @@ -25,5 +25,5 @@ export function canAccountMakeEvmTransaction( return undefined } const minimumGasFee = calculateGasFeeInGlow(gasLimit, gasPrice) - return BigInt(baseTokenAccountBalance) < BigInt(minimumGasFee.toString()) + return BigInt(baseTokenAccountBalance) > BigInt(minimumGasFee.toString()) } diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts b/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts index fc3d681ae6..db92552b69 100644 --- a/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/getGasFeesForLayer1ToLayer2Transaction.ts @@ -1,9 +1,9 @@ -import { SendFlowParameters } from '@core/wallet' import { BigIntLike } from '@ethereumjs/util' +import { SendFlowParameters } from '@core/wallet/types' import { GAS_LIMIT_MULTIPLIER } from '../constants' import { calculateGasFeeInGlow } from '../helpers' +import { getEvmChainGasPrice } from '../stores' import { estimateGasForLayer1ToLayer2Transaction } from './estimateGasForLayer1ToLayer2Transaction' -import { getGasPriceFromProvider } from './getGasPriceFromProvider' export async function getGasFeesForLayer1ToLayer2Transaction( sendFlowParameters: SendFlowParameters @@ -12,7 +12,7 @@ export async function getGasFeesForLayer1ToLayer2Transaction( if (sendFlowParameters.destinationNetworkId) { const estimatedGas = await estimateGasForLayer1ToLayer2Transaction(sendFlowParameters) const gasLimit = Math.floor(estimatedGas * GAS_LIMIT_MULTIPLIER) - const gasPrice = await getGasPriceFromProvider(sendFlowParameters.destinationNetworkId) + const gasPrice = getEvmChainGasPrice(sendFlowParameters.destinationNetworkId) const estimatedGasFee = calculateGasFeeInGlow(estimatedGas, gasPrice) const maxGasFee = calculateGasFeeInGlow(gasLimit, gasPrice) return { estimatedGasFee, maxGasFee } diff --git a/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts b/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts index 6c78ec2ee6..389f46ec27 100644 --- a/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts +++ b/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts @@ -6,7 +6,7 @@ type SpitNetworkId = | { namespace: NetworkNamespace.Evm; chainId: EvmChainId } export function getSplitNetworkId(networkId: NetworkId): SpitNetworkId | undefined { - const parts = networkId.split(':') + const parts = networkId?.split(':') if ((parts?.[0] as NetworkNamespace) === NetworkNamespace.Stardust && parts?.[1]) { return { namespace: NetworkNamespace.Stardust, From e524b320d29497b7102383a053f708852251870f Mon Sep 17 00:00:00 2001 From: Matthew Maxwell Date: Tue, 5 Sep 2023 12:52:43 -0500 Subject: [PATCH 4/6] Remove extra console log --- .../views/dashboard/send-flow/SendFlowRouterView.svelte | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte b/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte index ed256f0c0b..a68b217fdc 100644 --- a/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte +++ b/packages/desktop/views/dashboard/send-flow/SendFlowRouterView.svelte @@ -13,10 +13,6 @@ Platform.trackEvent('send-flow-route', { route: $sendFlowRoute }) } - import { evmChainGasPrices } from 'shared/src/lib/core/layer-2/stores' - /* eslint-disable no-console */ - $: console.log('GAS PRICES UPDATED: ', $evmChainGasPrices) - onDestroy(() => { stopPollingEvmChainGasPrices() }) From 25ab4554c9cc7f2dce2a88858c711822b411c69f Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Wed, 6 Sep 2023 18:13:11 +0100 Subject: [PATCH 5/6] fix: pr review comments Co-authored-by: Matthew Maxwell --- .../send-flow/views/SelectTokenView.svelte | 16 +++++++-- .../actions/getGasPriceFromProvider.ts | 2 +- .../layer-2/actions/pollEvmChainGasPrices.ts | 35 +++++++++++-------- .../layer-2/actions/updateEvmChainGasPrice.ts | 4 +-- .../stores/evm-chain-gas-prices.store.ts | 6 ++-- .../types/evm-chain-gas-prices.type.ts | 4 +-- .../core/network/utils/getSplitNetworkId.ts | 2 +- 7 files changed, 42 insertions(+), 27 deletions(-) diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte index ca31957862..7516474217 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte @@ -6,8 +6,15 @@ import { localize } from '@core/i18n' import { canAccountMakeEvmTransaction, pollEvmChainGasPrice } from '@core/layer-2/actions' import { marketCoinPrices } from '@core/market/stores' - import { getNetwork, isEvmChain } from '@core/network' - import { AccountTokens, BASE_TOKEN_ID, IToken, ITokenWithBalance, TokenStandard } from '@core/token' + import { NetworkId, getNetwork, isEvmChain } from '@core/network' + import { + AccountTokens, + BASE_TOKEN_ID, + IAccountTokensPerNetwork, + IToken, + ITokenWithBalance, + TokenStandard, + } from '@core/token' import { getAccountTokensForSelectedAccount, getTokenBalance } from '@core/token/actions' import { selectedAccountTokens } from '@core/token/stores' import { SendFlowType, sendFlowParameters, setSendFlowParameters } from '@core/wallet' @@ -42,7 +49,10 @@ let tokenList: ITokenWithBalance[] function getTokenList(): ITokenWithBalance[] { const list = [] - for (const [networkId, tokensPerNetwork] of Object.entries(accountTokens)) { + for (const [networkId, tokensPerNetwork] of Object.entries(accountTokens) as [ + NetworkId, + IAccountTokensPerNetwork, + ][]) { if (isEvmChain(networkId)) { pollEvmChainGasPrice(networkId) } diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts b/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts index 9a2835671f..652489bb54 100644 --- a/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts +++ b/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts @@ -2,7 +2,7 @@ import { NetworkId } from '@core/network/types' import { getNetwork } from '@core/network/stores' import { Converter } from '@core/utils' -export async function getGasPriceFromProvider(networkId: NetworkId): Promise { +export async function getGasPriceForNetwork(networkId: NetworkId): Promise { const chain = getNetwork()?.getChain(networkId) const provider = chain?.getProvider() diff --git a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts index 51f037a2c5..c842153e6a 100644 --- a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts +++ b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts @@ -1,33 +1,38 @@ -import { EvmChainId } from '@core/network/enums' import { NetworkId } from '@core/network/types' import { MILLISECONDS_PER_SECOND } from '@core/utils' import { updateEvmChainGasPrice } from './updateEvmChainGasPrice' -const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 15 * MILLISECONDS_PER_SECOND +const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 60 * MILLISECONDS_PER_SECOND -const pollIntervalMap: { [key in EvmChainId]?: number } = {} +const pollIntervalMap: { [id in NetworkId]?: number } = {} -export function pollEvmChainGasPrice(chainId: NetworkId): void { - if (!chainId || typeof pollIntervalMap[chainId] === 'number') { +export function pollEvmChainGasPrice(networkId: NetworkId): void { + if (!networkId || isPollingEvmChainGasPrice(networkId)) { return } - void updateEvmChainGasPrice(chainId) - pollIntervalMap[chainId] = window.setInterval(() => { - void updateEvmChainGasPrice(chainId) + void updateEvmChainGasPrice(networkId) + pollIntervalMap[networkId] = window.setInterval(() => { + void updateEvmChainGasPrice(networkId) }, EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL) } -export function pollEvmChainGasPrices(chainIds: NetworkId[]): void { +export function pollEvmChainGasPrices(networkIds: NetworkId[]): void { stopPollingEvmChainGasPrices() - for (const chainId of chainIds) { - pollEvmChainGasPrice(chainId) + for (const networkId of networkIds) { + pollEvmChainGasPrice(networkId) } } -export function stopPollingEvmChainGasPrices(chainIdsToIgnore?: NetworkId[]): void { - for (const chainId of Object.keys(pollIntervalMap)) { - if (!chainIdsToIgnore?.includes(chainId as NetworkId)) { - clearInterval(pollIntervalMap[chainId]) +export function stopPollingEvmChainGasPrices(networkIdsToIgnore?: NetworkId[]): void { + for (const networkId of Object.keys(pollIntervalMap) as NetworkId[]) { + if (!networkIdsToIgnore?.includes(networkId)) { + if (isPollingEvmChainGasPrice(networkId)) { + clearInterval(pollIntervalMap[networkId]) + } } } } + +export function isPollingEvmChainGasPrice(networkId: NetworkId): boolean { + return typeof pollIntervalMap[networkId] === 'number' +} diff --git a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts index 05a88ea22b..5743a16728 100644 --- a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts +++ b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts @@ -1,11 +1,11 @@ import { handleError } from '@core/error/handlers' import { NetworkId } from '@core/network/types' import { setEvmChainGasPrice } from '../stores' -import { getGasPriceFromProvider } from './getGasPriceFromProvider' +import { getGasPriceForNetwork } from './getGasPriceFromProvider' export async function updateEvmChainGasPrice(chainId: NetworkId): Promise { try { - const gasPrice = await getGasPriceFromProvider(chainId) + const gasPrice = await getGasPriceForNetwork(chainId) if (gasPrice) { setEvmChainGasPrice(BigInt(gasPrice), chainId) } diff --git a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts b/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts index 7556e28e58..395fc7563b 100644 --- a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts +++ b/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts @@ -10,14 +10,14 @@ export function getEvmChainGasPrice(networkId: NetworkId): bigint | undefined { } export function setEvmChainGasPrice(price: bigint, networkId: NetworkId): void { - evmChainGasPrices.update((_evmChainGasPrices) => { + evmChainGasPrices.update((state) => { if (typeof price === 'bigint' && isEvmChain(networkId)) { return { - ..._evmChainGasPrices, + ...state, [networkId]: price, } } else { - return _evmChainGasPrices + return state } }) } diff --git a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts b/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts index 1394f84c9c..876a3c8e17 100644 --- a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts +++ b/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts @@ -1,5 +1,5 @@ -import { EvmChainId } from '@core/network' +import { NetworkId } from '@core/network/types' export type EvmChainGasPrices = { - [key in EvmChainId]?: bigint + [id in NetworkId]?: bigint } diff --git a/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts b/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts index 389f46ec27..6c78ec2ee6 100644 --- a/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts +++ b/packages/shared/src/lib/core/network/utils/getSplitNetworkId.ts @@ -6,7 +6,7 @@ type SpitNetworkId = | { namespace: NetworkNamespace.Evm; chainId: EvmChainId } export function getSplitNetworkId(networkId: NetworkId): SpitNetworkId | undefined { - const parts = networkId?.split(':') + const parts = networkId.split(':') if ((parts?.[0] as NetworkNamespace) === NetworkNamespace.Stardust && parts?.[1]) { return { namespace: NetworkNamespace.Stardust, From 28f7452a4f2f8f4362e74478a826eddcea164196 Mon Sep 17 00:00:00 2001 From: Matthew Maxwell Date: Wed, 6 Sep 2023 12:31:17 -0500 Subject: [PATCH 6/6] Fix tests --- ...asPriceFromProvider.ts => getGasPriceForNetwork.ts} | 0 packages/shared/src/lib/core/layer-2/actions/index.ts | 4 ++-- .../lib/core/layer-2/actions/updateEvmChainGasPrice.ts | 2 +- .../lib/core/wallet/tests/getOutputParameters.test.ts | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) rename packages/shared/src/lib/core/layer-2/actions/{getGasPriceFromProvider.ts => getGasPriceForNetwork.ts} (100%) diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts b/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts similarity index 100% rename from packages/shared/src/lib/core/layer-2/actions/getGasPriceFromProvider.ts rename to packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts diff --git a/packages/shared/src/lib/core/layer-2/actions/index.ts b/packages/shared/src/lib/core/layer-2/actions/index.ts index 53863b368b..675d3455ec 100644 --- a/packages/shared/src/lib/core/layer-2/actions/index.ts +++ b/packages/shared/src/lib/core/layer-2/actions/index.ts @@ -5,12 +5,12 @@ export * from './canAccountMakeEvmTransaction' export * from './estimateGasForLayer1ToLayer2Transaction' export * from './fetchSelectedAccountLayer2Balance' export * from './generateAndStoreEvmAddressForAccount' -export * from './getGasPriceFromProvider' -export * from './getNetworkIdFromAddress' export * from './getGasFeesForLayer1ToLayer2Transaction' +export * from './getGasPriceForNetwork' export * from './getIscpTransferSmartContractData' export * from './getLayer2MetadataForTransfer' export * from './getLayer2NetworkFromAddress' +export * from './getNetworkIdFromAddress' export * from './pollEvmChainGasPrices' export * from './pollLayer2Tokens' export * from './signEvmTransactionWithStronghold' diff --git a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts index 5743a16728..2f569aa892 100644 --- a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts +++ b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts @@ -1,7 +1,7 @@ import { handleError } from '@core/error/handlers' import { NetworkId } from '@core/network/types' import { setEvmChainGasPrice } from '../stores' -import { getGasPriceForNetwork } from './getGasPriceFromProvider' +import { getGasPriceForNetwork } from './getGasPriceForNetwork' export async function updateEvmChainGasPrice(chainId: NetworkId): Promise { try { diff --git a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts index 5e9038ec85..e54fde7597 100644 --- a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts +++ b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts @@ -90,8 +90,8 @@ jest.mock('../../network/actions/getChainConfiguration', () => ({ getChainConfiguration: jest.fn((_) => destinationNetwork), })) -jest.mock('../../layer-2/actions/getGasPriceInWei', () => ({ - getGasPriceInWei: jest.fn((_) => 1_000_000_000_000n), +jest.mock('../../layer-2/actions/getGasPriceForNetwork', () => ({ + getGasPriceForNetwork: jest.fn((_) => 1_000_000_000_000n), })) jest.mock('../../layer-2/actions/estimateGasForLayer1ToLayer2Transaction', () => ({ @@ -234,7 +234,7 @@ describe('File: getOutputParameters.ts', () => { const output = await getOutputParameters(sendFlowParameters, senderAddress) const expectedOutput = { recipientAddress: destinationNetwork.aliasAddress, - amount: '1000026620', + amount: '1000000000', features: { metadata: '0x00000000025e4b3ca1e3f423fccf01010161200300010000070c000c30680e00000090000f0ea000060009000d300000000000808094ebdc03', @@ -266,7 +266,7 @@ describe('File: getOutputParameters.ts', () => { const expectedOutput = { recipientAddress: destinationNetwork.aliasAddress, - amount: '26785', + amount: '0', assets: { nativeTokens: [ { @@ -297,7 +297,7 @@ describe('File: getOutputParameters.ts', () => { const expectedOutput = { recipientAddress: destinationNetwork.aliasAddress, - amount: '27170', + amount: '0', assets: { nftId, },