@avalabs/evm-module 0.0.21 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +8 -5
- package/CHANGELOG.md +15 -0
- package/dist/index.cjs +19 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +18 -19
- package/dist/index.js.map +1 -1
- package/manifest.json +10 -1
- package/package.json +9 -8
- package/src/handlers/forward-to-rpc-node/forward-to-rpc-node.test.ts +90 -0
- package/src/handlers/forward-to-rpc-node/forward-to-rpc-node.ts +23 -0
- package/src/handlers/get-address/get-address.ts +26 -0
- package/src/handlers/get-balances/evm-balance-service/get-erc20-balances.test.ts +3 -4
- package/src/handlers/get-balances/evm-balance-service/get-erc20-balances.ts +13 -17
- package/src/handlers/get-balances/evm-balance-service/get-native-token-balances.test.ts +4 -5
- package/src/handlers/get-balances/evm-balance-service/get-native-token-balances.ts +7 -10
- package/src/handlers/get-balances/get-balances.test.ts +10 -11
- package/src/handlers/get-balances/get-balances.ts +5 -3
- package/src/handlers/get-balances/glacier-balance-service/get-erc20-balances.test.ts +1 -2
- package/src/handlers/get-balances/glacier-balance-service/get-erc20-balances.ts +10 -13
- package/src/handlers/get-balances/glacier-balance-service/get-native-token-balances.test.ts +2 -3
- package/src/handlers/get-balances/glacier-balance-service/get-native-token-balances.ts +10 -9
- package/src/handlers/get-transaction-history/converters/etherscan-transaction-converter/convert-transaction-erc20.test.ts +53 -0
- package/src/handlers/get-transaction-history/converters/etherscan-transaction-converter/convert-transaction-erc20.ts +3 -5
- package/src/handlers/get-transaction-history/converters/etherscan-transaction-converter/convert-transaction-normal.test.ts +57 -0
- package/src/handlers/get-transaction-history/converters/etherscan-transaction-converter/convert-transaction-normal.ts +3 -4
- package/src/handlers/get-transaction-history/converters/evm-transaction-converter/get-tokens.ts +5 -6
- package/src/module.ts +17 -2
package/manifest.json
CHANGED
|
@@ -32,7 +32,16 @@
|
|
|
32
32
|
"permissions": {
|
|
33
33
|
"rpc": {
|
|
34
34
|
"dapps": true,
|
|
35
|
-
"methods": [
|
|
35
|
+
"methods": [
|
|
36
|
+
"personal_sign",
|
|
37
|
+
"eth_sendTransaction",
|
|
38
|
+
"eth_*",
|
|
39
|
+
"web3_clientVersion",
|
|
40
|
+
"web3_sha3",
|
|
41
|
+
"net_version",
|
|
42
|
+
"net_peerCount",
|
|
43
|
+
"net_listening"
|
|
44
|
+
]
|
|
36
45
|
}
|
|
37
46
|
},
|
|
38
47
|
"manifestVersion": "0.0"
|
package/package.json
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avalabs/evm-module",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"main": "dist/index.cjs",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@avalabs/vm-module-types": "0.0.
|
|
10
|
-
"@avalabs/coingecko-sdk": "v2.8.0-alpha.
|
|
11
|
-
"@avalabs/utils-sdk": "2.8.0-alpha.
|
|
12
|
-
"@avalabs/etherscan-sdk": "v2.8.0-alpha.
|
|
13
|
-
"@avalabs/glacier-sdk": "v2.8.0-alpha.
|
|
14
|
-
"@avalabs/wallets-sdk": "v2.8.0-alpha.
|
|
9
|
+
"@avalabs/vm-module-types": "0.0.23",
|
|
10
|
+
"@avalabs/coingecko-sdk": "v2.8.0-alpha.195",
|
|
11
|
+
"@avalabs/utils-sdk": "2.8.0-alpha.195",
|
|
12
|
+
"@avalabs/etherscan-sdk": "v2.8.0-alpha.195",
|
|
13
|
+
"@avalabs/glacier-sdk": "v2.8.0-alpha.195",
|
|
14
|
+
"@avalabs/wallets-sdk": "v2.8.0-alpha.195",
|
|
15
15
|
"@blockaid/client": "0.11.0",
|
|
16
16
|
"bn.js": "5.2.1",
|
|
17
17
|
"lodash.startcase": "4.4.0",
|
|
18
18
|
"@metamask/rpc-errors": "6.3.0",
|
|
19
19
|
"zod": "3.23.8",
|
|
20
|
-
"@zodios/core": "10.9.6"
|
|
20
|
+
"@zodios/core": "10.9.6",
|
|
21
|
+
"@avalabs/types": "2.8.0-alpha.193"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"typechain": "8.3.1",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { forwardToRpcNode } from './forward-to-rpc-node';
|
|
2
|
+
import { getProvider } from '../../utils/get-provider';
|
|
3
|
+
import { rpcErrors } from '@metamask/rpc-errors';
|
|
4
|
+
import { NetworkVMType, RpcMethod } from '@avalabs/vm-module-types';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../utils/get-provider');
|
|
7
|
+
jest.mock('@metamask/rpc-errors', () => ({
|
|
8
|
+
rpcErrors: {
|
|
9
|
+
internal: jest.fn().mockImplementation((message) => ({ error: `mocked error: ${message}` })),
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const mockProvider = {
|
|
14
|
+
send: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const network = {
|
|
18
|
+
chainId: 1,
|
|
19
|
+
chainName: 'mainnet',
|
|
20
|
+
rpcUrl: 'https://example.com',
|
|
21
|
+
networkToken: {
|
|
22
|
+
name: 'ethereum',
|
|
23
|
+
symbol: 'ETH',
|
|
24
|
+
decimals: 18,
|
|
25
|
+
},
|
|
26
|
+
vmName: NetworkVMType.EVM,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
describe('forwardToRpcNode', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
jest.clearAllMocks();
|
|
32
|
+
(getProvider as jest.Mock).mockReturnValue(mockProvider);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should forward the request and return the result on success', async () => {
|
|
36
|
+
const request = {
|
|
37
|
+
method: 'eth_chainId' as RpcMethod,
|
|
38
|
+
params: [1, 2],
|
|
39
|
+
requestId: 'requestId',
|
|
40
|
+
sessionId: 'sessionId',
|
|
41
|
+
chainId: 'eip155:1',
|
|
42
|
+
dappInfo: {
|
|
43
|
+
name: 'some dapp',
|
|
44
|
+
url: 'some url',
|
|
45
|
+
icon: 'some icon',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const expectedResult = '0x1';
|
|
50
|
+
|
|
51
|
+
mockProvider.send.mockResolvedValue(expectedResult);
|
|
52
|
+
|
|
53
|
+
const result = await forwardToRpcNode(request, network);
|
|
54
|
+
|
|
55
|
+
expect(getProvider).toHaveBeenCalledWith({
|
|
56
|
+
chainId: network.chainId,
|
|
57
|
+
chainName: network.chainName,
|
|
58
|
+
rpcUrl: network.rpcUrl,
|
|
59
|
+
multiContractAddress: undefined,
|
|
60
|
+
pollingInterval: 1000,
|
|
61
|
+
});
|
|
62
|
+
expect(mockProvider.send).toHaveBeenCalledWith(request.method, request.params);
|
|
63
|
+
expect(result).toEqual({ result: expectedResult });
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should handle errors and return a formatted error response', async () => {
|
|
67
|
+
const request = {
|
|
68
|
+
method: 'eth_accounts' as RpcMethod,
|
|
69
|
+
params: [],
|
|
70
|
+
requestId: 'requestId',
|
|
71
|
+
sessionId: 'sessionId',
|
|
72
|
+
chainId: 'eip155:1',
|
|
73
|
+
dappInfo: {
|
|
74
|
+
name: 'some dapp',
|
|
75
|
+
url: 'some url',
|
|
76
|
+
icon: 'some icon',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const error = new Error('Test error');
|
|
81
|
+
|
|
82
|
+
mockProvider.send.mockRejectedValue(error);
|
|
83
|
+
|
|
84
|
+
const result = await forwardToRpcNode(request, network);
|
|
85
|
+
|
|
86
|
+
expect(rpcErrors.internal).toHaveBeenCalledWith(error.message);
|
|
87
|
+
expect(result).toHaveProperty('error');
|
|
88
|
+
expect(result.error).toEqual({ error: `mocked error: ${error.message}` });
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Network, RpcRequest } from '@avalabs/vm-module-types';
|
|
2
|
+
import { rpcErrors } from '@metamask/rpc-errors';
|
|
3
|
+
import { getProvider } from '../../utils/get-provider';
|
|
4
|
+
|
|
5
|
+
export const forwardToRpcNode = async (request: RpcRequest, network: Network) => {
|
|
6
|
+
try {
|
|
7
|
+
const provider = getProvider({
|
|
8
|
+
chainId: network.chainId,
|
|
9
|
+
chainName: network.chainName,
|
|
10
|
+
rpcUrl: network.rpcUrl,
|
|
11
|
+
multiContractAddress: network.utilityAddresses?.multicall,
|
|
12
|
+
pollingInterval: 1000,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const response = await provider.send(request.method, request.params as unknown[]);
|
|
16
|
+
return { result: response };
|
|
17
|
+
} catch (error) {
|
|
18
|
+
// extracting the error message based on the error object structure from ethers lib
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
const message = (error as any).info?.error?.message || (error as any).error?.message || (error as Error).message;
|
|
21
|
+
return { error: rpcErrors.internal(message) };
|
|
22
|
+
}
|
|
23
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NetworkVMType, WalletType, type GetAddressParams, type GetAddressResponse } from '@avalabs/vm-module-types';
|
|
2
|
+
import { getAddressFromXPub, getEvmAddressFromPubKey } from '@avalabs/wallets-sdk';
|
|
3
|
+
import { rpcErrors } from '@metamask/rpc-errors';
|
|
4
|
+
|
|
5
|
+
type GetAddress = Omit<GetAddressParams, 'isTestnet' | 'xpubXP'>;
|
|
6
|
+
|
|
7
|
+
export const getAddress = async ({ accountIndex, xpub, walletType }: GetAddress): Promise<GetAddressResponse> => {
|
|
8
|
+
switch (walletType) {
|
|
9
|
+
case WalletType.Mnemonic:
|
|
10
|
+
case WalletType.Ledger:
|
|
11
|
+
case WalletType.Keystone: {
|
|
12
|
+
return {
|
|
13
|
+
[NetworkVMType.EVM]: getAddressFromXPub(xpub, accountIndex),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
case WalletType.LedgerLive:
|
|
17
|
+
case WalletType.Seedless: {
|
|
18
|
+
const pubKeyBuffer = Buffer.from(xpub, 'hex');
|
|
19
|
+
return {
|
|
20
|
+
[NetworkVMType.EVM]: getEvmAddressFromPubKey(pubKeyBuffer),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
default:
|
|
24
|
+
throw rpcErrors.invalidParams(`Unsupported wallet type: ${walletType}`);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BN } from 'bn.js';
|
|
2
1
|
import { getErc20Balances } from './get-erc20-balances';
|
|
3
2
|
import { ethers } from 'ethers';
|
|
4
3
|
import { TokenType } from '@avalabs/vm-module-types';
|
|
@@ -7,7 +6,7 @@ describe('get-erc20-balances', () => {
|
|
|
7
6
|
it('should return erc20 token balances', async () => {
|
|
8
7
|
jest.spyOn(ethers, 'Contract').mockImplementation(() => {
|
|
9
8
|
return {
|
|
10
|
-
balanceOf: jest.fn().mockResolvedValue(
|
|
9
|
+
balanceOf: jest.fn().mockResolvedValue(1000000000000000000n),
|
|
11
10
|
} as never;
|
|
12
11
|
});
|
|
13
12
|
|
|
@@ -23,7 +22,7 @@ describe('get-erc20-balances', () => {
|
|
|
23
22
|
},
|
|
24
23
|
],
|
|
25
24
|
provider: {
|
|
26
|
-
getBalance: jest.fn().mockResolvedValue(
|
|
25
|
+
getBalance: jest.fn().mockResolvedValue(1000000000000000000n),
|
|
27
26
|
} as never,
|
|
28
27
|
tokenService: {
|
|
29
28
|
getPricesByAddresses: jest.fn().mockResolvedValue({
|
|
@@ -63,7 +62,7 @@ describe('get-erc20-balances', () => {
|
|
|
63
62
|
symbol: 'ETH',
|
|
64
63
|
decimals: 18,
|
|
65
64
|
logoUri: 'https://example.com/logo.png',
|
|
66
|
-
balance:
|
|
65
|
+
balance: 1000000000000000000n,
|
|
67
66
|
balanceCurrencyDisplayValue: '1000.00',
|
|
68
67
|
balanceDisplayValue: '1',
|
|
69
68
|
balanceInCurrency: 1000,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TokenUnit } from '@avalabs/utils-sdk';
|
|
2
|
+
import { type ERC20Token, type Network, TokenType, type TokenWithBalanceEVM } from '@avalabs/vm-module-types';
|
|
3
3
|
import { ethers, type Provider } from 'ethers';
|
|
4
4
|
import ERC20 from '@openzeppelin/contracts/build/contracts/ERC20.json';
|
|
5
5
|
import type { TokenService } from '@internal/utils';
|
|
6
6
|
import { VsCurrencyType } from '@avalabs/coingecko-sdk';
|
|
7
|
-
import BN from 'bn.js';
|
|
8
7
|
|
|
9
8
|
export const getErc20Balances = async ({
|
|
10
9
|
provider,
|
|
@@ -20,7 +19,7 @@ export const getErc20Balances = async ({
|
|
|
20
19
|
currency: string;
|
|
21
20
|
tokens: ERC20Token[];
|
|
22
21
|
network: Network;
|
|
23
|
-
}): Promise<Record<string,
|
|
22
|
+
}): Promise<Record<string, TokenWithBalanceEVM>> => {
|
|
24
23
|
const coingeckoPlatformId = network.pricingProviders?.coingecko.assetPlatformId;
|
|
25
24
|
const coingeckoTokenId = network.pricingProviders?.coingecko.nativeTokenId;
|
|
26
25
|
const tokenAddresses = tokens.map((token) => token.address);
|
|
@@ -28,19 +27,17 @@ export const getErc20Balances = async ({
|
|
|
28
27
|
const tokensBalances = await Promise.allSettled(
|
|
29
28
|
tokens.map(async (token) => {
|
|
30
29
|
const contract = new ethers.Contract(token.address, ERC20.abi, provider);
|
|
31
|
-
const balanceBig = await contract.balanceOf?.(userAddress);
|
|
32
|
-
const balance =
|
|
30
|
+
const balanceBig: bigint = await contract.balanceOf?.(userAddress);
|
|
31
|
+
const balance = balanceBig || 0n;
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
return {
|
|
35
34
|
...token,
|
|
36
35
|
balance,
|
|
37
36
|
};
|
|
38
|
-
|
|
39
|
-
return tokenWithBalance;
|
|
40
37
|
}),
|
|
41
38
|
).then((res) => {
|
|
42
|
-
return res.reduce<(ERC20Token & { balance:
|
|
43
|
-
return result.status === 'fulfilled' &&
|
|
39
|
+
return res.reduce<(ERC20Token & { balance: bigint })[]>((acc, result) => {
|
|
40
|
+
return result.status === 'fulfilled' && result.value.balance !== 0n ? [...acc, result.value] : acc;
|
|
44
41
|
}, []);
|
|
45
42
|
});
|
|
46
43
|
|
|
@@ -58,11 +55,10 @@ export const getErc20Balances = async ({
|
|
|
58
55
|
const vol24 = simplePriceResponse?.[coingeckoTokenId ?? '']?.[currency]?.vol24 ?? undefined;
|
|
59
56
|
const change24 = simplePriceResponse?.[coingeckoTokenId ?? '']?.[currency]?.change24 ?? undefined;
|
|
60
57
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const balanceDisplayValue =
|
|
65
|
-
const balanceCurrencyDisplayValue = balanceInCurrency?.toFixed(2);
|
|
58
|
+
const balance = new TokenUnit(token.balance, token.decimals, token.symbol);
|
|
59
|
+
const balanceCurrencyDisplayValue = priceInCurrency ? balance.mul(priceInCurrency).toDisplay(2) : undefined;
|
|
60
|
+
const balanceInCurrency = balanceCurrencyDisplayValue ? Number(balanceCurrencyDisplayValue) : undefined;
|
|
61
|
+
const balanceDisplayValue = balance.toDisplay();
|
|
66
62
|
|
|
67
63
|
return {
|
|
68
64
|
...acc,
|
|
@@ -80,6 +76,6 @@ export const getErc20Balances = async ({
|
|
|
80
76
|
},
|
|
81
77
|
};
|
|
82
78
|
},
|
|
83
|
-
{} as Record<string,
|
|
79
|
+
{} as Record<string, TokenWithBalanceEVM>,
|
|
84
80
|
);
|
|
85
81
|
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { BN } from 'bn.js';
|
|
2
1
|
import { getNativeTokenBalances } from './get-native-token-balances';
|
|
3
2
|
|
|
4
3
|
describe('get-native-token-balances', () => {
|
|
5
4
|
it('should return native token balances', async () => {
|
|
6
5
|
const balance = getNativeTokenBalances({
|
|
7
6
|
provider: {
|
|
8
|
-
getBalance: jest.fn().mockResolvedValue(
|
|
7
|
+
getBalance: jest.fn().mockResolvedValue(1000000000000000000n),
|
|
9
8
|
} as never,
|
|
10
9
|
tokenService: {
|
|
11
10
|
getSimplePrice: jest.fn().mockResolvedValue({
|
|
@@ -43,7 +42,7 @@ describe('get-native-token-balances', () => {
|
|
|
43
42
|
symbol: 'ETH',
|
|
44
43
|
decimals: 18,
|
|
45
44
|
logoUri: 'https://example.com/logo.png',
|
|
46
|
-
balance:
|
|
45
|
+
balance: 1000000000000000000n,
|
|
47
46
|
balanceCurrencyDisplayValue: '1000.00',
|
|
48
47
|
balanceDisplayValue: '1',
|
|
49
48
|
balanceInCurrency: 1000,
|
|
@@ -59,7 +58,7 @@ describe('get-native-token-balances', () => {
|
|
|
59
58
|
it('should return native token object without balance data', async () => {
|
|
60
59
|
const balance = getNativeTokenBalances({
|
|
61
60
|
provider: {
|
|
62
|
-
getBalance: jest.fn().mockResolvedValue(
|
|
61
|
+
getBalance: jest.fn().mockResolvedValue(0n),
|
|
63
62
|
} as never,
|
|
64
63
|
tokenService: {
|
|
65
64
|
getSimplePrice: jest.fn().mockResolvedValue({}),
|
|
@@ -87,7 +86,7 @@ describe('get-native-token-balances', () => {
|
|
|
87
86
|
symbol: 'ETH',
|
|
88
87
|
decimals: 18,
|
|
89
88
|
logoUri: 'https://example.com/logo.png',
|
|
90
|
-
balance:
|
|
89
|
+
balance: 0n,
|
|
91
90
|
balanceCurrencyDisplayValue: undefined,
|
|
92
91
|
balanceDisplayValue: '0',
|
|
93
92
|
coingeckoId: '123',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TokenUnit } from '@avalabs/utils-sdk';
|
|
2
|
+
import { type Network, type NetworkTokenWithBalance, TokenType } from '@avalabs/vm-module-types';
|
|
3
3
|
import type { VsCurrencyType } from '@avalabs/coingecko-sdk';
|
|
4
4
|
import { TokenService } from '@internal/utils';
|
|
5
5
|
import type { Provider } from 'ethers';
|
|
@@ -31,14 +31,11 @@ export const getNativeTokenBalances = async ({
|
|
|
31
31
|
const vol24 = simplePriceResponse?.[coingeckoTokenId ?? '']?.[currency]?.vol24 ?? undefined;
|
|
32
32
|
const change24 = simplePriceResponse?.[coingeckoTokenId ?? '']?.[currency]?.change24 ?? undefined;
|
|
33
33
|
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const balanceInCurrency =
|
|
39
|
-
? bnToBig(balance, networkToken.decimals).mul(priceInCurrency).toNumber()
|
|
40
|
-
: undefined;
|
|
41
|
-
const balanceCurrencyDisplayValue = balanceInCurrency?.toFixed(2);
|
|
34
|
+
const balance = await provider.getBalance(address);
|
|
35
|
+
const balanceUnit = new TokenUnit(balance, networkToken.decimals, networkToken.symbol);
|
|
36
|
+
const balanceDisplayValue = balanceUnit.toDisplay();
|
|
37
|
+
const balanceCurrencyDisplayValue = priceInCurrency ? balanceUnit.mul(priceInCurrency).toDisplay(2) : undefined;
|
|
38
|
+
const balanceInCurrency = balanceCurrencyDisplayValue ? Number(balanceCurrencyDisplayValue) : undefined;
|
|
42
39
|
|
|
43
40
|
return {
|
|
44
41
|
...networkToken,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { NetworkVMType, TokenType } from '@avalabs/vm-module-types';
|
|
2
2
|
import { getBalances } from './get-balances';
|
|
3
3
|
import * as GlacierNativeToken from './glacier-balance-service/get-native-token-balances';
|
|
4
|
-
import { BN } from 'bn.js';
|
|
5
4
|
import * as GlacierERC20Token from './glacier-balance-service/get-erc20-balances';
|
|
6
5
|
import * as EvmNativeToken from './evm-balance-service/get-native-token-balances';
|
|
7
6
|
import * as EvmERC20Token from './evm-balance-service/get-erc20-balances';
|
|
@@ -22,7 +21,7 @@ describe('get-balances', () => {
|
|
|
22
21
|
type: TokenType.NATIVE,
|
|
23
22
|
logoUri:
|
|
24
23
|
'https://images.ctfassets.net/gcj8jwzm6086/6l56QLVZmvacuBfjHBTThP/791d743dd2c526692562780c2325fedf/eth-circle__1_.svg',
|
|
25
|
-
balance:
|
|
24
|
+
balance: 1n,
|
|
26
25
|
balanceDisplayValue: '1',
|
|
27
26
|
balanceInCurrency: 1,
|
|
28
27
|
balanceCurrencyDisplayValue: '1',
|
|
@@ -43,7 +42,7 @@ describe('get-balances', () => {
|
|
|
43
42
|
symbol: 'DAI',
|
|
44
43
|
decimals: 18,
|
|
45
44
|
logoUri: 'https://s3.us-east-2.amazonaws.com/nomics-api/static/images/currencies/dai.svg',
|
|
46
|
-
balance:
|
|
45
|
+
balance: 1n,
|
|
47
46
|
balanceCurrencyDisplayValue: '1',
|
|
48
47
|
balanceDisplayValue: '1',
|
|
49
48
|
balanceInCurrency: 1,
|
|
@@ -67,7 +66,7 @@ describe('get-balances', () => {
|
|
|
67
66
|
decimals: 18,
|
|
68
67
|
symbol: 'ETH',
|
|
69
68
|
description:
|
|
70
|
-
'Ether is used to pay for transaction fees and computational services on
|
|
69
|
+
'Ether is used to pay for transaction fees and computational services on Ethereum. Users can send Ether to other users, and developers can write smart contracts that receive, hold, and send Ether.',
|
|
71
70
|
logoUri:
|
|
72
71
|
'https://images.ctfassets.net/gcj8jwzm6086/6l56QLVZmvacuBfjHBTThP/791d743dd2c526692562780c2325fedf/eth-circle__1_.svg',
|
|
73
72
|
},
|
|
@@ -83,7 +82,7 @@ describe('get-balances', () => {
|
|
|
83
82
|
'0x123': {
|
|
84
83
|
'0x123': {
|
|
85
84
|
address: '0x123',
|
|
86
|
-
balance:
|
|
85
|
+
balance: 1n,
|
|
87
86
|
balanceCurrencyDisplayValue: '1',
|
|
88
87
|
balanceDisplayValue: '1',
|
|
89
88
|
balanceInCurrency: 1,
|
|
@@ -99,7 +98,7 @@ describe('get-balances', () => {
|
|
|
99
98
|
vol24: 0,
|
|
100
99
|
},
|
|
101
100
|
ETH: {
|
|
102
|
-
balance:
|
|
101
|
+
balance: 1n,
|
|
103
102
|
balanceCurrencyDisplayValue: '1',
|
|
104
103
|
balanceDisplayValue: '1',
|
|
105
104
|
balanceInCurrency: 1,
|
|
@@ -150,7 +149,7 @@ describe('get-balances', () => {
|
|
|
150
149
|
type: TokenType.NATIVE,
|
|
151
150
|
logoUri:
|
|
152
151
|
'https://images.ctfassets.net/gcj8jwzm6086/6l56QLVZmvacuBfjHBTThP/791d743dd2c526692562780c2325fedf/eth-circle__1_.svg',
|
|
153
|
-
balance:
|
|
152
|
+
balance: 1n,
|
|
154
153
|
balanceDisplayValue: '1',
|
|
155
154
|
balanceInCurrency: 1,
|
|
156
155
|
balanceCurrencyDisplayValue: '1',
|
|
@@ -171,7 +170,7 @@ describe('get-balances', () => {
|
|
|
171
170
|
symbol: 'DAI2',
|
|
172
171
|
decimals: 18,
|
|
173
172
|
logoUri: 'https://s3.us-east-2.amazonaws.com/nomics-api/static/images/currencies/dai.svg',
|
|
174
|
-
balance:
|
|
173
|
+
balance: 1n,
|
|
175
174
|
balanceCurrencyDisplayValue: '1',
|
|
176
175
|
balanceDisplayValue: '1',
|
|
177
176
|
balanceInCurrency: 1,
|
|
@@ -195,7 +194,7 @@ describe('get-balances', () => {
|
|
|
195
194
|
decimals: 18,
|
|
196
195
|
symbol: 'ETH2',
|
|
197
196
|
description:
|
|
198
|
-
'Ether is used to pay for transaction fees and computational services on
|
|
197
|
+
'Ether is used to pay for transaction fees and computational services on Ethereum. Users can send Ether to other users, and developers can write smart contracts that receive, hold, and send Ether.',
|
|
199
198
|
logoUri:
|
|
200
199
|
'https://images.ctfassets.net/gcj8jwzm6086/6l56QLVZmvacuBfjHBTThP/791d743dd2c526692562780c2325fedf/eth-circle__1_.svg',
|
|
201
200
|
},
|
|
@@ -211,7 +210,7 @@ describe('get-balances', () => {
|
|
|
211
210
|
'0x456': {
|
|
212
211
|
'0x456': {
|
|
213
212
|
address: '0x456',
|
|
214
|
-
balance:
|
|
213
|
+
balance: 1n,
|
|
215
214
|
balanceCurrencyDisplayValue: '1',
|
|
216
215
|
balanceDisplayValue: '1',
|
|
217
216
|
balanceInCurrency: 1,
|
|
@@ -227,7 +226,7 @@ describe('get-balances', () => {
|
|
|
227
226
|
vol24: 0,
|
|
228
227
|
},
|
|
229
228
|
ETH2: {
|
|
230
|
-
balance:
|
|
229
|
+
balance: 1n,
|
|
231
230
|
balanceCurrencyDisplayValue: '1',
|
|
232
231
|
balanceDisplayValue: '1',
|
|
233
232
|
balanceInCurrency: 1,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type GetBalancesResponse,
|
|
3
2
|
type GetBalancesParams,
|
|
4
3
|
type Storage,
|
|
5
4
|
TokenType,
|
|
6
5
|
type NetworkContractToken,
|
|
7
6
|
type ERC20Token,
|
|
7
|
+
type TokenWithBalanceEVM,
|
|
8
8
|
} from '@avalabs/vm-module-types';
|
|
9
9
|
import { getErc20Balances } from './evm-balance-service/get-erc20-balances';
|
|
10
10
|
import { TokenService } from '@internal/utils';
|
|
@@ -15,6 +15,8 @@ import { getNativeTokenBalances as getNativeTokenBalancesFromGlacier } from './g
|
|
|
15
15
|
import { getErc20Balances as getErc20BalancesFromGlacier } from './glacier-balance-service/get-erc20-balances';
|
|
16
16
|
import type { EvmGlacierService } from '../../services/glacier-service/glacier-service';
|
|
17
17
|
|
|
18
|
+
type GetEvmBalancesResponse = Record<string, Record<string, TokenWithBalanceEVM>>;
|
|
19
|
+
|
|
18
20
|
export const getBalances = async ({
|
|
19
21
|
addresses,
|
|
20
22
|
currency,
|
|
@@ -27,7 +29,7 @@ export const getBalances = async ({
|
|
|
27
29
|
proxyApiUrl: string;
|
|
28
30
|
glacierService: EvmGlacierService;
|
|
29
31
|
storage?: Storage;
|
|
30
|
-
}): Promise<
|
|
32
|
+
}): Promise<GetEvmBalancesResponse> => {
|
|
31
33
|
const chainId = network.chainId;
|
|
32
34
|
const isNetworkSupported = await glacierService.isNetworkSupported(network.chainId);
|
|
33
35
|
const isHealthy = glacierService.isHealthy();
|
|
@@ -111,7 +113,7 @@ export const getBalances = async ({
|
|
|
111
113
|
...acc,
|
|
112
114
|
[result.value.address]: result.value.balances,
|
|
113
115
|
};
|
|
114
|
-
}, {} as
|
|
116
|
+
}, {} as GetEvmBalancesResponse);
|
|
115
117
|
|
|
116
118
|
return filterBalances;
|
|
117
119
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BN } from 'bn.js';
|
|
2
1
|
import { getErc20Balances } from './get-erc20-balances';
|
|
3
2
|
import type { EvmGlacierService } from '../../../services/glacier-service/glacier-service';
|
|
4
3
|
|
|
@@ -45,7 +44,7 @@ describe('get-erc20-balances', () => {
|
|
|
45
44
|
symbol: 'ETH',
|
|
46
45
|
decimals: 18,
|
|
47
46
|
logoUri: 'https://example.com/logo.png',
|
|
48
|
-
balance:
|
|
47
|
+
balance: 1000000000000000000n,
|
|
49
48
|
balanceCurrencyDisplayValue: '1000',
|
|
50
49
|
balanceDisplayValue: '1',
|
|
51
50
|
balanceInCurrency: 1000,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TokenUnit } from '@avalabs/utils-sdk';
|
|
2
2
|
import {
|
|
3
|
+
type ERC20Token,
|
|
3
4
|
TokenType,
|
|
5
|
+
type TokenWithBalanceEVM,
|
|
4
6
|
type TokenWithBalanceERC20,
|
|
5
|
-
type TokenWithBalance,
|
|
6
|
-
type ERC20Token,
|
|
7
7
|
} from '@avalabs/vm-module-types';
|
|
8
8
|
import { CurrencyCode, Erc20TokenBalance } from '@avalabs/glacier-sdk';
|
|
9
|
-
import BN from 'bn.js';
|
|
10
9
|
import type { EvmGlacierService } from '../../../services/glacier-service/glacier-service';
|
|
11
10
|
import { DEFAULT_DECIMALS } from '../../../constants';
|
|
12
11
|
|
|
@@ -22,7 +21,7 @@ export const getErc20Balances = async ({
|
|
|
22
21
|
currency: string;
|
|
23
22
|
chainId: number;
|
|
24
23
|
customTokens: ERC20Token[];
|
|
25
|
-
}): Promise<Record<string,
|
|
24
|
+
}): Promise<Record<string, TokenWithBalanceEVM>> => {
|
|
26
25
|
const tokensWithBalance: TokenWithBalanceERC20[] = [];
|
|
27
26
|
/**
|
|
28
27
|
* Load all pages to make sure we have all the tokens with balances
|
|
@@ -56,7 +55,7 @@ export const getErc20Balances = async ({
|
|
|
56
55
|
(acc, token) => {
|
|
57
56
|
return { ...acc, [token.address.toLowerCase()]: token };
|
|
58
57
|
},
|
|
59
|
-
{} as Record<string,
|
|
58
|
+
{} as Record<string, TokenWithBalanceEVM>,
|
|
60
59
|
);
|
|
61
60
|
};
|
|
62
61
|
|
|
@@ -66,7 +65,7 @@ const convertErc20TokenToTokenWithBalance = (tokens: ERC20Token[]): TokenWithBal
|
|
|
66
65
|
...token,
|
|
67
66
|
decimals: token.decimals ?? DEFAULT_DECIMALS,
|
|
68
67
|
type: TokenType.ERC20,
|
|
69
|
-
balance:
|
|
68
|
+
balance: 0n,
|
|
70
69
|
balanceInCurrency: 0,
|
|
71
70
|
balanceDisplayValue: '0',
|
|
72
71
|
balanceCurrencyDisplayValue: '0',
|
|
@@ -83,13 +82,11 @@ const convertErc20TokenWithBalanceToTokenWithBalance = (
|
|
|
83
82
|
chainId: number,
|
|
84
83
|
): TokenWithBalanceERC20[] => {
|
|
85
84
|
return tokenBalances.map((token: Erc20TokenBalance): TokenWithBalanceERC20 => {
|
|
86
|
-
const balance = new
|
|
87
|
-
const balanceDisplayValue =
|
|
85
|
+
const balance = new TokenUnit(token.balance, token.decimals, token.symbol);
|
|
86
|
+
const balanceDisplayValue = balance.toDisplay();
|
|
88
87
|
const balanceCurrencyDisplayValue = token.balanceValue?.value.toString();
|
|
89
88
|
const priceInCurrency = token.price?.value;
|
|
90
|
-
const balanceInCurrency = priceInCurrency
|
|
91
|
-
? bnToBig(balance, token.decimals).mul(priceInCurrency).toNumber()
|
|
92
|
-
: undefined;
|
|
89
|
+
const balanceInCurrency = priceInCurrency ? Number(balance.mul(priceInCurrency).toDisplay(2)) : undefined;
|
|
93
90
|
|
|
94
91
|
return {
|
|
95
92
|
chainId,
|
|
@@ -98,7 +95,7 @@ const convertErc20TokenWithBalanceToTokenWithBalance = (
|
|
|
98
95
|
symbol: token.symbol,
|
|
99
96
|
decimals: token.decimals,
|
|
100
97
|
logoUri: token.logoUri,
|
|
101
|
-
balance,
|
|
98
|
+
balance: balance.toSubUnit(),
|
|
102
99
|
balanceCurrencyDisplayValue,
|
|
103
100
|
balanceDisplayValue,
|
|
104
101
|
balanceInCurrency,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BN } from 'bn.js';
|
|
2
1
|
import { getNativeTokenBalances } from './get-native-token-balances';
|
|
3
2
|
import type { EvmGlacierService } from '../../../services/glacier-service/glacier-service';
|
|
4
3
|
|
|
@@ -8,7 +7,7 @@ describe('get-native-token-balances', () => {
|
|
|
8
7
|
...expect.any(Object),
|
|
9
8
|
getNativeBalance: jest.fn().mockResolvedValue({
|
|
10
9
|
nativeTokenBalance: {
|
|
11
|
-
balance:
|
|
10
|
+
balance: 1000000000000000000n,
|
|
12
11
|
decimals: 18,
|
|
13
12
|
name: 'Ethereum',
|
|
14
13
|
symbol: 'ETH',
|
|
@@ -34,7 +33,7 @@ describe('get-native-token-balances', () => {
|
|
|
34
33
|
decimals: 18,
|
|
35
34
|
type: 'NATIVE',
|
|
36
35
|
logoUri: 'https://example.com/logo.png',
|
|
37
|
-
balance:
|
|
36
|
+
balance: 1000000000000000000n,
|
|
38
37
|
balanceDisplayValue: '1',
|
|
39
38
|
balanceInCurrency: 1000,
|
|
40
39
|
balanceCurrencyDisplayValue: '1000.00',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { CurrencyCode } from '@avalabs/glacier-sdk';
|
|
2
2
|
import { TokenType, type NetworkTokenWithBalance } from '@avalabs/vm-module-types';
|
|
3
|
-
import {
|
|
4
|
-
import { BN } from 'bn.js';
|
|
3
|
+
import { TokenUnit } from '@avalabs/utils-sdk';
|
|
5
4
|
import type { EvmGlacierService } from '../../../services/glacier-service/glacier-service';
|
|
6
5
|
|
|
7
6
|
export const getNativeTokenBalances = async ({
|
|
@@ -23,13 +22,15 @@ export const getNativeTokenBalances = async ({
|
|
|
23
22
|
currency: currency.toLocaleLowerCase() as CurrencyCode,
|
|
24
23
|
});
|
|
25
24
|
const nativeTokenBalance = nativeBalance.nativeTokenBalance;
|
|
26
|
-
const
|
|
27
|
-
|
|
25
|
+
const balanceTokenUnit = new TokenUnit(
|
|
26
|
+
nativeTokenBalance.balance,
|
|
27
|
+
nativeTokenBalance.decimals,
|
|
28
|
+
nativeTokenBalance.symbol,
|
|
29
|
+
);
|
|
30
|
+
const balanceDisplayValue = balanceTokenUnit.toDisplay();
|
|
28
31
|
const priceInCurrency = nativeTokenBalance.price?.value;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
: undefined;
|
|
32
|
-
const balanceCurrencyDisplayValue = balanceInCurrency?.toFixed(2);
|
|
32
|
+
const balanceCurrencyDisplayValue = priceInCurrency ? balanceTokenUnit.mul(priceInCurrency).toDisplay(2) : undefined;
|
|
33
|
+
const balanceInCurrency = balanceCurrencyDisplayValue ? Number(balanceCurrencyDisplayValue) : undefined;
|
|
33
34
|
|
|
34
35
|
return {
|
|
35
36
|
name: nativeTokenBalance.name,
|
|
@@ -37,7 +38,7 @@ export const getNativeTokenBalances = async ({
|
|
|
37
38
|
decimals: nativeTokenBalance.decimals,
|
|
38
39
|
type: TokenType.NATIVE,
|
|
39
40
|
logoUri: nativeTokenBalance.logoUri,
|
|
40
|
-
balance,
|
|
41
|
+
balance: balanceTokenUnit.toSubUnit(),
|
|
41
42
|
balanceDisplayValue,
|
|
42
43
|
balanceInCurrency,
|
|
43
44
|
balanceCurrencyDisplayValue,
|