@subwallet/extension-base 1.3.29-1 → 1.3.31-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.
Files changed (142) hide show
  1. package/background/KoniTypes.d.ts +16 -4
  2. package/background/errors/SwapError.js +1 -1
  3. package/cjs/background/errors/SwapError.js +1 -1
  4. package/cjs/constants/blocked-actions.js +2 -2
  5. package/cjs/constants/paraspell-chain-map.js +13 -0
  6. package/cjs/constants/remind-notification-time.js +3 -3
  7. package/cjs/core/logic-validation/swap.js +63 -4
  8. package/cjs/core/logic-validation/transfer.js +13 -1
  9. package/cjs/core/substrate/xcm-parser.js +5 -1
  10. package/cjs/core/utils.js +36 -15
  11. package/cjs/koni/background/handlers/Extension.js +141 -172
  12. package/cjs/koni/background/handlers/State.js +8 -1
  13. package/cjs/packageInfo.js +1 -1
  14. package/cjs/services/balance-service/helpers/process.js +27 -0
  15. package/cjs/services/balance-service/index.js +9 -0
  16. package/cjs/services/balance-service/transfer/xcm/acrossBridge/index.js +229 -0
  17. package/cjs/services/balance-service/transfer/xcm/availBridge.js +6 -6
  18. package/cjs/services/balance-service/transfer/xcm/index.js +96 -7
  19. package/cjs/services/balance-service/transfer/xcm/utils.js +213 -0
  20. package/cjs/services/chain-service/constants.js +2 -4
  21. package/cjs/services/chain-service/index.js +71 -17
  22. package/cjs/services/chain-service/utils/patch.js +1 -1
  23. package/cjs/services/earning-service/handlers/base.js +6 -3
  24. package/cjs/services/earning-service/handlers/native-staking/base.js +4 -1
  25. package/cjs/services/earning-service/handlers/native-staking/dtao.js +68 -50
  26. package/cjs/services/earning-service/handlers/native-staking/tao.js +12 -2
  27. package/cjs/services/earning-service/handlers/special.js +18 -9
  28. package/cjs/services/earning-service/service.js +2 -1
  29. package/cjs/services/fee-service/utils/index.js +16 -4
  30. package/cjs/services/inapp-notification-service/index.js +19 -13
  31. package/cjs/services/keyring-service/context/handlers/Ledger.js +1 -1
  32. package/cjs/services/keyring-service/context/state.js +3 -0
  33. package/cjs/services/migration-service/scripts/DisableZeroBalanceTokens.js +60 -0
  34. package/cjs/services/migration-service/scripts/EnableChain.js +1 -1
  35. package/cjs/services/migration-service/scripts/index.js +3 -2
  36. package/cjs/services/swap-service/handler/asset-hub/handler.js +61 -314
  37. package/cjs/services/swap-service/handler/base-handler.js +406 -231
  38. package/cjs/services/swap-service/handler/chainflip-handler.js +18 -40
  39. package/cjs/services/swap-service/handler/hydradx-handler.js +77 -269
  40. package/cjs/services/swap-service/handler/simpleswap-handler.js +27 -48
  41. package/cjs/services/swap-service/handler/uniswap-handler.js +33 -54
  42. package/cjs/services/swap-service/index.js +154 -143
  43. package/cjs/services/swap-service/utils.js +107 -17
  44. package/cjs/services/transaction-service/index.js +1 -1
  45. package/cjs/services/transaction-service/utils.js +38 -14
  46. package/cjs/types/swap/index.js +13 -1
  47. package/cjs/utils/fee/transfer.js +52 -28
  48. package/cjs/utils/staticData/index.js +7 -2
  49. package/cjs/utils/swap.js +5 -1
  50. package/constants/blocked-actions.d.ts +1 -1
  51. package/constants/blocked-actions.js +1 -1
  52. package/constants/paraspell-chain-map.d.ts +1 -0
  53. package/constants/paraspell-chain-map.js +7 -0
  54. package/constants/remind-notification-time.d.ts +1 -1
  55. package/constants/remind-notification-time.js +1 -1
  56. package/core/logic-validation/swap.d.ts +15 -0
  57. package/core/logic-validation/swap.js +60 -4
  58. package/core/logic-validation/transfer.d.ts +1 -0
  59. package/core/logic-validation/transfer.js +12 -1
  60. package/core/substrate/xcm-parser.d.ts +1 -0
  61. package/core/substrate/xcm-parser.js +4 -1
  62. package/core/utils.d.ts +2 -2
  63. package/core/utils.js +36 -15
  64. package/koni/background/handlers/Extension.d.ts +1 -1
  65. package/koni/background/handlers/Extension.js +66 -98
  66. package/koni/background/handlers/State.d.ts +1 -0
  67. package/koni/background/handlers/State.js +7 -1
  68. package/package.json +23 -13
  69. package/packageInfo.js +1 -1
  70. package/services/balance-service/helpers/process.d.ts +2 -1
  71. package/services/balance-service/helpers/process.js +26 -0
  72. package/services/balance-service/index.js +11 -2
  73. package/services/balance-service/transfer/xcm/acrossBridge/index.d.ts +15 -0
  74. package/services/balance-service/transfer/xcm/acrossBridge/index.js +216 -0
  75. package/services/balance-service/transfer/xcm/availBridge.js +6 -6
  76. package/services/balance-service/transfer/xcm/index.d.ts +5 -1
  77. package/services/balance-service/transfer/xcm/index.js +85 -1
  78. package/services/balance-service/transfer/xcm/utils.d.ts +11 -0
  79. package/services/balance-service/transfer/xcm/utils.js +208 -0
  80. package/services/base/types.d.ts +0 -4
  81. package/services/chain-service/constants.d.ts +0 -1
  82. package/services/chain-service/constants.js +1 -2
  83. package/services/chain-service/index.d.ts +9 -2
  84. package/services/chain-service/index.js +72 -18
  85. package/services/chain-service/utils/patch.js +1 -1
  86. package/services/earning-service/handlers/base.d.ts +4 -3
  87. package/services/earning-service/handlers/base.js +6 -4
  88. package/services/earning-service/handlers/native-staking/base.js +4 -1
  89. package/services/earning-service/handlers/native-staking/dtao.d.ts +9 -6
  90. package/services/earning-service/handlers/native-staking/dtao.js +69 -48
  91. package/services/earning-service/handlers/native-staking/tao.js +12 -2
  92. package/services/earning-service/handlers/special.js +19 -10
  93. package/services/earning-service/service.d.ts +2 -1
  94. package/services/earning-service/service.js +2 -1
  95. package/services/fee-service/utils/index.d.ts +1 -0
  96. package/services/fee-service/utils/index.js +14 -4
  97. package/services/inapp-notification-service/index.js +13 -7
  98. package/services/keyring-service/context/handlers/Ledger.js +1 -1
  99. package/services/keyring-service/context/state.d.ts +1 -0
  100. package/services/keyring-service/context/state.js +3 -0
  101. package/services/migration-service/scripts/DisableZeroBalanceTokens.d.ts +4 -0
  102. package/services/migration-service/scripts/DisableZeroBalanceTokens.js +51 -0
  103. package/services/migration-service/scripts/EnableChain.js +1 -1
  104. package/services/migration-service/scripts/index.js +3 -2
  105. package/services/swap-service/handler/asset-hub/handler.d.ts +2 -9
  106. package/services/swap-service/handler/asset-hub/handler.js +64 -317
  107. package/services/swap-service/handler/base-handler.d.ts +6 -9
  108. package/services/swap-service/handler/base-handler.js +405 -230
  109. package/services/swap-service/handler/chainflip-handler.d.ts +2 -4
  110. package/services/swap-service/handler/chainflip-handler.js +15 -37
  111. package/services/swap-service/handler/hydradx-handler.d.ts +3 -10
  112. package/services/swap-service/handler/hydradx-handler.js +78 -270
  113. package/services/swap-service/handler/simpleswap-handler.d.ts +2 -4
  114. package/services/swap-service/handler/simpleswap-handler.js +24 -45
  115. package/services/swap-service/handler/uniswap-handler.d.ts +4 -6
  116. package/services/swap-service/handler/uniswap-handler.js +25 -46
  117. package/services/swap-service/index.d.ts +8 -14
  118. package/services/swap-service/index.js +141 -129
  119. package/services/swap-service/utils.d.ts +11 -3
  120. package/services/swap-service/utils.js +96 -15
  121. package/services/transaction-service/index.js +2 -2
  122. package/services/transaction-service/types.d.ts +3 -2
  123. package/services/transaction-service/utils.d.ts +1 -0
  124. package/services/transaction-service/utils.js +38 -15
  125. package/types/balance/transfer.d.ts +1 -0
  126. package/types/service-base.d.ts +2 -3
  127. package/types/swap/index.d.ts +25 -9
  128. package/types/swap/index.js +10 -0
  129. package/types/transaction/process.d.ts +19 -0
  130. package/types/transaction/request.d.ts +7 -0
  131. package/types/yield/actions/join/submit.d.ts +4 -1
  132. package/types/yield/actions/others.d.ts +2 -0
  133. package/utils/fee/transfer.d.ts +1 -0
  134. package/utils/fee/transfer.js +54 -30
  135. package/utils/staticData/index.d.ts +4 -1
  136. package/utils/staticData/index.js +5 -1
  137. package/utils/staticData/paraSpellChainMap.json +1 -0
  138. package/utils/swap.d.ts +3 -0
  139. package/utils/swap.js +3 -0
  140. package/cjs/services/swap-service/interface.js +0 -14
  141. package/services/swap-service/interface.d.ts +0 -9
  142. package/services/swap-service/interface.js +0 -8
@@ -1,26 +1,28 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
5
+ import { _AssetRefPath } from '@subwallet/chain-list/types';
4
6
  import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
5
7
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
8
+ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
9
+ import { fetchBlockedConfigObjects, fetchLatestBlockedActionsAndFeatures, getPassConfigId } from '@subwallet/extension-base/constants';
6
10
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
7
11
  import { _getAssetOriginChain, _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils';
8
12
  import { AssetHubSwapHandler } from '@subwallet/extension-base/services/swap-service/handler/asset-hub';
9
13
  import { ChainflipSwapHandler } from '@subwallet/extension-base/services/swap-service/handler/chainflip-handler';
10
14
  import { HydradxHandler } from '@subwallet/extension-base/services/swap-service/handler/hydradx-handler';
11
- import { _PROVIDER_TO_SUPPORTED_PAIR_MAP, findXcmDestination, getBridgeStep, getSwapAltToken, getSwapStep, isChainsHasSameProvider, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
12
- import { BasicTxErrorType } from '@subwallet/extension-base/types';
15
+ import { findAllBridgeDestinations, findBridgeTransitDestination, findSwapTransitDestination, getBridgeStep, getSupportSwapChain, getSwapAltToken, getSwapStep, getTokenPairFromStep, isChainsHasSameProvider, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
16
+ import { BasicTxErrorType, DynamicSwapType } from '@subwallet/extension-base/types';
13
17
  import { DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
14
18
  import { _SUPPORTED_SWAP_PROVIDERS, SwapErrorType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
15
- import { createPromiseHandler, reformatAddress } from '@subwallet/extension-base/utils';
19
+ import { _reformatAddressWithChain, createPromiseHandler, reformatAddress } from '@subwallet/extension-base/utils';
16
20
  import subwalletApiSdk from '@subwallet/subwallet-api-sdk';
21
+ import BigN from 'bignumber.js';
22
+ import { t } from 'i18next';
17
23
  import { BehaviorSubject } from 'rxjs';
18
24
  import { SimpleSwapHandler } from "./handler/simpleswap-handler.js";
19
25
  import { UniswapHandler } from "./handler/uniswap-handler.js";
20
- export const _isChainSupportedByProvider = (providerSlug, chain) => {
21
- const supportedChains = _PROVIDER_TO_SUPPORTED_PAIR_MAP[providerSlug];
22
- return supportedChains ? supportedChains.includes(chain) : false;
23
- };
24
26
  export class SwapService {
25
27
  swapPairSubject = new BehaviorSubject([]);
26
28
  handlers = {};
@@ -35,13 +37,6 @@ export class SwapService {
35
37
  async askProvidersForQuote(request) {
36
38
  var _subwalletApiSdk$swap;
37
39
  const availableQuotes = [];
38
- await Promise.all(Object.values(this.handlers).map(async handler => {
39
- // temporary solution to reduce number of requests to providers, will work as long as there's only 1 provider for 1 chain
40
-
41
- if (handler.init && handler.isReady === false) {
42
- await handler.init();
43
- }
44
- }));
45
40
  const quotes = await ((_subwalletApiSdk$swap = subwalletApiSdk.swapApi) === null || _subwalletApiSdk$swap === void 0 ? void 0 : _subwalletApiSdk$swap.fetchSwapQuoteData(request));
46
41
  if (Array.isArray(quotes)) {
47
42
  quotes.forEach(quoteData => {
@@ -61,32 +56,17 @@ export class SwapService {
61
56
  }
62
57
  return availableQuotes;
63
58
  }
64
- getDefaultProcess(params) {
65
- const result = {
66
- totalFee: [MOCK_STEP_FEE],
67
- steps: [DEFAULT_FIRST_STEP],
68
- path: []
69
- };
70
- result.totalFee.push({
71
- feeComponent: [],
72
- feeOptions: [params.request.pair.from],
73
- defaultFeeToken: params.request.pair.from
74
- });
75
- result.steps.push({
76
- id: result.steps.length,
77
- name: 'Swap',
78
- type: SwapStepType.SWAP
79
- });
80
- return result;
81
- }
82
59
  getDefaultProcessV2(params) {
83
60
  const result = {
84
61
  totalFee: [MOCK_STEP_FEE],
85
62
  steps: [DEFAULT_FIRST_STEP],
86
63
  path: []
87
64
  };
88
- const swapPairInfo = params.path[0].pair; // todo: improve for Round 2
89
-
65
+ const swapPairInfo = params.path.find(action => action.action === DynamicSwapType.SWAP);
66
+ if (!swapPairInfo) {
67
+ console.error('Swap pair is not found');
68
+ return result;
69
+ }
90
70
  result.totalFee.push({
91
71
  feeComponent: [],
92
72
  feeOptions: [params.request.pair.from],
@@ -98,34 +78,18 @@ export class SwapService {
98
78
  type: SwapStepType.SWAP,
99
79
  metadata: {
100
80
  sendingValue: params.request.fromAmount.toString(),
101
- originTokenInfo: this.chainService.getAssetBySlug(swapPairInfo.from),
102
- destinationTokenInfo: this.chainService.getAssetBySlug(swapPairInfo.to)
81
+ originTokenInfo: this.chainService.getAssetBySlug(swapPairInfo.pair.from),
82
+ destinationTokenInfo: this.chainService.getAssetBySlug(swapPairInfo.pair.to)
103
83
  }
104
84
  });
105
85
  return result;
106
86
  }
107
-
108
- // deprecated
109
- async generateOptimalProcess(params) {
110
- if (!params.selectedQuote) {
111
- return this.getDefaultProcess(params);
112
- } else {
113
- var _params$request$curre;
114
- const providerId = ((_params$request$curre = params.request.currentQuote) === null || _params$request$curre === void 0 ? void 0 : _params$request$curre.id) || params.selectedQuote.provider.id;
115
- const handler = this.handlers[providerId];
116
- if (handler) {
117
- return handler.generateOptimalProcess(params);
118
- } else {
119
- return this.getDefaultProcess(params);
120
- }
121
- }
122
- }
123
87
  async generateOptimalProcessV2(params) {
124
88
  if (!params.selectedQuote) {
125
89
  return this.getDefaultProcessV2(params);
126
90
  } else {
127
- var _params$request$curre2;
128
- const providerId = ((_params$request$curre2 = params.request.currentQuote) === null || _params$request$curre2 === void 0 ? void 0 : _params$request$curre2.id) || params.selectedQuote.provider.id;
91
+ var _params$request$curre;
92
+ const providerId = ((_params$request$curre = params.request.currentQuote) === null || _params$request$curre === void 0 ? void 0 : _params$request$curre.id) || params.selectedQuote.provider.id;
129
93
  const handler = this.handlers[providerId];
130
94
  if (handler) {
131
95
  return handler.generateOptimalProcessV2(params);
@@ -134,48 +98,6 @@ export class SwapService {
134
98
  }
135
99
  }
136
100
  }
137
- async generateOptimalProcessWithoutPath(params) {
138
- var _params$request$curre3;
139
- if (!params.selectedQuote || params.path.length > 0) {
140
- return this.getDefaultProcessV2(params);
141
- }
142
- const [path, directSwapRequest] = this.getAvailablePath(params.request);
143
- if (!directSwapRequest) {
144
- return this.getDefaultProcessV2(params);
145
- }
146
- params.path = path;
147
- const providerId = ((_params$request$curre3 = params.request.currentQuote) === null || _params$request$curre3 === void 0 ? void 0 : _params$request$curre3.id) || params.selectedQuote.provider.id;
148
- const handler = this.handlers[providerId];
149
- if (handler) {
150
- return handler.generateOptimalProcessV2(params);
151
- } else {
152
- return this.getDefaultProcessV2(params);
153
- }
154
- }
155
-
156
- // deprecated
157
- // eslint-disable-next-line @typescript-eslint/require-await
158
- async handleSwapRequest(request) {
159
- /*
160
- * 1. Ask swap quotes from providers
161
- * 2. Select the best quote
162
- * 3. Generate optimal process for that quote
163
- * */
164
-
165
- // const swapQuoteResponse = await this.getLatestDirectQuotes(request);
166
-
167
- // const optimalProcess = await this.generateOptimalProcess({
168
- // request,
169
- // selectedQuote: swapQuoteResponse.optimalQuote
170
- // });
171
-
172
- return {
173
- // @ts-ignore
174
- process: null,
175
- // @ts-ignore
176
- quote: null
177
- };
178
- }
179
101
  async handleSwapRequestV2(request) {
180
102
  /*
181
103
  * 1. Find available path
@@ -184,14 +106,6 @@ export class SwapService {
184
106
  * 4. Generate optimal process for that quote
185
107
  * */
186
108
 
187
- // todo: path will become a list of path in Round 2
188
- // const [path, directSwapRequest] = this.getAvailablePath(request);
189
- //
190
- // if (!directSwapRequest) {
191
- // throw Error('Swap pair not found');
192
- // }
193
-
194
- // const swapQuoteResponse = await this.getLatestDirectQuotes(directSwapRequest);
195
109
  const {
196
110
  path,
197
111
  swapQuoteResponse
@@ -201,63 +115,131 @@ export class SwapService {
201
115
  selectedQuote: swapQuoteResponse.optimalQuote,
202
116
  path
203
117
  });
118
+ console.log('-------');
119
+ console.log('optimalProcess', optimalProcess);
120
+ console.log('-------');
121
+ if (optimalProcess.steps.length - 1 < optimalProcess.path.length) {
122
+ // minus the fill info step
123
+ throw new Error('Swap pair is not found');
124
+ }
204
125
  return {
205
126
  process: optimalProcess,
206
127
  quote: swapQuoteResponse
207
128
  };
208
129
  }
130
+
131
+ // todo: rewrite this function
209
132
  getAvailablePath(request) {
210
133
  const {
134
+ address,
211
135
  pair
212
136
  } = request;
213
137
  // todo: control provider tighter
214
- const allSupportedChainsBySwapProvider = [...new Set(Object.values(_PROVIDER_TO_SUPPORTED_PAIR_MAP).flat())];
138
+ const supportSwapChains = getSupportSwapChain();
215
139
  const fromToken = this.chainService.getAssetBySlug(pair.from);
216
140
  const toToken = this.chainService.getAssetBySlug(pair.to);
217
141
  const fromChain = _getAssetOriginChain(fromToken);
218
142
  const toChain = _getAssetOriginChain(toToken);
219
143
  const toChainInfo = this.chainService.getChainInfoByKey(toChain);
220
- const process = [];
144
+ const assetRefMap = this.chainService.getAssetRefMap();
145
+ let process = [];
221
146
  if (!fromToken || !toToken) {
222
147
  throw Error('Token not found');
223
148
  }
224
149
  if (!fromChain || !toChain) {
225
150
  throw Error('Token metadata error');
226
151
  }
152
+ const directXcmRef = Object.values(assetRefMap).find(assetRef => assetRef.path === _AssetRefPath.XCM && assetRef.srcAsset === fromToken.slug && assetRef.destAsset === toToken.slug);
153
+ if (directXcmRef) {
154
+ return [[], undefined];
155
+ }
227
156
 
228
157
  // SWAP: 2 tokens in the same chain and chain has dex
229
158
  if (isChainsHasSameProvider(fromChain, toChain)) {
230
159
  // there's a dex that can support direct swapping
231
- const swapStep = getSwapStep(fromToken.slug, toToken.slug);
160
+ process.push(getSwapStep(fromToken.slug, toToken.slug));
161
+ return [process, request];
162
+ }
163
+
164
+ // ------------------------
165
+ // BRIDGE -> SWAP: Try to find a token in dest chain that can bridge from fromToken
166
+ const bridgeTransit = findBridgeTransitDestination(assetRefMap, fromToken, toToken);
167
+ if (bridgeTransit && supportSwapChains.includes(toChain)) {
168
+ const swapStep = getSwapStep(bridgeTransit, toToken.slug);
169
+ process.push(getBridgeStep(fromToken.slug, bridgeTransit));
232
170
  process.push(swapStep);
233
171
  return [process, {
234
172
  ...request,
173
+ address: reformatAddress(address, _getChainSubstrateAddressPrefix(toChainInfo)),
235
174
  pair: swapStep.pair
236
175
  }];
237
176
  }
238
177
 
239
- // BRIDGE -> SWAP: Try to find a token in dest chain that can bridge from fromToken
240
- const bridgeDestination = findXcmDestination(this.chainService.getAssetRefMap(), fromToken, toChain);
241
- if (bridgeDestination && allSupportedChainsBySwapProvider.includes(toChain)) {
242
- const bridgeStep = getBridgeStep(fromToken.slug, bridgeDestination);
243
- const swapStep = getSwapStep(bridgeDestination, toToken.slug);
244
- process.push(bridgeStep);
178
+ // ------------------------
179
+ // SWAP -> BRIDGE: Try to find a token in from chain that can bridge to toToken
180
+ const swapTransit = findSwapTransitDestination(assetRefMap, fromToken, toToken);
181
+ if (swapTransit && supportSwapChains.includes(fromChain)) {
182
+ const swapStep = getSwapStep(fromToken.slug, swapTransit);
245
183
  process.push(swapStep);
184
+ process.push(getBridgeStep(swapTransit, toToken.slug));
246
185
  return [process, {
247
186
  ...request,
248
- address: reformatAddress(request.address, _getChainSubstrateAddressPrefix(toChainInfo)),
249
187
  pair: swapStep.pair
250
188
  }];
251
189
  }
252
190
 
253
- // todo: improve to support SWAP -> BRIDGE and BRIDGE -> SWAP -> BRIDGE
191
+ // ------------------------
192
+ // BRIDGE -> SWAP -> BRIDGE: Try to find a tri-step path to swap
193
+ const processList = [];
194
+ const swapPairList = [];
195
+ const allBridgeDestinations = findAllBridgeDestinations(assetRefMap, fromToken);
196
+
197
+ // currently find first path. Todo: return all paths or best path.
198
+ for (const bridgeTransit of allBridgeDestinations) {
199
+ process = [];
200
+ const bridgeDestinationInfo = this.chainService.getAssetBySlug(bridgeTransit);
201
+ const swapTransit = findSwapTransitDestination(assetRefMap, bridgeDestinationInfo, toToken);
202
+ if (bridgeTransit === swapTransit) {
203
+ continue;
204
+ }
205
+ if (swapTransit && supportSwapChains.includes(bridgeDestinationInfo.originChain)) {
206
+ const swapStep = getSwapStep(bridgeTransit, swapTransit);
207
+ process.push(getBridgeStep(fromToken.slug, bridgeTransit));
208
+ process.push(swapStep);
209
+ process.push(getBridgeStep(swapTransit, toToken.slug));
210
+
211
+ // set the highest priority to hydration provider
212
+ if (bridgeDestinationInfo.originChain === COMMON_CHAIN_SLUGS.HYDRADX) {
213
+ return [process, {
214
+ ...request,
215
+ address: _reformatAddressWithChain(address, this.chainService.getChainInfoByKey(COMMON_CHAIN_SLUGS.HYDRADX)),
216
+ pair: swapStep.pair
217
+ }];
218
+ }
219
+ processList.push(process);
220
+ swapPairList.push(swapStep.pair);
221
+ }
222
+ }
223
+
224
+ // get first process
225
+ if (processList.length && swapPairList.length) {
226
+ const [firstProcess, firstSwapPair] = [processList[0], swapPairList[0]];
227
+ const chainSwap = this.chainService.getAssetBySlug(firstSwapPair.from).originChain;
228
+ return [firstProcess, {
229
+ ...request,
230
+ address: _reformatAddressWithChain(address, this.chainService.getChainInfoByKey(chainSwap)),
231
+ pair: firstSwapPair
232
+ }];
233
+ }
234
+
235
+ // todo: encapsulate each route type to function
254
236
 
255
237
  return [[], undefined];
256
238
  }
257
239
  async getLatestQuoteFromSwapRequest(request) {
258
240
  const [path, directSwapRequest] = this.getAvailablePath(request);
259
241
  if (!directSwapRequest) {
260
- throw Error('Swap pair not found');
242
+ throw Error('Swap pair is not found');
261
243
  }
262
244
  const swapQuoteResponse = await this.getLatestDirectQuotes(directSwapRequest);
263
245
  return {
@@ -284,12 +266,32 @@ export class SwapService {
284
266
  quoteError = (preferredErrorResp === null || preferredErrorResp === void 0 ? void 0 : preferredErrorResp.error) || (defaultErrorResp === null || defaultErrorResp === void 0 ? void 0 : defaultErrorResp.error);
285
267
  } else {
286
268
  var _selectedQuote;
287
- selectedQuote = availableQuotes.find(quote => {
288
- var _request$currentQuote;
289
- return quote.provider.id === ((_request$currentQuote = request.currentQuote) === null || _request$currentQuote === void 0 ? void 0 : _request$currentQuote.id);
290
- }) || availableQuotes[0]; // todo: choose best quote based on rate
269
+ // sort quotes by largest receivable, with priority for some providers
270
+ availableQuotes.sort((a, b) => {
271
+ const bnToAmountA = BigN(a.toAmount);
272
+ const bnToAmountB = BigN(b.toAmount);
273
+ if (bnToAmountB.eq(bnToAmountA) && [SwapProviderId.CHAIN_FLIP_MAINNET, SwapProviderId.UNISWAP].includes(a.provider.id)) {
274
+ return -1;
275
+ }
276
+ if (bnToAmountA.gt(bnToAmountB)) {
277
+ return -1;
278
+ } else {
279
+ return 1;
280
+ }
281
+ });
282
+ if (request.preferredProvider) {
283
+ selectedQuote = availableQuotes.find(quote => quote.provider.id === request.preferredProvider) || availableQuotes[0];
284
+ } else {
285
+ selectedQuote = availableQuotes[0];
286
+ }
291
287
  aliveUntil = ((_selectedQuote = selectedQuote) === null || _selectedQuote === void 0 ? void 0 : _selectedQuote.aliveUntil) || +Date.now() + SWAP_QUOTE_TIMEOUT_MAP.default;
292
288
  }
289
+ const neededProviders = availableQuotes.map(quote => quote.provider.id);
290
+ await Promise.all(Object.values(this.handlers).map(async handler => {
291
+ if (neededProviders.includes(handler.providerSlug) && handler.init && handler.isReady === false) {
292
+ await handler.init();
293
+ }
294
+ }));
293
295
  return {
294
296
  optimalQuote: selectedQuote,
295
297
  quotes: availableQuotes,
@@ -393,18 +395,29 @@ export class SwapService {
393
395
  };
394
396
  });
395
397
  }
396
-
397
- // private getSwapPairMetadata (slug: string): Record<string, any> | undefined {
398
- // return this.getSwapPairs().find((pair) => pair.slug === slug)?.metadata;
399
- // }
400
-
401
- async validateSwapProcess(params) {
398
+ async validateSwapProcessV2(params) {
402
399
  const providerId = params.selectedQuote.provider.id;
403
400
  const handler = this.handlers[providerId];
404
- if (params.currentStep > 1) {
405
- // only validate from the first step
401
+ if (params.currentStep > 0) {
406
402
  return [];
407
403
  }
404
+ const blockedConfigObjects = await fetchBlockedConfigObjects();
405
+ const currentConfig = this.state.settingService.getEnvironmentSetting();
406
+ const passBlockedConfigId = getPassConfigId(currentConfig, blockedConfigObjects);
407
+ const blockedActionsFeaturesMaps = await fetchLatestBlockedActionsAndFeatures(passBlockedConfigId);
408
+ const originSwapPairInfo = getTokenPairFromStep(params.process.steps);
409
+ if (!originSwapPairInfo) {
410
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
411
+ }
412
+ const currentAction = `${ExtrinsicType.SWAP}___${originSwapPairInfo.slug}___${params.selectedQuote.provider.id}`;
413
+ for (const blockedActionsFeaturesMap of blockedActionsFeaturesMaps) {
414
+ const {
415
+ blockedActionsMap
416
+ } = blockedActionsFeaturesMap;
417
+ if (blockedActionsMap.swap.includes(currentAction)) {
418
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED, t('Feature under maintenance. Try again later'))];
419
+ }
420
+ }
408
421
  if (handler) {
409
422
  return handler.validateSwapProcessV2(params);
410
423
  } else {
@@ -417,7 +430,6 @@ export class SwapService {
417
430
  // todo: do better to handle error generating steps
418
431
  return Promise.reject(new TransactionError(BasicTxErrorType.INTERNAL_ERROR, 'Please check your network and try again'));
419
432
  }
420
- console.log('handling swap process: ', params.process);
421
433
  if (handler) {
422
434
  return handler.handleSwapProcess(params);
423
435
  } else {
@@ -1,6 +1,5 @@
1
1
  import { _AssetRef, _ChainAsset } from '@subwallet/chain-list/types';
2
- import { DynamicSwapAction } from '@subwallet/extension-base/services/swap-service/interface';
3
- import { CommonStepDetail } from '@subwallet/extension-base/types';
2
+ import { CommonStepDetail, DynamicSwapAction } from '@subwallet/extension-base/types';
4
3
  import { SwapPair } from '@subwallet/extension-base/types/swap';
5
4
  export declare const CHAIN_FLIP_TESTNET_EXPLORER = "https://blocks-perseverance.chainflip.io";
6
5
  export declare const CHAIN_FLIP_MAINNET_EXPLORER = "https://scan.chainflip.io";
@@ -9,6 +8,7 @@ export declare const SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING: Record<string,
9
8
  export declare const SWAP_QUOTE_TIMEOUT_MAP: Record<string, number>;
10
9
  export declare const _PROVIDER_TO_SUPPORTED_PAIR_MAP: Record<string, string[]>;
11
10
  export declare const FEE_RATE_MULTIPLIER: Record<string, number>;
11
+ export declare function getSupportSwapChain(): string[];
12
12
  export declare function getSwapAlternativeAsset(swapPair: SwapPair): string | undefined;
13
13
  export declare function getSwapAltToken(chainAsset: _ChainAsset): string | undefined;
14
14
  export declare function calculateSwapRate(fromAmount: string, toAmount: string, fromAsset: _ChainAsset, toAsset: _ChainAsset): number;
@@ -28,6 +28,14 @@ export declare function getChainflipBroker(isTestnet: boolean): {
28
28
  export declare function getChainflipSwap(isTestnet: boolean): string;
29
29
  export declare function getBridgeStep(from: string, to: string): DynamicSwapAction;
30
30
  export declare function getSwapStep(from: string, to: string): DynamicSwapAction;
31
- export declare function findXcmDestination(assetRefMap: Record<string, _AssetRef>, chainAsset: _ChainAsset, destChain: string): string | undefined;
31
+ export declare function findBridgeTransitDestination(assetRefMap: Record<string, _AssetRef>, fromToken: _ChainAsset, toToken: _ChainAsset): string | undefined;
32
+ export declare function findSwapTransitDestination(assetRefMap: Record<string, _AssetRef>, fromToken: _ChainAsset, toToken: _ChainAsset): string | undefined;
33
+ export declare function findAllBridgeDestinations(assetRefMap: Record<string, _AssetRef>, fromToken: _ChainAsset): string[];
34
+ export declare function getAmountAfterSlippage(amount: string, slippage: number): string;
32
35
  export declare function isChainsHasSameProvider(fromChain: string, toChain: string): boolean;
36
+ export declare function getLastAmountFromSteps(steps: CommonStepDetail[]): string | undefined;
37
+ export declare function getFirstAmountFromSteps(steps: CommonStepDetail[]): string | undefined;
38
+ export declare function getChainRouteFromSteps(steps: CommonStepDetail[]): string[];
33
39
  export declare function getTokenPairFromStep(steps: CommonStepDetail[]): SwapPair | undefined;
40
+ export declare function getSwapChainsFromPath(path: DynamicSwapAction[]): string[];
41
+ export declare const DEFAULT_EXCESS_AMOUNT_WEIGHT = 1.04;
@@ -3,10 +3,9 @@
3
3
 
4
4
  import { COMMON_ASSETS, COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
5
5
  import { _AssetRefPath } from '@subwallet/chain-list/types';
6
- import { _getAssetDecimals } from '@subwallet/extension-base/services/chain-service/utils';
6
+ import { _getAssetDecimals, _getAssetOriginChain, _getOriginChainOfAsset, _parseAssetRefKey } from '@subwallet/extension-base/services/chain-service/utils';
7
7
  import { CHAINFLIP_BROKER_API } from '@subwallet/extension-base/services/swap-service/handler/chainflip-handler';
8
- import { DynamicSwapType } from '@subwallet/extension-base/services/swap-service/interface';
9
- import { CommonStepType } from '@subwallet/extension-base/types';
8
+ import { CommonStepType, DynamicSwapType, SwapStepType } from '@subwallet/extension-base/types';
10
9
  import { SwapProviderId } from '@subwallet/extension-base/types/swap';
11
10
  import BigN from 'bignumber.js';
12
11
  export const CHAIN_FLIP_TESTNET_EXPLORER = 'https://blocks-perseverance.chainflip.io';
@@ -21,7 +20,7 @@ export const SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING = {
21
20
  };
22
21
  export const SWAP_QUOTE_TIMEOUT_MAP = {
23
22
  // in milliseconds
24
- default: 30000,
23
+ default: 90000,
25
24
  [SwapProviderId.CHAIN_FLIP_TESTNET]: 30000,
26
25
  [SwapProviderId.CHAIN_FLIP_MAINNET]: 30000
27
26
  };
@@ -43,6 +42,9 @@ export const FEE_RATE_MULTIPLIER = {
43
42
  medium: 1.2,
44
43
  high: 2
45
44
  };
45
+ export function getSupportSwapChain() {
46
+ return [...new Set(Object.values(_PROVIDER_TO_SUPPORTED_PAIR_MAP).flat())];
47
+ }
46
48
  export function getSwapAlternativeAsset(swapPair) {
47
49
  var _swapPair$metadata;
48
50
  return swapPair === null || swapPair === void 0 ? void 0 : (_swapPair$metadata = swapPair.metadata) === null || _swapPair$metadata === void 0 ? void 0 : _swapPair$metadata.alternativeAsset;
@@ -52,15 +54,15 @@ export function getSwapAltToken(chainAsset) {
52
54
  return (_chainAsset$metadata = chainAsset.metadata) === null || _chainAsset$metadata === void 0 ? void 0 : _chainAsset$metadata.alternativeSwapAsset;
53
55
  }
54
56
  export function calculateSwapRate(fromAmount, toAmount, fromAsset, toAsset) {
55
- const bnFromAmount = new BigN(fromAmount);
56
- const bnToAmount = new BigN(toAmount);
57
+ const bnFromAmount = BigN(fromAmount);
58
+ const bnToAmount = BigN(toAmount);
57
59
  const decimalDiff = _getAssetDecimals(toAsset) - _getAssetDecimals(fromAsset);
58
60
  const bnRate = bnFromAmount.div(bnToAmount);
59
61
  return 1 / bnRate.times(10 ** decimalDiff).toNumber();
60
62
  }
61
63
  export function convertSwapRate(rate, fromAsset, toAsset) {
62
64
  const decimalDiff = _getAssetDecimals(toAsset) - _getAssetDecimals(fromAsset);
63
- const bnRate = new BigN(rate);
65
+ const bnRate = BigN(rate);
64
66
  return bnRate.times(10 ** decimalDiff).pow(-1).toNumber();
65
67
  }
66
68
  export function getChainflipOptions(isTestnet) {
@@ -101,6 +103,7 @@ export function getBridgeStep(from, to) {
101
103
  action: DynamicSwapType.BRIDGE,
102
104
  pair: {
103
105
  slug: `${from}___${to}`,
106
+ // todo: recheck with assetRef format from chain list
104
107
  from,
105
108
  to
106
109
  }
@@ -111,18 +114,33 @@ export function getSwapStep(from, to) {
111
114
  action: DynamicSwapType.SWAP,
112
115
  pair: {
113
116
  slug: `${from}___${to}`,
117
+ // todo: recheck with assetRef format from chain list
114
118
  from,
115
119
  to
116
120
  }
117
121
  };
118
122
  }
119
- export function findXcmDestination(assetRefMap, chainAsset, destChain) {
120
- const foundAssetRef = Object.values(assetRefMap).find(assetRef => assetRef.srcAsset === chainAsset.slug && assetRef.destChain === destChain && assetRef.path === _AssetRefPath.XCM);
123
+ export function findBridgeTransitDestination(assetRefMap, fromToken, toToken) {
124
+ const foundAssetRef = Object.values(assetRefMap).find(assetRef => assetRef.srcAsset === fromToken.slug && assetRef.destChain === _getAssetOriginChain(toToken) && assetRef.path === _AssetRefPath.XCM);
121
125
  if (foundAssetRef) {
122
126
  return foundAssetRef.destAsset;
123
127
  }
124
128
  return undefined;
125
129
  }
130
+ export function findSwapTransitDestination(assetRefMap, fromToken, toToken) {
131
+ const foundAssetRef = Object.values(assetRefMap).find(assetRef => assetRef.destAsset === toToken.slug && assetRef.srcChain === _getAssetOriginChain(fromToken) && assetRef.path === _AssetRefPath.XCM);
132
+ if (foundAssetRef) {
133
+ return foundAssetRef.srcAsset;
134
+ }
135
+ return undefined;
136
+ }
137
+ export function findAllBridgeDestinations(assetRefMap, fromToken) {
138
+ const foundAssetRefs = Object.values(assetRefMap).filter(assetRef => assetRef.srcAsset === fromToken.slug && assetRef.path === _AssetRefPath.XCM);
139
+ return foundAssetRefs.map(assetRef => assetRef.destAsset);
140
+ }
141
+ export function getAmountAfterSlippage(amount, slippage) {
142
+ return BigN(amount).multipliedBy(BigN(1).minus(BigN(slippage))).integerValue(BigN.ROUND_DOWN).toString();
143
+ }
126
144
  export function isChainsHasSameProvider(fromChain, toChain) {
127
145
  // todo: a provider may support multiple chains but not cross-chain swaps
128
146
  for (const group of Object.values(_PROVIDER_TO_SUPPORTED_PAIR_MAP)) {
@@ -132,27 +150,90 @@ export function isChainsHasSameProvider(fromChain, toChain) {
132
150
  }
133
151
  return false;
134
152
  }
135
- export function getTokenPairFromStep(steps) {
153
+ export function getLastAmountFromSteps(steps) {
154
+ var _lastStep$metadata;
155
+ const lastStep = steps[steps.length - 1]; // last step
156
+ const lastAmount = lastStep === null || lastStep === void 0 ? void 0 : (_lastStep$metadata = lastStep.metadata) === null || _lastStep$metadata === void 0 ? void 0 : _lastStep$metadata.destinationValue;
157
+ return lastAmount !== null && lastAmount !== void 0 ? lastAmount : undefined;
158
+ }
159
+ export function getFirstAmountFromSteps(steps) {
160
+ var _firstStep$metadata;
161
+ const firstStep = steps[1]; // first step after default step
162
+ const firstAmount = firstStep === null || firstStep === void 0 ? void 0 : (_firstStep$metadata = firstStep.metadata) === null || _firstStep$metadata === void 0 ? void 0 : _firstStep$metadata.sendingValue;
163
+ return firstAmount !== null && firstAmount !== void 0 ? firstAmount : undefined;
164
+ }
165
+ export function getChainRouteFromSteps(steps) {
166
+ // todo: handle metadata for other providers than hydra & pah. Also add validate metadata.
136
167
  const mainSteps = steps.filter(step => step.type !== CommonStepType.DEFAULT);
168
+ return mainSteps.reduce((chainRoute, currentStep, currentIndex) => {
169
+ const metadata = currentStep.metadata;
170
+ if (!metadata) {
171
+ console.error('Step has no metadata');
172
+ return chainRoute;
173
+ }
174
+ if (currentIndex === 0) {
175
+ chainRoute.push(metadata.originTokenInfo.originChain);
176
+ chainRoute.push(metadata.destinationTokenInfo.originChain);
177
+ } else {
178
+ chainRoute.push(metadata.destinationTokenInfo.originChain);
179
+ }
180
+ return chainRoute;
181
+ }, []);
182
+ }
183
+
184
+ // note: this function may return undefined if metadata version is < 2 or does not exist
185
+ export function getTokenPairFromStep(steps) {
186
+ // todo: review this
187
+ const mainSteps = steps.filter(step => step.type !== CommonStepType.DEFAULT && step.type !== CommonStepType.TOKEN_APPROVAL && step.type !== SwapStepType.PERMIT);
137
188
  if (!mainSteps.length) {
138
189
  return undefined;
139
190
  }
191
+ const isStepValidIfSwap = step => {
192
+ const metadata = step.metadata;
193
+ return step.type !== SwapStepType.SWAP || !!(metadata !== null && metadata !== void 0 && metadata.version) && (metadata === null || metadata === void 0 ? void 0 : metadata.version) >= 2;
194
+ };
140
195
  if (mainSteps.length === 1) {
141
- const metadata = mainSteps[0].metadata; // todo: temp for round 1, the exact interface is handle in round 2
142
-
196
+ if (!isStepValidIfSwap(mainSteps[0])) {
197
+ return undefined;
198
+ }
199
+ const metadata = mainSteps[0].metadata;
200
+ if (!metadata) {
201
+ return undefined;
202
+ }
143
203
  return {
144
204
  from: metadata.originTokenInfo.slug,
145
205
  to: metadata.destinationTokenInfo.slug,
146
- slug: `${metadata.originTokenInfo.slug}___${metadata.destinationTokenInfo.slug}`
206
+ slug: _parseAssetRefKey(metadata.originTokenInfo.slug, metadata.destinationTokenInfo.slug)
147
207
  };
148
208
  }
149
209
  const firstStep = mainSteps[0];
150
210
  const lastStep = mainSteps[mainSteps.length - 1];
211
+ if (!isStepValidIfSwap(firstStep) || !isStepValidIfSwap(lastStep)) {
212
+ return undefined;
213
+ }
151
214
  const firstMetadata = firstStep.metadata;
152
215
  const lastMetadata = lastStep.metadata;
216
+ if (!firstMetadata || !lastMetadata) {
217
+ return undefined;
218
+ }
153
219
  return {
154
220
  from: firstMetadata.originTokenInfo.slug,
155
221
  to: lastMetadata.destinationTokenInfo.slug,
156
- slug: `${firstMetadata.originTokenInfo.slug}___${lastMetadata.destinationTokenInfo.slug}`
222
+ slug: _parseAssetRefKey(firstMetadata.originTokenInfo.slug, lastMetadata.destinationTokenInfo.slug)
157
223
  };
158
- }
224
+ }
225
+ export function getSwapChainsFromPath(path) {
226
+ const swapChains = [];
227
+ path.forEach(pathElement => {
228
+ const fromAssetOriginChain = _getOriginChainOfAsset(pathElement.pair.from);
229
+ const toAssetOriginChain = _getOriginChainOfAsset(pathElement.pair.to);
230
+ if (swapChains.at(-1) !== fromAssetOriginChain) {
231
+ swapChains.push(fromAssetOriginChain);
232
+ }
233
+ if (swapChains.at(-1) !== toAssetOriginChain) {
234
+ swapChains.push(toAssetOriginChain);
235
+ }
236
+ });
237
+ return swapChains;
238
+ }
239
+ export const DEFAULT_EXCESS_AMOUNT_WEIGHT = 1.04; // add 2%
@@ -4,7 +4,7 @@
4
4
  import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError';
5
5
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
6
6
  import { ChainType, EvmProviderErrorType, ExtrinsicStatus, ExtrinsicType, NotificationType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
7
- import { _SUPPORT_TOKEN_PAY_FEE_GROUP, ALL_ACCOUNT_KEY, fetchBlockedConfigObjects, fetchLastestBlockedActionsAndFeatures, getPassConfigId } from '@subwallet/extension-base/constants';
7
+ import { _SUPPORT_TOKEN_PAY_FEE_GROUP, ALL_ACCOUNT_KEY, fetchBlockedConfigObjects, fetchLatestBlockedActionsAndFeatures, getPassConfigId } from '@subwallet/extension-base/constants';
8
8
  import { checkBalanceWithTransactionFee, checkSigningAccountForTransaction, checkSupportForAction, checkSupportForFeature, checkSupportForTransaction, estimateFeeForTransaction } from '@subwallet/extension-base/core/logic-validation/transfer';
9
9
  import { cellToBase64Str, externalMessage, getTransferCellPromise } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
10
10
  import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getEvmChainId, _isChainEvmCompatible, _isNativeTokenBySlug } from '@subwallet/extension-base/services/chain-service/utils';
@@ -80,7 +80,7 @@ export default class TransactionService {
80
80
  const blockedConfigObjects = await fetchBlockedConfigObjects();
81
81
  const currentConfig = this.state.settingService.getEnvironmentSetting();
82
82
  const passBlockedConfigId = getPassConfigId(currentConfig, blockedConfigObjects);
83
- const blockedActionsFeaturesMaps = await fetchLastestBlockedActionsAndFeatures(passBlockedConfigId);
83
+ const blockedActionsFeaturesMaps = await fetchLatestBlockedActionsAndFeatures(passBlockedConfigId);
84
84
  for (const blockedActionsFeaturesMap of blockedActionsFeaturesMaps) {
85
85
  const {
86
86
  blockedActionsMap,