@subwallet/extension-base 1.3.77-0 → 1.3.79-1

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 (96) hide show
  1. package/background/KoniTypes.d.ts +5 -3
  2. package/cjs/core/logic-validation/index.js +1 -13
  3. package/cjs/core/substrate/xcm-parser.js +10 -1
  4. package/cjs/koni/background/handlers/Extension.js +41 -9
  5. package/cjs/koni/background/handlers/State.js +20 -0
  6. package/cjs/packageInfo.js +1 -1
  7. package/cjs/services/balance-service/helpers/subscribe/evm.js +85 -6
  8. package/cjs/services/balance-service/helpers/subscribe/index.js +2 -1
  9. package/cjs/services/balance-service/index.js +6 -2
  10. package/cjs/services/balance-service/transfer/token.js +15 -0
  11. package/cjs/services/balance-service/transfer/xcm/bittensorBridge/index.js +27 -0
  12. package/cjs/services/balance-service/transfer/xcm/bittensorBridge/nativeTokenBridge.js +58 -0
  13. package/cjs/services/balance-service/transfer/xcm/bittensorBridge/utils.js +36 -0
  14. package/cjs/services/balance-service/transfer/xcm/index.js +61 -2
  15. package/cjs/services/balance-service/transfer/xcm/utils.js +103 -15
  16. package/cjs/services/chain-service/constants.js +4 -2
  17. package/cjs/services/chain-service/utils/patch.js +1 -1
  18. package/cjs/services/earning-service/constants/chains.js +4 -2
  19. package/cjs/services/earning-service/handlers/native-staking/dtao.js +13 -13
  20. package/cjs/services/earning-service/handlers/native-staking/tao.js +16 -10
  21. package/cjs/services/earning-service/handlers/special.js +89 -65
  22. package/cjs/services/earning-service/service.js +1 -0
  23. package/cjs/services/swap-service/handler/asset-hub/handler.js +7 -4
  24. package/cjs/services/swap-service/handler/asset-hub/router.js +2 -66
  25. package/cjs/services/swap-service/handler/base-handler.js +4 -3
  26. package/cjs/services/swap-service/handler/bittensor-handler.js +197 -0
  27. package/cjs/services/swap-service/handler/hydradx-handler.js +9 -5
  28. package/cjs/services/swap-service/index.js +12 -4
  29. package/cjs/services/transaction-service/index.js +1 -0
  30. package/cjs/types/balance/index.js +1 -0
  31. package/cjs/types/swap/index.js +7 -10
  32. package/cjs/utils/account/common.js +44 -8
  33. package/cjs/utils/fee/transfer.js +20 -5
  34. package/core/logic-validation/index.d.ts +0 -1
  35. package/core/logic-validation/index.js +1 -2
  36. package/core/substrate/xcm-parser.d.ts +2 -0
  37. package/core/substrate/xcm-parser.js +8 -1
  38. package/koni/background/handlers/Extension.d.ts +3 -0
  39. package/koni/background/handlers/Extension.js +42 -10
  40. package/koni/background/handlers/State.d.ts +1 -0
  41. package/koni/background/handlers/State.js +20 -0
  42. package/package.json +26 -11
  43. package/packageInfo.js +1 -1
  44. package/services/balance-service/helpers/subscribe/evm.d.ts +1 -0
  45. package/services/balance-service/helpers/subscribe/evm.js +76 -1
  46. package/services/balance-service/helpers/subscribe/index.js +2 -1
  47. package/services/balance-service/index.js +6 -2
  48. package/services/balance-service/transfer/token.d.ts +2 -1
  49. package/services/balance-service/transfer/token.js +15 -0
  50. package/services/balance-service/transfer/xcm/bittensorBridge/index.d.ts +2 -0
  51. package/services/balance-service/transfer/xcm/bittensorBridge/index.js +5 -0
  52. package/services/balance-service/transfer/xcm/bittensorBridge/nativeTokenBridge.d.ts +6 -0
  53. package/services/balance-service/transfer/xcm/bittensorBridge/nativeTokenBridge.js +50 -0
  54. package/services/balance-service/transfer/xcm/bittensorBridge/utils.d.ts +8 -0
  55. package/services/balance-service/transfer/xcm/bittensorBridge/utils.js +29 -0
  56. package/services/balance-service/transfer/xcm/index.d.ts +5 -0
  57. package/services/balance-service/transfer/xcm/index.js +57 -2
  58. package/services/balance-service/transfer/xcm/utils.d.ts +3 -2
  59. package/services/balance-service/transfer/xcm/utils.js +96 -10
  60. package/services/chain-service/constants.d.ts +2 -0
  61. package/services/chain-service/constants.js +4 -2
  62. package/services/chain-service/utils/patch.d.ts +1 -1
  63. package/services/chain-service/utils/patch.js +1 -1
  64. package/services/earning-service/constants/chains.d.ts +1 -0
  65. package/services/earning-service/constants/chains.js +2 -1
  66. package/services/earning-service/handlers/native-staking/dtao.js +12 -13
  67. package/services/earning-service/handlers/native-staking/tao.d.ts +2 -1
  68. package/services/earning-service/handlers/native-staking/tao.js +15 -10
  69. package/services/earning-service/handlers/special.d.ts +1 -1
  70. package/services/earning-service/handlers/special.js +92 -68
  71. package/services/earning-service/service.js +1 -0
  72. package/services/swap-service/handler/asset-hub/handler.js +7 -4
  73. package/services/swap-service/handler/asset-hub/router.d.ts +0 -4
  74. package/services/swap-service/handler/asset-hub/router.js +1 -64
  75. package/services/swap-service/handler/base-handler.js +4 -3
  76. package/services/swap-service/handler/bittensor-handler.d.ts +21 -0
  77. package/services/swap-service/handler/bittensor-handler.js +189 -0
  78. package/services/swap-service/handler/hydradx-handler.js +9 -5
  79. package/services/swap-service/index.js +12 -4
  80. package/services/transaction-service/index.js +1 -0
  81. package/services/transaction-service/types.d.ts +4 -3
  82. package/types/balance/index.d.ts +3 -1
  83. package/types/balance/index.js +1 -0
  84. package/types/balance/transfer.d.ts +7 -0
  85. package/types/fee/base.d.ts +1 -0
  86. package/types/swap/index.d.ts +10 -36
  87. package/types/swap/index.js +6 -9
  88. package/types/yield/actions/join/step.d.ts +7 -0
  89. package/types/yield/actions/join/submit.d.ts +3 -1
  90. package/utils/account/common.d.ts +22 -1
  91. package/utils/account/common.js +44 -8
  92. package/utils/fee/transfer.d.ts +1 -0
  93. package/utils/fee/transfer.js +21 -6
  94. package/cjs/core/logic-validation/swap.js +0 -235
  95. package/core/logic-validation/swap.d.ts +0 -26
  96. package/core/logic-validation/swap.js +0 -219
@@ -36,4 +36,5 @@ export const CHANNEL_ID = 7;
36
36
  export const STAKING_IDENTITY_API_SLUG = {
37
37
  statemine: 'peopleKusama',
38
38
  statemint: 'polkadot_people'
39
- };
39
+ };
40
+ export const MIN_XCM_LIQUID_STAKING_DOT = '15000000000';
@@ -9,20 +9,19 @@ import { reformatAddress } from '@subwallet/extension-base/utils';
9
9
  import BigN from 'bignumber.js';
10
10
  import { BN_ZERO } from '@polkadot/util';
11
11
  import TaoNativeStakingPoolHandler, { DEFAULT_DTAO_MINBOND } from "./tao.js";
12
- const getAlphaToTaoRateMap = async substrateApi => {
13
- const allSubnets = (await substrateApi.api.call.subnetInfoRuntimeApi.getAllDynamicInfo()).toJSON();
14
- if (!allSubnets || allSubnets.length === 0) {
15
- return {};
16
- }
12
+ const getAlphaToTaoRateMap = async (substrateApi, priceScaleDecimals = 9) => {
17
13
  const result = Object.create(null);
18
- for (const subnet of allSubnets) {
19
- const netuid = subnet === null || subnet === void 0 ? void 0 : subnet.netuid;
20
- if (netuid === undefined) {
21
- continue;
14
+ const PRICE_SCALE = new BigN(10).pow(priceScaleDecimals);
15
+ const allSubnetPrices = (await substrateApi.api.call.swapRuntimeApi.currentAlphaPriceAll()).toJSON();
16
+ if (allSubnetPrices && allSubnetPrices.length > 0) {
17
+ for (const subnetPrice of allSubnetPrices) {
18
+ const netuid = subnetPrice === null || subnetPrice === void 0 ? void 0 : subnetPrice.netuid;
19
+ if (netuid === undefined) {
20
+ continue;
21
+ }
22
+ const rawPrice = subnetPrice !== null && subnetPrice !== void 0 && subnetPrice.price ? new BigN(subnetPrice.price) : new BigN(0);
23
+ result[netuid] = netuid === 0 ? '1' : rawPrice.dividedBy(PRICE_SCALE).toFixed();
22
24
  }
23
- const taoIn = subnet !== null && subnet !== void 0 && subnet.taoIn ? new BigN(subnet.taoIn) : new BigN(0);
24
- const alphaIn = subnet !== null && subnet !== void 0 && subnet.alphaIn ? new BigN(subnet.alphaIn) : new BigN(0);
25
- result[netuid] = netuid === 0 || alphaIn.lte(0) ? '1' : taoIn.dividedBy(alphaIn).toString();
26
25
  }
27
26
  return result;
28
27
  };
@@ -204,7 +203,7 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan
204
203
  const getPoolPosition = async () => {
205
204
  const rawDelegateStateInfos = await substrateApi.api.call.stakeInfoRuntimeApi.getStakeInfoForColdkeys(useAddresses);
206
205
  const delegateStateInfos = rawDelegateStateInfos.toPrimitive();
207
- const alphaToTaoRateMap = await getAlphaToTaoRateMap(this.substrateApi);
206
+ const alphaToTaoRateMap = await getAlphaToTaoRateMap(this.substrateApi, this.getAlphaPriceScaleDecimals());
208
207
  if (!delegateStateInfos || delegateStateInfos.length === 0) {
209
208
  return;
210
209
  }
@@ -82,10 +82,11 @@ export declare class BittensorCache {
82
82
  fetchApr(netuid: number): Promise<ValidatorAprResponse>;
83
83
  fetchSubnetFeeRate(netuid: number): Promise<string>;
84
84
  }
85
- export declare const getAlphaToTaoRate: (substrateApi: _SubstrateApi, netuid: number) => Promise<string>;
85
+ export declare const getAlphaToTaoRate: (substrateApi: _SubstrateApi, netuid: number, priceScaleDecimals?: number) => Promise<string>;
86
86
  export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHandler {
87
87
  readonly availableMethod: YieldPoolMethodInfo;
88
88
  protected bittensorCache: BittensorCache;
89
+ protected getAlphaPriceScaleDecimals(): number;
89
90
  protected getMinBond(netuid?: number): Promise<BigN>;
90
91
  constructor(state: KoniState, chain: string);
91
92
  get maintainBalance(): string;
@@ -113,14 +113,16 @@ export class BittensorCache {
113
113
  }
114
114
  }
115
115
  }
116
- export const getAlphaToTaoRate = async (substrateApi, netuid) => {
117
- const subnetInfo = (await substrateApi.api.call.subnetInfoRuntimeApi.getDynamicInfo(netuid)).toJSON();
118
- if (!subnetInfo) {
116
+ export const getAlphaToTaoRate = async (substrateApi, netuid, priceScaleDecimals = 9) => {
117
+ if (netuid === 0) {
119
118
  return '1';
120
119
  }
121
- const taoIn = subnetInfo.taoIn ? new BigN(subnetInfo.taoIn) : new BigN(0);
122
- const alphaIn = subnetInfo.alphaIn ? new BigN(subnetInfo.alphaIn) : new BigN(0);
123
- return netuid === 0 || alphaIn.lte(0) ? '1' : taoIn.dividedBy(alphaIn).toString();
120
+ const [rawSubnetPrice, rawRootPrice] = await Promise.all([substrateApi.api.call.swapRuntimeApi.currentAlphaPrice(netuid), substrateApi.api.call.swapRuntimeApi.currentAlphaPrice(0)]);
121
+ const subnetPrice = new BigN(rawSubnetPrice.toString());
122
+ const defaultScale = new BigN(10).pow(priceScaleDecimals);
123
+ const rootPrice = new BigN(rawRootPrice.toString());
124
+ const priceScale = rootPrice.lte(0) ? defaultScale : rootPrice;
125
+ return subnetPrice.lte(0) ? '0' : subnetPrice.dividedBy(priceScale).toFixed();
124
126
  };
125
127
  export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHandler {
126
128
  availableMethod = {
@@ -132,6 +134,9 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
132
134
  claimReward: false,
133
135
  changeValidator: true
134
136
  };
137
+ getAlphaPriceScaleDecimals() {
138
+ return _getAssetDecimals(this.nativeToken);
139
+ }
135
140
  async getMinBond(netuid) {
136
141
  var _cachedPool$metadata2, _cachedPool$statistic, _cachedPool$statistic2, _onlinePool$metadata2, _onlinePool$statistic, _onlinePool$statistic2;
137
142
  // @ts-ignore
@@ -469,7 +474,7 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
469
474
  const hotkey = selectedValidatorInfo.address;
470
475
  const netuid = (_subnetData$netuid = subnetData === null || subnetData === void 0 ? void 0 : subnetData.netuid) !== null && _subnetData$netuid !== void 0 ? _subnetData$netuid : 0;
471
476
  const slippage = (_subnetData$slippage = subnetData === null || subnetData === void 0 ? void 0 : subnetData.slippage) !== null && _subnetData$slippage !== void 0 ? _subnetData$slippage : DEFAULT_BITTENSOR_SLIPPAGE;
472
- const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid));
477
+ const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid, this.getAlphaPriceScaleDecimals()));
473
478
  const limitPrice = alphaToTaoPrice.multipliedBy(10 ** _getAssetDecimals(this.nativeToken)).multipliedBy(1 + slippage);
474
479
  const BNlimitPrice = new BigN(limitPrice.integerValue(BigN.ROUND_CEIL).toFixed());
475
480
  const extrinsic = chainApi.api.tx.subtensorModule.addStakeLimit(hotkey, netuid, binaryAmount.toFixed(), BNlimitPrice.toFixed(), false);
@@ -511,7 +516,7 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
511
516
  return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS));
512
517
  }
513
518
  const binaryAmount = new BigN(amount);
514
- const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid));
519
+ const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid, this.getAlphaPriceScaleDecimals()));
515
520
  const limitPrice = alphaToTaoPrice.multipliedBy(10 ** _getAssetDecimals(this.nativeToken)).multipliedBy(1 - slippage);
516
521
  const BNlimitPrice = new BigN(limitPrice.integerValue(BigN.ROUND_CEIL).toFixed());
517
522
  const extrinsic = apiPromise.api.tx.subtensorModule.removeStakeLimit(selectedTarget, netuid, binaryAmount.toFixed(), BNlimitPrice.toFixed(), false);
@@ -527,7 +532,7 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
527
532
  return [new TransactionError(BasicTxErrorType.INVALID_PARAMS)];
528
533
  }
529
534
  const netuid = (_poolInfo$metadata$su = poolInfo.metadata.subnetData) === null || _poolInfo$metadata$su === void 0 ? void 0 : _poolInfo$metadata$su.netuid;
530
- const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid || 0));
535
+ const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid || 0, this.getAlphaPriceScaleDecimals()));
531
536
  const minDelegatorStake = await this.getMinBond(netuid);
532
537
  const minUnstake = minDelegatorStake.dividedBy(alphaToTaoPrice);
533
538
  if (new BigN(amount).lt(minUnstake)) {
@@ -567,7 +572,7 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
567
572
  if (originValidator === destValidator) {
568
573
  return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.fromValidatorSameAsTo')));
569
574
  }
570
- const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid));
575
+ const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid, this.getAlphaPriceScaleDecimals()));
571
576
  const bnMinStake = await this.getMinBond(netuid);
572
577
  const minUnstake = bnMinStake.dividedBy(alphaToTaoPrice);
573
578
  const formattedMinUnstake = minUnstake.dividedBy(1000000).integerValue(BigN.ROUND_CEIL).dividedBy(1000);
@@ -55,7 +55,7 @@ export default abstract class BaseSpecialStakingPoolHandler extends BasePoolHand
55
55
  protected validateJoinStep(id: number, params: OptimalYieldPathParams, path: OptimalYieldPath, bnInputTokenBalance: BN, isXcmOk: boolean): Promise<TransactionError[]>;
56
56
  validateYieldJoin(params: SubmitYieldJoinData, path: OptimalYieldPath): Promise<TransactionError[]>;
57
57
  protected handleTokenApproveStep(data: SubmitYieldJoinData, path: OptimalYieldPath): Promise<HandleYieldStepData>;
58
- handleXcmStep(data: SubmitYieldJoinData, path: OptimalYieldPath, xcmFee: string): Promise<HandleYieldStepData>;
58
+ handleXcmStep(data: SubmitYieldJoinData, path: OptimalYieldPath): Promise<HandleYieldStepData>;
59
59
  abstract handleSubmitStep(data: SubmitYieldJoinData, path: OptimalYieldPath): Promise<HandleYieldStepData>;
60
60
  handleYieldJoin(data: SubmitYieldJoinData, path: OptimalYieldPath, currentStep: number): Promise<HandleYieldStepData>;
61
61
  handleYieldUnstake(amount: string, address: string, selectedTarget?: string): Promise<[ExtrinsicType, TransactionData]>;
@@ -3,11 +3,12 @@
3
3
 
4
4
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
5
5
  import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
- import { ALL_ACCOUNT_KEY, XCM_FEE_RATIO, XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
6
+ import { ALL_ACCOUNT_KEY, XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
7
7
  import { YIELD_POOL_STAT_REFRESH_INTERVAL } from '@subwallet/extension-base/koni/api/yield/helper/utils';
8
- import { createXcmExtrinsicV2 } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
8
+ import { createXcmExtrinsicV2, dryRunXcmExtrinsicV2, getMinXcmTransferableAmount } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
9
9
  import { estimateXcmFee } from '@subwallet/extension-base/services/balance-service/transfer/xcm/utils';
10
- import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetName, _getAssetSymbol, _getChainNativeTokenSlug, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
10
+ import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetSymbol, _getChainName, _getChainNativeTokenSlug } from '@subwallet/extension-base/services/chain-service/utils';
11
+ import { MIN_XCM_LIQUID_STAKING_DOT } from '@subwallet/extension-base/services/earning-service/constants';
11
12
  import { BasicTxErrorType, YieldStepType, YieldValidationStatus } from '@subwallet/extension-base/types';
12
13
  import { createPromiseHandler, formatNumber } from '@subwallet/extension-base/utils';
13
14
  import { getId } from '@subwallet/extension-base/utils/getId';
@@ -207,51 +208,52 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
207
208
  address,
208
209
  amount
209
210
  } = params;
210
- const bnAmount = new BN(amount);
211
+ const bnStakeAmount = new BigN(amount);
211
212
  const inputTokenSlug = this.inputAsset; // assume that the pool only has 1 input token, will update later
212
213
  const inputTokenInfo = this.state.getAssetBySlug(inputTokenSlug);
213
214
  const inputTokenBalance = await this.state.balanceService.getTransferableBalance(address, inputTokenInfo.originChain, inputTokenSlug);
214
- const bnInputTokenBalance = new BN(inputTokenBalance.value);
215
- if (!bnInputTokenBalance.gte(bnAmount)) {
215
+ const bnInputTokenBalance = new BigN(inputTokenBalance.value);
216
+ if (amount && !bnInputTokenBalance.gte(bnStakeAmount)) {
216
217
  if (this.altInputAsset) {
217
218
  const altInputTokenSlug = this.altInputAsset;
218
219
  const altInputTokenInfo = this.state.getAssetBySlug(altInputTokenSlug);
219
220
  const altInputTokenBalance = await this.state.balanceService.getTransferableBalance(address, altInputTokenInfo.originChain, altInputTokenSlug);
220
- const bnAltInputTokenBalance = new BN(altInputTokenBalance.value || '0');
221
- if (bnAltInputTokenBalance.gt(BN_ZERO)) {
221
+ const bnAltInputTokenBalance = new BigN(altInputTokenBalance.value || '0');
222
+ if (bnAltInputTokenBalance.gt(BigN(0))) {
222
223
  const altChainInfo = this.state.getChainInfo(altInputTokenInfo.originChain);
223
224
  const symbol = altInputTokenInfo.symbol;
224
225
  const networkName = altChainInfo.name;
225
-
226
- // TODO: calculate fee for destination chain
227
- const xcmFeeInfo = await estimateXcmFee({
226
+ const xcmRequest = {
228
227
  fromChainInfo: altChainInfo,
229
228
  fromTokenInfo: altInputTokenInfo,
230
229
  toChainInfo: this.chainInfo,
231
230
  recipient: address,
232
231
  sender: address,
233
- value: bnAmount.toString()
234
- });
232
+ value: bnStakeAmount.toString()
233
+ };
234
+ const [xcmFeeInfo, _minXcmTransferableAmount] = await Promise.all([estimateXcmFee(xcmRequest), getMinXcmTransferableAmount(xcmRequest)]);
235
235
  if (!xcmFeeInfo) {
236
236
  throw new Error('Error estimating XCM fee');
237
237
  }
238
- const xcmFee = BigN(xcmFeeInfo.origin.fee).multipliedBy(XCM_MIN_AMOUNT_RATIO).toFixed(0, 1);
238
+ const xcmOriginFee = BigN(xcmFeeInfo.origin.fee).toFixed(0, 1);
239
+ const xcmDestinationFee = BigN(xcmFeeInfo.destination.fee).toFixed(0, 1);
239
240
  const fee = {
240
241
  slug: altInputTokenSlug,
241
- amount: xcmFee
242
+ amount: xcmOriginFee
242
243
  };
243
- let bnTransferAmount = bnAmount.sub(bnInputTokenBalance);
244
- if (_isNativeToken(altInputTokenInfo)) {
245
- const bnXcmFee = new BN(fee.amount || 0); // xcm fee is paid in native token but swap token is not always native token
246
-
247
- bnTransferAmount = bnTransferAmount.add(bnXcmFee);
244
+ let sendingValue = bnStakeAmount.minus(bnInputTokenBalance).plus(xcmDestinationFee).toString();
245
+ const minXcmTransferableAmount = _minXcmTransferableAmount || MIN_XCM_LIQUID_STAKING_DOT;
246
+ if (new BigN(minXcmTransferableAmount).gt(sendingValue)) {
247
+ sendingValue = minXcmTransferableAmount;
248
248
  }
249
+ const metadata = {
250
+ sendingValue,
251
+ xcmDestinationFee,
252
+ originTokenInfo: altInputTokenInfo,
253
+ destinationTokenInfo: inputTokenInfo
254
+ };
249
255
  const step = {
250
- metadata: {
251
- sendingValue: bnTransferAmount.toString(),
252
- originTokenInfo: altInputTokenInfo,
253
- destinationTokenInfo: inputTokenInfo
254
- },
256
+ metadata: metadata,
255
257
  name: `Transfer ${symbol} from ${networkName}`,
256
258
  type: YieldStepType.XCM
257
259
  };
@@ -294,31 +296,35 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
294
296
  return Promise.resolve([new TransactionError(BasicTxErrorType.UNSUPPORTED)]);
295
297
  }
296
298
  async validateXcmStep(params, path, bnInputTokenBalance) {
299
+ // todo: BN -> BigN or BigInt
297
300
  const processValidation = {
298
301
  ok: true,
299
302
  status: YieldValidationStatus.OK
300
303
  };
301
- const bnAmount = new BN(params.amount);
302
- const altInputTokenSlug = this.altInputAsset || '';
303
- const altInputTokenInfo = this.state.getAssetBySlug(altInputTokenSlug);
304
- const inputTokenInfo = this.state.getAssetBySlug(this.inputAsset);
305
- const altInputTokenBalance = await this.state.balanceService.getTransferableBalance(params.address, altInputTokenInfo.originChain, altInputTokenSlug);
306
- const missingAmount = bnAmount.sub(bnInputTokenBalance); // TODO: what if input token is not LOCAL ??
307
- const xcmFeeValidate = new BN(path.totalFee[1].amount || '0').mul(new BN(XCM_FEE_RATIO));
308
- const bnAltInputTokenBalance = new BN(altInputTokenBalance.value || '0');
309
- if (!bnAltInputTokenBalance.sub(missingAmount).sub(xcmFeeValidate).gt(BN_ZERO)) {
304
+ const metadata = path.steps[1].metadata;
305
+ const {
306
+ destinationTokenInfo,
307
+ originTokenInfo,
308
+ sendingValue
309
+ } = metadata;
310
+ const originChainInfo = this.state.getChainInfo(originTokenInfo.originChain);
311
+ const originTokenBalance = await this.state.balanceService.getTransferableBalance(params.address, originTokenInfo.originChain, originTokenInfo.slug);
312
+ const bnOriginTokenBalance = new BN(originTokenBalance.value || '0');
313
+ const bnAdjustOriginFee = new BN(path.totalFee[1].amount || '0').mul(new BN(XCM_MIN_AMOUNT_RATIO));
314
+ const bnSendingValue = new BN(sendingValue);
315
+ if (!bnOriginTokenBalance.sub(bnSendingValue).sub(bnAdjustOriginFee).gt(BN_ZERO)) {
310
316
  processValidation.failedStep = path.steps[1];
311
317
  processValidation.ok = false;
312
318
  processValidation.status = YieldValidationStatus.NOT_ENOUGH_BALANCE;
313
- const bnMaxXCM = new BN(altInputTokenBalance.value).sub(xcmFeeValidate);
314
- const inputTokenDecimal = _getAssetDecimals(inputTokenInfo);
315
- const maxBn = bnInputTokenBalance.add(bnAltInputTokenBalance.sub(xcmFeeValidate));
316
- const maxValue = formatNumber(maxBn.toString(), inputTokenInfo.decimals || 0);
317
- const maxXCMValue = formatNumber(bnMaxXCM.toString(), inputTokenDecimal);
318
- const symbol = _getAssetSymbol(altInputTokenInfo);
319
+ const bnMaxXCM = new BN(originTokenBalance.value).sub(bnAdjustOriginFee);
320
+ const destinationTokenDecimal = _getAssetDecimals(destinationTokenInfo);
321
+ const maxBn = bnInputTokenBalance.add(bnOriginTokenBalance.sub(bnAdjustOriginFee));
322
+ const maxValue = formatNumber(maxBn.toString(), destinationTokenInfo.decimals || 0);
323
+ const maxXCMValue = formatNumber(bnMaxXCM.toString(), destinationTokenDecimal);
324
+ const symbol = _getAssetSymbol(originTokenInfo);
319
325
  const inputNetworkName = this.chainInfo.name;
320
- const altNetworkName = _getAssetName(altInputTokenInfo);
321
- const currentValue = formatNumber(bnInputTokenBalance.toString(), inputTokenDecimal);
326
+ const altNetworkName = _getChainName(originChainInfo);
327
+ const currentValue = formatNumber(bnInputTokenBalance.toString(), destinationTokenDecimal);
322
328
  processValidation.message = t('bg.EARNING.services.service.earning.specialHandler.maximumInputExceeded', {
323
329
  replace: {
324
330
  symbol,
@@ -331,6 +337,24 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
331
337
  });
332
338
  return [new TransactionError(YieldValidationStatus.NOT_ENOUGH_BALANCE, processValidation.message, processValidation)];
333
339
  }
340
+ const id = getId();
341
+ const feeInfo = await this.state.feeService.subscribeChainFee(id, originChainInfo.slug, 'substrate');
342
+ const substrateApi = this.state.getSubstrateApi(originChainInfo.slug);
343
+ const xcmRequest = {
344
+ destinationTokenInfo: destinationTokenInfo,
345
+ originTokenInfo: originTokenInfo,
346
+ recipient: params.address,
347
+ sendingValue,
348
+ substrateApi,
349
+ sender: params.address,
350
+ originChain: originChainInfo,
351
+ destinationChain: this.chainInfo,
352
+ feeInfo
353
+ };
354
+ const isDryRunSuccess = await dryRunXcmExtrinsicV2(xcmRequest);
355
+ if (!isDryRunSuccess) {
356
+ return [new TransactionError(BasicTxErrorType.UNABLE_TO_SEND, 'Unable to perform transaction. Select another token or destination chain and try again')];
357
+ }
334
358
  return [];
335
359
  }
336
360
  async validateJoinStep(id, params, path, bnInputTokenBalance, isXcmOk) {
@@ -350,7 +374,7 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
350
374
  const feeTokenInfo = this.state.getAssetBySlug(feeTokenSlug);
351
375
  const inputTokenInfo = this.state.getAssetBySlug(this.inputAsset);
352
376
  const defaultFeeTokenSlug = this.feeAssets[0];
353
- const bnAmount = new BN(params.amount);
377
+ const bnStakeAmount = new BN(params.amount);
354
378
  if (this.feeAssets.length === 1 && feeTokenSlug === defaultFeeTokenSlug) {
355
379
  var _path$totalFee$id;
356
380
  const bnFeeAmount = new BN(((_path$totalFee$id = path.totalFee[id]) === null || _path$totalFee$id === void 0 ? void 0 : _path$totalFee$id.amount) || '0');
@@ -364,13 +388,13 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
364
388
  return [new TransactionError(YieldValidationStatus.NOT_ENOUGH_FEE, processValidation.message, processValidation)];
365
389
  }
366
390
  }
367
- if (!bnAmount.gte(new BN(poolInfo.statistic.earningThreshold.join || '0'))) {
391
+ if (!bnStakeAmount.gte(new BN(poolInfo.statistic.earningThreshold.join || '0'))) {
368
392
  processValidation.failedStep = path.steps[id];
369
393
  processValidation.ok = false;
370
394
  processValidation.status = YieldValidationStatus.NOT_ENOUGH_MIN_JOIN_POOL;
371
395
  return [new TransactionError(YieldValidationStatus.NOT_ENOUGH_MIN_JOIN_POOL, processValidation.message, processValidation)];
372
396
  }
373
- if (!isXcmOk && bnAmount.gt(bnInputTokenBalance)) {
397
+ if (!isXcmOk && bnStakeAmount.gt(bnInputTokenBalance)) {
374
398
  processValidation.failedStep = path.steps[id];
375
399
  processValidation.ok = false;
376
400
  processValidation.status = YieldValidationStatus.NOT_ENOUGH_BALANCE;
@@ -394,8 +418,8 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
394
418
  const balanceService = this.state.balanceService;
395
419
  const inputTokenBalance = await balanceService.getTransferableBalance(params.address, inputTokenInfo.originChain, inputTokenSlug);
396
420
  const bnInputTokenBalance = new BN(inputTokenBalance.value || '0');
397
- const bnAmount = new BN(params.amount);
398
- if (bnAmount.lte(BN_ZERO)) {
421
+ const bnStakeAmount = new BN(params.amount);
422
+ if (bnStakeAmount.lte(BN_ZERO)) {
399
423
  return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
400
424
  }
401
425
  let isXcmOk = false;
@@ -429,31 +453,26 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
429
453
  async handleTokenApproveStep(data, path) {
430
454
  return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED));
431
455
  }
432
- async handleXcmStep(data, path, xcmFee) {
456
+ async handleXcmStep(data, path) {
457
+ const metadata = path.steps[1].metadata;
458
+ const xcmStepFee = path.totalFee[1].amount;
459
+ const address = data.address;
433
460
  const {
434
- address,
435
- amount
436
- } = data;
437
- const destinationTokenSlug = this.inputAsset;
438
- const altInputTokenSlug = this.altInputAsset || '';
439
- const altInputTokenInfo = this.state.getAssetBySlug(altInputTokenSlug);
440
- const originChainInfo = this.state.getChainInfo(altInputTokenInfo.originChain);
461
+ destinationTokenInfo,
462
+ originTokenInfo,
463
+ sendingValue,
464
+ xcmDestinationFee
465
+ } = metadata;
466
+ const originChainInfo = this.state.getChainInfo(originTokenInfo.originChain);
441
467
  const originTokenSlug = _getChainNativeTokenSlug(originChainInfo);
442
- const originTokenInfo = this.state.getAssetBySlug(originTokenSlug);
443
- const destinationTokenInfo = this.state.getAssetBySlug(destinationTokenSlug);
444
468
  const substrateApi = this.state.getSubstrateApi(originChainInfo.slug);
445
- const inputTokenBalance = await this.state.balanceService.getTransferableBalance(address, destinationTokenInfo.originChain, destinationTokenSlug);
446
- const bnInputTokenBalance = new BN(inputTokenBalance.value);
447
- const bnXcmFee = new BN(xcmFee);
448
- const bnAmount = new BN(amount);
449
- const bnTotalAmount = bnAmount.sub(bnInputTokenBalance).add(bnXcmFee);
450
469
  const id = getId();
451
470
  const feeInfo = await this.state.feeService.subscribeChainFee(id, originChainInfo.slug, 'substrate');
452
471
  const xcmRequest = {
453
472
  destinationTokenInfo,
454
473
  originTokenInfo,
455
474
  recipient: address,
456
- sendingValue: bnTotalAmount.toString(),
475
+ sendingValue,
457
476
  substrateApi,
458
477
  sender: address,
459
478
  originChain: originChainInfo,
@@ -469,7 +488,7 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
469
488
  destinationNetworkKey: destinationTokenInfo.originChain,
470
489
  from: address,
471
490
  to: address,
472
- value: bnTotalAmount.toString(),
491
+ value: sendingValue,
473
492
  tokenSlug: originTokenSlug,
474
493
  showExtraWarning: true
475
494
  };
@@ -478,8 +497,14 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
478
497
  extrinsicType: ExtrinsicType.TRANSFER_XCM,
479
498
  extrinsic,
480
499
  txData: xcmData,
481
- transferNativeAmount: bnTotalAmount.toString(),
482
- chainType: ChainType.SUBSTRATE
500
+ transferNativeAmount: sendingValue,
501
+ chainType: ChainType.SUBSTRATE,
502
+ xcmStepFee,
503
+ xcmDestinationFee: xcmDestinationFee ? {
504
+ decimals: _getAssetDecimals(destinationTokenInfo),
505
+ symbol: _getAssetSymbol(destinationTokenInfo),
506
+ value: xcmDestinationFee
507
+ } : undefined
483
508
  };
484
509
  }
485
510
  handleYieldJoin(data, path, currentStep) {
@@ -491,8 +516,7 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
491
516
  return this.handleTokenApproveStep(data, path);
492
517
  case YieldStepType.XCM:
493
518
  {
494
- const xcmFee = path.totalFee[currentStep].amount || '0';
495
- return this.handleXcmStep(data, path, xcmFee);
519
+ return this.handleXcmStep(data, path);
496
520
  }
497
521
  default:
498
522
  return this.handleSubmitStep(data, path);
@@ -871,6 +871,7 @@ export default class EarningService {
871
871
  } = params;
872
872
  const handler = this.getPoolHandler(slug);
873
873
  if (handler) {
874
+ console.log('all step', await handler.generateOptimalPath(params));
874
875
  return handler.generateOptimalPath(params);
875
876
  } else {
876
877
  throw new TransactionError(BasicTxErrorType.INTERNAL_ERROR);
@@ -64,7 +64,10 @@ export class AssetHubSwapHandler {
64
64
  const {
65
65
  path,
66
66
  request: {
67
- fromAmount
67
+ address,
68
+ alternativeAddress,
69
+ fromAmount,
70
+ recipient
68
71
  },
69
72
  selectedQuote
70
73
  } = params;
@@ -86,12 +89,12 @@ export class AssetHubSwapHandler {
86
89
  const needModifyData = swapXcm || xcmSwapXcm;
87
90
  let bnSendingValue = BigN(fromAmount);
88
91
  let bnExpectedReceive = BigN(selectedQuote.toAmount);
89
- const sender = _reformatAddressWithChain(params.request.address, originChain);
90
- let receiver = _reformatAddressWithChain(params.request.recipient || params.request.address, destinationChain);
92
+ const sender = _reformatAddressWithChain(address, originChain, alternativeAddress);
93
+ let receiver = _reformatAddressWithChain(recipient || address, destinationChain);
91
94
  if (needModifyData) {
92
95
  bnSendingValue = bnSendingValue.multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT);
93
96
  bnExpectedReceive = bnExpectedReceive.multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT);
94
- receiver = _reformatAddressWithChain(params.request.address, destinationChain);
97
+ receiver = _reformatAddressWithChain(address, destinationChain, alternativeAddress);
95
98
  }
96
99
  const submitStep = {
97
100
  name: 'Swap',
@@ -1,7 +1,6 @@
1
1
  import { _ChainAsset } from '@subwallet/chain-list/types';
2
2
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
3
3
  import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
4
- import { AssetHubSwapEarlyValidation, SwapPair, SwapRequest } from '@subwallet/extension-base/types/swap';
5
4
  import { SubmittableExtrinsic } from '@polkadot/api/types';
6
5
  export declare class AssetHubRouter {
7
6
  private readonly chain;
@@ -9,8 +8,5 @@ export declare class AssetHubRouter {
9
8
  constructor(chain: string, chainService: ChainService);
10
9
  get substrateApi(): _SubstrateApi;
11
10
  get nativeToken(): _ChainAsset;
12
- buildPath(pair: SwapPair): Array<_ChainAsset>;
13
- earlyValidateSwapValidation(request: SwapRequest): Promise<AssetHubSwapEarlyValidation>;
14
- estimateAmountOut(pair: SwapPair, amountIn: string): Promise<string>;
15
11
  buildSwapExtrinsic(path: Array<_ChainAsset>, recipient: string, amountIn: string, amountOutMin: string): Promise<SubmittableExtrinsic<'promise'>>;
16
12
  }
@@ -1,10 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { _getTokenMinAmount } from '@subwallet/extension-base/services/chain-service/utils';
5
- import { buildSwapExtrinsic, checkLiquidityForPath, checkMinAmountForPath, estimatePriceImpactPct, estimateRateAfterForPath, estimateRateForPath, estimateTokensForPath, getReserveForPath } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
6
- import { SwapErrorType } from '@subwallet/extension-base/types/swap';
7
- import BigN from 'bignumber.js';
4
+ import { buildSwapExtrinsic } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
8
5
  export class AssetHubRouter {
9
6
  constructor(chain, chainService) {
10
7
  this.chain = chain;
@@ -16,66 +13,6 @@ export class AssetHubRouter {
16
13
  get nativeToken() {
17
14
  return this.chainService.getNativeTokenInfo(this.chain);
18
15
  }
19
- buildPath(pair) {
20
- // const nativeToken = this.nativeToken;
21
- // const nativeTokenSlug = nativeToken.slug;
22
-
23
- const assetFrom = this.chainService.getAssetBySlug(pair.from);
24
- const assetTo = this.chainService.getAssetBySlug(pair.to);
25
- return [assetFrom, assetTo];
26
- // if (pair.from === nativeTokenSlug || pair.to === nativeTokenSlug) {
27
- // return [assetFrom, assetTo];
28
- // } else {
29
- // return [assetFrom, nativeToken, assetTo];
30
- // }
31
- }
32
- async earlyValidateSwapValidation(request) {
33
- const substrateApi = await this.substrateApi.isReady;
34
- const paths = this.buildPath(request.pair);
35
- const api = await substrateApi.api.isReady;
36
- const amount = request.fromAmount;
37
- const reserves = await getReserveForPath(api, paths);
38
- const amounts = estimateTokensForPath(amount, reserves);
39
- const marketRate = estimateRateForPath(reserves);
40
- const marketRateAfter = estimateRateAfterForPath(amount, reserves);
41
- const priceImpactPct = estimatePriceImpactPct(marketRate, marketRateAfter);
42
- const errors = [];
43
-
44
- // Check liquidity
45
- const liquidityError = checkLiquidityForPath(amounts, reserves);
46
- if (liquidityError) {
47
- errors.push(liquidityError);
48
- }
49
-
50
- // Check amount token in pool after swap
51
- const minAmounts = paths.map(asset => _getTokenMinAmount(asset));
52
- const minAmountAfterSwapError = checkMinAmountForPath(reserves, amounts, minAmounts);
53
- if (minAmountAfterSwapError) {
54
- errors.push(minAmountAfterSwapError);
55
- }
56
- const bnAmount = new BigN(request.fromAmount);
57
- if (bnAmount.lte(0)) {
58
- errors.push(SwapErrorType.AMOUNT_CANNOT_BE_ZERO);
59
- }
60
- const metadata = {
61
- chain: this.chainService.getChainInfoByKey(this.chain),
62
- toAmount: amounts[amounts.length - 1],
63
- quoteRate: marketRate,
64
- priceImpactPct: priceImpactPct
65
- };
66
- return {
67
- error: errors[0],
68
- metadata
69
- };
70
- }
71
- async estimateAmountOut(pair, amountIn) {
72
- const substrateApi = await this.substrateApi.isReady;
73
- const paths = this.buildPath(pair);
74
- const api = await substrateApi.api.isReady;
75
- const reserves = await getReserveForPath(api, paths);
76
- const amounts = estimateTokensForPath(amountIn, reserves);
77
- return amounts[amounts.length - 1];
78
- }
79
16
  async buildSwapExtrinsic(path, recipient, amountIn, amountOutMin) {
80
17
  const substrateApi = await this.substrateApi.isReady;
81
18
  const api = await substrateApi.api.isReady;
@@ -71,6 +71,7 @@ export class SwapBaseHandler {
71
71
  path,
72
72
  request: {
73
73
  address,
74
+ alternativeAddress,
74
75
  fromAmount,
75
76
  recipient
76
77
  },
@@ -94,12 +95,12 @@ export class SwapBaseHandler {
94
95
  throw Error('Token or chain not found');
95
96
  }
96
97
  let recipientAddress;
97
- const senderAddress = _reformatAddressWithChain(address, fromChainInfo);
98
+ const senderAddress = _reformatAddressWithChain(address, fromChainInfo, alternativeAddress);
98
99
  if (stepIndex === 0) {
99
- recipientAddress = _reformatAddressWithChain(address, toChainInfo);
100
+ recipientAddress = _reformatAddressWithChain(address, toChainInfo, alternativeAddress);
100
101
  } else {
101
102
  // bridge after swap
102
- recipientAddress = _reformatAddressWithChain(recipient || address, toChainInfo);
103
+ recipientAddress = _reformatAddressWithChain(recipient || address, toChainInfo, alternativeAddress);
103
104
  }
104
105
  if (!_isXcmWithinSameConsensus(fromChainInfo, toChainInfo) || _isSnowBridgeXcm(fromChainInfo, toChainInfo) || _isAcrossBridgeXcm(fromChainInfo, toChainInfo)) {
105
106
  return undefined;
@@ -0,0 +1,21 @@
1
+ import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
2
+ import { BaseStepDetail, CommonOptimalSwapPath, CommonStepFeeInfo, OptimalSwapPathParamsV2, SwapProviderId, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types';
3
+ import { BalanceService } from '../../balance-service';
4
+ import { ChainService } from '../../chain-service';
5
+ import FeeService from '../../fee-service/service';
6
+ import { SwapBaseInterface } from './base-handler';
7
+ export declare class BittensorSwapHandler implements SwapBaseInterface {
8
+ private swapBaseHandler;
9
+ providerSlug: SwapProviderId;
10
+ isReady: boolean;
11
+ constructor(chainService: ChainService, balanceService: BalanceService, feeService: FeeService, isTestnet: boolean);
12
+ get chainService(): ChainService;
13
+ get providerInfo(): import("@subwallet/extension-base/types").SwapProvider;
14
+ generateOptimalProcessV2(params: OptimalSwapPathParamsV2): Promise<CommonOptimalSwapPath>;
15
+ getSubmitStep(params: OptimalSwapPathParamsV2): Promise<[BaseStepDetail, CommonStepFeeInfo] | undefined>;
16
+ validateSwapProcessV2(params: ValidateSwapProcessParams): Promise<TransactionError[]>;
17
+ handleSwapProcess(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
18
+ handleSubmitStep(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
19
+ private getHotkeysByNetuidDesc;
20
+ private buildSwapCalls;
21
+ }