@subwallet/extension-base 1.2.13-0 → 1.2.15-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/errors/SwapError.js +5 -1
- package/cjs/background/errors/SwapError.js +5 -1
- package/cjs/core/logic-validation/swap.js +56 -3
- package/cjs/core/substrate/nominationpools-pallet.js +2 -1
- package/cjs/koni/api/nft/config.js +37 -23
- package/cjs/koni/api/nft/index.js +9 -1
- package/cjs/koni/api/nft/unique_network_nft/index.js +12 -20
- package/cjs/koni/background/handlers/Extension.js +12 -0
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/transfer/xcm/utils.js +2 -2
- package/cjs/services/chain-service/constants.js +2 -1
- package/cjs/services/chain-service/handler/SubstrateApi.js +6 -0
- package/cjs/services/chain-service/health-check/constants/index.js +4 -4
- package/cjs/services/chain-service/health-check/utils/asset-info.js +23 -6
- package/cjs/services/chain-service/health-check/utils/chain-info.js +25 -2
- package/cjs/services/chain-service/health-check/utils/new-utils/asset-asset-validate.js +160 -0
- package/cjs/services/chain-service/health-check/utils/new-utils/asset-validate.js +45 -0
- package/cjs/services/chain-service/health-check/utils/new-utils/chain-asset-validate.js +73 -0
- package/cjs/services/chain-service/health-check/utils/new-utils/chain-validate.js +34 -0
- package/cjs/services/chain-service/index.js +47 -5
- package/cjs/services/earning-service/handlers/liquid-staking/acala.js +49 -19
- package/cjs/services/migration-service/scripts/databases/ReloadMetadata.js +35 -0
- package/cjs/services/migration-service/scripts/index.js +4 -2
- package/cjs/services/price-service/coingecko.js +57 -32
- package/cjs/services/price-service/index.js +30 -11
- package/cjs/services/storage-service/db-stores/BaseStore.js +4 -0
- package/cjs/services/swap-service/handler/asset-hub/handler.js +343 -0
- package/cjs/services/swap-service/handler/asset-hub/index.js +12 -0
- package/cjs/services/swap-service/handler/asset-hub/router.js +93 -0
- package/cjs/services/swap-service/handler/asset-hub/utils.js +158 -0
- package/cjs/services/swap-service/index.js +10 -1
- package/cjs/services/swap-service/utils.js +10 -1
- package/cjs/types/swap/index.js +5 -1
- package/core/logic-validation/swap.d.ts +3 -1
- package/core/logic-validation/swap.js +55 -4
- package/core/substrate/nominationpools-pallet.js +2 -1
- package/koni/api/nft/config.d.ts +1 -0
- package/koni/api/nft/config.js +31 -19
- package/koni/api/nft/index.js +9 -1
- package/koni/api/nft/unique_network_nft/index.js +12 -20
- package/koni/background/handlers/Extension.js +12 -0
- package/package.json +56 -11
- package/packageInfo.js +1 -1
- package/services/balance-service/transfer/xcm/utils.js +2 -2
- package/services/chain-service/constants.d.ts +1 -0
- package/services/chain-service/constants.js +2 -1
- package/services/chain-service/handler/SubstrateApi.js +6 -0
- package/services/chain-service/health-check/constants/index.js +4 -4
- package/services/chain-service/health-check/utils/asset-info.d.ts +1 -0
- package/services/chain-service/health-check/utils/asset-info.js +20 -4
- package/services/chain-service/health-check/utils/chain-info.d.ts +4 -2
- package/services/chain-service/health-check/utils/chain-info.js +20 -0
- package/services/chain-service/health-check/utils/new-utils/asset-asset-validate.d.ts +10 -0
- package/services/chain-service/health-check/utils/new-utils/asset-asset-validate.js +146 -0
- package/services/chain-service/health-check/utils/new-utils/asset-validate.d.ts +3 -0
- package/services/chain-service/health-check/utils/new-utils/asset-validate.js +38 -0
- package/services/chain-service/health-check/utils/new-utils/chain-asset-validate.d.ts +5 -0
- package/services/chain-service/health-check/utils/new-utils/chain-asset-validate.js +64 -0
- package/services/chain-service/health-check/utils/new-utils/chain-validate.d.ts +4 -0
- package/services/chain-service/health-check/utils/new-utils/chain-validate.js +26 -0
- package/services/chain-service/index.js +47 -5
- package/services/chain-service/types.d.ts +5 -0
- package/services/earning-service/handlers/liquid-staking/acala.js +46 -17
- package/services/migration-service/scripts/databases/ReloadMetadata.d.ts +5 -0
- package/services/migration-service/scripts/databases/ReloadMetadata.js +27 -0
- package/services/migration-service/scripts/index.js +4 -2
- package/services/price-service/coingecko.js +54 -32
- package/services/price-service/index.js +29 -11
- package/services/storage-service/db-stores/BaseStore.d.ts +3 -0
- package/services/storage-service/db-stores/BaseStore.js +4 -0
- package/services/swap-service/handler/asset-hub/handler.d.ts +31 -0
- package/services/swap-service/handler/asset-hub/handler.js +335 -0
- package/services/swap-service/handler/asset-hub/index.d.ts +1 -0
- package/services/swap-service/handler/asset-hub/index.js +4 -0
- package/services/swap-service/handler/asset-hub/router.d.ts +16 -0
- package/services/swap-service/handler/asset-hub/router.js +85 -0
- package/services/swap-service/handler/asset-hub/utils.d.ts +18 -0
- package/services/swap-service/handler/asset-hub/utils.js +133 -0
- package/services/swap-service/index.js +10 -1
- package/services/swap-service/utils.d.ts +1 -0
- package/services/swap-service/utils.js +9 -1
- package/types/swap/index.d.ts +15 -2
- package/types/swap/index.js +5 -1
- /package/cjs/services/migration-service/scripts/{ClearMetadataDatabase.js → databases/ClearMetadataDatabase.js} +0 -0
- /package/services/migration-service/scripts/{ClearMetadataDatabase.d.ts → databases/ClearMetadataDatabase.d.ts} +0 -0
- /package/services/migration-service/scripts/{ClearMetadataDatabase.js → databases/ClearMetadataDatabase.js} +0 -0
|
@@ -5,15 +5,25 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.getPriceMap = exports.getExchangeRateMap = void 0;
|
|
7
7
|
var _staticData = require("@subwallet/extension-base/utils/staticData");
|
|
8
|
+
var _util = require("@polkadot/util");
|
|
8
9
|
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
9
10
|
// SPDX-License-Identifier: Apache-2.0
|
|
10
11
|
|
|
11
12
|
const DEFAULT_CURRENCY = 'USD';
|
|
12
13
|
let useBackupApi = false;
|
|
13
14
|
const getExchangeRateMap = async () => {
|
|
15
|
+
let response;
|
|
14
16
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
var _response, _response2;
|
|
18
|
+
try {
|
|
19
|
+
response = await fetch('https://api-cache.subwallet.app/exchange-rate');
|
|
20
|
+
} catch (e) {}
|
|
21
|
+
if (((_response = response) === null || _response === void 0 ? void 0 : _response.status) !== 200) {
|
|
22
|
+
try {
|
|
23
|
+
response = await fetch('https://static-cache.subwallet.app/exchange-rate/data.json');
|
|
24
|
+
} catch (e) {}
|
|
25
|
+
}
|
|
26
|
+
const responseDataExchangeRate = (await ((_response2 = response) === null || _response2 === void 0 ? void 0 : _response2.json())) || {};
|
|
17
27
|
const exchangeRateMap = Object.keys(responseDataExchangeRate.conversion_rates).reduce((map, exchangeKey) => {
|
|
18
28
|
if (!_staticData.staticData[_staticData.StaticKey.CURRENCY_SYMBOL][exchangeKey]) {
|
|
19
29
|
return map;
|
|
@@ -26,45 +36,60 @@ const getExchangeRateMap = async () => {
|
|
|
26
36
|
}, {});
|
|
27
37
|
return exchangeRateMap;
|
|
28
38
|
} catch (e) {
|
|
29
|
-
console.warn('Failed to get exchange rate');
|
|
30
39
|
return {};
|
|
31
40
|
}
|
|
32
41
|
};
|
|
33
42
|
exports.getExchangeRateMap = getExchangeRateMap;
|
|
34
43
|
const getPriceMap = async function (priceIds) {
|
|
35
|
-
var _rs, _rs2;
|
|
36
44
|
let currency = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'USD';
|
|
37
45
|
const idStr = Array.from(priceIds).join(',');
|
|
38
|
-
let
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
var _response3, _response5;
|
|
49
|
+
if (!useBackupApi) {
|
|
50
|
+
try {
|
|
51
|
+
response = await fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currency.toLowerCase()}&per_page=250&ids=${idStr}`);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
useBackupApi = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (useBackupApi || ((_response3 = response) === null || _response3 === void 0 ? void 0 : _response3.status) !== 200) {
|
|
57
|
+
var _response4;
|
|
43
58
|
useBackupApi = true;
|
|
59
|
+
try {
|
|
60
|
+
response = await fetch(`https://api-cache.subwallet.app/api/price/get?ids=${idStr}`);
|
|
61
|
+
} catch (e) {}
|
|
62
|
+
if (((_response4 = response) === null || _response4 === void 0 ? void 0 : _response4.status) !== 200) {
|
|
63
|
+
try {
|
|
64
|
+
response = await fetch('https://static-cache.subwallet.app/price/data.json');
|
|
65
|
+
} catch (e) {}
|
|
66
|
+
}
|
|
44
67
|
}
|
|
68
|
+
const generateDataPriceRaw = (await ((_response5 = response) === null || _response5 === void 0 ? void 0 : _response5.json())) || [];
|
|
69
|
+
const responseDataPrice = (0, _util.isArray)(generateDataPriceRaw) ? generateDataPriceRaw : Object.entries(generateDataPriceRaw).map(_ref => {
|
|
70
|
+
let [id, value] = _ref;
|
|
71
|
+
return {
|
|
72
|
+
...value,
|
|
73
|
+
id
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
const currencyData = _staticData.staticData[_staticData.StaticKey.CURRENCY_SYMBOL][currency || DEFAULT_CURRENCY];
|
|
77
|
+
const priceMap = {};
|
|
78
|
+
const price24hMap = {};
|
|
79
|
+
responseDataPrice.forEach(val => {
|
|
80
|
+
const currentPrice = val.current_price || 0;
|
|
81
|
+
const price24h = currentPrice - (val.price_change_24h || 0);
|
|
82
|
+
priceMap[val.id] = currentPrice;
|
|
83
|
+
price24hMap[val.id] = price24h;
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
currency,
|
|
87
|
+
currencyData,
|
|
88
|
+
priceMap,
|
|
89
|
+
price24hMap
|
|
90
|
+
};
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return {};
|
|
45
93
|
}
|
|
46
|
-
if (useBackupApi || ((_rs = rs) === null || _rs === void 0 ? void 0 : _rs.status) !== 200) {
|
|
47
|
-
useBackupApi = true;
|
|
48
|
-
rs = await fetch(`https://chain-data.subwallet.app/api/price/get?ids=${idStr}`);
|
|
49
|
-
}
|
|
50
|
-
if (((_rs2 = rs) === null || _rs2 === void 0 ? void 0 : _rs2.status) !== 200) {
|
|
51
|
-
console.warn('Failed to get token price');
|
|
52
|
-
}
|
|
53
|
-
const responseDataPrice = (await rs.json()) || [];
|
|
54
|
-
const currencyData = _staticData.staticData[_staticData.StaticKey.CURRENCY_SYMBOL][currency || DEFAULT_CURRENCY];
|
|
55
|
-
const priceMap = {};
|
|
56
|
-
const price24hMap = {};
|
|
57
|
-
responseDataPrice.forEach(val => {
|
|
58
|
-
const currentPrice = val.current_price || 0;
|
|
59
|
-
const price24h = currentPrice - (val.price_change_24h || 0);
|
|
60
|
-
priceMap[val.id] = currentPrice;
|
|
61
|
-
price24hMap[val.id] = price24h;
|
|
62
|
-
});
|
|
63
|
-
return {
|
|
64
|
-
currency,
|
|
65
|
-
currencyData,
|
|
66
|
-
priceMap,
|
|
67
|
-
price24hMap
|
|
68
|
-
};
|
|
69
94
|
};
|
|
70
95
|
exports.getPriceMap = getPriceMap;
|
|
@@ -9,6 +9,7 @@ var _types = require("@subwallet/extension-base/services/base/types");
|
|
|
9
9
|
var _coingecko = require("@subwallet/extension-base/services/price-service/coingecko");
|
|
10
10
|
var _storage = require("@subwallet/extension-base/storage");
|
|
11
11
|
var _stores = require("@subwallet/extension-base/stores");
|
|
12
|
+
var _utils = require("@subwallet/extension-base/utils");
|
|
12
13
|
var _promise = require("@subwallet/extension-base/utils/promise");
|
|
13
14
|
var _staticData = require("@subwallet/extension-base/utils/staticData");
|
|
14
15
|
var _rxjs = require("rxjs");
|
|
@@ -28,6 +29,9 @@ const DEFAULT_PRICE_SUBJECT = {
|
|
|
28
29
|
price24hMap: {},
|
|
29
30
|
exchangeRateMap: {}
|
|
30
31
|
};
|
|
32
|
+
const checkFetchSuccess = (obj1, obj2) => {
|
|
33
|
+
return Object.keys(obj1).length > 0 && Object.keys(obj2).length > 0;
|
|
34
|
+
};
|
|
31
35
|
class PriceService {
|
|
32
36
|
priceIds = new Set();
|
|
33
37
|
currency = new _stores.CurrentCurrencyStore();
|
|
@@ -49,11 +53,16 @@ class PriceService {
|
|
|
49
53
|
this.init().then(() => this.getCurrentCurrency(updateCurrency)).catch(console.error);
|
|
50
54
|
}
|
|
51
55
|
async getTokenPrice(priceIds, currency, resolve, reject) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
const getPriceData = async () => {
|
|
57
|
+
await Promise.all([(0, _coingecko.getExchangeRateMap)(), (0, _coingecko.getPriceMap)(priceIds, currency)]).then(_ref => {
|
|
58
|
+
let [exchangeRateMap, priceMap] = _ref;
|
|
59
|
+
if (checkFetchSuccess(priceMap, exchangeRateMap)) {
|
|
60
|
+
this.rawExchangeRateMap.next(exchangeRateMap);
|
|
61
|
+
this.rawPriceSubject.next(priceMap);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
await Promise.race([getPriceData(), (0, _utils.wait)(10 * 1000)]);
|
|
57
66
|
}
|
|
58
67
|
getCurrentCurrencySubject() {
|
|
59
68
|
return this.currency.getSubject();
|
|
@@ -89,17 +98,27 @@ class PriceService {
|
|
|
89
98
|
})();
|
|
90
99
|
}
|
|
91
100
|
async calculatePriceMap(currency) {
|
|
92
|
-
|
|
101
|
+
let {
|
|
93
102
|
price24hMap,
|
|
94
103
|
priceMap
|
|
95
104
|
} = this.rawPriceSubject.value;
|
|
96
|
-
|
|
105
|
+
let exchangeRateData = this.rawExchangeRateMap.value;
|
|
106
|
+
const priceStored = await this.dbService.getPriceStore(currency);
|
|
97
107
|
const currencyKey = currency || DEFAULT_CURRENCY;
|
|
98
108
|
if (Object.keys(this.rawPriceSubject.value).length === 0) {
|
|
99
|
-
|
|
109
|
+
if (priceStored !== null && priceStored !== void 0 && priceStored.exchangeRateMap) {
|
|
110
|
+
exchangeRateData = priceStored.exchangeRateMap;
|
|
111
|
+
}
|
|
100
112
|
}
|
|
101
113
|
if (Object.keys(exchangeRateData).length === 0) {
|
|
102
|
-
|
|
114
|
+
if (priceStored !== null && priceStored !== void 0 && priceStored.price24hMap) {
|
|
115
|
+
price24hMap = {
|
|
116
|
+
...priceStored.price24hMap
|
|
117
|
+
};
|
|
118
|
+
priceMap = {
|
|
119
|
+
...priceStored.priceMap
|
|
120
|
+
};
|
|
121
|
+
}
|
|
103
122
|
}
|
|
104
123
|
const finalPriceMap = {
|
|
105
124
|
priceMap: {
|
|
@@ -165,8 +184,8 @@ class PriceService {
|
|
|
165
184
|
this.refreshPriceMapByAction();
|
|
166
185
|
}
|
|
167
186
|
};
|
|
168
|
-
this.getCurrentCurrencySubject().subscribe(
|
|
169
|
-
|
|
187
|
+
(0, _rxjs.combineLatest)([this.getCurrentCurrencySubject(), this.rawPriceSubject, this.rawExchangeRateMap]).subscribe(_ref2 => {
|
|
188
|
+
let [currency] = _ref2;
|
|
170
189
|
this.calculatePriceMap(currency).then(data => {
|
|
171
190
|
if (data) {
|
|
172
191
|
this.priceSubject.next(data);
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.AssetHubSwapHandler = void 0;
|
|
8
|
+
var _SwapError = require("@subwallet/extension-base/background/errors/SwapError");
|
|
9
|
+
var _TransactionError = require("@subwallet/extension-base/background/errors/TransactionError");
|
|
10
|
+
var _KoniTypes = require("@subwallet/extension-base/background/KoniTypes");
|
|
11
|
+
var _swap = require("@subwallet/extension-base/core/logic-validation/swap");
|
|
12
|
+
var _xcm = require("@subwallet/extension-base/services/balance-service/transfer/xcm");
|
|
13
|
+
var _utils = require("@subwallet/extension-base/services/chain-service/utils");
|
|
14
|
+
var _utils2 = require("@subwallet/extension-base/services/swap-service/utils");
|
|
15
|
+
var _serviceBase = require("@subwallet/extension-base/types/service-base");
|
|
16
|
+
var _swap2 = require("@subwallet/extension-base/types/swap");
|
|
17
|
+
var _bignumber = _interopRequireDefault(require("bignumber.js"));
|
|
18
|
+
var _baseHandler = require("../base-handler");
|
|
19
|
+
var _router = require("./router");
|
|
20
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
21
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
22
|
+
|
|
23
|
+
const PAH_LOW_LIQUIDITY_THRESHOLD = 0.15;
|
|
24
|
+
class AssetHubSwapHandler {
|
|
25
|
+
isReady = false;
|
|
26
|
+
constructor(chainService, balanceService, chain) {
|
|
27
|
+
const chainInfo = chainService.getChainInfoByKey(chain);
|
|
28
|
+
const providerSlug = chain === 'statemint' ? _swap2.SwapProviderId.POLKADOT_ASSET_HUB : chain === 'statemine' ? _swap2.SwapProviderId.KUSAMA_ASSET_HUB : _swap2.SwapProviderId.ROCOCO_ASSET_HUB;
|
|
29
|
+
this.swapBaseHandler = new _baseHandler.SwapBaseHandler({
|
|
30
|
+
balanceService,
|
|
31
|
+
chainService,
|
|
32
|
+
providerName: chainInfo.name,
|
|
33
|
+
providerSlug
|
|
34
|
+
});
|
|
35
|
+
this.providerSlug = providerSlug;
|
|
36
|
+
this.chain = chain;
|
|
37
|
+
}
|
|
38
|
+
get chainService() {
|
|
39
|
+
return this.swapBaseHandler.chainService;
|
|
40
|
+
}
|
|
41
|
+
get balanceService() {
|
|
42
|
+
return this.swapBaseHandler.balanceService;
|
|
43
|
+
}
|
|
44
|
+
get providerInfo() {
|
|
45
|
+
return this.swapBaseHandler.providerInfo;
|
|
46
|
+
}
|
|
47
|
+
get name() {
|
|
48
|
+
return this.swapBaseHandler.name;
|
|
49
|
+
}
|
|
50
|
+
get slug() {
|
|
51
|
+
return this.swapBaseHandler.slug;
|
|
52
|
+
}
|
|
53
|
+
async init() {
|
|
54
|
+
const chainState = this.chainService.getChainStateByKey(this.chain);
|
|
55
|
+
if (!chainState.active) {
|
|
56
|
+
await this.chainService.enableChain(this.chain);
|
|
57
|
+
}
|
|
58
|
+
const substrateApi = this.chainService.getSubstrateApi(this.chain);
|
|
59
|
+
await substrateApi.api.isReady;
|
|
60
|
+
this.router = new _router.AssetHubRouter(this.chain, this.chainService);
|
|
61
|
+
this.isReady = true;
|
|
62
|
+
}
|
|
63
|
+
async getXcmStep(params) {
|
|
64
|
+
const bnAmount = new _bignumber.default(params.request.fromAmount);
|
|
65
|
+
const fromAsset = this.chainService.getAssetBySlug(params.request.pair.from);
|
|
66
|
+
const fromAssetBalance = await this.balanceService.getTransferableBalance(params.request.address, fromAsset.originChain, fromAsset.slug);
|
|
67
|
+
const bnFromAssetBalance = new _bignumber.default(fromAssetBalance.value);
|
|
68
|
+
if (bnFromAssetBalance.gte(bnAmount)) {
|
|
69
|
+
return undefined; // enough balance, no need to xcm
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const alternativeAssetSlug = (0, _utils2.getSwapAlternativeAsset)(params.request.pair);
|
|
73
|
+
if (!alternativeAssetSlug) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
const alternativeAsset = this.chainService.getAssetBySlug(alternativeAssetSlug);
|
|
77
|
+
const alternativeAssetBalance = await this.balanceService.getTransferableBalance(params.request.address, alternativeAsset.originChain, alternativeAsset.slug);
|
|
78
|
+
const bnAlternativeAssetBalance = new _bignumber.default(alternativeAssetBalance.value);
|
|
79
|
+
if (bnAlternativeAssetBalance.lte(0)) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const alternativeChainInfo = this.chainService.getChainInfoByKey(alternativeAsset.originChain);
|
|
84
|
+
const step = {
|
|
85
|
+
metadata: {
|
|
86
|
+
sendingValue: bnAmount.toString(),
|
|
87
|
+
originTokenInfo: alternativeAsset,
|
|
88
|
+
destinationTokenInfo: fromAsset
|
|
89
|
+
},
|
|
90
|
+
name: `Transfer ${alternativeAsset.symbol} from ${alternativeChainInfo.name}`,
|
|
91
|
+
type: _serviceBase.CommonStepType.XCM
|
|
92
|
+
};
|
|
93
|
+
const xcmOriginSubstrateApi = await this.chainService.getSubstrateApi(alternativeAsset.originChain).isReady;
|
|
94
|
+
const xcmTransfer = await (0, _xcm.createXcmExtrinsic)({
|
|
95
|
+
originTokenInfo: alternativeAsset,
|
|
96
|
+
destinationTokenInfo: fromAsset,
|
|
97
|
+
sendingValue: bnAmount.toString(),
|
|
98
|
+
recipient: params.request.address,
|
|
99
|
+
chainInfoMap: this.chainService.getChainInfoMap(),
|
|
100
|
+
substrateApi: xcmOriginSubstrateApi
|
|
101
|
+
});
|
|
102
|
+
const _xcmFeeInfo = await xcmTransfer.paymentInfo(params.request.address);
|
|
103
|
+
const xcmFeeInfo = _xcmFeeInfo.toPrimitive();
|
|
104
|
+
const fee = {
|
|
105
|
+
feeComponent: [{
|
|
106
|
+
feeType: _swap2.SwapFeeType.NETWORK_FEE,
|
|
107
|
+
amount: Math.round(xcmFeeInfo.partialFee * 1.2).toString(),
|
|
108
|
+
tokenSlug: (0, _utils._getChainNativeTokenSlug)(alternativeChainInfo)
|
|
109
|
+
}],
|
|
110
|
+
defaultFeeToken: (0, _utils._getChainNativeTokenSlug)(alternativeChainInfo),
|
|
111
|
+
feeOptions: [(0, _utils._getChainNativeTokenSlug)(alternativeChainInfo)]
|
|
112
|
+
};
|
|
113
|
+
return [step, fee];
|
|
114
|
+
} catch (e) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async getSubmitStep(params) {
|
|
119
|
+
if (params.selectedQuote) {
|
|
120
|
+
const submitStep = {
|
|
121
|
+
name: 'Swap',
|
|
122
|
+
type: _swap2.SwapStepType.SWAP
|
|
123
|
+
};
|
|
124
|
+
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]);
|
|
125
|
+
}
|
|
126
|
+
return Promise.resolve(undefined);
|
|
127
|
+
}
|
|
128
|
+
generateOptimalProcess(params) {
|
|
129
|
+
return this.swapBaseHandler.generateOptimalProcess(params, [this.getXcmStep, this.getSubmitStep]);
|
|
130
|
+
}
|
|
131
|
+
async getSwapQuote(request) {
|
|
132
|
+
const fromAsset = this.chainService.getAssetBySlug(request.pair.from);
|
|
133
|
+
const toAsset = this.chainService.getAssetBySlug(request.pair.to);
|
|
134
|
+
const fromChain = this.chainService.getChainInfoByKey(fromAsset.originChain);
|
|
135
|
+
const fromChainNativeTokenSlug = (0, _utils._getChainNativeTokenSlug)(fromChain);
|
|
136
|
+
if (!this.isReady || !this.router) {
|
|
137
|
+
return new _SwapError.SwapError(_swap2.SwapErrorType.UNKNOWN);
|
|
138
|
+
}
|
|
139
|
+
const earlyValidation = await this.validateSwapRequest(request);
|
|
140
|
+
if (earlyValidation.error) {
|
|
141
|
+
const metadata = earlyValidation.metadata;
|
|
142
|
+
return (0, _swap._getEarlyAssetHubValidationError)(earlyValidation.error, metadata);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const paths = this.router.buildPath(request.pair);
|
|
146
|
+
const amountOut = earlyValidation.metadata.toAmount;
|
|
147
|
+
const toAmount = new _bignumber.default(amountOut);
|
|
148
|
+
const minReceive = toAmount.times(1 - request.slippage).integerValue(_bignumber.default.ROUND_DOWN);
|
|
149
|
+
const extrinsic = await this.router.buildSwapExtrinsic(paths, request.address, request.fromAmount, minReceive.toString());
|
|
150
|
+
const paymentInfo = await extrinsic.paymentInfo(request.address);
|
|
151
|
+
const networkFee = {
|
|
152
|
+
tokenSlug: fromChainNativeTokenSlug,
|
|
153
|
+
amount: paymentInfo.partialFee.toString(),
|
|
154
|
+
feeType: _swap2.SwapFeeType.NETWORK_FEE
|
|
155
|
+
};
|
|
156
|
+
const feeTokenOptions = [fromChainNativeTokenSlug];
|
|
157
|
+
const selectedFeeToken = fromChainNativeTokenSlug;
|
|
158
|
+
const priceImpactPct = earlyValidation.metadata.priceImpactPct || '0';
|
|
159
|
+
return {
|
|
160
|
+
pair: request.pair,
|
|
161
|
+
fromAmount: request.fromAmount,
|
|
162
|
+
toAmount: toAmount.toString(),
|
|
163
|
+
rate: (0, _utils2.convertSwapRate)(earlyValidation.metadata.quoteRate, fromAsset, toAsset),
|
|
164
|
+
provider: this.providerInfo,
|
|
165
|
+
aliveUntil: +Date.now() + (_utils2.SWAP_QUOTE_TIMEOUT_MAP[this.slug] || _utils2.SWAP_QUOTE_TIMEOUT_MAP.default),
|
|
166
|
+
feeInfo: {
|
|
167
|
+
feeComponent: [networkFee],
|
|
168
|
+
defaultFeeToken: fromChainNativeTokenSlug,
|
|
169
|
+
feeOptions: feeTokenOptions,
|
|
170
|
+
// TODO: enable fee options
|
|
171
|
+
selectedFeeToken
|
|
172
|
+
},
|
|
173
|
+
isLowLiquidity: Math.abs(parseFloat(priceImpactPct)) >= PAH_LOW_LIQUIDITY_THRESHOLD,
|
|
174
|
+
route: {
|
|
175
|
+
path: paths.map(asset => asset.slug)
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
} catch (e) {
|
|
179
|
+
return new _SwapError.SwapError(_swap2.SwapErrorType.ERROR_FETCHING_QUOTE);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async handleXcmStep(params) {
|
|
183
|
+
const pair = params.quote.pair;
|
|
184
|
+
const alternativeAssetSlug = (0, _utils2.getSwapAlternativeAsset)(pair);
|
|
185
|
+
const originAsset = this.chainService.getAssetBySlug(alternativeAssetSlug);
|
|
186
|
+
const destinationAsset = this.chainService.getAssetBySlug(pair.from);
|
|
187
|
+
const substrateApi = this.chainService.getSubstrateApi(originAsset.originChain);
|
|
188
|
+
const chainApi = await substrateApi.isReady;
|
|
189
|
+
const destinationAssetBalance = await this.balanceService.getTransferableBalance(params.address, destinationAsset.originChain, destinationAsset.slug);
|
|
190
|
+
const xcmFee = params.process.totalFee[params.currentStep];
|
|
191
|
+
const bnAmount = new _bignumber.default(params.quote.fromAmount);
|
|
192
|
+
const bnDestinationAssetBalance = new _bignumber.default(destinationAssetBalance.value);
|
|
193
|
+
let bnTotalAmount = bnAmount.minus(bnDestinationAssetBalance);
|
|
194
|
+
if ((0, _utils._isNativeToken)(originAsset)) {
|
|
195
|
+
const bnXcmFee = new _bignumber.default(xcmFee.feeComponent[0].amount); // xcm fee is paid in native token but swap token is not always native token
|
|
196
|
+
|
|
197
|
+
bnTotalAmount = bnTotalAmount.plus(bnXcmFee);
|
|
198
|
+
}
|
|
199
|
+
const xcmTransfer = await (0, _xcm.createXcmExtrinsic)({
|
|
200
|
+
originTokenInfo: originAsset,
|
|
201
|
+
destinationTokenInfo: destinationAsset,
|
|
202
|
+
sendingValue: bnTotalAmount.toString(),
|
|
203
|
+
recipient: params.address,
|
|
204
|
+
chainInfoMap: this.chainService.getChainInfoMap(),
|
|
205
|
+
substrateApi: chainApi
|
|
206
|
+
});
|
|
207
|
+
const xcmData = {
|
|
208
|
+
originNetworkKey: originAsset.originChain,
|
|
209
|
+
destinationNetworkKey: destinationAsset.originChain,
|
|
210
|
+
from: params.address,
|
|
211
|
+
to: params.address,
|
|
212
|
+
value: bnTotalAmount.toString(),
|
|
213
|
+
tokenSlug: originAsset.slug,
|
|
214
|
+
showExtraWarning: true
|
|
215
|
+
};
|
|
216
|
+
return {
|
|
217
|
+
txChain: originAsset.originChain,
|
|
218
|
+
extrinsic: xcmTransfer,
|
|
219
|
+
transferNativeAmount: (0, _utils._isNativeToken)(originAsset) ? bnTotalAmount.toString() : '0',
|
|
220
|
+
extrinsicType: _KoniTypes.ExtrinsicType.TRANSFER_XCM,
|
|
221
|
+
chainType: _KoniTypes.ChainType.SUBSTRATE,
|
|
222
|
+
txData: xcmData
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async handleSubmitStep(params) {
|
|
226
|
+
var _this$router;
|
|
227
|
+
const fromAsset = this.chainService.getAssetBySlug(params.quote.pair.from);
|
|
228
|
+
const txData = {
|
|
229
|
+
provider: this.providerInfo,
|
|
230
|
+
quote: params.quote,
|
|
231
|
+
address: params.address,
|
|
232
|
+
slippage: params.slippage,
|
|
233
|
+
process: params.process
|
|
234
|
+
};
|
|
235
|
+
const paths = params.quote.route.path.map(slug => this.chainService.getAssetBySlug(slug));
|
|
236
|
+
const {
|
|
237
|
+
fromAmount,
|
|
238
|
+
toAmount
|
|
239
|
+
} = params.quote;
|
|
240
|
+
const minReceive = new _bignumber.default(1 - params.slippage).times(toAmount).integerValue(_bignumber.default.ROUND_DOWN);
|
|
241
|
+
const extrinsic = await ((_this$router = this.router) === null || _this$router === void 0 ? void 0 : _this$router.buildSwapExtrinsic(paths, params.address, fromAmount, minReceive.toString()));
|
|
242
|
+
return {
|
|
243
|
+
txChain: fromAsset.originChain,
|
|
244
|
+
txData,
|
|
245
|
+
extrinsic,
|
|
246
|
+
transferNativeAmount: (0, _utils._isNativeToken)(fromAsset) ? params.quote.fromAmount : '0',
|
|
247
|
+
// todo
|
|
248
|
+
extrinsicType: _KoniTypes.ExtrinsicType.SWAP,
|
|
249
|
+
chainType: _KoniTypes.ChainType.SUBSTRATE
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
handleSwapProcess(params) {
|
|
253
|
+
const {
|
|
254
|
+
currentStep,
|
|
255
|
+
process
|
|
256
|
+
} = params;
|
|
257
|
+
const type = process.steps[currentStep].type;
|
|
258
|
+
switch (type) {
|
|
259
|
+
case _serviceBase.CommonStepType.XCM:
|
|
260
|
+
return this.handleXcmStep(params);
|
|
261
|
+
case _swap2.SwapStepType.SWAP:
|
|
262
|
+
return this.handleSubmitStep(params);
|
|
263
|
+
default:
|
|
264
|
+
return Promise.reject(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNSUPPORTED));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async validateSwapStep(params, isXcmOk, stepIndex) {
|
|
268
|
+
// check swap quote timestamp
|
|
269
|
+
// check balance to pay transaction fee
|
|
270
|
+
// check balance against spending amount
|
|
271
|
+
if (!params.selectedQuote) {
|
|
272
|
+
return Promise.resolve([new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.INTERNAL_ERROR)]);
|
|
273
|
+
}
|
|
274
|
+
const selectedQuote = params.selectedQuote;
|
|
275
|
+
const currentTimestamp = +Date.now();
|
|
276
|
+
if (selectedQuote.aliveUntil <= currentTimestamp) {
|
|
277
|
+
return Promise.resolve([new _TransactionError.TransactionError(_swap2.SwapErrorType.QUOTE_TIMEOUT)]);
|
|
278
|
+
}
|
|
279
|
+
const stepFee = params.process.totalFee[stepIndex].feeComponent;
|
|
280
|
+
const networkFee = stepFee.find(fee => fee.feeType === _swap2.SwapFeeType.NETWORK_FEE);
|
|
281
|
+
if (!networkFee) {
|
|
282
|
+
return Promise.resolve([new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.INTERNAL_ERROR)]);
|
|
283
|
+
}
|
|
284
|
+
const fromAsset = this.chainService.getAssetBySlug(params.selectedQuote.pair.from);
|
|
285
|
+
const feeTokenInfo = this.chainService.getAssetBySlug(networkFee.tokenSlug);
|
|
286
|
+
const feeTokenChain = this.chainService.getChainInfoByKey(feeTokenInfo.originChain);
|
|
287
|
+
const {
|
|
288
|
+
fromAmount,
|
|
289
|
+
minSwap
|
|
290
|
+
} = params.selectedQuote;
|
|
291
|
+
const [feeTokenBalance, fromAssetBalance] = await Promise.all([this.balanceService.getTransferableBalance(params.address, feeTokenInfo.originChain, feeTokenInfo.slug), this.balanceService.getTransferableBalance(params.address, fromAsset.originChain, fromAsset.slug)]);
|
|
292
|
+
const balanceError = (0, _swap._validateBalanceToSwapOnAssetHub)(fromAsset, feeTokenInfo, feeTokenChain, networkFee.amount, fromAssetBalance.value, feeTokenBalance.value, fromAmount, isXcmOk, minSwap);
|
|
293
|
+
if (balanceError) {
|
|
294
|
+
return Promise.resolve([balanceError]);
|
|
295
|
+
}
|
|
296
|
+
if (!params.recipient) {
|
|
297
|
+
return Promise.resolve([]);
|
|
298
|
+
}
|
|
299
|
+
const toAsset = this.chainService.getAssetBySlug(params.selectedQuote.pair.to);
|
|
300
|
+
const toAssetChain = this.chainService.getChainInfoByKey(toAsset.originChain);
|
|
301
|
+
const recipientError = (0, _swap._validateSwapRecipient)(toAssetChain, params.recipient);
|
|
302
|
+
if (recipientError) {
|
|
303
|
+
return Promise.resolve([recipientError]);
|
|
304
|
+
}
|
|
305
|
+
return Promise.resolve([]);
|
|
306
|
+
}
|
|
307
|
+
async validateSwapProcess(params) {
|
|
308
|
+
const amount = params.selectedQuote.fromAmount;
|
|
309
|
+
const bnAmount = new _bignumber.default(amount);
|
|
310
|
+
if (bnAmount.lte(0)) {
|
|
311
|
+
return [new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
|
|
312
|
+
}
|
|
313
|
+
let isXcmOk = false;
|
|
314
|
+
for (const [index, step] of params.process.steps.entries()) {
|
|
315
|
+
const getErrors = async () => {
|
|
316
|
+
switch (step.type) {
|
|
317
|
+
case _serviceBase.CommonStepType.DEFAULT:
|
|
318
|
+
return Promise.resolve([]);
|
|
319
|
+
case _serviceBase.CommonStepType.XCM:
|
|
320
|
+
return this.swapBaseHandler.validateXcmStep(params, index);
|
|
321
|
+
case _swap2.SwapStepType.SWAP:
|
|
322
|
+
return this.validateSwapStep(params, isXcmOk, index);
|
|
323
|
+
default:
|
|
324
|
+
return Promise.reject(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNSUPPORTED));
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
const errors = await getErrors();
|
|
328
|
+
if (errors.length) {
|
|
329
|
+
return errors;
|
|
330
|
+
} else if (step.type === _serviceBase.CommonStepType.XCM) {
|
|
331
|
+
isXcmOk = true;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return [];
|
|
335
|
+
}
|
|
336
|
+
validateSwapRequest(request) {
|
|
337
|
+
if (!this.isReady || !this.router) {
|
|
338
|
+
throw new _SwapError.SwapError(_swap2.SwapErrorType.ERROR_FETCHING_QUOTE);
|
|
339
|
+
}
|
|
340
|
+
return this.router.earlyValidateSwapValidation(request);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
exports.AssetHubSwapHandler = AssetHubSwapHandler;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "AssetHubSwapHandler", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _handler.AssetHubSwapHandler;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _handler = require("./handler");
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.AssetHubRouter = void 0;
|
|
8
|
+
var _utils = require("@subwallet/extension-base/services/chain-service/utils");
|
|
9
|
+
var _utils2 = require("@subwallet/extension-base/services/swap-service/handler/asset-hub/utils");
|
|
10
|
+
var _swap = require("@subwallet/extension-base/types/swap");
|
|
11
|
+
var _bignumber = _interopRequireDefault(require("bignumber.js"));
|
|
12
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
13
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
14
|
+
|
|
15
|
+
class AssetHubRouter {
|
|
16
|
+
constructor(chain, chainService) {
|
|
17
|
+
this.chain = chain;
|
|
18
|
+
this.chainService = chainService;
|
|
19
|
+
}
|
|
20
|
+
get substrateApi() {
|
|
21
|
+
return this.chainService.getSubstrateApi(this.chain);
|
|
22
|
+
}
|
|
23
|
+
get nativeToken() {
|
|
24
|
+
return this.chainService.getNativeTokenInfo(this.chain);
|
|
25
|
+
}
|
|
26
|
+
buildPath(pair) {
|
|
27
|
+
// const nativeToken = this.nativeToken;
|
|
28
|
+
// const nativeTokenSlug = nativeToken.slug;
|
|
29
|
+
|
|
30
|
+
const assetFrom = this.chainService.getAssetBySlug(pair.from);
|
|
31
|
+
const assetTo = this.chainService.getAssetBySlug(pair.to);
|
|
32
|
+
return [assetFrom, assetTo];
|
|
33
|
+
// if (pair.from === nativeTokenSlug || pair.to === nativeTokenSlug) {
|
|
34
|
+
// return [assetFrom, assetTo];
|
|
35
|
+
// } else {
|
|
36
|
+
// return [assetFrom, nativeToken, assetTo];
|
|
37
|
+
// }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async earlyValidateSwapValidation(request) {
|
|
41
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
42
|
+
const paths = this.buildPath(request.pair);
|
|
43
|
+
const api = await substrateApi.api.isReady;
|
|
44
|
+
const amount = request.fromAmount;
|
|
45
|
+
const reserves = await (0, _utils2.getReserveForPath)(api, paths);
|
|
46
|
+
const amounts = (0, _utils2.estimateTokensForPath)(amount, reserves);
|
|
47
|
+
const marketRate = (0, _utils2.estimateRateForPath)(reserves);
|
|
48
|
+
const marketRateAfter = (0, _utils2.estimateRateAfter)(amount, reserves);
|
|
49
|
+
const priceImpactPct = (0, _utils2.estimatePriceImpactPct)(marketRate, marketRateAfter);
|
|
50
|
+
const errors = [];
|
|
51
|
+
|
|
52
|
+
// Check liquidity
|
|
53
|
+
const liquidityError = (0, _utils2.checkLiquidityForPath)(amounts, reserves);
|
|
54
|
+
if (liquidityError) {
|
|
55
|
+
errors.push(liquidityError);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check amount token in pool after swap
|
|
59
|
+
const minAmounts = paths.map(asset => (0, _utils._getTokenMinAmount)(asset));
|
|
60
|
+
const minAmountAfterSwapError = (0, _utils2.checkMinAmountForPath)(reserves, amounts, minAmounts);
|
|
61
|
+
if (minAmountAfterSwapError) {
|
|
62
|
+
errors.push(minAmountAfterSwapError);
|
|
63
|
+
}
|
|
64
|
+
const bnAmount = new _bignumber.default(request.fromAmount);
|
|
65
|
+
if (bnAmount.lte(0)) {
|
|
66
|
+
errors.push(_swap.SwapErrorType.AMOUNT_CANNOT_BE_ZERO);
|
|
67
|
+
}
|
|
68
|
+
const metadata = {
|
|
69
|
+
chain: this.chainService.getChainInfoByKey(this.chain),
|
|
70
|
+
toAmount: amounts[amounts.length - 1],
|
|
71
|
+
quoteRate: marketRate,
|
|
72
|
+
priceImpactPct: priceImpactPct
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
error: errors[0],
|
|
76
|
+
metadata
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async estimateAmountOut(pair, amountIn) {
|
|
80
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
81
|
+
const paths = this.buildPath(pair);
|
|
82
|
+
const api = await substrateApi.api.isReady;
|
|
83
|
+
const reserves = await (0, _utils2.getReserveForPath)(api, paths);
|
|
84
|
+
const amounts = (0, _utils2.estimateTokensForPath)(amountIn, reserves);
|
|
85
|
+
return amounts[amounts.length - 1];
|
|
86
|
+
}
|
|
87
|
+
async buildSwapExtrinsic(path, recipient, amountIn, amountOutMin) {
|
|
88
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
89
|
+
const api = await substrateApi.api.isReady;
|
|
90
|
+
return (0, _utils2.buildSwapExtrinsic)(api, path, recipient, amountIn, amountOutMin);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.AssetHubRouter = AssetHubRouter;
|