@subwallet/extension-base 1.3.10-0 → 1.3.11-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 -0
- package/cjs/background/errors/SwapError.js +5 -0
- package/cjs/core/logic-validation/swap.js +27 -0
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/utils/patch.js +1 -1
- package/cjs/services/swap-service/handler/chainflip-handler.js +0 -1
- package/cjs/services/swap-service/handler/simpleswap-handler.js +444 -0
- package/cjs/services/swap-service/index.js +15 -3
- package/cjs/services/swap-service/utils.js +13 -2
- package/cjs/services/transaction-service/index.js +14 -10
- package/cjs/services/transaction-service/utils.js +9 -1
- package/cjs/types/swap/index.js +7 -3
- package/cjs/utils/number.js +11 -6
- package/core/logic-validation/swap.d.ts +2 -1
- package/core/logic-validation/swap.js +26 -0
- package/package.json +11 -6
- package/packageInfo.js +1 -1
- package/services/chain-service/utils/patch.js +1 -1
- package/services/swap-service/handler/chainflip-handler.js +0 -1
- package/services/swap-service/handler/simpleswap-handler.d.ts +24 -0
- package/services/swap-service/handler/simpleswap-handler.js +434 -0
- package/services/swap-service/index.d.ts +2 -1
- package/services/swap-service/index.js +13 -2
- package/services/swap-service/utils.d.ts +2 -0
- package/services/swap-service/utils.js +10 -1
- package/services/transaction-service/index.js +15 -11
- package/services/transaction-service/utils.d.ts +2 -1
- package/services/transaction-service/utils.js +9 -2
- package/types/swap/index.d.ts +15 -3
- package/types/swap/index.js +5 -2
- package/utils/number.d.ts +9 -1
- package/utils/number.js +10 -4
|
@@ -47,6 +47,11 @@ const defaultErrorMap = {
|
|
|
47
47
|
MAKE_POOL_NOT_ENOUGH_EXISTENTIAL_DEPOSIT: {
|
|
48
48
|
message: detectTranslate('Insufficient liquidity to complete the swap. Lower your amount and try again'),
|
|
49
49
|
code: undefined
|
|
50
|
+
},
|
|
51
|
+
NOT_MEET_MIN_EXPECTED: {
|
|
52
|
+
// TODO: update message
|
|
53
|
+
message: detectTranslate('Unable to process this swap at the moment. Try again later'),
|
|
54
|
+
code: undefined
|
|
50
55
|
}
|
|
51
56
|
};
|
|
52
57
|
export class SwapError extends SWError {
|
|
@@ -53,6 +53,11 @@ const defaultErrorMap = {
|
|
|
53
53
|
MAKE_POOL_NOT_ENOUGH_EXISTENTIAL_DEPOSIT: {
|
|
54
54
|
message: (0, _utils.detectTranslate)('Insufficient liquidity to complete the swap. Lower your amount and try again'),
|
|
55
55
|
code: undefined
|
|
56
|
+
},
|
|
57
|
+
NOT_MEET_MIN_EXPECTED: {
|
|
58
|
+
// TODO: update message
|
|
59
|
+
message: (0, _utils.detectTranslate)('Unable to process this swap at the moment. Try again later'),
|
|
60
|
+
code: undefined
|
|
56
61
|
}
|
|
57
62
|
};
|
|
58
63
|
class SwapError extends _SWError.SWError {
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports._getChainflipEarlyValidationError = _getChainflipEarlyValidationError;
|
|
8
8
|
exports._getEarlyAssetHubValidationError = _getEarlyAssetHubValidationError;
|
|
9
9
|
exports._getEarlyHydradxValidationError = _getEarlyHydradxValidationError;
|
|
10
|
+
exports._getSimpleSwapEarlyValidationError = _getSimpleSwapEarlyValidationError;
|
|
10
11
|
exports._validateBalanceToSwap = _validateBalanceToSwap;
|
|
11
12
|
exports._validateBalanceToSwapOnAssetHub = _validateBalanceToSwapOnAssetHub;
|
|
12
13
|
exports._validateSwapRecipient = _validateSwapRecipient;
|
|
@@ -149,4 +150,30 @@ function _getEarlyAssetHubValidationError(error, metadata) {
|
|
|
149
150
|
default:
|
|
150
151
|
return new _SwapError.SwapError(error);
|
|
151
152
|
}
|
|
153
|
+
}
|
|
154
|
+
function _getSimpleSwapEarlyValidationError(error, metadata) {
|
|
155
|
+
// todo: support more providers
|
|
156
|
+
switch (error) {
|
|
157
|
+
case _swap.SwapErrorType.NOT_MEET_MIN_SWAP:
|
|
158
|
+
{
|
|
159
|
+
const message = `Amount too low. Increase your amount above ${metadata.minSwap.value} ${metadata.minSwap.symbol} and try again`;
|
|
160
|
+
return new _SwapError.SwapError(error, message);
|
|
161
|
+
}
|
|
162
|
+
case _swap.SwapErrorType.SWAP_EXCEED_ALLOWANCE:
|
|
163
|
+
{
|
|
164
|
+
if (metadata.maxSwap) {
|
|
165
|
+
return new _SwapError.SwapError(error, `Amount too high. Lower your amount below ${metadata.maxSwap.value} ${metadata.maxSwap.symbol} and try again`);
|
|
166
|
+
} else {
|
|
167
|
+
return new _SwapError.SwapError(error, 'Amount too high. Lower your amount and try again');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
case _swap.SwapErrorType.ASSET_NOT_SUPPORTED:
|
|
171
|
+
return new _SwapError.SwapError(error, 'This swap pair is not supported');
|
|
172
|
+
case _swap.SwapErrorType.UNKNOWN:
|
|
173
|
+
return new _SwapError.SwapError(error, `Undefined error. Check your Internet and ${metadata.chain.slug} connection or contact support`);
|
|
174
|
+
case _swap.SwapErrorType.ERROR_FETCHING_QUOTE:
|
|
175
|
+
return new _SwapError.SwapError(error, 'No swap quote found. Adjust your amount or try again later.');
|
|
176
|
+
default:
|
|
177
|
+
return new _SwapError.SwapError(error);
|
|
178
|
+
}
|
|
152
179
|
}
|
package/cjs/packageInfo.js
CHANGED
|
@@ -11,7 +11,7 @@ const PRODUCTION_BRANCHES = ['master', 'webapp', 'webapp-dev'];
|
|
|
11
11
|
const branchName = process.env.BRANCH_NAME || 'subwallet-dev';
|
|
12
12
|
const fetchDomain = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'https://chain-list-assets.subwallet.app' : 'https://dev.sw-chain-list-assets.pages.dev';
|
|
13
13
|
const fetchFile = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'list.json' : 'preview.json';
|
|
14
|
-
const ChainListVersion = '0.2.
|
|
14
|
+
const ChainListVersion = '0.2.96'; // update this when build chainlist
|
|
15
15
|
|
|
16
16
|
// todo: move this interface to chainlist
|
|
17
17
|
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.simpleSwapApiKey = exports.SimpleSwapHandler = void 0;
|
|
7
|
+
var _SwapError = require("@subwallet/extension-base/background/errors/SwapError");
|
|
8
|
+
var _TransactionError = require("@subwallet/extension-base/background/errors/TransactionError");
|
|
9
|
+
var _KoniTypes = require("@subwallet/extension-base/background/KoniTypes");
|
|
10
|
+
var _swap = require("@subwallet/extension-base/core/logic-validation/swap");
|
|
11
|
+
var _utils = require("@subwallet/extension-base/services/chain-service/utils");
|
|
12
|
+
var _types = require("@subwallet/extension-base/types");
|
|
13
|
+
var _utils2 = require("@subwallet/extension-base/utils");
|
|
14
|
+
var _bignumber = _interopRequireWildcard(require("bignumber.js"));
|
|
15
|
+
var _smartContract = require("../../balance-service/transfer/smart-contract");
|
|
16
|
+
var _token = require("../../balance-service/transfer/token");
|
|
17
|
+
var _utils3 = require("../utils");
|
|
18
|
+
var _baseHandler = require("./base-handler");
|
|
19
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
20
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
21
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
22
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
23
|
+
|
|
24
|
+
const apiUrl = 'https://api.simpleswap.io';
|
|
25
|
+
const simpleSwapApiKey = process.env.SIMPLE_SWAP_API_KEY || '';
|
|
26
|
+
exports.simpleSwapApiKey = simpleSwapApiKey;
|
|
27
|
+
const toBNString = (input, decimal) => {
|
|
28
|
+
const raw = new _bignumber.BigNumber(input);
|
|
29
|
+
return raw.shiftedBy(decimal).integerValue(_bignumber.BigNumber.ROUND_CEIL).toFixed();
|
|
30
|
+
};
|
|
31
|
+
const fetchSwapList = async params => {
|
|
32
|
+
const swapListParams = new URLSearchParams({
|
|
33
|
+
api_key: `${simpleSwapApiKey}`,
|
|
34
|
+
fixed: 'false',
|
|
35
|
+
symbol: params.fromSymbol
|
|
36
|
+
});
|
|
37
|
+
const response = await fetch(`${apiUrl}/get_pairs?${swapListParams.toString()}`, {
|
|
38
|
+
headers: {
|
|
39
|
+
accept: 'application/json'
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return await response.json();
|
|
43
|
+
};
|
|
44
|
+
const fetchRanges = async params => {
|
|
45
|
+
const rangesParams = new URLSearchParams({
|
|
46
|
+
api_key: `${simpleSwapApiKey}`,
|
|
47
|
+
fixed: 'false',
|
|
48
|
+
currency_from: params.fromSymbol,
|
|
49
|
+
currency_to: params.toSymbol
|
|
50
|
+
});
|
|
51
|
+
const response = await fetch(`${apiUrl}/get_ranges?${rangesParams.toString()}`, {
|
|
52
|
+
headers: {
|
|
53
|
+
accept: 'application/json'
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return await response.json();
|
|
57
|
+
};
|
|
58
|
+
async function getEstimate(request, fromAsset, toAsset) {
|
|
59
|
+
const fromSymbol = _utils3.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING[fromAsset.slug];
|
|
60
|
+
const toSymbol = _utils3.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING[toAsset.slug];
|
|
61
|
+
const assetDecimals = (0, _utils._getAssetDecimals)(fromAsset);
|
|
62
|
+
if (!fromSymbol || !toSymbol) {
|
|
63
|
+
throw new _SwapError.SwapError(_types.SwapErrorType.ASSET_NOT_SUPPORTED);
|
|
64
|
+
}
|
|
65
|
+
const formatedAmount = (0, _utils2.formatNumber)(request.fromAmount, assetDecimals, s => s);
|
|
66
|
+
const params = new URLSearchParams({
|
|
67
|
+
api_key: `${simpleSwapApiKey}`,
|
|
68
|
+
fixed: 'false',
|
|
69
|
+
currency_from: fromSymbol,
|
|
70
|
+
currency_to: toSymbol,
|
|
71
|
+
amount: formatedAmount
|
|
72
|
+
});
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(`${apiUrl}/get_estimated?${params.toString()}`, {
|
|
75
|
+
headers: {
|
|
76
|
+
accept: 'application/json'
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new _SwapError.SwapError(_types.SwapErrorType.ERROR_FETCHING_QUOTE);
|
|
81
|
+
}
|
|
82
|
+
const resToAmount = await response.json();
|
|
83
|
+
const toAmount = toBNString(resToAmount, (0, _utils._getAssetDecimals)(toAsset));
|
|
84
|
+
const bnToAmount = new _bignumber.default(toAmount);
|
|
85
|
+
const walletFeeRate = 4 / 1000;
|
|
86
|
+
const toAmountBeforeFee = bnToAmount.dividedBy(new _bignumber.default(1 - walletFeeRate));
|
|
87
|
+
const walletFeeAmount = toAmountBeforeFee.multipliedBy(4).dividedBy(1000).toString();
|
|
88
|
+
return {
|
|
89
|
+
toAmount,
|
|
90
|
+
walletFeeAmount
|
|
91
|
+
};
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error('Error:', err);
|
|
94
|
+
throw new _SwapError.SwapError(_types.SwapErrorType.ERROR_FETCHING_QUOTE);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const createSwapRequest = async params => {
|
|
98
|
+
const fromDecimals = (0, _utils._getAssetDecimals)(params.fromAsset);
|
|
99
|
+
const toDecimals = (0, _utils._getAssetDecimals)(params.toAsset);
|
|
100
|
+
const formatedAmount = (0, _utils2.formatNumber)(params.fromAmount, fromDecimals, s => s);
|
|
101
|
+
const requestBody = {
|
|
102
|
+
fixed: false,
|
|
103
|
+
currency_from: params.fromSymbol,
|
|
104
|
+
currency_to: params.toSymbol,
|
|
105
|
+
amount: formatedAmount,
|
|
106
|
+
// Convert to small number due to require of api
|
|
107
|
+
address_to: params.receiver,
|
|
108
|
+
extra_id_to: '',
|
|
109
|
+
user_refund_address: params.sender,
|
|
110
|
+
user_refund_extra_id: ''
|
|
111
|
+
};
|
|
112
|
+
const response = await fetch(`${apiUrl}/create_exchange?api_key=${simpleSwapApiKey}`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
Accept: 'application/json'
|
|
117
|
+
},
|
|
118
|
+
body: JSON.stringify(requestBody)
|
|
119
|
+
});
|
|
120
|
+
const depositAddressResponse = await response.json();
|
|
121
|
+
return {
|
|
122
|
+
id: depositAddressResponse.id,
|
|
123
|
+
addressFrom: depositAddressResponse.address_from,
|
|
124
|
+
amountTo: toBNString(depositAddressResponse.amount_to, toDecimals)
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
class SimpleSwapHandler {
|
|
128
|
+
constructor(chainService, balanceService) {
|
|
129
|
+
this.swapBaseHandler = new _baseHandler.SwapBaseHandler({
|
|
130
|
+
chainService,
|
|
131
|
+
balanceService,
|
|
132
|
+
providerName: 'SimpleSwap',
|
|
133
|
+
providerSlug: _types.SwapProviderId.SIMPLE_SWAP
|
|
134
|
+
});
|
|
135
|
+
this.providerSlug = _types.SwapProviderId.SIMPLE_SWAP;
|
|
136
|
+
}
|
|
137
|
+
async validateSwapProcess(params) {
|
|
138
|
+
const amount = params.selectedQuote.fromAmount;
|
|
139
|
+
const bnAmount = BigInt(amount);
|
|
140
|
+
if (bnAmount <= BigInt(0)) {
|
|
141
|
+
return Promise.resolve([new _TransactionError.TransactionError(_types.BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')]);
|
|
142
|
+
}
|
|
143
|
+
let isXcmOk = false;
|
|
144
|
+
for (const [index, step] of params.process.steps.entries()) {
|
|
145
|
+
const getErrors = async () => {
|
|
146
|
+
switch (step.type) {
|
|
147
|
+
case _types.CommonStepType.DEFAULT:
|
|
148
|
+
return Promise.resolve([]);
|
|
149
|
+
case _types.CommonStepType.TOKEN_APPROVAL:
|
|
150
|
+
return Promise.reject(new _TransactionError.TransactionError(_types.BasicTxErrorType.UNSUPPORTED));
|
|
151
|
+
default:
|
|
152
|
+
return this.swapBaseHandler.validateSwapStep(params, isXcmOk, index);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const errors = await getErrors();
|
|
156
|
+
if (errors.length) {
|
|
157
|
+
return errors;
|
|
158
|
+
} else if (step.type === _types.CommonStepType.XCM) {
|
|
159
|
+
isXcmOk = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
get chainService() {
|
|
165
|
+
return this.swapBaseHandler.chainService;
|
|
166
|
+
}
|
|
167
|
+
get balanceService() {
|
|
168
|
+
return this.swapBaseHandler.balanceService;
|
|
169
|
+
}
|
|
170
|
+
get providerInfo() {
|
|
171
|
+
return this.swapBaseHandler.providerInfo;
|
|
172
|
+
}
|
|
173
|
+
get name() {
|
|
174
|
+
return this.swapBaseHandler.name;
|
|
175
|
+
}
|
|
176
|
+
get slug() {
|
|
177
|
+
return this.swapBaseHandler.slug;
|
|
178
|
+
}
|
|
179
|
+
async getSwapQuote(request) {
|
|
180
|
+
try {
|
|
181
|
+
var _metadata$maxSwap;
|
|
182
|
+
const fromAsset = this.chainService.getAssetBySlug(request.pair.from);
|
|
183
|
+
const toAsset = this.chainService.getAssetBySlug(request.pair.to);
|
|
184
|
+
if (!fromAsset || !toAsset) {
|
|
185
|
+
return new _SwapError.SwapError(_types.SwapErrorType.UNKNOWN);
|
|
186
|
+
}
|
|
187
|
+
const earlyValidation = await this.validateSwapRequest(request);
|
|
188
|
+
const metadata = earlyValidation.metadata;
|
|
189
|
+
if (earlyValidation.error) {
|
|
190
|
+
return (0, _swap._getSimpleSwapEarlyValidationError)(earlyValidation.error, metadata);
|
|
191
|
+
}
|
|
192
|
+
const {
|
|
193
|
+
toAmount,
|
|
194
|
+
walletFeeAmount
|
|
195
|
+
} = await getEstimate(request, fromAsset, toAsset);
|
|
196
|
+
const fromAmount = request.fromAmount;
|
|
197
|
+
const rate = (0, _utils3.calculateSwapRate)(request.fromAmount, toAmount, fromAsset, toAsset);
|
|
198
|
+
const fromChain = this.chainService.getChainInfoByKey(fromAsset.originChain);
|
|
199
|
+
const fromChainNativeTokenSlug = (0, _utils._getChainNativeTokenSlug)(fromChain);
|
|
200
|
+
const defaultFeeToken = (0, _utils._isNativeToken)(fromAsset) ? fromAsset.slug : fromChainNativeTokenSlug;
|
|
201
|
+
const chainType = (0, _utils._isChainSubstrateCompatible)(fromChain) ? _KoniTypes.ChainType.SUBSTRATE : _KoniTypes.ChainType.EVM;
|
|
202
|
+
let api;
|
|
203
|
+
if (chainType === _KoniTypes.ChainType.SUBSTRATE) {
|
|
204
|
+
api = this.chainService.getSubstrateApi(fromChain.slug);
|
|
205
|
+
} else {
|
|
206
|
+
api = this.chainService.getEvmApi(fromChain.slug);
|
|
207
|
+
}
|
|
208
|
+
const networkFeeAmount = await (0, _token.getTransferMockTxFee)(request.address, fromChain, fromAsset, api);
|
|
209
|
+
const networkFee = {
|
|
210
|
+
tokenSlug: fromChainNativeTokenSlug,
|
|
211
|
+
amount: networkFeeAmount.toString(),
|
|
212
|
+
feeType: _types.SwapFeeType.NETWORK_FEE
|
|
213
|
+
};
|
|
214
|
+
const walletFee = {
|
|
215
|
+
tokenSlug: toAsset.slug,
|
|
216
|
+
amount: walletFeeAmount,
|
|
217
|
+
feeType: _types.SwapFeeType.WALLET_FEE
|
|
218
|
+
};
|
|
219
|
+
return {
|
|
220
|
+
pair: request.pair,
|
|
221
|
+
fromAmount,
|
|
222
|
+
toAmount,
|
|
223
|
+
rate,
|
|
224
|
+
provider: this.providerInfo,
|
|
225
|
+
aliveUntil: +Date.now() + (_utils3.SWAP_QUOTE_TIMEOUT_MAP[this.slug] || _utils3.SWAP_QUOTE_TIMEOUT_MAP.default),
|
|
226
|
+
minSwap: toBNString(metadata.minSwap.value, (0, _utils._getAssetDecimals)(fromAsset)),
|
|
227
|
+
maxSwap: toBNString((_metadata$maxSwap = metadata.maxSwap) === null || _metadata$maxSwap === void 0 ? void 0 : _metadata$maxSwap.value, (0, _utils._getAssetDecimals)(fromAsset)),
|
|
228
|
+
estimatedArrivalTime: 3600,
|
|
229
|
+
isLowLiquidity: false,
|
|
230
|
+
feeInfo: {
|
|
231
|
+
feeComponent: [networkFee, walletFee],
|
|
232
|
+
defaultFeeToken,
|
|
233
|
+
feeOptions: [defaultFeeToken]
|
|
234
|
+
},
|
|
235
|
+
route: {
|
|
236
|
+
path: [fromAsset.slug, toAsset.slug]
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
} catch (e) {
|
|
240
|
+
return new _SwapError.SwapError(_types.SwapErrorType.UNKNOWN);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
generateOptimalProcess(params) {
|
|
244
|
+
return this.swapBaseHandler.generateOptimalProcess(params, [this.getSubmitStep]);
|
|
245
|
+
}
|
|
246
|
+
async getSubmitStep(params) {
|
|
247
|
+
if (params.selectedQuote) {
|
|
248
|
+
const submitStep = {
|
|
249
|
+
name: 'Swap',
|
|
250
|
+
type: _types.SwapStepType.SWAP
|
|
251
|
+
};
|
|
252
|
+
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]);
|
|
253
|
+
}
|
|
254
|
+
return Promise.resolve(undefined);
|
|
255
|
+
}
|
|
256
|
+
async validateSwapRequest(request) {
|
|
257
|
+
try {
|
|
258
|
+
const fromAsset = this.chainService.getAssetBySlug(request.pair.from);
|
|
259
|
+
const toAsset = this.chainService.getAssetBySlug(request.pair.to);
|
|
260
|
+
if (!fromAsset || !toAsset) {
|
|
261
|
+
return {
|
|
262
|
+
error: _types.SwapErrorType.ERROR_FETCHING_QUOTE
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const fromSymbol = _utils3.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING[fromAsset.slug];
|
|
266
|
+
const toSymbol = _utils3.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING[toAsset.slug];
|
|
267
|
+
if (!fromSymbol || !toSymbol) {
|
|
268
|
+
return {
|
|
269
|
+
error: _types.SwapErrorType.ASSET_NOT_SUPPORTED
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
const swapList = await fetchSwapList({
|
|
274
|
+
fromSymbol
|
|
275
|
+
});
|
|
276
|
+
if (!swapList.includes(toSymbol)) {
|
|
277
|
+
return {
|
|
278
|
+
error: _types.SwapErrorType.ASSET_NOT_SUPPORTED
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
} catch (err) {
|
|
282
|
+
console.error('Error:', err);
|
|
283
|
+
}
|
|
284
|
+
const ranges = await fetchRanges({
|
|
285
|
+
fromSymbol,
|
|
286
|
+
toSymbol
|
|
287
|
+
});
|
|
288
|
+
const {
|
|
289
|
+
max,
|
|
290
|
+
min
|
|
291
|
+
} = ranges;
|
|
292
|
+
const bnMin = toBNString(min, (0, _utils._getAssetDecimals)(fromAsset));
|
|
293
|
+
const bnAmount = BigInt(request.fromAmount);
|
|
294
|
+
if (bnAmount < BigInt(bnMin)) {
|
|
295
|
+
return {
|
|
296
|
+
error: _types.SwapErrorType.NOT_MEET_MIN_SWAP,
|
|
297
|
+
metadata: {
|
|
298
|
+
minSwap: {
|
|
299
|
+
value: min,
|
|
300
|
+
symbol: fromAsset.symbol
|
|
301
|
+
},
|
|
302
|
+
maxSwap: max ? {
|
|
303
|
+
value: max,
|
|
304
|
+
symbol: fromAsset.symbol
|
|
305
|
+
} : undefined,
|
|
306
|
+
chain: this.chainService.getChainInfoByKey(fromAsset.originChain)
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (max && bnAmount > BigInt(toBNString(max, (0, _utils._getAssetDecimals)(fromAsset)))) {
|
|
311
|
+
return {
|
|
312
|
+
error: _types.SwapErrorType.SWAP_EXCEED_ALLOWANCE,
|
|
313
|
+
metadata: {
|
|
314
|
+
minSwap: {
|
|
315
|
+
value: min,
|
|
316
|
+
symbol: fromAsset.symbol
|
|
317
|
+
},
|
|
318
|
+
maxSwap: {
|
|
319
|
+
value: max,
|
|
320
|
+
symbol: fromAsset.symbol
|
|
321
|
+
},
|
|
322
|
+
chain: this.chainService.getChainInfoByKey(fromAsset.originChain)
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
metadata: {
|
|
328
|
+
minSwap: {
|
|
329
|
+
value: min,
|
|
330
|
+
symbol: fromAsset.symbol
|
|
331
|
+
},
|
|
332
|
+
maxSwap: max ? {
|
|
333
|
+
value: max,
|
|
334
|
+
symbol: fromAsset.symbol
|
|
335
|
+
} : undefined,
|
|
336
|
+
chain: this.chainService.getChainInfoByKey(fromAsset.originChain)
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
} catch (e) {
|
|
340
|
+
console.error(e);
|
|
341
|
+
return {
|
|
342
|
+
error: _types.SwapErrorType.UNKNOWN
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
async handleSwapProcess(params) {
|
|
347
|
+
const {
|
|
348
|
+
currentStep,
|
|
349
|
+
process
|
|
350
|
+
} = params;
|
|
351
|
+
const type = process.steps[currentStep].type;
|
|
352
|
+
switch (type) {
|
|
353
|
+
case _types.CommonStepType.DEFAULT:
|
|
354
|
+
return Promise.reject(new _TransactionError.TransactionError(_types.BasicTxErrorType.UNSUPPORTED));
|
|
355
|
+
case _types.SwapStepType.SWAP:
|
|
356
|
+
return this.handleSubmitStep(params);
|
|
357
|
+
default:
|
|
358
|
+
return this.handleSubmitStep(params);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async handleSubmitStep(params) {
|
|
362
|
+
const {
|
|
363
|
+
address,
|
|
364
|
+
quote,
|
|
365
|
+
recipient
|
|
366
|
+
} = params;
|
|
367
|
+
const pair = quote.pair;
|
|
368
|
+
const fromAsset = this.chainService.getAssetBySlug(pair.from);
|
|
369
|
+
const toAsset = this.chainService.getAssetBySlug(pair.to);
|
|
370
|
+
const chainInfo = this.chainService.getChainInfoByKey(fromAsset.originChain);
|
|
371
|
+
const toChainInfo = this.chainService.getChainInfoByKey(toAsset.originChain);
|
|
372
|
+
const chainType = (0, _utils._isChainSubstrateCompatible)(chainInfo) ? _KoniTypes.ChainType.SUBSTRATE : _KoniTypes.ChainType.EVM;
|
|
373
|
+
const sender = (0, _utils2._reformatAddressWithChain)(address, chainInfo);
|
|
374
|
+
const receiver = (0, _utils2._reformatAddressWithChain)(recipient !== null && recipient !== void 0 ? recipient : sender, toChainInfo);
|
|
375
|
+
const fromSymbol = _utils3.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING[fromAsset.slug];
|
|
376
|
+
const toSymbol = _utils3.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING[toAsset.slug];
|
|
377
|
+
const {
|
|
378
|
+
fromAmount
|
|
379
|
+
} = quote;
|
|
380
|
+
const {
|
|
381
|
+
addressFrom,
|
|
382
|
+
amountTo,
|
|
383
|
+
id
|
|
384
|
+
} = await createSwapRequest({
|
|
385
|
+
fromSymbol,
|
|
386
|
+
toSymbol,
|
|
387
|
+
fromAmount,
|
|
388
|
+
fromAsset,
|
|
389
|
+
receiver,
|
|
390
|
+
sender,
|
|
391
|
+
toAsset
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Validate the amount to be swapped
|
|
395
|
+
const rate = (0, _bignumber.default)(amountTo).div((0, _bignumber.default)(quote.toAmount)).multipliedBy(100);
|
|
396
|
+
if (rate.lt(95)) {
|
|
397
|
+
throw new _SwapError.SwapError(_types.SwapErrorType.NOT_MEET_MIN_EXPECTED);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Can modify quote.toAmount to amountTo after confirm real amount received
|
|
401
|
+
|
|
402
|
+
const txData = {
|
|
403
|
+
id: id,
|
|
404
|
+
address,
|
|
405
|
+
provider: this.providerInfo,
|
|
406
|
+
quote: params.quote,
|
|
407
|
+
slippage: params.slippage,
|
|
408
|
+
recipient: receiver,
|
|
409
|
+
process: params.process
|
|
410
|
+
};
|
|
411
|
+
let extrinsic;
|
|
412
|
+
if (chainType === _KoniTypes.ChainType.SUBSTRATE) {
|
|
413
|
+
const chainApi = this.chainService.getSubstrateApi(chainInfo.slug);
|
|
414
|
+
const substrateApi = await chainApi.isReady;
|
|
415
|
+
const [submittableExtrinsic] = await (0, _token.createTransferExtrinsic)({
|
|
416
|
+
from: address,
|
|
417
|
+
networkKey: chainInfo.slug,
|
|
418
|
+
substrateApi,
|
|
419
|
+
to: addressFrom,
|
|
420
|
+
tokenInfo: fromAsset,
|
|
421
|
+
transferAll: false,
|
|
422
|
+
value: quote.fromAmount
|
|
423
|
+
});
|
|
424
|
+
extrinsic = submittableExtrinsic;
|
|
425
|
+
} else {
|
|
426
|
+
if ((0, _utils._isNativeToken)(fromAsset)) {
|
|
427
|
+
const [transactionConfig] = await (0, _smartContract.getEVMTransactionObject)(chainInfo, address, addressFrom, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));
|
|
428
|
+
extrinsic = transactionConfig;
|
|
429
|
+
} else {
|
|
430
|
+
const [transactionConfig] = await (0, _smartContract.getERC20TransactionObject)((0, _utils._getContractAddressOfToken)(fromAsset), chainInfo, address, addressFrom, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));
|
|
431
|
+
extrinsic = transactionConfig;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
txChain: fromAsset.originChain,
|
|
436
|
+
txData,
|
|
437
|
+
extrinsic,
|
|
438
|
+
transferNativeAmount: (0, _utils._isNativeToken)(fromAsset) ? quote.fromAmount : '0',
|
|
439
|
+
extrinsicType: _KoniTypes.ExtrinsicType.SWAP,
|
|
440
|
+
chainType
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
exports.SimpleSwapHandler = SimpleSwapHandler;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.SwapService = void 0;
|
|
6
|
+
exports._isChainSupportedByProvider = exports.SwapService = void 0;
|
|
7
7
|
var _SwapError = require("@subwallet/extension-base/background/errors/SwapError");
|
|
8
8
|
var _TransactionError = require("@subwallet/extension-base/background/errors/TransactionError");
|
|
9
9
|
var _types = require("@subwallet/extension-base/services/base/types");
|
|
@@ -16,9 +16,15 @@ var _serviceBase = require("@subwallet/extension-base/types/service-base");
|
|
|
16
16
|
var _swap = require("@subwallet/extension-base/types/swap");
|
|
17
17
|
var _utils2 = require("@subwallet/extension-base/utils");
|
|
18
18
|
var _rxjs = require("rxjs");
|
|
19
|
+
var _simpleswapHandler = require("./handler/simpleswap-handler");
|
|
19
20
|
// Copyright 2019-2022 @subwallet/extension-base
|
|
20
21
|
// SPDX-License-Identifier: Apache-2.0
|
|
21
22
|
|
|
23
|
+
const _isChainSupportedByProvider = (providerSlug, chain) => {
|
|
24
|
+
const supportedChains = _utils._PROVIDER_TO_SUPPORTED_PAIR_MAP[providerSlug];
|
|
25
|
+
return supportedChains ? supportedChains.includes(chain) : false;
|
|
26
|
+
};
|
|
27
|
+
exports._isChainSupportedByProvider = _isChainSupportedByProvider;
|
|
22
28
|
class SwapService {
|
|
23
29
|
swapPairSubject = new _rxjs.BehaviorSubject([]);
|
|
24
30
|
handlers = {};
|
|
@@ -35,7 +41,7 @@ class SwapService {
|
|
|
35
41
|
const swappingSrcChain = this.chainService.getAssetBySlug(request.pair.from).originChain;
|
|
36
42
|
await Promise.all(Object.values(this.handlers).map(async handler => {
|
|
37
43
|
// temporary solution to reduce number of requests to providers, will work as long as there's only 1 provider for 1 chain
|
|
38
|
-
if (!
|
|
44
|
+
if (!_isChainSupportedByProvider(handler.providerSlug, swappingSrcChain)) {
|
|
39
45
|
return;
|
|
40
46
|
}
|
|
41
47
|
if (handler.init && handler.isReady === false) {
|
|
@@ -122,7 +128,10 @@ class SwapService {
|
|
|
122
128
|
quoteError = (preferredErrorResp === null || preferredErrorResp === void 0 ? void 0 : preferredErrorResp.error) || (defaultErrorResp === null || defaultErrorResp === void 0 ? void 0 : defaultErrorResp.error);
|
|
123
129
|
} else {
|
|
124
130
|
var _selectedQuote;
|
|
125
|
-
selectedQuote = availableQuotes
|
|
131
|
+
selectedQuote = availableQuotes.find(quote => {
|
|
132
|
+
var _request$currentQuote;
|
|
133
|
+
return quote.provider.id === ((_request$currentQuote = request.currentQuote) === null || _request$currentQuote === void 0 ? void 0 : _request$currentQuote.id);
|
|
134
|
+
}) || availableQuotes[0];
|
|
126
135
|
aliveUntil = ((_selectedQuote = selectedQuote) === null || _selectedQuote === void 0 ? void 0 : _selectedQuote.aliveUntil) || +Date.now() + _utils.SWAP_QUOTE_TIMEOUT_MAP.default;
|
|
127
136
|
}
|
|
128
137
|
return {
|
|
@@ -156,6 +165,9 @@ class SwapService {
|
|
|
156
165
|
case _swap.SwapProviderId.ROCOCO_ASSET_HUB:
|
|
157
166
|
this.handlers[providerId] = new _assetHub.AssetHubSwapHandler(this.chainService, this.state.balanceService, 'rococo_assethub');
|
|
158
167
|
break;
|
|
168
|
+
case _swap.SwapProviderId.SIMPLE_SWAP:
|
|
169
|
+
this.handlers[providerId] = new _simpleswapHandler.SimpleSwapHandler(this.chainService, this.state.balanceService);
|
|
170
|
+
break;
|
|
159
171
|
default:
|
|
160
172
|
throw new Error('Unsupported provider');
|
|
161
173
|
}
|
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports._PROVIDER_TO_SUPPORTED_PAIR_MAP = exports.SWAP_QUOTE_TIMEOUT_MAP = exports.CHAIN_FLIP_TESTNET_EXPLORER = exports.CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING = exports.CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING = exports.CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING = exports.CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING = exports.CHAIN_FLIP_MAINNET_EXPLORER = void 0;
|
|
7
|
+
exports._PROVIDER_TO_SUPPORTED_PAIR_MAP = exports.SWAP_QUOTE_TIMEOUT_MAP = exports.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING = exports.SIMPLE_SWAP_EXPLORER = exports.CHAIN_FLIP_TESTNET_EXPLORER = exports.CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING = exports.CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING = exports.CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING = exports.CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING = exports.CHAIN_FLIP_MAINNET_EXPLORER = void 0;
|
|
8
8
|
exports.calculateSwapRate = calculateSwapRate;
|
|
9
9
|
exports.convertSwapRate = convertSwapRate;
|
|
10
10
|
exports.getChainflipBroker = getChainflipBroker;
|
|
@@ -24,6 +24,8 @@ const CHAIN_FLIP_TESTNET_EXPLORER = 'https://blocks-perseverance.chainflip.io';
|
|
|
24
24
|
exports.CHAIN_FLIP_TESTNET_EXPLORER = CHAIN_FLIP_TESTNET_EXPLORER;
|
|
25
25
|
const CHAIN_FLIP_MAINNET_EXPLORER = 'https://scan.chainflip.io';
|
|
26
26
|
exports.CHAIN_FLIP_MAINNET_EXPLORER = CHAIN_FLIP_MAINNET_EXPLORER;
|
|
27
|
+
const SIMPLE_SWAP_EXPLORER = 'https://simpleswap.io';
|
|
28
|
+
exports.SIMPLE_SWAP_EXPLORER = SIMPLE_SWAP_EXPLORER;
|
|
27
29
|
const CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING = {
|
|
28
30
|
[_chainList.COMMON_CHAIN_SLUGS.POLKADOT]: _swap.Chains.Polkadot,
|
|
29
31
|
[_chainList.COMMON_CHAIN_SLUGS.ETHEREUM]: _swap.Chains.Ethereum,
|
|
@@ -48,6 +50,14 @@ const CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING = {
|
|
|
48
50
|
[_chainList.COMMON_ASSETS.USDC_SEPOLIA]: _swap.Assets.USDC
|
|
49
51
|
};
|
|
50
52
|
exports.CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING = CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING;
|
|
53
|
+
const SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING = {
|
|
54
|
+
'bittensor-NATIVE-TAO': 'tao',
|
|
55
|
+
[_chainList.COMMON_ASSETS.ETH]: 'eth',
|
|
56
|
+
[_chainList.COMMON_ASSETS.DOT]: 'dot',
|
|
57
|
+
[_chainList.COMMON_ASSETS.USDC_ETHEREUM]: 'usdc',
|
|
58
|
+
[_chainList.COMMON_ASSETS.USDT_ETHEREUM]: 'usdterc20'
|
|
59
|
+
};
|
|
60
|
+
exports.SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING = SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING;
|
|
51
61
|
const SWAP_QUOTE_TIMEOUT_MAP = {
|
|
52
62
|
// in milliseconds
|
|
53
63
|
default: 30000,
|
|
@@ -62,7 +72,8 @@ const _PROVIDER_TO_SUPPORTED_PAIR_MAP = {
|
|
|
62
72
|
[_swap2.SwapProviderId.CHAIN_FLIP_TESTNET]: [_chainList.COMMON_CHAIN_SLUGS.CHAINFLIP_POLKADOT, _chainList.COMMON_CHAIN_SLUGS.ETHEREUM_SEPOLIA],
|
|
63
73
|
[_swap2.SwapProviderId.POLKADOT_ASSET_HUB]: [_chainList.COMMON_CHAIN_SLUGS.POLKADOT_ASSET_HUB],
|
|
64
74
|
[_swap2.SwapProviderId.KUSAMA_ASSET_HUB]: [_chainList.COMMON_CHAIN_SLUGS.KUSAMA_ASSET_HUB],
|
|
65
|
-
[_swap2.SwapProviderId.ROCOCO_ASSET_HUB]: [_chainList.COMMON_CHAIN_SLUGS.ROCOCO_ASSET_HUB]
|
|
75
|
+
[_swap2.SwapProviderId.ROCOCO_ASSET_HUB]: [_chainList.COMMON_CHAIN_SLUGS.ROCOCO_ASSET_HUB],
|
|
76
|
+
[_swap2.SwapProviderId.SIMPLE_SWAP]: ['bittensor', _chainList.COMMON_CHAIN_SLUGS.ETHEREUM, _chainList.COMMON_CHAIN_SLUGS.POLKADOT]
|
|
66
77
|
};
|
|
67
78
|
exports._PROVIDER_TO_SUPPORTED_PAIR_MAP = _PROVIDER_TO_SUPPORTED_PAIR_MAP;
|
|
68
79
|
function getSwapAlternativeAsset(swapPair) {
|
|
@@ -1063,7 +1063,7 @@ class TransactionService {
|
|
|
1063
1063
|
}
|
|
1064
1064
|
return emitter;
|
|
1065
1065
|
}
|
|
1066
|
-
|
|
1066
|
+
signAndSendSubstrateTransaction(_ref10) {
|
|
1067
1067
|
let {
|
|
1068
1068
|
address,
|
|
1069
1069
|
chain,
|
|
@@ -1079,8 +1079,9 @@ class TransactionService {
|
|
|
1079
1079
|
extrinsicHash: id
|
|
1080
1080
|
};
|
|
1081
1081
|
const extrinsic = transaction;
|
|
1082
|
-
const registry = extrinsic.registry;
|
|
1083
|
-
const signedExtensions = registry.signedExtensions;
|
|
1082
|
+
// const registry = extrinsic.registry;
|
|
1083
|
+
// const signedExtensions = registry.signedExtensions;
|
|
1084
|
+
|
|
1084
1085
|
const signerOption = {
|
|
1085
1086
|
signer: {
|
|
1086
1087
|
signPayload: async payload => {
|
|
@@ -1097,13 +1098,16 @@ class TransactionService {
|
|
|
1097
1098
|
},
|
|
1098
1099
|
withSignedTransaction: true
|
|
1099
1100
|
};
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1101
|
+
|
|
1102
|
+
// if (_isRuntimeUpdated(signedExtensions)) {
|
|
1103
|
+
// const metadataHash = await this.state.chainService.calculateMetadataHash(chain);
|
|
1104
|
+
//
|
|
1105
|
+
// if (metadataHash) {
|
|
1106
|
+
// signerOption.mode = 1;
|
|
1107
|
+
// signerOption.metadataHash = metadataHash;
|
|
1108
|
+
// }
|
|
1109
|
+
// }
|
|
1110
|
+
|
|
1107
1111
|
extrinsic.signAsync(address, signerOption).then(async rs => {
|
|
1108
1112
|
// Emit signed event
|
|
1109
1113
|
emitter.emit('signed', eventData);
|