From a5af55164e14e609bd00df5b1fd8e12acc1d1533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Leszczyk?= Date: Wed, 21 Aug 2024 15:19:26 +0200 Subject: [PATCH] refactor: get btc fees via BitcoinModule (#8) Co-authored-by: Gergely Lovas --- package.json | 2 +- .../services/network/NetworkService.ts | 2 +- .../networkFee/NetworkFeeService.test.ts | 87 +++++++++++++------ .../services/networkFee/NetworkFeeService.ts | 46 +++++----- .../networkFee/handlers/getNetworkFee.ts | 4 +- .../eth_sendTransaction.test.ts | 2 +- .../eth_sendTransaction.ts | 4 +- yarn.lock | 5 -- 8 files changed, 92 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index d0873a8a6..654f4fc7d 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@avalabs/core-token-prices-sdk": "3.0.1-alpha.1", "@avalabs/core-utils-sdk": "3.0.1-alpha.1", "@avalabs/core-wallets-sdk": "3.0.1-alpha.1", - "@avalabs/glacier-sdk": "2.8.0-alpha.188", + "@avalabs/glacier-sdk": "3.0.1-alpha.1", "@avalabs/hw-app-avalanche": "0.14.1", "@avalabs/core-k2-components": "4.18.0-alpha.47", "@avalabs/types": "3.0.1-alpha.1", diff --git a/src/background/services/network/NetworkService.ts b/src/background/services/network/NetworkService.ts index 654135595..2e80240a6 100644 --- a/src/background/services/network/NetworkService.ts +++ b/src/background/services/network/NetworkService.ts @@ -516,7 +516,7 @@ export class NetworkService implements OnLock, OnStorageReady { return getProviderForNetwork(network) as JsonRpcBatchInternal; } - async getBitcoinNetwork(): Promise { + async getBitcoinNetwork(): Promise { const activeNetworks = await this.activeNetworks.promisify(); const network = activeNetworks[ChainId.BITCOIN] ?? diff --git a/src/background/services/networkFee/NetworkFeeService.test.ts b/src/background/services/networkFee/NetworkFeeService.test.ts index 4a090e4ed..2405ff7a4 100644 --- a/src/background/services/networkFee/NetworkFeeService.test.ts +++ b/src/background/services/networkFee/NetworkFeeService.test.ts @@ -1,8 +1,12 @@ import { NetworkVMType } from '@avalabs/core-chains-sdk'; import { NetworkFeeService } from './NetworkFeeService'; import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork'; +import { NetworkWithCaipId } from '../network/models'; +import ModuleManager from '@src/background/vmModules/ModuleManager'; +import { serializeToJSON } from '@src/background/serialization/serialize'; jest.mock('@src/utils/network/getProviderForNetwork'); +jest.mock('@src/background/vmModules/ModuleManager'); describe('src/background/services/networkFee/NetworkFeeService', () => { beforeEach(() => { @@ -13,41 +17,74 @@ describe('src/background/services/networkFee/NetworkFeeService', () => { const provider = { getFeeData: jest.fn(), }; - const networkService = { - activeNetwork: { vmName: NetworkVMType.EVM }, - getProviderForNetwork: jest.fn(), - } as any; + const evm = { + vmName: NetworkVMType.EVM, + caipId: 'eip155:1', + } as NetworkWithCaipId; + const btc = { + vmName: NetworkVMType.BITCOIN, + caipId: 'bip122:whatever', + } as NetworkWithCaipId; beforeEach(() => { jest.mocked(getProviderForNetwork).mockReturnValue(provider as any); }); + it('uses BitcoinModule for BTC fees', async () => { + const getNetworkFee = jest.fn().mockResolvedValue({ + isFixedFee: false, + low: { maxFeePerGas: 3n }, + medium: { maxFeePerGas: 4n }, + high: { maxFeePerGas: 5n }, + }); + + jest + .spyOn(ModuleManager, 'loadModuleByNetwork') + .mockResolvedValueOnce({ getNetworkFee } as any); + + const service = new NetworkFeeService(); + + const result = await service.getNetworkFee(btc); + + expect(ModuleManager.loadModuleByNetwork).toHaveBeenCalledWith(btc); + expect(getNetworkFee).toHaveBeenCalledWith(btc); + + // Jest has issues with objects containing BigInts, so we make it easier by using our own serializer + expect(serializeToJSON(result)).toEqual( + serializeToJSON({ + isFixedFee: false, + low: { maxFee: 3n }, + medium: { maxFee: 4n }, + high: { maxFee: 5n }, + displayDecimals: 0, + }) + ); + }); + it('provides base information and three rate presets', async () => { const maxFeePerGas = BigInt(30e9); // 30 gwei provider.getFeeData.mockResolvedValueOnce({ maxFeePerGas }); - const service = new NetworkFeeService(networkService as any); - - expect(await service.getNetworkFee(networkService.activeNetwork)).toEqual( - { - displayDecimals: 9, // use Gwei to display amount - baseMaxFee: maxFeePerGas, - low: { - maxFee: maxFeePerGas + BigInt(5e8), - maxTip: BigInt(5e8), - }, - medium: { - maxFee: maxFeePerGas + BigInt(2e9), - maxTip: BigInt(2e9), - }, - high: { - maxFee: maxFeePerGas + BigInt(3e9), - maxTip: BigInt(3e9), - }, - isFixedFee: false, - } - ); + const service = new NetworkFeeService(); + + expect(await service.getNetworkFee(evm)).toEqual({ + displayDecimals: 9, // use Gwei to display amount + baseMaxFee: maxFeePerGas, + low: { + maxFee: maxFeePerGas + BigInt(5e8), + maxTip: BigInt(5e8), + }, + medium: { + maxFee: maxFeePerGas + BigInt(2e9), + maxTip: BigInt(2e9), + }, + high: { + maxFee: maxFeePerGas + BigInt(3e9), + maxTip: BigInt(3e9), + }, + isFixedFee: false, + }); }); }); }); diff --git a/src/background/services/networkFee/NetworkFeeService.ts b/src/background/services/networkFee/NetworkFeeService.ts index 147b86292..97fd5b0c1 100644 --- a/src/background/services/networkFee/NetworkFeeService.ts +++ b/src/background/services/networkFee/NetworkFeeService.ts @@ -1,14 +1,11 @@ import { NetworkVMType } from '@avalabs/core-chains-sdk'; -import { - BitcoinProviderAbstract, - JsonRpcBatchInternal, -} from '@avalabs/core-wallets-sdk'; +import { JsonRpcBatchInternal } from '@avalabs/core-wallets-sdk'; import { isSwimmer } from '@src/utils/isSwimmerNetwork'; import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork'; import { singleton } from 'tsyringe'; -import { NetworkService } from '../network/NetworkService'; import { FeeRate, NetworkFee, TransactionPriority } from './models'; -import { Network } from '../network/models'; +import { NetworkWithCaipId } from '../network/models'; +import ModuleManager from '@src/background/vmModules/ModuleManager'; const EVM_BASE_TIP = BigInt(5e8); // 0.5 Gwei const EVM_TIP_MODIFIERS: Record = { @@ -19,24 +16,33 @@ const EVM_TIP_MODIFIERS: Record = { @singleton() export class NetworkFeeService { - constructor(private networkService: NetworkService) {} - - async getNetworkFee(network: Network): Promise { - const provider = getProviderForNetwork(network); + constructor() {} + async getNetworkFee(network: NetworkWithCaipId): Promise { if (network.vmName === NetworkVMType.EVM) { + const provider = getProviderForNetwork(network); return this.getEip1559NetworkFeeRates( network, provider as JsonRpcBatchInternal ); } else if (network.vmName === NetworkVMType.BITCOIN) { - const rates = await (provider as BitcoinProviderAbstract).getFeeRates(); + const module = await ModuleManager.loadModuleByNetwork(network); + const { low, medium, high, isFixedFee } = await module.getNetworkFee( + network + ); + return { + isFixedFee, + low: { + maxFee: low.maxFeePerGas, + }, + medium: { + maxFee: medium.maxFeePerGas, + }, + high: { + maxFee: high.maxFeePerGas, + }, displayDecimals: 0, // display btc fees in satoshi - low: this.formatBtcFee(rates.low), - medium: this.formatBtcFee(rates.medium), - high: this.formatBtcFee(rates.high), - isFixedFee: false, }; } @@ -44,7 +50,7 @@ export class NetworkFeeService { } private async getEip1559NetworkFeeRates( - network: Network, + network: NetworkWithCaipId, provider: JsonRpcBatchInternal ): Promise { const { maxFeePerGas: baseMaxFee } = await ( @@ -79,17 +85,11 @@ export class NetworkFeeService { }; } - private formatBtcFee(rate: number) { - return { - maxFee: BigInt(rate), - }; - } - async estimateGasLimit( from: string, to: string, data: string, - network: Network, + network: NetworkWithCaipId, value?: bigint ): Promise { if (network.vmName !== NetworkVMType.EVM) { diff --git a/src/background/services/networkFee/handlers/getNetworkFee.ts b/src/background/services/networkFee/handlers/getNetworkFee.ts index c233f815c..120821c14 100644 --- a/src/background/services/networkFee/handlers/getNetworkFee.ts +++ b/src/background/services/networkFee/handlers/getNetworkFee.ts @@ -4,7 +4,7 @@ import { injectable } from 'tsyringe'; import { NetworkService } from '../../network/NetworkService'; import { NetworkFee } from '../models'; import { NetworkFeeService } from '../NetworkFeeService'; -import { Network } from '../../network/models'; +import { NetworkWithCaipId } from '../../network/models'; type HandlerType = ExtensionRequestHandler< ExtensionRequest.NETWORK_FEE_GET, @@ -24,7 +24,7 @@ export class GetNetworkFeeHandler implements HandlerType { handle: HandlerType['handle'] = async ({ request, scope }) => { const [networkCaipId] = request.params; - let network: Network | undefined; + let network: NetworkWithCaipId | undefined; if (networkCaipId) { network = await this.networkService.getNetwork(networkCaipId); diff --git a/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.test.ts b/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.test.ts index 5c74ea948..75ee796b3 100644 --- a/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.test.ts +++ b/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.test.ts @@ -138,7 +138,7 @@ const displayValuesMock: TransactionDisplayValues = { describe('background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts', () => { const networkService = new NetworkService({} as any, {} as any); - const networkFeeService = new NetworkFeeService({} as any); + const networkFeeService = new NetworkFeeService(); const balanceAggregatorService = new BalanceAggregatorService( {} as any, {} as any, diff --git a/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts b/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts index 73eaa23eb..9af70e5e7 100644 --- a/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts +++ b/src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts @@ -35,7 +35,6 @@ import { parseBasicDisplayValues } from './contracts/contractParsers/utils/parse import browser, { runtime } from 'webextension-polyfill'; import { getExplorerAddressByNetwork } from '@src/utils/getExplorerAddress'; import { txToCustomEvmTx } from './utils/txToCustomEvmTx'; -import { Network } from '@avalabs/core-chains-sdk'; import { WalletService } from '@src/background/services/wallet/WalletService'; import { JsonRpcBatchInternal } from '@avalabs/core-wallets-sdk'; import { AnalyticsServicePosthog } from '@src/background/services/analytics/AnalyticsServicePosthog'; @@ -43,6 +42,7 @@ import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork' import { BlockaidService } from '@src/background/services/blockaid/BlockaidService'; import { openApprovalWindow } from '@src/background/runtime/openApprovalWindow'; import { EnsureDefined } from '@src/background/models'; +import { NetworkWithCaipId } from '@src/background/services/network/models'; import { caipToChainId } from '@src/utils/caipConversion'; import { TxDisplayOptions } from '../models'; @@ -330,7 +330,7 @@ export class EthSendTransactionHandler extends DAppRequestHandler< }; async #addGasInformation( - network: Network, + network: NetworkWithCaipId, tx: EnsureDefined ): Promise> { const fees = await this.networkFeeService.getNetworkFee(network); diff --git a/yarn.lock b/yarn.lock index c38fbca38..d0d7fc747 100644 --- a/yarn.lock +++ b/yarn.lock @@ -178,11 +178,6 @@ ledger-bitcoin "0.2.3" xss "1.0.14" -"@avalabs/glacier-sdk@2.8.0-alpha.188": - version "2.8.0-alpha.188" - resolved "https://registry.yarnpkg.com/@avalabs/glacier-sdk/-/glacier-sdk-2.8.0-alpha.188.tgz#82e4efc4be55b2f67a825e033863a25a14a13915" - integrity sha512-NjtlHXWpxC7aDZE+USb5YkZ1In+IjkCi/THHxOZg0ahv2RyccUiA75VU+daZ0zAZWgIUQCutniTB46HFq5Sjbw== - "@avalabs/glacier-sdk@3.0.1-alpha.1": version "3.0.1-alpha.1" resolved "https://registry.yarnpkg.com/@avalabs/glacier-sdk/-/glacier-sdk-3.0.1-alpha.1.tgz#7cd1fe5d534beb0c5370642a8bb22ad94bc14e48"