diff --git a/packages/extension/package.json b/packages/extension/package.json index b3af75bf9..e7828c5ed 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,6 +1,6 @@ { "name": "@enkryptcom/extension", - "version": "2.0.2", + "version": "2.1.0", "private": true, "type": "module", "scripts": { diff --git a/packages/extension/src/libs/metrics/index.ts b/packages/extension/src/libs/metrics/index.ts index 5aff53bc3..071bb2305 100644 --- a/packages/extension/src/libs/metrics/index.ts +++ b/packages/extension/src/libs/metrics/index.ts @@ -7,9 +7,12 @@ import { GenericEvents, NFTEventType, NetworkChangeEvents, + NetworkType, SendEventType, SettingEventType, SwapEventType, + UpdatesEventType, + UpdatesOpenLocation } from './types'; const metrics = new Metrics(); @@ -18,9 +21,24 @@ const trackGenericEvents = (event: GenericEvents) => { metrics.track('generic', { event }); }; -const trackNetworkSelected = ( +const trackNetwork = ( event: NetworkChangeEvents, - options: { provider: ProviderName; network: NetworkNames }, + options: { + provider?: ProviderName; + network?: NetworkNames, + networkTab?: string, + networkType?: NetworkType, + isPinned?: boolean, + sortOption?: string, + customRpcUrl?: string, + customNetworkName?: string, + customNetworkNameLong?: string, + customNetworkCurrency?: string, + customNetworkCurrencyLong?: string, + customChainId?: string, + customBlockExplorerUrlTx?: string + customBlockExplorerUrlAddr?: string + }, ) => { metrics.track('network', { event, ...options }); }; @@ -75,6 +93,14 @@ const trackDAppsEvents = ( metrics.track('dapps', { event, ...options }); }; +const trackUpdatesEvents = (event: UpdatesEventType, options: { + network: NetworkNames; + location?: UpdatesOpenLocation; + duration?: number; +}): void => { + metrics.track('updatesClick', { event, ...options }); + +} const optOutofMetrics = (optOut: boolean) => { if (!__IS_FIREFOX__) { metrics.setOptOut(false); @@ -87,7 +113,7 @@ const optOutofMetrics = (optOut: boolean) => { }; export { - trackNetworkSelected, + trackNetwork, trackSwapEvents, trackBuyEvents, trackSendEvents, @@ -95,4 +121,5 @@ export { trackDAppsEvents, optOutofMetrics, trackGenericEvents, + trackUpdatesEvents }; diff --git a/packages/extension/src/libs/metrics/types.ts b/packages/extension/src/libs/metrics/types.ts index 955ee03e3..23f132584 100644 --- a/packages/extension/src/libs/metrics/types.ts +++ b/packages/extension/src/libs/metrics/types.ts @@ -13,9 +13,23 @@ export enum GenericEvents { login_error = 'login_error', } +export enum NetworkType { + Regular = 'regular', + Custom = 'custom', + Testnet = 'testnet', +} + export enum NetworkChangeEvents { NetworkChangePopup = 'network_change_popup', NetworkChangeAPI = 'network_change_api', + NetworkTabsClicked = 'network_tabs_clicked', + NetworkPinnedStatusChanged = 'network_pinned_status_changed', + NetworkActiveChanged = 'network_active_changed', + NetworkSortOptionChanged = 'network_sort_option_changed', + NetworkAddCustomClicked = 'network_add_custom_clicked', + NetworkCustomNetworkAdded = 'network_custom_network_added', + NetworkDeleteCustomNetwork = 'network_delete_custom_network', + NetworkCustomBackButton = 'network_custom_back_button', } export enum BuyEventType { @@ -47,3 +61,13 @@ export enum DAppsEventType { export enum SettingEventType { OptOut = 'opt_out', } + +export enum UpdatesEventType { + UpdatesOpen = 'updates_open', + UpdatesClosed = 'updates_closed', +} + +export enum UpdatesOpenLocation { + settings = 'settings', + logo = "logo", +} diff --git a/packages/extension/src/libs/networks-state/index.ts b/packages/extension/src/libs/networks-state/index.ts index 3a0af4706..59dbf6cad 100644 --- a/packages/extension/src/libs/networks-state/index.ts +++ b/packages/extension/src/libs/networks-state/index.ts @@ -15,9 +15,19 @@ class NetworksState { const networks: NetworkStorageElement[] = POPULAR_NAMES.map(name => ({ name, })); - await this.setState({ networks, newNetworksVersion: '' }); + await this.setState({ + networks, + newNetworksVersion: '', + enabledTestNetworks: [], + newUsedFeatures: { networks: [], swap: [] }, + }); } + /** + * Pins or unpins a network on the UI. + * @param targetNetworkName - the name of the network to set the status of + * @param isActive - represents whether or not the network is pinned on the ui + */ async setNetworkStatus( targetNetworkName: string, isActive: boolean, @@ -43,6 +53,16 @@ class NetworksState { await this.setState(state); } + /** + * Inserts networks with new features. + * + * This method first retrieves the current state and checks if the networks + * have been updated to the latest version. If the state and networks are defined, + * it filters out the networks that are not in the predefined list of networks with new features. + * It then maps the filtered networks to a new network item and inserts them into the valid networks. + * The new networks are inserted at the 6th index, or at the end if there are fewer than 6 networks. + * The state is then updated with the new networks and the latest version. + */ async insertNetworksWithNewFeatures(): Promise { const state: IState | undefined = await this.getState(); if ( @@ -69,11 +89,44 @@ class NetworksState { .concat(fnetworkItem, validNetworks.slice(insertIdx)); state.networks = validNetworks; state.newNetworksVersion = __PACKAGE_VERSION__ as string; + state.newUsedFeatures = { networks: [], swap: [] }; await this.setState(state); } } - async getActiveNetworkNames(): Promise { + async setUsedFeature(feature: 'networks' | 'swap', networkName: string) { + const state: IState | undefined = await this.getState(); + if (state) { + const newUsedFeatures = state.newUsedFeatures || { + networks: [], + swap: [], + }; + newUsedFeatures[feature].push(networkName); + await this.setState({ ...state, newUsedFeatures }); + } + } + + async getUsedFeatures(): Promise { + const state: IState | undefined = await this.getState(); + if (state && state.newUsedFeatures) { + return state.newUsedFeatures; + } + return { networks: [], swap: [] }; + } + + /** + * Retrieves the names of the pinned networks. + * + * This method first ensures that networks with new features are inserted. + * It then attempts to retrieve the current state. If the state and its networks + * are defined, it maps and returns the names of the valid networks. + * If the state or networks are not defined, it sets the initial active networks + * and returns a predefined list of popular network names. + * + * Previously, the method was named `getActiveNetworks`. + * @returns {Promise} A promise that resolves to an array of active network names. + */ + async getPinnedNetworkNames(): Promise { await this.insertNetworksWithNewFeatures(); const state: IState | undefined = await this.getState(); if (state && state.networks) { @@ -85,16 +138,37 @@ class NetworksState { } } + async getEnabledTestNetworks(): Promise { + await this.insertNetworksWithNewFeatures(); + const state: IState | undefined = await this.getState(); + if (state && state.enabledTestNetworks) { + const validNetworks = state.enabledTestNetworks; + return validNetworks.map(({ name }) => name); + } else { + this.setState(Object.assign({}, state, { enabledTestNetworks: [] })); + return []; + } + } + + async setTestnetStatus( + networkName: string, + isEnabled: boolean, + ): Promise { + const state: IState | undefined = await this.getState(); + const enabledTestNetworks = (state.enabledTestNetworks || []).filter( + n => n.name !== networkName, + ); + if (isEnabled) enabledTestNetworks.push({ name: networkName }); + await this.setState({ ...state, enabledTestNetworks }); + } + async reorderNetwork(networkNames: string[]): Promise { const state: IState | undefined = await this.getState(); const activeNetworks: NetworkStorageElement[] = networkNames.map(name => ({ name, isActive: true, })); - await this.setState({ - networks: activeNetworks, - newNetworksVersion: state.newNetworksVersion, - }); + await this.setState({ ...state, networks: activeNetworks }); } async setState(state: IState): Promise { diff --git a/packages/extension/src/libs/networks-state/types.ts b/packages/extension/src/libs/networks-state/types.ts index b70751088..ab36d94c9 100644 --- a/packages/extension/src/libs/networks-state/types.ts +++ b/packages/extension/src/libs/networks-state/types.ts @@ -9,4 +9,9 @@ export interface NetworkStorageElement { export interface IState { networks: NetworkStorageElement[]; newNetworksVersion: string; + enabledTestNetworks: NetworkStorageElement[]; + newUsedFeatures: { + networks: string[]; + swap: string[]; + }; } diff --git a/packages/extension/src/libs/recently-sent-addresses/index.ts b/packages/extension/src/libs/recently-sent-addresses/index.ts new file mode 100644 index 000000000..73f9a56ed --- /dev/null +++ b/packages/extension/src/libs/recently-sent-addresses/index.ts @@ -0,0 +1,41 @@ +import { InternalStorageNamespace } from "@/types/provider"; +import BrowserStorage from "../common/browser-storage"; +import { IState, } from "./types"; +import { NetworkNames } from "@enkryptcom/types"; +import { BaseNetwork } from "@/types/base-network"; + +class RecentlySentAddressesState { + #storage: BrowserStorage + + constructor() { + this.#storage = new BrowserStorage( + InternalStorageNamespace.recentlySentAddresses, + ); + } + + async addRecentlySentAddress( + network: Pick, + address: string, + ): Promise { + const key = network.name + const state: IState | undefined = await this.#storage.get(key) + const newState: IState = { + ...state, + addresses: Array.from(new Set([ + network.displayAddress(address), + ...(state?.addresses ?? []), + ])).slice(0, 5), + } + await this.#storage.set(key, newState) + } + + async getRecentlySentAddresses(networkName: NetworkNames): Promise { + const key = networkName + const out: IState | undefined = await this.#storage.get(key) + if (!out) return [] + return out.addresses + } +} + +export default RecentlySentAddressesState + diff --git a/packages/extension/src/libs/recently-sent-addresses/types.ts b/packages/extension/src/libs/recently-sent-addresses/types.ts new file mode 100644 index 000000000..44976940a --- /dev/null +++ b/packages/extension/src/libs/recently-sent-addresses/types.ts @@ -0,0 +1,3 @@ +export type IState = { + addresses: string[] +} diff --git a/packages/extension/src/libs/updates-state/index.ts b/packages/extension/src/libs/updates-state/index.ts new file mode 100644 index 000000000..83a6c97f0 --- /dev/null +++ b/packages/extension/src/libs/updates-state/index.ts @@ -0,0 +1,62 @@ +import BrowserStorage from '../common/browser-storage'; +import { InternalStorageNamespace } from '@/types/provider'; +import { IState, StorageKeys } from './types'; + +class UpdatesState { + private storage: BrowserStorage; + + constructor() { + this.storage = new BrowserStorage(InternalStorageNamespace.updatesState); + } + + async setState(state: IState): Promise { + return this.storage.set(StorageKeys.updatesInfo, state); + } + + async getState(): Promise { + const state = this.storage.get(StorageKeys.updatesInfo); + if (!state) { + const newState: IState = { + lastVersionViewed: '', + currentRelease: '', + currentReleaseTimestamp: 0, + } + return newState + } + return state; + } + + async getLastVersionViewed(): Promise { + const state: IState = await this.getState(); + return state?.lastVersionViewed ?? ''; + } + async setLastVersionViewed(lastVersionViewed: string): Promise { + const state: IState = await this.getState(); + const newState: IState = { ...state, lastVersionViewed } + await this.setState(newState); + } + + async getCurrentRelease(): Promise { + const state: IState = await this.getState(); + return state?.currentRelease ?? ''; + } + + async setCurrentRelease(currentRelease: string): Promise { + const state: IState = await this.getState(); + const newState: IState = { ...state, currentRelease } + await this.setState(newState); + } + + async getCurrentReleaseTimestamp(): Promise { + const state: IState = await this.getState(); + return state?.currentReleaseTimestamp ?? 0; + } + + async setCurrentReleaseTimestamp(currentReleaseTimestamp: number): Promise { + const state: IState = await this.getState(); + const newState: IState = { ...state, currentReleaseTimestamp } + await this.setState(newState); + } +} + +export default UpdatesState; diff --git a/packages/extension/src/libs/updates-state/types.ts b/packages/extension/src/libs/updates-state/types.ts new file mode 100644 index 000000000..dae0fb32a --- /dev/null +++ b/packages/extension/src/libs/updates-state/types.ts @@ -0,0 +1,9 @@ +export enum StorageKeys { + updatesInfo = 'updates-info', +} + +export interface IState { + lastVersionViewed: string; + currentRelease: string; + currentReleaseTimestamp: number; +} diff --git a/packages/extension/src/libs/utils/networks.ts b/packages/extension/src/libs/utils/networks.ts index 9afe2f2eb..7634ac299 100644 --- a/packages/extension/src/libs/utils/networks.ts +++ b/packages/extension/src/libs/utils/networks.ts @@ -22,19 +22,21 @@ const providerNetworks: Record> = { [ProviderName.solana]: SolanaNetworks, [ProviderName.enkrypt]: {}, }; -const getAllNetworks = async (): Promise => { +const getAllNetworks = async (includeCustom: boolean = true): Promise => { const customNetworksState = new CustomNetworksState(); const customNetworks = ( await customNetworksState.getAllCustomEVMNetworks() ).map(options => new CustomEvmNetwork(options)); - - return (Object.values(EthereumNetworks) as BaseNetwork[]) + const allNetworks = (Object.values(EthereumNetworks) as BaseNetwork[]) .concat(Object.values(PolkadotNetworks) as BaseNetwork[]) .concat(Object.values(BitcoinNetworks) as BaseNetwork[]) .concat(Object.values(KadenaNetworks) as BaseNetwork[]) - .concat(Object.values(SolanaNetworks) as BaseNetwork[]) - .concat(customNetworks); + .concat(Object.values(SolanaNetworks) as BaseNetwork[]); + if (!includeCustom) { + return allNetworks + } + return allNetworks.concat(customNetworks); }; const getNetworkByName = async ( name: string, @@ -73,12 +75,13 @@ const DEFAULT_SOLANA_NETWORK = Solana; const POPULAR_NAMES = [ NetworkNames.Bitcoin, NetworkNames.Ethereum, + NetworkNames.Solana, NetworkNames.Matic, NetworkNames.Polkadot, NetworkNames.Binance, NetworkNames.Rootstock, NetworkNames.Optimism, - NetworkNames.Kadena, + NetworkNames.Arbitrum, ]; export { getAllNetworks, diff --git a/packages/extension/src/providers/bitcoin/inject.ts b/packages/extension/src/providers/bitcoin/inject.ts index e541f9058..0165eae05 100644 --- a/packages/extension/src/providers/bitcoin/inject.ts +++ b/packages/extension/src/providers/bitcoin/inject.ts @@ -136,8 +136,9 @@ const injectDocument = ( JSON.stringify({ method: InternalMethods.getSettings, params: [] }), ) .then((settings: SettingsType) => { - if (settings.btc.injectUnisat) document['unisat'] = provider; + if (settings.btc.injectUnisat) + (document as EnkryptWindow)['unisat'] = provider; }); - document['enkrypt']['providers'][options.name] = provider; + (document as EnkryptWindow)['enkrypt']['providers'][options.name] = provider; }; export default injectDocument; diff --git a/packages/extension/src/providers/bitcoin/methods/btc_getNetwork.ts b/packages/extension/src/providers/bitcoin/methods/btc_getNetwork.ts index 86f3c1335..c31066b7e 100644 --- a/packages/extension/src/providers/bitcoin/methods/btc_getNetwork.ts +++ b/packages/extension/src/providers/bitcoin/methods/btc_getNetwork.ts @@ -27,6 +27,8 @@ const method: MiddlewareFunction = function ( return res(null, 'livenet'); if (this.network.name === NetworkNames.BitcoinTest) return res(null, 'testnet'); + if (this.network.name === NetworkNames.Litecoin) + return res(null, 'litecoin'); res(null, ''); }); } diff --git a/packages/extension/src/providers/bitcoin/methods/btc_switchNetwork.ts b/packages/extension/src/providers/bitcoin/methods/btc_switchNetwork.ts index 307736a10..1e1e5a7fa 100644 --- a/packages/extension/src/providers/bitcoin/methods/btc_switchNetwork.ts +++ b/packages/extension/src/providers/bitcoin/methods/btc_switchNetwork.ts @@ -7,7 +7,7 @@ import BTCNetworks from '../networks'; import DomainState from '@/libs/domain-state'; import BitcoinProvider from '..'; import { BitcoinNetworks } from '../types'; -import { trackNetworkSelected } from '@/libs/metrics'; +import { trackNetwork } from '@/libs/metrics'; import { NetworkChangeEvents } from '@/libs/metrics/types'; const method: MiddlewareFunction = function ( this: BitcoinProvider, @@ -29,7 +29,7 @@ const method: MiddlewareFunction = function ( const allNetworks = Object.values(BTCNetworks); const validNetwork = allNetworks.find(net => net.name === internalName); if (validNetwork) { - trackNetworkSelected(NetworkChangeEvents.NetworkChangeAPI, { + trackNetwork(NetworkChangeEvents.NetworkChangeAPI, { provider: validNetwork.provider, network: validNetwork.name, }); @@ -49,8 +49,7 @@ const method: MiddlewareFunction = function ( } else { return res( getCustomError( - `btc_switchNetwork: porvided network ${ - payload.params![0] + `btc_switchNetwork: porvided network ${payload.params![0] } not supported`, ), ); diff --git a/packages/extension/src/providers/bitcoin/types/index.ts b/packages/extension/src/providers/bitcoin/types/index.ts index 4a9fab70f..983185ee3 100644 --- a/packages/extension/src/providers/bitcoin/types/index.ts +++ b/packages/extension/src/providers/bitcoin/types/index.ts @@ -5,6 +5,7 @@ import { PaymentType } from './bitcoin-network'; export const BitcoinNetworks = { livenet: NetworkNames.Bitcoin, testnet: NetworkNames.BitcoinTest, + litecoin: NetworkNames.Litecoin, }; export interface BitcoinNetworkInfo { diff --git a/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue b/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue index 43b4e805a..bb8003b1c 100644 --- a/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue +++ b/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue @@ -169,6 +169,7 @@ import { getTxInfo as getBTCTxInfo } from '@/providers/bitcoin/libs/utils'; import { NFTItem, NFTItemWithCollectionName, NFTType } from '@/types/nft'; import { trackSendEvents } from '@/libs/metrics'; import { SendEventType } from '@/libs/metrics/types'; +import RecentlySentAddressesState from '@/libs/recently-sent-addresses'; const props = defineProps({ network: { @@ -428,7 +429,14 @@ const selectNFT = (item: NFTItemWithCollectionName) => { isOpenSelectNft.value = false; }; +const recentlySentAddresses = new RecentlySentAddressesState(); + const sendAction = async () => { + await recentlySentAddresses.addRecentlySentAddress( + props.network, + addressTo.value, + ); + const keyring = new PublicKeyRing(); const fromAccountInfo = await keyring.getAccount(addressFrom.value); const currentFee = toBN( diff --git a/packages/extension/src/providers/common/ui/send-transaction/nft-select-list/components/nft-select-list-item.vue b/packages/extension/src/providers/common/ui/send-transaction/nft-select-list/components/nft-select-list-item.vue index 06e126c82..4d5f9f9d3 100644 --- a/packages/extension/src/providers/common/ui/send-transaction/nft-select-list/components/nft-select-list-item.vue +++ b/packages/extension/src/providers/common/ui/send-transaction/nft-select-list/components/nft-select-list-item.vue @@ -1,22 +1,14 @@ - diff --git a/packages/extension/src/ui/action/icons/common/drag-icon.vue b/packages/extension/src/ui/action/icons/common/drag-icon.vue index f025f8fce..2e092d23d 100644 --- a/packages/extension/src/ui/action/icons/common/drag-icon.vue +++ b/packages/extension/src/ui/action/icons/common/drag-icon.vue @@ -1,17 +1,14 @@ diff --git a/packages/extension/src/ui/action/icons/common/manage-networks-icon.vue b/packages/extension/src/ui/action/icons/common/manage-networks-icon.vue index 887496296..76c75187b 100644 --- a/packages/extension/src/ui/action/icons/common/manage-networks-icon.vue +++ b/packages/extension/src/ui/action/icons/common/manage-networks-icon.vue @@ -6,26 +6,19 @@ fill="none" xmlns="http://www.w3.org/2000/svg" > - - - - + + + + + + + + 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 1e484a44b..20353f0f7 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 @@ -39,6 +39,7 @@ {{ token.priceChangePercentage.toFixed(2) }}% + Last 24h

@@ -156,6 +157,14 @@ const close = () => { height: auto; box-sizing: border-box; + &__last-24 { + font-weight: 400; + font-size: 12px; + line-height: 16px; + letter-spacing: 0.5px; + color: @grayPrimary; + } + &__wrap { background: @white; box-shadow: diff --git a/packages/extension/src/ui/action/views/assets-select-list/components/assets-select-list-item.vue b/packages/extension/src/ui/action/views/assets-select-list/components/assets-select-list-item.vue index 473a908f3..af3692c3c 100644 --- a/packages/extension/src/ui/action/views/assets-select-list/components/assets-select-list-item.vue +++ b/packages/extension/src/ui/action/views/assets-select-list/components/assets-select-list-item.vue @@ -5,7 +5,9 @@
-

{{ token.name }}

+

+ {{ $filters.truncate(token.name, 25) }} +

{{ balance ? $filters.formatFloatingPointValue(balance).value : '~' }} {{ token.symbol }} diff --git a/packages/extension/src/ui/action/views/network-activity/components/network-activity-action.vue b/packages/extension/src/ui/action/views/network-activity/components/network-activity-action.vue index e8245aa13..20b93cc0a 100644 --- a/packages/extension/src/ui/action/views/network-activity/components/network-activity-action.vue +++ b/packages/extension/src/ui/action/views/network-activity/components/network-activity-action.vue @@ -4,11 +4,9 @@ Deposit -

Buy/Sell -
+
+

Token

+
+
+

Last 24h

+
+
+

Value

+
+ + + + + + diff --git a/packages/extension/src/ui/action/views/network-assets/components/network-assets-item.vue b/packages/extension/src/ui/action/views/network-assets/components/network-assets-item.vue index a23da895c..3a9b45b2b 100644 --- a/packages/extension/src/ui/action/views/network-assets/components/network-assets-item.vue +++ b/packages/extension/src/ui/action/views/network-assets/components/network-assets-item.vue @@ -89,8 +89,8 @@ const props = defineProps({ use([SVGRenderer, LineChart, TooltipComponent, GridComponent]); const option = ref({ - width: 32, - height: 32, + width: 48, + height: 20, color: [props.token.priceChangePercentage >= 0 ? '#80FFA5' : '#e01f43'], grid: { show: false, left: 0, top: 0 }, xAxis: [ @@ -180,8 +180,8 @@ const toggleDetail = () => { diff --git a/packages/extension/src/ui/action/views/updates/components/updates-network.vue b/packages/extension/src/ui/action/views/updates/components/updates-network.vue new file mode 100644 index 000000000..2071de211 --- /dev/null +++ b/packages/extension/src/ui/action/views/updates/components/updates-network.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/packages/extension/src/ui/action/views/updates/index.vue b/packages/extension/src/ui/action/views/updates/index.vue new file mode 100644 index 000000000..872dd7205 --- /dev/null +++ b/packages/extension/src/ui/action/views/updates/index.vue @@ -0,0 +1,250 @@ + + + + + diff --git a/packages/swap/src/providers/paraswap/index.ts b/packages/swap/src/providers/paraswap/index.ts index a3ee7f010..0dd39ed94 100644 --- a/packages/swap/src/providers/paraswap/index.ts +++ b/packages/swap/src/providers/paraswap/index.ts @@ -198,7 +198,7 @@ class ParaSwap extends ProviderClass { .then((res) => res.json()) .then(async (response: ParaswapResponseType) => { if (response.error) { - console.error(response.error); + console.error("Error in swap response from ParaSwap", response.error); return Promise.resolve(null); } const transactions: EVMTransaction[] = []; @@ -245,7 +245,7 @@ class ParaSwap extends ProviderClass { }; }) .catch((e) => { - console.error(e); + console.error("Error generating swap from ParaSwap", e); return Promise.resolve(null); }); } @@ -283,6 +283,18 @@ class ParaSwap extends ProviderClass { .then((j) => j.json()) .then(async (jsonRes) => { if (!jsonRes) return null; + // Note: sometimes `jsonRes.priceRoute` is undefined and "error" is set instead + if (!jsonRes.priceRoute) { + if (jsonRes.error) { + // Sometimes ParaSwap returns this error: "No routes found with enough liquidity" + throw new Error(`ParaSwap error getting prices: ${jsonRes.error}`); + } else { + // Didn't have the expected "priceRoute" property + throw new Error( + `ParaSwap error getting prices, no "priceRoute" property on response: ${JSON.stringify(jsonRes)}`, + ); + } + } const res: ParaswpQuoteResponse = jsonRes.priceRoute; const transactions: EVMTransaction[] = []; if (options.fromToken.address !== NATIVE_TOKEN_ADDRESS) { @@ -320,7 +332,7 @@ class ParaSwap extends ProviderClass { return response; }) .catch((e) => { - console.error(e); + console.error("Error getting quote from ParaSwap", e); return Promise.resolve(null); }); } diff --git a/packages/swap/src/providers/rango/index.ts b/packages/swap/src/providers/rango/index.ts index aaa4f5651..e4bc0c549 100644 --- a/packages/swap/src/providers/rango/index.ts +++ b/packages/swap/src/providers/rango/index.ts @@ -311,6 +311,13 @@ class Rango extends ProviderClass { async init(tokenList?: TokenType[]): Promise { logger.info(`init: Initialising against ${tokenList?.length} tokens...`); + if (!Rango.isNetworkSupportedByEnkrypt(this.network)) { + logger.info( + `init: Enkrypt does not support network on Rango: ${this.network}`, + ); + return; + } + const [rangoMeta, swaplist] = await Promise.all([ rangoClient.meta({ excludeNonPopulars: true, @@ -429,10 +436,16 @@ class Rango extends ProviderClass { return matchingRangoBlockchain; } + static isNetworkSupportedByEnkrypt( + supportedNetworkName: SupportedNetworkName, + ): boolean { + return supportedNetworkInfoByName.has(supportedNetworkName); + } + /** * Is this network supported by both enkrypt and rango? */ - static isNetworkSupported( + static isNetworkSupportedByEnkryptAndRango( supportedNetworkName: SupportedNetworkName, rangoBlockchains: ReadonlyArray, ): boolean { diff --git a/packages/swap/src/providers/rango/supported.ts b/packages/swap/src/providers/rango/supported.ts index 0b4f5fb10..272300fd6 100644 --- a/packages/swap/src/providers/rango/supported.ts +++ b/packages/swap/src/providers/rango/supported.ts @@ -1,4 +1,4 @@ -import { SupportedNetworkName, } from '../../types' +import { SupportedNetworkName } from "../../types"; export type SupportedNetworkInfo = { /** Standard base10 chain ID, can be obtained from `https://chainlist.org` */ @@ -179,4 +179,3 @@ export const supportedNetworkByRangoBlockchain = new Map< }, ]), ); - diff --git a/packages/swap/tests/changelly.test.ts b/packages/swap/tests/changelly.test.ts index 3f9708c42..b1f9ade80 100644 --- a/packages/swap/tests/changelly.test.ts +++ b/packages/swap/tests/changelly.test.ts @@ -51,9 +51,7 @@ describe("Changelly Provider", () => { (swap?.transactions[0] as EVMTransaction).data.startsWith("0xa9059cbb"), ).to.be.eq(true); const status = await changelly.getStatus( - ( - await swap!.getStatusObject({ transactions: [] }) - ).options, + (await swap!.getStatusObject({ transactions: [] })).options, ); expect(status).to.be.eq("pending"); });