@avalabs/avalanche-module 0.0.23 → 0.1.0
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/LICENSE +9 -0
- package/package.json +7 -2
- package/.turbo/turbo-build.log +0 -22
- package/.turbo/turbo-lint.log +0 -4
- package/.turbo/turbo-test.log +0 -12
- package/CHANGELOG.md +0 -99
- package/jest.config.js +0 -10
- package/src/env.ts +0 -25
- package/src/handlers/get-address/get-address.ts +0 -44
- package/src/handlers/get-balances/convert-p-chain-balance.ts +0 -91
- package/src/handlers/get-balances/covnert-x-chain-balance.ts +0 -74
- package/src/handlers/get-balances/get-balances.ts +0 -101
- package/src/handlers/get-balances/typeguards.ts +0 -9
- package/src/handlers/get-balances/utils.ts +0 -27
- package/src/handlers/get-network-fee/get-network-fee.test.ts +0 -19
- package/src/handlers/get-network-fee/get-network-fee.ts +0 -21
- package/src/handlers/get-transaction-history/convert-p-chain-transaction.ts +0 -132
- package/src/handlers/get-transaction-history/convert-x-chain-transaction.ts +0 -106
- package/src/handlers/get-transaction-history/get-transaction-history.ts +0 -59
- package/src/handlers/get-transaction-history/utils.ts +0 -31
- package/src/index.ts +0 -2
- package/src/module.ts +0 -72
- package/src/services/glacier-service/glacier-service.ts +0 -75
- package/src/utils/hash-blockchain-id.test.ts +0 -43
- package/src/utils/hash-blockchain-id.ts +0 -11
- package/tsconfig.jest.json +0 -7
- package/tsconfig.json +0 -14
- package/tsup.config.ts +0 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Copyright (C) 2021, Ava Labs, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
Subject to the limited license below (**”License””), you may not, and you may not permit anyone else to, copy, reproduce, aggregate, republish, download, post, distribute, license, sublicense, reverse engineer, modify, or create derivative works based on this software (collectively, **“Software”**).
|
|
4
|
+
|
|
5
|
+
You are hereby granted a limited, non-exclusive, non-sublicensable and non-transferable license to download and use the Software as-is solely (i) for use in connection with the Avalanche Public Blockchain platform, having a NetworkID of 1 (Mainnet) or 5 (Fuji), and associated blockchains, comprised exclusively of the Avalanche X-Chain, C-Chain, P-Chain and any subnets linked to the P-Chain (**“Avalanche Authorized Platform”**) or (ii) for non-production, testing or research purposes without any commercial application within the Avalanche ecosystem (**“Non-Commercial Use”**); provided that, in each case, you may not use or allow use of the Software (a) in connection with any forks of the Avalanche Authorized Platform, (b) in any manner not operationally connected to the Avalanche Authorized Platform other than for Non-Commercial Use, or (c) to the extent the number of monthly active users or the number of total installs of any software that uses the Software across all versions thereof exceeds 10,000 at any time. You may not modify or alter the Software in any way.
|
|
6
|
+
|
|
7
|
+
You hereby acknowledge and agree to the terms set forth at www.avalabs.org/important-notice.
|
|
8
|
+
|
|
9
|
+
**TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, AND AVA LABS EXPRESSLY DISCLAIMS AND EXCLUDES ALL REPRESENTATIONS, WARRANTIES AND OTHER TERMS AND CONDITIONS, WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION BY OPERATION OF LAW OR BY CUSTOM, STATUTE OR OTHERWISE, AND INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTY, TERM, OR CONDITION OF NON-INFRINGEMENT, MERCHANTABILITY, TITLE, OR FITNESS FOR PARTICULAR PURPOSE. YOU USE THE SOFTWARE AT YOUR OWN RISK. AVA LABS EXPRESSLY DISCLAIMS ALL LIABILITY (INCLUDING FOR ALL DIRECT, CONSEQUENTIAL OR OTHER DAMAGES OR LOSSES) RELATED TO ANY USE OF THE SOFTWARE.**
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avalabs/avalanche-module",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"main": "dist/index.cjs",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"manifest.json"
|
|
11
|
+
],
|
|
12
|
+
"license": "Limited Ecosystem License",
|
|
8
13
|
"dependencies": {
|
|
9
|
-
"@avalabs/vm-module-types": "0.0
|
|
14
|
+
"@avalabs/vm-module-types": "0.1.0",
|
|
10
15
|
"@metamask/rpc-errors": "6.3.0",
|
|
11
16
|
"@avalabs/utils-sdk": "v2.8.0-alpha.193",
|
|
12
17
|
"@avalabs/etherscan-sdk": "v2.8.0-alpha.193",
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @avalabs/avalanche-module@0.0.23 build /home/runner/work/vm-modules/vm-modules/packages/avalanche-module
|
|
3
|
-
> tsup
|
|
4
|
-
|
|
5
|
-
[34mCLI[39m Building entry: ./src/index.ts
|
|
6
|
-
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup v7.2.0
|
|
8
|
-
[34mCLI[39m Using tsup config: /home/runner/work/vm-modules/vm-modules/packages/avalanche-module/tsup.config.ts
|
|
9
|
-
[34mCLI[39m Target: es2021
|
|
10
|
-
[34mCLI[39m Cleaning output folder
|
|
11
|
-
[34mCJS[39m Build start
|
|
12
|
-
[34mESM[39m Build start
|
|
13
|
-
[32mESM[39m [1mdist/index.js [22m[32m16.73 KB[39m
|
|
14
|
-
[32mESM[39m [1mdist/index.js.map [22m[32m64.68 KB[39m
|
|
15
|
-
[32mESM[39m ⚡️ Build success in 2768ms
|
|
16
|
-
[32mCJS[39m [1mdist/index.cjs [22m[32m17.70 KB[39m
|
|
17
|
-
[32mCJS[39m [1mdist/index.cjs.map [22m[32m64.68 KB[39m
|
|
18
|
-
[32mCJS[39m ⚡️ Build success in 2797ms
|
|
19
|
-
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in 24712ms
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[32m1.68 KB[39m
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.68 KB[39m
|
package/.turbo/turbo-lint.log
DELETED
package/.turbo/turbo-test.log
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @avalabs/avalanche-module@0.0.23 test /home/runner/work/vm-modules/vm-modules/packages/avalanche-module
|
|
3
|
-
> jest
|
|
4
|
-
|
|
5
|
-
PASS src/utils/hash-blockchain-id.test.ts (27.639 s)
|
|
6
|
-
PASS src/handlers/get-network-fee/get-network-fee.test.ts
|
|
7
|
-
|
|
8
|
-
Test Suites: 2 passed, 2 total
|
|
9
|
-
Tests: 7 passed, 7 total
|
|
10
|
-
Snapshots: 0 total
|
|
11
|
-
Time: 29.674 s
|
|
12
|
-
Ran all test suites.
|
package/CHANGELOG.md
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# @avalabs/avalanche-module
|
|
2
|
-
|
|
3
|
-
## 0.0.23
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- bed2fcb: add transaction types for bitcoin module
|
|
8
|
-
- 898dde1: Add getAddress function
|
|
9
|
-
- Updated dependencies [fbdefd2]
|
|
10
|
-
- @avalabs/vm-module-types@0.0.23
|
|
11
|
-
|
|
12
|
-
## 0.0.22
|
|
13
|
-
|
|
14
|
-
### Patch Changes
|
|
15
|
-
|
|
16
|
-
- a841a90: handle all eth\_\* methods
|
|
17
|
-
- @avalabs/vm-module-types@0.0.22
|
|
18
|
-
|
|
19
|
-
## 0.0.21
|
|
20
|
-
|
|
21
|
-
### Patch Changes
|
|
22
|
-
|
|
23
|
-
- bb1478d: fix simplePrice caching logic
|
|
24
|
-
- @avalabs/vm-module-types@0.0.21
|
|
25
|
-
|
|
26
|
-
## 0.0.20
|
|
27
|
-
|
|
28
|
-
### Patch Changes
|
|
29
|
-
|
|
30
|
-
- Updated dependencies [9bfa82d]
|
|
31
|
-
- @avalabs/vm-module-types@0.0.20
|
|
32
|
-
|
|
33
|
-
## 0.0.19
|
|
34
|
-
|
|
35
|
-
### Patch Changes
|
|
36
|
-
|
|
37
|
-
- 5af458b: Add getBalances to avalanche-module
|
|
38
|
-
- Updated dependencies [5af458b]
|
|
39
|
-
- @avalabs/vm-module-types@0.0.19
|
|
40
|
-
|
|
41
|
-
## 0.0.18
|
|
42
|
-
|
|
43
|
-
### Patch Changes
|
|
44
|
-
|
|
45
|
-
- @avalabs/vm-module-types@0.0.18
|
|
46
|
-
|
|
47
|
-
## 0.0.17
|
|
48
|
-
|
|
49
|
-
### Patch Changes
|
|
50
|
-
|
|
51
|
-
- Updated dependencies [3590edf]
|
|
52
|
-
- @avalabs/vm-module-types@0.0.17
|
|
53
|
-
|
|
54
|
-
## 0.0.16
|
|
55
|
-
|
|
56
|
-
### Patch Changes
|
|
57
|
-
|
|
58
|
-
- f39ff3a: Fixe internal dependencies
|
|
59
|
-
- 2bb0a1a: add getHashedBlockchainId util to avalanche module
|
|
60
|
-
- Updated dependencies [bc48457]
|
|
61
|
-
- @avalabs/vm-module-types@0.0.16
|
|
62
|
-
|
|
63
|
-
## 0.0.15
|
|
64
|
-
|
|
65
|
-
### Patch Changes
|
|
66
|
-
|
|
67
|
-
- Updated dependencies [f536d58]
|
|
68
|
-
- @avalabs/vm-module-types@0.0.15
|
|
69
|
-
- @internal/utils@0.0.3
|
|
70
|
-
|
|
71
|
-
## 0.0.14
|
|
72
|
-
|
|
73
|
-
### Patch Changes
|
|
74
|
-
|
|
75
|
-
- 0593258: add getBalances to evm-module
|
|
76
|
-
- Updated dependencies [0593258]
|
|
77
|
-
- @avalabs/vm-module-types@0.0.14
|
|
78
|
-
- @internal/utils@0.0.2
|
|
79
|
-
|
|
80
|
-
## 0.0.13
|
|
81
|
-
|
|
82
|
-
### Patch Changes
|
|
83
|
-
|
|
84
|
-
- af68c81: Add getTransactionHistory to avalanche module
|
|
85
|
-
- d9fa0f5: added getNetworkFee to avalanche module
|
|
86
|
-
- Updated dependencies [af68c81]
|
|
87
|
-
- Updated dependencies [d9fa0f5]
|
|
88
|
-
- @avalabs/vm-module-types@0.0.13
|
|
89
|
-
|
|
90
|
-
## 0.0.12
|
|
91
|
-
|
|
92
|
-
### Patch Changes
|
|
93
|
-
|
|
94
|
-
- d0c2cc9: make module interface more consistent
|
|
95
|
-
- 02560da: Created Avalanche module
|
|
96
|
-
- Updated dependencies [cd97708]
|
|
97
|
-
- Updated dependencies [d0c2cc9]
|
|
98
|
-
- Updated dependencies [7bc6c6e]
|
|
99
|
-
- @avalabs/vm-module-types@0.0.12
|
package/jest.config.js
DELETED
package/src/env.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Environment } from '@avalabs/vm-module-types';
|
|
2
|
-
|
|
3
|
-
type Env = {
|
|
4
|
-
glacierApiUrl: string;
|
|
5
|
-
proxyApiUrl: string;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export const prodEnv: Env = {
|
|
9
|
-
glacierApiUrl: 'https://glacier-api.avax.network',
|
|
10
|
-
proxyApiUrl: 'https://proxy-api.avax.network',
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const devEnv: Env = {
|
|
14
|
-
glacierApiUrl: 'https://glacier-api-dev.avax.network',
|
|
15
|
-
proxyApiUrl: 'https://proxy-api-dev.avax.network',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const getEnv = (environment: Environment): Env => {
|
|
19
|
-
switch (environment) {
|
|
20
|
-
case Environment.PRODUCTION:
|
|
21
|
-
return prodEnv;
|
|
22
|
-
case Environment.DEV:
|
|
23
|
-
return devEnv;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { GetAddressParams, GetAddressResponse } from '@avalabs/vm-module-types';
|
|
2
|
-
import { Avalanche } from '@avalabs/wallets-sdk';
|
|
3
|
-
import { NetworkVMType, WalletType } from '@avalabs/vm-module-types';
|
|
4
|
-
import { rpcErrors } from '@metamask/rpc-errors';
|
|
5
|
-
|
|
6
|
-
type GetAddress = Omit<GetAddressParams, 'xpub'>;
|
|
7
|
-
|
|
8
|
-
export const getAddress = async ({
|
|
9
|
-
accountIndex,
|
|
10
|
-
isTestnet,
|
|
11
|
-
xpubXP,
|
|
12
|
-
walletType,
|
|
13
|
-
}: GetAddress): Promise<GetAddressResponse> => {
|
|
14
|
-
if (xpubXP === undefined) {
|
|
15
|
-
throw rpcErrors.invalidParams('xpubXP is required to get address');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const provXP = isTestnet
|
|
19
|
-
? Avalanche.JsonRpcProvider.getDefaultFujiProvider()
|
|
20
|
-
: Avalanche.JsonRpcProvider.getDefaultMainnetProvider();
|
|
21
|
-
let xpPub: Buffer;
|
|
22
|
-
|
|
23
|
-
switch (walletType) {
|
|
24
|
-
case WalletType.Mnemonic:
|
|
25
|
-
case WalletType.Ledger:
|
|
26
|
-
case WalletType.Keystone: {
|
|
27
|
-
// X and P addresses different derivation path m/44'/9000'/0'...
|
|
28
|
-
xpPub = Avalanche.getAddressPublicKeyFromXpub(xpubXP, accountIndex);
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
case WalletType.LedgerLive:
|
|
32
|
-
case WalletType.Seedless: {
|
|
33
|
-
xpPub = Buffer.from(xpubXP, 'hex');
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
default:
|
|
37
|
-
throw rpcErrors.invalidParams(`Unsupported wallet type: ${walletType}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
[NetworkVMType.AVM]: provXP.getAddress(xpPub, 'X'),
|
|
42
|
-
[NetworkVMType.PVM]: provXP.getAddress(xpPub, 'P'),
|
|
43
|
-
};
|
|
44
|
-
};
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { AggregatedAssetAmount, PChainBalance } from '@avalabs/glacier-sdk';
|
|
2
|
-
import { balanceToDisplayValue, bnToBig } from '@avalabs/utils-sdk';
|
|
3
|
-
import { BN } from 'bn.js';
|
|
4
|
-
import { calculateTotalBalance, getTokenValue } from './utils';
|
|
5
|
-
import { TokenType, type NetworkToken, type TokenWithBalancePVM } from '@avalabs/vm-module-types';
|
|
6
|
-
|
|
7
|
-
export const convertPChainBalance = ({
|
|
8
|
-
balance,
|
|
9
|
-
networkToken,
|
|
10
|
-
priceInCurrency,
|
|
11
|
-
marketCap,
|
|
12
|
-
vol24,
|
|
13
|
-
change24,
|
|
14
|
-
coingeckoId,
|
|
15
|
-
}: {
|
|
16
|
-
balance: PChainBalance;
|
|
17
|
-
networkToken: NetworkToken;
|
|
18
|
-
priceInCurrency?: number;
|
|
19
|
-
marketCap?: number;
|
|
20
|
-
vol24?: number;
|
|
21
|
-
change24?: number;
|
|
22
|
-
coingeckoId: string;
|
|
23
|
-
}): TokenWithBalancePVM => {
|
|
24
|
-
const decimals = networkToken.decimals;
|
|
25
|
-
const balancePerType: Record<string, number> = {};
|
|
26
|
-
|
|
27
|
-
const balanceTypes: Record<string, AggregatedAssetAmount[]> = {
|
|
28
|
-
unlockedUnstaked: balance.unlockedUnstaked,
|
|
29
|
-
unlockedStaked: balance.unlockedStaked,
|
|
30
|
-
pendingStaked: balance.pendingStaked,
|
|
31
|
-
lockedStaked: balance.lockedStaked,
|
|
32
|
-
lockedStakeable: balance.lockedStakeable,
|
|
33
|
-
lockedPlatform: balance.lockedPlatform,
|
|
34
|
-
atomicMemoryLocked: balance.atomicMemoryLocked,
|
|
35
|
-
atomicMemoryUnlocked: balance.atomicMemoryUnlocked,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
for (const balanceType in balanceTypes) {
|
|
39
|
-
const balancesToAdd = balanceTypes[balanceType];
|
|
40
|
-
if (!balancesToAdd || !balancesToAdd.length) {
|
|
41
|
-
balancePerType[balanceType] = 0;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
balancesToAdd.forEach((uxto: AggregatedAssetAmount) => {
|
|
46
|
-
const previousBalance = balancePerType[balanceType] ?? 0;
|
|
47
|
-
const newBalance = previousBalance + Number(uxto.amount);
|
|
48
|
-
balancePerType[balanceType] = newBalance;
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const available = balancePerType['unlockedUnstaked'] ? new BN(balancePerType['unlockedUnstaked']) : new BN(0);
|
|
53
|
-
const availableInCurrency = priceInCurrency
|
|
54
|
-
? bnToBig(available, decimals).mul(priceInCurrency).toNumber()
|
|
55
|
-
: undefined;
|
|
56
|
-
const availableDisplayValue = balanceToDisplayValue(available, decimals);
|
|
57
|
-
const totalBalance = calculateTotalBalance(balance);
|
|
58
|
-
const balanceInCurrency = priceInCurrency
|
|
59
|
-
? bnToBig(totalBalance, decimals).mul(priceInCurrency).toNumber()
|
|
60
|
-
: undefined;
|
|
61
|
-
const balanceDisplayValue = balanceToDisplayValue(totalBalance, decimals);
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
...networkToken,
|
|
65
|
-
type: TokenType.NATIVE,
|
|
66
|
-
priceInCurrency,
|
|
67
|
-
balance: totalBalance,
|
|
68
|
-
balanceInCurrency,
|
|
69
|
-
balanceDisplayValue,
|
|
70
|
-
balanceCurrencyDisplayValue: balanceInCurrency?.toFixed(2),
|
|
71
|
-
available,
|
|
72
|
-
availableInCurrency,
|
|
73
|
-
availableDisplayValue,
|
|
74
|
-
availableCurrencyDisplayValue: availableInCurrency?.toFixed(2),
|
|
75
|
-
utxos: balance,
|
|
76
|
-
balancePerType: {
|
|
77
|
-
lockedStaked: getTokenValue(decimals, balancePerType['lockedStaked']),
|
|
78
|
-
lockedStakeable: getTokenValue(decimals, balancePerType['lockedStakeable']),
|
|
79
|
-
lockedPlatform: getTokenValue(decimals, balancePerType['lockedPlatform']),
|
|
80
|
-
atomicMemoryLocked: getTokenValue(decimals, balancePerType['atomicMemoryLocked']),
|
|
81
|
-
atomicMemoryUnlocked: getTokenValue(decimals, balancePerType['atomicMemoryUnlocked']),
|
|
82
|
-
unlockedUnstaked: getTokenValue(decimals, balancePerType['unlockedUnstaked']),
|
|
83
|
-
unlockedStaked: getTokenValue(decimals, balancePerType['unlockedStaked']),
|
|
84
|
-
pendingStaked: getTokenValue(decimals, balancePerType['pendingStaked']),
|
|
85
|
-
},
|
|
86
|
-
marketCap,
|
|
87
|
-
vol24,
|
|
88
|
-
change24,
|
|
89
|
-
coingeckoId,
|
|
90
|
-
};
|
|
91
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { AggregatedAssetAmount, XChainBalances } from '@avalabs/glacier-sdk';
|
|
2
|
-
import { balanceToDisplayValue, bnToBig } from '@avalabs/utils-sdk';
|
|
3
|
-
import { calculateTotalBalance, getTokenValue } from './utils';
|
|
4
|
-
import { TokenType, type NetworkToken, type TokenWithBalanceAVM } from '@avalabs/vm-module-types';
|
|
5
|
-
|
|
6
|
-
export const convertXChainBalance = ({
|
|
7
|
-
balance,
|
|
8
|
-
networkToken,
|
|
9
|
-
priceInCurrency,
|
|
10
|
-
marketCap,
|
|
11
|
-
vol24,
|
|
12
|
-
change24,
|
|
13
|
-
coingeckoId,
|
|
14
|
-
}: {
|
|
15
|
-
balance: XChainBalances;
|
|
16
|
-
networkToken: NetworkToken;
|
|
17
|
-
priceInCurrency?: number;
|
|
18
|
-
marketCap?: number;
|
|
19
|
-
vol24?: number;
|
|
20
|
-
change24?: number;
|
|
21
|
-
coingeckoId: string;
|
|
22
|
-
}): TokenWithBalanceAVM => {
|
|
23
|
-
const decimals = networkToken.decimals;
|
|
24
|
-
const balancePerType: Record<string, number> = {};
|
|
25
|
-
|
|
26
|
-
const balanceTypes: Record<string, AggregatedAssetAmount[]> = {
|
|
27
|
-
unlocked: balance.unlocked,
|
|
28
|
-
locked: balance.locked,
|
|
29
|
-
atomicMemoryUnlocked: balance.atomicMemoryUnlocked,
|
|
30
|
-
atomicMemoryLocked: balance.atomicMemoryLocked,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
for (const balanceType in balanceTypes) {
|
|
34
|
-
const balancesToAdd = balanceTypes[balanceType];
|
|
35
|
-
if (!balancesToAdd || !balancesToAdd.length) {
|
|
36
|
-
balancePerType[balanceType] = 0;
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
balancesToAdd.forEach((uxto: AggregatedAssetAmount) => {
|
|
41
|
-
const previousBalance = balancePerType[balanceType] ?? 0;
|
|
42
|
-
const newBalance = previousBalance + Number(uxto.amount);
|
|
43
|
-
balancePerType[balanceType] = newBalance;
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const totalBalance = calculateTotalBalance(balance);
|
|
48
|
-
const balanceDisplayValue = balanceToDisplayValue(totalBalance, decimals);
|
|
49
|
-
const balanceInCurrency = priceInCurrency
|
|
50
|
-
? bnToBig(totalBalance, decimals).mul(priceInCurrency).toNumber()
|
|
51
|
-
: undefined;
|
|
52
|
-
const balanceCurrencyDisplayValue = balanceInCurrency?.toFixed(2);
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
...networkToken,
|
|
56
|
-
coingeckoId,
|
|
57
|
-
type: TokenType.NATIVE,
|
|
58
|
-
priceInCurrency,
|
|
59
|
-
balance: totalBalance,
|
|
60
|
-
balanceInCurrency,
|
|
61
|
-
balanceDisplayValue,
|
|
62
|
-
balanceCurrencyDisplayValue,
|
|
63
|
-
utxos: balance,
|
|
64
|
-
balancePerType: {
|
|
65
|
-
unlocked: getTokenValue(decimals, balancePerType['unlocked']),
|
|
66
|
-
locked: getTokenValue(decimals, balancePerType['locked']),
|
|
67
|
-
atomicMemoryUnlocked: getTokenValue(decimals, balancePerType['atomicMemoryUnlocked']),
|
|
68
|
-
atomicMemoryLocked: getTokenValue(decimals, balancePerType['atomicMemoryLocked']),
|
|
69
|
-
},
|
|
70
|
-
marketCap,
|
|
71
|
-
vol24,
|
|
72
|
-
change24,
|
|
73
|
-
};
|
|
74
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NetworkVMType,
|
|
3
|
-
type GetBalancesParams,
|
|
4
|
-
type TokenWithBalanceAVM,
|
|
5
|
-
type TokenWithBalancePVM,
|
|
6
|
-
} from '@avalabs/vm-module-types';
|
|
7
|
-
import { type AvalancheGlacierService } from '../../services/glacier-service/glacier-service';
|
|
8
|
-
import {
|
|
9
|
-
BlockchainId,
|
|
10
|
-
Network,
|
|
11
|
-
type ListPChainBalancesResponse,
|
|
12
|
-
type ListXChainBalancesResponse,
|
|
13
|
-
} from '@avalabs/glacier-sdk';
|
|
14
|
-
import type { TokenService } from '@internal/utils';
|
|
15
|
-
import { VsCurrencyType } from '@avalabs/coingecko-sdk';
|
|
16
|
-
import { isPchainBalance, isXchainBalance } from './utils';
|
|
17
|
-
import { convertPChainBalance } from './convert-p-chain-balance';
|
|
18
|
-
import { convertXChainBalance } from './covnert-x-chain-balance';
|
|
19
|
-
|
|
20
|
-
type GetAvalancheBalancesResponse = Record<string, Record<string, TokenWithBalanceAVM | TokenWithBalancePVM>>;
|
|
21
|
-
|
|
22
|
-
export const getBalances = async ({
|
|
23
|
-
addresses,
|
|
24
|
-
currency,
|
|
25
|
-
network,
|
|
26
|
-
glacierService,
|
|
27
|
-
tokenService,
|
|
28
|
-
}: GetBalancesParams & {
|
|
29
|
-
glacierService: AvalancheGlacierService;
|
|
30
|
-
tokenService: TokenService;
|
|
31
|
-
}): Promise<GetAvalancheBalancesResponse> => {
|
|
32
|
-
const isHealthy = glacierService.isHealthy();
|
|
33
|
-
if (!isHealthy) {
|
|
34
|
-
return Promise.reject('Glacier is unhealthy. Try again later.');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const lowercaseCurrency = currency.toLowerCase();
|
|
38
|
-
const address = addresses[0] ?? '';
|
|
39
|
-
const networkToken = network.networkToken;
|
|
40
|
-
const coingeckoId = network.pricingProviders?.coingecko.nativeTokenId;
|
|
41
|
-
|
|
42
|
-
const blockchainId = network.vmName === NetworkVMType.PVM ? BlockchainId.P_CHAIN : BlockchainId.X_CHAIN;
|
|
43
|
-
const networkName = network.isTestnet ? Network.FUJI : Network.MAINNET;
|
|
44
|
-
|
|
45
|
-
const chainBalances = await glacierService
|
|
46
|
-
.getChainBalance({
|
|
47
|
-
blockchainId,
|
|
48
|
-
network: networkName,
|
|
49
|
-
addresses: addresses.join(','),
|
|
50
|
-
})
|
|
51
|
-
.then((value) => (value as ListPChainBalancesResponse | ListXChainBalancesResponse).balances);
|
|
52
|
-
|
|
53
|
-
const simplePriceResponse = coingeckoId
|
|
54
|
-
? await tokenService.getSimplePrice({
|
|
55
|
-
coinIds: [coingeckoId],
|
|
56
|
-
currencies: [lowercaseCurrency] as VsCurrencyType[],
|
|
57
|
-
})
|
|
58
|
-
: {};
|
|
59
|
-
|
|
60
|
-
const priceInCurrency = simplePriceResponse?.[coingeckoId ?? '']?.[lowercaseCurrency]?.price ?? undefined;
|
|
61
|
-
const marketCap = simplePriceResponse?.[coingeckoId ?? '']?.[lowercaseCurrency]?.marketCap ?? undefined;
|
|
62
|
-
const vol24 = simplePriceResponse?.[coingeckoId ?? '']?.[lowercaseCurrency]?.vol24 ?? undefined;
|
|
63
|
-
const change24 = simplePriceResponse?.[coingeckoId ?? '']?.[lowercaseCurrency]?.change24 ?? undefined;
|
|
64
|
-
|
|
65
|
-
let balance: TokenWithBalanceAVM | TokenWithBalancePVM;
|
|
66
|
-
if (isPchainBalance(chainBalances)) {
|
|
67
|
-
balance = convertPChainBalance({
|
|
68
|
-
balance: chainBalances,
|
|
69
|
-
networkToken,
|
|
70
|
-
priceInCurrency,
|
|
71
|
-
marketCap,
|
|
72
|
-
vol24,
|
|
73
|
-
change24,
|
|
74
|
-
coingeckoId: coingeckoId ?? '',
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
[address]: {
|
|
79
|
-
[networkToken.symbol]: balance,
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (isXchainBalance(chainBalances)) {
|
|
85
|
-
balance = convertXChainBalance({
|
|
86
|
-
balance: chainBalances,
|
|
87
|
-
networkToken,
|
|
88
|
-
priceInCurrency,
|
|
89
|
-
marketCap,
|
|
90
|
-
vol24,
|
|
91
|
-
change24,
|
|
92
|
-
coingeckoId: coingeckoId ?? '',
|
|
93
|
-
});
|
|
94
|
-
return {
|
|
95
|
-
[address]: {
|
|
96
|
-
[networkToken.symbol]: balance,
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
return Promise.reject('Incorrect type balance was returned from glacier');
|
|
101
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { TokenWithBalance, TokenWithBalanceAVM, TokenWithBalancePVM } from '@avalabs/vm-module-types';
|
|
2
|
-
|
|
3
|
-
export const isTokenWithBalancePVM = (token: TokenWithBalance): token is TokenWithBalancePVM => {
|
|
4
|
-
return 'balancePerType' in token && 'unlockedUnstaked' in token.balancePerType;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const isTokenWithBalanceAVM = (token: TokenWithBalance): token is TokenWithBalanceAVM => {
|
|
8
|
-
return 'balancePerType' in token && 'unlocked' in token.balancePerType;
|
|
9
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { PChainBalance, XChainBalances } from '@avalabs/glacier-sdk';
|
|
2
|
-
import BN from 'bn.js';
|
|
3
|
-
|
|
4
|
-
export const isPchainBalance = (balanceResult: PChainBalance | XChainBalances): balanceResult is PChainBalance => {
|
|
5
|
-
return Object.keys(balanceResult).includes('unlockedUnstaked');
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export const isXchainBalance = (balanceResult: PChainBalance | XChainBalances): balanceResult is XChainBalances => {
|
|
9
|
-
return Object.keys(balanceResult).includes('locked');
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export function calculateTotalBalance(uxtos: PChainBalance | XChainBalances): BN {
|
|
13
|
-
const sum = Object.values(uxtos).reduce(function (totalAcc, utxoList) {
|
|
14
|
-
const typeSum = utxoList.reduce(function (typeAcc, utxo) {
|
|
15
|
-
const balanceToAdd = Number(utxo.amount);
|
|
16
|
-
return typeAcc + balanceToAdd;
|
|
17
|
-
}, 0);
|
|
18
|
-
|
|
19
|
-
return totalAcc + typeSum;
|
|
20
|
-
}, 0);
|
|
21
|
-
|
|
22
|
-
return new BN(sum);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getTokenValue(decimals: number, amount?: number) {
|
|
26
|
-
return amount === undefined ? 0 : amount / 10 ** decimals;
|
|
27
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { getNetworkFee } from './get-network-fee';
|
|
2
|
-
|
|
3
|
-
describe('get-network-fee', () => {
|
|
4
|
-
it('should return fixed network fees', async () => {
|
|
5
|
-
await expect(getNetworkFee()).resolves.toEqual({
|
|
6
|
-
baseFee: 1000000n,
|
|
7
|
-
low: {
|
|
8
|
-
maxFeePerGas: 1000000n,
|
|
9
|
-
},
|
|
10
|
-
medium: {
|
|
11
|
-
maxFeePerGas: 1000000n,
|
|
12
|
-
},
|
|
13
|
-
high: {
|
|
14
|
-
maxFeePerGas: 1000000n,
|
|
15
|
-
},
|
|
16
|
-
isFixedFee: true,
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { NetworkFees } from '@avalabs/vm-module-types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns {@link NetworkFees} based on a fixed fee.
|
|
5
|
-
*/
|
|
6
|
-
export async function getNetworkFee(): Promise<NetworkFees> {
|
|
7
|
-
// this is 0.001 Avax denominated in nAvax, taken from https://docs.avax.network/reference/standards/guides/txn-fees#fee-schedule
|
|
8
|
-
return {
|
|
9
|
-
baseFee: BigInt(1000000),
|
|
10
|
-
low: {
|
|
11
|
-
maxFeePerGas: BigInt(1000000),
|
|
12
|
-
},
|
|
13
|
-
medium: {
|
|
14
|
-
maxFeePerGas: BigInt(1000000),
|
|
15
|
-
},
|
|
16
|
-
high: {
|
|
17
|
-
maxFeePerGas: BigInt(1000000),
|
|
18
|
-
},
|
|
19
|
-
isFixedFee: true,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { type PChainTransaction, type NetworkToken } from '@avalabs/glacier-sdk';
|
|
2
|
-
import Big from 'big.js';
|
|
3
|
-
import { Avalanche } from '@avalabs/wallets-sdk';
|
|
4
|
-
import { TokenType, type Transaction } from '@avalabs/vm-module-types';
|
|
5
|
-
import { getExplorerAddressByNetwork, getTokenValue } from './utils';
|
|
6
|
-
|
|
7
|
-
export function convertPChainTransaction({
|
|
8
|
-
tx,
|
|
9
|
-
address,
|
|
10
|
-
networkToken,
|
|
11
|
-
chainId,
|
|
12
|
-
explorerUrl,
|
|
13
|
-
isTestnet,
|
|
14
|
-
}: {
|
|
15
|
-
tx: PChainTransaction;
|
|
16
|
-
address: string;
|
|
17
|
-
networkToken: NetworkToken;
|
|
18
|
-
chainId: number;
|
|
19
|
-
explorerUrl?: string;
|
|
20
|
-
isTestnet?: boolean;
|
|
21
|
-
}): Transaction {
|
|
22
|
-
const froms = new Set(tx.consumedUtxos.flatMap((utxo) => utxo.addresses) || []);
|
|
23
|
-
const tos = new Set(tx.emittedUtxos.flatMap((utxo) => utxo.addresses) || []);
|
|
24
|
-
|
|
25
|
-
const amount = getAmount({
|
|
26
|
-
tx,
|
|
27
|
-
isTestnet,
|
|
28
|
-
networkToken,
|
|
29
|
-
froms,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const avaxBurnedAmount = getBurnedAmount({ tx, isTestnet, networkToken });
|
|
33
|
-
const chainAddress = address.toLowerCase().startsWith('p-') ? address.slice(2) : address;
|
|
34
|
-
const isSender = froms.has(chainAddress);
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
hash: tx.txHash,
|
|
38
|
-
isContractCall: false,
|
|
39
|
-
isIncoming: !isSender,
|
|
40
|
-
isOutgoing: isSender,
|
|
41
|
-
from: [...froms.values()].join(','),
|
|
42
|
-
to: [...tos.values()].join(','),
|
|
43
|
-
isSender,
|
|
44
|
-
timestamp: tx.blockTimestamp * 1000, // to millis
|
|
45
|
-
tokens: [
|
|
46
|
-
{
|
|
47
|
-
decimal: networkToken.decimals.toString(),
|
|
48
|
-
name: networkToken.name,
|
|
49
|
-
symbol: networkToken.symbol,
|
|
50
|
-
type: TokenType.NATIVE,
|
|
51
|
-
amount: amount.toString(),
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
gasUsed: avaxBurnedAmount.toString(),
|
|
55
|
-
explorerLink: getExplorerAddressByNetwork(explorerUrl ?? '', tx.txHash, 'tx'),
|
|
56
|
-
txType: tx.txType,
|
|
57
|
-
chainId: chainId.toString(),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function getAmount({
|
|
62
|
-
tx,
|
|
63
|
-
isTestnet,
|
|
64
|
-
networkToken,
|
|
65
|
-
froms,
|
|
66
|
-
}: {
|
|
67
|
-
tx: PChainTransaction;
|
|
68
|
-
isTestnet?: boolean;
|
|
69
|
-
networkToken: NetworkToken;
|
|
70
|
-
froms: Set<string>;
|
|
71
|
-
}): Big {
|
|
72
|
-
const isImportExport = ['ImportTx', 'ExportTx'].includes(tx.txType);
|
|
73
|
-
const isBaseTx = tx.txType === 'BaseTx';
|
|
74
|
-
|
|
75
|
-
const nonChangeEmittedUtxosAmt = tx.emittedUtxos
|
|
76
|
-
.filter(
|
|
77
|
-
(utxo) => utxo.asset.assetId === getAvaxAssetId(!!isTestnet) && !utxo.addresses.some((addr) => froms.has(addr)),
|
|
78
|
-
)
|
|
79
|
-
.reduce((agg, utxo) => agg.add(utxo.asset.amount), new Big(0));
|
|
80
|
-
const txValue = tx.value.find((val) => val.assetId === getAvaxAssetId(!!isTestnet))?.amount;
|
|
81
|
-
// This ternary attempts to cover the case where users send themselves AVAX
|
|
82
|
-
// in which case the senders are the recipients and we should use the total tx value.
|
|
83
|
-
const baseTxValue = nonChangeEmittedUtxosAmt.gt(new Big(0))
|
|
84
|
-
? nonChangeEmittedUtxosAmt
|
|
85
|
-
: txValue
|
|
86
|
-
? new Big(txValue)
|
|
87
|
-
: new Big(0) ?? new Big(0);
|
|
88
|
-
|
|
89
|
-
const pBlockchainId = isTestnet ? Avalanche.FujiContext.pBlockchainID : Avalanche.MainnetContext.pBlockchainID;
|
|
90
|
-
|
|
91
|
-
const importExportAmount = tx.emittedUtxos
|
|
92
|
-
.filter(
|
|
93
|
-
(utxo) =>
|
|
94
|
-
utxo.asset.assetId === getAvaxAssetId(!!isTestnet) &&
|
|
95
|
-
((tx.txType === 'ImportTx' && utxo.consumedOnChainId === pBlockchainId) ||
|
|
96
|
-
(tx.txType === 'ExportTx' && utxo.consumedOnChainId !== pBlockchainId)),
|
|
97
|
-
)
|
|
98
|
-
.reduce((agg, utxo) => agg.add(utxo.amount), new Big(0));
|
|
99
|
-
const nAvaxAmount = isBaseTx
|
|
100
|
-
? baseTxValue
|
|
101
|
-
: isImportExport
|
|
102
|
-
? importExportAmount
|
|
103
|
-
: tx.amountStaked.length === 0
|
|
104
|
-
? aggregateValue(tx.value, !!isTestnet)
|
|
105
|
-
: aggregateValue(tx.amountStaked, !!isTestnet);
|
|
106
|
-
return getTokenValue({ amount: nAvaxAmount?.toNumber(), decimals: networkToken.decimals });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function getBurnedAmount({
|
|
110
|
-
tx,
|
|
111
|
-
isTestnet,
|
|
112
|
-
networkToken,
|
|
113
|
-
}: {
|
|
114
|
-
tx: PChainTransaction;
|
|
115
|
-
isTestnet?: boolean;
|
|
116
|
-
networkToken: NetworkToken;
|
|
117
|
-
}): Big {
|
|
118
|
-
const nAvaxFee = tx.amountBurned
|
|
119
|
-
?.filter((value) => value.assetId === getAvaxAssetId(!!isTestnet))
|
|
120
|
-
.reduce((accumulator, value) => accumulator.add(value.amount), new Big(0));
|
|
121
|
-
return getTokenValue({ amount: nAvaxFee?.toNumber(), decimals: networkToken.decimals });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function aggregateValue(value: PChainTransaction['value'], isTestnet: boolean): Big | undefined {
|
|
125
|
-
return value
|
|
126
|
-
.filter((value_) => value_.assetId === getAvaxAssetId(isTestnet))
|
|
127
|
-
.reduce((accumulator, value_) => accumulator.add(value_.amount), new Big(0));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function getAvaxAssetId(isTestnet: boolean): string {
|
|
131
|
-
return isTestnet ? Avalanche.FujiContext.avaxAssetID : Avalanche.MainnetContext.avaxAssetID;
|
|
132
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { type NetworkToken, XChainNonLinearTransaction, XChainLinearTransaction } from '@avalabs/glacier-sdk';
|
|
2
|
-
import Big from 'big.js';
|
|
3
|
-
import { Avalanche } from '@avalabs/wallets-sdk';
|
|
4
|
-
import { TokenType, type Transaction } from '@avalabs/vm-module-types';
|
|
5
|
-
import { getExplorerAddressByNetwork, getTokenValue } from './utils';
|
|
6
|
-
|
|
7
|
-
export function convertXChainTransaction({
|
|
8
|
-
tx,
|
|
9
|
-
address,
|
|
10
|
-
networkToken,
|
|
11
|
-
chainId,
|
|
12
|
-
explorerUrl,
|
|
13
|
-
isTestnet,
|
|
14
|
-
}: {
|
|
15
|
-
tx: XChainNonLinearTransaction | XChainLinearTransaction;
|
|
16
|
-
address: string;
|
|
17
|
-
networkToken: NetworkToken;
|
|
18
|
-
chainId: number;
|
|
19
|
-
isTestnet?: boolean;
|
|
20
|
-
explorerUrl?: string;
|
|
21
|
-
}): Transaction {
|
|
22
|
-
const froms = new Set(tx.consumedUtxos.flatMap((utxo) => utxo.addresses) || []);
|
|
23
|
-
const tos = new Set(tx.emittedUtxos.flatMap((utxo) => utxo.addresses) || []);
|
|
24
|
-
|
|
25
|
-
const amount = getAmount({
|
|
26
|
-
tx,
|
|
27
|
-
isTestnet,
|
|
28
|
-
networkToken,
|
|
29
|
-
});
|
|
30
|
-
const avaxBurnedAmount = getBurnedAmount({ isTestnet, tx, totalAmountCreated: amount, networkToken });
|
|
31
|
-
const chainAddress = address.toLowerCase().startsWith('x-') ? address.slice(2) : address;
|
|
32
|
-
const isSender = froms.has(chainAddress);
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
hash: tx.txHash,
|
|
36
|
-
isContractCall: false,
|
|
37
|
-
isIncoming: !isSender,
|
|
38
|
-
isOutgoing: isSender,
|
|
39
|
-
from: [...froms.values()].join(','),
|
|
40
|
-
to: [...tos.values()].join(','),
|
|
41
|
-
isSender,
|
|
42
|
-
timestamp: tx.timestamp * 1000, // to millis
|
|
43
|
-
tokens: [
|
|
44
|
-
{
|
|
45
|
-
decimal: networkToken.decimals.toString(),
|
|
46
|
-
name: networkToken.name,
|
|
47
|
-
symbol: networkToken.symbol,
|
|
48
|
-
type: TokenType.NATIVE,
|
|
49
|
-
amount: amount.toString(),
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
gasUsed: avaxBurnedAmount.toString(),
|
|
53
|
-
explorerLink: getExplorerAddressByNetwork(explorerUrl ?? '', tx.txHash, 'tx'),
|
|
54
|
-
txType: tx.txType,
|
|
55
|
-
chainId: chainId.toString(),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function getAmount({
|
|
60
|
-
tx,
|
|
61
|
-
isTestnet,
|
|
62
|
-
networkToken,
|
|
63
|
-
}: {
|
|
64
|
-
tx: XChainNonLinearTransaction | XChainLinearTransaction;
|
|
65
|
-
isTestnet?: boolean;
|
|
66
|
-
networkToken: NetworkToken;
|
|
67
|
-
}): Big {
|
|
68
|
-
const isImportExport = ['ImportTx', 'ExportTx'].includes(tx.txType);
|
|
69
|
-
const xBlockchainId = isTestnet ? Avalanche.FujiContext.xBlockchainID : Avalanche.MainnetContext.xBlockchainID;
|
|
70
|
-
const importExportAmount = tx.emittedUtxos
|
|
71
|
-
.filter(
|
|
72
|
-
(utxo) =>
|
|
73
|
-
utxo.asset.assetId === getAvaxAssetId(!!isTestnet) &&
|
|
74
|
-
((tx.txType === 'ImportTx' && utxo.consumedOnChainId === xBlockchainId) ||
|
|
75
|
-
(tx.txType === 'ExportTx' && utxo.consumedOnChainId !== xBlockchainId)),
|
|
76
|
-
)
|
|
77
|
-
.reduce((agg, utxo) => agg.add(utxo.asset.amount), new Big(0));
|
|
78
|
-
|
|
79
|
-
const totalAmountCreated = tx.amountCreated
|
|
80
|
-
.filter((asset) => asset.assetId === getAvaxAssetId(!!isTestnet))
|
|
81
|
-
.reduce((accumulator, asset) => accumulator.add(asset.amount), new Big(0));
|
|
82
|
-
const nAvaxAmt = isImportExport ? importExportAmount : totalAmountCreated;
|
|
83
|
-
return getTokenValue({ amount: nAvaxAmt.toNumber(), decimals: networkToken.decimals });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function getBurnedAmount({
|
|
87
|
-
isTestnet,
|
|
88
|
-
tx,
|
|
89
|
-
totalAmountCreated,
|
|
90
|
-
networkToken,
|
|
91
|
-
}: {
|
|
92
|
-
isTestnet?: boolean;
|
|
93
|
-
tx: XChainNonLinearTransaction | XChainLinearTransaction;
|
|
94
|
-
totalAmountCreated: Big;
|
|
95
|
-
networkToken: NetworkToken;
|
|
96
|
-
}): Big {
|
|
97
|
-
const totalAmountUnlocked = tx.amountUnlocked
|
|
98
|
-
.filter((asset) => asset.assetId === getAvaxAssetId(!!isTestnet))
|
|
99
|
-
.reduce((accumulator, asset) => accumulator.add(asset.amount), new Big(0));
|
|
100
|
-
const nAvaxFee = totalAmountUnlocked.minus(totalAmountCreated);
|
|
101
|
-
return getTokenValue({ amount: nAvaxFee.toNumber(), decimals: networkToken.decimals });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function getAvaxAssetId(isTestnet: boolean): string {
|
|
105
|
-
return isTestnet ? Avalanche.FujiContext.avaxAssetID : Avalanche.MainnetContext.avaxAssetID;
|
|
106
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { GetTransactionHistory, Transaction, TransactionHistoryResponse } from '@avalabs/vm-module-types';
|
|
2
|
-
import { BlockchainId, Network, SortOrder } from '@avalabs/glacier-sdk';
|
|
3
|
-
import { isPChainTransactions, isXChainTransactions } from './utils';
|
|
4
|
-
import { convertPChainTransaction } from './convert-p-chain-transaction';
|
|
5
|
-
import { convertXChainTransaction } from './convert-x-chain-transaction';
|
|
6
|
-
import type { AvalancheGlacierService } from '../../services/glacier-service/glacier-service';
|
|
7
|
-
|
|
8
|
-
export const getTransactionHistory = async ({
|
|
9
|
-
address,
|
|
10
|
-
nextPageToken,
|
|
11
|
-
offset,
|
|
12
|
-
network,
|
|
13
|
-
glacierService,
|
|
14
|
-
}: GetTransactionHistory & { glacierService: AvalancheGlacierService }): Promise<TransactionHistoryResponse> => {
|
|
15
|
-
const { isTestnet, networkToken, explorerUrl, chainId } = network;
|
|
16
|
-
const isHealthy = glacierService.isHealthy();
|
|
17
|
-
if (!isHealthy) {
|
|
18
|
-
return {
|
|
19
|
-
transactions: [],
|
|
20
|
-
nextPageToken: '',
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const response = await glacierService.listLatestPrimaryNetworkTransactions({
|
|
25
|
-
addresses: address,
|
|
26
|
-
blockchainId: getBlockchainIdByAddress(address),
|
|
27
|
-
network: isTestnet ? Network.FUJI : Network.MAINNET,
|
|
28
|
-
pageSize: offset,
|
|
29
|
-
pageToken: nextPageToken,
|
|
30
|
-
sortOrder: SortOrder.DESC,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
let transactions: Transaction[] = [];
|
|
34
|
-
if (isPChainTransactions(response)) {
|
|
35
|
-
transactions = response.transactions.map((value) =>
|
|
36
|
-
convertPChainTransaction({ tx: value, isTestnet, address, networkToken, explorerUrl, chainId }),
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
if (isXChainTransactions(response)) {
|
|
40
|
-
transactions = response.transactions.map((value) =>
|
|
41
|
-
convertXChainTransaction({ tx: value, isTestnet, address, networkToken, explorerUrl, chainId }),
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
transactions,
|
|
47
|
-
nextPageToken: response.nextPageToken,
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const getBlockchainIdByAddress = (address: string) => {
|
|
52
|
-
// A comma separated list of X-Chain or P-Chain wallet addresses,
|
|
53
|
-
// starting with "avax"/"fuji", "P-avax"/"P-fuji" or "X-avax"/"X-fuji"
|
|
54
|
-
const firstAddress = address.split(',')[0];
|
|
55
|
-
if (firstAddress?.toLowerCase().startsWith('p-')) {
|
|
56
|
-
return BlockchainId.P_CHAIN;
|
|
57
|
-
}
|
|
58
|
-
return BlockchainId.X_CHAIN;
|
|
59
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PrimaryNetworkChainName,
|
|
3
|
-
type ListCChainAtomicTransactionsResponse,
|
|
4
|
-
type ListPChainTransactionsResponse,
|
|
5
|
-
type ListXChainTransactionsResponse,
|
|
6
|
-
} from '@avalabs/glacier-sdk';
|
|
7
|
-
import Big from 'big.js';
|
|
8
|
-
|
|
9
|
-
export const isPChainTransactions = (
|
|
10
|
-
value: ListPChainTransactionsResponse | ListXChainTransactionsResponse | ListCChainAtomicTransactionsResponse,
|
|
11
|
-
): value is ListPChainTransactionsResponse => {
|
|
12
|
-
return value.chainInfo.chainName === PrimaryNetworkChainName.P_CHAIN;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const isXChainTransactions = (
|
|
16
|
-
value: ListPChainTransactionsResponse | ListXChainTransactionsResponse | ListCChainAtomicTransactionsResponse,
|
|
17
|
-
): value is ListXChainTransactionsResponse => {
|
|
18
|
-
return value.chainInfo.chainName === PrimaryNetworkChainName.X_CHAIN;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export function getExplorerAddressByNetwork(
|
|
22
|
-
explorerUrl: string,
|
|
23
|
-
hash: string,
|
|
24
|
-
hashType: 'address' | 'tx' = 'tx',
|
|
25
|
-
): string {
|
|
26
|
-
return `${explorerUrl}/${hashType}/${hash}`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getTokenValue({ amount, decimals }: { decimals: number; amount?: number }): Big {
|
|
30
|
-
return amount === undefined ? new Big(0) : new Big(amount / 10 ** decimals);
|
|
31
|
-
}
|
package/src/index.ts
DELETED
package/src/module.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Module,
|
|
3
|
-
Manifest,
|
|
4
|
-
NetworkFees,
|
|
5
|
-
GetTransactionHistory,
|
|
6
|
-
RpcRequest,
|
|
7
|
-
Network,
|
|
8
|
-
GetBalancesParams,
|
|
9
|
-
GetBalancesResponse,
|
|
10
|
-
Environment,
|
|
11
|
-
GetAddressParams,
|
|
12
|
-
GetAddressResponse,
|
|
13
|
-
} from '@avalabs/vm-module-types';
|
|
14
|
-
import { parseManifest } from '@avalabs/vm-module-types';
|
|
15
|
-
import { rpcErrors } from '@metamask/rpc-errors';
|
|
16
|
-
import ManifestJson from '../manifest.json';
|
|
17
|
-
import { getNetworkFee } from './handlers/get-network-fee/get-network-fee';
|
|
18
|
-
import { getTransactionHistory } from './handlers/get-transaction-history/get-transaction-history';
|
|
19
|
-
import { getEnv } from './env';
|
|
20
|
-
import { AvalancheGlacierService } from './services/glacier-service/glacier-service';
|
|
21
|
-
import { TokenService } from '@internal/utils';
|
|
22
|
-
import { getBalances } from './handlers/get-balances/get-balances';
|
|
23
|
-
import { hashBlockchainId } from './utils/hash-blockchain-id';
|
|
24
|
-
import { getAddress } from './handlers/get-address/get-address';
|
|
25
|
-
|
|
26
|
-
export class AvalancheModule implements Module {
|
|
27
|
-
#glacierService: AvalancheGlacierService;
|
|
28
|
-
#proxyApiUrl: string;
|
|
29
|
-
|
|
30
|
-
constructor({ environment }: { environment: Environment }) {
|
|
31
|
-
const { glacierApiUrl, proxyApiUrl } = getEnv(environment);
|
|
32
|
-
this.#glacierService = new AvalancheGlacierService({ glacierApiUrl });
|
|
33
|
-
this.#proxyApiUrl = proxyApiUrl;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getAddress({ accountIndex, xpubXP, isTestnet, walletType }: GetAddressParams): Promise<GetAddressResponse> {
|
|
37
|
-
return getAddress({ accountIndex, xpubXP, isTestnet, walletType });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getBalances({ addresses, network, storage, currency }: GetBalancesParams): Promise<GetBalancesResponse> {
|
|
41
|
-
const tokenService = new TokenService({ storage, proxyApiUrl: this.#proxyApiUrl });
|
|
42
|
-
return getBalances({ addresses, currency, network, glacierService: this.#glacierService, tokenService });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
getManifest(): Manifest | undefined {
|
|
46
|
-
const result = parseManifest(ManifestJson);
|
|
47
|
-
return result.success ? result.data : undefined;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
getNetworkFee(_: Network): Promise<NetworkFees> {
|
|
51
|
-
return getNetworkFee();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
getTransactionHistory({ network, address, nextPageToken, offset }: GetTransactionHistory) {
|
|
55
|
-
return getTransactionHistory({ network, address, nextPageToken, offset, glacierService: this.#glacierService });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
getTokens(_: Network) {
|
|
59
|
-
return Promise.resolve([]);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async onRpcRequest(request: RpcRequest, _network: Network) {
|
|
63
|
-
switch (request.method) {
|
|
64
|
-
default:
|
|
65
|
-
return { error: rpcErrors.methodNotSupported(`Method ${request.method} not supported`) };
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
static getHashedBlockchainId({ blockchainId, isTestnet }: { blockchainId: string; isTestnet?: boolean }): string {
|
|
70
|
-
return hashBlockchainId({ blockchainId, isTestnet });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BlockchainId,
|
|
3
|
-
Glacier,
|
|
4
|
-
type ListCChainAtomicBalancesResponse,
|
|
5
|
-
type ListCChainAtomicTransactionsResponse,
|
|
6
|
-
type ListPChainBalancesResponse,
|
|
7
|
-
type ListPChainTransactionsResponse,
|
|
8
|
-
type ListXChainBalancesResponse,
|
|
9
|
-
type ListXChainTransactionsResponse,
|
|
10
|
-
Network,
|
|
11
|
-
PrimaryNetworkTxType,
|
|
12
|
-
SortOrder,
|
|
13
|
-
} from '@avalabs/glacier-sdk';
|
|
14
|
-
|
|
15
|
-
class GlacierUnhealthyError extends Error {
|
|
16
|
-
override message = 'Glacier is unhealthy. Try again later.';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class AvalancheGlacierService {
|
|
20
|
-
glacierSdk: Glacier;
|
|
21
|
-
isGlacierHealthy = true;
|
|
22
|
-
|
|
23
|
-
constructor({ glacierApiUrl }: { glacierApiUrl: string }) {
|
|
24
|
-
this.glacierSdk = new Glacier({ BASE: glacierApiUrl });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
isHealthy = (): boolean => this.isGlacierHealthy;
|
|
28
|
-
|
|
29
|
-
setGlacierToUnhealthy(): void {
|
|
30
|
-
this.isGlacierHealthy = false;
|
|
31
|
-
setTimeout(
|
|
32
|
-
() => {
|
|
33
|
-
this.isGlacierHealthy = true;
|
|
34
|
-
},
|
|
35
|
-
5 * 60 * 1000,
|
|
36
|
-
); // 5 minutes
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async listLatestPrimaryNetworkTransactions(params: {
|
|
40
|
-
blockchainId: BlockchainId;
|
|
41
|
-
network: Network;
|
|
42
|
-
addresses?: string;
|
|
43
|
-
txTypes?: Array<PrimaryNetworkTxType>;
|
|
44
|
-
startTimestamp?: number;
|
|
45
|
-
endTimestamp?: number;
|
|
46
|
-
pageToken?: string;
|
|
47
|
-
pageSize?: number;
|
|
48
|
-
sortOrder?: SortOrder;
|
|
49
|
-
}): Promise<ListPChainTransactionsResponse | ListXChainTransactionsResponse | ListCChainAtomicTransactionsResponse> {
|
|
50
|
-
try {
|
|
51
|
-
return this.glacierSdk.primaryNetworkTransactions.listLatestPrimaryNetworkTransactions(params);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
if (error instanceof GlacierUnhealthyError) {
|
|
54
|
-
this.setGlacierToUnhealthy();
|
|
55
|
-
}
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async getChainBalance(params: {
|
|
61
|
-
blockchainId: BlockchainId;
|
|
62
|
-
network: Network;
|
|
63
|
-
blockTimestamp?: number;
|
|
64
|
-
addresses?: string;
|
|
65
|
-
}): Promise<ListPChainBalancesResponse | ListXChainBalancesResponse | ListCChainAtomicBalancesResponse> {
|
|
66
|
-
try {
|
|
67
|
-
return this.glacierSdk.primaryNetworkBalances.getBalancesByAddresses(params);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
if (error instanceof GlacierUnhealthyError) {
|
|
70
|
-
this.setGlacierToUnhealthy();
|
|
71
|
-
}
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { hashBlockchainId } from '../utils/hash-blockchain-id';
|
|
2
|
-
|
|
3
|
-
describe('hashBlockchainId', () => {
|
|
4
|
-
it('hashes the c-chain mainnet blockchain id', () => {
|
|
5
|
-
const result = hashBlockchainId({
|
|
6
|
-
blockchainId: '2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5',
|
|
7
|
-
});
|
|
8
|
-
expect(result).toBe('avax:8aDU0Kqh-5d23op-B-r-4YbQFRbsgF9a');
|
|
9
|
-
});
|
|
10
|
-
it('hashes the c-chain testnet blockchain id', () => {
|
|
11
|
-
const result = hashBlockchainId({
|
|
12
|
-
blockchainId: 'yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp',
|
|
13
|
-
isTestnet: true,
|
|
14
|
-
});
|
|
15
|
-
expect(result).toBe('avax:YRLfeDBJpfEqUWe2FYR1OpXsnDDZeKWd');
|
|
16
|
-
});
|
|
17
|
-
it('hashes the p-chain mainnet blockchain id', () => {
|
|
18
|
-
const result = hashBlockchainId({
|
|
19
|
-
blockchainId: '11111111111111111111111111111111LpoYY',
|
|
20
|
-
});
|
|
21
|
-
expect(result).toBe('avax:Rr9hnPVPxuUvrdCul-vjEsU1zmqKqRDo');
|
|
22
|
-
});
|
|
23
|
-
it('hashes the p-chain testnet blockchain id', () => {
|
|
24
|
-
const result = hashBlockchainId({
|
|
25
|
-
blockchainId: '11111111111111111111111111111111LpoYY',
|
|
26
|
-
isTestnet: true,
|
|
27
|
-
});
|
|
28
|
-
expect(result).toBe('avax:Sj7NVE3jXTbJvwFAiu7OEUo_8g8ctXMG');
|
|
29
|
-
});
|
|
30
|
-
it('hashes the x-chain mainnet blockchain id', () => {
|
|
31
|
-
const result = hashBlockchainId({
|
|
32
|
-
blockchainId: '2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM',
|
|
33
|
-
});
|
|
34
|
-
expect(result).toBe('avax:imji8papUf2EhV3le337w1vgFauqkJg-');
|
|
35
|
-
});
|
|
36
|
-
it('hashes the x-chain testnet blockchain id', () => {
|
|
37
|
-
const result = hashBlockchainId({
|
|
38
|
-
blockchainId: '2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm',
|
|
39
|
-
isTestnet: true,
|
|
40
|
-
});
|
|
41
|
-
expect(result).toBe('avax:8AJTpRj3SAqv1e80Mtl9em08LhvKEbkl');
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import Crypto from 'crypto';
|
|
2
|
-
|
|
3
|
-
//github.com/gergelylovas/chain-agnostic-namespaces/pull/1/files#diff-cf7185539a48e85d069d194c1c17d7cfa0317b3caa3a89c92e797e3717e49d59R40
|
|
4
|
-
export function hashBlockchainId({ blockchainId, isTestnet }: { blockchainId: string; isTestnet?: boolean }): string {
|
|
5
|
-
const blockChainIdWithPrefix = isTestnet ? 'fuji' + blockchainId : blockchainId;
|
|
6
|
-
const base64 = Crypto.createHash('sha256').update(blockChainIdWithPrefix).digest('base64');
|
|
7
|
-
const hash = convertBase64ToBase64Url(base64).substring(0, 32);
|
|
8
|
-
return 'avax:' + hash;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const convertBase64ToBase64Url = (base64: string) => base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
package/tsconfig.jest.json
DELETED
package/tsconfig.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@internal/tsconfig/tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "./dist",
|
|
5
|
-
"declaration": false,
|
|
6
|
-
"incremental": false // Need to turn off because of tsup dts
|
|
7
|
-
},
|
|
8
|
-
"include": ["src"],
|
|
9
|
-
"references": [
|
|
10
|
-
{
|
|
11
|
-
"path": "../../packages-internal/utils/tsconfig.json"
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
package/tsup.config.ts
DELETED