@subwallet/extension-base 1.3.53-0 → 1.3.54-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/background/KoniTypes.d.ts +10 -3
- package/cjs/koni/background/handlers/Extension.js +4 -4
- package/cjs/koni/background/handlers/State.js +1 -0
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/transfer/xcm/snowBridge.js +21 -10
- package/cjs/services/chain-online-service/index.js +168 -15
- package/cjs/services/chain-service/index.js +39 -10
- package/cjs/services/chain-service/utils/patch.js +2 -2
- package/cjs/services/earning-service/constants/chains.js +2 -4
- package/cjs/services/earning-service/handlers/base.js +1 -1
- package/cjs/services/earning-service/handlers/native-staking/base.js +4 -2
- package/cjs/services/earning-service/handlers/native-staking/dtao.js +9 -3
- package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +1 -10
- package/cjs/services/earning-service/handlers/native-staking/tao.js +24 -14
- package/cjs/services/earning-service/service.js +2 -2
- package/cjs/services/migration-service/scripts/MigrateTransactionHistoryBySymbol.js +6 -2
- package/cjs/services/migration-service/scripts/databases/MigrateAssetSetting.js +6 -2
- package/cjs/services/migration-service/scripts/index.js +2 -2
- package/cjs/services/swap-service/index.js +24 -18
- package/cjs/services/transaction-service/utils.js +25 -16
- package/koni/background/handlers/Extension.d.ts +1 -1
- package/koni/background/handlers/Extension.js +4 -4
- package/koni/background/handlers/State.js +1 -0
- package/package.json +8 -6
- package/packageInfo.js +1 -1
- package/services/balance-service/transfer/xcm/snowBridge.js +21 -10
- package/services/chain-online-service/index.d.ts +4 -1
- package/services/chain-online-service/index.js +168 -15
- package/services/chain-service/index.js +39 -10
- package/services/chain-service/utils/patch.d.ts +1 -1
- package/services/chain-service/utils/patch.js +2 -2
- package/services/earning-service/constants/chains.d.ts +0 -1
- package/services/earning-service/constants/chains.js +1 -2
- package/services/earning-service/handlers/base.d.ts +3 -3
- package/services/earning-service/handlers/base.js +1 -1
- package/services/earning-service/handlers/native-staking/base.js +4 -2
- package/services/earning-service/handlers/native-staking/dtao.d.ts +4 -3
- package/services/earning-service/handlers/native-staking/dtao.js +9 -3
- package/services/earning-service/handlers/native-staking/relay-chain.d.ts +0 -2
- package/services/earning-service/handlers/native-staking/relay-chain.js +2 -11
- package/services/earning-service/handlers/native-staking/tao.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/tao.js +24 -14
- package/services/earning-service/service.d.ts +3 -3
- package/services/earning-service/service.js +2 -2
- package/services/migration-service/scripts/MigrateTransactionHistoryBySymbol.js +6 -2
- package/services/migration-service/scripts/databases/MigrateAssetSetting.js +6 -2
- package/services/migration-service/scripts/index.js +2 -2
- package/services/swap-service/index.js +24 -18
- package/services/transaction-service/utils.js +25 -16
- package/types/yield/actions/join/submit.d.ts +5 -0
- package/types/yield/actions/others.d.ts +7 -2
- package/types/yield/info/account/info.d.ts +1 -0
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { AssetLogoMap, ChainLogoMap } from '@subwallet/chain-list';
|
|
5
|
+
import { _ChainStatus } from '@subwallet/chain-list/types';
|
|
5
6
|
import { LATEST_CHAIN_PATCH_FETCHING_INTERVAL, md5HashChainAsset, md5HashChainInfo } from '@subwallet/extension-base/services/chain-online-service/constants';
|
|
6
7
|
import { filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service';
|
|
7
8
|
import { _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
|
|
8
|
-
import { fetchPatchData, randomizeProvider } from '@subwallet/extension-base/services/chain-service/utils';
|
|
9
|
+
import { _isCustomAsset, _isCustomChain, _isEqualSmartContractAsset, fetchPatchData, randomizeProvider } from '@subwallet/extension-base/services/chain-service/utils';
|
|
9
10
|
export class ChainOnlineService {
|
|
10
11
|
constructor(chainService, settingService, eventService, dbService) {
|
|
11
12
|
this.chainService = chainService;
|
|
@@ -14,6 +15,9 @@ export class ChainOnlineService {
|
|
|
14
15
|
this.dbService = dbService;
|
|
15
16
|
this.firstApplied = false;
|
|
16
17
|
}
|
|
18
|
+
resetFirstApplied() {
|
|
19
|
+
this.firstApplied = false;
|
|
20
|
+
}
|
|
17
21
|
validatePatchWithHash(latestPatch) {
|
|
18
22
|
const {
|
|
19
23
|
ChainAsset,
|
|
@@ -61,7 +65,7 @@ export class ChainOnlineService {
|
|
|
61
65
|
providers: _providers,
|
|
62
66
|
...info
|
|
63
67
|
} = _info;
|
|
64
|
-
const providers =
|
|
68
|
+
const providers = rs[slug] ? (_rs$slug = rs[slug]) === null || _rs$slug === void 0 ? void 0 : _rs$slug.providers : _providers;
|
|
65
69
|
rs[slug] = {
|
|
66
70
|
...info,
|
|
67
71
|
providers
|
|
@@ -69,6 +73,26 @@ export class ChainOnlineService {
|
|
|
69
73
|
}
|
|
70
74
|
return rs;
|
|
71
75
|
}
|
|
76
|
+
checkExistedPredefinedChain(latestChainInfoMap, genesisHash, evmChainId) {
|
|
77
|
+
let duplicatedSlug = '';
|
|
78
|
+
if (genesisHash) {
|
|
79
|
+
for (const chainInfo of Object.values(latestChainInfoMap)) {
|
|
80
|
+
if (chainInfo.substrateInfo && chainInfo.substrateInfo.genesisHash === genesisHash) {
|
|
81
|
+
duplicatedSlug = chainInfo.slug;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} else if (evmChainId) {
|
|
85
|
+
for (const chainInfo of Object.values(latestChainInfoMap)) {
|
|
86
|
+
if (chainInfo.evmInfo && chainInfo.evmInfo.evmChainId === evmChainId) {
|
|
87
|
+
duplicatedSlug = chainInfo.slug;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return duplicatedSlug;
|
|
92
|
+
}
|
|
93
|
+
generateSlugForSmartContractAsset(originChain, assetType, symbol, contractAddress) {
|
|
94
|
+
return `${originChain}-${assetType}-${symbol}-${contractAddress}`;
|
|
95
|
+
}
|
|
72
96
|
async handleLatestPatch(latestPatch) {
|
|
73
97
|
try {
|
|
74
98
|
var _await$this$settingSe;
|
|
@@ -88,31 +112,151 @@ export class ChainOnlineService {
|
|
|
88
112
|
let assetRegistry = structuredClone(this.chainService.getAssetRegistry());
|
|
89
113
|
const currentChainStateMap = structuredClone(this.chainService.getChainStateMap());
|
|
90
114
|
const currentChainStatusMap = structuredClone(this.chainService.getChainStatusMap());
|
|
115
|
+
const assetSetting = structuredClone(await this.chainService.getAssetSettings());
|
|
116
|
+
const migratedAssetSetting = {};
|
|
91
117
|
let addedChain = [];
|
|
118
|
+
const customChains = [];
|
|
119
|
+
const deprecatedChains = [];
|
|
120
|
+
const deprecatedChainMap = {};
|
|
121
|
+
const deprecatedAssets = [];
|
|
92
122
|
if (isSafePatch && (!this.firstApplied || currentPatchVersion !== latestPatchVersion)) {
|
|
93
123
|
this.firstApplied = true;
|
|
94
124
|
|
|
95
125
|
// 2. merge data map
|
|
96
126
|
if (latestChainInfo && Object.keys(latestChainInfo).length > 0) {
|
|
127
|
+
const storedChainSettings = await this.dbService.getAllChainStore();
|
|
128
|
+
const storedChainSettingMap = {};
|
|
129
|
+
storedChainSettings.forEach(chainStoredSetting => {
|
|
130
|
+
storedChainSettingMap[chainStoredSetting.slug] = chainStoredSetting;
|
|
131
|
+
});
|
|
132
|
+
if (storedChainSettings.length > 0) {
|
|
133
|
+
for (const [storedSlug, storedChainInfo] of Object.entries(storedChainSettingMap)) {
|
|
134
|
+
if (_isCustomChain(storedSlug)) {
|
|
135
|
+
var _storedChainInfo$subs, _storedChainInfo$evmI;
|
|
136
|
+
// Check if this custom chain duplicates any of the latest chainInfo from patch based on genesisHash (for Substrate) or EVM chain ID.
|
|
137
|
+
const duplicatedDefaultSlug = this.checkExistedPredefinedChain(latestChainInfo, (_storedChainInfo$subs = storedChainInfo.substrateInfo) === null || _storedChainInfo$subs === void 0 ? void 0 : _storedChainInfo$subs.genesisHash, (_storedChainInfo$evmI = storedChainInfo.evmInfo) === null || _storedChainInfo$evmI === void 0 ? void 0 : _storedChainInfo$evmI.evmChainId);
|
|
138
|
+
if (duplicatedDefaultSlug.length > 0) {
|
|
139
|
+
// Add the old custom chain slug to the list of deprecated chains.
|
|
140
|
+
deprecatedChainMap[storedSlug] = duplicatedDefaultSlug;
|
|
141
|
+
deprecatedChains.push(storedSlug);
|
|
142
|
+
const storedChainState = currentChainStateMap[storedSlug];
|
|
143
|
+
const storedChainStatus = currentChainStatusMap[storedSlug];
|
|
144
|
+
|
|
145
|
+
// Update the current chain state to use the new chain slug, inheriting the active/inactive status from custom chain and randomly assigning a provider
|
|
146
|
+
currentChainStateMap[duplicatedDefaultSlug] = {
|
|
147
|
+
slug: duplicatedDefaultSlug,
|
|
148
|
+
active: storedChainState.active,
|
|
149
|
+
currentProvider: randomizeProvider(latestChainInfo[duplicatedDefaultSlug].providers).providerKey,
|
|
150
|
+
manualTurnOff: storedChainState.manualTurnOff
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Update the current chain status to use the new chain slug, inheriting the connection status from custom chain and updating the last updated timestamp
|
|
154
|
+
currentChainStatusMap[duplicatedDefaultSlug] = {
|
|
155
|
+
slug: duplicatedDefaultSlug,
|
|
156
|
+
connectionStatus: storedChainStatus.connectionStatus,
|
|
157
|
+
lastUpdated: Date.now()
|
|
158
|
+
};
|
|
159
|
+
customChains.push(duplicatedDefaultSlug);
|
|
160
|
+
|
|
161
|
+
// Remove the deprecated custom chain's info from the old chain info map and the current state/status maps.
|
|
162
|
+
delete oldChainInfoMap[storedSlug];
|
|
163
|
+
delete currentChainStateMap[storedSlug];
|
|
164
|
+
delete currentChainStatusMap[storedSlug];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
97
169
|
chainInfoMap = this.mergeChainList(oldChainInfoMap, latestChainInfo);
|
|
98
170
|
const [currentChainStateKey, newChainKey] = [Object.keys(currentChainStateMap), Object.keys(chainInfoMap)];
|
|
99
|
-
addedChain = newChainKey.filter(chain => !currentChainStateKey.includes(chain));
|
|
171
|
+
addedChain = newChainKey.filter(chain => !currentChainStateKey.includes(chain) || customChains.includes(chain));
|
|
100
172
|
addedChain.forEach(key => {
|
|
101
|
-
currentChainStateMap[key]
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
173
|
+
if (!currentChainStateMap[key] && !currentChainStatusMap[key]) {
|
|
174
|
+
currentChainStateMap[key] = {
|
|
175
|
+
active: false,
|
|
176
|
+
currentProvider: randomizeProvider(chainInfoMap[key].providers).providerKey,
|
|
177
|
+
manualTurnOff: false,
|
|
178
|
+
slug: key
|
|
179
|
+
};
|
|
180
|
+
currentChainStatusMap[key] = {
|
|
181
|
+
slug: key,
|
|
182
|
+
connectionStatus: _ChainConnectionStatus.DISCONNECTED,
|
|
183
|
+
lastUpdated: Date.now()
|
|
184
|
+
};
|
|
185
|
+
}
|
|
112
186
|
});
|
|
113
187
|
}
|
|
114
188
|
if (latestAssetInfo && Object.keys(latestAssetInfo).length > 0) {
|
|
115
|
-
|
|
189
|
+
// Get all previously stored asset registry entries from the database.
|
|
190
|
+
const storedAssetRegistry = await this.dbService.getAllAssetStore();
|
|
191
|
+
const availableChains = Object.values(chainInfoMap).filter(info => info.chainStatus === _ChainStatus.ACTIVE).map(chainInfo => chainInfo.slug);
|
|
192
|
+
let finalAssetRegistry;
|
|
193
|
+
if (storedAssetRegistry.length === 0) {
|
|
194
|
+
finalAssetRegistry = oldAssetRegistry;
|
|
195
|
+
} else {
|
|
196
|
+
const mergedAssetRegistry = oldAssetRegistry;
|
|
197
|
+
const parsedStoredAssetRegistry = {};
|
|
198
|
+
|
|
199
|
+
// Update custom assets of merged custom chains
|
|
200
|
+
for (const storedAsset of Object.values(storedAssetRegistry)) {
|
|
201
|
+
var _storedAsset$metadata;
|
|
202
|
+
// If the stored asset is a custom asset and its origin chain is marked as deprecated, and its assetType is ERC20
|
|
203
|
+
if (_isCustomAsset(storedAsset.slug) && Object.keys(deprecatedChainMap).includes(storedAsset.originChain) && (_storedAsset$metadata = storedAsset.metadata) !== null && _storedAsset$metadata !== void 0 && _storedAsset$metadata.contractAddress) {
|
|
204
|
+
const newOriginChain = deprecatedChainMap[storedAsset.originChain];
|
|
205
|
+
// const newSlug = this.generateSlugForSmartContractAsset(newOriginChain, storedAsset.assetType, storedAsset.symbol, storedAsset.metadata?.contractAddress);
|
|
206
|
+
|
|
207
|
+
// Mark the old custom asset slug as deprecated.
|
|
208
|
+
deprecatedAssets.push(storedAsset.slug);
|
|
209
|
+
parsedStoredAssetRegistry[storedAsset.slug] = {
|
|
210
|
+
...storedAsset,
|
|
211
|
+
originChain: newOriginChain
|
|
212
|
+
};
|
|
213
|
+
} else {
|
|
214
|
+
parsedStoredAssetRegistry[storedAsset.slug] = storedAsset;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
for (const storedAssetInfo of Object.values(parsedStoredAssetRegistry)) {
|
|
218
|
+
let duplicated = false;
|
|
219
|
+
let deprecated = false;
|
|
220
|
+
let defaultSlugForMigration;
|
|
221
|
+
for (const defaultChainAsset of Object.values(latestAssetInfo)) {
|
|
222
|
+
// case: the stored asset is the same to a smart contract asset from patch
|
|
223
|
+
if (_isEqualSmartContractAsset(storedAssetInfo, defaultChainAsset)) {
|
|
224
|
+
duplicated = true;
|
|
225
|
+
defaultSlugForMigration = defaultChainAsset.slug;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// case: the origin chain of the stored asset is no longer active (Exp: custom chain is deprecated)
|
|
230
|
+
if (availableChains.indexOf(storedAssetInfo.originChain) === -1) {
|
|
231
|
+
deprecated = true;
|
|
232
|
+
defaultSlugForMigration = defaultChainAsset.slug;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// If the stored asset is a duplicate of a default asset or its origin chain is deprecated.
|
|
238
|
+
if (duplicated || deprecated) {
|
|
239
|
+
if (Object.keys(assetSetting).includes(storedAssetInfo.slug)) {
|
|
240
|
+
const isVisible = assetSetting[storedAssetInfo.slug].visible;
|
|
241
|
+
|
|
242
|
+
// Migrate assetSetting from custom token to token from patch
|
|
243
|
+
if (defaultSlugForMigration) {
|
|
244
|
+
migratedAssetSetting[defaultSlugForMigration] = {
|
|
245
|
+
visible: isVisible
|
|
246
|
+
};
|
|
247
|
+
delete assetSetting[storedAssetInfo.slug];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
delete mergedAssetRegistry[storedAssetInfo.slug];
|
|
251
|
+
deprecatedAssets.push(storedAssetInfo.slug);
|
|
252
|
+
} else {
|
|
253
|
+
// If the stored asset is not a duplicate and its origin chain is active, keep it in the merged registry.
|
|
254
|
+
mergedAssetRegistry[storedAssetInfo.slug] = storedAssetInfo;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
finalAssetRegistry = mergedAssetRegistry;
|
|
258
|
+
}
|
|
259
|
+
assetRegistry = filterAssetInfoMap(oldChainInfoMap, Object.assign({}, finalAssetRegistry, latestAssetInfo), addedChain);
|
|
116
260
|
}
|
|
117
261
|
|
|
118
262
|
// 3. validate data before write
|
|
@@ -130,6 +274,15 @@ export class ChainOnlineService {
|
|
|
130
274
|
this.chainService.setChainStateMap(currentChainStateMap);
|
|
131
275
|
this.chainService.subscribeChainStateMap().next(currentChainStateMap);
|
|
132
276
|
this.chainService.subscribeChainStatusMap().next(currentChainStatusMap);
|
|
277
|
+
// Migrate assetSetting
|
|
278
|
+
this.chainService.setAssetSettings({
|
|
279
|
+
...assetSetting,
|
|
280
|
+
...migratedAssetSetting
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Remove all custom chains and custom tokens that is duplicated from chains or tokens in patch
|
|
284
|
+
await this.dbService.removeFromChainStore(deprecatedChains);
|
|
285
|
+
await this.dbService.removeFromAssetStore(deprecatedAssets);
|
|
133
286
|
const storedChainInfoList = Object.keys(chainInfoMap).map(chainSlug => {
|
|
134
287
|
return {
|
|
135
288
|
...chainInfoMap[chainSlug],
|
|
@@ -1229,8 +1229,11 @@ export class ChainService {
|
|
|
1229
1229
|
async initAssetRegistry(deprecatedCustomChainMap) {
|
|
1230
1230
|
const storedAssetRegistry = await this.dbService.getAllAssetStore();
|
|
1231
1231
|
const latestAssetRegistry = filterAssetInfoMap(this.getChainInfoMap(), ChainAssetMap);
|
|
1232
|
+
const assetSetting = await this.getAssetSettings();
|
|
1232
1233
|
const availableChains = Object.values(this.dataMap.chainInfoMap).filter(info => info.chainStatus === _ChainStatus.ACTIVE).map(chainInfo => chainInfo.slug);
|
|
1234
|
+
const customChains = Object.keys(deprecatedCustomChainMap).filter(chain => _isCustomChain(chain));
|
|
1233
1235
|
let finalAssetRegistry = {};
|
|
1236
|
+
const migratedAssetSetting = {};
|
|
1234
1237
|
if (storedAssetRegistry.length === 0) {
|
|
1235
1238
|
finalAssetRegistry = latestAssetRegistry;
|
|
1236
1239
|
} else {
|
|
@@ -1240,15 +1243,18 @@ export class ChainService {
|
|
|
1240
1243
|
|
|
1241
1244
|
// Update custom assets of merged custom chains
|
|
1242
1245
|
Object.values(storedAssetRegistry).forEach(storedAsset => {
|
|
1243
|
-
|
|
1244
|
-
|
|
1246
|
+
var _storedAsset$metadata;
|
|
1247
|
+
const isFromCustomChain = customChains ? customChains.includes(storedAsset.originChain) : false;
|
|
1248
|
+
|
|
1249
|
+
// If the stored asset is a custom asset, from a deprecated custom chain, and has a contract address.
|
|
1250
|
+
if (_isCustomAsset(storedAsset.slug) && isFromCustomChain && (_storedAsset$metadata = storedAsset.metadata) !== null && _storedAsset$metadata !== void 0 && _storedAsset$metadata.contractAddress) {
|
|
1245
1251
|
const newOriginChain = deprecatedCustomChainMap[storedAsset.originChain];
|
|
1246
|
-
const newSlug = this.generateSlugForSmartContractAsset(newOriginChain, storedAsset.assetType, storedAsset.symbol,
|
|
1252
|
+
// const newSlug = this.generateSlugForSmartContractAsset(newOriginChain, storedAsset.assetType, storedAsset.symbol, storedAsset.metadata?.contractAddress);
|
|
1253
|
+
|
|
1247
1254
|
deprecatedAssets.push(storedAsset.slug);
|
|
1248
|
-
parsedStoredAssetRegistry[
|
|
1255
|
+
parsedStoredAssetRegistry[storedAsset.slug] = {
|
|
1249
1256
|
...storedAsset,
|
|
1250
|
-
originChain: newOriginChain
|
|
1251
|
-
slug: newSlug
|
|
1257
|
+
originChain: newOriginChain
|
|
1252
1258
|
};
|
|
1253
1259
|
} else {
|
|
1254
1260
|
parsedStoredAssetRegistry[storedAsset.slug] = storedAsset;
|
|
@@ -1257,25 +1263,48 @@ export class ChainService {
|
|
|
1257
1263
|
for (const storedAssetInfo of Object.values(parsedStoredAssetRegistry)) {
|
|
1258
1264
|
let duplicated = false;
|
|
1259
1265
|
let deprecated = false;
|
|
1266
|
+
let defaultSlugForMigration;
|
|
1260
1267
|
for (const defaultChainAsset of Object.values(latestAssetRegistry)) {
|
|
1261
|
-
//
|
|
1268
|
+
// Case: The stored asset is the same to a smart contract asset from new stable chainlist
|
|
1262
1269
|
if (_isEqualSmartContractAsset(storedAssetInfo, defaultChainAsset)) {
|
|
1263
1270
|
duplicated = true;
|
|
1271
|
+
defaultSlugForMigration = defaultChainAsset.slug;
|
|
1264
1272
|
break;
|
|
1265
1273
|
}
|
|
1274
|
+
|
|
1275
|
+
// Case: If the origin chain of the stored asset is no longer active. (custom chain is deprecated)
|
|
1266
1276
|
if (availableChains.indexOf(storedAssetInfo.originChain) === -1) {
|
|
1267
1277
|
deprecated = true;
|
|
1278
|
+
defaultSlugForMigration = defaultChainAsset.slug;
|
|
1268
1279
|
break;
|
|
1269
1280
|
}
|
|
1281
|
+
|
|
1282
|
+
// Case: If a default asset already exists with the same slug as the stored asset (from patch)
|
|
1270
1283
|
if (defaultChainAsset.slug === storedAssetInfo.slug) {
|
|
1271
1284
|
duplicated = true;
|
|
1285
|
+
defaultSlugForMigration = defaultChainAsset.slug;
|
|
1272
1286
|
break;
|
|
1273
1287
|
}
|
|
1274
1288
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1289
|
+
|
|
1290
|
+
// If the stored asset is a duplicate of a default asset or its origin chain is deprecated.
|
|
1291
|
+
if (duplicated || deprecated) {
|
|
1292
|
+
if (Object.keys(assetSetting).includes(storedAssetInfo.slug)) {
|
|
1293
|
+
const isVisible = assetSetting[storedAssetInfo.slug].visible;
|
|
1294
|
+
|
|
1295
|
+
// Migrate assetSetting from custom token to new default token
|
|
1296
|
+
if (defaultSlugForMigration) {
|
|
1297
|
+
migratedAssetSetting[defaultSlugForMigration] = {
|
|
1298
|
+
visible: isVisible
|
|
1299
|
+
};
|
|
1300
|
+
delete assetSetting[storedAssetInfo.slug];
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
delete mergedAssetRegistry[storedAssetInfo.slug];
|
|
1278
1304
|
deprecatedAssets.push(storedAssetInfo.slug);
|
|
1305
|
+
} else {
|
|
1306
|
+
// If the stored asset is not a duplicate and its origin chain is active, keep it in the merged registry.
|
|
1307
|
+
mergedAssetRegistry[storedAssetInfo.slug] = storedAssetInfo;
|
|
1279
1308
|
}
|
|
1280
1309
|
}
|
|
1281
1310
|
finalAssetRegistry = mergedAssetRegistry;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types';
|
|
2
|
-
export declare const ChainListVersion = "0.2.
|
|
2
|
+
export declare const ChainListVersion = "0.2.112";
|
|
3
3
|
export interface PatchInfo {
|
|
4
4
|
patchVersion: string;
|
|
5
5
|
appliedVersion: string;
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
const PRODUCTION_BRANCHES = ['master', 'webapp', 'webapp-dev'];
|
|
5
5
|
const branchName = process.env.BRANCH_NAME || 'subwallet-dev';
|
|
6
|
-
const fetchDomain = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'https://chain-list-assets.subwallet.app' : 'https://dev.sw-chain-list-assets.pages.dev';
|
|
6
|
+
const fetchDomain = process.env.PATCH_CHAIN_LIST_URL || (PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'https://chain-list-assets.subwallet.app' : 'https://dev.sw-chain-list-assets.pages.dev');
|
|
7
7
|
const fetchFile = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'list.json' : 'preview.json';
|
|
8
|
-
export const ChainListVersion = '0.2.
|
|
8
|
+
export const ChainListVersion = '0.2.112'; // update this when build chain-list
|
|
9
9
|
|
|
10
10
|
// todo: move this interface to chainlist
|
|
11
11
|
|
|
@@ -23,4 +23,3 @@ export declare const MANTA_VALIDATOR_POINTS_PER_BLOCK = 20;
|
|
|
23
23
|
export declare const MANTA_MIN_DELEGATION = 500;
|
|
24
24
|
export declare const CHANNEL_ID = 7;
|
|
25
25
|
export declare const STAKING_IDENTITY_API_SLUG: Record<string, string>;
|
|
26
|
-
export declare const _SUPPORT_CHANGE_VALIDATOR_CHAIN: string[];
|
|
@@ -3,8 +3,8 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr
|
|
|
3
3
|
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
4
4
|
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
5
5
|
import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
6
|
-
import { BasePoolInfo, BaseYieldPoolMetadata, EarningRewardHistoryItem, EarningRewardItem, HandleYieldStepData, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield,
|
|
7
|
-
import {
|
|
6
|
+
import { BasePoolInfo, BaseYieldPoolMetadata, EarningRewardHistoryItem, EarningRewardItem, HandleYieldStepData, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestEarningImpact, ResponseEarlyValidateYield, StakeCancelWithdrawalParams, SubmitChangeValidatorStaking, SubmitYieldJoinData, TransactionData, UnstakingInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPoolTarget, YieldPoolType, YieldPositionInfo, YieldStepBaseInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types';
|
|
7
|
+
import { EarningImpactResult } from './native-staking/dtao';
|
|
8
8
|
/**
|
|
9
9
|
* @class BasePoolHandler
|
|
10
10
|
* @description Base pool handler
|
|
@@ -120,5 +120,5 @@ export default abstract class BasePoolHandler {
|
|
|
120
120
|
abstract handleChangeEarningValidator(data: SubmitChangeValidatorStaking): Promise<TransactionData>;
|
|
121
121
|
/** Check handler can handle slug */
|
|
122
122
|
canHandleSlug(slug: string): boolean;
|
|
123
|
-
|
|
123
|
+
getEarningImpact(params: RequestEarningImpact): Promise<EarningImpactResult>;
|
|
124
124
|
}
|
|
@@ -131,7 +131,8 @@ export default class BaseNativeStakingPoolHandler extends BasePoolHandler {
|
|
|
131
131
|
address,
|
|
132
132
|
amount,
|
|
133
133
|
selectedValidators,
|
|
134
|
-
slug
|
|
134
|
+
slug,
|
|
135
|
+
subnetData
|
|
135
136
|
} = data;
|
|
136
137
|
const positionInfo = await this.getPoolPosition(address, slug);
|
|
137
138
|
const [extrinsic] = await this.createJoinExtrinsic(data, positionInfo);
|
|
@@ -140,7 +141,8 @@ export default class BaseNativeStakingPoolHandler extends BasePoolHandler {
|
|
|
140
141
|
slug: this.slug,
|
|
141
142
|
amount,
|
|
142
143
|
address,
|
|
143
|
-
selectedValidators
|
|
144
|
+
selectedValidators,
|
|
145
|
+
subnetData
|
|
144
146
|
};
|
|
145
147
|
return {
|
|
146
148
|
txChain: this.chain,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
2
|
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
3
|
-
import { BaseYieldPositionInfo,
|
|
3
|
+
import { BaseYieldPositionInfo, RequestEarningImpact, YieldPoolInfo, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types';
|
|
4
4
|
import TaoNativeStakingPoolHandler, { TaoStakingStakeOption } from './tao';
|
|
5
5
|
export interface SubnetData {
|
|
6
6
|
netuid: number;
|
|
@@ -20,9 +20,10 @@ export interface RawDelegateState {
|
|
|
20
20
|
stake: string;
|
|
21
21
|
}>;
|
|
22
22
|
}
|
|
23
|
-
export interface
|
|
23
|
+
export interface EarningImpactResult {
|
|
24
24
|
slippage: number;
|
|
25
25
|
rate: number;
|
|
26
|
+
stakingTaoFee?: string;
|
|
26
27
|
}
|
|
27
28
|
export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHandler {
|
|
28
29
|
readonly type = YieldPoolType.SUBNET_STAKING;
|
|
@@ -33,7 +34,7 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan
|
|
|
33
34
|
private isInit;
|
|
34
35
|
constructor(state: KoniState, chain: string);
|
|
35
36
|
canHandleSlug(slug: string): boolean;
|
|
36
|
-
|
|
37
|
+
getEarningImpact(params: RequestEarningImpact): Promise<EarningImpactResult>;
|
|
37
38
|
private init;
|
|
38
39
|
protected getDescription(): string;
|
|
39
40
|
subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
|
|
@@ -41,7 +41,7 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan
|
|
|
41
41
|
canHandleSlug(slug) {
|
|
42
42
|
return slug.startsWith(`${this.slug}__`);
|
|
43
43
|
}
|
|
44
|
-
async
|
|
44
|
+
async getEarningImpact(params) {
|
|
45
45
|
const substrateApi = await this.substrateApi.isReady;
|
|
46
46
|
const subnetInfo = (await substrateApi.api.call.subnetInfoRuntimeApi.getDynamicInfo(params.netuid)).toJSON();
|
|
47
47
|
const alphaIn = new BigN((subnetInfo === null || subnetInfo === void 0 ? void 0 : subnetInfo.alphaIn) || 0);
|
|
@@ -49,15 +49,18 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan
|
|
|
49
49
|
const k = alphaIn.multipliedBy(taoIn);
|
|
50
50
|
const value = new BigN(params.value);
|
|
51
51
|
const rate = taoIn.dividedBy(alphaIn);
|
|
52
|
+
const feeRate = await this.bittensorCache.fetchSubnetFeeRate(params.netuid);
|
|
52
53
|
if (params.type === ExtrinsicType.STAKING_BOND) {
|
|
53
54
|
const newTaoIn = taoIn.plus(value);
|
|
54
55
|
const newAlphaIn = k.dividedBy(newTaoIn);
|
|
55
56
|
const alphaReturned = alphaIn.minus(newAlphaIn);
|
|
56
57
|
const alphaIdeal = value.multipliedBy(alphaIn).dividedBy(taoIn);
|
|
57
58
|
const slippage = alphaIdeal.minus(alphaReturned).dividedBy(alphaIdeal);
|
|
59
|
+
const bnStakingTaoFee = value.multipliedBy(feeRate);
|
|
58
60
|
return {
|
|
59
61
|
slippage: slippage.plus(0.0001).toNumber(),
|
|
60
|
-
rate: rate.toNumber()
|
|
62
|
+
rate: rate.toNumber(),
|
|
63
|
+
stakingTaoFee: bnStakingTaoFee.toString()
|
|
61
64
|
};
|
|
62
65
|
} else if (params.type === ExtrinsicType.STAKING_UNBOND) {
|
|
63
66
|
const newAlphaIn = alphaIn.plus(value);
|
|
@@ -65,9 +68,12 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan
|
|
|
65
68
|
const taoReturned = taoIn.minus(newTaoReserve);
|
|
66
69
|
const taoIdeal = value.multipliedBy(taoIn).dividedBy(alphaIn);
|
|
67
70
|
const slippage = taoIdeal.minus(taoReturned).dividedBy(taoIdeal);
|
|
71
|
+
const taoAmount = value.multipliedBy(rate);
|
|
72
|
+
const bnStakingTaoFee = taoAmount.multipliedBy(feeRate);
|
|
68
73
|
return {
|
|
69
74
|
slippage: slippage.plus(0.0001).toNumber(),
|
|
70
|
-
rate: rate.toNumber()
|
|
75
|
+
rate: rate.toNumber(),
|
|
76
|
+
stakingTaoFee: bnStakingTaoFee.toString()
|
|
71
77
|
};
|
|
72
78
|
}
|
|
73
79
|
return {
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
3
3
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
4
4
|
import { ExtrinsicType, NominationInfo, UnstakingInfo } from '@subwallet/extension-base/background/KoniTypes';
|
|
5
|
-
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
6
5
|
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
7
6
|
import { BaseYieldPositionInfo, OptimalYieldPath, PalletStakingNominations, PalletStakingStakingLedger, StakeCancelWithdrawalParams, SubmitChangeValidatorStaking, SubmitJoinNativeStaking, SubmitYieldJoinData, TransactionData, ValidatorInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types';
|
|
8
7
|
import { BN } from '@polkadot/util';
|
|
9
8
|
import BaseNativeStakingPoolHandler from './base';
|
|
10
9
|
export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPoolHandler {
|
|
11
10
|
availableMethod: YieldPoolMethodInfo;
|
|
12
|
-
constructor(state: KoniState, chain: string);
|
|
13
11
|
subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
|
|
14
12
|
parseNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, ledger: PalletStakingStakingLedger, currentEra: string, minStake: BN): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
|
|
15
13
|
handleNominationsList(substrateApi: _SubstrateApi, chain: string, nominations: PalletStakingNominations, currentEra: string, address: string, maxNominatorRewardedPerValidator: number | undefined): Promise<NominationInfo[]>;
|
|
@@ -6,7 +6,7 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
|
6
6
|
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturnV2, calculateInflation, calculateTernoaValidatorReturn, calculateValidatorStakedReturn, getAvgValidatorEraReward, getCommission, getMaxValidatorErrorMessage, getMinStakeErrorMessage, getRelayBlockedValidatorList, getRelayEraRewardMap, getRelayMaxNominations, getRelayTopValidatorByPoints, getRelayValidatorPointsMap, getRelayWaitingValidatorList, getSupportedDaysByHistoryDepth } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
7
7
|
import { _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
8
8
|
import { _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils';
|
|
9
|
-
import { _STAKING_CHAIN_GROUP,
|
|
9
|
+
import { _STAKING_CHAIN_GROUP, MaxEraRewardPointsEras } from '@subwallet/extension-base/services/earning-service/constants';
|
|
10
10
|
import { applyDecimal, parseIdentity } from '@subwallet/extension-base/services/earning-service/utils';
|
|
11
11
|
import { BasicTxErrorType, EarningStatus, StakingTxErrorType, UnstakingStatus } from '@subwallet/extension-base/types';
|
|
12
12
|
import { balanceFormatter, formatNumber, reformatAddress } from '@subwallet/extension-base/utils';
|
|
@@ -22,17 +22,8 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
|
|
|
22
22
|
cancelUnstake: true,
|
|
23
23
|
withdraw: true,
|
|
24
24
|
claimReward: false,
|
|
25
|
-
changeValidator:
|
|
25
|
+
changeValidator: true
|
|
26
26
|
};
|
|
27
|
-
constructor(state, chain) {
|
|
28
|
-
super(state, chain);
|
|
29
|
-
if (_SUPPORT_CHANGE_VALIDATOR_CHAIN.includes(chain)) {
|
|
30
|
-
this.availableMethod = {
|
|
31
|
-
...this.availableMethod,
|
|
32
|
-
changeValidator: true
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
27
|
/* Subscribe pool info */
|
|
37
28
|
|
|
38
29
|
async subscribePoolInfo(callback) {
|
|
@@ -80,6 +80,7 @@ export declare class BittensorCache {
|
|
|
80
80
|
get(): Promise<ValidatorResponse>;
|
|
81
81
|
private fetchData;
|
|
82
82
|
fetchApr(netuid: number): Promise<ValidatorAprResponse>;
|
|
83
|
+
fetchSubnetFeeRate(netuid: number): Promise<string>;
|
|
83
84
|
}
|
|
84
85
|
export declare const getAlphaToTaoRate: (substrateApi: _SubstrateApi, netuid: number) => Promise<string>;
|
|
85
86
|
export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHandler {
|
|
@@ -10,6 +10,7 @@ import BaseParaStakingPoolHandler from '@subwallet/extension-base/services/earni
|
|
|
10
10
|
import { BasicTxErrorType, EarningStatus, StakingTxErrorType, YieldPoolType } from '@subwallet/extension-base/types';
|
|
11
11
|
import { ProxyServiceRoute } from '@subwallet/extension-base/types/environment';
|
|
12
12
|
import { fetchFromProxyService, formatNumber, reformatAddress } from '@subwallet/extension-base/utils';
|
|
13
|
+
import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache';
|
|
13
14
|
import BigN from 'bignumber.js';
|
|
14
15
|
import { t } from 'i18next';
|
|
15
16
|
import { BehaviorSubject, combineLatest } from 'rxjs';
|
|
@@ -44,21 +45,12 @@ export class BittensorCache {
|
|
|
44
45
|
}
|
|
45
46
|
async fetchData() {
|
|
46
47
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
headers: {
|
|
50
|
-
'Content-Type': 'application/json'
|
|
51
|
-
}
|
|
48
|
+
const fetchData = await fetchStaticCache('earning/dtao/validator.json', {
|
|
49
|
+
data: {}
|
|
52
50
|
});
|
|
53
|
-
|
|
54
|
-
console.error('Fetch bittensor delegates fail:', resp.status);
|
|
55
|
-
return this.cache || {
|
|
56
|
-
data: []
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const rawData = await resp.json();
|
|
51
|
+
const validators = Object.values(fetchData.data);
|
|
60
52
|
const data = {
|
|
61
|
-
data:
|
|
53
|
+
data: validators.filter(validator => parseFloat(validator.root_stake) > 0)
|
|
62
54
|
};
|
|
63
55
|
this.cache = data;
|
|
64
56
|
this.promise = null;
|
|
@@ -71,7 +63,8 @@ export class BittensorCache {
|
|
|
71
63
|
this.cache = newData;
|
|
72
64
|
}
|
|
73
65
|
}).catch(console.error);
|
|
74
|
-
}, 60 *
|
|
66
|
+
}, 60 * 1000); // Cache 1 minute
|
|
67
|
+
|
|
75
68
|
return data;
|
|
76
69
|
} catch (error) {
|
|
77
70
|
console.error(error);
|
|
@@ -102,6 +95,23 @@ export class BittensorCache {
|
|
|
102
95
|
};
|
|
103
96
|
}
|
|
104
97
|
}
|
|
98
|
+
async fetchSubnetFeeRate(netuid) {
|
|
99
|
+
try {
|
|
100
|
+
var _subnet$fee_rate;
|
|
101
|
+
const resp = await fetchFromProxyService(ProxyServiceRoute.BITTENSOR, '/subnet/latest/v1', {
|
|
102
|
+
method: 'GET',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json'
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
const rawData = await resp.json();
|
|
108
|
+
const subnet = rawData.data.find(item => item.netuid === netuid);
|
|
109
|
+
return (_subnet$fee_rate = subnet === null || subnet === void 0 ? void 0 : subnet.fee_rate) !== null && _subnet$fee_rate !== void 0 ? _subnet$fee_rate : '0.0005';
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error(error);
|
|
112
|
+
return '0.0005'; // Default fee rate if fetch fails
|
|
113
|
+
}
|
|
114
|
+
}
|
|
105
115
|
}
|
|
106
116
|
|
|
107
117
|
// export async function fetchTaoDelegateState (address: string): Promise<RawDelegateState> {
|
|
@@ -3,10 +3,10 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr
|
|
|
3
3
|
import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
4
4
|
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
5
5
|
import { PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
|
|
6
|
-
import { EarningRewardHistoryItem, EarningRewardItem, EarningRewardJson, HandleYieldStepData, HandleYieldStepParams, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield,
|
|
6
|
+
import { EarningRewardHistoryItem, EarningRewardItem, EarningRewardJson, HandleYieldStepData, HandleYieldStepParams, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestEarningImpact, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestYieldLeave, RequestYieldWithdrawal, ResponseEarlyValidateYield, SubmitChangeValidatorStaking, TransactionData, ValidateYieldProcessParams, YieldPoolInfo, YieldPoolTarget, YieldPositionInfo } from '@subwallet/extension-base/types';
|
|
7
7
|
import { PromiseHandler } from '@subwallet/extension-base/utils';
|
|
8
8
|
import { BehaviorSubject } from 'rxjs';
|
|
9
|
-
import {
|
|
9
|
+
import { EarningImpactResult } from './handlers/native-staking/dtao';
|
|
10
10
|
import { BasePoolHandler } from './handlers';
|
|
11
11
|
export declare const fetchPoolsData: () => Promise<Record<string, YieldPoolInfo>>;
|
|
12
12
|
export default class EarningService implements StoppableServiceInterface, PersistDataServiceInterface {
|
|
@@ -107,7 +107,7 @@ export default class EarningService implements StoppableServiceInterface, Persis
|
|
|
107
107
|
handleYieldWithdraw(params: RequestYieldWithdrawal): Promise<TransactionData>;
|
|
108
108
|
handleYieldCancelUnstake(params: RequestStakeCancelWithdrawal): Promise<TransactionData>;
|
|
109
109
|
handleYieldClaimReward(params: RequestStakeClaimReward): Promise<TransactionData>;
|
|
110
|
-
|
|
110
|
+
yieldGetEarningImpact(params: RequestEarningImpact): Promise<EarningImpactResult>;
|
|
111
111
|
handleYieldChangeValidator(params: SubmitChangeValidatorStaking): Promise<TransactionData>;
|
|
112
112
|
resetWallet(): Promise<void>;
|
|
113
113
|
}
|