Skip to content

Commit

Permalink
chore: some refactors, missing tests added
Browse files Browse the repository at this point in the history
  • Loading branch information
meeh0w committed Nov 4, 2024
1 parent 4e3de58 commit 56e1b58
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 80 deletions.
68 changes: 68 additions & 0 deletions src/background/services/balances/BalanceAggregatorService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,73 @@ describe('src/background/services/balances/BalanceAggregatorService.ts', () => {

expect(balances).toEqual(freshBalances);
});

it.only('emits the BalanceServiceEvents.UPDATED if balances did change', async () => {
// Cached balances include two accounts: account1, account2
const cachedBalances = {
[network2.chainId]: {
...balanceForNetwork2,
[account2.addressC]: network1TokenBalance,
},
};

(storageService.load as jest.Mock).mockResolvedValue({
balances: cachedBalances,
});

await service.onUnlock();

// Fresh balances include only one account (account2) and the values for it HAVE changed
balancesServiceMock.getBalancesForNetwork.mockResolvedValueOnce({
[account2.addressC]: {
[networkToken2.symbol]: {
...network1TokenBalance,
balance: 200n,
balanceDisplayValue: '0.00002',
},
},
});

const updatesListener = jest.fn();
service.addListener(BalanceServiceEvents.UPDATED, updatesListener);

await service.getBalancesForNetworks([network2.chainId], [account2], []);
await new Promise(process.nextTick);

// The fresh balances include new information, therefore an event should be emitted.
expect(updatesListener).toHaveBeenCalled();
});

it.only('DOES NOT emit the BalanceServiceEvents.UPDATED if balances did not change', async () => {
// Cached balances include two accounts: account1, account2
const cachedBalances = {
[network2.chainId]: {
...balanceForNetwork2,
[account2.addressC]: balanceForNetwork1,
},
};

(storageService.load as jest.Mock).mockResolvedValue({
balances: cachedBalances,
});

await service.onUnlock();

// Fresh balances include only one account (account1) and the values for it DID NOT change
balancesServiceMock.getBalancesForNetwork.mockResolvedValueOnce(
balanceForNetwork2
);

const updatesListener = jest.fn();
service.addListener(BalanceServiceEvents.UPDATED, updatesListener);

await service.getBalancesForNetworks([network2.chainId], [account1], []);
await new Promise(process.nextTick);

// Cached & fresh balances as a whole are different,
// but the fresh balances do not include any new information,
// therefore no event should be emitted.
expect(updatesListener).not.toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AVM,
utils,
EVM,
PVM,
} from '@avalabs/avalanchejs';
import { DEFERRED_RESPONSE } from '@src/background/connections/middlewares/models';
import { Action } from '../../actions/models';
Expand Down Expand Up @@ -309,6 +310,40 @@ describe('src/background/services/wallet/handlers/avalanche_sendTransaction.ts',
checkExpected(requestWithUtxos, result, tx);
});

it('passes feeTolerance to the parsing util', async () => {
const tx = { vm: PVM };
(utils.unpackWithManager as jest.Mock).mockReturnValueOnce(tx);
getAddressesByIndicesMock.mockResolvedValue([]);
(Avalanche.parseAvalancheTx as jest.Mock).mockReturnValueOnce({
type: 'import',
});
(utils.parse as jest.Mock).mockReturnValueOnce([
undefined,
undefined,
new Uint8Array([0, 1, 2]),
]);
(
Avalanche.createAvalancheUnsignedTx as jest.Mock
).mockReturnValueOnce(unsignedTxMock);

await handler.handleAuthenticated(
buildRpcCall({
...request,
params: {
...request.params,
feeTolerance: 25,
},
})
);

expect(Avalanche.parseAvalancheTx).toHaveBeenCalledWith(
unsignedTxMock,
providerMock,
expect.anything(),
{ feeTolerance: 25 }
);
});

it('works without provided UTXOs', async () => {
const tx = { vm: AVM };
(utils.unpackWithManager as jest.Mock).mockReturnValueOnce(tx);
Expand Down
86 changes: 6 additions & 80 deletions src/contexts/NetworkProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {
Dispatch,
SetStateAction,
createContext,
useCallback,
useContext,
Expand All @@ -11,7 +9,6 @@ import {
import { useConnectionContext } from './ConnectionProvider';
import { filter, map } from 'rxjs';
import { ExtensionRequest } from '@src/background/connections/extensionConnection/models';
import { ChainId } from '@avalabs/core-chains-sdk';
import { networksUpdatedEventListener } from '@src/background/services/network/events/networksUpdatedEventListener';
import { useAnalyticsContext } from './AnalyticsProvider';
import { SetDevelopermodeNetworkHandler } from '@src/background/services/network/handlers/setDeveloperMode';
Expand All @@ -22,7 +19,6 @@ import { SaveCustomNetworkHandler } from '@src/background/services/network/handl
import { AddFavoriteNetworkHandler } from '@src/background/services/network/handlers/addFavoriteNetwork';
import { UpdateDefaultNetworkHandler } from '@src/background/services/network/handlers/updateDefaultNetwork';
import {
Avalanche,
BitcoinProvider,
JsonRpcBatchInternal,
} from '@avalabs/core-wallets-sdk';
Expand All @@ -32,13 +28,14 @@ import {
NetworkOverrides,
NetworkWithCaipId,
} from '@src/background/services/network/models';
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';
import { isNetworkUpdatedEvent } from '@src/background/services/network/events/isNetworkUpdatedEvent';
import { SetActiveNetworkHandler } from '@src/background/services/network/handlers/setActiveNetwork';
import { updateIfDifferent } from '@src/utils/updateIfDifferent';
import { getNetworkCaipId } from '@src/utils/caipConversion';
import { isDevnet } from '@src/utils/isDevnet';
import { networkChanged } from './NetworkProvider/networkChanges';
import { useBitcoinProvider } from '@src/hooks/useBitcoinProvider';
import { useEthereumProvider } from '@src/hooks/useEthereumProvider';
import { useAvalancheCProvider } from '@src/hooks/useAvalancheCProvider';

const NetworkContext = createContext<{
network?: NetworkWithCaipId | undefined;
Expand All @@ -58,7 +55,6 @@ const NetworkContext = createContext<{
isChainIdExist(chainId: number): boolean;
getNetwork(chainId: number | string): NetworkWithCaipId | undefined;
avaxProviderC?: JsonRpcBatchInternal;
avaxProviderP?: Avalanche.JsonRpcProvider;
ethereumProvider?: JsonRpcBatchInternal;
bitcoinProvider?: BitcoinProvider;
}>({} as any);
Expand Down Expand Up @@ -118,78 +114,9 @@ export function NetworkContextProvider({ children }: { children: any }) {
[networks]
);

const [bitcoinProvider, setBitcoinProvider] = useState<BitcoinProvider>();
const [ethereumProvider, setEthereumProvider] =
useState<JsonRpcBatchInternal>();
const [avaxProviderC, setAvaxProviderC] = useState<JsonRpcBatchInternal>();
const [avaxProviderP, setAvaxProviderP] =
useState<Avalanche.JsonRpcProvider>();

useEffect(() => {
if (!network) {
setBitcoinProvider(undefined);
setEthereumProvider(undefined);
setAvaxProviderC(undefined);
setAvaxProviderP(undefined);
return;
}

let isMounted = true;

const avaxNetworkC = getNetwork(
network.isTestnet
? ChainId.AVALANCHE_TESTNET_ID
: ChainId.AVALANCHE_MAINNET_ID
);
const avaxNetworkP = getNetwork(
isDevnet(network)
? ChainId.AVALANCHE_DEVNET_P
: network.isTestnet
? ChainId.AVALANCHE_TEST_P
: ChainId.AVALANCHE_P
);
const ethNetwork = getNetwork(
network.isTestnet
? ChainId.ETHEREUM_TEST_SEPOLIA
: ChainId.ETHEREUM_HOMESTEAD
);
const btcNetwork = getNetwork(
network.isTestnet ? ChainId.BITCOIN_TESTNET : ChainId.BITCOIN
);

function updateIfMounted(setter: Dispatch<SetStateAction<any>>) {
return (p) => {
if (isMounted) {
setter(p);
}
};
}

if (avaxNetworkC) {
getProviderForNetwork(avaxNetworkC).then(
updateIfMounted(setAvaxProviderC)
);
}
if (avaxNetworkP) {
getProviderForNetwork(avaxNetworkP).then(
updateIfMounted(setAvaxProviderP)
);
}
if (ethNetwork) {
getProviderForNetwork(ethNetwork).then(
updateIfMounted(setEthereumProvider)
);
}
if (btcNetwork) {
getProviderForNetwork(btcNetwork).then(
updateIfMounted(setBitcoinProvider)
);
}

return () => {
isMounted = false;
};
}, [getNetwork, network]);
const bitcoinProvider = useBitcoinProvider(Boolean(network?.isTestnet));
const ethereumProvider = useEthereumProvider(Boolean(network?.isTestnet));
const avaxProviderC = useAvalancheCProvider(Boolean(network?.isTestnet));

const getNetworkState = useCallback(() => {
return request<GetNetworksStateHandler>({
Expand Down Expand Up @@ -317,7 +244,6 @@ export function NetworkContextProvider({ children }: { children: any }) {
isChainIdExist,
getNetwork,
avaxProviderC,
avaxProviderP,
bitcoinProvider,
ethereumProvider,
}}
Expand Down
36 changes: 36 additions & 0 deletions src/hooks/useAvalancheCProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
import { ChainId } from '@avalabs/core-chains-sdk';
import { JsonRpcBatchInternal } from '@avalabs/core-wallets-sdk';

import { useNetworkContext } from '@src/contexts/NetworkProvider';
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';

export const useAvalancheCProvider = (isTestnet) => {
const { getNetwork } = useNetworkContext();

const [provider, setProvider] = useState<JsonRpcBatchInternal>();

useEffect(() => {
const cChain = getNetwork(
isTestnet ? ChainId.AVALANCHE_MAINNET_ID : ChainId.AVALANCHE_TESTNET_ID
);

if (!cChain) {
return;
}

let isMounted = true;

getProviderForNetwork(cChain).then((cChainProvider) => {
if (isMounted && cChainProvider instanceof JsonRpcBatchInternal) {
setProvider(cChainProvider);
}
});

return () => {
isMounted = false;
};
});

return provider;
};
36 changes: 36 additions & 0 deletions src/hooks/useBitcoinProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
import { ChainId } from '@avalabs/core-chains-sdk';
import { BitcoinProvider } from '@avalabs/core-wallets-sdk';

import { useNetworkContext } from '@src/contexts/NetworkProvider';
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';

export const useBitcoinProvider = (isTestnet) => {
const { getNetwork } = useNetworkContext();

const [provider, setProvider] = useState<BitcoinProvider>();

useEffect(() => {
const btcNetwork = getNetwork(
isTestnet ? ChainId.BITCOIN_TESTNET : ChainId.BITCOIN
);

if (!btcNetwork) {
return;
}

let isMounted = true;

getProviderForNetwork(btcNetwork).then((bitcoinProvider) => {
if (isMounted && bitcoinProvider instanceof BitcoinProvider) {
setProvider(bitcoinProvider);
}
});

return () => {
isMounted = false;
};
});

return provider;
};
36 changes: 36 additions & 0 deletions src/hooks/useEthereumProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
import { ChainId } from '@avalabs/core-chains-sdk';
import { JsonRpcBatchInternal } from '@avalabs/core-wallets-sdk';

import { useNetworkContext } from '@src/contexts/NetworkProvider';
import { getProviderForNetwork } from '@src/utils/network/getProviderForNetwork';

export const useEthereumProvider = (isTestnet) => {
const { getNetwork } = useNetworkContext();

const [provider, setProvider] = useState<JsonRpcBatchInternal>();

useEffect(() => {
const ethNetwork = getNetwork(
isTestnet ? ChainId.ETHEREUM_TEST_SEPOLIA : ChainId.ETHEREUM_HOMESTEAD
);

if (!ethNetwork) {
return;
}

let isMounted = true;

getProviderForNetwork(ethNetwork).then((ethProvider) => {
if (isMounted && ethProvider instanceof JsonRpcBatchInternal) {
setProvider(ethProvider);
}
});

return () => {
isMounted = false;
};
});

return provider;
};
Loading

0 comments on commit 56e1b58

Please sign in to comment.