Skip to content

Commit a5af551

Browse files
meeh0wgergelylovas
andauthored
refactor: get btc fees via BitcoinModule (#8)
Co-authored-by: Gergely Lovas <gergely.lovas@avalabs.org>
1 parent 243e747 commit a5af551

File tree

8 files changed

+92
-60
lines changed

8 files changed

+92
-60
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"@avalabs/core-token-prices-sdk": "3.0.1-alpha.1",
3636
"@avalabs/core-utils-sdk": "3.0.1-alpha.1",
3737
"@avalabs/core-wallets-sdk": "3.0.1-alpha.1",
38-
"@avalabs/glacier-sdk": "2.8.0-alpha.188",
38+
"@avalabs/glacier-sdk": "3.0.1-alpha.1",
3939
"@avalabs/hw-app-avalanche": "0.14.1",
4040
"@avalabs/core-k2-components": "4.18.0-alpha.47",
4141
"@avalabs/types": "3.0.1-alpha.1",

src/background/services/network/NetworkService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ export class NetworkService implements OnLock, OnStorageReady {
516516
return getProviderForNetwork(network) as JsonRpcBatchInternal;
517517
}
518518

519-
async getBitcoinNetwork(): Promise<Network> {
519+
async getBitcoinNetwork(): Promise<NetworkWithCaipId> {
520520
const activeNetworks = await this.activeNetworks.promisify();
521521
const network =
522522
activeNetworks[ChainId.BITCOIN] ??
Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { NetworkVMType } from '@avalabs/core-chains-sdk';
22
import { NetworkFeeService } from './NetworkFeeService';
33
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';
4+
import { NetworkWithCaipId } from '../network/models';
5+
import ModuleManager from '@src/background/vmModules/ModuleManager';
6+
import { serializeToJSON } from '@src/background/serialization/serialize';
47

58
jest.mock('@src/utils/network/getProviderForNetwork');
9+
jest.mock('@src/background/vmModules/ModuleManager');
610

711
describe('src/background/services/networkFee/NetworkFeeService', () => {
812
beforeEach(() => {
@@ -13,41 +17,74 @@ describe('src/background/services/networkFee/NetworkFeeService', () => {
1317
const provider = {
1418
getFeeData: jest.fn(),
1519
};
16-
const networkService = {
17-
activeNetwork: { vmName: NetworkVMType.EVM },
18-
getProviderForNetwork: jest.fn(),
19-
} as any;
20+
const evm = {
21+
vmName: NetworkVMType.EVM,
22+
caipId: 'eip155:1',
23+
} as NetworkWithCaipId;
24+
const btc = {
25+
vmName: NetworkVMType.BITCOIN,
26+
caipId: 'bip122:whatever',
27+
} as NetworkWithCaipId;
2028

2129
beforeEach(() => {
2230
jest.mocked(getProviderForNetwork).mockReturnValue(provider as any);
2331
});
2432

33+
it('uses BitcoinModule for BTC fees', async () => {
34+
const getNetworkFee = jest.fn().mockResolvedValue({
35+
isFixedFee: false,
36+
low: { maxFeePerGas: 3n },
37+
medium: { maxFeePerGas: 4n },
38+
high: { maxFeePerGas: 5n },
39+
});
40+
41+
jest
42+
.spyOn(ModuleManager, 'loadModuleByNetwork')
43+
.mockResolvedValueOnce({ getNetworkFee } as any);
44+
45+
const service = new NetworkFeeService();
46+
47+
const result = await service.getNetworkFee(btc);
48+
49+
expect(ModuleManager.loadModuleByNetwork).toHaveBeenCalledWith(btc);
50+
expect(getNetworkFee).toHaveBeenCalledWith(btc);
51+
52+
// Jest has issues with objects containing BigInts, so we make it easier by using our own serializer
53+
expect(serializeToJSON(result)).toEqual(
54+
serializeToJSON({
55+
isFixedFee: false,
56+
low: { maxFee: 3n },
57+
medium: { maxFee: 4n },
58+
high: { maxFee: 5n },
59+
displayDecimals: 0,
60+
})
61+
);
62+
});
63+
2564
it('provides base information and three rate presets', async () => {
2665
const maxFeePerGas = BigInt(30e9); // 30 gwei
2766

2867
provider.getFeeData.mockResolvedValueOnce({ maxFeePerGas });
2968

30-
const service = new NetworkFeeService(networkService as any);
31-
32-
expect(await service.getNetworkFee(networkService.activeNetwork)).toEqual(
33-
{
34-
displayDecimals: 9, // use Gwei to display amount
35-
baseMaxFee: maxFeePerGas,
36-
low: {
37-
maxFee: maxFeePerGas + BigInt(5e8),
38-
maxTip: BigInt(5e8),
39-
},
40-
medium: {
41-
maxFee: maxFeePerGas + BigInt(2e9),
42-
maxTip: BigInt(2e9),
43-
},
44-
high: {
45-
maxFee: maxFeePerGas + BigInt(3e9),
46-
maxTip: BigInt(3e9),
47-
},
48-
isFixedFee: false,
49-
}
50-
);
69+
const service = new NetworkFeeService();
70+
71+
expect(await service.getNetworkFee(evm)).toEqual({
72+
displayDecimals: 9, // use Gwei to display amount
73+
baseMaxFee: maxFeePerGas,
74+
low: {
75+
maxFee: maxFeePerGas + BigInt(5e8),
76+
maxTip: BigInt(5e8),
77+
},
78+
medium: {
79+
maxFee: maxFeePerGas + BigInt(2e9),
80+
maxTip: BigInt(2e9),
81+
},
82+
high: {
83+
maxFee: maxFeePerGas + BigInt(3e9),
84+
maxTip: BigInt(3e9),
85+
},
86+
isFixedFee: false,
87+
});
5188
});
5289
});
5390
});

src/background/services/networkFee/NetworkFeeService.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import { NetworkVMType } from '@avalabs/core-chains-sdk';
2-
import {
3-
BitcoinProviderAbstract,
4-
JsonRpcBatchInternal,
5-
} from '@avalabs/core-wallets-sdk';
2+
import { JsonRpcBatchInternal } from '@avalabs/core-wallets-sdk';
63
import { isSwimmer } from '@src/utils/isSwimmerNetwork';
74
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';
85
import { singleton } from 'tsyringe';
9-
import { NetworkService } from '../network/NetworkService';
106
import { FeeRate, NetworkFee, TransactionPriority } from './models';
11-
import { Network } from '../network/models';
7+
import { NetworkWithCaipId } from '../network/models';
8+
import ModuleManager from '@src/background/vmModules/ModuleManager';
129

1310
const EVM_BASE_TIP = BigInt(5e8); // 0.5 Gwei
1411
const EVM_TIP_MODIFIERS: Record<TransactionPriority, bigint> = {
@@ -19,32 +16,41 @@ const EVM_TIP_MODIFIERS: Record<TransactionPriority, bigint> = {
1916

2017
@singleton()
2118
export class NetworkFeeService {
22-
constructor(private networkService: NetworkService) {}
23-
24-
async getNetworkFee(network: Network): Promise<NetworkFee | null> {
25-
const provider = getProviderForNetwork(network);
19+
constructor() {}
2620

21+
async getNetworkFee(network: NetworkWithCaipId): Promise<NetworkFee | null> {
2722
if (network.vmName === NetworkVMType.EVM) {
23+
const provider = getProviderForNetwork(network);
2824
return this.getEip1559NetworkFeeRates(
2925
network,
3026
provider as JsonRpcBatchInternal
3127
);
3228
} else if (network.vmName === NetworkVMType.BITCOIN) {
33-
const rates = await (provider as BitcoinProviderAbstract).getFeeRates();
29+
const module = await ModuleManager.loadModuleByNetwork(network);
30+
const { low, medium, high, isFixedFee } = await module.getNetworkFee(
31+
network
32+
);
33+
3434
return {
35+
isFixedFee,
36+
low: {
37+
maxFee: low.maxFeePerGas,
38+
},
39+
medium: {
40+
maxFee: medium.maxFeePerGas,
41+
},
42+
high: {
43+
maxFee: high.maxFeePerGas,
44+
},
3545
displayDecimals: 0, // display btc fees in satoshi
36-
low: this.formatBtcFee(rates.low),
37-
medium: this.formatBtcFee(rates.medium),
38-
high: this.formatBtcFee(rates.high),
39-
isFixedFee: false,
4046
};
4147
}
4248

4349
return null;
4450
}
4551

4652
private async getEip1559NetworkFeeRates(
47-
network: Network,
53+
network: NetworkWithCaipId,
4854
provider: JsonRpcBatchInternal
4955
): Promise<NetworkFee> {
5056
const { maxFeePerGas: baseMaxFee } = await (
@@ -79,17 +85,11 @@ export class NetworkFeeService {
7985
};
8086
}
8187

82-
private formatBtcFee(rate: number) {
83-
return {
84-
maxFee: BigInt(rate),
85-
};
86-
}
87-
8888
async estimateGasLimit(
8989
from: string,
9090
to: string,
9191
data: string,
92-
network: Network,
92+
network: NetworkWithCaipId,
9393
value?: bigint
9494
): Promise<number | null> {
9595
if (network.vmName !== NetworkVMType.EVM) {

src/background/services/networkFee/handlers/getNetworkFee.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { injectable } from 'tsyringe';
44
import { NetworkService } from '../../network/NetworkService';
55
import { NetworkFee } from '../models';
66
import { NetworkFeeService } from '../NetworkFeeService';
7-
import { Network } from '../../network/models';
7+
import { NetworkWithCaipId } from '../../network/models';
88

99
type HandlerType = ExtensionRequestHandler<
1010
ExtensionRequest.NETWORK_FEE_GET,
@@ -24,7 +24,7 @@ export class GetNetworkFeeHandler implements HandlerType {
2424
handle: HandlerType['handle'] = async ({ request, scope }) => {
2525
const [networkCaipId] = request.params;
2626

27-
let network: Network | undefined;
27+
let network: NetworkWithCaipId | undefined;
2828

2929
if (networkCaipId) {
3030
network = await this.networkService.getNetwork(networkCaipId);

src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ const displayValuesMock: TransactionDisplayValues = {
138138

139139
describe('background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts', () => {
140140
const networkService = new NetworkService({} as any, {} as any);
141-
const networkFeeService = new NetworkFeeService({} as any);
141+
const networkFeeService = new NetworkFeeService();
142142
const balanceAggregatorService = new BalanceAggregatorService(
143143
{} as any,
144144
{} as any,

src/background/services/wallet/handlers/eth_sendTransaction/eth_sendTransaction.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ import { parseBasicDisplayValues } from './contracts/contractParsers/utils/parse
3535
import browser, { runtime } from 'webextension-polyfill';
3636
import { getExplorerAddressByNetwork } from '@src/utils/getExplorerAddress';
3737
import { txToCustomEvmTx } from './utils/txToCustomEvmTx';
38-
import { Network } from '@avalabs/core-chains-sdk';
3938
import { WalletService } from '@src/background/services/wallet/WalletService';
4039
import { JsonRpcBatchInternal } from '@avalabs/core-wallets-sdk';
4140
import { AnalyticsServicePosthog } from '@src/background/services/analytics/AnalyticsServicePosthog';
4241
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';
4342
import { BlockaidService } from '@src/background/services/blockaid/BlockaidService';
4443
import { openApprovalWindow } from '@src/background/runtime/openApprovalWindow';
4544
import { EnsureDefined } from '@src/background/models';
45+
import { NetworkWithCaipId } from '@src/background/services/network/models';
4646
import { caipToChainId } from '@src/utils/caipConversion';
4747
import { TxDisplayOptions } from '../models';
4848

@@ -330,7 +330,7 @@ export class EthSendTransactionHandler extends DAppRequestHandler<
330330
};
331331

332332
async #addGasInformation(
333-
network: Network,
333+
network: NetworkWithCaipId,
334334
tx: EnsureDefined<EthSendTransactionParams, 'chainId'>
335335
): Promise<EnsureDefined<EthSendTransactionParamsWithGas, 'chainId'>> {
336336
const fees = await this.networkFeeService.getNetworkFee(network);

yarn.lock

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,6 @@
178178
ledger-bitcoin "0.2.3"
179179
xss "1.0.14"
180180

181-
"@avalabs/glacier-sdk@2.8.0-alpha.188":
182-
version "2.8.0-alpha.188"
183-
resolved "https://registry.yarnpkg.com/@avalabs/glacier-sdk/-/glacier-sdk-2.8.0-alpha.188.tgz#82e4efc4be55b2f67a825e033863a25a14a13915"
184-
integrity sha512-NjtlHXWpxC7aDZE+USb5YkZ1In+IjkCi/THHxOZg0ahv2RyccUiA75VU+daZ0zAZWgIUQCutniTB46HFq5Sjbw==
185-
186181
"@avalabs/glacier-sdk@3.0.1-alpha.1":
187182
version "3.0.1-alpha.1"
188183
resolved "https://registry.yarnpkg.com/@avalabs/glacier-sdk/-/glacier-sdk-3.0.1-alpha.1.tgz#7cd1fe5d534beb0c5370642a8bb22ad94bc14e48"

0 commit comments

Comments
 (0)