@talismn/balances 0.0.0-pr2075-20250703111149 → 0.0.0-pr2075-20250707042608
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/dist/declarations/src/NewBalanceModules.d.ts +99 -0
- package/dist/declarations/src/index.d.ts +2 -0
- package/dist/declarations/src/modules/EvmErc20Module.d.ts +1 -1
- package/dist/declarations/src/modules/IBalanceModule.d.ts +100 -0
- package/dist/declarations/src/modules/abis/index.d.ts +2 -0
- package/dist/declarations/src/modules/evm-erc20/config.d.ts +16 -0
- package/dist/declarations/src/modules/evm-erc20/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/evm-erc20/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/evm-erc20/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/evm-erc20/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/evm-erc20/index.d.ts +1 -0
- package/dist/declarations/src/modules/evm-erc20/module.d.ts +3 -0
- package/dist/declarations/src/modules/evm-erc20/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/evm-erc20/utils.d.ts +6 -0
- package/dist/declarations/src/modules/evm-native/config.d.ts +15 -0
- package/dist/declarations/src/modules/evm-native/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/evm-native/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/evm-native/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/evm-native/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/evm-native/index.d.ts +1 -0
- package/dist/declarations/src/modules/evm-native/module.d.ts +3 -0
- package/dist/declarations/src/modules/evm-native/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/config.d.ts +16 -0
- package/dist/declarations/src/modules/evm-uniswapv2/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/index.d.ts +1 -0
- package/dist/declarations/src/modules/evm-uniswapv2/module.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/evm-uniswapv2/utils.d.ts +12 -0
- package/dist/declarations/src/modules/index.d.ts +2 -1
- package/dist/declarations/src/modules/shared/errors.d.ts +11 -0
- package/dist/declarations/src/modules/shared/fetchRuntimeCallResult.d.ts +2 -0
- package/dist/declarations/src/modules/shared/getContantValue.d.ts +1 -0
- package/dist/declarations/src/modules/shared/hasConstantValue.d.ts +427 -0
- package/dist/declarations/src/modules/shared/index.d.ts +7 -0
- package/dist/declarations/src/modules/shared/tryGetConstantValue.d.ts +1 -0
- package/dist/declarations/src/modules/shared/types.d.ts +10 -0
- package/dist/declarations/src/modules/shared/utils.d.ts +4 -0
- package/dist/declarations/src/modules/substrate-assets/config.d.ts +16 -0
- package/dist/declarations/src/modules/substrate-assets/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-assets/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-assets/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-assets/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-assets/index.d.ts +1 -0
- package/dist/declarations/src/modules/substrate-assets/module.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-assets/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-foreignassets/config.d.ts +16 -0
- package/dist/declarations/src/modules/substrate-foreignassets/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-foreignassets/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-foreignassets/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-foreignassets/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-foreignassets/index.d.ts +1 -0
- package/dist/declarations/src/modules/substrate-foreignassets/module.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-foreignassets/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-hydration/config.d.ts +2 -0
- package/dist/declarations/src/modules/substrate-hydration/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-hydration/fetchTokens.d.ts +4 -0
- package/dist/declarations/src/modules/substrate-hydration/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-hydration/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-hydration/index.d.ts +2 -0
- package/dist/declarations/src/modules/substrate-hydration/module.d.ts +4 -0
- package/dist/declarations/src/modules/substrate-hydration/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-hydration/types.d.ts +14 -0
- package/dist/declarations/src/modules/substrate-native/bittensor/getSubtensorStakingBalances.d.ts +9 -0
- package/dist/declarations/src/modules/substrate-native/bittensor/subtensor.d.ts +20 -0
- package/dist/declarations/src/modules/substrate-native/config.d.ts +25 -0
- package/dist/declarations/src/modules/substrate-native/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-native/fetchTokens.d.ts +8 -0
- package/dist/declarations/src/modules/substrate-native/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-native/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-native/index.d.ts +1 -0
- package/dist/declarations/src/modules/substrate-native/module.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-native/queries/buildBaseQueries.d.ts +20 -0
- package/dist/declarations/src/modules/substrate-native/queries/buildNomPoolQueries.d.ts +8 -0
- package/dist/declarations/src/modules/substrate-native/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-native/util/lockTypes.d.ts +15 -0
- package/dist/declarations/src/modules/substrate-native/util/nompoolAccountId.d.ts +5 -0
- package/dist/declarations/src/modules/substrate-psp22/config.d.ts +16 -0
- package/dist/declarations/src/modules/substrate-psp22/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-psp22/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-psp22/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-psp22/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-psp22/index.d.ts +1 -0
- package/dist/declarations/src/modules/substrate-psp22/module.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-psp22/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-tokens/config.d.ts +23 -0
- package/dist/declarations/src/modules/substrate-tokens/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-tokens/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-tokens/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-tokens/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-tokens/index.d.ts +1 -0
- package/dist/declarations/src/modules/substrate-tokens/module.d.ts +3 -0
- package/dist/declarations/src/modules/substrate-tokens/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/util/RpcStateQueriesHelper.d.ts +12 -0
- package/dist/declarations/src/modules/util/buildStorageCoders.d.ts +2 -2
- package/dist/declarations/src/types/balances.d.ts +2 -1
- package/dist/declarations/src/types/minimetadatas.d.ts +1 -1
- package/dist/declarations/src/version.d.ts +1 -0
- package/dist/talismn-balances.cjs.dev.js +3901 -331
- package/dist/talismn-balances.cjs.prod.js +3901 -331
- package/dist/talismn-balances.esm.js +3887 -323
- package/package.json +8 -8
- package/dist/declarations/src/libVersion.d.ts +0 -1
- package/dist/declarations/src/modules/abis/erc20.d.ts +0 -227
@@ -9,8 +9,8 @@ var BigNumber = require('bignumber.js');
|
|
9
9
|
var util$1 = require('@polkadot/util');
|
10
10
|
var utilCrypto = require('@polkadot/util-crypto');
|
11
11
|
var pako = require('pako');
|
12
|
-
var z = require('zod/v4');
|
13
12
|
var viem = require('viem');
|
13
|
+
var z = require('zod/v4');
|
14
14
|
var lodash = require('lodash');
|
15
15
|
var isEqual = require('lodash/isEqual');
|
16
16
|
var txwrapperCore = require('@substrate/txwrapper-core');
|
@@ -73,11 +73,10 @@ const DefaultBalanceModule = type => ({
|
|
73
73
|
// internal
|
74
74
|
//
|
75
75
|
|
76
|
-
var
|
77
|
-
name: "@talismn/balances"
|
78
|
-
version: "0.0.0-pr2075-20250703111149"};
|
76
|
+
var packageJson = {
|
77
|
+
name: "@talismn/balances"};
|
79
78
|
|
80
|
-
var log = anylogger__default.default(
|
79
|
+
var log = anylogger__default.default(packageJson.name);
|
81
80
|
|
82
81
|
function excludeFromTransferableAmount(locks) {
|
83
82
|
if (typeof locks === "string") return BigInt(locks);
|
@@ -861,9 +860,8 @@ const getValueId = amount => {
|
|
861
860
|
const deriveMiniMetadataId = ({
|
862
861
|
source,
|
863
862
|
chainId,
|
864
|
-
specVersion
|
865
|
-
|
866
|
-
}) => util$1.u8aToHex(utilCrypto.xxhashAsU8a(new TextEncoder().encode(`${source}${chainId}${specVersion}${libVersion}`), 64), undefined, false);
|
863
|
+
specVersion
|
864
|
+
}) => util$1.u8aToHex(utilCrypto.xxhashAsU8a(new TextEncoder().encode(`${source}${chainId}${specVersion}${chaindataProvider.MINIMETADATA_VERSION}`), 64), undefined, false);
|
867
865
|
|
868
866
|
// for DB version 3, Wallet version 1.21.0
|
869
867
|
const upgradeRemoveSymbolFromNativeTokenId = async tx => {
|
@@ -962,234 +960,6 @@ const TokenConfigBaseSchema = chaindataProvider.TokenBaseSchema.partial().omit({
|
|
962
960
|
id: true
|
963
961
|
});
|
964
962
|
|
965
|
-
const erc20Abi = [{
|
966
|
-
constant: true,
|
967
|
-
inputs: [],
|
968
|
-
name: "name",
|
969
|
-
outputs: [{
|
970
|
-
name: "",
|
971
|
-
type: "string"
|
972
|
-
}],
|
973
|
-
payable: false,
|
974
|
-
stateMutability: "view",
|
975
|
-
type: "function"
|
976
|
-
}, {
|
977
|
-
constant: false,
|
978
|
-
inputs: [{
|
979
|
-
name: "_spender",
|
980
|
-
type: "address"
|
981
|
-
}, {
|
982
|
-
name: "_value",
|
983
|
-
type: "uint256"
|
984
|
-
}],
|
985
|
-
name: "approve",
|
986
|
-
outputs: [{
|
987
|
-
name: "",
|
988
|
-
type: "bool"
|
989
|
-
}],
|
990
|
-
payable: false,
|
991
|
-
stateMutability: "nonpayable",
|
992
|
-
type: "function"
|
993
|
-
}, {
|
994
|
-
constant: true,
|
995
|
-
inputs: [],
|
996
|
-
name: "totalSupply",
|
997
|
-
outputs: [{
|
998
|
-
name: "",
|
999
|
-
type: "uint256"
|
1000
|
-
}],
|
1001
|
-
payable: false,
|
1002
|
-
stateMutability: "view",
|
1003
|
-
type: "function"
|
1004
|
-
}, {
|
1005
|
-
constant: false,
|
1006
|
-
inputs: [{
|
1007
|
-
name: "_from",
|
1008
|
-
type: "address"
|
1009
|
-
}, {
|
1010
|
-
name: "_to",
|
1011
|
-
type: "address"
|
1012
|
-
}, {
|
1013
|
-
name: "_value",
|
1014
|
-
type: "uint256"
|
1015
|
-
}],
|
1016
|
-
name: "transferFrom",
|
1017
|
-
outputs: [{
|
1018
|
-
name: "",
|
1019
|
-
type: "bool"
|
1020
|
-
}],
|
1021
|
-
payable: false,
|
1022
|
-
stateMutability: "nonpayable",
|
1023
|
-
type: "function"
|
1024
|
-
}, {
|
1025
|
-
constant: true,
|
1026
|
-
inputs: [],
|
1027
|
-
name: "decimals",
|
1028
|
-
outputs: [{
|
1029
|
-
name: "",
|
1030
|
-
type: "uint8"
|
1031
|
-
}],
|
1032
|
-
payable: false,
|
1033
|
-
stateMutability: "view",
|
1034
|
-
type: "function"
|
1035
|
-
}, {
|
1036
|
-
constant: false,
|
1037
|
-
inputs: [{
|
1038
|
-
name: "_to",
|
1039
|
-
type: "address"
|
1040
|
-
}, {
|
1041
|
-
name: "_value",
|
1042
|
-
type: "uint256"
|
1043
|
-
}, {
|
1044
|
-
name: "_data",
|
1045
|
-
type: "bytes"
|
1046
|
-
}],
|
1047
|
-
name: "transferAndCall",
|
1048
|
-
outputs: [{
|
1049
|
-
name: "success",
|
1050
|
-
type: "bool"
|
1051
|
-
}],
|
1052
|
-
payable: false,
|
1053
|
-
stateMutability: "nonpayable",
|
1054
|
-
type: "function"
|
1055
|
-
}, {
|
1056
|
-
constant: false,
|
1057
|
-
inputs: [{
|
1058
|
-
name: "_spender",
|
1059
|
-
type: "address"
|
1060
|
-
}, {
|
1061
|
-
name: "_subtractedValue",
|
1062
|
-
type: "uint256"
|
1063
|
-
}],
|
1064
|
-
name: "decreaseApproval",
|
1065
|
-
outputs: [{
|
1066
|
-
name: "success",
|
1067
|
-
type: "bool"
|
1068
|
-
}],
|
1069
|
-
payable: false,
|
1070
|
-
stateMutability: "nonpayable",
|
1071
|
-
type: "function"
|
1072
|
-
}, {
|
1073
|
-
constant: true,
|
1074
|
-
inputs: [{
|
1075
|
-
name: "_owner",
|
1076
|
-
type: "address"
|
1077
|
-
}],
|
1078
|
-
name: "balanceOf",
|
1079
|
-
outputs: [{
|
1080
|
-
name: "balance",
|
1081
|
-
type: "uint256"
|
1082
|
-
}],
|
1083
|
-
payable: false,
|
1084
|
-
stateMutability: "view",
|
1085
|
-
type: "function"
|
1086
|
-
}, {
|
1087
|
-
constant: true,
|
1088
|
-
inputs: [],
|
1089
|
-
name: "symbol",
|
1090
|
-
outputs: [{
|
1091
|
-
name: "",
|
1092
|
-
type: "string"
|
1093
|
-
}],
|
1094
|
-
payable: false,
|
1095
|
-
stateMutability: "view",
|
1096
|
-
type: "function"
|
1097
|
-
}, {
|
1098
|
-
constant: false,
|
1099
|
-
inputs: [{
|
1100
|
-
name: "_to",
|
1101
|
-
type: "address"
|
1102
|
-
}, {
|
1103
|
-
name: "_value",
|
1104
|
-
type: "uint256"
|
1105
|
-
}],
|
1106
|
-
name: "transfer",
|
1107
|
-
outputs: [{
|
1108
|
-
name: "success",
|
1109
|
-
type: "bool"
|
1110
|
-
}],
|
1111
|
-
payable: false,
|
1112
|
-
stateMutability: "nonpayable",
|
1113
|
-
type: "function"
|
1114
|
-
}, {
|
1115
|
-
constant: false,
|
1116
|
-
inputs: [{
|
1117
|
-
name: "_spender",
|
1118
|
-
type: "address"
|
1119
|
-
}, {
|
1120
|
-
name: "_addedValue",
|
1121
|
-
type: "uint256"
|
1122
|
-
}],
|
1123
|
-
name: "increaseApproval",
|
1124
|
-
outputs: [{
|
1125
|
-
name: "success",
|
1126
|
-
type: "bool"
|
1127
|
-
}],
|
1128
|
-
payable: false,
|
1129
|
-
stateMutability: "nonpayable",
|
1130
|
-
type: "function"
|
1131
|
-
}, {
|
1132
|
-
constant: true,
|
1133
|
-
inputs: [{
|
1134
|
-
name: "_owner",
|
1135
|
-
type: "address"
|
1136
|
-
}, {
|
1137
|
-
name: "_spender",
|
1138
|
-
type: "address"
|
1139
|
-
}],
|
1140
|
-
name: "allowance",
|
1141
|
-
outputs: [{
|
1142
|
-
name: "remaining",
|
1143
|
-
type: "uint256"
|
1144
|
-
}],
|
1145
|
-
payable: false,
|
1146
|
-
stateMutability: "view",
|
1147
|
-
type: "function"
|
1148
|
-
}, {
|
1149
|
-
inputs: [],
|
1150
|
-
payable: false,
|
1151
|
-
stateMutability: "nonpayable",
|
1152
|
-
type: "constructor"
|
1153
|
-
}, {
|
1154
|
-
anonymous: false,
|
1155
|
-
inputs: [{
|
1156
|
-
indexed: true,
|
1157
|
-
name: "from",
|
1158
|
-
type: "address"
|
1159
|
-
}, {
|
1160
|
-
indexed: true,
|
1161
|
-
name: "to",
|
1162
|
-
type: "address"
|
1163
|
-
}, {
|
1164
|
-
indexed: false,
|
1165
|
-
name: "value",
|
1166
|
-
type: "uint256"
|
1167
|
-
}, {
|
1168
|
-
indexed: false,
|
1169
|
-
name: "data",
|
1170
|
-
type: "bytes"
|
1171
|
-
}],
|
1172
|
-
name: "Transfer",
|
1173
|
-
type: "event"
|
1174
|
-
}, {
|
1175
|
-
anonymous: false,
|
1176
|
-
inputs: [{
|
1177
|
-
indexed: true,
|
1178
|
-
name: "owner",
|
1179
|
-
type: "address"
|
1180
|
-
}, {
|
1181
|
-
indexed: true,
|
1182
|
-
name: "spender",
|
1183
|
-
type: "address"
|
1184
|
-
}, {
|
1185
|
-
indexed: false,
|
1186
|
-
name: "value",
|
1187
|
-
type: "uint256"
|
1188
|
-
}],
|
1189
|
-
name: "Approval",
|
1190
|
-
type: "event"
|
1191
|
-
}];
|
1192
|
-
|
1193
963
|
const erc20BalancesAggregatorAbi = viem.parseAbi(["struct AccountToken {address account; address token;}", "function balances(AccountToken[] memory accountTokens) public view returns (uint256[] memory)"]);
|
1194
964
|
|
1195
965
|
const moduleType$7 = "evm-erc20";
|
@@ -1345,7 +1115,7 @@ const EvmErc20Module = hydrate => {
|
|
1345
1115
|
const {
|
1346
1116
|
errors,
|
1347
1117
|
results
|
1348
|
-
} = await fetchBalances$
|
1118
|
+
} = await fetchBalances$c(chainConnectors.evm, {
|
1349
1119
|
[evmNetworkId]: fetchesPerNetwork[evmNetworkId]
|
1350
1120
|
}, aggregators);
|
1351
1121
|
|
@@ -1403,7 +1173,7 @@ const EvmErc20Module = hydrate => {
|
|
1403
1173
|
if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
|
1404
1174
|
const [aggregators, tokens] = await Promise.all([getErc20Aggregators(), getModuleTokens()]);
|
1405
1175
|
const fetchesPerNetwork = await prepareFetchParameters(addressesByToken, tokens);
|
1406
|
-
const balances = await fetchBalances$
|
1176
|
+
const balances = await fetchBalances$c(chainConnectors.evm, fetchesPerNetwork, aggregators);
|
1407
1177
|
return new Balances(balances.results);
|
1408
1178
|
}
|
1409
1179
|
};
|
@@ -1425,7 +1195,7 @@ class EvmErc20NetworkError extends Error {
|
|
1425
1195
|
this.evmNetworkId = evmNetworkId;
|
1426
1196
|
}
|
1427
1197
|
}
|
1428
|
-
const fetchBalances$
|
1198
|
+
const fetchBalances$c = async (evmChainConnector, tokenAddressesByNetwork, erc20Aggregators = {}) => {
|
1429
1199
|
const result = {
|
1430
1200
|
results: [],
|
1431
1201
|
errors: []
|
@@ -1458,7 +1228,7 @@ const getEvmTokenBalancesWithoutAggregator = async (client, balanceDefs, errors)
|
|
1458
1228
|
}) => {
|
1459
1229
|
try {
|
1460
1230
|
const balance = await client.readContract({
|
1461
|
-
abi: erc20Abi,
|
1231
|
+
abi: viem.erc20Abi,
|
1462
1232
|
address: token.contractAddress,
|
1463
1233
|
functionName: "balanceOf",
|
1464
1234
|
args: [address]
|
@@ -1600,7 +1370,7 @@ const EvmNativeModule = hydrate => {
|
|
1600
1370
|
if (!tokenId) throw new Error(`No native token for evm network ${evmNetworkId}`);
|
1601
1371
|
try {
|
1602
1372
|
if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
|
1603
|
-
const balances = await fetchBalances$
|
1373
|
+
const balances = await fetchBalances$b(chainConnectors.evm, {
|
1604
1374
|
[tokenId]: addresses
|
1605
1375
|
}, tokens);
|
1606
1376
|
const resultBalances = [];
|
@@ -1642,7 +1412,7 @@ const EvmNativeModule = hydrate => {
|
|
1642
1412
|
async fetchBalances(addressesByToken) {
|
1643
1413
|
if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
|
1644
1414
|
const tokens = await getModuleTokens();
|
1645
|
-
const balanceResults = await fetchBalances$
|
1415
|
+
const balanceResults = await fetchBalances$b(chainConnectors.evm, addressesByToken, tokens);
|
1646
1416
|
const pureBalances = balanceResults.flat().filter(b => !(b instanceof EvmNativeBalanceError) && BigInt(b.value) > 0n);
|
1647
1417
|
return new Balances(pureBalances);
|
1648
1418
|
}
|
@@ -1658,7 +1428,7 @@ class EvmNativeBalanceError extends Error {
|
|
1658
1428
|
}
|
1659
1429
|
}
|
1660
1430
|
}
|
1661
|
-
const fetchBalances$
|
1431
|
+
const fetchBalances$b = async (evmChainConnector, addressesByToken, tokens) => {
|
1662
1432
|
if (!evmChainConnector) throw new Error(`This module requires an evm chain connector`);
|
1663
1433
|
return Promise.all(Object.entries(addressesByToken).map(async ([tokenId, addresses]) => {
|
1664
1434
|
const token = tokens[tokenId];
|
@@ -2410,7 +2180,7 @@ const EvmUniswapV2Module = hydrate => {
|
|
2410
2180
|
}
|
2411
2181
|
try {
|
2412
2182
|
if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
|
2413
|
-
const balances = await fetchBalances$
|
2183
|
+
const balances = await fetchBalances$a(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
|
2414
2184
|
|
2415
2185
|
// Don't call callback with balances which have not changed since the last poll.
|
2416
2186
|
const json = balances.toJSON();
|
@@ -2439,11 +2209,11 @@ const EvmUniswapV2Module = hydrate => {
|
|
2439
2209
|
if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
|
2440
2210
|
const evmNetworks = await chaindataProvider$1.getNetworksMapById("ethereum");
|
2441
2211
|
const tokens = await chaindataProvider$1.getTokensMapById();
|
2442
|
-
return fetchBalances$
|
2212
|
+
return fetchBalances$a(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
|
2443
2213
|
}
|
2444
2214
|
};
|
2445
2215
|
};
|
2446
|
-
const fetchBalances$
|
2216
|
+
const fetchBalances$a = async (evmChainConnector, evmNetworks, tokens, addressesByToken) => {
|
2447
2217
|
const addressesByTokenGroupedByEvmNetwork = groupAddressesByTokenByEvmNetwork(addressesByToken, tokens);
|
2448
2218
|
const balances = (await Promise.allSettled(Object.entries(addressesByTokenGroupedByEvmNetwork).map(async ([networkId, addressesByToken]) => {
|
2449
2219
|
if (!evmChainConnector) throw new Error(`This module requires an evm chain connector`);
|
@@ -2583,8 +2353,6 @@ async function getPoolBalance(publicClient, contractAddress, accountAddress) {
|
|
2583
2353
|
}
|
2584
2354
|
}
|
2585
2355
|
|
2586
|
-
const libVersion = pkg.version;
|
2587
|
-
|
2588
2356
|
// cache the promise so it can be shared across multiple calls
|
2589
2357
|
const CACHE_GET_SPEC_VERSION = new Map();
|
2590
2358
|
const fetchSpecVersion = async (chainConnector, networkId) => {
|
@@ -2660,7 +2428,7 @@ const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, sp
|
|
2660
2428
|
}
|
2661
2429
|
};
|
2662
2430
|
const DotBalanceModuleTypeSchema = z__default.default.keyof(chaindataProvider.DotNetworkBalancesConfigSchema);
|
2663
|
-
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion, signal) => {
|
2431
|
+
const fetchMiniMetadatas = async (chainConnector, chaindataProvider$1, chainId, specVersion, signal) => {
|
2664
2432
|
const start = performance.now();
|
2665
2433
|
log.info("[miniMetadata] fetching minimetadatas for %s", chainId);
|
2666
2434
|
try {
|
@@ -2672,11 +2440,11 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
|
|
2672
2440
|
};
|
2673
2441
|
const modules = defaultBalanceModules.map(mod => mod({
|
2674
2442
|
chainConnectors,
|
2675
|
-
chaindataProvider
|
2443
|
+
chaindataProvider: chaindataProvider$1
|
2676
2444
|
})).filter(mod => DotBalanceModuleTypeSchema.safeParse(mod.type).success);
|
2677
2445
|
return Promise.all(modules.map(async mod => {
|
2678
2446
|
const source = mod.type;
|
2679
|
-
const chain = await chaindataProvider.getNetworkById(chainId, "polkadot");
|
2447
|
+
const chain = await chaindataProvider$1.getNetworkById(chainId, "polkadot");
|
2680
2448
|
const balancesConfig = chain?.balancesConfig?.[mod.type];
|
2681
2449
|
const chainMeta = await mod.fetchSubstrateChainMeta(chainId, balancesConfig,
|
2682
2450
|
// TODO better typing
|
@@ -2685,13 +2453,12 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
|
|
2685
2453
|
id: deriveMiniMetadataId({
|
2686
2454
|
source,
|
2687
2455
|
chainId,
|
2688
|
-
specVersion
|
2689
|
-
libVersion
|
2456
|
+
specVersion
|
2690
2457
|
}),
|
2691
2458
|
source,
|
2692
2459
|
chainId,
|
2693
2460
|
specVersion,
|
2694
|
-
|
2461
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
2695
2462
|
data: chainMeta?.miniMetadata ?? null,
|
2696
2463
|
extra: chainMeta?.extra ?? null
|
2697
2464
|
};
|
@@ -2713,24 +2480,23 @@ const getUpdatedMiniMetadatas = async (chainConnector, chaindataProvider, chainI
|
|
2713
2480
|
return miniMetadatas;
|
2714
2481
|
};
|
2715
2482
|
|
2716
|
-
const getMiniMetadata = async (chaindataProvider, chainConnector, chainId, source, signal) => {
|
2483
|
+
const getMiniMetadata$9 = async (chaindataProvider$1, chainConnector, chainId, source, signal) => {
|
2717
2484
|
const specVersion = await getSpecVersion(chainConnector, chainId);
|
2718
2485
|
signal?.throwIfAborted();
|
2719
2486
|
const miniMetadataId = deriveMiniMetadataId({
|
2720
2487
|
source,
|
2721
2488
|
chainId,
|
2722
|
-
specVersion
|
2723
|
-
libVersion
|
2489
|
+
specVersion
|
2724
2490
|
});
|
2725
2491
|
|
2726
2492
|
// lookup local ones
|
2727
|
-
const [dbMiniMetadata, ghMiniMetadata] = await Promise.all([db.miniMetadatas.get(miniMetadataId), chaindataProvider.miniMetadataById(miniMetadataId)]);
|
2493
|
+
const [dbMiniMetadata, ghMiniMetadata] = await Promise.all([db.miniMetadatas.get(miniMetadataId), chaindataProvider$1.miniMetadataById(miniMetadataId)]);
|
2728
2494
|
signal?.throwIfAborted();
|
2729
2495
|
const miniMetadata = dbMiniMetadata ?? ghMiniMetadata;
|
2730
2496
|
if (miniMetadata) return miniMetadata;
|
2731
2497
|
|
2732
2498
|
// update from live chain metadata and persist locally
|
2733
|
-
const miniMetadatas = await getUpdatedMiniMetadatas(chainConnector, chaindataProvider, chainId, specVersion, signal);
|
2499
|
+
const miniMetadatas = await getUpdatedMiniMetadatas(chainConnector, chaindataProvider$1, chainId, specVersion, signal);
|
2734
2500
|
signal?.throwIfAborted();
|
2735
2501
|
const found = miniMetadatas.find(m => m.id === miniMetadataId);
|
2736
2502
|
if (!found) {
|
@@ -2738,7 +2504,7 @@ const getMiniMetadata = async (chaindataProvider, chainConnector, chainId, sourc
|
|
2738
2504
|
source,
|
2739
2505
|
chainId,
|
2740
2506
|
specVersion,
|
2741
|
-
|
2507
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
2742
2508
|
miniMetadataId,
|
2743
2509
|
miniMetadatas
|
2744
2510
|
});
|
@@ -2794,6 +2560,8 @@ const buildStorageCoders = ({
|
|
2794
2560
|
return [];
|
2795
2561
|
}
|
2796
2562
|
}));
|
2563
|
+
// type StorageCoder<TCoders extends NetworkCoders> = ReturnType<ReturnType<typeof getDynamicBuilder>["buildStorage"]>[keyof TCoders]
|
2564
|
+
|
2797
2565
|
const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
|
2798
2566
|
if (!miniMetadata.data) return null;
|
2799
2567
|
const metadata = scale.unifyMetadata(scale.decAnyMetadata(miniMetadata.data));
|
@@ -3052,8 +2820,8 @@ const SubAssetsModule = hydrate => {
|
|
3052
2820
|
for (const tokenConfig of tokens ?? []) {
|
3053
2821
|
try {
|
3054
2822
|
const assetId = String(tokenConfig.assetId);
|
3055
|
-
const assetStateKey = tryEncode(assetCoder, BigInt(assetId)) ?? tryEncode(assetCoder, assetId);
|
3056
|
-
const metadataStateKey = tryEncode(metadataCoder, BigInt(assetId)) ?? tryEncode(metadataCoder, assetId);
|
2823
|
+
const assetStateKey = tryEncode$1(assetCoder, BigInt(assetId)) ?? tryEncode$1(assetCoder, assetId);
|
2824
|
+
const metadataStateKey = tryEncode$1(metadataCoder, BigInt(assetId)) ?? tryEncode$1(metadataCoder, assetId);
|
3057
2825
|
if (assetStateKey === null || metadataStateKey === null) throw new Error(`Failed to encode stateKey for asset ${assetId} on chain ${chainId}`);
|
3058
2826
|
const [assetsAsset, assetsMetadata] = await Promise.all([chainConnector.send(chainId, "state_getStorage", [assetStateKey]).then(result => assetCoder.value.dec(result) ?? null), chainConnector.send(chainId, "state_getStorage", [metadataStateKey]).then(result => metadataCoder.value.dec(result) ?? null)]);
|
3059
2827
|
const existentialDeposit = assetsAsset?.min_balance?.toString?.() ?? "0";
|
@@ -3073,6 +2841,7 @@ const SubAssetsModule = hydrate => {
|
|
3073
2841
|
logo: tokenConfig?.logo,
|
3074
2842
|
existentialDeposit,
|
3075
2843
|
assetId,
|
2844
|
+
isSufficient: false,
|
3076
2845
|
isFrozen,
|
3077
2846
|
networkId: chainId
|
3078
2847
|
};
|
@@ -3125,7 +2894,7 @@ const SubAssetsModule = hydrate => {
|
|
3125
2894
|
},
|
3126
2895
|
async fetchBalances(addressesByToken) {
|
3127
2896
|
util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
|
3128
|
-
const queries = await buildQueries$
|
2897
|
+
const queries = await buildQueries$6(chainConnector, chaindataProvider$1, addressesByToken);
|
3129
2898
|
const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
|
3130
2899
|
const balances = result?.filter(b => b !== null) ?? [];
|
3131
2900
|
return new Balances(balances);
|
@@ -3195,7 +2964,7 @@ const SubAssetsModule = hydrate => {
|
|
3195
2964
|
};
|
3196
2965
|
};
|
3197
2966
|
async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
|
3198
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$4, signal);
|
2967
|
+
const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$4, signal);
|
3199
2968
|
const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
|
3200
2969
|
const tokensById = await chaindataProvider.getTokensMapById();
|
3201
2970
|
signal?.throwIfAborted();
|
@@ -3219,7 +2988,7 @@ async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvide
|
|
3219
2988
|
}
|
3220
2989
|
return addresses.flatMap(address => {
|
3221
2990
|
const scaleCoder = networkStorageCoders?.storage;
|
3222
|
-
const stateKey = tryEncode(scaleCoder, Number(token.assetId), address) ?? tryEncode(scaleCoder, BigInt(token.assetId), address);
|
2991
|
+
const stateKey = tryEncode$1(scaleCoder, Number(token.assetId), address) ?? tryEncode$1(scaleCoder, BigInt(token.assetId), address);
|
3223
2992
|
if (!stateKey) {
|
3224
2993
|
log.warn(`Invalid assetId / address in ${networkId} storage query ${token.assetId} / ${address}`);
|
3225
2994
|
return [];
|
@@ -3274,7 +3043,7 @@ async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvide
|
|
3274
3043
|
});
|
3275
3044
|
});
|
3276
3045
|
}
|
3277
|
-
async function buildQueries$
|
3046
|
+
async function buildQueries$6(chainConnector, chaindataProvider$1, addressesByToken, signal) {
|
3278
3047
|
const byNetwork = lodash.keys(addressesByToken).reduce((acc, tokenId) => {
|
3279
3048
|
const networkId = chaindataProvider.parseSubAssetTokenId(tokenId).networkId;
|
3280
3049
|
if (!acc[networkId]) acc[networkId] = {};
|
@@ -3289,7 +3058,7 @@ async function buildQueries$3(chainConnector, chaindataProvider$1, addressesByTo
|
|
3289
3058
|
// E.g. Polkadot Asset Hub needs it to be a string, Astar needs it to be a bigint
|
3290
3059
|
//
|
3291
3060
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
3292
|
-
const tryEncode = (scaleCoder, ...args) => {
|
3061
|
+
const tryEncode$1 = (scaleCoder, ...args) => {
|
3293
3062
|
try {
|
3294
3063
|
return scaleCoder?.keys?.enc?.(...args);
|
3295
3064
|
} catch {
|
@@ -3372,6 +3141,7 @@ const SubForeignAssetsModule = hydrate => {
|
|
3372
3141
|
logo: tokenConfig?.logo,
|
3373
3142
|
existentialDeposit,
|
3374
3143
|
onChainId: tokenConfig.onChainId,
|
3144
|
+
isSufficient: assetsAsset?.is_sufficient ?? false,
|
3375
3145
|
isFrozen,
|
3376
3146
|
networkId: chainId
|
3377
3147
|
};
|
@@ -3420,7 +3190,7 @@ const SubForeignAssetsModule = hydrate => {
|
|
3420
3190
|
},
|
3421
3191
|
async fetchBalances(addressesByToken) {
|
3422
3192
|
util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
|
3423
|
-
const queries = await buildQueries$
|
3193
|
+
const queries = await buildQueries$5(chainConnector, chaindataProvider$1, addressesByToken);
|
3424
3194
|
const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
|
3425
3195
|
const balances = result?.filter(b => b !== null) ?? [];
|
3426
3196
|
return new Balances(balances);
|
@@ -3476,7 +3246,7 @@ const SubForeignAssetsModule = hydrate => {
|
|
3476
3246
|
};
|
3477
3247
|
};
|
3478
3248
|
async function buildNetworkQueries$1(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
|
3479
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$3, signal);
|
3249
|
+
const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$3, signal);
|
3480
3250
|
const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
|
3481
3251
|
const tokensById = await chaindataProvider.getTokensMapById();
|
3482
3252
|
signal?.throwIfAborted();
|
@@ -3558,7 +3328,7 @@ async function buildNetworkQueries$1(networkId, chainConnector, chaindataProvide
|
|
3558
3328
|
});
|
3559
3329
|
});
|
3560
3330
|
}
|
3561
|
-
async function buildQueries$
|
3331
|
+
async function buildQueries$5(chainConnector, chaindataProvider$1, addressesByToken, signal) {
|
3562
3332
|
const byNetwork = lodash.keys(addressesByToken).reduce((acc, tokenId) => {
|
3563
3333
|
const networkId = chaindataProvider.parseSubForeignAssetTokenId(tokenId).networkId;
|
3564
3334
|
if (!acc[networkId]) acc[networkId] = {};
|
@@ -3612,7 +3382,7 @@ const asObservable = handler => (...args) => new rxjs.Observable(subscriber => {
|
|
3612
3382
|
* Each nominationPool in the nominationPools pallet has access to some accountIds which have no
|
3613
3383
|
* associated private key. Instead, they are derived from this function.
|
3614
3384
|
*/
|
3615
|
-
const nompoolAccountId = (palletId, poolId, index) => {
|
3385
|
+
const nompoolAccountId$1 = (palletId, poolId, index) => {
|
3616
3386
|
const utf8Encoder = new TextEncoder();
|
3617
3387
|
const encModPrefix = utf8Encoder.encode("modl");
|
3618
3388
|
const encPalletId = utf8Encoder.encode(palletId);
|
@@ -3625,7 +3395,7 @@ const nompoolAccountId = (palletId, poolId, index) => {
|
|
3625
3395
|
return polkadotApi.AccountId().dec(bytes);
|
3626
3396
|
};
|
3627
3397
|
/** The stash account for the nomination pool */
|
3628
|
-
const nompoolStashAccountId = (palletId, poolId) => nompoolAccountId(palletId, poolId, 0);
|
3398
|
+
const nompoolStashAccountId$1 = (palletId, poolId) => nompoolAccountId$1(palletId, poolId, 0);
|
3629
3399
|
|
3630
3400
|
// TODO make this method chain-specific
|
3631
3401
|
async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addressesByToken, callback, signal) {
|
@@ -3637,7 +3407,7 @@ async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addr
|
|
3637
3407
|
const networkIds = lodash.keys(addressesByToken).map(tokenId => chaindataProvider.parseTokenId(tokenId).networkId);
|
3638
3408
|
const miniMetadatas = new Map();
|
3639
3409
|
for (const networkId of networkIds) {
|
3640
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider$1, chainConnector, networkId, "substrate-native");
|
3410
|
+
const miniMetadata = await getMiniMetadata$9(chaindataProvider$1, chainConnector, networkId, "substrate-native");
|
3641
3411
|
miniMetadatas.set(networkId, miniMetadata);
|
3642
3412
|
}
|
3643
3413
|
signal?.throwIfAborted();
|
@@ -3763,7 +3533,7 @@ async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addr
|
|
3763
3533
|
const scaleCoder = chainStorageCoders.get(chainId)?.ledger;
|
3764
3534
|
const queries = poolIds.flatMap(poolId => {
|
3765
3535
|
if (!nominationPoolsPalletId) return [];
|
3766
|
-
const stashAddress = nompoolStashAccountId(nominationPoolsPalletId, poolId);
|
3536
|
+
const stashAddress = nompoolStashAccountId$1(nominationPoolsPalletId, poolId);
|
3767
3537
|
const stateKey = scale.encodeStateKey(scaleCoder, `Invalid address in ${chainId} ledger query ${stashAddress}`, stashAddress);
|
3768
3538
|
if (!stateKey) return [];
|
3769
3539
|
const decodeResult = change => {
|
@@ -3916,12 +3686,12 @@ async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addr
|
|
3916
3686
|
}
|
3917
3687
|
}
|
3918
3688
|
|
3919
|
-
const SUBTENSOR_ROOT_NETUID = 0;
|
3920
|
-
const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = 1000000n;
|
3921
|
-
const TAO_DECIMALS = 9n;
|
3922
|
-
const SCALE_FACTOR = 10n ** TAO_DECIMALS; // Equivalent to 10e9 for precision
|
3923
|
-
const ONE_ALPHA_TOKEN = SCALE_FACTOR;
|
3924
|
-
const calculateAlphaPrice = ({
|
3689
|
+
const SUBTENSOR_ROOT_NETUID$1 = 0;
|
3690
|
+
const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1 = 1000000n;
|
3691
|
+
const TAO_DECIMALS$1 = 9n;
|
3692
|
+
const SCALE_FACTOR$1 = 10n ** TAO_DECIMALS$1; // Equivalent to 10e9 for precision
|
3693
|
+
const ONE_ALPHA_TOKEN$1 = SCALE_FACTOR$1;
|
3694
|
+
const calculateAlphaPrice$1 = ({
|
3925
3695
|
dynamicInfo
|
3926
3696
|
}) => {
|
3927
3697
|
if (!dynamicInfo) return 0n;
|
@@ -3931,25 +3701,25 @@ const calculateAlphaPrice = ({
|
|
3931
3701
|
} = dynamicInfo;
|
3932
3702
|
|
3933
3703
|
// Scale taoIn before division to preserve precision
|
3934
|
-
const result = tao_in * SCALE_FACTOR / alpha_in;
|
3704
|
+
const result = tao_in * SCALE_FACTOR$1 / alpha_in;
|
3935
3705
|
return result; // Scaled price as bigint
|
3936
3706
|
};
|
3937
|
-
const calculateTaoAmountFromAlpha = ({
|
3707
|
+
const calculateTaoAmountFromAlpha$1 = ({
|
3938
3708
|
alphaPrice,
|
3939
3709
|
alphaStaked
|
3940
3710
|
}) => {
|
3941
3711
|
if (!alphaStaked || !alphaPrice) return 0n;
|
3942
3712
|
const expectedAlpha = alphaStaked * alphaPrice;
|
3943
|
-
return expectedAlpha / SCALE_FACTOR;
|
3713
|
+
return expectedAlpha / SCALE_FACTOR$1;
|
3944
3714
|
};
|
3945
|
-
const calculateTaoFromDynamicInfo = ({
|
3715
|
+
const calculateTaoFromDynamicInfo$1 = ({
|
3946
3716
|
dynamicInfo,
|
3947
3717
|
alphaStaked
|
3948
3718
|
}) => {
|
3949
|
-
const alphaPrice = calculateAlphaPrice({
|
3719
|
+
const alphaPrice = calculateAlphaPrice$1({
|
3950
3720
|
dynamicInfo
|
3951
3721
|
});
|
3952
|
-
return calculateTaoAmountFromAlpha({
|
3722
|
+
return calculateTaoAmountFromAlpha$1({
|
3953
3723
|
alphaPrice,
|
3954
3724
|
alphaStaked
|
3955
3725
|
});
|
@@ -3965,7 +3735,7 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
|
|
3965
3735
|
const networkIds = lodash.keys(addressesByToken).map(tokenId => chaindataProvider.parseTokenId(tokenId).networkId);
|
3966
3736
|
const miniMetadatas = new Map();
|
3967
3737
|
for (const networkId of networkIds) {
|
3968
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider$1, chainConnector, networkId, "substrate-native", signal);
|
3738
|
+
const miniMetadata = await getMiniMetadata$9(chaindataProvider$1, chainConnector, networkId, "substrate-native", signal);
|
3969
3739
|
miniMetadatas.set(networkId, miniMetadata);
|
3970
3740
|
}
|
3971
3741
|
signal?.throwIfAborted();
|
@@ -4056,7 +3826,7 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
|
|
4056
3826
|
const params = [address];
|
4057
3827
|
const result = await scaleApi.getRuntimeCallValue("StakeInfoRuntimeApi", "get_stake_info_for_coldkey", params);
|
4058
3828
|
if (!Array.isArray(result)) return [];
|
4059
|
-
const uniqueNetuids = Array.from(new Set(result.map(item => Number(item.netuid)).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID)));
|
3829
|
+
const uniqueNetuids = Array.from(new Set(result.map(item => Number(item.netuid)).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID$1)));
|
4060
3830
|
await fetchDynamicInfoForNetuids(uniqueNetuids);
|
4061
3831
|
const stakes = result?.map(({
|
4062
3832
|
coldkey,
|
@@ -4073,7 +3843,7 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
|
|
4073
3843
|
};
|
4074
3844
|
}).filter(({
|
4075
3845
|
stake
|
4076
|
-
}) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK);
|
3846
|
+
}) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1);
|
4077
3847
|
return stakes;
|
4078
3848
|
}];
|
4079
3849
|
const errors = [];
|
@@ -4119,15 +3889,15 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
|
|
4119
3889
|
const subnetIdentity = subnet_identity ? binaryToText(subnet_identity) : undefined;
|
4120
3890
|
|
4121
3891
|
// Add 1n balance if failed to fetch dynamic info, so the position is not ignored by Balance lib and is displayed in the UI.
|
4122
|
-
const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo({
|
3892
|
+
const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo$1({
|
4123
3893
|
dynamicInfo,
|
4124
3894
|
alphaStaked: stake
|
4125
3895
|
}) : 1n;
|
4126
|
-
const alphaToTaoRate = calculateTaoFromDynamicInfo({
|
3896
|
+
const alphaToTaoRate = calculateTaoFromDynamicInfo$1({
|
4127
3897
|
dynamicInfo: dynamicInfo ?? null,
|
4128
|
-
alphaStaked: ONE_ALPHA_TOKEN
|
3898
|
+
alphaStaked: ONE_ALPHA_TOKEN$1
|
4129
3899
|
}).toString();
|
4130
|
-
const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID ? stake : alphaStakedInTao;
|
3900
|
+
const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID$1 ? stake : alphaStakedInTao;
|
4131
3901
|
return {
|
4132
3902
|
source: "substrate-native",
|
4133
3903
|
status: "live",
|
@@ -4187,14 +3957,14 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
|
|
4187
3957
|
}
|
4188
3958
|
}
|
4189
3959
|
|
4190
|
-
const getOtherType = input => `other-${input}`;
|
3960
|
+
const getOtherType$1 = input => `other-${input}`;
|
4191
3961
|
|
4192
3962
|
/**
|
4193
3963
|
* For converting the value of `lock?.id?.toUtf8?.()` which is retrieved from
|
4194
3964
|
* the Balances.Locks storage key into a useful classification for our UI
|
4195
3965
|
*/
|
4196
|
-
const getLockedType = input => {
|
4197
|
-
if (typeof input !== "string") return getOtherType("unknown");
|
3966
|
+
const getLockedType$1 = input => {
|
3967
|
+
if (typeof input !== "string") return getOtherType$1("unknown");
|
4198
3968
|
if (input.includes("vesting")) return "vesting";
|
4199
3969
|
if (input.includes("calamvst")) return "vesting"; // vesting on manta network
|
4200
3970
|
if (input.includes("ormlvest")) return "vesting"; // vesting ORML tokens
|
@@ -4216,19 +3986,19 @@ const getLockedType = input => {
|
|
4216
3986
|
if (input.includes("councilo")) return "democracy"; // Councilor
|
4217
3987
|
if (input.includes("proposal")) return "democracy";
|
4218
3988
|
if (input.includes("boundsta")) return "staking"; // Bound Staking Account
|
4219
|
-
if (input.includes("invitemb")) return getOtherType(input); // Invite member
|
4220
|
-
if (input.includes("bounty")) return getOtherType(input);
|
4221
|
-
if (input.startsWith("wg-")) return getOtherType(input);
|
3989
|
+
if (input.includes("invitemb")) return getOtherType$1(input); // Invite member
|
3990
|
+
if (input.includes("bounty")) return getOtherType$1(input);
|
3991
|
+
if (input.startsWith("wg-")) return getOtherType$1(input);
|
4222
3992
|
|
4223
3993
|
// ignore technical or undocumented lock types
|
4224
|
-
if (input.includes("pdexlock")) return getOtherType(input);
|
4225
|
-
if (input.includes("phala/sp")) return getOtherType(input);
|
4226
|
-
if (input.includes("aca/earn")) return getOtherType(input);
|
4227
|
-
if (input.includes("stk_stks")) return getOtherType(input);
|
3994
|
+
if (input.includes("pdexlock")) return getOtherType$1(input);
|
3995
|
+
if (input.includes("phala/sp")) return getOtherType$1(input);
|
3996
|
+
if (input.includes("aca/earn")) return getOtherType$1(input);
|
3997
|
+
if (input.includes("stk_stks")) return getOtherType$1(input);
|
4228
3998
|
|
4229
3999
|
// eslint-disable-next-line no-console
|
4230
4000
|
console.warn(`unknown locked type: ${input}`);
|
4231
|
-
return getOtherType(input);
|
4001
|
+
return getOtherType$1(input);
|
4232
4002
|
};
|
4233
4003
|
const baseLockLabels = ["fees", "misc"];
|
4234
4004
|
const isBaseLock = lock => baseLockLabels.includes(lock.label);
|
@@ -4325,7 +4095,7 @@ const AccountInfoOverrides = {
|
|
4325
4095
|
// nftmart is not yet on metadata v14
|
4326
4096
|
"nftmart": RegularAccountInfoFallback
|
4327
4097
|
};
|
4328
|
-
async function buildQueries$
|
4098
|
+
async function buildQueries$4(chains, tokens, chainStorageCoders, miniMetadatas, addressesByToken) {
|
4329
4099
|
return Object.entries(addressesByToken).reduce((outerResult, [tokenId, addresses]) => {
|
4330
4100
|
const token = tokens[tokenId];
|
4331
4101
|
if (!token) {
|
@@ -4457,7 +4227,7 @@ async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas,
|
|
4457
4227
|
locksQueryLocks = decoded?.map?.(lock => ({
|
4458
4228
|
type: "locked",
|
4459
4229
|
source: "substrate-native-locks",
|
4460
|
-
label: getLockedType(lock?.id?.asText?.()),
|
4230
|
+
label: getLockedType$1(lock?.id?.asText?.()),
|
4461
4231
|
meta: {
|
4462
4232
|
id: lock?.id?.asText?.()
|
4463
4233
|
},
|
@@ -4521,7 +4291,7 @@ async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas,
|
|
4521
4291
|
freezesQueryLocks = decoded?.map?.(lock => ({
|
4522
4292
|
type: "locked",
|
4523
4293
|
source: "substrate-native-freezes",
|
4524
|
-
label: getLockedType(lock?.id?.type?.toLowerCase?.()),
|
4294
|
+
label: getLockedType$1(lock?.id?.type?.toLowerCase?.()),
|
4525
4295
|
amount: lock?.amount?.toString?.() ?? "0"
|
4526
4296
|
})) ?? [];
|
4527
4297
|
|
@@ -4660,7 +4430,7 @@ class QueryCache {
|
|
4660
4430
|
const byNetwork = getAddresssesByTokenByNetwork(addressesByToken);
|
4661
4431
|
for (const networkId of lodash.keys(byNetwork)) {
|
4662
4432
|
if (this.miniMetadatas.has(networkId)) continue;
|
4663
|
-
const miniMetadata = await getMiniMetadata(this.#chaindataProvider, this.#chainConnector, networkId, "substrate-native");
|
4433
|
+
const miniMetadata = await getMiniMetadata$9(this.#chaindataProvider, this.#chainConnector, networkId, "substrate-native");
|
4664
4434
|
this.miniMetadatas.set(networkId, miniMetadata);
|
4665
4435
|
}
|
4666
4436
|
|
@@ -4679,7 +4449,7 @@ class QueryCache {
|
|
4679
4449
|
freezes: ["Balances", "Freezes"]
|
4680
4450
|
}
|
4681
4451
|
});
|
4682
|
-
const queries = await buildQueries$
|
4452
|
+
const queries = await buildQueries$4(chains, tokens, chainStorageCoders, this.miniMetadatas, queryResults.newAddressesByToken);
|
4683
4453
|
// now update the cache
|
4684
4454
|
Object.entries(queries).forEach(([key, query]) => {
|
4685
4455
|
this.balanceQueryCache.set(key, query);
|
@@ -4708,21 +4478,21 @@ class SubNativeBalanceError extends Error {
|
|
4708
4478
|
}
|
4709
4479
|
}
|
4710
4480
|
|
4711
|
-
const DotNetworkPropertiesSimple = z__default.default.object({
|
4481
|
+
const DotNetworkPropertiesSimple$1 = z__default.default.object({
|
4712
4482
|
tokenDecimals: z__default.default.number().optional().default(0),
|
4713
4483
|
tokenSymbol: z__default.default.string().optional().default("Unit")
|
4714
4484
|
});
|
4715
|
-
const DotNetworkPropertiesArray = z__default.default.object({
|
4485
|
+
const DotNetworkPropertiesArray$1 = z__default.default.object({
|
4716
4486
|
tokenDecimals: z__default.default.array(z__default.default.number()).nonempty(),
|
4717
4487
|
tokenSymbol: z__default.default.array(z__default.default.string()).nonempty()
|
4718
4488
|
});
|
4719
|
-
const DotNetworkPropertiesSchema = z__default.default.union([DotNetworkPropertiesSimple, DotNetworkPropertiesArray]).transform(val => ({
|
4489
|
+
const DotNetworkPropertiesSchema$1 = z__default.default.union([DotNetworkPropertiesSimple$1, DotNetworkPropertiesArray$1]).transform(val => ({
|
4720
4490
|
tokenDecimals: Array.isArray(val.tokenDecimals) ? val.tokenDecimals[0] : val.tokenDecimals,
|
4721
4491
|
tokenSymbol: Array.isArray(val.tokenSymbol) ? val.tokenSymbol[0] : val.tokenSymbol
|
4722
4492
|
}));
|
4723
|
-
const getChainProperties = async (chainConnector, networkId) => {
|
4493
|
+
const getChainProperties$1 = async (chainConnector, networkId) => {
|
4724
4494
|
const properties = await chainConnector.send(networkId, "system_properties", [], true);
|
4725
|
-
return DotNetworkPropertiesSchema.parse(properties);
|
4495
|
+
return DotNetworkPropertiesSchema$1.parse(properties);
|
4726
4496
|
};
|
4727
4497
|
|
4728
4498
|
const POLLING_WINDOW_SIZE = 20;
|
@@ -5008,7 +4778,7 @@ const SubNativeModule = hydrate => {
|
|
5008
4778
|
const {
|
5009
4779
|
tokenSymbol: symbol,
|
5010
4780
|
tokenDecimals: decimals
|
5011
|
-
} = await getChainProperties(chainConnector$1, chainId);
|
4781
|
+
} = await getChainProperties$1(chainConnector$1, chainId);
|
5012
4782
|
const {
|
5013
4783
|
existentialDeposit
|
5014
4784
|
} = chainMeta.extra ?? {};
|
@@ -5047,7 +4817,7 @@ const SubNativeModule = hydrate => {
|
|
5047
4817
|
try {
|
5048
4818
|
// this is what we want to be done separately for each network
|
5049
4819
|
// this will update the DB so minimetadata will be available when it's used, everywhere else down the tree of subscribeChainBalances
|
5050
|
-
await getMiniMetadata(chaindataProvider$1, chainConnector$1, networkId, moduleType$2, controller.signal);
|
4820
|
+
await getMiniMetadata$9(chaindataProvider$1, chainConnector$1, networkId, moduleType$2, controller.signal);
|
5051
4821
|
} catch (err) {
|
5052
4822
|
if (!util.isAbortError(err)) log.warn("Failed to get native token miniMetadata for network", networkId, err);
|
5053
4823
|
return () => {};
|
@@ -6364,7 +6134,7 @@ const SubPsp22Module = hydrate => {
|
|
6364
6134
|
if (!subscriptionActive) return;
|
6365
6135
|
try {
|
6366
6136
|
util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
|
6367
|
-
const balances = await fetchBalances(chainConnectors.substrate, tokens, addressesByToken);
|
6137
|
+
const balances = await fetchBalances$9(chainConnectors.substrate, tokens, addressesByToken);
|
6368
6138
|
|
6369
6139
|
// Don't call callback with balances which have not changed since the last poll.
|
6370
6140
|
const updatedBalances = new Balances([...balances].filter(b => {
|
@@ -6387,7 +6157,7 @@ const SubPsp22Module = hydrate => {
|
|
6387
6157
|
async fetchBalances(addressesByToken) {
|
6388
6158
|
util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
|
6389
6159
|
const tokens = await chaindataProvider$1.getTokensMapById();
|
6390
|
-
return fetchBalances(chainConnectors.substrate, tokens, addressesByToken);
|
6160
|
+
return fetchBalances$9(chainConnectors.substrate, tokens, addressesByToken);
|
6391
6161
|
},
|
6392
6162
|
async transferToken({
|
6393
6163
|
tokenId,
|
@@ -6467,7 +6237,7 @@ const SubPsp22Module = hydrate => {
|
|
6467
6237
|
}
|
6468
6238
|
};
|
6469
6239
|
};
|
6470
|
-
const fetchBalances = async (chainConnector, tokens, addressesByToken) => {
|
6240
|
+
const fetchBalances$9 = async (chainConnector, tokens, addressesByToken) => {
|
6471
6241
|
const registry = new types.TypeRegistry();
|
6472
6242
|
const Psp22Abi = new apiContract.Abi(psp22Abi);
|
6473
6243
|
const balanceRequests = Object.entries(addressesByToken).flatMap(([tokenId, addresses]) => addresses.map(address => [tokenId, address])).flatMap(async ([tokenId, address]) => {
|
@@ -6628,7 +6398,7 @@ const SubTokensModule = hydrate => {
|
|
6628
6398
|
},
|
6629
6399
|
async fetchBalances(addressesByToken) {
|
6630
6400
|
util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
|
6631
|
-
const queries = await buildQueries(chainConnector, chaindataProvider$1, addressesByToken);
|
6401
|
+
const queries = await buildQueries$3(chainConnector, chaindataProvider$1, addressesByToken);
|
6632
6402
|
const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
|
6633
6403
|
const balances = result?.filter(b => b !== null) ?? [];
|
6634
6404
|
return new Balances(balances);
|
@@ -6645,7 +6415,7 @@ const SubTokensModule = hydrate => {
|
|
6645
6415
|
const chainId = token.networkId;
|
6646
6416
|
const chain = await chaindataProvider$1.getNetworkById(chainId, "polkadot");
|
6647
6417
|
util$1.assert(chain?.genesisHash, `Chain ${chainId} not found in store`);
|
6648
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider$1, chainConnector, chainId, moduleType);
|
6418
|
+
const miniMetadata = await getMiniMetadata$9(chaindataProvider$1, chainConnector, chainId, moduleType);
|
6649
6419
|
const tokensPallet = miniMetadata?.extra?.palletId ?? defaultPalletId;
|
6650
6420
|
const onChainId = (() => {
|
6651
6421
|
try {
|
@@ -6746,7 +6516,7 @@ const SubTokensModule = hydrate => {
|
|
6746
6516
|
};
|
6747
6517
|
};
|
6748
6518
|
async function buildNetworkQueries(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
|
6749
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType, signal);
|
6519
|
+
const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType, signal);
|
6750
6520
|
const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
|
6751
6521
|
const tokens = await chaindataProvider.getTokensMapById();
|
6752
6522
|
if (!chain) return [];
|
@@ -6817,7 +6587,7 @@ async function buildNetworkQueries(networkId, chainConnector, chaindataProvider,
|
|
6817
6587
|
});
|
6818
6588
|
});
|
6819
6589
|
}
|
6820
|
-
async function buildQueries(chainConnector, chaindataProvider$1, addressesByToken, signal) {
|
6590
|
+
async function buildQueries$3(chainConnector, chaindataProvider$1, addressesByToken, signal) {
|
6821
6591
|
const byNetwork = lodash.keys(addressesByToken).reduce((acc, tokenId) => {
|
6822
6592
|
const networkId = chaindataProvider.parseSubTokensTokenId(tokenId).networkId;
|
6823
6593
|
if (!acc[networkId]) acc[networkId] = {};
|
@@ -6831,6 +6601,3806 @@ async function buildQueries(chainConnector, chaindataProvider$1, addressesByToke
|
|
6831
6601
|
|
6832
6602
|
const defaultBalanceModules = [EvmErc20Module, EvmNativeModule, EvmUniswapV2Module, SubAssetsModule, SubForeignAssetsModule, SubNativeModule, SubPsp22Module, SubTokensModule];
|
6833
6603
|
|
6604
|
+
const MODULE_TYPE$8 = chaindataProvider.EvmErc20TokenSchema.shape.type.value;
|
6605
|
+
const PLATFORM$8 = chaindataProvider.EvmErc20TokenSchema.shape.platform.value;
|
6606
|
+
|
6607
|
+
// to be used by chaindata too
|
6608
|
+
z__default.default.strictObject({
|
6609
|
+
contractAddress: chaindataProvider.EvmErc20TokenSchema.shape.contractAddress,
|
6610
|
+
...TokenConfigBaseSchema.shape
|
6611
|
+
});
|
6612
|
+
|
6613
|
+
class BalanceFetchError extends Error {
|
6614
|
+
constructor(message, tokenId, address, cause) {
|
6615
|
+
super(message);
|
6616
|
+
this.name = "BalanceFetchError";
|
6617
|
+
this.tokenId = tokenId;
|
6618
|
+
this.address = address;
|
6619
|
+
if (cause) this.cause = cause;
|
6620
|
+
}
|
6621
|
+
}
|
6622
|
+
class BalanceFetchNetworkError extends Error {
|
6623
|
+
constructor(message, evmNetworkId, cause) {
|
6624
|
+
super(message);
|
6625
|
+
this.name = "BalanceFetchNetworkError";
|
6626
|
+
this.evmNetworkId = evmNetworkId;
|
6627
|
+
if (cause) this.cause = cause;
|
6628
|
+
}
|
6629
|
+
}
|
6630
|
+
|
6631
|
+
const getBalanceDefs = addressesByToken => {
|
6632
|
+
return addressesByToken.flatMap(([token, addresses]) => addresses.map(address => ({
|
6633
|
+
token,
|
6634
|
+
address
|
6635
|
+
})));
|
6636
|
+
};
|
6637
|
+
|
6638
|
+
const fetchBalances$8 = async ({
|
6639
|
+
networkId,
|
6640
|
+
addressesByToken,
|
6641
|
+
connector
|
6642
|
+
}) => {
|
6643
|
+
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
6644
|
+
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
6645
|
+
for (const [token, addresses] of addressesByToken) {
|
6646
|
+
if (token.type !== MODULE_TYPE$8 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
6647
|
+
for (const address of addresses) if (!util.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
6648
|
+
}
|
6649
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
6650
|
+
if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
|
6651
|
+
const erc20Aggregator = client.chain.contracts.erc20Aggregator;
|
6652
|
+
return fetchWithAggregator$1(client, balanceDefs, erc20Aggregator.address);
|
6653
|
+
}
|
6654
|
+
return fetchWithoutAggregator$1(client, balanceDefs);
|
6655
|
+
};
|
6656
|
+
const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
|
6657
|
+
if (balanceDefs.length === 0) return {
|
6658
|
+
success: [],
|
6659
|
+
errors: []
|
6660
|
+
};
|
6661
|
+
log.debug("fetching %s balances without aggregator", MODULE_TYPE$8, balanceDefs.length);
|
6662
|
+
const results = await Promise.allSettled(balanceDefs.map(async ({
|
6663
|
+
token,
|
6664
|
+
address
|
6665
|
+
}) => {
|
6666
|
+
try {
|
6667
|
+
const result = await client.readContract({
|
6668
|
+
abi: viem.erc20Abi,
|
6669
|
+
address: token.contractAddress,
|
6670
|
+
functionName: "balanceOf",
|
6671
|
+
args: [address]
|
6672
|
+
});
|
6673
|
+
const balance = {
|
6674
|
+
address,
|
6675
|
+
tokenId: token.id,
|
6676
|
+
value: result.toString(),
|
6677
|
+
source: MODULE_TYPE$8,
|
6678
|
+
networkId: chaindataProvider.parseEvmErc20TokenId(token.id).networkId,
|
6679
|
+
status: "cache"
|
6680
|
+
};
|
6681
|
+
return balance;
|
6682
|
+
} catch (err) {
|
6683
|
+
throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
|
6684
|
+
}
|
6685
|
+
}));
|
6686
|
+
return results.reduce((acc, result) => {
|
6687
|
+
if (result.status === "fulfilled") acc.success.push(result.value);else {
|
6688
|
+
const error = result.reason;
|
6689
|
+
acc.errors.push({
|
6690
|
+
tokenId: error.tokenId,
|
6691
|
+
address: error.address,
|
6692
|
+
error
|
6693
|
+
});
|
6694
|
+
}
|
6695
|
+
return acc;
|
6696
|
+
}, {
|
6697
|
+
success: [],
|
6698
|
+
errors: []
|
6699
|
+
});
|
6700
|
+
};
|
6701
|
+
const fetchWithAggregator$1 = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
|
6702
|
+
if (balanceDefs.length === 0) return {
|
6703
|
+
success: [],
|
6704
|
+
errors: []
|
6705
|
+
};
|
6706
|
+
log.debug("fetching %s balances with aggregator", MODULE_TYPE$8, balanceDefs.length);
|
6707
|
+
try {
|
6708
|
+
const erc20Balances = await client.readContract({
|
6709
|
+
abi: erc20BalancesAggregatorAbi,
|
6710
|
+
address: erc20BalancesAggregatorAddress,
|
6711
|
+
functionName: "balances",
|
6712
|
+
args: [balanceDefs.map(b => ({
|
6713
|
+
account: b.address,
|
6714
|
+
token: b.token.contractAddress
|
6715
|
+
}))]
|
6716
|
+
});
|
6717
|
+
const success = balanceDefs.map((balanceDef, index) => ({
|
6718
|
+
address: balanceDef.address,
|
6719
|
+
tokenId: balanceDef.token.id,
|
6720
|
+
value: erc20Balances[index].toString(),
|
6721
|
+
source: MODULE_TYPE$8,
|
6722
|
+
networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
|
6723
|
+
status: "cache"
|
6724
|
+
}));
|
6725
|
+
return {
|
6726
|
+
success,
|
6727
|
+
errors: []
|
6728
|
+
};
|
6729
|
+
} catch (err) {
|
6730
|
+
const errors = balanceDefs.map(balanceDef => ({
|
6731
|
+
tokenId: balanceDef.token.id,
|
6732
|
+
address: balanceDef.address,
|
6733
|
+
error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
|
6734
|
+
}));
|
6735
|
+
return {
|
6736
|
+
success: [],
|
6737
|
+
errors
|
6738
|
+
};
|
6739
|
+
}
|
6740
|
+
};
|
6741
|
+
|
6742
|
+
const getErc20ContractData$1 = async (client, contractAddress) => {
|
6743
|
+
try {
|
6744
|
+
const contract = getTypedContract$1(client, viem.erc20Abi, contractAddress);
|
6745
|
+
|
6746
|
+
// eslint-disable-next-line no-var
|
6747
|
+
var [symbol, decimals, name] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
|
6748
|
+
} catch (e) {
|
6749
|
+
if (e instanceof viem.ContractFunctionExecutionError) {
|
6750
|
+
// try to perform the contract read with bytes32 symbol
|
6751
|
+
const contract = getTypedContract$1(client, viem.erc20Abi_bytes32, contractAddress);
|
6752
|
+
|
6753
|
+
// eslint-disable-next-line no-var
|
6754
|
+
var [bytesSymbol, decimals, nameSymbol] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
|
6755
|
+
symbol = viem.hexToString(bytesSymbol).replace(/\0/g, "").trim(); // remove NULL characters
|
6756
|
+
name = viem.hexToString(nameSymbol).replace(/\0/g, "").trim(); // remove NULL characters
|
6757
|
+
} else throw e;
|
6758
|
+
}
|
6759
|
+
return {
|
6760
|
+
symbol,
|
6761
|
+
decimals,
|
6762
|
+
name
|
6763
|
+
};
|
6764
|
+
};
|
6765
|
+
const getTypedContract$1 = (client, abi, contractAddress) => viem.getContract({
|
6766
|
+
address: contractAddress,
|
6767
|
+
abi,
|
6768
|
+
client: {
|
6769
|
+
public: client
|
6770
|
+
}
|
6771
|
+
});
|
6772
|
+
|
6773
|
+
const TokenCacheSchema$1 = chaindataProvider.EvmErc20TokenSchema.pick({
|
6774
|
+
symbol: true,
|
6775
|
+
decimals: true,
|
6776
|
+
name: true
|
6777
|
+
});
|
6778
|
+
const fetchTokens$8 = async ({
|
6779
|
+
networkId,
|
6780
|
+
tokens,
|
6781
|
+
connector,
|
6782
|
+
cache
|
6783
|
+
}) => {
|
6784
|
+
const result = [];
|
6785
|
+
for (const tokenConfig of tokens) {
|
6786
|
+
const tokenId = chaindataProvider.evmErc20TokenId(networkId, tokenConfig.contractAddress);
|
6787
|
+
if (!cache[tokenId] || !TokenCacheSchema$1.safeParse(cache[tokenId]).success) {
|
6788
|
+
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
6789
|
+
if (!client) {
|
6790
|
+
log.warn(`No client found for network ${networkId} while fetching EVM ERC20 tokens`);
|
6791
|
+
continue;
|
6792
|
+
}
|
6793
|
+
try {
|
6794
|
+
const {
|
6795
|
+
name,
|
6796
|
+
decimals,
|
6797
|
+
symbol
|
6798
|
+
} = await getErc20ContractData$1(client, tokenConfig.contractAddress);
|
6799
|
+
cache[tokenId] = {
|
6800
|
+
id: tokenId,
|
6801
|
+
symbol,
|
6802
|
+
decimals,
|
6803
|
+
name
|
6804
|
+
};
|
6805
|
+
} catch (err) {
|
6806
|
+
log.warn(`Failed to fetch ERC20 token data for ${tokenConfig.contractAddress}`, err);
|
6807
|
+
continue;
|
6808
|
+
}
|
6809
|
+
}
|
6810
|
+
const base = {
|
6811
|
+
type: MODULE_TYPE$8,
|
6812
|
+
platform: PLATFORM$8,
|
6813
|
+
networkId
|
6814
|
+
};
|
6815
|
+
const token = lodash.assign(base, cache[tokenId], tokenConfig);
|
6816
|
+
const parsed = chaindataProvider.EvmErc20TokenSchema.safeParse(token);
|
6817
|
+
if (!parsed.success) {
|
6818
|
+
log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
|
6819
|
+
continue;
|
6820
|
+
}
|
6821
|
+
result.push(parsed.data);
|
6822
|
+
}
|
6823
|
+
return result;
|
6824
|
+
};
|
6825
|
+
|
6826
|
+
const getMiniMetadata$8 = () => {
|
6827
|
+
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
6828
|
+
};
|
6829
|
+
|
6830
|
+
const getTransferCallData$8 = ({
|
6831
|
+
from,
|
6832
|
+
to,
|
6833
|
+
value,
|
6834
|
+
token
|
6835
|
+
}) => {
|
6836
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$8)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$8}.`);
|
6837
|
+
if (!util.isEthereumAddress(from)) throw new Error("Invalid from address");
|
6838
|
+
if (!util.isEthereumAddress(to)) throw new Error("Invalid to address");
|
6839
|
+
const data = viem.encodeFunctionData({
|
6840
|
+
abi: viem.erc20Abi,
|
6841
|
+
functionName: "transfer",
|
6842
|
+
args: [to, BigInt(value)]
|
6843
|
+
});
|
6844
|
+
return {
|
6845
|
+
from,
|
6846
|
+
to: token.contractAddress,
|
6847
|
+
data
|
6848
|
+
};
|
6849
|
+
};
|
6850
|
+
|
6851
|
+
const SUBSCRIPTION_INTERVAL$8 = 6_000;
|
6852
|
+
const subscribeBalances$8 = ({
|
6853
|
+
networkId,
|
6854
|
+
addressesByToken,
|
6855
|
+
connector
|
6856
|
+
}) => {
|
6857
|
+
return new rxjs.Observable(subscriber => {
|
6858
|
+
const abortController = new AbortController();
|
6859
|
+
const poll = async () => {
|
6860
|
+
try {
|
6861
|
+
if (abortController.signal.aborted) return;
|
6862
|
+
const balances = await fetchBalances$8({
|
6863
|
+
networkId,
|
6864
|
+
addressesByToken,
|
6865
|
+
connector
|
6866
|
+
});
|
6867
|
+
if (abortController.signal.aborted) return;
|
6868
|
+
subscriber.next(balances);
|
6869
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$8);
|
6870
|
+
} catch (error) {
|
6871
|
+
log.error("Error", {
|
6872
|
+
module: MODULE_TYPE$8,
|
6873
|
+
networkId,
|
6874
|
+
addressesByToken,
|
6875
|
+
error
|
6876
|
+
});
|
6877
|
+
subscriber.error(error);
|
6878
|
+
}
|
6879
|
+
};
|
6880
|
+
poll();
|
6881
|
+
return () => {
|
6882
|
+
abortController.abort();
|
6883
|
+
};
|
6884
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
6885
|
+
};
|
6886
|
+
|
6887
|
+
const EvmErc20BalanceModule = {
|
6888
|
+
type: MODULE_TYPE$8,
|
6889
|
+
platform: PLATFORM$8,
|
6890
|
+
getMiniMetadata: getMiniMetadata$8,
|
6891
|
+
fetchTokens: fetchTokens$8,
|
6892
|
+
fetchBalances: fetchBalances$8,
|
6893
|
+
subscribeBalances: subscribeBalances$8,
|
6894
|
+
getTransferCallData: getTransferCallData$8
|
6895
|
+
};
|
6896
|
+
|
6897
|
+
const MODULE_TYPE$7 = chaindataProvider.EvmNativeTokenSchema.shape.type.value;
|
6898
|
+
const PLATFORM$7 = chaindataProvider.EvmNativeTokenSchema.shape.platform.value;
|
6899
|
+
|
6900
|
+
// to be used by chaindata too
|
6901
|
+
z__default.default.strictObject({
|
6902
|
+
...TokenConfigBaseSchema.shape
|
6903
|
+
});
|
6904
|
+
|
6905
|
+
const fetchBalances$7 = async ({
|
6906
|
+
networkId,
|
6907
|
+
addressesByToken,
|
6908
|
+
connector
|
6909
|
+
}) => {
|
6910
|
+
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
6911
|
+
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
6912
|
+
for (const [token, addresses] of addressesByToken) {
|
6913
|
+
if (token.type !== MODULE_TYPE$7 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
6914
|
+
for (const address of addresses) if (!util.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
6915
|
+
}
|
6916
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
6917
|
+
if (client.chain?.contracts?.multicall3 && balanceDefs.length > 1) {
|
6918
|
+
const multicall3 = client.chain.contracts.multicall3;
|
6919
|
+
return fetchWithMulticall(client, balanceDefs, multicall3.address);
|
6920
|
+
}
|
6921
|
+
return fetchWithoutMulticall(client, balanceDefs);
|
6922
|
+
};
|
6923
|
+
const fetchWithoutMulticall = async (client, balanceDefs) => {
|
6924
|
+
if (balanceDefs.length === 0) return {
|
6925
|
+
success: [],
|
6926
|
+
errors: []
|
6927
|
+
};
|
6928
|
+
log.debug("fetching %s balances without multicall3", MODULE_TYPE$7, balanceDefs.length);
|
6929
|
+
const results = await Promise.allSettled(balanceDefs.map(async ({
|
6930
|
+
token,
|
6931
|
+
address
|
6932
|
+
}) => {
|
6933
|
+
try {
|
6934
|
+
const result = await client.getBalance({
|
6935
|
+
address
|
6936
|
+
});
|
6937
|
+
const balance = {
|
6938
|
+
address,
|
6939
|
+
tokenId: token.id,
|
6940
|
+
value: result.toString(),
|
6941
|
+
source: MODULE_TYPE$7,
|
6942
|
+
networkId: chaindataProvider.parseTokenId(token.id).networkId,
|
6943
|
+
status: "live"
|
6944
|
+
};
|
6945
|
+
return balance;
|
6946
|
+
} catch (err) {
|
6947
|
+
throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
|
6948
|
+
}
|
6949
|
+
}));
|
6950
|
+
return results.reduce((acc, result) => {
|
6951
|
+
if (result.status === "fulfilled") acc.success.push(result.value);else {
|
6952
|
+
const error = result.reason;
|
6953
|
+
acc.errors.push({
|
6954
|
+
tokenId: error.tokenId,
|
6955
|
+
address: error.address,
|
6956
|
+
error
|
6957
|
+
});
|
6958
|
+
}
|
6959
|
+
return acc;
|
6960
|
+
}, {
|
6961
|
+
success: [],
|
6962
|
+
errors: []
|
6963
|
+
});
|
6964
|
+
};
|
6965
|
+
const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
|
6966
|
+
if (balanceDefs.length === 0) return {
|
6967
|
+
success: [],
|
6968
|
+
errors: []
|
6969
|
+
};
|
6970
|
+
log.debug("fetching %s balances with multicall3", MODULE_TYPE$7, balanceDefs.length);
|
6971
|
+
try {
|
6972
|
+
const callResults = await client.multicall({
|
6973
|
+
contracts: balanceDefs.map(({
|
6974
|
+
address
|
6975
|
+
}) => ({
|
6976
|
+
address: multicall3Address,
|
6977
|
+
abi: abiMulticall,
|
6978
|
+
functionName: "getEthBalance",
|
6979
|
+
args: [address]
|
6980
|
+
}))
|
6981
|
+
});
|
6982
|
+
return callResults.reduce((acc, result, index) => {
|
6983
|
+
if (result.status === "success") {
|
6984
|
+
acc.success.push({
|
6985
|
+
address: balanceDefs[index].address,
|
6986
|
+
tokenId: balanceDefs[index].token.id,
|
6987
|
+
value: result.result.toString(),
|
6988
|
+
source: MODULE_TYPE$7,
|
6989
|
+
networkId: chaindataProvider.parseTokenId(balanceDefs[index].token.id).networkId,
|
6990
|
+
status: "live"
|
6991
|
+
});
|
6992
|
+
}
|
6993
|
+
if (result.status === "failure") {
|
6994
|
+
acc.errors.push({
|
6995
|
+
tokenId: balanceDefs[index].token.id,
|
6996
|
+
address: balanceDefs[index].address,
|
6997
|
+
error: new BalanceFetchError(`Failed to get balance for token ${balanceDefs[index].token.id} and address ${balanceDefs[index].address} on chain ${client.chain?.id}`, balanceDefs[index].token.id, balanceDefs[index].address, result.error)
|
6998
|
+
});
|
6999
|
+
}
|
7000
|
+
return acc;
|
7001
|
+
}, {
|
7002
|
+
success: [],
|
7003
|
+
errors: []
|
7004
|
+
});
|
7005
|
+
} catch (err) {
|
7006
|
+
const errors = balanceDefs.map(balanceDef => ({
|
7007
|
+
tokenId: balanceDef.token.id,
|
7008
|
+
address: balanceDef.address,
|
7009
|
+
error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
|
7010
|
+
}));
|
7011
|
+
return {
|
7012
|
+
success: [],
|
7013
|
+
errors
|
7014
|
+
};
|
7015
|
+
}
|
7016
|
+
};
|
7017
|
+
|
7018
|
+
const fetchTokens$7 = async ({
|
7019
|
+
networkId,
|
7020
|
+
tokens
|
7021
|
+
}) => {
|
7022
|
+
// assume there is one and only one token in the array
|
7023
|
+
if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
|
7024
|
+
const token = lodash.assign({
|
7025
|
+
id: chaindataProvider.evmNativeTokenId(networkId),
|
7026
|
+
type: MODULE_TYPE$7,
|
7027
|
+
platform: PLATFORM$7,
|
7028
|
+
networkId,
|
7029
|
+
isDefault: true
|
7030
|
+
}, tokens[0]);
|
7031
|
+
const parsed = chaindataProvider.EvmNativeTokenSchema.safeParse(token);
|
7032
|
+
if (!parsed.success) {
|
7033
|
+
log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
|
7034
|
+
return [];
|
7035
|
+
}
|
7036
|
+
return [parsed.data];
|
7037
|
+
};
|
7038
|
+
|
7039
|
+
const getMiniMetadata$7 = () => {
|
7040
|
+
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
7041
|
+
};
|
7042
|
+
|
7043
|
+
const getTransferCallData$7 = ({
|
7044
|
+
from,
|
7045
|
+
to,
|
7046
|
+
value,
|
7047
|
+
token
|
7048
|
+
}) => {
|
7049
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$7)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$7}.`);
|
7050
|
+
if (!util.isEthereumAddress(from)) throw new Error("Invalid from address");
|
7051
|
+
if (!util.isEthereumAddress(to)) throw new Error("Invalid to address");
|
7052
|
+
return {
|
7053
|
+
from,
|
7054
|
+
to,
|
7055
|
+
value,
|
7056
|
+
data: "0x"
|
7057
|
+
};
|
7058
|
+
};
|
7059
|
+
|
7060
|
+
const SUBSCRIPTION_INTERVAL$7 = 6_000;
|
7061
|
+
const subscribeBalances$7 = ({
|
7062
|
+
networkId,
|
7063
|
+
addressesByToken,
|
7064
|
+
connector
|
7065
|
+
}) => {
|
7066
|
+
return new rxjs.Observable(subscriber => {
|
7067
|
+
const abortController = new AbortController();
|
7068
|
+
const poll = async () => {
|
7069
|
+
try {
|
7070
|
+
if (abortController.signal.aborted) return;
|
7071
|
+
const balances = await fetchBalances$7({
|
7072
|
+
networkId,
|
7073
|
+
addressesByToken,
|
7074
|
+
connector
|
7075
|
+
});
|
7076
|
+
if (abortController.signal.aborted) return;
|
7077
|
+
subscriber.next(balances);
|
7078
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$7);
|
7079
|
+
} catch (error) {
|
7080
|
+
log.error("Error", {
|
7081
|
+
module: MODULE_TYPE$7,
|
7082
|
+
networkId,
|
7083
|
+
addressesByToken,
|
7084
|
+
error
|
7085
|
+
});
|
7086
|
+
subscriber.error(error);
|
7087
|
+
}
|
7088
|
+
};
|
7089
|
+
poll();
|
7090
|
+
return () => {
|
7091
|
+
abortController.abort();
|
7092
|
+
};
|
7093
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
7094
|
+
};
|
7095
|
+
|
7096
|
+
const EvmNativeBalanceModule = {
|
7097
|
+
type: MODULE_TYPE$7,
|
7098
|
+
platform: PLATFORM$7,
|
7099
|
+
getMiniMetadata: getMiniMetadata$7,
|
7100
|
+
fetchTokens: fetchTokens$7,
|
7101
|
+
fetchBalances: fetchBalances$7,
|
7102
|
+
subscribeBalances: subscribeBalances$7,
|
7103
|
+
getTransferCallData: getTransferCallData$7
|
7104
|
+
};
|
7105
|
+
|
7106
|
+
const MODULE_TYPE$6 = chaindataProvider.EvmUniswapV2TokenSchema.shape.type.value;
|
7107
|
+
const PLATFORM$6 = chaindataProvider.EvmUniswapV2TokenSchema.shape.platform.value;
|
7108
|
+
|
7109
|
+
// to be used by chaindata too
|
7110
|
+
z__default.default.strictObject({
|
7111
|
+
contractAddress: chaindataProvider.EvmUniswapV2TokenSchema.shape.contractAddress,
|
7112
|
+
...TokenConfigBaseSchema.shape
|
7113
|
+
});
|
7114
|
+
|
7115
|
+
const fetchBalances$6 = async ({
|
7116
|
+
networkId,
|
7117
|
+
addressesByToken,
|
7118
|
+
connector
|
7119
|
+
}) => {
|
7120
|
+
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
7121
|
+
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
7122
|
+
for (const [token, addresses] of addressesByToken) {
|
7123
|
+
if (token.type !== MODULE_TYPE$6 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
7124
|
+
for (const address of addresses) if (!util.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
7125
|
+
}
|
7126
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
7127
|
+
if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
|
7128
|
+
const erc20Aggregator = client.chain.contracts.erc20Aggregator;
|
7129
|
+
return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
|
7130
|
+
}
|
7131
|
+
return fetchWithoutAggregator(client, balanceDefs);
|
7132
|
+
};
|
7133
|
+
const fetchWithoutAggregator = async (client, balanceDefs) => {
|
7134
|
+
if (balanceDefs.length === 0) return {
|
7135
|
+
success: [],
|
7136
|
+
errors: []
|
7137
|
+
};
|
7138
|
+
log.debug("fetching %s balances without aggregator", MODULE_TYPE$6, balanceDefs.length);
|
7139
|
+
const results = await Promise.allSettled(balanceDefs.map(async ({
|
7140
|
+
token,
|
7141
|
+
address
|
7142
|
+
}) => {
|
7143
|
+
try {
|
7144
|
+
const result = await client.readContract({
|
7145
|
+
abi: viem.erc20Abi,
|
7146
|
+
address: token.contractAddress,
|
7147
|
+
functionName: "balanceOf",
|
7148
|
+
args: [address]
|
7149
|
+
});
|
7150
|
+
const balance = {
|
7151
|
+
address,
|
7152
|
+
tokenId: token.id,
|
7153
|
+
value: result.toString(),
|
7154
|
+
source: MODULE_TYPE$6,
|
7155
|
+
networkId: chaindataProvider.parseTokenId(token.id).networkId,
|
7156
|
+
status: "cache"
|
7157
|
+
};
|
7158
|
+
return balance;
|
7159
|
+
} catch (err) {
|
7160
|
+
throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
|
7161
|
+
}
|
7162
|
+
}));
|
7163
|
+
return results.reduce((acc, result) => {
|
7164
|
+
if (result.status === "fulfilled") acc.success.push(result.value);else {
|
7165
|
+
const error = result.reason;
|
7166
|
+
acc.errors.push({
|
7167
|
+
tokenId: error.tokenId,
|
7168
|
+
address: error.address,
|
7169
|
+
error
|
7170
|
+
});
|
7171
|
+
}
|
7172
|
+
return acc;
|
7173
|
+
}, {
|
7174
|
+
success: [],
|
7175
|
+
errors: []
|
7176
|
+
});
|
7177
|
+
};
|
7178
|
+
const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
|
7179
|
+
if (balanceDefs.length === 0) return {
|
7180
|
+
success: [],
|
7181
|
+
errors: []
|
7182
|
+
};
|
7183
|
+
log.debug("fetching %s balances with aggregator", MODULE_TYPE$6, balanceDefs.length);
|
7184
|
+
try {
|
7185
|
+
const erc20Balances = await client.readContract({
|
7186
|
+
abi: erc20BalancesAggregatorAbi,
|
7187
|
+
address: erc20BalancesAggregatorAddress,
|
7188
|
+
functionName: "balances",
|
7189
|
+
args: [balanceDefs.map(b => ({
|
7190
|
+
account: b.address,
|
7191
|
+
token: b.token.contractAddress
|
7192
|
+
}))]
|
7193
|
+
});
|
7194
|
+
const success = balanceDefs.map((balanceDef, index) => ({
|
7195
|
+
address: balanceDef.address,
|
7196
|
+
tokenId: balanceDef.token.id,
|
7197
|
+
value: erc20Balances[index].toString(),
|
7198
|
+
source: MODULE_TYPE$6,
|
7199
|
+
networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
|
7200
|
+
status: "cache"
|
7201
|
+
}));
|
7202
|
+
return {
|
7203
|
+
success,
|
7204
|
+
errors: []
|
7205
|
+
};
|
7206
|
+
} catch (err) {
|
7207
|
+
const errors = balanceDefs.map(balanceDef => ({
|
7208
|
+
tokenId: balanceDef.token.id,
|
7209
|
+
address: balanceDef.address,
|
7210
|
+
error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
|
7211
|
+
}));
|
7212
|
+
return {
|
7213
|
+
success: [],
|
7214
|
+
errors
|
7215
|
+
};
|
7216
|
+
}
|
7217
|
+
};
|
7218
|
+
|
7219
|
+
const getErc20ContractData = async (client, contractAddress) => {
|
7220
|
+
try {
|
7221
|
+
const contract = getTypedContract(client, viem.erc20Abi, contractAddress);
|
7222
|
+
|
7223
|
+
// eslint-disable-next-line no-var
|
7224
|
+
var [symbol, decimals, name] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
|
7225
|
+
} catch (e) {
|
7226
|
+
if (e instanceof viem.ContractFunctionExecutionError) {
|
7227
|
+
// try to perform the contract read with bytes32 symbol
|
7228
|
+
const contract = getTypedContract(client, viem.erc20Abi_bytes32, contractAddress);
|
7229
|
+
|
7230
|
+
// eslint-disable-next-line no-var
|
7231
|
+
var [bytesSymbol, decimals, nameSymbol] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
|
7232
|
+
symbol = viem.hexToString(bytesSymbol).replace(/\0/g, "").trim(); // remove NULL characters
|
7233
|
+
name = viem.hexToString(nameSymbol).replace(/\0/g, "").trim(); // remove NULL characters
|
7234
|
+
} else throw e;
|
7235
|
+
}
|
7236
|
+
return {
|
7237
|
+
symbol,
|
7238
|
+
decimals,
|
7239
|
+
name
|
7240
|
+
};
|
7241
|
+
};
|
7242
|
+
const getTypedContract = (client, abi, contractAddress) => viem.getContract({
|
7243
|
+
address: contractAddress,
|
7244
|
+
abi,
|
7245
|
+
client: {
|
7246
|
+
public: client
|
7247
|
+
}
|
7248
|
+
});
|
7249
|
+
const getUniswapV2PairContractData = async (client, contractAddress) => {
|
7250
|
+
const contract = getTypedContract(client, uniswapV2PairAbi, contractAddress);
|
7251
|
+
|
7252
|
+
// eslint-disable-next-line no-var
|
7253
|
+
var [token0, token1, decimals, name] = await Promise.all([contract.read.token0(), contract.read.token1(), contract.read.decimals(), contract.read.name()]);
|
7254
|
+
return {
|
7255
|
+
token0,
|
7256
|
+
token1,
|
7257
|
+
decimals,
|
7258
|
+
name
|
7259
|
+
};
|
7260
|
+
};
|
7261
|
+
|
7262
|
+
const TokenCacheSchema = chaindataProvider.EvmUniswapV2TokenSchema.pick({
|
7263
|
+
symbol: true,
|
7264
|
+
decimals: true,
|
7265
|
+
name: true,
|
7266
|
+
tokenAddress0: true,
|
7267
|
+
tokenAddress1: true,
|
7268
|
+
decimals0: true,
|
7269
|
+
decimals1: true,
|
7270
|
+
symbol0: true,
|
7271
|
+
symbol1: true
|
7272
|
+
});
|
7273
|
+
const fetchTokens$6 = async ({
|
7274
|
+
networkId,
|
7275
|
+
tokens,
|
7276
|
+
connector,
|
7277
|
+
cache
|
7278
|
+
}) => {
|
7279
|
+
const result = [];
|
7280
|
+
for (const tokenConfig of tokens) {
|
7281
|
+
const tokenId = chaindataProvider.evmUniswapV2TokenId(networkId, tokenConfig.contractAddress);
|
7282
|
+
if (!cache[tokenId] || !TokenCacheSchema.safeParse(cache[tokenId]).success) {
|
7283
|
+
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
7284
|
+
if (!client) {
|
7285
|
+
log.warn(`No client found for network ${networkId} while fetching EVM ERC20 tokens`);
|
7286
|
+
continue;
|
7287
|
+
}
|
7288
|
+
try {
|
7289
|
+
const {
|
7290
|
+
token0,
|
7291
|
+
token1,
|
7292
|
+
name,
|
7293
|
+
decimals
|
7294
|
+
} = await getUniswapV2PairContractData(client, tokenConfig.contractAddress);
|
7295
|
+
const {
|
7296
|
+
symbol: symbol0,
|
7297
|
+
decimals: decimals0
|
7298
|
+
} = await getErc20ContractData(client, token0);
|
7299
|
+
const {
|
7300
|
+
symbol: symbol1,
|
7301
|
+
decimals: decimals1
|
7302
|
+
} = await getErc20ContractData(client, token1);
|
7303
|
+
cache[tokenId] = {
|
7304
|
+
id: tokenId,
|
7305
|
+
symbol: `${symbol0}/${symbol1}`,
|
7306
|
+
decimals,
|
7307
|
+
name,
|
7308
|
+
tokenAddress0: token0,
|
7309
|
+
tokenAddress1: token1,
|
7310
|
+
decimals0,
|
7311
|
+
decimals1,
|
7312
|
+
symbol0,
|
7313
|
+
symbol1
|
7314
|
+
};
|
7315
|
+
} catch (err) {
|
7316
|
+
log.warn(`Failed to fetch UniswapV2 token data for ${tokenConfig.contractAddress}`, err.shortMessage);
|
7317
|
+
continue;
|
7318
|
+
}
|
7319
|
+
}
|
7320
|
+
const base = {
|
7321
|
+
type: MODULE_TYPE$6,
|
7322
|
+
platform: PLATFORM$6,
|
7323
|
+
networkId
|
7324
|
+
};
|
7325
|
+
const token = lodash.assign(base, cache[tokenId], tokenConfig);
|
7326
|
+
const parsed = chaindataProvider.EvmUniswapV2TokenSchema.safeParse(token);
|
7327
|
+
if (!parsed.success) {
|
7328
|
+
log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
|
7329
|
+
continue;
|
7330
|
+
}
|
7331
|
+
result.push(parsed.data);
|
7332
|
+
}
|
7333
|
+
return result;
|
7334
|
+
};
|
7335
|
+
|
7336
|
+
const getMiniMetadata$6 = () => {
|
7337
|
+
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
7338
|
+
};
|
7339
|
+
|
7340
|
+
const getTransferCallData$6 = ({
|
7341
|
+
from,
|
7342
|
+
to,
|
7343
|
+
value,
|
7344
|
+
token
|
7345
|
+
}) => {
|
7346
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$6)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$6}.`);
|
7347
|
+
if (!util.isEthereumAddress(from)) throw new Error("Invalid from address");
|
7348
|
+
if (!util.isEthereumAddress(to)) throw new Error("Invalid to address");
|
7349
|
+
const data = viem.encodeFunctionData({
|
7350
|
+
abi: viem.erc20Abi,
|
7351
|
+
functionName: "transfer",
|
7352
|
+
args: [to, BigInt(value)]
|
7353
|
+
});
|
7354
|
+
return {
|
7355
|
+
from,
|
7356
|
+
to: token.contractAddress,
|
7357
|
+
data
|
7358
|
+
};
|
7359
|
+
};
|
7360
|
+
|
7361
|
+
const SUBSCRIPTION_INTERVAL$6 = 6_000;
|
7362
|
+
const subscribeBalances$6 = ({
|
7363
|
+
networkId,
|
7364
|
+
addressesByToken,
|
7365
|
+
connector
|
7366
|
+
}) => {
|
7367
|
+
return new rxjs.Observable(subscriber => {
|
7368
|
+
const abortController = new AbortController();
|
7369
|
+
const poll = async () => {
|
7370
|
+
try {
|
7371
|
+
if (abortController.signal.aborted) return;
|
7372
|
+
const balances = await fetchBalances$6({
|
7373
|
+
networkId,
|
7374
|
+
addressesByToken,
|
7375
|
+
connector
|
7376
|
+
});
|
7377
|
+
if (abortController.signal.aborted) return;
|
7378
|
+
subscriber.next(balances);
|
7379
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$6);
|
7380
|
+
} catch (error) {
|
7381
|
+
log.error("Error", {
|
7382
|
+
module: MODULE_TYPE$6,
|
7383
|
+
networkId,
|
7384
|
+
addressesByToken,
|
7385
|
+
error
|
7386
|
+
});
|
7387
|
+
subscriber.error(error);
|
7388
|
+
}
|
7389
|
+
};
|
7390
|
+
poll();
|
7391
|
+
return () => {
|
7392
|
+
abortController.abort();
|
7393
|
+
};
|
7394
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
7395
|
+
};
|
7396
|
+
|
7397
|
+
const EvmUniswapV2BalanceModule = {
|
7398
|
+
type: MODULE_TYPE$6,
|
7399
|
+
platform: PLATFORM$6,
|
7400
|
+
getMiniMetadata: getMiniMetadata$6,
|
7401
|
+
fetchTokens: fetchTokens$6,
|
7402
|
+
fetchBalances: fetchBalances$6,
|
7403
|
+
subscribeBalances: subscribeBalances$6,
|
7404
|
+
getTransferCallData: getTransferCallData$6
|
7405
|
+
};
|
7406
|
+
|
7407
|
+
const MODULE_TYPE$5 = chaindataProvider.SubAssetsTokenSchema.shape.type.value;
|
7408
|
+
const PLATFORM$5 = chaindataProvider.SubAssetsTokenSchema.shape.platform.value;
|
7409
|
+
|
7410
|
+
// to be used by chaindata too
|
7411
|
+
z__default.default.strictObject({
|
7412
|
+
assetId: chaindataProvider.SubAssetsTokenSchema.shape.assetId,
|
7413
|
+
...TokenConfigBaseSchema.shape
|
7414
|
+
});
|
7415
|
+
|
7416
|
+
const fetchBalances$5 = async ({
|
7417
|
+
networkId,
|
7418
|
+
addressesByToken,
|
7419
|
+
connector,
|
7420
|
+
miniMetadata
|
7421
|
+
}) => {
|
7422
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
7423
|
+
if (!miniMetadata?.data) {
|
7424
|
+
log.warn("MiniMetadata is required for fetching balances");
|
7425
|
+
return {
|
7426
|
+
success: [],
|
7427
|
+
errors: balanceDefs.map(def => ({
|
7428
|
+
tokenId: def.token.id,
|
7429
|
+
address: def.address,
|
7430
|
+
error: new Error("Minimetadata is required for fetching balances")
|
7431
|
+
}))
|
7432
|
+
};
|
7433
|
+
}
|
7434
|
+
if (miniMetadata.source !== MODULE_TYPE$5) {
|
7435
|
+
log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$5}.`);
|
7436
|
+
return {
|
7437
|
+
success: [],
|
7438
|
+
errors: balanceDefs.map(def => ({
|
7439
|
+
tokenId: def.token.id,
|
7440
|
+
address: def.address,
|
7441
|
+
error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$5}`)
|
7442
|
+
}))
|
7443
|
+
};
|
7444
|
+
}
|
7445
|
+
if (miniMetadata.chainId !== networkId) {
|
7446
|
+
log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$5}. Expected chainId is ${networkId}`);
|
7447
|
+
return {
|
7448
|
+
success: [],
|
7449
|
+
errors: balanceDefs.map(def => ({
|
7450
|
+
tokenId: def.token.id,
|
7451
|
+
address: def.address,
|
7452
|
+
error: new Error(`Invalid request: Expected chainId is ${networkId}`)
|
7453
|
+
}))
|
7454
|
+
};
|
7455
|
+
}
|
7456
|
+
const queries = buildQueries$2(networkId, balanceDefs, miniMetadata);
|
7457
|
+
const balances = await new RpcStateQueryHelper(connector, queries).fetch();
|
7458
|
+
return balanceDefs.reduce((acc, def) => {
|
7459
|
+
const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
|
7460
|
+
if (balance) acc.success.push(balance);
|
7461
|
+
//if no entry consider empty balance
|
7462
|
+
else acc.success.push({
|
7463
|
+
address: def.address,
|
7464
|
+
networkId,
|
7465
|
+
tokenId: def.token.id,
|
7466
|
+
source: MODULE_TYPE$5,
|
7467
|
+
status: "live",
|
7468
|
+
values: [{
|
7469
|
+
type: "free",
|
7470
|
+
label: "free",
|
7471
|
+
amount: "0"
|
7472
|
+
}, {
|
7473
|
+
type: "locked",
|
7474
|
+
label: "frozen",
|
7475
|
+
amount: "0"
|
7476
|
+
}]
|
7477
|
+
});
|
7478
|
+
return acc;
|
7479
|
+
}, {
|
7480
|
+
success: [],
|
7481
|
+
errors: []
|
7482
|
+
});
|
7483
|
+
};
|
7484
|
+
const buildQueries$2 = (networkId, balanceDefs, miniMetadata) => {
|
7485
|
+
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
7486
|
+
storage: ["Assets", "Account"]
|
7487
|
+
});
|
7488
|
+
return balanceDefs.map(({
|
7489
|
+
token,
|
7490
|
+
address
|
7491
|
+
}) => {
|
7492
|
+
const scaleCoder = networkStorageCoders?.storage;
|
7493
|
+
const stateKey = tryEncode(scaleCoder, Number(token.assetId), address) ??
|
7494
|
+
// Asset Hub
|
7495
|
+
tryEncode(scaleCoder, BigInt(token.assetId), address); // Astar
|
7496
|
+
|
7497
|
+
if (!stateKey) {
|
7498
|
+
log.warn(`Invalid assetId / address in ${networkId} storage query ${token.assetId} / ${address}`);
|
7499
|
+
return null;
|
7500
|
+
}
|
7501
|
+
const decodeResult = change => {
|
7502
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
7503
|
+
|
7504
|
+
const decoded = scale.decodeScale(scaleCoder, change, `Failed to decode substrate-assets balance on chain ${networkId}`) ?? {
|
7505
|
+
balance: 0n,
|
7506
|
+
status: {
|
7507
|
+
type: "Liquid"
|
7508
|
+
}};
|
7509
|
+
const isFrozen = decoded?.status?.type === "Frozen";
|
7510
|
+
const amount = (decoded?.balance ?? 0n).toString();
|
7511
|
+
|
7512
|
+
// due to the following balance calculations, which are made in the `Balance` type:
|
7513
|
+
//
|
7514
|
+
// total balance = (free balance) + (reserved balance)
|
7515
|
+
// transferable balance = (free balance) - (frozen balance)
|
7516
|
+
//
|
7517
|
+
// when `isFrozen` is true we need to set **both** the `free` and `frozen` amounts
|
7518
|
+
// of this balance to the value we received from the RPC.
|
7519
|
+
//
|
7520
|
+
// if we only set the `frozen` amount, then the `total` calculation will be incorrect!
|
7521
|
+
const free = amount;
|
7522
|
+
const frozen = token.isFrozen || isFrozen ? amount : "0";
|
7523
|
+
|
7524
|
+
// include balance values even if zero, so that newly-zero values overwrite old values
|
7525
|
+
const balanceValues = [{
|
7526
|
+
type: "free",
|
7527
|
+
label: "free",
|
7528
|
+
amount: free.toString()
|
7529
|
+
}, {
|
7530
|
+
type: "locked",
|
7531
|
+
label: "frozen",
|
7532
|
+
amount: frozen.toString()
|
7533
|
+
}];
|
7534
|
+
const balance = {
|
7535
|
+
source: "substrate-assets",
|
7536
|
+
status: "live",
|
7537
|
+
address,
|
7538
|
+
networkId,
|
7539
|
+
tokenId: token.id,
|
7540
|
+
values: balanceValues
|
7541
|
+
};
|
7542
|
+
return balance;
|
7543
|
+
};
|
7544
|
+
return {
|
7545
|
+
chainId: networkId,
|
7546
|
+
stateKey,
|
7547
|
+
decodeResult
|
7548
|
+
};
|
7549
|
+
}).filter(util.isNotNil);
|
7550
|
+
};
|
7551
|
+
const tryEncode = (scaleCoder, ...args) => {
|
7552
|
+
try {
|
7553
|
+
return scaleCoder?.keys?.enc?.(...args);
|
7554
|
+
} catch {
|
7555
|
+
return null;
|
7556
|
+
}
|
7557
|
+
};
|
7558
|
+
|
7559
|
+
const fetchTokens$5 = async ({
|
7560
|
+
networkId,
|
7561
|
+
tokens,
|
7562
|
+
connector,
|
7563
|
+
miniMetadata
|
7564
|
+
}) => {
|
7565
|
+
const anyMiniMetadata = miniMetadata;
|
7566
|
+
if (!anyMiniMetadata?.data) return [];
|
7567
|
+
const {
|
7568
|
+
builder
|
7569
|
+
} = scale.parseMetadataRpc(anyMiniMetadata.data);
|
7570
|
+
const assetCodec = builder.buildStorage("Assets", "Asset");
|
7571
|
+
const metadataCodec = builder.buildStorage("Assets", "Metadata");
|
7572
|
+
const [allAssetStorageKeys, allMetadataStorageKeys] = await Promise.all([connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("Assets", "Asset")]), connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("Assets", "Metadata")])]);
|
7573
|
+
const [assetStorageResults, metadataStorageResults] = await Promise.all([connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]), connector.send(networkId, "state_queryStorageAt", [allMetadataStorageKeys])]);
|
7574
|
+
const assetStorageEntries = assetStorageResults[0].changes;
|
7575
|
+
const metadataStorageEntries = metadataStorageResults[0].changes;
|
7576
|
+
const assetByAssetId = lodash.keyBy(assetStorageEntries.map(([key, value]) => {
|
7577
|
+
const [assetId] = assetCodec.keys.dec(key);
|
7578
|
+
const asset = assetCodec.value.dec(value);
|
7579
|
+
return {
|
7580
|
+
assetId,
|
7581
|
+
existentialDeposit: asset.min_balance,
|
7582
|
+
isSufficient: asset.is_sufficient
|
7583
|
+
};
|
7584
|
+
}), a => a.assetId);
|
7585
|
+
const metadataByAssetId = lodash.keyBy(metadataStorageEntries.map(([key, value]) => {
|
7586
|
+
const [assetId] = metadataCodec.keys.dec(key);
|
7587
|
+
const metadata = metadataCodec.value.dec(value);
|
7588
|
+
return {
|
7589
|
+
assetId,
|
7590
|
+
decimals: metadata.decimals,
|
7591
|
+
isFrozen: metadata.is_frozen,
|
7592
|
+
name: metadata.name?.asText(),
|
7593
|
+
symbol: metadata.symbol?.asText()
|
7594
|
+
};
|
7595
|
+
}), a => a.assetId);
|
7596
|
+
const allTokens = lodash.keys(assetByAssetId).map(assetId => lodash.assign({}, assetByAssetId[assetId], metadataByAssetId[assetId] ?? undefined));
|
7597
|
+
const configTokenByAssetId = lodash.keyBy(tokens, t => t.assetId);
|
7598
|
+
return allTokens.map(asset => ({
|
7599
|
+
id: chaindataProvider.subAssetTokenId(networkId, String(asset.assetId)),
|
7600
|
+
type: MODULE_TYPE$5,
|
7601
|
+
platform: "polkadot",
|
7602
|
+
networkId,
|
7603
|
+
assetId: String(asset.assetId),
|
7604
|
+
isSufficient: asset.isSufficient,
|
7605
|
+
isFrozen: asset.isFrozen,
|
7606
|
+
name: asset.name,
|
7607
|
+
symbol: asset.symbol,
|
7608
|
+
decimals: asset.decimals ?? 0,
|
7609
|
+
existentialDeposit: String(asset.existentialDeposit),
|
7610
|
+
isDefault: true
|
7611
|
+
}))
|
7612
|
+
// keep all tokens listed in the config + all tokens marked as sufficient
|
7613
|
+
.filter(token => {
|
7614
|
+
const configToken = configTokenByAssetId[token.assetId];
|
7615
|
+
return configToken || token.isSufficient;
|
7616
|
+
})
|
7617
|
+
// apply config overrides
|
7618
|
+
.map(token => {
|
7619
|
+
const configToken = configTokenByAssetId[token.assetId];
|
7620
|
+
return configToken ? lodash.assign({}, token, configToken) : token;
|
7621
|
+
})
|
7622
|
+
// validate results
|
7623
|
+
.filter(t => {
|
7624
|
+
const parsed = chaindataProvider.SubAssetsTokenSchema.safeParse(t);
|
7625
|
+
if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$5}`, t);
|
7626
|
+
return parsed.success;
|
7627
|
+
});
|
7628
|
+
};
|
7629
|
+
|
7630
|
+
const getConstantValue = (metadataRpc, pallet, constant) => {
|
7631
|
+
const {
|
7632
|
+
unifiedMetadata,
|
7633
|
+
builder
|
7634
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
7635
|
+
const codec = builder.buildConstant(pallet, constant);
|
7636
|
+
const encodedValue = unifiedMetadata.pallets.find(({
|
7637
|
+
name
|
7638
|
+
}) => name === pallet)?.constants.find(({
|
7639
|
+
name
|
7640
|
+
}) => name === constant)?.value;
|
7641
|
+
if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
|
7642
|
+
return codec.dec(encodedValue);
|
7643
|
+
};
|
7644
|
+
|
7645
|
+
const hasStorageItem = (metadata, palletName, itemName) => {
|
7646
|
+
const pallet = metadata.pallets.find(p => p.name === palletName);
|
7647
|
+
if (!pallet || !pallet.storage) return false;
|
7648
|
+
return pallet.storage.items.some(item => item.name === itemName);
|
7649
|
+
};
|
7650
|
+
const hasStorageItems = (metadata, palletName, itemNames) => {
|
7651
|
+
const pallet = metadata.pallets.find(p => p.name === palletName);
|
7652
|
+
if (!pallet || !pallet.storage) return false;
|
7653
|
+
return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
|
7654
|
+
};
|
7655
|
+
const hasRuntimeApi = (metadata, apiName, method) => {
|
7656
|
+
const api = metadata.apis.find(api => api.name === apiName);
|
7657
|
+
if (!api || !api.methods) return false;
|
7658
|
+
return api.methods.some(m => m.name === method);
|
7659
|
+
};
|
7660
|
+
|
7661
|
+
const getMiniMetadata$5 = ({
|
7662
|
+
networkId,
|
7663
|
+
specVersion,
|
7664
|
+
metadataRpc
|
7665
|
+
}) => {
|
7666
|
+
const source = MODULE_TYPE$5;
|
7667
|
+
const chainId = networkId;
|
7668
|
+
const systemVersion = getConstantValue(metadataRpc, "System", "Version");
|
7669
|
+
if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
|
7670
|
+
networkId,
|
7671
|
+
specVersion,
|
7672
|
+
systemVersion
|
7673
|
+
});
|
7674
|
+
const id = deriveMiniMetadataId({
|
7675
|
+
source,
|
7676
|
+
chainId,
|
7677
|
+
specVersion
|
7678
|
+
});
|
7679
|
+
const {
|
7680
|
+
unifiedMetadata
|
7681
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
7682
|
+
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
7683
|
+
return {
|
7684
|
+
id,
|
7685
|
+
source,
|
7686
|
+
chainId,
|
7687
|
+
specVersion,
|
7688
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
7689
|
+
data: getData$3(metadataRpc),
|
7690
|
+
extra: null
|
7691
|
+
};
|
7692
|
+
};
|
7693
|
+
const getData$3 = metadataRpc => {
|
7694
|
+
const {
|
7695
|
+
metadata,
|
7696
|
+
unifiedMetadata
|
7697
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
7698
|
+
|
7699
|
+
// ensure the network has all the required bits
|
7700
|
+
if (!hasStorageItems(unifiedMetadata, "Assets", ["Account", "Asset", "Metadata"])) return null;
|
7701
|
+
scale.compactMetadata(metadata, [{
|
7702
|
+
pallet: "Assets",
|
7703
|
+
items: ["Account", "Asset", "Metadata"]
|
7704
|
+
}]);
|
7705
|
+
return scale.encodeMetadata(metadata);
|
7706
|
+
};
|
7707
|
+
|
7708
|
+
const getTransferCallData$5 = ({
|
7709
|
+
from,
|
7710
|
+
to,
|
7711
|
+
value,
|
7712
|
+
token,
|
7713
|
+
type,
|
7714
|
+
metadataRpc
|
7715
|
+
}) => {
|
7716
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$5)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$5}.`);
|
7717
|
+
const {
|
7718
|
+
builder
|
7719
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
7720
|
+
const method = getTransferMethod$3(type);
|
7721
|
+
const {
|
7722
|
+
codec,
|
7723
|
+
location
|
7724
|
+
} = builder.buildCall("Assets", method);
|
7725
|
+
const args = getEncodedArgs$2(method, token.assetId, to, value, codec);
|
7726
|
+
const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
|
7727
|
+
return {
|
7728
|
+
address: from,
|
7729
|
+
method: callData.asHex()
|
7730
|
+
};
|
7731
|
+
};
|
7732
|
+
const getTransferMethod$3 = type => {
|
7733
|
+
switch (type) {
|
7734
|
+
case "keep-alive":
|
7735
|
+
return "transfer_keep_alive";
|
7736
|
+
case "all":
|
7737
|
+
return "transfer_all";
|
7738
|
+
case "allow-death":
|
7739
|
+
return "transfer";
|
7740
|
+
}
|
7741
|
+
};
|
7742
|
+
const getEncodedArgs$2 = (method, assetId, to, value, argsCodec) => {
|
7743
|
+
try {
|
7744
|
+
switch (method) {
|
7745
|
+
case "transfer_keep_alive":
|
7746
|
+
case "transfer":
|
7747
|
+
return getTransferEncodedArgs$2(assetId, to, value, argsCodec);
|
7748
|
+
case "transfer_all":
|
7749
|
+
return getTransferAllEncodedArgs$2(assetId, to, argsCodec);
|
7750
|
+
}
|
7751
|
+
} catch {
|
7752
|
+
throw new Error(`Failed to encode arguments for method ${method}: ${assetId}, ${to}, ${value}`);
|
7753
|
+
}
|
7754
|
+
};
|
7755
|
+
const getEncodedValue$2 = (codec, possibleValue) => {
|
7756
|
+
for (const getArgs of possibleValue) {
|
7757
|
+
try {
|
7758
|
+
return codec.enc(getArgs());
|
7759
|
+
} catch (error) {
|
7760
|
+
// wrong inputs, ignore and try the next one
|
7761
|
+
}
|
7762
|
+
}
|
7763
|
+
throw new Error("Failed to encode");
|
7764
|
+
};
|
7765
|
+
|
7766
|
+
// same inputs for both KeepAlive and allowDeath
|
7767
|
+
const getTransferEncodedArgs$2 = (assetId, to, value, codec) => {
|
7768
|
+
return getEncodedValue$2(codec, [() => ({
|
7769
|
+
id: Number(assetId),
|
7770
|
+
// for most networks
|
7771
|
+
target: polkadotApi.Enum("Id", to),
|
7772
|
+
amount: BigInt(value)
|
7773
|
+
}), () => ({
|
7774
|
+
id: BigInt(assetId),
|
7775
|
+
// for Astar
|
7776
|
+
target: polkadotApi.Enum("Id", to),
|
7777
|
+
amount: BigInt(value)
|
7778
|
+
})]);
|
7779
|
+
};
|
7780
|
+
const getTransferAllEncodedArgs$2 = (assetId, to, codec) => {
|
7781
|
+
return getEncodedValue$2(codec, [() => ({
|
7782
|
+
id: Number(assetId),
|
7783
|
+
// for most networks
|
7784
|
+
target: polkadotApi.Enum("Id", to),
|
7785
|
+
keep_alive: false
|
7786
|
+
}), () => ({
|
7787
|
+
id: BigInt(assetId),
|
7788
|
+
// for Astar
|
7789
|
+
target: polkadotApi.Enum("Id", to),
|
7790
|
+
keep_alive: false
|
7791
|
+
})]);
|
7792
|
+
};
|
7793
|
+
|
7794
|
+
const SUBSCRIPTION_INTERVAL$5 = 6_000;
|
7795
|
+
const subscribeBalances$5 = ({
|
7796
|
+
networkId,
|
7797
|
+
addressesByToken,
|
7798
|
+
connector,
|
7799
|
+
miniMetadata
|
7800
|
+
}) => {
|
7801
|
+
return new rxjs.Observable(subscriber => {
|
7802
|
+
const abortController = new AbortController();
|
7803
|
+
|
7804
|
+
// on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
|
7805
|
+
// => poll values for each block
|
7806
|
+
const poll = async () => {
|
7807
|
+
try {
|
7808
|
+
if (abortController.signal.aborted) return;
|
7809
|
+
const balances = await fetchBalances$5({
|
7810
|
+
networkId,
|
7811
|
+
addressesByToken,
|
7812
|
+
connector,
|
7813
|
+
miniMetadata
|
7814
|
+
});
|
7815
|
+
if (abortController.signal.aborted) return;
|
7816
|
+
subscriber.next(balances);
|
7817
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$5);
|
7818
|
+
} catch (error) {
|
7819
|
+
log.error("Error", {
|
7820
|
+
module: MODULE_TYPE$5,
|
7821
|
+
networkId,
|
7822
|
+
miniMetadata,
|
7823
|
+
addressesByToken,
|
7824
|
+
error
|
7825
|
+
});
|
7826
|
+
subscriber.error(error);
|
7827
|
+
}
|
7828
|
+
};
|
7829
|
+
poll();
|
7830
|
+
return () => {
|
7831
|
+
abortController.abort();
|
7832
|
+
};
|
7833
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
7834
|
+
};
|
7835
|
+
|
7836
|
+
const SubAssetsBalanceModule = {
|
7837
|
+
type: MODULE_TYPE$5,
|
7838
|
+
platform: PLATFORM$5,
|
7839
|
+
getMiniMetadata: getMiniMetadata$5,
|
7840
|
+
fetchTokens: fetchTokens$5,
|
7841
|
+
fetchBalances: fetchBalances$5,
|
7842
|
+
subscribeBalances: subscribeBalances$5,
|
7843
|
+
getTransferCallData: getTransferCallData$5
|
7844
|
+
};
|
7845
|
+
|
7846
|
+
const MODULE_TYPE$4 = chaindataProvider.SubForeignAssetsTokenSchema.shape.type.value;
|
7847
|
+
const PLATFORM$4 = chaindataProvider.SubForeignAssetsTokenSchema.shape.platform.value;
|
7848
|
+
|
7849
|
+
// to be used by chaindata too
|
7850
|
+
z__default.default.strictObject({
|
7851
|
+
onChainId: chaindataProvider.SubForeignAssetsTokenSchema.shape.onChainId,
|
7852
|
+
...TokenConfigBaseSchema.shape
|
7853
|
+
});
|
7854
|
+
|
7855
|
+
const fetchBalances$4 = async ({
|
7856
|
+
networkId,
|
7857
|
+
addressesByToken,
|
7858
|
+
connector,
|
7859
|
+
miniMetadata
|
7860
|
+
}) => {
|
7861
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
7862
|
+
if (!miniMetadata?.data) {
|
7863
|
+
log.warn("MiniMetadata is required for fetching balances");
|
7864
|
+
return {
|
7865
|
+
success: [],
|
7866
|
+
errors: balanceDefs.map(def => ({
|
7867
|
+
tokenId: def.token.id,
|
7868
|
+
address: def.address,
|
7869
|
+
error: new Error("Minimetadata is required for fetching balances")
|
7870
|
+
}))
|
7871
|
+
};
|
7872
|
+
}
|
7873
|
+
if (miniMetadata.source !== MODULE_TYPE$4) {
|
7874
|
+
log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$4}.`);
|
7875
|
+
return {
|
7876
|
+
success: [],
|
7877
|
+
errors: balanceDefs.map(def => ({
|
7878
|
+
tokenId: def.token.id,
|
7879
|
+
address: def.address,
|
7880
|
+
error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$4}`)
|
7881
|
+
}))
|
7882
|
+
};
|
7883
|
+
}
|
7884
|
+
if (miniMetadata.chainId !== networkId) {
|
7885
|
+
log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$4}. Expected chainId is ${networkId}`);
|
7886
|
+
return {
|
7887
|
+
success: [],
|
7888
|
+
errors: balanceDefs.map(def => ({
|
7889
|
+
tokenId: def.token.id,
|
7890
|
+
address: def.address,
|
7891
|
+
error: new Error(`Invalid request: Expected chainId is ${networkId}`)
|
7892
|
+
}))
|
7893
|
+
};
|
7894
|
+
}
|
7895
|
+
const queries = buildQueries$1(networkId, balanceDefs, miniMetadata);
|
7896
|
+
const balances = await new RpcStateQueryHelper(connector, queries).fetch();
|
7897
|
+
return balanceDefs.reduce((acc, def) => {
|
7898
|
+
const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
|
7899
|
+
if (balance) acc.success.push(balance);
|
7900
|
+
//if no entry consider empty balance
|
7901
|
+
else acc.success.push({
|
7902
|
+
address: def.address,
|
7903
|
+
networkId,
|
7904
|
+
tokenId: def.token.id,
|
7905
|
+
source: MODULE_TYPE$4,
|
7906
|
+
status: "live",
|
7907
|
+
values: [{
|
7908
|
+
type: "free",
|
7909
|
+
label: "free",
|
7910
|
+
amount: "0"
|
7911
|
+
}, {
|
7912
|
+
type: "locked",
|
7913
|
+
label: "frozen",
|
7914
|
+
amount: "0"
|
7915
|
+
}]
|
7916
|
+
});
|
7917
|
+
return acc;
|
7918
|
+
}, {
|
7919
|
+
success: [],
|
7920
|
+
errors: []
|
7921
|
+
});
|
7922
|
+
};
|
7923
|
+
const buildQueries$1 = (networkId, balanceDefs, miniMetadata) => {
|
7924
|
+
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
7925
|
+
storage: ["ForeignAssets", "Account"]
|
7926
|
+
});
|
7927
|
+
return balanceDefs.map(({
|
7928
|
+
token,
|
7929
|
+
address
|
7930
|
+
}) => {
|
7931
|
+
const scaleCoder = networkStorageCoders?.storage;
|
7932
|
+
const getStateKey = onChainId => {
|
7933
|
+
try {
|
7934
|
+
return scaleCoder?.keys?.enc?.(scale.papiParse(onChainId), address);
|
7935
|
+
} catch {
|
7936
|
+
return null;
|
7937
|
+
}
|
7938
|
+
};
|
7939
|
+
const stateKey = getStateKey(token.onChainId);
|
7940
|
+
if (!stateKey) {
|
7941
|
+
log.warn(`Invalid assetId / address in ${networkId} storage query ${token.onChainId} / ${address}`);
|
7942
|
+
return null;
|
7943
|
+
}
|
7944
|
+
const decodeResult = change => {
|
7945
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
7946
|
+
|
7947
|
+
const decoded = scale.decodeScale(scaleCoder, change, `Failed to decode substrate-assets balance on chain ${networkId}`) ?? {
|
7948
|
+
balance: 0n,
|
7949
|
+
is_frozen: false,
|
7950
|
+
status: {
|
7951
|
+
type: "Liquid"
|
7952
|
+
}};
|
7953
|
+
const isFrozen = decoded.is_frozen ?? decoded?.status?.type === "Frozen";
|
7954
|
+
const amount = (decoded?.balance ?? 0n).toString();
|
7955
|
+
|
7956
|
+
// due to the following balance calculations, which are made in the `Balance` type:
|
7957
|
+
//
|
7958
|
+
// total balance = (free balance) + (reserved balance)
|
7959
|
+
// transferable balance = (free balance) - (frozen balance)
|
7960
|
+
//
|
7961
|
+
// when `isFrozen` is true we need to set **both** the `free` and `frozen` amounts
|
7962
|
+
// of this balance to the value we received from the RPC.
|
7963
|
+
//
|
7964
|
+
// if we only set the `frozen` amount, then the `total` calculation will be incorrect!
|
7965
|
+
const free = amount;
|
7966
|
+
const frozen = token.isFrozen || isFrozen ? amount : "0";
|
7967
|
+
|
7968
|
+
// include balance values even if zero, so that newly-zero values overwrite old values
|
7969
|
+
const balanceValues = [{
|
7970
|
+
type: "free",
|
7971
|
+
label: "free",
|
7972
|
+
amount: free.toString()
|
7973
|
+
}, {
|
7974
|
+
type: "locked",
|
7975
|
+
label: "frozen",
|
7976
|
+
amount: frozen.toString()
|
7977
|
+
}];
|
7978
|
+
const balance = {
|
7979
|
+
source: "substrate-assets",
|
7980
|
+
status: "live",
|
7981
|
+
address,
|
7982
|
+
networkId,
|
7983
|
+
tokenId: token.id,
|
7984
|
+
values: balanceValues
|
7985
|
+
};
|
7986
|
+
return balance;
|
7987
|
+
};
|
7988
|
+
return {
|
7989
|
+
chainId: networkId,
|
7990
|
+
stateKey,
|
7991
|
+
decodeResult
|
7992
|
+
};
|
7993
|
+
}).filter(util.isNotNil);
|
7994
|
+
};
|
7995
|
+
|
7996
|
+
const fetchTokens$4 = async ({
|
7997
|
+
networkId,
|
7998
|
+
tokens,
|
7999
|
+
connector,
|
8000
|
+
miniMetadata
|
8001
|
+
}) => {
|
8002
|
+
const anyMiniMetadata = miniMetadata;
|
8003
|
+
if (!anyMiniMetadata?.data) return [];
|
8004
|
+
const {
|
8005
|
+
builder
|
8006
|
+
} = scale.parseMetadataRpc(anyMiniMetadata.data);
|
8007
|
+
const assetCodec = builder.buildStorage("ForeignAssets", "Asset");
|
8008
|
+
const metadataCodec = builder.buildStorage("ForeignAssets", "Metadata");
|
8009
|
+
const [allAssetStorageKeys, allMetadataStorageKeys] = await Promise.all([connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("ForeignAssets", "Asset")]), connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("ForeignAssets", "Metadata")])]);
|
8010
|
+
const [assetStorageResults, metadataStorageResults] = await Promise.all([connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]), connector.send(networkId, "state_queryStorageAt", [allMetadataStorageKeys])]);
|
8011
|
+
const assetStorageEntries = assetStorageResults[0].changes;
|
8012
|
+
const metadataStorageEntries = metadataStorageResults[0].changes;
|
8013
|
+
const assetByOnChainId = lodash.keyBy(assetStorageEntries.map(([key, value]) => {
|
8014
|
+
const [decodedKey] = assetCodec.keys.dec(key);
|
8015
|
+
const onChainId = scale.papiStringify(decodedKey);
|
8016
|
+
const asset = assetCodec.value.dec(value);
|
8017
|
+
return {
|
8018
|
+
onChainId,
|
8019
|
+
existentialDeposit: asset.min_balance,
|
8020
|
+
isSufficient: asset.is_sufficient
|
8021
|
+
};
|
8022
|
+
}), a => a.onChainId);
|
8023
|
+
const metadataByOnChainId = lodash.keyBy(metadataStorageEntries.map(([key, value]) => {
|
8024
|
+
const [decodedKey] = metadataCodec.keys.dec(key);
|
8025
|
+
const onChainId = scale.papiStringify(decodedKey);
|
8026
|
+
const metadata = metadataCodec.value.dec(value);
|
8027
|
+
return {
|
8028
|
+
onChainId,
|
8029
|
+
decimals: metadata.decimals,
|
8030
|
+
isFrozen: metadata.is_frozen,
|
8031
|
+
name: metadata.name?.asText(),
|
8032
|
+
symbol: metadata.symbol?.asText()
|
8033
|
+
};
|
8034
|
+
}), a => a.onChainId);
|
8035
|
+
const allTokens = lodash.keys(assetByOnChainId).map(onChainId => lodash.assign({}, assetByOnChainId[onChainId], metadataByOnChainId[onChainId] ?? undefined));
|
8036
|
+
const configTokenByOnChainId = lodash.keyBy(tokens, t => t.onChainId);
|
8037
|
+
return allTokens.map(asset => ({
|
8038
|
+
id: chaindataProvider.subForeignAssetTokenId(networkId, asset.onChainId),
|
8039
|
+
type: MODULE_TYPE$4,
|
8040
|
+
platform: "polkadot",
|
8041
|
+
networkId,
|
8042
|
+
onChainId: String(asset.onChainId),
|
8043
|
+
isSufficient: asset.isSufficient,
|
8044
|
+
isFrozen: asset.isFrozen,
|
8045
|
+
name: asset.name,
|
8046
|
+
symbol: asset.symbol,
|
8047
|
+
decimals: asset.decimals ?? 0,
|
8048
|
+
existentialDeposit: String(asset.existentialDeposit),
|
8049
|
+
isDefault: true
|
8050
|
+
}))
|
8051
|
+
// keep all tokens listed in the config + all tokens marked as sufficient
|
8052
|
+
.filter(token => {
|
8053
|
+
const configToken = configTokenByOnChainId[token.onChainId];
|
8054
|
+
return configToken || token.isSufficient;
|
8055
|
+
})
|
8056
|
+
// apply config overrides
|
8057
|
+
.map(token => {
|
8058
|
+
const configToken = configTokenByOnChainId[token.onChainId];
|
8059
|
+
return configToken ? lodash.assign({}, token, configToken) : token;
|
8060
|
+
})
|
8061
|
+
// validate results
|
8062
|
+
.filter(t => {
|
8063
|
+
const parsed = chaindataProvider.SubForeignAssetsTokenSchema.safeParse(t);
|
8064
|
+
if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$4}`, t);
|
8065
|
+
return parsed.success;
|
8066
|
+
});
|
8067
|
+
};
|
8068
|
+
|
8069
|
+
const getMiniMetadata$4 = ({
|
8070
|
+
networkId,
|
8071
|
+
specVersion,
|
8072
|
+
metadataRpc
|
8073
|
+
}) => {
|
8074
|
+
const source = MODULE_TYPE$4;
|
8075
|
+
const chainId = networkId;
|
8076
|
+
const systemVersion = getConstantValue(metadataRpc, "System", "Version");
|
8077
|
+
if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
|
8078
|
+
networkId,
|
8079
|
+
specVersion,
|
8080
|
+
systemVersion
|
8081
|
+
});
|
8082
|
+
const id = deriveMiniMetadataId({
|
8083
|
+
source,
|
8084
|
+
chainId,
|
8085
|
+
specVersion
|
8086
|
+
});
|
8087
|
+
const {
|
8088
|
+
unifiedMetadata
|
8089
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8090
|
+
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
8091
|
+
return {
|
8092
|
+
id,
|
8093
|
+
source,
|
8094
|
+
chainId,
|
8095
|
+
specVersion,
|
8096
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
8097
|
+
data: getData$2(metadataRpc),
|
8098
|
+
extra: null
|
8099
|
+
};
|
8100
|
+
};
|
8101
|
+
const getData$2 = metadataRpc => {
|
8102
|
+
const {
|
8103
|
+
metadata,
|
8104
|
+
unifiedMetadata
|
8105
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8106
|
+
|
8107
|
+
// ensure the network has all the required bits
|
8108
|
+
if (!hasStorageItems(unifiedMetadata, "ForeignAssets", ["Account", "Asset", "Metadata"])) return null;
|
8109
|
+
scale.compactMetadata(metadata, [{
|
8110
|
+
pallet: "ForeignAssets",
|
8111
|
+
items: ["Account", "Asset", "Metadata"]
|
8112
|
+
}]);
|
8113
|
+
return scale.encodeMetadata(metadata);
|
8114
|
+
};
|
8115
|
+
|
8116
|
+
const getTransferCallData$4 = ({
|
8117
|
+
from,
|
8118
|
+
to,
|
8119
|
+
value,
|
8120
|
+
token,
|
8121
|
+
type,
|
8122
|
+
metadataRpc
|
8123
|
+
}) => {
|
8124
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$4)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$4}.`);
|
8125
|
+
const {
|
8126
|
+
builder
|
8127
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8128
|
+
const method = getTransferMethod$2(type);
|
8129
|
+
const {
|
8130
|
+
codec,
|
8131
|
+
location
|
8132
|
+
} = builder.buildCall("ForeignAssets", method);
|
8133
|
+
const args = getEncodedArgs$1(method, token.onChainId, to, value, codec);
|
8134
|
+
const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
|
8135
|
+
return {
|
8136
|
+
address: from,
|
8137
|
+
method: callData.asHex()
|
8138
|
+
};
|
8139
|
+
};
|
8140
|
+
const getTransferMethod$2 = type => {
|
8141
|
+
switch (type) {
|
8142
|
+
case "keep-alive":
|
8143
|
+
return "transfer_keep_alive";
|
8144
|
+
case "all":
|
8145
|
+
return "transfer_all";
|
8146
|
+
case "allow-death":
|
8147
|
+
return "transfer";
|
8148
|
+
}
|
8149
|
+
};
|
8150
|
+
const getEncodedArgs$1 = (method, onChainId, to, value, argsCodec) => {
|
8151
|
+
try {
|
8152
|
+
switch (method) {
|
8153
|
+
case "transfer_keep_alive":
|
8154
|
+
case "transfer":
|
8155
|
+
return getTransferEncodedArgs$1(onChainId, to, value, argsCodec);
|
8156
|
+
case "transfer_all":
|
8157
|
+
return getTransferAllEncodedArgs$1(onChainId, to, argsCodec);
|
8158
|
+
}
|
8159
|
+
} catch {
|
8160
|
+
throw new Error(`Failed to encode arguments for method ${method}: ${onChainId}, ${to}, ${value}`);
|
8161
|
+
}
|
8162
|
+
};
|
8163
|
+
const getEncodedValue$1 = (codec, possibleValue) => {
|
8164
|
+
for (const getArgs of possibleValue) {
|
8165
|
+
try {
|
8166
|
+
return codec.enc(getArgs());
|
8167
|
+
} catch (error) {
|
8168
|
+
// wrong inputs, ignore and try the next one
|
8169
|
+
}
|
8170
|
+
}
|
8171
|
+
throw new Error("Failed to encode");
|
8172
|
+
};
|
8173
|
+
|
8174
|
+
// same inputs for both KeepAlive and allowDeath
|
8175
|
+
const getTransferEncodedArgs$1 = (onChainId, to, value, codec) => {
|
8176
|
+
return getEncodedValue$1(codec, [() => ({
|
8177
|
+
id: scale.papiParse(onChainId),
|
8178
|
+
// for most networks
|
8179
|
+
target: polkadotApi.Enum("Id", to),
|
8180
|
+
amount: BigInt(value)
|
8181
|
+
})]);
|
8182
|
+
};
|
8183
|
+
const getTransferAllEncodedArgs$1 = (onChainId, to, codec) => {
|
8184
|
+
return getEncodedValue$1(codec, [() => ({
|
8185
|
+
id: scale.papiParse(onChainId),
|
8186
|
+
// for most networks
|
8187
|
+
target: polkadotApi.Enum("Id", to),
|
8188
|
+
keep_alive: false
|
8189
|
+
})]);
|
8190
|
+
};
|
8191
|
+
|
8192
|
+
const SUBSCRIPTION_INTERVAL$4 = 6_000;
|
8193
|
+
const subscribeBalances$4 = ({
|
8194
|
+
networkId,
|
8195
|
+
addressesByToken,
|
8196
|
+
connector,
|
8197
|
+
miniMetadata
|
8198
|
+
}) => {
|
8199
|
+
return new rxjs.Observable(subscriber => {
|
8200
|
+
const abortController = new AbortController();
|
8201
|
+
|
8202
|
+
// on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
|
8203
|
+
// => poll values for each block
|
8204
|
+
const poll = async () => {
|
8205
|
+
try {
|
8206
|
+
if (abortController.signal.aborted) return;
|
8207
|
+
const balances = await fetchBalances$4({
|
8208
|
+
networkId,
|
8209
|
+
addressesByToken,
|
8210
|
+
connector,
|
8211
|
+
miniMetadata
|
8212
|
+
});
|
8213
|
+
if (abortController.signal.aborted) return;
|
8214
|
+
subscriber.next(balances);
|
8215
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$4);
|
8216
|
+
} catch (error) {
|
8217
|
+
log.error("Error", {
|
8218
|
+
module: MODULE_TYPE$4,
|
8219
|
+
networkId,
|
8220
|
+
miniMetadata,
|
8221
|
+
addressesByToken,
|
8222
|
+
error
|
8223
|
+
});
|
8224
|
+
subscriber.error(error);
|
8225
|
+
}
|
8226
|
+
};
|
8227
|
+
poll();
|
8228
|
+
return () => {
|
8229
|
+
abortController.abort();
|
8230
|
+
};
|
8231
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
8232
|
+
};
|
8233
|
+
|
8234
|
+
const SubForeignAssetsBalanceModule = {
|
8235
|
+
type: MODULE_TYPE$4,
|
8236
|
+
platform: PLATFORM$4,
|
8237
|
+
getMiniMetadata: getMiniMetadata$4,
|
8238
|
+
fetchTokens: fetchTokens$4,
|
8239
|
+
fetchBalances: fetchBalances$4,
|
8240
|
+
subscribeBalances: subscribeBalances$4,
|
8241
|
+
getTransferCallData: getTransferCallData$4
|
8242
|
+
};
|
8243
|
+
|
8244
|
+
// to be used by chaindata too
|
8245
|
+
z__default.default.strictObject({
|
8246
|
+
onChainId: chaindataProvider.SubHydrationTokenSchema.shape.onChainId,
|
8247
|
+
...TokenConfigBaseSchema.shape
|
8248
|
+
});
|
8249
|
+
|
8250
|
+
const MODULE_TYPE$3 = chaindataProvider.SubHydrationTokenSchema.shape.type.value;
|
8251
|
+
const PLATFORM$3 = chaindataProvider.SubHydrationTokenSchema.shape.platform.value;
|
8252
|
+
|
8253
|
+
const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
|
8254
|
+
const {
|
8255
|
+
builder
|
8256
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8257
|
+
const call = builder.buildRuntimeCall(apiName, method);
|
8258
|
+
const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, scale.toHex(call.args.enc(args))]);
|
8259
|
+
return call.value.dec(hex);
|
8260
|
+
};
|
8261
|
+
|
8262
|
+
const tryGetConstantValue = (metadataRpc, pallet, constant) => {
|
8263
|
+
const {
|
8264
|
+
unifiedMetadata,
|
8265
|
+
builder
|
8266
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8267
|
+
const encodedValue = unifiedMetadata.pallets.find(({
|
8268
|
+
name
|
8269
|
+
}) => name === pallet)?.constants.find(({
|
8270
|
+
name
|
8271
|
+
}) => name === constant)?.value;
|
8272
|
+
if (!encodedValue) return null;
|
8273
|
+
const codec = builder.buildConstant(pallet, constant);
|
8274
|
+
return codec.dec(encodedValue);
|
8275
|
+
};
|
8276
|
+
|
8277
|
+
const fetchBalances$3 = async ({
|
8278
|
+
networkId,
|
8279
|
+
addressesByToken,
|
8280
|
+
connector,
|
8281
|
+
miniMetadata
|
8282
|
+
}) => {
|
8283
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
8284
|
+
if (!miniMetadata?.data) {
|
8285
|
+
log.warn("MiniMetadata is required for fetching balances");
|
8286
|
+
return {
|
8287
|
+
success: [],
|
8288
|
+
errors: balanceDefs.map(def => ({
|
8289
|
+
tokenId: def.token.id,
|
8290
|
+
address: def.address,
|
8291
|
+
error: new Error("Minimetadata is required for fetching balances")
|
8292
|
+
}))
|
8293
|
+
};
|
8294
|
+
}
|
8295
|
+
if (miniMetadata.source !== MODULE_TYPE$3) {
|
8296
|
+
log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$3}.`);
|
8297
|
+
return {
|
8298
|
+
success: [],
|
8299
|
+
errors: balanceDefs.map(def => ({
|
8300
|
+
tokenId: def.token.id,
|
8301
|
+
address: def.address,
|
8302
|
+
error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$3}`)
|
8303
|
+
}))
|
8304
|
+
};
|
8305
|
+
}
|
8306
|
+
if (miniMetadata.chainId !== networkId) {
|
8307
|
+
log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$3}. Expected chainId is ${networkId}`);
|
8308
|
+
return {
|
8309
|
+
success: [],
|
8310
|
+
errors: balanceDefs.map(def => ({
|
8311
|
+
tokenId: def.token.id,
|
8312
|
+
address: def.address,
|
8313
|
+
error: new Error(`Invalid request: Expected chainId is ${networkId}`)
|
8314
|
+
}))
|
8315
|
+
};
|
8316
|
+
}
|
8317
|
+
const addresses = lodash.uniq(balanceDefs.map(def => def.address));
|
8318
|
+
try {
|
8319
|
+
const res = await Promise.all(addresses.map(address => fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "CurrenciesApi", "accounts", [address])));
|
8320
|
+
const fetchedBalances = addresses.flatMap((address, index) => {
|
8321
|
+
return res[index].map(([onChainId, balance]) => ({
|
8322
|
+
address,
|
8323
|
+
onChainId,
|
8324
|
+
free: balance.free.toString(),
|
8325
|
+
reserved: balance.reserved.toString(),
|
8326
|
+
frozen: balance.frozen.toString()
|
8327
|
+
})).filter(b => b.onChainId !== undefined);
|
8328
|
+
});
|
8329
|
+
const balancesByKey = lodash.keyBy(fetchedBalances, b => `${b.address}:${b.onChainId}`);
|
8330
|
+
const success = addressesByToken.reduce((acc, [token, addresses]) => {
|
8331
|
+
if (token.type === MODULE_TYPE$3) for (const address of addresses) {
|
8332
|
+
const rawBalance = balancesByKey[`${address}:${token.onChainId}`];
|
8333
|
+
|
8334
|
+
// the endpoint only returns entries for which the address has a non-zero balance
|
8335
|
+
// => generate an zero balance object if not found
|
8336
|
+
const balance = {
|
8337
|
+
address,
|
8338
|
+
networkId,
|
8339
|
+
tokenId: token.id,
|
8340
|
+
source: MODULE_TYPE$3,
|
8341
|
+
status: "cache",
|
8342
|
+
values: [{
|
8343
|
+
type: "free",
|
8344
|
+
label: "free",
|
8345
|
+
amount: rawBalance?.free.toString() ?? "0"
|
8346
|
+
}, {
|
8347
|
+
type: "reserved",
|
8348
|
+
label: "reserved",
|
8349
|
+
amount: rawBalance?.reserved.toString() ?? "0"
|
8350
|
+
}, {
|
8351
|
+
type: "locked",
|
8352
|
+
label: "frozen",
|
8353
|
+
amount: rawBalance?.frozen.toString() ?? "0"
|
8354
|
+
}]
|
8355
|
+
};
|
8356
|
+
acc.push(balance);
|
8357
|
+
}
|
8358
|
+
return acc;
|
8359
|
+
}, []);
|
8360
|
+
return {
|
8361
|
+
success,
|
8362
|
+
errors: []
|
8363
|
+
};
|
8364
|
+
} catch (err) {
|
8365
|
+
log.warn("Failed to fetch balances for substrate-hydration", err);
|
8366
|
+
const errors = balanceDefs.map(def => ({
|
8367
|
+
tokenId: def.token.id,
|
8368
|
+
address: def.address,
|
8369
|
+
error: new Error(`Failed to fetch balance for ${def.address} on ${networkId}`)
|
8370
|
+
}));
|
8371
|
+
return {
|
8372
|
+
success: [],
|
8373
|
+
errors
|
8374
|
+
};
|
8375
|
+
}
|
8376
|
+
};
|
8377
|
+
|
8378
|
+
const fetchTokens$3 = async ({
|
8379
|
+
networkId,
|
8380
|
+
tokens,
|
8381
|
+
connector,
|
8382
|
+
miniMetadata
|
8383
|
+
}) => {
|
8384
|
+
const anyMiniMetadata = miniMetadata;
|
8385
|
+
if (!anyMiniMetadata?.data) return [];
|
8386
|
+
const {
|
8387
|
+
builder
|
8388
|
+
} = scale.parseMetadataRpc(anyMiniMetadata.data);
|
8389
|
+
const assetsCodec = builder.buildStorage("AssetRegistry", "Assets");
|
8390
|
+
const allAssetStorageKeys = await connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("AssetRegistry", "Assets")]);
|
8391
|
+
const assetStorageResults = await connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]);
|
8392
|
+
const assetStorageEntries = assetStorageResults[0].changes;
|
8393
|
+
const configTokenByAssetId = lodash.keyBy(tokens, t => t.onChainId);
|
8394
|
+
return assetStorageEntries.map(([key, value]) => {
|
8395
|
+
// parse results
|
8396
|
+
const [onChainId] = assetsCodec.keys.dec(key);
|
8397
|
+
const asset = assetsCodec.value.dec(value);
|
8398
|
+
return {
|
8399
|
+
onChainId,
|
8400
|
+
assetType: asset.asset_type.type,
|
8401
|
+
isSufficient: asset.is_sufficient,
|
8402
|
+
name: asset.name?.asText(),
|
8403
|
+
symbol: asset.symbol?.asText(),
|
8404
|
+
decimals: asset.decimals,
|
8405
|
+
existentialDeposit: asset.existential_deposit.toString()
|
8406
|
+
};
|
8407
|
+
})
|
8408
|
+
// exclude unsupported asset types
|
8409
|
+
.filter(({
|
8410
|
+
assetType
|
8411
|
+
}) => ["Erc20", "Token"].includes(assetType))
|
8412
|
+
// convert asset to a SubHydrationToken
|
8413
|
+
.map(asset => ({
|
8414
|
+
id: chaindataProvider.subHydrationTokenId(networkId, asset.onChainId),
|
8415
|
+
type: MODULE_TYPE$3,
|
8416
|
+
platform: "polkadot",
|
8417
|
+
networkId,
|
8418
|
+
onChainId: asset.onChainId,
|
8419
|
+
assetType: asset.assetType,
|
8420
|
+
// Erc20 or Token,
|
8421
|
+
isSufficient: asset.isSufficient,
|
8422
|
+
name: asset.name,
|
8423
|
+
symbol: asset.symbol,
|
8424
|
+
decimals: asset.decimals ?? 0,
|
8425
|
+
existentialDeposit: asset.existentialDeposit,
|
8426
|
+
isDefault: true
|
8427
|
+
}))
|
8428
|
+
// keep all tokens listed in the config + all tokens marked as sufficient
|
8429
|
+
.filter(token => {
|
8430
|
+
const configToken = configTokenByAssetId[token.onChainId];
|
8431
|
+
return configToken || token.isSufficient;
|
8432
|
+
})
|
8433
|
+
// apply config overrides
|
8434
|
+
.map(token => {
|
8435
|
+
const configToken = configTokenByAssetId[token.onChainId];
|
8436
|
+
return configToken ? lodash.assign({}, token, configToken) : token;
|
8437
|
+
})
|
8438
|
+
// validate results
|
8439
|
+
.filter(t => {
|
8440
|
+
const parsed = chaindataProvider.SubHydrationTokenSchema.safeParse(t);
|
8441
|
+
if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$3}`, t);
|
8442
|
+
return parsed.success;
|
8443
|
+
});
|
8444
|
+
};
|
8445
|
+
|
8446
|
+
const getMiniMetadata$3 = ({
|
8447
|
+
networkId,
|
8448
|
+
specVersion,
|
8449
|
+
metadataRpc
|
8450
|
+
}) => {
|
8451
|
+
const source = MODULE_TYPE$3;
|
8452
|
+
const chainId = networkId;
|
8453
|
+
const systemVersion = getConstantValue(metadataRpc, "System", "Version");
|
8454
|
+
if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
|
8455
|
+
networkId,
|
8456
|
+
specVersion,
|
8457
|
+
systemVersion
|
8458
|
+
});
|
8459
|
+
const id = deriveMiniMetadataId({
|
8460
|
+
source,
|
8461
|
+
chainId,
|
8462
|
+
specVersion
|
8463
|
+
});
|
8464
|
+
const {
|
8465
|
+
unifiedMetadata
|
8466
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8467
|
+
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
8468
|
+
return {
|
8469
|
+
id,
|
8470
|
+
source,
|
8471
|
+
chainId,
|
8472
|
+
specVersion,
|
8473
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
8474
|
+
data: getData$1(metadataRpc),
|
8475
|
+
extra: null
|
8476
|
+
};
|
8477
|
+
};
|
8478
|
+
const getData$1 = metadataRpc => {
|
8479
|
+
const {
|
8480
|
+
metadata,
|
8481
|
+
unifiedMetadata
|
8482
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8483
|
+
|
8484
|
+
// ensure the network has all the required bits
|
8485
|
+
if (!hasStorageItem(unifiedMetadata, "AssetRegistry", "Assets") || !hasStorageItem(unifiedMetadata, "Tokens", "Accounts") || !hasRuntimeApi(unifiedMetadata, "CurrenciesApi", "accounts")) return null;
|
8486
|
+
scale.compactMetadata(metadata, [{
|
8487
|
+
pallet: "AssetRegistry",
|
8488
|
+
items: ["Assets"]
|
8489
|
+
},
|
8490
|
+
// token specs
|
8491
|
+
{
|
8492
|
+
pallet: "Tokens",
|
8493
|
+
items: ["Accounts"]
|
8494
|
+
} // balances for tokens
|
8495
|
+
], [{
|
8496
|
+
runtimeApi: "CurrenciesApi",
|
8497
|
+
methods: ["accounts"]
|
8498
|
+
}]);
|
8499
|
+
return scale.encodeMetadata(metadata);
|
8500
|
+
};
|
8501
|
+
|
8502
|
+
const getTransferCallData$3 = ({
|
8503
|
+
from,
|
8504
|
+
to,
|
8505
|
+
value,
|
8506
|
+
token,
|
8507
|
+
metadataRpc
|
8508
|
+
}) => {
|
8509
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$3)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$3}.`);
|
8510
|
+
|
8511
|
+
// there is only one transfer method, no existential deposit handling.
|
8512
|
+
// => leave this to the frontend and dry runs
|
8513
|
+
const {
|
8514
|
+
builder
|
8515
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
8516
|
+
const {
|
8517
|
+
codec,
|
8518
|
+
location
|
8519
|
+
} = builder.buildCall("Currencies", "transfer");
|
8520
|
+
const args = {
|
8521
|
+
dest: to,
|
8522
|
+
currency_id: token.onChainId,
|
8523
|
+
amount: BigInt(value)
|
8524
|
+
};
|
8525
|
+
const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), codec.enc(args)]));
|
8526
|
+
return {
|
8527
|
+
address: from,
|
8528
|
+
method: callData.asHex()
|
8529
|
+
};
|
8530
|
+
};
|
8531
|
+
|
8532
|
+
const SUBSCRIPTION_INTERVAL$3 = 6_000;
|
8533
|
+
const subscribeBalances$3 = ({
|
8534
|
+
networkId,
|
8535
|
+
addressesByToken,
|
8536
|
+
connector,
|
8537
|
+
miniMetadata
|
8538
|
+
}) => {
|
8539
|
+
return new rxjs.Observable(subscriber => {
|
8540
|
+
const abortController = new AbortController();
|
8541
|
+
|
8542
|
+
// on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
|
8543
|
+
// => poll values for each block
|
8544
|
+
const poll = async () => {
|
8545
|
+
try {
|
8546
|
+
if (abortController.signal.aborted) return;
|
8547
|
+
const balances = await fetchBalances$3({
|
8548
|
+
networkId,
|
8549
|
+
addressesByToken,
|
8550
|
+
connector,
|
8551
|
+
miniMetadata
|
8552
|
+
});
|
8553
|
+
if (abortController.signal.aborted) return;
|
8554
|
+
subscriber.next(balances);
|
8555
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$3);
|
8556
|
+
} catch (error) {
|
8557
|
+
log.error("Error", {
|
8558
|
+
module: MODULE_TYPE$3,
|
8559
|
+
networkId,
|
8560
|
+
miniMetadata,
|
8561
|
+
addressesByToken,
|
8562
|
+
error
|
8563
|
+
});
|
8564
|
+
subscriber.error(error);
|
8565
|
+
}
|
8566
|
+
};
|
8567
|
+
poll();
|
8568
|
+
return () => {
|
8569
|
+
abortController.abort();
|
8570
|
+
};
|
8571
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
8572
|
+
};
|
8573
|
+
|
8574
|
+
const SubHydrationBalanceModule = {
|
8575
|
+
type: MODULE_TYPE$3,
|
8576
|
+
platform: PLATFORM$3,
|
8577
|
+
getMiniMetadata: getMiniMetadata$3,
|
8578
|
+
fetchTokens: fetchTokens$3,
|
8579
|
+
fetchBalances: fetchBalances$3,
|
8580
|
+
subscribeBalances: subscribeBalances$3,
|
8581
|
+
getTransferCallData: getTransferCallData$3
|
8582
|
+
};
|
8583
|
+
|
8584
|
+
const MODULE_TYPE$2 = chaindataProvider.SubNativeTokenSchema.shape.type.value;
|
8585
|
+
const PLATFORM$2 = chaindataProvider.SubNativeTokenSchema.shape.platform.value;
|
8586
|
+
|
8587
|
+
// to be used by chaindata too
|
8588
|
+
z__default.default.strictObject({
|
8589
|
+
...TokenConfigBaseSchema.shape
|
8590
|
+
});
|
8591
|
+
|
8592
|
+
// Do not use this type outside of this module
|
8593
|
+
|
8594
|
+
// Do not use this type outside of this module
|
8595
|
+
|
8596
|
+
// Do not use this type outside of this module
|
8597
|
+
|
8598
|
+
/**
|
8599
|
+
* Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
|
8600
|
+
*/
|
8601
|
+
|
8602
|
+
const fetchQueriesPack = async (connector, networkId, queries) => {
|
8603
|
+
const allStateKeys = queries.flatMap(({
|
8604
|
+
stateKeys
|
8605
|
+
}) => stateKeys).filter(util.isNotNil);
|
8606
|
+
|
8607
|
+
// doing a query with only null keys would throw an error => return early
|
8608
|
+
if (!allStateKeys.length) return queries.map(({
|
8609
|
+
stateKeys,
|
8610
|
+
decodeResult
|
8611
|
+
}) => decodeResult(stateKeys.map(() => null)));
|
8612
|
+
const response = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
|
8613
|
+
const results = queries.reduce((acc, {
|
8614
|
+
stateKeys,
|
8615
|
+
decodeResult
|
8616
|
+
}) => {
|
8617
|
+
const changes = stateKeys.map(stateKey => {
|
8618
|
+
if (!stateKey) return null;
|
8619
|
+
const change = response[0].changes.find(([key]) => key === stateKey);
|
8620
|
+
if (!change) return null;
|
8621
|
+
return change[1];
|
8622
|
+
});
|
8623
|
+
acc.push(decodeResult(changes));
|
8624
|
+
return acc;
|
8625
|
+
}, []);
|
8626
|
+
return results;
|
8627
|
+
};
|
8628
|
+
|
8629
|
+
/**
|
8630
|
+
* Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
|
8631
|
+
*/
|
8632
|
+
// export class RpcStateQueriesHelper<T> {
|
8633
|
+
// #connector: ChainConnector
|
8634
|
+
// #queries: Array<RpcStateQueries<T>>
|
8635
|
+
|
8636
|
+
// constructor(connector: ChainConnector, queries: Array<RpcStateQueries<T>>) {
|
8637
|
+
// this.#connector = connector
|
8638
|
+
// this.#queries = queries
|
8639
|
+
// }
|
8640
|
+
|
8641
|
+
// async subscribe(
|
8642
|
+
// networkId: DotNetworkId,
|
8643
|
+
// callback: SubscriptionCallback<T[]>,
|
8644
|
+
// timeout: number | false = false,
|
8645
|
+
// subscribeMethod = "state_subscribeStorage",
|
8646
|
+
// responseMethod = "state_storage",
|
8647
|
+
// unsubscribeMethod = "state_unsubscribeStorage",
|
8648
|
+
// ): Promise<UnsubscribeFn> {
|
8649
|
+
// const params = [this.#queries.flatMap(({ stateKeys }) => stateKeys)]
|
8650
|
+
|
8651
|
+
// const unsub = this.#connector.subscribe(
|
8652
|
+
// networkId,
|
8653
|
+
// subscribeMethod,
|
8654
|
+
// responseMethod,
|
8655
|
+
// params,
|
8656
|
+
// (error, result) => {
|
8657
|
+
// error
|
8658
|
+
// ? callback(error)
|
8659
|
+
// : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result))
|
8660
|
+
// },
|
8661
|
+
// timeout,
|
8662
|
+
// )
|
8663
|
+
|
8664
|
+
// const subscriptions = queries.map(([chainId, queries]) => {
|
8665
|
+
// const params = [queries.map(({ stateKey }) => stateKey)]
|
8666
|
+
|
8667
|
+
// const unsub = this.#connector.subscribe(
|
8668
|
+
// networkId,
|
8669
|
+
// subscribeMethod,
|
8670
|
+
// responseMethod,
|
8671
|
+
// params,
|
8672
|
+
// (error, result) => {
|
8673
|
+
// error
|
8674
|
+
// ? callback(error)
|
8675
|
+
// : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result))
|
8676
|
+
// },
|
8677
|
+
// timeout,
|
8678
|
+
// )
|
8679
|
+
|
8680
|
+
// return () => unsub.then((unsubscribe) => unsubscribe(unsubscribeMethod))
|
8681
|
+
// })
|
8682
|
+
|
8683
|
+
// return () => subscriptions.forEach((unsubscribe) => unsubscribe())
|
8684
|
+
// }
|
8685
|
+
|
8686
|
+
// async fetch(method = "state_queryStorageAt"): Promise<T[]> {
|
8687
|
+
// const queriesByChain = groupBy(this.#queries, "chainId")
|
8688
|
+
|
8689
|
+
// const resultsByChain = await Promise.all(
|
8690
|
+
// Object.entries(queriesByChain).map(async ([chainId, queries]) => {
|
8691
|
+
// const params = [queries.map(({ stateKey }) => stateKey)]
|
8692
|
+
|
8693
|
+
// const result = (await this.#connector.send(chainId, method, params))[0]
|
8694
|
+
// return this.#distributeChangesToQueryDecoders.call(this, chainId, result)
|
8695
|
+
// }),
|
8696
|
+
// )
|
8697
|
+
|
8698
|
+
// return resultsByChain.flatMap((result) => result)
|
8699
|
+
// }
|
8700
|
+
|
8701
|
+
// #distributeChangesToQueryDecoders(chainId: DotNetworkId, result: unknown): T[] {
|
8702
|
+
// if (typeof result !== "object" || result === null) return []
|
8703
|
+
// if (!hasOwnProperty(result, "changes") || typeof result.changes !== "object") return []
|
8704
|
+
// if (!Array.isArray(result.changes)) return []
|
8705
|
+
|
8706
|
+
// return result.changes.flatMap(([reference, change]: [unknown, unknown]): [T] | [] => {
|
8707
|
+
// if (typeof reference !== "string") {
|
8708
|
+
// log.warn(`Received non-string reference in RPC result: ${reference}`)
|
8709
|
+
// return []
|
8710
|
+
// }
|
8711
|
+
|
8712
|
+
// if (typeof change !== "string" && change !== null) {
|
8713
|
+
// log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`)
|
8714
|
+
// return []
|
8715
|
+
// }
|
8716
|
+
|
8717
|
+
// const query = this.#queries.find(
|
8718
|
+
// ({ chainId: cId, stateKey }) => cId === chainId && stateKey === reference,
|
8719
|
+
// )
|
8720
|
+
// if (!query) {
|
8721
|
+
// log.warn(
|
8722
|
+
// `Failed to find query:\n${reference} in\n${this.#queries.map(({ stateKey }) => stateKey)}`,
|
8723
|
+
// )
|
8724
|
+
// return []
|
8725
|
+
// }
|
8726
|
+
|
8727
|
+
// return [query.decodeResult(change)]
|
8728
|
+
// })
|
8729
|
+
// }
|
8730
|
+
// }
|
8731
|
+
|
8732
|
+
const SUBTENSOR_ROOT_NETUID = 0;
|
8733
|
+
const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = 1000000n;
|
8734
|
+
const TAO_DECIMALS = 9n;
|
8735
|
+
const SCALE_FACTOR = 10n ** TAO_DECIMALS; // Equivalent to 10e9 for precision
|
8736
|
+
const ONE_ALPHA_TOKEN = SCALE_FACTOR;
|
8737
|
+
const calculateAlphaPrice = ({
|
8738
|
+
dynamicInfo
|
8739
|
+
}) => {
|
8740
|
+
if (!dynamicInfo) return 0n;
|
8741
|
+
const {
|
8742
|
+
alpha_in,
|
8743
|
+
tao_in
|
8744
|
+
} = dynamicInfo;
|
8745
|
+
|
8746
|
+
// Scale taoIn before division to preserve precision
|
8747
|
+
const result = tao_in * SCALE_FACTOR / alpha_in;
|
8748
|
+
return result; // Scaled price as bigint
|
8749
|
+
};
|
8750
|
+
const calculateTaoAmountFromAlpha = ({
|
8751
|
+
alphaPrice,
|
8752
|
+
alphaStaked
|
8753
|
+
}) => {
|
8754
|
+
if (!alphaStaked || !alphaPrice) return 0n;
|
8755
|
+
const expectedAlpha = alphaStaked * alphaPrice;
|
8756
|
+
return expectedAlpha / SCALE_FACTOR;
|
8757
|
+
};
|
8758
|
+
const calculateTaoFromDynamicInfo = ({
|
8759
|
+
dynamicInfo,
|
8760
|
+
alphaStaked
|
8761
|
+
}) => {
|
8762
|
+
const alphaPrice = calculateAlphaPrice({
|
8763
|
+
dynamicInfo
|
8764
|
+
});
|
8765
|
+
return calculateTaoAmountFromAlpha({
|
8766
|
+
alphaPrice,
|
8767
|
+
alphaStaked
|
8768
|
+
});
|
8769
|
+
};
|
8770
|
+
|
8771
|
+
// per address, lists of values to add to the native balance
|
8772
|
+
|
8773
|
+
const getSubtensorStakingBalances$ = (connector, networkId, balanceDefs, miniMetadata) => {
|
8774
|
+
const addresses = balanceDefs.map(def => def.address);
|
8775
|
+
const token = balanceDefs[0].token;
|
8776
|
+
if (!addresses.length || !token || !miniMetadata.extra.hasSubtensorPallet || !miniMetadata.data) return rxjs.of({});
|
8777
|
+
|
8778
|
+
// we are only doing runtime calls, there is no way to subscribe to changes, except polling
|
8779
|
+
// => start immediately, then repeat every 30 seconds
|
8780
|
+
return rxjs.timer(0, 30000).pipe(rxjs.switchMap(() => rxjs.from(fetchStakeInfoByAddress(connector, networkId, miniMetadata, addresses)).pipe(rxjs.switchMap(stakeInfoByAddress => fetchStakingBalanceValuesByAddress(connector, networkId, miniMetadata, stakeInfoByAddress)))));
|
8781
|
+
};
|
8782
|
+
const fetchStakingBalanceValuesByAddress = async (connector, networkId, miniMetadata, stakeInfoByAddress) => {
|
8783
|
+
const uniqueNetuids = lodash.uniq(lodash.values(stakeInfoByAddress).flatMap(infos => infos.map(info => info.netuid))).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID);
|
8784
|
+
const dynamicInfoByNetuid = await fetchDynamicInfoByNetuid(connector, networkId, miniMetadata, uniqueNetuids);
|
8785
|
+
return lodash.fromPairs(lodash.toPairs(stakeInfoByAddress).map(([address, stakeInfos]) => {
|
8786
|
+
const stakesBalances = stakeInfos.filter(({
|
8787
|
+
stake
|
8788
|
+
}) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK).map(({
|
8789
|
+
hotkey,
|
8790
|
+
netuid,
|
8791
|
+
stake
|
8792
|
+
}) => ({
|
8793
|
+
hotkey,
|
8794
|
+
netuid: Number(netuid),
|
8795
|
+
stake: BigInt(stake),
|
8796
|
+
dynamicInfo: dynamicInfoByNetuid[Number(netuid)]
|
8797
|
+
})).map(({
|
8798
|
+
hotkey,
|
8799
|
+
stake,
|
8800
|
+
netuid,
|
8801
|
+
dynamicInfo
|
8802
|
+
}) => {
|
8803
|
+
const {
|
8804
|
+
token_symbol,
|
8805
|
+
subnet_name,
|
8806
|
+
subnet_identity
|
8807
|
+
} = dynamicInfo ?? {};
|
8808
|
+
const tokenSymbol = new TextDecoder().decode(Uint8Array.from(token_symbol ?? []));
|
8809
|
+
const subnetName = new TextDecoder().decode(Uint8Array.from(subnet_name ?? []));
|
8810
|
+
const subnetIdentity = subnet_identity ? lodash.fromPairs(lodash.toPairs(subnet_identity).map(([key, binary]) => [key, binary.asText()])) : undefined;
|
8811
|
+
|
8812
|
+
// Add 1n balance if failed to fetch dynamic info, so the position is not ignored by Balance lib and is displayed in the UI.
|
8813
|
+
const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo({
|
8814
|
+
dynamicInfo,
|
8815
|
+
alphaStaked: stake
|
8816
|
+
}) : 1n;
|
8817
|
+
const alphaToTaoRate = calculateTaoFromDynamicInfo({
|
8818
|
+
dynamicInfo: dynamicInfo ?? null,
|
8819
|
+
alphaStaked: ONE_ALPHA_TOKEN
|
8820
|
+
}).toString();
|
8821
|
+
const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID ? stake : alphaStakedInTao;
|
8822
|
+
const balanceValue = {
|
8823
|
+
source: "subtensor-staking",
|
8824
|
+
type: "subtensor",
|
8825
|
+
label: "subtensor-staking",
|
8826
|
+
amount: stakeByNetuid.toString(),
|
8827
|
+
meta: {
|
8828
|
+
type: "subtensor-staking",
|
8829
|
+
hotkey,
|
8830
|
+
netuid,
|
8831
|
+
amountStaked: stake.toString(),
|
8832
|
+
alphaToTaoRate,
|
8833
|
+
dynamicInfo: {
|
8834
|
+
tokenSymbol,
|
8835
|
+
subnetName,
|
8836
|
+
subnetIdentity: {
|
8837
|
+
...subnetIdentity,
|
8838
|
+
subnetName: subnetIdentity?.subnet_name || subnetName
|
8839
|
+
}
|
8840
|
+
}
|
8841
|
+
}
|
8842
|
+
};
|
8843
|
+
return balanceValue;
|
8844
|
+
});
|
8845
|
+
return [address, stakesBalances];
|
8846
|
+
}));
|
8847
|
+
};
|
8848
|
+
const fetchStakeInfoByAddress = async (connector, networkId, miniMetadata, addresses) => {
|
8849
|
+
const pairs = await Promise.all(addresses.map(async address => [address, await viem.withRetry(() => fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "StakeInfoRuntimeApi", "get_stake_info_for_coldkey", [address]), {
|
8850
|
+
delay: 500,
|
8851
|
+
retryCount: 3
|
8852
|
+
})]));
|
8853
|
+
return lodash.fromPairs(pairs);
|
8854
|
+
};
|
8855
|
+
|
8856
|
+
// assume dynamic info doesnt change over the course of a browser session
|
8857
|
+
const dynamicInfoCache = new Map();
|
8858
|
+
const getCacheKey = (networkId, netuid) => `${networkId}:${netuid}`;
|
8859
|
+
const fetchDynamicInfoByNetuid = async (connector, networkId, miniMetadata, uniqueNetuids) => {
|
8860
|
+
const fetchInfo = async netuid => {
|
8861
|
+
if (netuid === SUBTENSOR_ROOT_NETUID) return null;
|
8862
|
+
const cacheKey = getCacheKey(networkId, netuid);
|
8863
|
+
if (!dynamicInfoCache.has(cacheKey)) {
|
8864
|
+
await viem.withRetry(async () => {
|
8865
|
+
const result = await fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "SubnetInfoRuntimeApi", "get_dynamic_info", [netuid]);
|
8866
|
+
dynamicInfoCache.set(cacheKey, result); // Cache successful response
|
8867
|
+
|
8868
|
+
return result;
|
8869
|
+
}, {
|
8870
|
+
delay: 500,
|
8871
|
+
retryCount: 3
|
8872
|
+
});
|
8873
|
+
}
|
8874
|
+
return dynamicInfoCache.get(cacheKey) ?? null;
|
8875
|
+
};
|
8876
|
+
const results = await Promise.all(uniqueNetuids.map(async netuid => [netuid, await fetchInfo(netuid)]));
|
8877
|
+
return lodash.fromPairs(results);
|
8878
|
+
};
|
8879
|
+
|
8880
|
+
const getOtherType = input => `other-${input}`;
|
8881
|
+
|
8882
|
+
/**
|
8883
|
+
* For converting the value of `lock?.id?.toUtf8?.()` which is retrieved from
|
8884
|
+
* the Balances.Locks storage key into a useful classification for our UI
|
8885
|
+
*/
|
8886
|
+
const getLockedType = input => {
|
8887
|
+
if (typeof input !== "string") return getOtherType("unknown");
|
8888
|
+
if (input.includes("vesting")) return "vesting";
|
8889
|
+
if (input.includes("calamvst")) return "vesting"; // vesting on manta network
|
8890
|
+
if (input.includes("ormlvest")) return "vesting"; // vesting ORML tokens
|
8891
|
+
if (input.includes("pyconvot")) return "democracy";
|
8892
|
+
if (input.includes("democrac")) return "democracy";
|
8893
|
+
if (input.includes("democracy")) return "democracy";
|
8894
|
+
if (input.includes("phrelect")) return "democracy"; // specific to council
|
8895
|
+
if (input.includes("staking")) return "staking";
|
8896
|
+
if (input.includes("stkngdel")) return "staking"; // staking delegator
|
8897
|
+
if (input.includes("stkngcol")) return "staking"; // staking collator
|
8898
|
+
if (input.includes("kiltpstk")) return "staking"; // Kilt specific staking
|
8899
|
+
if (input.includes("dapstake")) return "dapp-staking"; // Astar specific
|
8900
|
+
if (input.includes("appstake")) return "dapp-staking"; // Quartz (unique) specific
|
8901
|
+
if (input.includes("dappstaking")) return "dapp-staking";
|
8902
|
+
|
8903
|
+
// Joystream specifics https://github.com/Joystream/pioneer/blob/dev/packages/ui/src/accounts/model/lockTypes.ts
|
8904
|
+
if (input.includes("voting")) return "democracy";
|
8905
|
+
if (input.includes("candidac")) return "democracy"; // Council Candidate
|
8906
|
+
if (input.includes("councilo")) return "democracy"; // Councilor
|
8907
|
+
if (input.includes("proposal")) return "democracy";
|
8908
|
+
if (input.includes("boundsta")) return "staking"; // Bound Staking Account
|
8909
|
+
if (input.includes("invitemb")) return getOtherType(input); // Invite member
|
8910
|
+
if (input.includes("bounty")) return getOtherType(input);
|
8911
|
+
if (input.startsWith("wg-")) return getOtherType(input);
|
8912
|
+
|
8913
|
+
// ignore technical or undocumented lock types
|
8914
|
+
if (input.includes("pdexlock")) return getOtherType(input);
|
8915
|
+
if (input.includes("phala/sp")) return getOtherType(input);
|
8916
|
+
if (input.includes("aca/earn")) return getOtherType(input);
|
8917
|
+
if (input.includes("stk_stks")) return getOtherType(input);
|
8918
|
+
|
8919
|
+
// eslint-disable-next-line no-console
|
8920
|
+
console.warn(`unknown locked type: ${input}`);
|
8921
|
+
return getOtherType(input);
|
8922
|
+
};
|
8923
|
+
|
8924
|
+
const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
|
8925
|
+
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
8926
|
+
account: ["System", "Account"],
|
8927
|
+
stakingLedger: ["Staking", "Ledger"],
|
8928
|
+
reserves: ["Balances", "Reserves"],
|
8929
|
+
// unused ??
|
8930
|
+
holds: ["Balances", "Holds"],
|
8931
|
+
locks: ["Balances", "Locks"],
|
8932
|
+
freezes: ["Balances", "Freezes"],
|
8933
|
+
poolMembers: ["NominationPools", "PoolMembers"]
|
8934
|
+
});
|
8935
|
+
if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
|
8936
|
+
return balanceDefs.map(({
|
8937
|
+
token,
|
8938
|
+
address
|
8939
|
+
}) => {
|
8940
|
+
const accountStateKey = networkStorageCoders.account ? networkStorageCoders.account.keys.enc(address) : null;
|
8941
|
+
const locksStateKey = networkStorageCoders.locks ? networkStorageCoders.locks.keys.enc(address) : null;
|
8942
|
+
const freezesStateKey = networkStorageCoders.freezes ? networkStorageCoders.freezes.keys.enc(address) : null;
|
8943
|
+
const holdsStateKey = networkStorageCoders.holds ? networkStorageCoders.holds.keys.enc(address) : null;
|
8944
|
+
const stakingLedgerStateKey = networkStorageCoders.stakingLedger ? networkStorageCoders.stakingLedger.keys.enc(address) : null;
|
8945
|
+
const poolMemberStateKey = networkStorageCoders.poolMembers ? networkStorageCoders.poolMembers.keys.enc(address) : null;
|
8946
|
+
const stateKeys = [accountStateKey, locksStateKey, freezesStateKey, holdsStateKey, stakingLedgerStateKey, poolMemberStateKey];
|
8947
|
+
return {
|
8948
|
+
stateKeys,
|
8949
|
+
decodeResult: changes => {
|
8950
|
+
const balance = {
|
8951
|
+
source: "substrate-native",
|
8952
|
+
status: "live",
|
8953
|
+
address,
|
8954
|
+
networkId,
|
8955
|
+
tokenId: token.id,
|
8956
|
+
values: [],
|
8957
|
+
useLegacyTransferableCalculation: miniMetadata.extra.useLegacyTransferableCalculation
|
8958
|
+
};
|
8959
|
+
let nomPoolMemberInfo = null;
|
8960
|
+
const [accountChange, lockChange, freezesChange, holdsChange, stakingLedgerChange, nomPoolMemberChange] = changes;
|
8961
|
+
if (networkStorageCoders.account) {
|
8962
|
+
// for account balance we decode even empty values
|
8963
|
+
const baseValues = decodeBaseResult(networkStorageCoders.account, accountChange, networkId);
|
8964
|
+
balance.values.push(...baseValues);
|
8965
|
+
}
|
8966
|
+
if (networkStorageCoders.locks && lockChange) {
|
8967
|
+
const lockValues = decodeLocksResult(networkStorageCoders.locks, lockChange, networkId);
|
8968
|
+
balance.values.push(...lockValues);
|
8969
|
+
}
|
8970
|
+
if (networkStorageCoders.freezes && freezesChange) {
|
8971
|
+
const freezesValues = decodeFreezesResult(networkStorageCoders.freezes, freezesChange, networkId);
|
8972
|
+
balance.values.push(...freezesValues);
|
8973
|
+
}
|
8974
|
+
if (networkStorageCoders.holds && holdsChange) {
|
8975
|
+
const holdsValues = decodeHoldsResult(networkStorageCoders.holds, holdsChange, networkId);
|
8976
|
+
balance.values.push(...holdsValues);
|
8977
|
+
}
|
8978
|
+
if (networkStorageCoders.stakingLedger && stakingLedgerChange) {
|
8979
|
+
const stakingLedgerValues = decodeStakingLedgerResult(networkStorageCoders.stakingLedger, stakingLedgerChange, networkId);
|
8980
|
+
balance.values.push(...stakingLedgerValues);
|
8981
|
+
}
|
8982
|
+
if (networkStorageCoders.poolMembers && nomPoolMemberChange) {
|
8983
|
+
const nomPoolMemberValue = decodePoolMemberResult(networkStorageCoders.poolMembers, nomPoolMemberChange, networkId);
|
8984
|
+
if (nomPoolMemberValue) nomPoolMemberInfo = nomPoolMemberValue;
|
8985
|
+
}
|
8986
|
+
return {
|
8987
|
+
balance,
|
8988
|
+
nomPoolMemberInfo
|
8989
|
+
};
|
8990
|
+
}
|
8991
|
+
};
|
8992
|
+
}).filter(util.isNotNil);
|
8993
|
+
};
|
8994
|
+
|
8995
|
+
// AccountInfo is the state_storage data format for nativeToken balances
|
8996
|
+
// Theory: new chains will be at least on metadata v14, and so we won't need to hardcode their AccountInfo type.
|
8997
|
+
// But for chains we want to support which aren't on metadata v14, hardcode them here:
|
8998
|
+
// If the chain upgrades to metadata v14, this override will be ignored :)
|
8999
|
+
// const RegularAccountInfoFallback = Struct({
|
9000
|
+
// nonce: u32,
|
9001
|
+
// consumers: u32,
|
9002
|
+
// providers: u32,
|
9003
|
+
// sufficients: u32,
|
9004
|
+
// data: Struct({ free: u128, reserved: u128, miscFrozen: u128, feeFrozen: u128 }),
|
9005
|
+
// })
|
9006
|
+
// const NoSufficientsAccountInfoFallback = Struct({
|
9007
|
+
// nonce: u32,
|
9008
|
+
// consumers: u32,
|
9009
|
+
// providers: u32,
|
9010
|
+
// data: Struct({ free: u128, reserved: u128, miscFrozen: u128, feeFrozen: u128 }),
|
9011
|
+
// })
|
9012
|
+
// const AccountInfoOverrides: Record<
|
9013
|
+
// string,
|
9014
|
+
// typeof RegularAccountInfoFallback | typeof NoSufficientsAccountInfoFallback | undefined
|
9015
|
+
// > = {
|
9016
|
+
// // crown-sterlin is not yet on metadata v14
|
9017
|
+
// "crown-sterling": NoSufficientsAccountInfoFallback,
|
9018
|
+
|
9019
|
+
// // crust is not yet on metadata v14
|
9020
|
+
// "crust": NoSufficientsAccountInfoFallback,
|
9021
|
+
|
9022
|
+
// // kulupu is not yet on metadata v14
|
9023
|
+
// "kulupu": RegularAccountInfoFallback,
|
9024
|
+
|
9025
|
+
// // nftmart is not yet on metadata v14
|
9026
|
+
// "nftmart": RegularAccountInfoFallback,
|
9027
|
+
// }
|
9028
|
+
|
9029
|
+
const decodeBaseResult = (coder, value, networkId) => {
|
9030
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9031
|
+
|
9032
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode base native balance on chain ${networkId}`);
|
9033
|
+
const free = (decoded?.data?.free ?? 0n).toString();
|
9034
|
+
const reserved = (decoded?.data?.reserved ?? 0n).toString();
|
9035
|
+
const miscLock = ((decoded?.data?.miscFrozen ?? 0n) + (
|
9036
|
+
// new chains don't split their `frozen` amount into `feeFrozen` and `miscFrozen`.
|
9037
|
+
// for these chains, we'll use the `frozen` amount as `miscFrozen`.
|
9038
|
+
decoded?.data?.frozen ?? 0n)).toString();
|
9039
|
+
const feesLock = (decoded?.data?.feeFrozen ?? 0n).toString();
|
9040
|
+
|
9041
|
+
// even if these values are 0, we still need to add them to the balanceJson.values array
|
9042
|
+
// so that the balance pool can handle newly zeroed balances
|
9043
|
+
// const existingValues = Object.fromEntries(
|
9044
|
+
// balanceJson.values.map((v) => [getValueId(v), v]),
|
9045
|
+
// )
|
9046
|
+
const newValues = [{
|
9047
|
+
type: "free",
|
9048
|
+
label: "free",
|
9049
|
+
amount: free.toString()
|
9050
|
+
}, {
|
9051
|
+
type: "reserved",
|
9052
|
+
label: "reserved",
|
9053
|
+
amount: reserved.toString()
|
9054
|
+
}, {
|
9055
|
+
type: "locked",
|
9056
|
+
label: "misc",
|
9057
|
+
amount: miscLock.toString()
|
9058
|
+
}, {
|
9059
|
+
type: "locked",
|
9060
|
+
label: "fees",
|
9061
|
+
amount: feesLock.toString()
|
9062
|
+
}];
|
9063
|
+
return newValues;
|
9064
|
+
};
|
9065
|
+
const decodeLocksResult = (coder, value, networkId) => {
|
9066
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9067
|
+
|
9068
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode lock on chain ${networkId}`);
|
9069
|
+
const locksQueryLocks = decoded?.map?.(lock => ({
|
9070
|
+
type: "locked",
|
9071
|
+
source: "substrate-native-locks",
|
9072
|
+
label: getLockedType(lock?.id?.asText?.()),
|
9073
|
+
meta: {
|
9074
|
+
id: lock?.id?.asText?.()
|
9075
|
+
},
|
9076
|
+
amount: (lock?.amount ?? 0n).toString()
|
9077
|
+
})) ?? [];
|
9078
|
+
return locksQueryLocks;
|
9079
|
+
|
9080
|
+
// // locked values should be replaced entirely, not merged or appended
|
9081
|
+
// const nonLockValues = balanceJson.values.filter(
|
9082
|
+
// (v) => v.source !== "substrate-native-locks",
|
9083
|
+
// )
|
9084
|
+
// balanceJson.values = nonLockValues.concat(locksQueryLocks)
|
9085
|
+
|
9086
|
+
// // fix any double-counting between Balances.Locks (for staking locks) and Staking.Ledger (for unbonding locks)
|
9087
|
+
// balanceJson.values = updateStakingLocksUsingUnbondingLocks(balanceJson.values)
|
9088
|
+
};
|
9089
|
+
const decodeFreezesResult = (coder, value, networkId) => {
|
9090
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9091
|
+
|
9092
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode freeze on chain ${networkId}`);
|
9093
|
+
const freezesValues = decoded?.map?.(lock => ({
|
9094
|
+
type: "locked",
|
9095
|
+
source: "substrate-native-freezes",
|
9096
|
+
label: getLockedType(lock?.id?.type?.toLowerCase?.()),
|
9097
|
+
amount: lock?.amount?.toString?.() ?? "0"
|
9098
|
+
})) ?? [];
|
9099
|
+
return freezesValues;
|
9100
|
+
|
9101
|
+
// // freezes values should be replaced entirely, not merged or appended
|
9102
|
+
// const nonFreezesValues = balanceJson.values.filter(
|
9103
|
+
// (v) => v.source !== "substrate-native-freezes",
|
9104
|
+
// )
|
9105
|
+
// balanceJson.values = nonFreezesValues.concat(freezesQueryLocks)
|
9106
|
+
|
9107
|
+
// return balanceJson
|
9108
|
+
};
|
9109
|
+
const decodeHoldsResult = (coder, value, networkId) => {
|
9110
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9111
|
+
|
9112
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode holds on chain ${networkId}`);
|
9113
|
+
|
9114
|
+
// at this time we re only interested in DelegatedStaking holds, to determine if nom pool staked amount is included in reserved or not
|
9115
|
+
const holdsValues = decoded?.filter(hold => hold.id?.type).map(hold => ({
|
9116
|
+
type: "locked",
|
9117
|
+
source: "substrate-native-holds",
|
9118
|
+
label: hold.id.type,
|
9119
|
+
// anount needs to be 0 or a row could appear in the UI, this entry is just for information
|
9120
|
+
amount: "0",
|
9121
|
+
meta: {
|
9122
|
+
amount: (hold?.amount ?? 0n).toString()
|
9123
|
+
}
|
9124
|
+
})) ?? [];
|
9125
|
+
return holdsValues;
|
9126
|
+
|
9127
|
+
// // values should be replaced entirely, not merged or appended
|
9128
|
+
// const nonHoldsValues = balanceJson.values.filter(
|
9129
|
+
// (v) => v.source !== "substrate-native-holds",
|
9130
|
+
// )
|
9131
|
+
// balanceJson.values = nonHoldsValues.concat(holdsQueryLocks)
|
9132
|
+
|
9133
|
+
// return balanceJson
|
9134
|
+
};
|
9135
|
+
const decodeStakingLedgerResult = (coder, value, networkId) => {
|
9136
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9137
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
9138
|
+
|
9139
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode unbonding query on chain ${networkId}`);
|
9140
|
+
const totalUnlocking = decoded?.unlocking?.reduce?.((acc, unlocking) => acc + unlocking.value, 0n) ?? 0n;
|
9141
|
+
const stakingLedgerResults = totalUnlocking <= 0n ? [] : [{
|
9142
|
+
type: "locked",
|
9143
|
+
source: "substrate-native-unbonding",
|
9144
|
+
label: "Unbonding",
|
9145
|
+
amount: totalUnlocking.toString()
|
9146
|
+
}];
|
9147
|
+
return stakingLedgerResults;
|
9148
|
+
|
9149
|
+
// if (totalUnlocking <= 0n) unbondingQueryLocks = []
|
9150
|
+
// else {
|
9151
|
+
// unbondingQueryLocks = [
|
9152
|
+
// {
|
9153
|
+
// type: "locked",
|
9154
|
+
// source: "substrate-native-unbonding",
|
9155
|
+
// label: "Unbonding",
|
9156
|
+
// amount: totalUnlocking.toString(),
|
9157
|
+
// },
|
9158
|
+
// ]
|
9159
|
+
// }
|
9160
|
+
|
9161
|
+
// // unbonding values should be replaced entirely, not merged or appended
|
9162
|
+
// const nonUnbondingValues = balanceJson.values.filter(
|
9163
|
+
// (v) => v.source !== "substrate-native-unbonding",
|
9164
|
+
// )
|
9165
|
+
// balanceJson.values = nonUnbondingValues.concat(unbondingQueryLocks)
|
9166
|
+
|
9167
|
+
// // fix any double-counting between Balances.Locks (for staking locks) and Staking.Ledger (for unbonding locks)
|
9168
|
+
// balanceJson.values = updateStakingLocksUsingUnbondingLocks(balanceJson.values)
|
9169
|
+
|
9170
|
+
// return balanceJson
|
9171
|
+
};
|
9172
|
+
const decodePoolMemberResult = (coder, value, networkId) => {
|
9173
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9174
|
+
|
9175
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode poolMembers on chain ${networkId}`);
|
9176
|
+
if (!decoded) return null;
|
9177
|
+
const poolId = decoded.pool_id.toString();
|
9178
|
+
const points = decoded.points.toString();
|
9179
|
+
const unbondingEras = Array.from(decoded.unbonding_eras ?? []).flatMap(entry => {
|
9180
|
+
if (entry === undefined) return [];
|
9181
|
+
const [key, value] = Array.from(entry);
|
9182
|
+
const era = key.toString();
|
9183
|
+
const amount = value.toString();
|
9184
|
+
if (typeof era !== "string" || typeof amount !== "string") return [];
|
9185
|
+
return {
|
9186
|
+
era,
|
9187
|
+
amount
|
9188
|
+
};
|
9189
|
+
});
|
9190
|
+
return {
|
9191
|
+
poolId,
|
9192
|
+
points,
|
9193
|
+
unbondingEras
|
9194
|
+
};
|
9195
|
+
};
|
9196
|
+
|
9197
|
+
// const getBaseQuery = (
|
9198
|
+
// networkId: string,
|
9199
|
+
// address: string,
|
9200
|
+
// coder: ScaleStorageCoder,
|
9201
|
+
// ): RpcStateQuery<Array<AmountWithLabel<string>>> | null => {
|
9202
|
+
// // For chains which are using metadata < v14
|
9203
|
+
// const getFallbackStateKey = () => {
|
9204
|
+
// const addressBytes = decodeAnyAddress(address) // TODO replace with modern api, this is slow
|
9205
|
+
// const addressHash = blake2Concat(addressBytes).replace(/^0x/, "")
|
9206
|
+
// const moduleHash = "26aa394eea5630e07c48ae0c9558cef7" // util_crypto.xxhashAsHex("System", 128);
|
9207
|
+
// const storageHash = "b99d880ec681799c0cf30e8886371da9" // util_crypto.xxhashAsHex("Account", 128);
|
9208
|
+
// const moduleStorageHash = `${moduleHash}${storageHash}` // System.Account is the state_storage key prefix for nativeToken balances
|
9209
|
+
// return `0x${moduleStorageHash}${addressHash}`
|
9210
|
+
// }
|
9211
|
+
|
9212
|
+
// // const scaleCoder = chainStorageCoders.get(chainId)?.base
|
9213
|
+
// // NOTE: Only use fallback key when `scaleCoder` is not defined
|
9214
|
+
// // i.e. when chain doesn't have metadata v14/v15
|
9215
|
+
// const stateKey = coder
|
9216
|
+
// ? encodeStateKey(coder, `Invalid address in ${networkId} base query ${address}`, address)
|
9217
|
+
// : getFallbackStateKey()
|
9218
|
+
// if (!stateKey) return null
|
9219
|
+
|
9220
|
+
// const decodeResult = (change: string | null) => {
|
9221
|
+
// // BEGIN: Handle chains which use metadata < v14
|
9222
|
+
// let oldChainBalance = null
|
9223
|
+
// if (!coder) {
|
9224
|
+
// const scaleAccountInfo = AccountInfoOverrides[networkId]
|
9225
|
+
// if (scaleAccountInfo === undefined) {
|
9226
|
+
// // chain metadata version is < 15 and we also don't have an override hardcoded in
|
9227
|
+
// // the best way to handle this case: log a warning and return an empty balance
|
9228
|
+
// log.debug(
|
9229
|
+
// `Native token on chain ${networkId} has no balance type for decoding. Defaulting to a balance of 0 (zero).`,
|
9230
|
+
// )
|
9231
|
+
// return []
|
9232
|
+
// }
|
9233
|
+
|
9234
|
+
// try {
|
9235
|
+
// // eslint-disable-next-line no-var
|
9236
|
+
// oldChainBalance = change === null ? null : scaleAccountInfo.dec(change)
|
9237
|
+
// } catch (error) {
|
9238
|
+
// log.warn(
|
9239
|
+
// `Failed to create pre-metadataV14 balance type for native on chain ${networkId}: ${error?.toString()}`,
|
9240
|
+
// )
|
9241
|
+
// return []
|
9242
|
+
// }
|
9243
|
+
// }
|
9244
|
+
// // END: Handle chains which use metadata < v14
|
9245
|
+
|
9246
|
+
// /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9247
|
+
// type DecodedType = {
|
9248
|
+
// data?: {
|
9249
|
+
// flags?: bigint
|
9250
|
+
// free?: bigint
|
9251
|
+
// frozen?: bigint
|
9252
|
+
// reserved?: bigint
|
9253
|
+
|
9254
|
+
// // deprecated fields (they only show up on old chains)
|
9255
|
+
// feeFrozen?: bigint
|
9256
|
+
// miscFrozen?: bigint
|
9257
|
+
// }
|
9258
|
+
// }
|
9259
|
+
// const decoded =
|
9260
|
+
// decodeScale<DecodedType>(
|
9261
|
+
// coder,
|
9262
|
+
// change,
|
9263
|
+
// `Failed to decode base native balance on chain ${networkId}`,
|
9264
|
+
// ) ?? oldChainBalance
|
9265
|
+
|
9266
|
+
// const free = (decoded?.data?.free ?? 0n).toString()
|
9267
|
+
// const reserved = (decoded?.data?.reserved ?? 0n).toString()
|
9268
|
+
// const miscLock = (
|
9269
|
+
// (decoded?.data?.miscFrozen ?? 0n) +
|
9270
|
+
// // new chains don't split their `frozen` amount into `feeFrozen` and `miscFrozen`.
|
9271
|
+
// // for these chains, we'll use the `frozen` amount as `miscFrozen`.
|
9272
|
+
// ((decoded?.data as DecodedType["data"])?.frozen ?? 0n)
|
9273
|
+
// ).toString()
|
9274
|
+
// const feesLock = (decoded?.data?.feeFrozen ?? 0n).toString()
|
9275
|
+
|
9276
|
+
// // even if these values are 0, we still need to add them to the balanceJson.values array
|
9277
|
+
// // so that the balance pool can handle newly zeroed balances
|
9278
|
+
// // const existingValues = Object.fromEntries(
|
9279
|
+
// // balanceJson.values.map((v) => [getValueId(v), v]),
|
9280
|
+
// // )
|
9281
|
+
// const newValues: AmountWithLabel<string>[] = [
|
9282
|
+
// { type: "free", label: "free", amount: free.toString() },
|
9283
|
+
// { type: "reserved", label: "reserved", amount: reserved.toString() },
|
9284
|
+
// { type: "locked", label: "misc", amount: miscLock.toString() },
|
9285
|
+
// { type: "locked", label: "fees", amount: feesLock.toString() },
|
9286
|
+
// ]
|
9287
|
+
|
9288
|
+
// return newValues
|
9289
|
+
|
9290
|
+
// // const newValuesObj = Object.fromEntries(newValues.map((v) => [getValueId(v), v]))
|
9291
|
+
|
9292
|
+
// // balanceJson.values = Object.values({ ...existingValues, ...newValuesObj })
|
9293
|
+
|
9294
|
+
// // return balanceJson
|
9295
|
+
// }
|
9296
|
+
|
9297
|
+
// return { chainId: networkId, stateKey, decodeResult }
|
9298
|
+
// }
|
9299
|
+
|
9300
|
+
/**
|
9301
|
+
* Each nominationPool in the nominationPools pallet has access to some accountIds which have no
|
9302
|
+
* associated private key. Instead, they are derived from this function.
|
9303
|
+
*/
|
9304
|
+
const nompoolAccountId = (palletId, poolId, index) => {
|
9305
|
+
const utf8Encoder = new TextEncoder();
|
9306
|
+
const encModPrefix = utf8Encoder.encode("modl");
|
9307
|
+
const encPalletId = utf8Encoder.encode(palletId);
|
9308
|
+
const encIndex = new Uint8Array([index]);
|
9309
|
+
const encPoolId = scaleTs.u32.enc(typeof poolId === "string" ? parseInt(poolId, 10) : poolId);
|
9310
|
+
const length = encModPrefix.length + encPalletId.length + encIndex.length + encPoolId.length;
|
9311
|
+
const remainingBytes = 32 - length;
|
9312
|
+
const encEmptyH256 = new Uint8Array(remainingBytes);
|
9313
|
+
const bytes = utils.mergeUint8([encModPrefix, encPalletId, encIndex, encPoolId, encEmptyH256]);
|
9314
|
+
return polkadotApi.AccountId().dec(bytes);
|
9315
|
+
};
|
9316
|
+
/** The stash account for the nomination pool */
|
9317
|
+
const nompoolStashAccountId = (palletId, poolId) => nompoolAccountId(palletId, poolId, 0);
|
9318
|
+
|
9319
|
+
const buildNomPoolQueries = (networkId, partialBalances, miniMetadata) => {
|
9320
|
+
const networkStorageCoders = getNomPoolCoders(networkId, miniMetadata);
|
9321
|
+
if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
|
9322
|
+
return partialBalances.map(({
|
9323
|
+
balance,
|
9324
|
+
nomPoolMemberInfo
|
9325
|
+
}) => {
|
9326
|
+
const stateKeys = getNomPoolStateKeys(networkStorageCoders, nomPoolMemberInfo, miniMetadata.extra);
|
9327
|
+
return {
|
9328
|
+
stateKeys,
|
9329
|
+
decodeResult: changes => {
|
9330
|
+
if (!nomPoolMemberInfo || !stateKeys.length || changes.includes(null)) return balance;
|
9331
|
+
const accountPoints = nomPoolMemberInfo?.points ?? "0";
|
9332
|
+
const {
|
9333
|
+
poolPoints = "0"
|
9334
|
+
} = decodePoolPoints(networkStorageCoders.bondedPools, changes[0], networkId);
|
9335
|
+
const {
|
9336
|
+
poolTotalActiveStake = "0"
|
9337
|
+
} = decodePoolStake(networkStorageCoders.ledger, changes[1], networkId);
|
9338
|
+
const {
|
9339
|
+
metadata = "0"
|
9340
|
+
} = decodePoolMeta(networkStorageCoders.metadata, changes[2], networkId);
|
9341
|
+
const amount = accountPoints === "0" || poolPoints === "0" || poolTotalActiveStake === "0" ? 0n : BigInt(poolTotalActiveStake) * BigInt(accountPoints) / BigInt(poolPoints);
|
9342
|
+
const unbondingAmount = nomPoolMemberInfo.unbondingEras.reduce((total, {
|
9343
|
+
amount
|
9344
|
+
}) => total + BigInt(amount ?? "0"), 0n);
|
9345
|
+
return {
|
9346
|
+
...balance,
|
9347
|
+
values: [...(balance.values ?? []), {
|
9348
|
+
source: "nompools-staking",
|
9349
|
+
type: "nompool",
|
9350
|
+
label: "nompools-staking",
|
9351
|
+
amount: amount.toString(),
|
9352
|
+
meta: {
|
9353
|
+
type: "nompool",
|
9354
|
+
poolId: nomPoolMemberInfo.poolId,
|
9355
|
+
description: metadata
|
9356
|
+
}
|
9357
|
+
}, {
|
9358
|
+
source: "nompools-staking",
|
9359
|
+
type: "nompool",
|
9360
|
+
label: "nompools-unbonding",
|
9361
|
+
amount: unbondingAmount.toString(),
|
9362
|
+
meta: {
|
9363
|
+
poolId: nomPoolMemberInfo.poolId,
|
9364
|
+
description: metadata ?? `Pool ${nomPoolMemberInfo.poolId}`,
|
9365
|
+
unbonding: true
|
9366
|
+
}
|
9367
|
+
}]
|
9368
|
+
};
|
9369
|
+
}
|
9370
|
+
};
|
9371
|
+
});
|
9372
|
+
};
|
9373
|
+
const getNomPoolCoders = (networkId, miniMetadata) => {
|
9374
|
+
return buildNetworkStorageCoders(networkId, miniMetadata, {
|
9375
|
+
poolMembers: ["NominationPools", "PoolMembers"],
|
9376
|
+
bondedPools: ["NominationPools", "BondedPools"],
|
9377
|
+
ledger: ["Staking", "Ledger"],
|
9378
|
+
metadata: ["NominationPools", "Metadata"]
|
9379
|
+
});
|
9380
|
+
};
|
9381
|
+
const decodePoolPoints = (coder, value, networkId) => {
|
9382
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9383
|
+
|
9384
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode bondedPools on chain ${networkId}`);
|
9385
|
+
return {
|
9386
|
+
poolPoints: decoded?.points.toString()
|
9387
|
+
};
|
9388
|
+
};
|
9389
|
+
const decodePoolStake = (coder, value, networkId) => {
|
9390
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9391
|
+
|
9392
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode ledger on chain ${networkId}`);
|
9393
|
+
return {
|
9394
|
+
poolTotalActiveStake: decoded?.active.toString()
|
9395
|
+
};
|
9396
|
+
};
|
9397
|
+
const decodePoolMeta = (coder, value, networkId) => {
|
9398
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
9399
|
+
|
9400
|
+
const decoded = scale.decodeScale(coder, value, `Failed to decode metadata on chain ${networkId}`);
|
9401
|
+
const metadata = decoded?.asText();
|
9402
|
+
return {
|
9403
|
+
metadata
|
9404
|
+
};
|
9405
|
+
};
|
9406
|
+
const getNomPoolStateKeys = (coders, nomPoolMemberInfo, extra) => {
|
9407
|
+
if (!nomPoolMemberInfo || !extra.nominationPoolsPalletId || !coders?.bondedPools || !coders.ledger || !coders.metadata) return [];
|
9408
|
+
const poolId = nomPoolMemberInfo.poolId;
|
9409
|
+
const stashAddress = nompoolStashAccountId(extra.nominationPoolsPalletId, poolId);
|
9410
|
+
const poolPointsStateKey = coders.bondedPools.keys.enc(poolId);
|
9411
|
+
const poolStakeStateKey = coders.ledger.keys.enc(stashAddress);
|
9412
|
+
const poolMetaStateKey = coders.metadata.keys.enc(poolId);
|
9413
|
+
return [poolPointsStateKey, poolStakeStateKey, poolMetaStateKey];
|
9414
|
+
};
|
9415
|
+
|
9416
|
+
const fetchBalances$2 = async ({
|
9417
|
+
networkId,
|
9418
|
+
addressesByToken,
|
9419
|
+
connector,
|
9420
|
+
miniMetadata
|
9421
|
+
}) => {
|
9422
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
9423
|
+
if (!miniMetadata?.data) {
|
9424
|
+
log.warn("MiniMetadata is required for fetching balances");
|
9425
|
+
return {
|
9426
|
+
success: [],
|
9427
|
+
errors: balanceDefs.map(def => ({
|
9428
|
+
tokenId: def.token.id,
|
9429
|
+
address: def.address,
|
9430
|
+
error: new Error("Minimetadata is required for fetching balances")
|
9431
|
+
}))
|
9432
|
+
};
|
9433
|
+
}
|
9434
|
+
if (miniMetadata.source !== MODULE_TYPE$2) {
|
9435
|
+
log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$2}.`);
|
9436
|
+
return {
|
9437
|
+
success: [],
|
9438
|
+
errors: balanceDefs.map(def => ({
|
9439
|
+
tokenId: def.token.id,
|
9440
|
+
address: def.address,
|
9441
|
+
error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$2}`)
|
9442
|
+
}))
|
9443
|
+
};
|
9444
|
+
}
|
9445
|
+
if (miniMetadata.chainId !== networkId) {
|
9446
|
+
log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$2}. Expected chainId is ${networkId}`);
|
9447
|
+
return {
|
9448
|
+
success: [],
|
9449
|
+
errors: balanceDefs.map(def => ({
|
9450
|
+
tokenId: def.token.id,
|
9451
|
+
address: def.address,
|
9452
|
+
error: new Error(`Invalid request: Expected chainId is ${networkId}`)
|
9453
|
+
}))
|
9454
|
+
};
|
9455
|
+
}
|
9456
|
+
const queries = buildBaseQueries(networkId, balanceDefs, miniMetadata);
|
9457
|
+
const partialBalances = await fetchQueriesPack(connector, networkId, queries);
|
9458
|
+
|
9459
|
+
// now for each balance that includes nomPoolStaking, we need to fetch the metadata for the pool
|
9460
|
+
const nomPoolQueries = buildNomPoolQueries(networkId, partialBalances, miniMetadata);
|
9461
|
+
const balances = await fetchQueriesPack(connector, networkId, nomPoolQueries);
|
9462
|
+
|
9463
|
+
// TODO ⚠️ dedupe locks
|
9464
|
+
|
9465
|
+
const subtensorBalances$ = getSubtensorStakingBalances$(connector, networkId, balanceDefs, miniMetadata);
|
9466
|
+
const subtensorBalancesByAddress = await rxjs.firstValueFrom(subtensorBalances$);
|
9467
|
+
for (const [address, subtensorBalances] of Object.entries(subtensorBalancesByAddress)) {
|
9468
|
+
const balance = balances.find(b => b.address === address);
|
9469
|
+
if (balance?.values) balance.values.push(...subtensorBalances);
|
9470
|
+
}
|
9471
|
+
return {
|
9472
|
+
success: balances,
|
9473
|
+
errors: []
|
9474
|
+
};
|
9475
|
+
};
|
9476
|
+
|
9477
|
+
const fetchTokens$2 = async ({
|
9478
|
+
networkId,
|
9479
|
+
tokens,
|
9480
|
+
connector,
|
9481
|
+
miniMetadata
|
9482
|
+
}) => {
|
9483
|
+
if (miniMetadata.extra.disable) return [];
|
9484
|
+
const {
|
9485
|
+
tokenSymbol: symbol,
|
9486
|
+
tokenDecimals: decimals
|
9487
|
+
} = await getChainProperties(connector, networkId);
|
9488
|
+
if (!miniMetadata.extra.existentialDeposit) log.warn(`Substrate native module: existentialDeposit is undefined for ${networkId}, using 0`);
|
9489
|
+
const tokenConfig = tokens[0];
|
9490
|
+
const nativeToken = {
|
9491
|
+
id: chaindataProvider.subNativeTokenId(networkId),
|
9492
|
+
type: "substrate-native",
|
9493
|
+
platform: "polkadot",
|
9494
|
+
networkId,
|
9495
|
+
isDefault: true,
|
9496
|
+
symbol: symbol,
|
9497
|
+
name: symbol,
|
9498
|
+
decimals: decimals,
|
9499
|
+
existentialDeposit: miniMetadata.extra.existentialDeposit ?? "0"
|
9500
|
+
};
|
9501
|
+
return [lodash.assign(nativeToken, tokenConfig)];
|
9502
|
+
};
|
9503
|
+
const DotNetworkPropertiesSimple = z__default.default.object({
|
9504
|
+
tokenDecimals: z__default.default.number().optional().default(0),
|
9505
|
+
tokenSymbol: z__default.default.string().optional().default("Unit")
|
9506
|
+
});
|
9507
|
+
const DotNetworkPropertiesArray = z__default.default.object({
|
9508
|
+
tokenDecimals: z__default.default.array(z__default.default.number()).nonempty(),
|
9509
|
+
tokenSymbol: z__default.default.array(z__default.default.string()).nonempty()
|
9510
|
+
});
|
9511
|
+
const DotNetworkPropertiesSchema = z__default.default.union([DotNetworkPropertiesSimple, DotNetworkPropertiesArray]).transform(val => ({
|
9512
|
+
tokenDecimals: Array.isArray(val.tokenDecimals) ? val.tokenDecimals[0] : val.tokenDecimals,
|
9513
|
+
tokenSymbol: Array.isArray(val.tokenSymbol) ? val.tokenSymbol[0] : val.tokenSymbol
|
9514
|
+
}));
|
9515
|
+
const getChainProperties = async (connector, networkId) => {
|
9516
|
+
const properties = await connector.send(networkId, "system_properties", [], true);
|
9517
|
+
return DotNetworkPropertiesSchema.parse(properties);
|
9518
|
+
};
|
9519
|
+
|
9520
|
+
const getMiniMetadata$2 = ({
|
9521
|
+
networkId,
|
9522
|
+
specVersion,
|
9523
|
+
metadataRpc,
|
9524
|
+
config
|
9525
|
+
}) => {
|
9526
|
+
const source = MODULE_TYPE$2;
|
9527
|
+
const chainId = networkId;
|
9528
|
+
const systemVersion = getConstantValue(metadataRpc, "System", "Version");
|
9529
|
+
if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
|
9530
|
+
networkId,
|
9531
|
+
specVersion,
|
9532
|
+
systemVersion
|
9533
|
+
});
|
9534
|
+
const id = deriveMiniMetadataId({
|
9535
|
+
source,
|
9536
|
+
chainId,
|
9537
|
+
specVersion
|
9538
|
+
});
|
9539
|
+
const {
|
9540
|
+
metadata,
|
9541
|
+
unifiedMetadata
|
9542
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
9543
|
+
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
9544
|
+
if (config?.disable) return {
|
9545
|
+
id,
|
9546
|
+
source,
|
9547
|
+
chainId,
|
9548
|
+
specVersion,
|
9549
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
9550
|
+
data: null,
|
9551
|
+
extra: {
|
9552
|
+
disable: true
|
9553
|
+
}
|
9554
|
+
};
|
9555
|
+
const existentialDeposit = tryGetConstantValue(metadataRpc, "Balances", "ExistentialDeposit")?.toString();
|
9556
|
+
const nominationPoolsPalletId = tryGetConstantValue(metadataRpc, "NominationPools", "PalletId")?.asText();
|
9557
|
+
const hasSubtensorPallet = !!tryGetConstantValue(metadataRpc, "SubtensorModule", "KeySwapCost");
|
9558
|
+
const hasFreezesItem = Boolean(unifiedMetadata.pallets.find(({
|
9559
|
+
name
|
9560
|
+
}) => name === "Balances")?.storage?.items.find(({
|
9561
|
+
name
|
9562
|
+
}) => name === "Freezes"));
|
9563
|
+
const useLegacyTransferableCalculation = !hasFreezesItem;
|
9564
|
+
scale.compactMetadata(metadata, [{
|
9565
|
+
pallet: "System",
|
9566
|
+
constants: ["Version", "SS58Prefix"],
|
9567
|
+
items: ["Account"]
|
9568
|
+
}, {
|
9569
|
+
pallet: "Balances",
|
9570
|
+
items: ["Reserves", "Holds", "Locks", "Freezes"]
|
9571
|
+
}, {
|
9572
|
+
pallet: "NominationPools",
|
9573
|
+
items: ["PoolMembers", "BondedPools", "Metadata"]
|
9574
|
+
}, {
|
9575
|
+
pallet: "Staking",
|
9576
|
+
items: ["Ledger"]
|
9577
|
+
},
|
9578
|
+
// TotalColdkeyStake is used until v.2.2.1, then it is replaced by StakingHotkeys+Stake
|
9579
|
+
// Need to keep TotalColdkeyStake for a while so chaindata keeps including it in miniMetadatas, so it doesnt break old versions of the wallet
|
9580
|
+
// TODO: Since chaindata v4 this is safe to now delete
|
9581
|
+
{
|
9582
|
+
pallet: "SubtensorModule",
|
9583
|
+
items: ["TotalColdkeyStake", "StakingHotkeys", "Stake"]
|
9584
|
+
}], [{
|
9585
|
+
runtimeApi: "StakeInfoRuntimeApi",
|
9586
|
+
methods: ["get_stake_info_for_coldkey"]
|
9587
|
+
}, {
|
9588
|
+
runtimeApi: "SubnetInfoRuntimeApi",
|
9589
|
+
methods: ["get_dynamic_info"]
|
9590
|
+
}]);
|
9591
|
+
return {
|
9592
|
+
id,
|
9593
|
+
source,
|
9594
|
+
chainId,
|
9595
|
+
specVersion,
|
9596
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
9597
|
+
data: scale.encodeMetadata(metadata),
|
9598
|
+
extra: {
|
9599
|
+
useLegacyTransferableCalculation,
|
9600
|
+
existentialDeposit,
|
9601
|
+
nominationPoolsPalletId,
|
9602
|
+
hasSubtensorPallet
|
9603
|
+
}
|
9604
|
+
};
|
9605
|
+
};
|
9606
|
+
|
9607
|
+
const getTransferCallData$2 = ({
|
9608
|
+
from,
|
9609
|
+
to,
|
9610
|
+
value,
|
9611
|
+
token,
|
9612
|
+
type,
|
9613
|
+
metadataRpc
|
9614
|
+
}) => {
|
9615
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$2)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$2}.`);
|
9616
|
+
const {
|
9617
|
+
unifiedMetadata,
|
9618
|
+
lookupFn,
|
9619
|
+
builder
|
9620
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
9621
|
+
const method = getTransferMethod$1(type, unifiedMetadata, lookupFn);
|
9622
|
+
const {
|
9623
|
+
codec,
|
9624
|
+
location
|
9625
|
+
} = builder.buildCall("Balances", method);
|
9626
|
+
const args = getEncodedArgs(method, to, value, codec);
|
9627
|
+
const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
|
9628
|
+
return {
|
9629
|
+
address: from,
|
9630
|
+
method: callData.asHex()
|
9631
|
+
};
|
9632
|
+
};
|
9633
|
+
const getTransferMethod$1 = (type, unifiedMetadata, lookupFn) => {
|
9634
|
+
switch (type) {
|
9635
|
+
case "keep-alive":
|
9636
|
+
return "transfer_keep_alive";
|
9637
|
+
case "all":
|
9638
|
+
return "transfer_all";
|
9639
|
+
case "allow-death":
|
9640
|
+
{
|
9641
|
+
const callType = unifiedMetadata.pallets.find(pallet => pallet.name === "Balances")?.calls?.type;
|
9642
|
+
if (callType) {
|
9643
|
+
const palletCalls = lookupFn(callType);
|
9644
|
+
if (palletCalls.type === "enum" && palletCalls.value["transfer_allow_death"]) return "transfer_allow_death";
|
9645
|
+
}
|
9646
|
+
|
9647
|
+
// legacy fallback
|
9648
|
+
return "transfer";
|
9649
|
+
}
|
9650
|
+
}
|
9651
|
+
};
|
9652
|
+
const getEncodedArgs = (method, to, value, argsCodec) => {
|
9653
|
+
try {
|
9654
|
+
switch (method) {
|
9655
|
+
case "transfer_allow_death":
|
9656
|
+
case "transfer_keep_alive":
|
9657
|
+
case "transfer":
|
9658
|
+
return getTransferEncodedArgs(to, value, argsCodec);
|
9659
|
+
case "transfer_all":
|
9660
|
+
return getTransferAllEncodedArgs(to, argsCodec);
|
9661
|
+
}
|
9662
|
+
} catch {
|
9663
|
+
throw new Error(`Failed to encode arguments for method ${method}, ${to}, ${value}`);
|
9664
|
+
}
|
9665
|
+
};
|
9666
|
+
const getEncodedValue = (codec, possibleValue) => {
|
9667
|
+
for (const getArgs of possibleValue) {
|
9668
|
+
try {
|
9669
|
+
return codec.enc(getArgs());
|
9670
|
+
} catch {
|
9671
|
+
// wrong inputs, ignore and try the next one
|
9672
|
+
}
|
9673
|
+
}
|
9674
|
+
throw new Error("Failed to encode");
|
9675
|
+
};
|
9676
|
+
|
9677
|
+
// same inputs for both KeepAlive and allowDeath
|
9678
|
+
const getTransferEncodedArgs = (to, value, codec) => {
|
9679
|
+
return getEncodedValue(codec, [() => ({
|
9680
|
+
dest: polkadotApi.Enum("Id", to),
|
9681
|
+
value: BigInt(value)
|
9682
|
+
})]);
|
9683
|
+
};
|
9684
|
+
const getTransferAllEncodedArgs = (to, codec) => {
|
9685
|
+
return getEncodedValue(codec, [() => ({
|
9686
|
+
dest: polkadotApi.Enum("Id", to),
|
9687
|
+
keep_alive: false
|
9688
|
+
})]);
|
9689
|
+
};
|
9690
|
+
|
9691
|
+
const SUBSCRIPTION_INTERVAL$2 = 6_000;
|
9692
|
+
const subscribeBalances$2 = ({
|
9693
|
+
networkId,
|
9694
|
+
addressesByToken,
|
9695
|
+
connector,
|
9696
|
+
miniMetadata
|
9697
|
+
}) => {
|
9698
|
+
return new rxjs.Observable(subscriber => {
|
9699
|
+
const abortController = new AbortController();
|
9700
|
+
|
9701
|
+
// on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
|
9702
|
+
// => poll values for each block
|
9703
|
+
const poll = async () => {
|
9704
|
+
try {
|
9705
|
+
if (abortController.signal.aborted) return;
|
9706
|
+
const balances = await fetchBalances$2({
|
9707
|
+
networkId,
|
9708
|
+
addressesByToken,
|
9709
|
+
connector,
|
9710
|
+
miniMetadata
|
9711
|
+
});
|
9712
|
+
if (abortController.signal.aborted) return;
|
9713
|
+
subscriber.next(balances);
|
9714
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$2);
|
9715
|
+
} catch (error) {
|
9716
|
+
log.error("Error", {
|
9717
|
+
module: MODULE_TYPE$2,
|
9718
|
+
networkId,
|
9719
|
+
miniMetadata,
|
9720
|
+
addressesByToken,
|
9721
|
+
error
|
9722
|
+
});
|
9723
|
+
subscriber.error(error);
|
9724
|
+
}
|
9725
|
+
};
|
9726
|
+
poll();
|
9727
|
+
return () => {
|
9728
|
+
abortController.abort();
|
9729
|
+
};
|
9730
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
9731
|
+
};
|
9732
|
+
|
9733
|
+
const SubNativeBalanceModule = {
|
9734
|
+
type: MODULE_TYPE$2,
|
9735
|
+
platform: PLATFORM$2,
|
9736
|
+
getMiniMetadata: getMiniMetadata$2,
|
9737
|
+
fetchTokens: fetchTokens$2,
|
9738
|
+
fetchBalances: fetchBalances$2,
|
9739
|
+
subscribeBalances: subscribeBalances$2,
|
9740
|
+
getTransferCallData: getTransferCallData$2
|
9741
|
+
};
|
9742
|
+
|
9743
|
+
const MODULE_TYPE$1 = chaindataProvider.SubPsp22TokenSchema.shape.type.value;
|
9744
|
+
const PLATFORM$1 = chaindataProvider.SubPsp22TokenSchema.shape.platform.value;
|
9745
|
+
|
9746
|
+
// to be used by chaindata too
|
9747
|
+
z__default.default.strictObject({
|
9748
|
+
contractAddress: chaindataProvider.SubPsp22TokenSchema.shape.contractAddress,
|
9749
|
+
...TokenConfigBaseSchema.shape
|
9750
|
+
});
|
9751
|
+
|
9752
|
+
const fetchBalances$1 = async ({
|
9753
|
+
networkId,
|
9754
|
+
addressesByToken,
|
9755
|
+
connector
|
9756
|
+
}) => {
|
9757
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
9758
|
+
if (!balanceDefs.length) return {
|
9759
|
+
success: [],
|
9760
|
+
errors: []
|
9761
|
+
};
|
9762
|
+
const registry = new types.TypeRegistry();
|
9763
|
+
const Psp22Abi = new apiContract.Abi(psp22Abi);
|
9764
|
+
const contractCall = makeContractCaller({
|
9765
|
+
chainConnector: connector,
|
9766
|
+
chainId: networkId,
|
9767
|
+
registry
|
9768
|
+
});
|
9769
|
+
const results = await Promise.allSettled(balanceDefs.map(async ({
|
9770
|
+
token,
|
9771
|
+
address
|
9772
|
+
}) => {
|
9773
|
+
const result = await contractCall(address, token.contractAddress, Psp22Abi.findMessage("PSP22::balance_of").toU8a([address]));
|
9774
|
+
if (!result.result.isOk) throw new Error("Failed to fetch balance");
|
9775
|
+
const value = registry.createType("Balance", result.result.asOk.data).toString();
|
9776
|
+
const balance = {
|
9777
|
+
source: "substrate-psp22",
|
9778
|
+
status: "live",
|
9779
|
+
address,
|
9780
|
+
networkId: token.networkId,
|
9781
|
+
tokenId: token.id,
|
9782
|
+
value
|
9783
|
+
};
|
9784
|
+
return balance;
|
9785
|
+
}));
|
9786
|
+
return results.reduce((acc, result) => {
|
9787
|
+
if (result.status === "fulfilled") acc.success.push(result.value);else {
|
9788
|
+
const error = result.reason;
|
9789
|
+
acc.errors.push({
|
9790
|
+
tokenId: error.tokenId,
|
9791
|
+
address: error.address,
|
9792
|
+
error
|
9793
|
+
});
|
9794
|
+
}
|
9795
|
+
return acc;
|
9796
|
+
}, {
|
9797
|
+
success: [],
|
9798
|
+
errors: []
|
9799
|
+
});
|
9800
|
+
};
|
9801
|
+
|
9802
|
+
const fetchTokens$1 = async ({
|
9803
|
+
networkId,
|
9804
|
+
tokens,
|
9805
|
+
connector
|
9806
|
+
}) => {
|
9807
|
+
if (!tokens.length) return [];
|
9808
|
+
const registry = new types.TypeRegistry();
|
9809
|
+
const Psp22Abi = new apiContract.Abi(psp22Abi);
|
9810
|
+
|
9811
|
+
// TODO: Use `decodeOutput` from `./util/decodeOutput`
|
9812
|
+
const contractCall = makeContractCaller({
|
9813
|
+
chainConnector: connector,
|
9814
|
+
chainId: networkId,
|
9815
|
+
registry
|
9816
|
+
});
|
9817
|
+
const tokenList = {};
|
9818
|
+
for (const tokenConfig of tokens ?? []) {
|
9819
|
+
try {
|
9820
|
+
let symbol = tokenConfig?.symbol ?? "Unit";
|
9821
|
+
let decimals = tokenConfig?.decimals ?? 0;
|
9822
|
+
const contractAddress = tokenConfig?.contractAddress ?? undefined;
|
9823
|
+
if (contractAddress === undefined) continue;
|
9824
|
+
await (async () => {
|
9825
|
+
const [symbolResult, decimalsResult] = await Promise.all([contractCall(contractAddress, contractAddress, Psp22Abi.findMessage("PSP22Metadata::token_symbol").toU8a([])), contractCall(contractAddress, contractAddress, Psp22Abi.findMessage("PSP22Metadata::token_decimals").toU8a([]))]);
|
9826
|
+
|
9827
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
9828
|
+
const symbolData = symbolResult.toJSON()?.result?.ok?.data;
|
9829
|
+
symbol = typeof symbolData === "string" && symbolData.startsWith("0x") ? util$1.u8aToString(registry.createType("Option<Vec<u8>>",
|
9830
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
9831
|
+
symbolResult.toJSON()?.result?.ok?.data)?.value)?.replace(/\p{C}/gu, "") : symbol;
|
9832
|
+
|
9833
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
9834
|
+
const decimalsData = decimalsResult.toJSON()?.result?.ok?.data;
|
9835
|
+
decimals = typeof decimalsData === "string" && decimalsData.startsWith("0x") ? util$1.hexToNumber(decimalsData) : decimals;
|
9836
|
+
})();
|
9837
|
+
const id = chaindataProvider.subPsp22TokenId(networkId, contractAddress);
|
9838
|
+
const token = {
|
9839
|
+
id,
|
9840
|
+
type: "substrate-psp22",
|
9841
|
+
platform: "polkadot",
|
9842
|
+
isDefault: tokenConfig.isDefault ?? true,
|
9843
|
+
symbol,
|
9844
|
+
decimals,
|
9845
|
+
name: tokenConfig?.name || symbol,
|
9846
|
+
logo: tokenConfig?.logo,
|
9847
|
+
contractAddress,
|
9848
|
+
networkId
|
9849
|
+
};
|
9850
|
+
if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
|
9851
|
+
if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
|
9852
|
+
tokenList[token.id] = token;
|
9853
|
+
} catch (error) {
|
9854
|
+
log.error(`Failed to build substrate-psp22 token ${tokenConfig.contractAddress} (${tokenConfig.symbol}) on ${networkId}`, error?.message ?? error);
|
9855
|
+
continue;
|
9856
|
+
}
|
9857
|
+
}
|
9858
|
+
return lodash.values(tokenList).filter(t => {
|
9859
|
+
const parsed = chaindataProvider.SubPsp22TokenSchema.safeParse(t);
|
9860
|
+
if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$1}`, t);
|
9861
|
+
return parsed.success;
|
9862
|
+
});
|
9863
|
+
};
|
9864
|
+
|
9865
|
+
const getMiniMetadata$1 = ({
|
9866
|
+
networkId,
|
9867
|
+
specVersion,
|
9868
|
+
metadataRpc
|
9869
|
+
}) => {
|
9870
|
+
const source = MODULE_TYPE$1;
|
9871
|
+
const chainId = networkId;
|
9872
|
+
const systemVersion = getConstantValue(metadataRpc, "System", "Version");
|
9873
|
+
if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
|
9874
|
+
networkId,
|
9875
|
+
specVersion,
|
9876
|
+
systemVersion
|
9877
|
+
});
|
9878
|
+
const id = deriveMiniMetadataId({
|
9879
|
+
source,
|
9880
|
+
chainId,
|
9881
|
+
specVersion
|
9882
|
+
});
|
9883
|
+
const {
|
9884
|
+
unifiedMetadata
|
9885
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
9886
|
+
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
9887
|
+
return {
|
9888
|
+
id,
|
9889
|
+
source,
|
9890
|
+
chainId,
|
9891
|
+
specVersion,
|
9892
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
9893
|
+
data: null,
|
9894
|
+
extra: null
|
9895
|
+
};
|
9896
|
+
};
|
9897
|
+
|
9898
|
+
const getTransferCallData$1 = async ({
|
9899
|
+
from,
|
9900
|
+
to,
|
9901
|
+
value,
|
9902
|
+
token,
|
9903
|
+
metadataRpc,
|
9904
|
+
connector
|
9905
|
+
}) => {
|
9906
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$1)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$1}.`);
|
9907
|
+
const networkId = chaindataProvider.parseTokenId(token.id).networkId;
|
9908
|
+
const {
|
9909
|
+
builder
|
9910
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
9911
|
+
const {
|
9912
|
+
codec,
|
9913
|
+
location
|
9914
|
+
} = builder.buildCall("Contracts", "call");
|
9915
|
+
const Psp22Abi = new apiContract.Abi(psp22Abi);
|
9916
|
+
const registry = new types.TypeRegistry();
|
9917
|
+
const contractCall = makeContractCaller({
|
9918
|
+
chainConnector: connector,
|
9919
|
+
chainId: networkId,
|
9920
|
+
registry
|
9921
|
+
});
|
9922
|
+
|
9923
|
+
// TODO use papi contract api
|
9924
|
+
const data = Psp22Abi.findMessage("PSP22::transfer").toU8a([to, value, undefined]);
|
9925
|
+
const hexData = registry.createType("Vec<u8>", data).toHex();
|
9926
|
+
const dryRunResult = await contractCall(from, token.contractAddress, data);
|
9927
|
+
const args = codec.enc({
|
9928
|
+
dest: polkadotApi.Enum("Id", token.contractAddress),
|
9929
|
+
value: 0,
|
9930
|
+
gas_limit: {
|
9931
|
+
ref_time: dryRunResult.gasRequired.refTime.toBigInt(),
|
9932
|
+
proof_size: dryRunResult.gasRequired.proofSize.toBigInt()
|
9933
|
+
},
|
9934
|
+
storage_deposit_limit: dryRunResult.storageDeposit.isCharge ? dryRunResult.storageDeposit.asCharge.toBigInt() : null,
|
9935
|
+
data: polkadotApi.Binary.fromHex(hexData)
|
9936
|
+
});
|
9937
|
+
const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
|
9938
|
+
return {
|
9939
|
+
address: from,
|
9940
|
+
method: callData.asHex()
|
9941
|
+
};
|
9942
|
+
};
|
9943
|
+
|
9944
|
+
const SUBSCRIPTION_INTERVAL$1 = 6_000;
|
9945
|
+
const subscribeBalances$1 = ({
|
9946
|
+
networkId,
|
9947
|
+
addressesByToken,
|
9948
|
+
connector,
|
9949
|
+
miniMetadata
|
9950
|
+
}) => {
|
9951
|
+
return new rxjs.Observable(subscriber => {
|
9952
|
+
const abortController = new AbortController();
|
9953
|
+
|
9954
|
+
// on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
|
9955
|
+
// => poll values for each block
|
9956
|
+
const poll = async () => {
|
9957
|
+
try {
|
9958
|
+
if (abortController.signal.aborted) return;
|
9959
|
+
const balances = await fetchBalances$1({
|
9960
|
+
networkId,
|
9961
|
+
addressesByToken,
|
9962
|
+
connector,
|
9963
|
+
miniMetadata
|
9964
|
+
});
|
9965
|
+
if (abortController.signal.aborted) return;
|
9966
|
+
subscriber.next(balances);
|
9967
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$1);
|
9968
|
+
} catch (error) {
|
9969
|
+
log.error("Error", {
|
9970
|
+
module: MODULE_TYPE$1,
|
9971
|
+
networkId,
|
9972
|
+
miniMetadata,
|
9973
|
+
addressesByToken,
|
9974
|
+
error
|
9975
|
+
});
|
9976
|
+
subscriber.error(error);
|
9977
|
+
}
|
9978
|
+
};
|
9979
|
+
poll();
|
9980
|
+
return () => {
|
9981
|
+
abortController.abort();
|
9982
|
+
};
|
9983
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
9984
|
+
};
|
9985
|
+
|
9986
|
+
const SubPsp22BalanceModule = {
|
9987
|
+
type: MODULE_TYPE$1,
|
9988
|
+
platform: PLATFORM$1,
|
9989
|
+
getMiniMetadata: getMiniMetadata$1,
|
9990
|
+
fetchTokens: fetchTokens$1,
|
9991
|
+
fetchBalances: fetchBalances$1,
|
9992
|
+
subscribeBalances: subscribeBalances$1,
|
9993
|
+
getTransferCallData: getTransferCallData$1
|
9994
|
+
};
|
9995
|
+
|
9996
|
+
const MODULE_TYPE = chaindataProvider.SubTokensTokenSchema.shape.type.value;
|
9997
|
+
const PLATFORM = chaindataProvider.SubTokensTokenSchema.shape.platform.value;
|
9998
|
+
|
9999
|
+
// to be used by chaindata too
|
10000
|
+
z__default.default.strictObject({
|
10001
|
+
onChainId: chaindataProvider.SubTokensTokenSchema.shape.onChainId,
|
10002
|
+
...TokenConfigBaseSchema.shape,
|
10003
|
+
// force these 3 fields because in this module we wont pull anything from chain
|
10004
|
+
symbol: z__default.default.string().nonempty(),
|
10005
|
+
decimals: z__default.default.number(),
|
10006
|
+
existentialDeposit: z__default.default.string().nonempty()
|
10007
|
+
});
|
10008
|
+
|
10009
|
+
// Do not use this type outside of this module
|
10010
|
+
|
10011
|
+
// Do not use this type outside of this module
|
10012
|
+
|
10013
|
+
const fetchBalances = async ({
|
10014
|
+
networkId,
|
10015
|
+
addressesByToken,
|
10016
|
+
connector,
|
10017
|
+
miniMetadata
|
10018
|
+
}) => {
|
10019
|
+
const balanceDefs = getBalanceDefs(addressesByToken);
|
10020
|
+
if (!miniMetadata?.data) {
|
10021
|
+
log.warn("MiniMetadata is required for fetching balances");
|
10022
|
+
return {
|
10023
|
+
success: [],
|
10024
|
+
errors: balanceDefs.map(def => ({
|
10025
|
+
tokenId: def.token.id,
|
10026
|
+
address: def.address,
|
10027
|
+
error: new Error("Minimetadata is required for fetching balances")
|
10028
|
+
}))
|
10029
|
+
};
|
10030
|
+
}
|
10031
|
+
if (miniMetadata.source !== MODULE_TYPE) {
|
10032
|
+
log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE}.`);
|
10033
|
+
return {
|
10034
|
+
success: [],
|
10035
|
+
errors: balanceDefs.map(def => ({
|
10036
|
+
tokenId: def.token.id,
|
10037
|
+
address: def.address,
|
10038
|
+
error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE}`)
|
10039
|
+
}))
|
10040
|
+
};
|
10041
|
+
}
|
10042
|
+
if (miniMetadata.chainId !== networkId) {
|
10043
|
+
log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE}. Expected chainId is ${networkId}`);
|
10044
|
+
return {
|
10045
|
+
success: [],
|
10046
|
+
errors: balanceDefs.map(def => ({
|
10047
|
+
tokenId: def.token.id,
|
10048
|
+
address: def.address,
|
10049
|
+
error: new Error(`Invalid request: Expected chainId is ${networkId}`)
|
10050
|
+
}))
|
10051
|
+
};
|
10052
|
+
}
|
10053
|
+
const queries = buildQueries(networkId, balanceDefs, miniMetadata);
|
10054
|
+
const balances = await new RpcStateQueryHelper(connector, queries).fetch();
|
10055
|
+
return balanceDefs.reduce((acc, def) => {
|
10056
|
+
const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
|
10057
|
+
if (balance) acc.success.push(balance);
|
10058
|
+
//if no entry consider empty balance
|
10059
|
+
else acc.success.push({
|
10060
|
+
address: def.address,
|
10061
|
+
networkId,
|
10062
|
+
tokenId: def.token.id,
|
10063
|
+
source: MODULE_TYPE,
|
10064
|
+
status: "live",
|
10065
|
+
values: [{
|
10066
|
+
type: "free",
|
10067
|
+
label: "free",
|
10068
|
+
amount: "0"
|
10069
|
+
}, {
|
10070
|
+
type: "locked",
|
10071
|
+
label: "frozen",
|
10072
|
+
amount: "0"
|
10073
|
+
}]
|
10074
|
+
});
|
10075
|
+
return acc;
|
10076
|
+
}, {
|
10077
|
+
success: [],
|
10078
|
+
errors: []
|
10079
|
+
});
|
10080
|
+
};
|
10081
|
+
const buildQueries = (networkId, balanceDefs, miniMetadata) => {
|
10082
|
+
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
10083
|
+
storage: [miniMetadata.extra.palletId, "Accounts"]
|
10084
|
+
});
|
10085
|
+
return balanceDefs.map(({
|
10086
|
+
token,
|
10087
|
+
address
|
10088
|
+
}) => {
|
10089
|
+
const scaleCoder = networkStorageCoders?.storage;
|
10090
|
+
const getStateKey = onChainId => {
|
10091
|
+
try {
|
10092
|
+
return scaleCoder.keys.enc(address, scale.papiParse(onChainId));
|
10093
|
+
} catch {
|
10094
|
+
return null;
|
10095
|
+
}
|
10096
|
+
};
|
10097
|
+
const stateKey = getStateKey(token.onChainId);
|
10098
|
+
if (!stateKey) {
|
10099
|
+
log.warn(`Invalid assetId / address in ${networkId} storage query ${token.onChainId} / ${address}`);
|
10100
|
+
return null;
|
10101
|
+
}
|
10102
|
+
const decodeResult = change => {
|
10103
|
+
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
10104
|
+
|
10105
|
+
const decoded = scale.decodeScale(scaleCoder, change, `Failed to decode substrate-tokens balance on chain ${networkId}`) ?? {
|
10106
|
+
free: 0n,
|
10107
|
+
reserved: 0n,
|
10108
|
+
frozen: 0n
|
10109
|
+
};
|
10110
|
+
const free = (decoded?.free ?? 0n).toString();
|
10111
|
+
const reserved = (decoded?.reserved ?? 0n).toString();
|
10112
|
+
const frozen = (decoded?.frozen ?? 0n).toString();
|
10113
|
+
const balanceValues = [{
|
10114
|
+
type: "free",
|
10115
|
+
label: "free",
|
10116
|
+
amount: free.toString()
|
10117
|
+
}, {
|
10118
|
+
type: "reserved",
|
10119
|
+
label: "reserved",
|
10120
|
+
amount: reserved.toString()
|
10121
|
+
}, {
|
10122
|
+
type: "locked",
|
10123
|
+
label: "frozen",
|
10124
|
+
amount: frozen.toString()
|
10125
|
+
}];
|
10126
|
+
return {
|
10127
|
+
source: "substrate-tokens",
|
10128
|
+
status: "live",
|
10129
|
+
address,
|
10130
|
+
networkId,
|
10131
|
+
tokenId: token.id,
|
10132
|
+
values: balanceValues
|
10133
|
+
};
|
10134
|
+
};
|
10135
|
+
return {
|
10136
|
+
chainId: networkId,
|
10137
|
+
stateKey,
|
10138
|
+
decodeResult
|
10139
|
+
};
|
10140
|
+
}).filter(util.isNotNil);
|
10141
|
+
};
|
10142
|
+
|
10143
|
+
const fetchTokens = async ({
|
10144
|
+
networkId,
|
10145
|
+
tokens,
|
10146
|
+
miniMetadata
|
10147
|
+
}) => {
|
10148
|
+
if (!miniMetadata?.data) return [];
|
10149
|
+
|
10150
|
+
// in this module we do not fetch any token information from the chain
|
10151
|
+
// this is because there are basically as many pallet implementations as there are networks (Expect Chaos, they said)
|
10152
|
+
// we rely on the config to provide all the info we need
|
10153
|
+
return tokens.map(tokenConfig => lodash.assign({
|
10154
|
+
id: chaindataProvider.subTokensTokenId(networkId, tokenConfig.onChainId),
|
10155
|
+
type: MODULE_TYPE,
|
10156
|
+
platform: PLATFORM,
|
10157
|
+
networkId,
|
10158
|
+
onChainId: tokenConfig.onChainId,
|
10159
|
+
symbol: tokenConfig.symbol ?? "Unit",
|
10160
|
+
decimals: tokenConfig.decimals ?? 0,
|
10161
|
+
name: tokenConfig.name ?? tokenConfig.symbol ?? "Unit",
|
10162
|
+
existentialDeposit: tokenConfig.existentialDeposit ?? "0",
|
10163
|
+
isDefault: true
|
10164
|
+
}, tokenConfig));
|
10165
|
+
};
|
10166
|
+
|
10167
|
+
const getMiniMetadata = ({
|
10168
|
+
networkId,
|
10169
|
+
specVersion,
|
10170
|
+
metadataRpc,
|
10171
|
+
config
|
10172
|
+
}) => {
|
10173
|
+
const source = MODULE_TYPE;
|
10174
|
+
const chainId = networkId;
|
10175
|
+
const systemVersion = getConstantValue(metadataRpc, "System", "Version");
|
10176
|
+
if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
|
10177
|
+
networkId,
|
10178
|
+
specVersion,
|
10179
|
+
systemVersion
|
10180
|
+
});
|
10181
|
+
const id = deriveMiniMetadataId({
|
10182
|
+
source,
|
10183
|
+
chainId,
|
10184
|
+
specVersion
|
10185
|
+
});
|
10186
|
+
const {
|
10187
|
+
unifiedMetadata
|
10188
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
10189
|
+
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
10190
|
+
const extra = {
|
10191
|
+
palletId: config?.palletId ?? "Tokens"
|
10192
|
+
};
|
10193
|
+
return {
|
10194
|
+
id,
|
10195
|
+
source,
|
10196
|
+
chainId,
|
10197
|
+
specVersion,
|
10198
|
+
version: chaindataProvider.MINIMETADATA_VERSION,
|
10199
|
+
data: getData(metadataRpc, extra.palletId),
|
10200
|
+
extra
|
10201
|
+
};
|
10202
|
+
};
|
10203
|
+
const getData = (metadataRpc, pallet) => {
|
10204
|
+
const {
|
10205
|
+
metadata,
|
10206
|
+
unifiedMetadata
|
10207
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
10208
|
+
|
10209
|
+
// ensure the network has all the required bits
|
10210
|
+
if (!hasStorageItems(unifiedMetadata, pallet, ["Accounts"])) return null;
|
10211
|
+
scale.compactMetadata(metadata, [{
|
10212
|
+
pallet,
|
10213
|
+
items: ["Accounts"]
|
10214
|
+
}]);
|
10215
|
+
return scale.encodeMetadata(metadata);
|
10216
|
+
};
|
10217
|
+
|
10218
|
+
const getTransferCallData = ({
|
10219
|
+
from,
|
10220
|
+
to,
|
10221
|
+
value,
|
10222
|
+
token,
|
10223
|
+
type,
|
10224
|
+
metadataRpc,
|
10225
|
+
config
|
10226
|
+
}) => {
|
10227
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE}.`);
|
10228
|
+
const {
|
10229
|
+
builder
|
10230
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
10231
|
+
|
10232
|
+
// each chain has its own way of encoding the transfer call data
|
10233
|
+
// let's try our luck until one works!
|
10234
|
+
const options = getCallDataOptions(to, token, value, type, config);
|
10235
|
+
const callData = getCallDataFromOptions(builder, options);
|
10236
|
+
return {
|
10237
|
+
address: from,
|
10238
|
+
method: callData.asHex()
|
10239
|
+
};
|
10240
|
+
};
|
10241
|
+
const getTransferMethod = type => {
|
10242
|
+
switch (type) {
|
10243
|
+
case "keep-alive":
|
10244
|
+
return "transfer_keep_alive";
|
10245
|
+
case "all":
|
10246
|
+
return "transfer_all";
|
10247
|
+
case "allow-death":
|
10248
|
+
return "transfer";
|
10249
|
+
}
|
10250
|
+
};
|
10251
|
+
const getCallDataFromOptions = (builder, options) => {
|
10252
|
+
for (const {
|
10253
|
+
pallet,
|
10254
|
+
method,
|
10255
|
+
getArgs
|
10256
|
+
} of options) {
|
10257
|
+
try {
|
10258
|
+
return buildCallData(builder, pallet, method, getArgs());
|
10259
|
+
} catch {
|
10260
|
+
// wrong inputs, ignore and try the next one
|
10261
|
+
}
|
10262
|
+
}
|
10263
|
+
throw new Error("Failed to encode call data");
|
10264
|
+
};
|
10265
|
+
const buildCallData = (builder, pallet, method, args) => {
|
10266
|
+
const {
|
10267
|
+
location,
|
10268
|
+
codec
|
10269
|
+
} = builder.buildCall(pallet, method);
|
10270
|
+
return polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), codec.enc(args)]));
|
10271
|
+
};
|
10272
|
+
const getCallDataOptions = (to, token, value, type, config) => {
|
10273
|
+
const onChainId = scale.papiParse(token.onChainId);
|
10274
|
+
const method = getTransferMethod(type);
|
10275
|
+
return [{
|
10276
|
+
pallet: "Currencies",
|
10277
|
+
method: "transfer",
|
10278
|
+
getArgs: () => ({
|
10279
|
+
dest: polkadotApi.Enum("Id", to),
|
10280
|
+
currency_id: onChainId,
|
10281
|
+
amount: BigInt(value)
|
10282
|
+
})
|
10283
|
+
}, {
|
10284
|
+
pallet: "Currencies",
|
10285
|
+
method: "transfer",
|
10286
|
+
getArgs: () => ({
|
10287
|
+
dest: to,
|
10288
|
+
currency_id: onChainId,
|
10289
|
+
amount: BigInt(value)
|
10290
|
+
})
|
10291
|
+
}, {
|
10292
|
+
pallet: "Tokens",
|
10293
|
+
method,
|
10294
|
+
getArgs: () => method === "transfer_all" ? {
|
10295
|
+
dest: polkadotApi.Enum("Id", to),
|
10296
|
+
currency_id: onChainId,
|
10297
|
+
keepAlive: false
|
10298
|
+
} : {
|
10299
|
+
dest: polkadotApi.Enum("Id", to),
|
10300
|
+
currency_id: onChainId,
|
10301
|
+
amount: BigInt(value)
|
10302
|
+
}
|
10303
|
+
}, {
|
10304
|
+
pallet: "Tokens",
|
10305
|
+
method,
|
10306
|
+
getArgs: () => method === "transfer_all" ? {
|
10307
|
+
dest: to,
|
10308
|
+
currency_id: onChainId,
|
10309
|
+
keepAlive: false
|
10310
|
+
} : {
|
10311
|
+
dest: to,
|
10312
|
+
currency_id: onChainId,
|
10313
|
+
amount: BigInt(value)
|
10314
|
+
}
|
10315
|
+
}].concat(...(config?.palletId ? [{
|
10316
|
+
pallet: config.palletId,
|
10317
|
+
method,
|
10318
|
+
getArgs: () => method === "transfer_all" ? {
|
10319
|
+
dest: polkadotApi.Enum("Id", to),
|
10320
|
+
currency_id: onChainId,
|
10321
|
+
keepAlive: false
|
10322
|
+
} : {
|
10323
|
+
dest: polkadotApi.Enum("Id", to),
|
10324
|
+
currency_id: onChainId,
|
10325
|
+
amount: BigInt(value)
|
10326
|
+
}
|
10327
|
+
}, {
|
10328
|
+
pallet: config.palletId,
|
10329
|
+
method,
|
10330
|
+
getArgs: () => method === "transfer_all" ? {
|
10331
|
+
dest: to,
|
10332
|
+
currency_id: onChainId,
|
10333
|
+
keepAlive: false
|
10334
|
+
} : {
|
10335
|
+
dest: to,
|
10336
|
+
currency_id: onChainId,
|
10337
|
+
amount: BigInt(value)
|
10338
|
+
}
|
10339
|
+
}] : []));
|
10340
|
+
};
|
10341
|
+
|
10342
|
+
const SUBSCRIPTION_INTERVAL = 6_000;
|
10343
|
+
const subscribeBalances = ({
|
10344
|
+
networkId,
|
10345
|
+
addressesByToken,
|
10346
|
+
connector,
|
10347
|
+
miniMetadata
|
10348
|
+
}) => {
|
10349
|
+
return new rxjs.Observable(subscriber => {
|
10350
|
+
const abortController = new AbortController();
|
10351
|
+
|
10352
|
+
// on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
|
10353
|
+
// => poll values for each block
|
10354
|
+
const poll = async () => {
|
10355
|
+
try {
|
10356
|
+
if (abortController.signal.aborted) return;
|
10357
|
+
const balances = await fetchBalances({
|
10358
|
+
networkId,
|
10359
|
+
addressesByToken,
|
10360
|
+
connector,
|
10361
|
+
miniMetadata
|
10362
|
+
});
|
10363
|
+
if (abortController.signal.aborted) return;
|
10364
|
+
subscriber.next(balances);
|
10365
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL);
|
10366
|
+
} catch (error) {
|
10367
|
+
log.error("Error", {
|
10368
|
+
module: MODULE_TYPE,
|
10369
|
+
networkId,
|
10370
|
+
miniMetadata,
|
10371
|
+
addressesByToken,
|
10372
|
+
error
|
10373
|
+
});
|
10374
|
+
subscriber.error(error);
|
10375
|
+
}
|
10376
|
+
};
|
10377
|
+
poll();
|
10378
|
+
return () => {
|
10379
|
+
abortController.abort();
|
10380
|
+
};
|
10381
|
+
}).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
|
10382
|
+
};
|
10383
|
+
|
10384
|
+
const SubTokensBalanceModule = {
|
10385
|
+
type: MODULE_TYPE,
|
10386
|
+
platform: PLATFORM,
|
10387
|
+
getMiniMetadata,
|
10388
|
+
fetchTokens,
|
10389
|
+
fetchBalances,
|
10390
|
+
subscribeBalances,
|
10391
|
+
getTransferCallData
|
10392
|
+
};
|
10393
|
+
|
10394
|
+
const NEW_BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule];
|
10395
|
+
|
10396
|
+
Object.defineProperty(exports, "MINIMETADATA_VERSION", {
|
10397
|
+
enumerable: true,
|
10398
|
+
get: function () { return chaindataProvider.MINIMETADATA_VERSION; }
|
10399
|
+
});
|
10400
|
+
Object.defineProperty(exports, "erc20Abi", {
|
10401
|
+
enumerable: true,
|
10402
|
+
get: function () { return viem.erc20Abi; }
|
10403
|
+
});
|
6834
10404
|
exports.Balance = Balance;
|
6835
10405
|
exports.BalanceFormatter = BalanceFormatter;
|
6836
10406
|
exports.BalanceValueGetter = BalanceValueGetter;
|
@@ -6844,12 +10414,13 @@ exports.EvmNativeTokenConfigSchema = EvmNativeTokenConfigSchema;
|
|
6844
10414
|
exports.EvmUniswapV2Module = EvmUniswapV2Module;
|
6845
10415
|
exports.EvmUniswapV2TokenConfigSchema = EvmUniswapV2TokenConfigSchema;
|
6846
10416
|
exports.FiatSumBalancesFormatter = FiatSumBalancesFormatter;
|
6847
|
-
exports.
|
10417
|
+
exports.NEW_BALANCE_MODULES = NEW_BALANCE_MODULES;
|
10418
|
+
exports.ONE_ALPHA_TOKEN = ONE_ALPHA_TOKEN$1;
|
6848
10419
|
exports.PlanckSumBalancesFormatter = PlanckSumBalancesFormatter;
|
6849
10420
|
exports.RpcStateQueryHelper = RpcStateQueryHelper;
|
6850
|
-
exports.SCALE_FACTOR = SCALE_FACTOR;
|
6851
|
-
exports.SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = SUBTENSOR_MIN_STAKE_AMOUNT_PLANK;
|
6852
|
-
exports.SUBTENSOR_ROOT_NETUID = SUBTENSOR_ROOT_NETUID;
|
10421
|
+
exports.SCALE_FACTOR = SCALE_FACTOR$1;
|
10422
|
+
exports.SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1;
|
10423
|
+
exports.SUBTENSOR_ROOT_NETUID = SUBTENSOR_ROOT_NETUID$1;
|
6853
10424
|
exports.SubAssetsModule = SubAssetsModule;
|
6854
10425
|
exports.SubAssetsTokenConfigSchema = SubAssetsTokenConfigSchema;
|
6855
10426
|
exports.SubForeignAssetsModule = SubForeignAssetsModule;
|
@@ -6866,9 +10437,9 @@ exports.abiMulticall = abiMulticall;
|
|
6866
10437
|
exports.balances = balances;
|
6867
10438
|
exports.buildNetworkStorageCoders = buildNetworkStorageCoders;
|
6868
10439
|
exports.buildStorageCoders = buildStorageCoders;
|
6869
|
-
exports.calculateAlphaPrice = calculateAlphaPrice;
|
6870
|
-
exports.calculateTaoAmountFromAlpha = calculateTaoAmountFromAlpha;
|
6871
|
-
exports.calculateTaoFromDynamicInfo = calculateTaoFromDynamicInfo;
|
10440
|
+
exports.calculateAlphaPrice = calculateAlphaPrice$1;
|
10441
|
+
exports.calculateTaoAmountFromAlpha = calculateTaoAmountFromAlpha$1;
|
10442
|
+
exports.calculateTaoFromDynamicInfo = calculateTaoFromDynamicInfo$1;
|
6872
10443
|
exports.compress = compress;
|
6873
10444
|
exports.configureStore = configureStore;
|
6874
10445
|
exports.db = db;
|
@@ -6877,7 +10448,6 @@ exports.decompress = decompress;
|
|
6877
10448
|
exports.defaultBalanceModules = defaultBalanceModules;
|
6878
10449
|
exports.deriveMiniMetadataId = deriveMiniMetadataId;
|
6879
10450
|
exports.detectTransferMethod = detectTransferMethod;
|
6880
|
-
exports.erc20Abi = erc20Abi;
|
6881
10451
|
exports.erc20BalancesAggregatorAbi = erc20BalancesAggregatorAbi;
|
6882
10452
|
exports.excludeFromFeePayableLocks = excludeFromFeePayableLocks;
|
6883
10453
|
exports.excludeFromTransferableAmount = excludeFromTransferableAmount;
|