Skip to content

Commit

Permalink
refactor: get btc fees via BitcoinModule (#8)
Browse files Browse the repository at this point in the history
Co-authored-by: Gergely Lovas <[email protected]>
  • Loading branch information
meeh0w and gergelylovas authored Aug 21, 2024
1 parent 243e747 commit a5af551
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 60 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion src/background/services/network/NetworkService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ export class NetworkService implements OnLock, OnStorageReady {
return getProviderForNetwork(network) as JsonRpcBatchInternal;
}

async getBitcoinNetwork(): Promise<Network> {
async getBitcoinNetwork(): Promise<NetworkWithCaipId> {
const activeNetworks = await this.activeNetworks.promisify();
const network =
activeNetworks[ChainId.BITCOIN] ??
Expand Down
87 changes: 62 additions & 25 deletions src/background/services/networkFee/NetworkFeeService.test.ts
Original file line number Diff line number Diff line change
@@ -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(() => {
Expand All @@ -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,
});
});
});
});
46 changes: 23 additions & 23 deletions src/background/services/networkFee/NetworkFeeService.ts
Original file line number Diff line number Diff line change
@@ -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<TransactionPriority, bigint> = {
Expand All @@ -19,32 +16,41 @@ const EVM_TIP_MODIFIERS: Record<TransactionPriority, bigint> = {

@singleton()
export class NetworkFeeService {
constructor(private networkService: NetworkService) {}

async getNetworkFee(network: Network): Promise<NetworkFee | null> {
const provider = getProviderForNetwork(network);
constructor() {}

async getNetworkFee(network: NetworkWithCaipId): Promise<NetworkFee | null> {
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,
};
}

return null;
}

private async getEip1559NetworkFeeRates(
network: Network,
network: NetworkWithCaipId,
provider: JsonRpcBatchInternal
): Promise<NetworkFee> {
const { maxFeePerGas: baseMaxFee } = await (
Expand Down Expand Up @@ -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<number | null> {
if (network.vmName !== NetworkVMType.EVM) {
Expand Down
4 changes: 2 additions & 2 deletions src/background/services/networkFee/handlers/getNetworkFee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ 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';
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';

Expand Down Expand Up @@ -330,7 +330,7 @@ export class EthSendTransactionHandler extends DAppRequestHandler<
};

async #addGasInformation(
network: Network,
network: NetworkWithCaipId,
tx: EnsureDefined<EthSendTransactionParams, 'chainId'>
): Promise<EnsureDefined<EthSendTransactionParamsWithGas, 'chainId'>> {
const fees = await this.networkFeeService.getNetworkFee(network);
Expand Down
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,6 @@
ledger-bitcoin "0.2.3"
xss "1.0.14"

"@avalabs/[email protected]":
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/[email protected]":
version "3.0.1-alpha.1"
resolved "https://registry.yarnpkg.com/@avalabs/glacier-sdk/-/glacier-sdk-3.0.1-alpha.1.tgz#7cd1fe5d534beb0c5370642a8bb22ad94bc14e48"
Expand Down

0 comments on commit a5af551

Please sign in to comment.