@subwallet/extension-base 1.1.24-0 → 1.1.24-1
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/background/KoniTypes.d.ts +1 -25
- package/cjs/constants/index.js +9 -3
- package/cjs/koni/api/staking/bonding/index.js +1 -0
- package/cjs/koni/api/tokens/evm/balance.js +5 -1
- package/cjs/koni/api/tokens/evm/transfer.js +8 -4
- package/cjs/koni/background/cron.js +2 -2
- package/cjs/koni/background/handlers/Extension.js +5 -5
- package/cjs/koni/background/handlers/Mobile.js +1 -1
- package/cjs/koni/background/handlers/State.js +123 -44
- package/cjs/koni/background/subscription.js +2 -2
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/helpers/group.js +53 -0
- package/cjs/services/balance-service/helpers/subscribe/balance.js +111 -0
- package/cjs/services/balance-service/helpers/subscribe/evm.js +95 -0
- package/cjs/services/balance-service/helpers/subscribe/substrate/equilibrium.js +113 -0
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +324 -0
- package/cjs/services/balance-service/index.js +41 -16
- package/cjs/services/history-service/helpers/subscan-extrinsic-parser-helper.js +7 -1
- package/cjs/services/history-service/index.js +12 -8
- package/cjs/services/migration-service/scripts/MigrateProvider.js +1 -1
- package/cjs/services/storage-service/DatabaseService.js +7 -2
- package/cjs/services/storage-service/db-stores/Balance.js +9 -9
- package/cjs/services/subscan-service/index.js +66 -22
- package/cjs/services/transaction-service/index.js +4 -3
- package/cjs/types/balance.js +1 -0
- package/cjs/types/index.js +11 -0
- package/cjs/utils/{address.js → account.js} +32 -2
- package/cjs/utils/eth.js +7 -2
- package/cjs/utils/index.js +12 -0
- package/constants/index.d.ts +2 -0
- package/constants/index.js +2 -0
- package/koni/api/staking/bonding/index.js +1 -0
- package/koni/api/tokens/evm/balance.js +5 -1
- package/koni/api/tokens/evm/transfer.d.ts +1 -1
- package/koni/api/tokens/evm/transfer.js +8 -4
- package/koni/background/cron.js +3 -3
- package/koni/background/handlers/Extension.js +5 -5
- package/koni/background/handlers/Mobile.js +1 -1
- package/koni/background/handlers/State.d.ts +6 -4
- package/koni/background/handlers/State.js +111 -33
- package/koni/background/subscription.js +2 -2
- package/package.json +39 -14
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/group.d.ts +9 -0
- package/services/balance-service/helpers/group.js +46 -0
- package/services/balance-service/helpers/subscribe/balance.d.ts +4 -0
- package/services/balance-service/helpers/subscribe/balance.js +103 -0
- package/services/balance-service/helpers/subscribe/evm.d.ts +5 -0
- package/services/balance-service/helpers/subscribe/evm.js +87 -0
- package/services/balance-service/helpers/subscribe/substrate/equilibrium.d.ts +4 -0
- package/services/balance-service/helpers/subscribe/substrate/equilibrium.js +105 -0
- package/services/balance-service/helpers/subscribe/substrate/index.d.ts +4 -0
- package/services/balance-service/helpers/subscribe/substrate/index.js +316 -0
- package/services/balance-service/index.d.ts +24 -5
- package/services/balance-service/index.js +40 -14
- package/services/history-service/helpers/subscan-extrinsic-parser-helper.js +7 -1
- package/services/history-service/index.js +12 -8
- package/services/migration-service/scripts/MigrateProvider.js +1 -1
- package/services/storage-service/DatabaseService.d.ts +4 -2
- package/services/storage-service/DatabaseService.js +7 -2
- package/services/storage-service/databases/index.d.ts +2 -1
- package/services/storage-service/db-stores/Balance.d.ts +2 -2
- package/services/storage-service/db-stores/Balance.js +9 -9
- package/services/subscan-service/index.d.ts +11 -5
- package/services/subscan-service/index.js +66 -26
- package/services/subscan-service/types.d.ts +4 -0
- package/services/transaction-service/index.js +5 -4
- package/types/balance.d.ts +40 -0
- package/types/balance.js +1 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +1 -0
- package/utils/account.d.ts +15 -0
- package/utils/{address.js → account.js} +28 -0
- package/utils/eth.d.ts +1 -0
- package/utils/eth.js +4 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/cjs/koni/api/dotsama/balance.js +0 -464
- package/koni/api/dotsama/balance.d.ts +0 -6
- package/koni/api/dotsama/balance.js +0 -451
- package/utils/address.d.ts +0 -5
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { _AssetType } from '@subwallet/chain-list/types';
|
|
5
|
+
import { APIItemState } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { ASTAR_REFRESH_BALANCE_INTERVAL, SUB_TOKEN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants';
|
|
7
|
+
import { getEVMBalance } from '@subwallet/extension-base/koni/api/tokens/evm/balance';
|
|
8
|
+
import { getERC20Contract } from '@subwallet/extension-base/koni/api/tokens/evm/web3';
|
|
9
|
+
import { state } from '@subwallet/extension-base/koni/background/handlers';
|
|
10
|
+
import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils';
|
|
11
|
+
import { BN } from '@polkadot/util';
|
|
12
|
+
export function subscribeERC20Interval(addresses, chain, evmApiMap, callBack) {
|
|
13
|
+
let tokenList = {};
|
|
14
|
+
const erc20ContractMap = {};
|
|
15
|
+
const getTokenBalances = () => {
|
|
16
|
+
Object.values(tokenList).map(async tokenInfo => {
|
|
17
|
+
try {
|
|
18
|
+
const contract = erc20ContractMap[tokenInfo.slug];
|
|
19
|
+
const balances = await Promise.all(addresses.map(async address => {
|
|
20
|
+
try {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
|
|
22
|
+
return await contract.methods.balanceOf(address).call();
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e);
|
|
25
|
+
return '0';
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
const items = balances.map((balance, index) => {
|
|
29
|
+
return {
|
|
30
|
+
address: addresses[index],
|
|
31
|
+
tokenSlug: tokenInfo.slug,
|
|
32
|
+
free: new BN(balance || 0).toString(),
|
|
33
|
+
locked: '0',
|
|
34
|
+
state: APIItemState.READY
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
callBack(items);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.log(tokenInfo.slug, err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
tokenList = state.getAssetByChainAndAsset(chain, [_AssetType.ERC20]);
|
|
44
|
+
Object.entries(tokenList).forEach(([slug, tokenInfo]) => {
|
|
45
|
+
erc20ContractMap[slug] = getERC20Contract(chain, _getContractAddressOfToken(tokenInfo), evmApiMap);
|
|
46
|
+
});
|
|
47
|
+
getTokenBalances();
|
|
48
|
+
const interval = setInterval(getTokenBalances, SUB_TOKEN_REFRESH_BALANCE_INTERVAL);
|
|
49
|
+
return () => {
|
|
50
|
+
clearInterval(interval);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function subscribeEVMBalance(chain, addresses, evmApiMap, callback, tokenInfo) {
|
|
54
|
+
function getBalance() {
|
|
55
|
+
getEVMBalance(chain, addresses, evmApiMap).then(balances => {
|
|
56
|
+
return balances.map((balance, index) => {
|
|
57
|
+
return {
|
|
58
|
+
address: addresses[index],
|
|
59
|
+
tokenSlug: tokenInfo.slug,
|
|
60
|
+
state: APIItemState.READY,
|
|
61
|
+
free: new BN(balance || '0').toString(),
|
|
62
|
+
locked: '0'
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}).catch(e => {
|
|
66
|
+
console.error(`Error on get native balance with token ${tokenInfo.slug}`, e);
|
|
67
|
+
return addresses.map(address => {
|
|
68
|
+
return {
|
|
69
|
+
address: address,
|
|
70
|
+
tokenSlug: tokenInfo.slug,
|
|
71
|
+
state: APIItemState.READY,
|
|
72
|
+
free: '0',
|
|
73
|
+
locked: '0'
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}).then(items => {
|
|
77
|
+
callback(items);
|
|
78
|
+
}).catch(console.error);
|
|
79
|
+
}
|
|
80
|
+
getBalance();
|
|
81
|
+
const interval = setInterval(getBalance, ASTAR_REFRESH_BALANCE_INTERVAL);
|
|
82
|
+
const unsub2 = subscribeERC20Interval(addresses, chain, evmApiMap, callback);
|
|
83
|
+
return () => {
|
|
84
|
+
clearInterval(interval);
|
|
85
|
+
unsub2 && unsub2();
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BalanceItem } from '@subwallet/extension-base/types';
|
|
2
|
+
import { ApiPromise } from '@polkadot/api';
|
|
3
|
+
export declare function subscribeEquilibriumTokenBalance(addresses: string[], chain: string, api: ApiPromise, callBack: (rs: BalanceItem[]) => void, includeNativeToken?: boolean): Promise<() => void>;
|
|
4
|
+
export declare function subscribeEqBalanceAccountPallet(addresses: string[], chain: string, api: ApiPromise, callBack: (rs: BalanceItem[]) => void, includeNativeToken?: boolean): Promise<() => void>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { _AssetType } from '@subwallet/chain-list/types';
|
|
5
|
+
import { APIItemState } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { state } from '@subwallet/extension-base/koni/background/handlers';
|
|
7
|
+
import { _getTokenOnChainAssetId } from '@subwallet/extension-base/services/chain-service/utils';
|
|
8
|
+
import BigN from 'bignumber.js';
|
|
9
|
+
import { BN, BN_ZERO } from '@polkadot/util';
|
|
10
|
+
export async function subscribeEquilibriumTokenBalance(addresses, chain, api, callBack, includeNativeToken) {
|
|
11
|
+
const tokenTypes = includeNativeToken ? [_AssetType.NATIVE, _AssetType.LOCAL] : [_AssetType.LOCAL];
|
|
12
|
+
const tokenMap = state.getAssetByChainAndAsset(chain, tokenTypes);
|
|
13
|
+
try {
|
|
14
|
+
const unsub = await api.query.system.account.multi(addresses, balances => {
|
|
15
|
+
// Equilibrium customizes the SystemAccount pallet
|
|
16
|
+
Object.values(tokenMap).forEach(tokenInfo => {
|
|
17
|
+
const assetId = _getTokenOnChainAssetId(tokenInfo);
|
|
18
|
+
const items = balances.map((balance, index) => {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
|
|
20
|
+
const balancesData = JSON.parse(balance.data.toString());
|
|
21
|
+
const balanceList = balancesData.v0.balance;
|
|
22
|
+
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
const freeTokenBalance = balanceList.find(data => data[0] === parseInt(assetId));
|
|
25
|
+
const bnFreeTokenBalance = freeTokenBalance ? new BN(new BigN(freeTokenBalance[1].positive).toString()) : BN_ZERO;
|
|
26
|
+
return {
|
|
27
|
+
address: addresses[index],
|
|
28
|
+
free: bnFreeTokenBalance.toString(),
|
|
29
|
+
locked: '0',
|
|
30
|
+
// Equilibrium doesn't show locked balance
|
|
31
|
+
state: APIItemState.READY,
|
|
32
|
+
tokenSlug: tokenInfo.slug
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
callBack(items);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
return () => {
|
|
39
|
+
unsub();
|
|
40
|
+
};
|
|
41
|
+
} catch (e) {
|
|
42
|
+
Object.values(tokenMap).forEach(tokenInfo => {
|
|
43
|
+
const items = addresses.map(address => {
|
|
44
|
+
return {
|
|
45
|
+
address: address,
|
|
46
|
+
free: '0',
|
|
47
|
+
locked: '0',
|
|
48
|
+
// Equilibrium doesn't show locked balance
|
|
49
|
+
state: APIItemState.READY,
|
|
50
|
+
tokenSlug: tokenInfo.slug
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
callBack(items);
|
|
54
|
+
});
|
|
55
|
+
return () => {
|
|
56
|
+
// Empty
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
62
|
+
export async function subscribeEqBalanceAccountPallet(addresses, chain, api, callBack, includeNativeToken) {
|
|
63
|
+
const tokenTypes = includeNativeToken ? [_AssetType.NATIVE, _AssetType.LOCAL] : [_AssetType.LOCAL];
|
|
64
|
+
const tokenMap = state.getAssetByChainAndAsset(chain, tokenTypes);
|
|
65
|
+
const unsubList = Object.values(tokenMap).map(async tokenInfo => {
|
|
66
|
+
try {
|
|
67
|
+
const assetId = _getTokenOnChainAssetId(tokenInfo);
|
|
68
|
+
const unsub = await api.query.eqBalances.account.multi(addresses.map(address => [address, [assetId]]), balances => {
|
|
69
|
+
const items = balances.map((balance, index) => {
|
|
70
|
+
return {
|
|
71
|
+
address: addresses[index],
|
|
72
|
+
free: balance.asPositive.toString(),
|
|
73
|
+
locked: '0',
|
|
74
|
+
// Equilibrium doesn't show locked balance
|
|
75
|
+
state: APIItemState.READY,
|
|
76
|
+
tokenSlug: tokenInfo.slug
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
callBack(items);
|
|
80
|
+
});
|
|
81
|
+
return unsub;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.warn(err);
|
|
84
|
+
const items = addresses.map(address => {
|
|
85
|
+
return {
|
|
86
|
+
address: address,
|
|
87
|
+
free: '0',
|
|
88
|
+
locked: '0',
|
|
89
|
+
// Equilibrium doesn't show locked balance
|
|
90
|
+
state: APIItemState.READY,
|
|
91
|
+
tokenSlug: tokenInfo.slug
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
callBack(items);
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return () => {
|
|
99
|
+
unsubList.forEach(subProm => {
|
|
100
|
+
subProm.then(unsub => {
|
|
101
|
+
unsub && unsub();
|
|
102
|
+
}).catch(console.error);
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
|
+
import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
3
|
+
import { BalanceItem } from '@subwallet/extension-base/types';
|
|
4
|
+
export declare function subscribeSubstrateBalance(addresses: string[], chainInfo: _ChainInfo, chain: string, networkAPI: _SubstrateApi, evmApiMap: Record<string, _EvmApi>, callBack: (rs: BalanceItem[]) => void): Promise<() => void>;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { _AssetType } from '@subwallet/chain-list/types';
|
|
5
|
+
import { APIItemState } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { SUB_TOKEN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants';
|
|
7
|
+
import { getPSP22ContractPromise } from '@subwallet/extension-base/koni/api/tokens/wasm';
|
|
8
|
+
import { getDefaultWeightV2 } from '@subwallet/extension-base/koni/api/tokens/wasm/utils';
|
|
9
|
+
import { state } from '@subwallet/extension-base/koni/background/handlers';
|
|
10
|
+
import { subscribeERC20Interval } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/evm';
|
|
11
|
+
import { _BALANCE_CHAIN_GROUP, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants';
|
|
12
|
+
import { _checkSmartContractSupportByChain, _getChainNativeTokenSlug, _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _isChainEvmCompatible, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
13
|
+
import { BN, BN_ZERO } from '@polkadot/util';
|
|
14
|
+
import { subscribeEqBalanceAccountPallet, subscribeEquilibriumTokenBalance } from "./equilibrium.js";
|
|
15
|
+
export async function subscribeSubstrateBalance(addresses, chainInfo, chain, networkAPI, evmApiMap, callBack) {
|
|
16
|
+
let unsubNativeToken;
|
|
17
|
+
if (!_BALANCE_CHAIN_GROUP.kintsugi.includes(chain) && !_BALANCE_CHAIN_GROUP.genshiro.includes(chain) && !_BALANCE_CHAIN_GROUP.equilibrium_parachain.includes(chain)) {
|
|
18
|
+
unsubNativeToken = await subscribeWithSystemAccountPallet(addresses, chainInfo, networkAPI.api, callBack);
|
|
19
|
+
}
|
|
20
|
+
let unsubLocalToken;
|
|
21
|
+
let unsubEvmContractToken;
|
|
22
|
+
let unsubWasmContractToken;
|
|
23
|
+
try {
|
|
24
|
+
if (_BALANCE_CHAIN_GROUP.bifrost.includes(chain)) {
|
|
25
|
+
unsubLocalToken = await subscribeTokensAccountsPallet(addresses, chain, networkAPI.api, callBack);
|
|
26
|
+
} else if (_BALANCE_CHAIN_GROUP.kintsugi.includes(chain)) {
|
|
27
|
+
unsubLocalToken = await subscribeTokensAccountsPallet(addresses, chain, networkAPI.api, callBack, true);
|
|
28
|
+
} else if (_BALANCE_CHAIN_GROUP.statemine.includes(chain)) {
|
|
29
|
+
unsubLocalToken = await subscribeAssetsAccountPallet(addresses, chain, networkAPI.api, callBack);
|
|
30
|
+
} else if (_BALANCE_CHAIN_GROUP.genshiro.includes(chain)) {
|
|
31
|
+
unsubLocalToken = await subscribeEqBalanceAccountPallet(addresses, chain, networkAPI.api, callBack, true);
|
|
32
|
+
} else if (_BALANCE_CHAIN_GROUP.equilibrium_parachain.includes(chain)) {
|
|
33
|
+
unsubLocalToken = await subscribeEquilibriumTokenBalance(addresses, chain, networkAPI.api, callBack, true);
|
|
34
|
+
} else if (_BALANCE_CHAIN_GROUP.centrifuge.includes(chain)) {
|
|
35
|
+
unsubLocalToken = await subscribeOrmlTokensPallet(addresses, chain, networkAPI.api, callBack);
|
|
36
|
+
}
|
|
37
|
+
if (_isChainEvmCompatible(chainInfo)) {
|
|
38
|
+
unsubEvmContractToken = subscribeERC20Interval(addresses, chain, evmApiMap, callBack);
|
|
39
|
+
}
|
|
40
|
+
if (_checkSmartContractSupportByChain(chainInfo, _AssetType.PSP22)) {
|
|
41
|
+
// Get sub-token for substrate-based chains
|
|
42
|
+
unsubWasmContractToken = subscribePSP22Balance(addresses, chain, networkAPI.api, callBack);
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.warn(err);
|
|
46
|
+
}
|
|
47
|
+
return () => {
|
|
48
|
+
unsubNativeToken && unsubNativeToken();
|
|
49
|
+
unsubLocalToken && unsubLocalToken();
|
|
50
|
+
unsubEvmContractToken && unsubEvmContractToken();
|
|
51
|
+
unsubWasmContractToken && unsubWasmContractToken();
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// handler according to different logic
|
|
56
|
+
async function subscribeWithSystemAccountPallet(addresses, chainInfo, networkAPI, callBack) {
|
|
57
|
+
const chainNativeTokenSlug = _getChainNativeTokenSlug(chainInfo);
|
|
58
|
+
|
|
59
|
+
// TODO: Need handle case error
|
|
60
|
+
const unsub = await networkAPI.query.system.account.multi(addresses, async balances => {
|
|
61
|
+
const pooledStakingBalances = [];
|
|
62
|
+
if (_isSubstrateRelayChain(chainInfo) && networkAPI.query.nominationPools) {
|
|
63
|
+
var _networkAPI$query$nom;
|
|
64
|
+
const poolMemberDatas = await ((_networkAPI$query$nom = networkAPI.query.nominationPools.poolMembers) === null || _networkAPI$query$nom === void 0 ? void 0 : _networkAPI$query$nom.multi(addresses));
|
|
65
|
+
if (poolMemberDatas) {
|
|
66
|
+
for (const _poolMemberData of poolMemberDatas) {
|
|
67
|
+
const poolMemberData = _poolMemberData.toPrimitive();
|
|
68
|
+
if (poolMemberData) {
|
|
69
|
+
let pooled = new BN(poolMemberData.points.toString());
|
|
70
|
+
Object.entries(poolMemberData.unbondingEras).forEach(([, amount]) => {
|
|
71
|
+
pooled = pooled.add(new BN(amount));
|
|
72
|
+
});
|
|
73
|
+
pooledStakingBalances.push(pooled);
|
|
74
|
+
} else {
|
|
75
|
+
pooledStakingBalances.push(BN_ZERO);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const items = balances.map((balance, index) => {
|
|
81
|
+
var _balance$data, _balance$data$free, _balance$data2, _balance$data2$reserv, _balance$data3, _balance$data3$miscFr, _balance$data4, _balance$data4$frozen, _balance$data5, _balance$data5$feeFro;
|
|
82
|
+
let total = ((_balance$data = balance.data) === null || _balance$data === void 0 ? void 0 : (_balance$data$free = _balance$data.free) === null || _balance$data$free === void 0 ? void 0 : _balance$data$free.toBn()) || new BN(0);
|
|
83
|
+
const reserved = ((_balance$data2 = balance.data) === null || _balance$data2 === void 0 ? void 0 : (_balance$data2$reserv = _balance$data2.reserved) === null || _balance$data2$reserv === void 0 ? void 0 : _balance$data2$reserv.toBn()) || new BN(0);
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
|
|
86
|
+
const miscFrozen = ((_balance$data3 = balance.data) === null || _balance$data3 === void 0 ? void 0 : (_balance$data3$miscFr = _balance$data3.miscFrozen) === null || _balance$data3$miscFr === void 0 ? void 0 : _balance$data3$miscFr.toBn()) || (balance === null || balance === void 0 ? void 0 : (_balance$data4 = balance.data) === null || _balance$data4 === void 0 ? void 0 : (_balance$data4$frozen = _balance$data4.frozen) === null || _balance$data4$frozen === void 0 ? void 0 : _balance$data4$frozen.toBn()) || new BN(0);
|
|
87
|
+
const feeFrozen = ((_balance$data5 = balance.data) === null || _balance$data5 === void 0 ? void 0 : (_balance$data5$feeFro = _balance$data5.feeFrozen) === null || _balance$data5$feeFro === void 0 ? void 0 : _balance$data5$feeFro.toBn()) || new BN(0);
|
|
88
|
+
let locked = reserved.add(miscFrozen);
|
|
89
|
+
total = total.add(reserved);
|
|
90
|
+
const pooledStakingBalance = pooledStakingBalances[index] || BN_ZERO;
|
|
91
|
+
if (pooledStakingBalance.gt(BN_ZERO)) {
|
|
92
|
+
total = total.add(pooledStakingBalance);
|
|
93
|
+
locked = locked.add(pooledStakingBalance);
|
|
94
|
+
}
|
|
95
|
+
const free = total.sub(locked);
|
|
96
|
+
return {
|
|
97
|
+
address: addresses[index],
|
|
98
|
+
tokenSlug: chainNativeTokenSlug,
|
|
99
|
+
free: free.gte(BN_ZERO) ? free.toString() : '0',
|
|
100
|
+
locked: locked.toString(),
|
|
101
|
+
state: APIItemState.READY,
|
|
102
|
+
substrateInfo: {
|
|
103
|
+
miscFrozen: miscFrozen.toString(),
|
|
104
|
+
reserved: reserved.toString(),
|
|
105
|
+
feeFrozen: feeFrozen.toString()
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
callBack(items);
|
|
110
|
+
});
|
|
111
|
+
return () => {
|
|
112
|
+
unsub();
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function subscribePSP22Balance(addresses, chain, api, callBack) {
|
|
116
|
+
let tokenList = {};
|
|
117
|
+
const psp22ContractMap = {};
|
|
118
|
+
const getTokenBalances = () => {
|
|
119
|
+
Object.values(tokenList).map(async tokenInfo => {
|
|
120
|
+
try {
|
|
121
|
+
const contract = psp22ContractMap[tokenInfo.slug];
|
|
122
|
+
const balances = await Promise.all(addresses.map(async address => {
|
|
123
|
+
try {
|
|
124
|
+
var _balanceOf$output, _ref;
|
|
125
|
+
const _balanceOf = await contract.query['psp22::balanceOf'](address, {
|
|
126
|
+
gasLimit: getDefaultWeightV2(api)
|
|
127
|
+
}, address);
|
|
128
|
+
const balanceObj = _balanceOf === null || _balanceOf === void 0 ? void 0 : (_balanceOf$output = _balanceOf.output) === null || _balanceOf$output === void 0 ? void 0 : _balanceOf$output.toPrimitive();
|
|
129
|
+
return {
|
|
130
|
+
address: address,
|
|
131
|
+
tokenSlug: tokenInfo.slug,
|
|
132
|
+
free: _balanceOf.output ? (_ref = balanceObj.ok) !== null && _ref !== void 0 ? _ref : balanceObj.Ok : '0',
|
|
133
|
+
locked: '0',
|
|
134
|
+
state: APIItemState.READY
|
|
135
|
+
};
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err);
|
|
138
|
+
return {
|
|
139
|
+
address: address,
|
|
140
|
+
tokenSlug: tokenInfo.slug,
|
|
141
|
+
free: '0',
|
|
142
|
+
locked: '0',
|
|
143
|
+
state: APIItemState.READY
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}));
|
|
147
|
+
callBack(balances);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
console.warn(tokenInfo.slug, err); // TODO: error createType
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
tokenList = state.getAssetByChainAndAsset(chain, [_AssetType.PSP22]);
|
|
155
|
+
Object.entries(tokenList).forEach(([slug, tokenInfo]) => {
|
|
156
|
+
psp22ContractMap[slug] = getPSP22ContractPromise(api, _getContractAddressOfToken(tokenInfo));
|
|
157
|
+
});
|
|
158
|
+
getTokenBalances();
|
|
159
|
+
const interval = setInterval(getTokenBalances, SUB_TOKEN_REFRESH_BALANCE_INTERVAL);
|
|
160
|
+
return () => {
|
|
161
|
+
clearInterval(interval);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async function subscribeTokensAccountsPallet(addresses, chain, api, callBack, includeNativeToken) {
|
|
165
|
+
const tokenTypes = includeNativeToken ? [_AssetType.NATIVE, _AssetType.LOCAL] : [_AssetType.LOCAL];
|
|
166
|
+
const tokenMap = state.getAssetByChainAndAsset(chain, tokenTypes);
|
|
167
|
+
const unsubList = await Promise.all(Object.values(tokenMap).map(async tokenInfo => {
|
|
168
|
+
try {
|
|
169
|
+
const onChainInfo = _getTokenOnChainInfo(tokenInfo);
|
|
170
|
+
const assetId = _getTokenOnChainAssetId(tokenInfo);
|
|
171
|
+
|
|
172
|
+
// Get Token Balance
|
|
173
|
+
// @ts-ignore
|
|
174
|
+
return await api.query.tokens.accounts.multi(addresses.map(address => [address, onChainInfo || assetId]), balances => {
|
|
175
|
+
const items = balances.map((balance, index) => {
|
|
176
|
+
const tokenBalance = {
|
|
177
|
+
reserved: balance.reserved || new BN(0),
|
|
178
|
+
frozen: balance.frozen || new BN(0),
|
|
179
|
+
free: balance.free || new BN(0) // free is actually total balance
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const freeBalance = tokenBalance.free.sub(tokenBalance.frozen);
|
|
183
|
+
const lockedBalance = tokenBalance.frozen.add(tokenBalance.reserved);
|
|
184
|
+
return {
|
|
185
|
+
address: addresses[index],
|
|
186
|
+
tokenSlug: tokenInfo.slug,
|
|
187
|
+
state: APIItemState.READY,
|
|
188
|
+
free: freeBalance.toString(),
|
|
189
|
+
locked: lockedBalance.toString(),
|
|
190
|
+
substrateInfo: {
|
|
191
|
+
reserved: tokenBalance.reserved.toString(),
|
|
192
|
+
miscFrozen: tokenBalance.frozen.toString()
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
callBack(items);
|
|
197
|
+
});
|
|
198
|
+
} catch (err) {
|
|
199
|
+
console.warn(err);
|
|
200
|
+
}
|
|
201
|
+
return undefined;
|
|
202
|
+
}));
|
|
203
|
+
return () => {
|
|
204
|
+
unsubList.forEach(unsub => {
|
|
205
|
+
unsub && unsub();
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function subscribeAssetsAccountPallet(addresses, chain, api, callBack) {
|
|
210
|
+
const tokenMap = state.getAssetByChainAndAsset(chain, [_AssetType.LOCAL]);
|
|
211
|
+
Object.values(tokenMap).forEach(token => {
|
|
212
|
+
if (_MANTA_ZK_CHAIN_GROUP.includes(token.originChain) && token.symbol.startsWith(_ZK_ASSET_PREFIX)) {
|
|
213
|
+
delete tokenMap[token.slug];
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
const unsubList = await Promise.all(Object.values(tokenMap).map(async tokenInfo => {
|
|
217
|
+
try {
|
|
218
|
+
const assetIndex = _getTokenOnChainAssetId(tokenInfo);
|
|
219
|
+
|
|
220
|
+
// Get Token Balance
|
|
221
|
+
return await api.query.assets.account.multi(addresses.map(address => [assetIndex, address]), balances => {
|
|
222
|
+
const items = balances.map((balance, index) => {
|
|
223
|
+
// @ts-ignore
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
|
225
|
+
const bdata = balance === null || balance === void 0 ? void 0 : balance.toHuman();
|
|
226
|
+
let frozen = BN_ZERO;
|
|
227
|
+
let total = BN_ZERO;
|
|
228
|
+
if (bdata) {
|
|
229
|
+
// @ts-ignore
|
|
230
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument
|
|
231
|
+
const addressBalance = new BN(String(bdata === null || bdata === void 0 ? void 0 : bdata.balance).replaceAll(',', '') || '0');
|
|
232
|
+
|
|
233
|
+
// @ts-ignore
|
|
234
|
+
if (bdata !== null && bdata !== void 0 && bdata.isFrozen) {
|
|
235
|
+
frozen = addressBalance;
|
|
236
|
+
} else {
|
|
237
|
+
total = addressBalance;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const free = total.sub(frozen);
|
|
241
|
+
return {
|
|
242
|
+
address: addresses[index],
|
|
243
|
+
tokenSlug: tokenInfo.slug,
|
|
244
|
+
free: free.toString(),
|
|
245
|
+
locked: frozen.toString(),
|
|
246
|
+
state: APIItemState.READY,
|
|
247
|
+
substrateInfo: {
|
|
248
|
+
miscFrozen: frozen.toString(),
|
|
249
|
+
reserved: '0'
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
});
|
|
253
|
+
callBack(items);
|
|
254
|
+
});
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.warn(err);
|
|
257
|
+
}
|
|
258
|
+
return undefined;
|
|
259
|
+
}));
|
|
260
|
+
return () => {
|
|
261
|
+
unsubList.forEach(unsub => {
|
|
262
|
+
unsub && unsub();
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
268
|
+
async function subscribeOrmlTokensPallet(addresses, chain, api, callBack) {
|
|
269
|
+
const tokenTypes = [_AssetType.LOCAL];
|
|
270
|
+
const tokenMap = state.getAssetByChainAndAsset(chain, tokenTypes);
|
|
271
|
+
const unsubList = Object.values(tokenMap).map(async tokenInfo => {
|
|
272
|
+
try {
|
|
273
|
+
const onChainInfo = _getTokenOnChainInfo(tokenInfo);
|
|
274
|
+
|
|
275
|
+
// Get Token Balance
|
|
276
|
+
// @ts-ignore
|
|
277
|
+
const unsub = await api.query.ormlTokens.accounts.multi(addresses.map(address => [address, onChainInfo]), balances => {
|
|
278
|
+
const items = balances.map((balance, index) => {
|
|
279
|
+
const tokenBalance = {
|
|
280
|
+
reserved: balance.reserved || new BN(0),
|
|
281
|
+
frozen: balance.frozen || new BN(0),
|
|
282
|
+
free: balance.free || new BN(0) // free is actually total balance
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// free balance = total balance - frozen misc
|
|
286
|
+
// locked balance = reserved + frozen misc
|
|
287
|
+
const freeBalance = tokenBalance.free.sub(tokenBalance.frozen);
|
|
288
|
+
const lockedBalance = tokenBalance.frozen.add(tokenBalance.reserved);
|
|
289
|
+
return {
|
|
290
|
+
address: addresses[index],
|
|
291
|
+
tokenSlug: tokenInfo.slug,
|
|
292
|
+
state: APIItemState.READY,
|
|
293
|
+
free: freeBalance.toString(),
|
|
294
|
+
locked: lockedBalance.toString(),
|
|
295
|
+
substrateInfo: {
|
|
296
|
+
reserved: tokenBalance.reserved.toString(),
|
|
297
|
+
miscFrozen: tokenBalance.frozen.toString()
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
callBack(items);
|
|
302
|
+
});
|
|
303
|
+
return unsub;
|
|
304
|
+
} catch (err) {
|
|
305
|
+
console.warn(err);
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
return () => {
|
|
310
|
+
unsubList.forEach(subProm => {
|
|
311
|
+
subProm.then(unsub => {
|
|
312
|
+
unsub && unsub();
|
|
313
|
+
}).catch(console.error);
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
}
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
-
import { AmountData
|
|
2
|
-
import
|
|
1
|
+
import { AmountData } from '@subwallet/extension-base/background/KoniTypes';
|
|
2
|
+
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
3
|
+
import { BalanceItem } from '@subwallet/extension-base/types';
|
|
4
|
+
/**
|
|
5
|
+
* Balance service
|
|
6
|
+
* @class
|
|
7
|
+
*/
|
|
3
8
|
export declare class BalanceService {
|
|
4
|
-
private
|
|
5
|
-
|
|
9
|
+
private state;
|
|
10
|
+
/**
|
|
11
|
+
* @constructor
|
|
12
|
+
* @param {KoniState} state - The state of extension.
|
|
13
|
+
*/
|
|
14
|
+
constructor(state: KoniState);
|
|
6
15
|
subscribeTokenFreeBalance(address: string, chain: string, tokenSlug: string | undefined, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
|
|
16
|
+
/**
|
|
17
|
+
* @public
|
|
18
|
+
* @async
|
|
19
|
+
* @function getTokenFreeBalance
|
|
20
|
+
* @desc Fetch free balance on chain
|
|
21
|
+
* @param {string} address - Address
|
|
22
|
+
* @param {string} chain - Slug of chain
|
|
23
|
+
* @param {string} [tokenSlug] - Slug of token
|
|
24
|
+
* @return {Promise<AmountData>} - Free token balance of address on chain
|
|
25
|
+
*/
|
|
7
26
|
getTokenFreeBalance(address: string, chain: string, tokenSlug?: string): Promise<AmountData>;
|
|
8
|
-
subscribeBalance(addresses: string[], chains: string[] | null,
|
|
27
|
+
subscribeBalance(addresses: string[], chains: string[] | null, _callback: (rs: BalanceItem) => void): () => void;
|
|
9
28
|
}
|
|
@@ -3,16 +3,25 @@
|
|
|
3
3
|
|
|
4
4
|
import { BalanceError } from '@subwallet/extension-base/background/errors/BalanceError';
|
|
5
5
|
import { BalanceErrorType } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { groupBalance } from '@subwallet/extension-base/services/balance-service/helpers/group';
|
|
7
|
+
import { subscribeEVMBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/evm';
|
|
8
|
+
import { subscribeSubstrateBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/substrate';
|
|
8
9
|
import { _PURE_EVM_CHAINS } from '@subwallet/extension-base/services/chain-service/constants';
|
|
9
10
|
import { _getChainNativeTokenSlug, _isChainEvmCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
10
11
|
import { categoryAddresses } from '@subwallet/extension-base/utils';
|
|
11
12
|
import { t } from 'i18next';
|
|
12
|
-
export class BalanceService {
|
|
13
|
-
constructor(chainService) {
|
|
14
|
-
this.chainService = chainService;
|
|
15
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Balance service
|
|
16
|
+
* @class
|
|
17
|
+
*/
|
|
18
|
+
export class BalanceService {
|
|
19
|
+
/**
|
|
20
|
+
* @constructor
|
|
21
|
+
* @param {KoniState} state - The state of extension.
|
|
22
|
+
*/
|
|
23
|
+
constructor(state) {
|
|
24
|
+
this.state = state;
|
|
16
25
|
// Todo: Load data from db to balanceSubject
|
|
17
26
|
// Todo: Start subscribe balance and data
|
|
18
27
|
// Todo: Listen change and apply to balanceSubject
|
|
@@ -23,9 +32,10 @@ export class BalanceService {
|
|
|
23
32
|
// Todo: Move everything of fetching balance to this service
|
|
24
33
|
}
|
|
25
34
|
|
|
35
|
+
/* Subscribe token free balance on chain */
|
|
26
36
|
async subscribeTokenFreeBalance(address, chain, tokenSlug, callback) {
|
|
27
|
-
const chainInfo = this.chainService.getChainInfoByKey(chain);
|
|
28
|
-
const chainState = this.chainService.getChainStateByKey(chain);
|
|
37
|
+
const chainInfo = this.state.chainService.getChainInfoByKey(chain);
|
|
38
|
+
const chainState = this.state.chainService.getChainStateByKey(chain);
|
|
29
39
|
if (!chainInfo || !chainState || !chainState.active) {
|
|
30
40
|
return Promise.reject(new BalanceError(BalanceErrorType.NETWORK_ERROR, t('{{chain}} is inactive. Please enable network', {
|
|
31
41
|
replace: {
|
|
@@ -34,7 +44,7 @@ export class BalanceService {
|
|
|
34
44
|
})));
|
|
35
45
|
}
|
|
36
46
|
const tSlug = tokenSlug || _getChainNativeTokenSlug(chainInfo);
|
|
37
|
-
const tokenInfo = this.chainService.getAssetBySlug(tSlug);
|
|
47
|
+
const tokenInfo = this.state.chainService.getAssetBySlug(tSlug);
|
|
38
48
|
if (!tokenInfo) {
|
|
39
49
|
return Promise.reject(new BalanceError(BalanceErrorType.TOKEN_ERROR, t('Transfer is currently not available for this token: {{tSlug}}', {
|
|
40
50
|
replace: {
|
|
@@ -69,28 +79,44 @@ export class BalanceService {
|
|
|
69
79
|
}, 9999);
|
|
70
80
|
});
|
|
71
81
|
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @public
|
|
85
|
+
* @async
|
|
86
|
+
* @function getTokenFreeBalance
|
|
87
|
+
* @desc Fetch free balance on chain
|
|
88
|
+
* @param {string} address - Address
|
|
89
|
+
* @param {string} chain - Slug of chain
|
|
90
|
+
* @param {string} [tokenSlug] - Slug of token
|
|
91
|
+
* @return {Promise<AmountData>} - Free token balance of address on chain
|
|
92
|
+
*/
|
|
72
93
|
async getTokenFreeBalance(address, chain, tokenSlug) {
|
|
73
94
|
const [, balance] = await this.subscribeTokenFreeBalance(address, chain, tokenSlug);
|
|
74
95
|
return balance;
|
|
75
96
|
}
|
|
76
|
-
subscribeBalance(addresses, chains,
|
|
97
|
+
subscribeBalance(addresses, chains, _callback) {
|
|
77
98
|
const [substrateAddresses, evmAddresses] = categoryAddresses(addresses);
|
|
78
|
-
const chainInfoMap = this.chainService.getChainInfoMap();
|
|
79
|
-
const chainStateMap = this.chainService.getChainStateMap();
|
|
80
|
-
const substrateApiMap = this.chainService.getSubstrateApiMap();
|
|
81
|
-
const evmApiMap = this.chainService.getEvmApiMap();
|
|
99
|
+
const chainInfoMap = this.state.chainService.getChainInfoMap();
|
|
100
|
+
const chainStateMap = this.state.chainService.getChainStateMap();
|
|
101
|
+
const substrateApiMap = this.state.chainService.getSubstrateApiMap();
|
|
102
|
+
const evmApiMap = this.state.chainService.getEvmApiMap();
|
|
82
103
|
|
|
83
104
|
// Get data from chain or all chains
|
|
84
105
|
const chainList = chains || Object.keys(chainInfoMap);
|
|
85
106
|
// Filter active chain only
|
|
86
107
|
const useChainInfos = chainList.filter(c => chainStateMap[c] && chainStateMap[c].active).map(c => chainInfoMap[c]);
|
|
108
|
+
const callback = items => {
|
|
109
|
+
if (items.length) {
|
|
110
|
+
_callback(groupBalance(items, 'GROUPED', items[0].tokenSlug));
|
|
111
|
+
}
|
|
112
|
+
};
|
|
87
113
|
|
|
88
114
|
// Looping over each chain
|
|
89
115
|
const unsubList = useChainInfos.map(async chainInfo => {
|
|
90
116
|
const chainSlug = chainInfo.slug;
|
|
91
117
|
const useAddresses = _isChainEvmCompatible(chainInfo) ? evmAddresses : substrateAddresses;
|
|
92
118
|
if (_isPureEvmChain(chainInfo)) {
|
|
93
|
-
const nativeTokenInfo = state.getNativeTokenInfo(chainSlug);
|
|
119
|
+
const nativeTokenInfo = this.state.getNativeTokenInfo(chainSlug);
|
|
94
120
|
return subscribeEVMBalance(chainSlug, useAddresses, evmApiMap, callback, nativeTokenInfo);
|
|
95
121
|
}
|
|
96
122
|
if (!useAddresses || useAddresses.length === 0 || _PURE_EVM_CHAINS.indexOf(chainSlug) > -1) {
|