@subwallet/extension-base 1.2.3-0 → 1.2.3-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 (72) hide show
  1. package/background/KoniTypes.d.ts +4 -0
  2. package/cjs/core/logic-validation/earning.js +47 -0
  3. package/cjs/core/logic-validation/swap.js +99 -0
  4. package/cjs/core/logic-validation/transfer.js +219 -0
  5. package/cjs/core/substrate/nominationpools-pallet.js +12 -0
  6. package/cjs/core/substrate/system-pallet.js +78 -0
  7. package/cjs/koni/api/dotsama/transfer.js +49 -4
  8. package/cjs/koni/api/staking/bonding/utils.js +1 -1
  9. package/cjs/koni/api/xcm/index.js +30 -2
  10. package/cjs/koni/background/handlers/Extension.js +135 -245
  11. package/cjs/packageInfo.js +1 -1
  12. package/cjs/services/balance-service/helpers/group.js +4 -27
  13. package/cjs/services/balance-service/helpers/subscribe/index.js +2 -30
  14. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +41 -80
  15. package/cjs/services/balance-service/index.js +11 -9
  16. package/cjs/services/chain-service/index.js +0 -1
  17. package/cjs/services/chain-service/utils/index.js +6 -0
  18. package/cjs/services/earning-service/handlers/base.js +1 -1
  19. package/cjs/services/earning-service/handlers/special.js +11 -12
  20. package/cjs/services/swap-service/handler/base-handler.js +28 -44
  21. package/cjs/services/swap-service/handler/chainflip-handler.js +23 -21
  22. package/cjs/services/swap-service/handler/hydradx-handler.js +40 -38
  23. package/cjs/services/swap-service/index.js +6 -0
  24. package/cjs/services/swap-service/utils.js +8 -49
  25. package/cjs/services/transaction-service/index.js +66 -155
  26. package/core/logic-validation/earning.d.ts +10 -0
  27. package/core/logic-validation/earning.js +37 -0
  28. package/core/logic-validation/swap.d.ts +8 -0
  29. package/core/logic-validation/swap.js +89 -0
  30. package/core/logic-validation/transfer.d.ts +16 -0
  31. package/core/logic-validation/transfer.js +206 -0
  32. package/core/substrate/nominationpools-pallet.d.ts +7 -0
  33. package/core/substrate/nominationpools-pallet.js +6 -0
  34. package/core/substrate/system-pallet.d.ts +27 -0
  35. package/core/substrate/system-pallet.js +71 -0
  36. package/koni/api/dotsama/transfer.d.ts +3 -1
  37. package/koni/api/dotsama/transfer.js +44 -1
  38. package/koni/api/staking/bonding/relayChain.d.ts +2 -1
  39. package/koni/api/staking/bonding/utils.js +1 -1
  40. package/koni/api/xcm/index.d.ts +2 -0
  41. package/koni/api/xcm/index.js +27 -1
  42. package/koni/background/handlers/Extension.d.ts +5 -5
  43. package/koni/background/handlers/Extension.js +111 -221
  44. package/package.json +34 -9
  45. package/packageInfo.js +1 -1
  46. package/services/balance-service/helpers/group.js +4 -27
  47. package/services/balance-service/helpers/subscribe/index.d.ts +2 -1
  48. package/services/balance-service/helpers/subscribe/index.js +2 -30
  49. package/services/balance-service/helpers/subscribe/substrate/index.d.ts +2 -1
  50. package/services/balance-service/helpers/subscribe/substrate/index.js +26 -64
  51. package/services/balance-service/index.d.ts +7 -6
  52. package/services/balance-service/index.js +12 -10
  53. package/services/chain-service/index.js +0 -1
  54. package/services/chain-service/utils/index.d.ts +1 -0
  55. package/services/chain-service/utils/index.js +4 -0
  56. package/services/earning-service/handlers/base.js +1 -1
  57. package/services/earning-service/handlers/nomination-pool/index.d.ts +2 -1
  58. package/services/earning-service/handlers/special.js +11 -12
  59. package/services/swap-service/handler/base-handler.d.ts +3 -2
  60. package/services/swap-service/handler/base-handler.js +26 -42
  61. package/services/swap-service/handler/chainflip-handler.d.ts +2 -1
  62. package/services/swap-service/handler/chainflip-handler.js +4 -2
  63. package/services/swap-service/handler/hydradx-handler.d.ts +2 -1
  64. package/services/swap-service/handler/hydradx-handler.js +7 -5
  65. package/services/swap-service/index.js +7 -1
  66. package/services/swap-service/utils.d.ts +2 -4
  67. package/services/swap-service/utils.js +7 -47
  68. package/services/transaction-service/index.d.ts +1 -1
  69. package/services/transaction-service/index.js +30 -119
  70. package/services/transaction-service/types.d.ts +1 -0
  71. package/types/balance/index.d.ts +6 -10
  72. package/types/yield/info/pallet.d.ts +0 -6
@@ -5,11 +5,12 @@ import { BalanceService } from '@subwallet/extension-base/services/balance-servi
5
5
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
6
6
  import { SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
7
7
  import { BaseStepDetail } from '@subwallet/extension-base/types/service-base';
8
- import { OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
8
+ import { OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapProviderId, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
9
9
  export declare class ChainflipSwapHandler implements SwapBaseInterface {
10
10
  private swapSdk;
11
11
  private readonly isTestnet;
12
12
  private swapBaseHandler;
13
+ providerSlug: SwapProviderId;
13
14
  constructor(chainService: ChainService, balanceService: BalanceService, isTestnet?: boolean);
14
15
  get chainService(): ChainService;
15
16
  get balanceService(): BalanceService;
@@ -6,11 +6,12 @@ import { COMMON_ASSETS } from '@subwallet/chain-list';
6
6
  import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
7
7
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
8
8
  import { BasicTxErrorType, ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
9
+ import { _getChainflipEarlyValidationError } from '@subwallet/extension-base/core/logic-validation/swap';
9
10
  import { createTransferExtrinsic } from '@subwallet/extension-base/koni/api/dotsama/transfer';
10
11
  import { getERC20TransactionObject, getEVMTransactionObject } from '@subwallet/extension-base/koni/api/tokens/evm/transfer';
11
12
  import { _getAssetDecimals, _getChainNativeTokenSlug, _getContractAddressOfToken, _isNativeToken, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils';
12
13
  import { SwapBaseHandler } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
13
- import { calculateSwapRate, CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, getChainflipEarlyValidationError, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
14
+ import { calculateSwapRate, CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
14
15
  import { SwapErrorType, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
15
16
  import BigNumber from 'bignumber.js';
16
17
  var ChainflipFeeType;
@@ -37,6 +38,7 @@ export class ChainflipSwapHandler {
37
38
  providerSlug: isTestnet ? SwapProviderId.CHAIN_FLIP_TESTNET : SwapProviderId.CHAIN_FLIP_MAINNET
38
39
  });
39
40
  this.isTestnet = isTestnet;
41
+ this.providerSlug = isTestnet ? SwapProviderId.CHAIN_FLIP_TESTNET : SwapProviderId.CHAIN_FLIP_MAINNET;
40
42
  this.swapSdk = new SwapSDK({
41
43
  network: isTestnet ? 'perseverance' : 'mainnet'
42
44
  });
@@ -191,7 +193,7 @@ export class ChainflipSwapHandler {
191
193
  const earlyValidation = await this.validateSwapRequest(request);
192
194
  const metadata = earlyValidation.metadata;
193
195
  if (earlyValidation.error) {
194
- return getChainflipEarlyValidationError(earlyValidation.error, metadata);
196
+ return _getChainflipEarlyValidationError(earlyValidation.error, metadata);
195
197
  }
196
198
  const srcChainId = this.chainMapping[fromAsset.originChain];
197
199
  const destChainId = this.chainMapping[toAsset.originChain];
@@ -4,12 +4,13 @@ import { BalanceService } from '@subwallet/extension-base/services/balance-servi
4
4
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
5
5
  import { SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
6
6
  import { BaseStepDetail } from '@subwallet/extension-base/types/service-base';
7
- import { OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
7
+ import { OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapProviderId, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
8
8
  export declare class HydradxHandler implements SwapBaseInterface {
9
9
  private swapBaseHandler;
10
10
  private tradeRouter;
11
11
  private readonly isTestnet;
12
12
  isReady: boolean;
13
+ providerSlug: SwapProviderId;
13
14
  constructor(chainService: ChainService, balanceService: BalanceService, isTestnet?: boolean);
14
15
  init(): Promise<void>;
15
16
  chain: () => string;
@@ -7,10 +7,11 @@ import { _AssetType } from '@subwallet/chain-list/types';
7
7
  import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
8
8
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
9
9
  import { BasicTxErrorType, ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
10
+ import { _getEarlyHydradxValidationError } from '@subwallet/extension-base/core/logic-validation/swap';
10
11
  import { createXcmExtrinsic } from '@subwallet/extension-base/koni/api/xcm';
11
12
  import { _getAssetDecimals, _getChainNativeTokenSlug, _getTokenOnChainAssetId, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
12
13
  import { SwapBaseHandler } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
13
- import { calculateSwapRate, getEarlyHydradxValidationError, getSwapAlternativeAsset, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
14
+ import { calculateSwapRate, getSwapAlternativeAsset, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
14
15
  import { SwapErrorType, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
15
16
  import BigNumber from 'bignumber.js';
16
17
  const HYDRADX_LOW_LIQUIDITY_THRESHOLD = 0.15;
@@ -28,6 +29,7 @@ export class HydradxHandler {
28
29
  providerName: isTestnet ? 'HydraDX Testnet' : 'HydraDX',
29
30
  providerSlug: isTestnet ? SwapProviderId.HYDRADX_TESTNET : SwapProviderId.HYDRADX_MAINNET
30
31
  });
32
+ this.providerSlug = isTestnet ? SwapProviderId.HYDRADX_TESTNET : SwapProviderId.HYDRADX_MAINNET;
31
33
  this.isTestnet = isTestnet;
32
34
  }
33
35
  async init() {
@@ -67,7 +69,7 @@ export class HydradxHandler {
67
69
  async getXcmStep(params) {
68
70
  const bnAmount = new BigNumber(params.request.fromAmount);
69
71
  const fromAsset = this.chainService.getAssetBySlug(params.request.pair.from);
70
- const fromAssetBalance = await this.balanceService.getTokenFreeBalance(params.request.address, fromAsset.originChain, fromAsset.slug);
72
+ const fromAssetBalance = await this.balanceService.getTransferableBalance(params.request.address, fromAsset.originChain, fromAsset.slug);
71
73
  const bnFromAssetBalance = new BigNumber(fromAssetBalance.value);
72
74
  if (bnFromAssetBalance.gte(bnAmount)) {
73
75
  return undefined; // enough balance, no need to xcm
@@ -78,7 +80,7 @@ export class HydradxHandler {
78
80
  return undefined;
79
81
  }
80
82
  const alternativeAsset = this.chainService.getAssetBySlug(alternativeAssetSlug);
81
- const alternativeAssetBalance = await this.balanceService.getTokenFreeBalance(params.request.address, alternativeAsset.originChain, alternativeAsset.slug);
83
+ const alternativeAssetBalance = await this.balanceService.getTransferableBalance(params.request.address, alternativeAsset.originChain, alternativeAsset.slug);
82
84
  const bnAlternativeAssetBalance = new BigNumber(alternativeAssetBalance.value);
83
85
  if (bnAlternativeAssetBalance.lte(0)) {
84
86
  return undefined;
@@ -214,7 +216,7 @@ export class HydradxHandler {
214
216
  const earlyValidation = await this.validateSwapRequest(request);
215
217
  if (earlyValidation.error) {
216
218
  const metadata = earlyValidation.metadata;
217
- return getEarlyHydradxValidationError(earlyValidation.error, metadata);
219
+ return _getEarlyHydradxValidationError(earlyValidation.error, metadata);
218
220
  }
219
221
  try {
220
222
  const fromAssetId = _getTokenOnChainAssetId(fromAsset);
@@ -295,7 +297,7 @@ export class HydradxHandler {
295
297
  const destinationAsset = this.chainService.getAssetBySlug(pair.from);
296
298
  const substrateApi = this.chainService.getSubstrateApi(originAsset.originChain);
297
299
  const chainApi = await substrateApi.isReady;
298
- const destinationAssetBalance = await this.balanceService.getTokenFreeBalance(params.address, destinationAsset.originChain, destinationAsset.slug);
300
+ const destinationAssetBalance = await this.balanceService.getTransferableBalance(params.address, destinationAsset.originChain, destinationAsset.slug);
299
301
  const xcmFee = params.process.totalFee[params.currentStep];
300
302
  const bnAmount = new BigNumber(params.quote.fromAmount);
301
303
  const bnDestinationAssetBalance = new BigNumber(destinationAssetBalance.value);
@@ -7,7 +7,7 @@ import { BasicTxErrorType } from '@subwallet/extension-base/background/KoniTypes
7
7
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
8
8
  import { ChainflipSwapHandler } from '@subwallet/extension-base/services/swap-service/handler/chainflip-handler';
9
9
  import { HydradxHandler } from '@subwallet/extension-base/services/swap-service/handler/hydradx-handler';
10
- import { DEFAULT_SWAP_FIRST_STEP, getSwapAltToken, MOCK_SWAP_FEE, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
10
+ import { _PROVIDER_TO_SUPPORTED_PAIR_MAP, DEFAULT_SWAP_FIRST_STEP, getSwapAltToken, MOCK_SWAP_FEE, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
11
11
  import { _SUPPORTED_SWAP_PROVIDERS, SwapErrorType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
12
12
  import { createPromiseHandler } from '@subwallet/extension-base/utils';
13
13
  import { BehaviorSubject } from 'rxjs';
@@ -24,12 +24,18 @@ export class SwapService {
24
24
  }
25
25
  async askProvidersForQuote(request) {
26
26
  const availableQuotes = [];
27
+ const swappingSrcChain = this.chainService.getAssetBySlug(request.pair.from).originChain;
27
28
  await Promise.all(Object.values(this.handlers).map(async handler => {
29
+ // temporary solution to reduce number of requests to providers, will work as long as there's only 1 provider for 1 chain
30
+ if (!_PROVIDER_TO_SUPPORTED_PAIR_MAP[handler.providerSlug].includes(swappingSrcChain)) {
31
+ return;
32
+ }
28
33
  if (handler.init && handler.isReady === false) {
29
34
  await handler.init();
30
35
  }
31
36
  const quote = await handler.getSwapQuote(request);
32
37
  if (!(quote instanceof SwapError)) {
38
+ // todo: can do better
33
39
  availableQuotes.push({
34
40
  quote
35
41
  });
@@ -1,7 +1,6 @@
1
1
  import { Asset, Chain } from '@chainflip/sdk/swap';
2
2
  import { _ChainAsset } from '@subwallet/chain-list/types';
3
- import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
4
- import { ChainflipPreValidationMetadata, HydradxPreValidationMetadata, SwapErrorType, SwapFeeInfo, SwapPair, SwapStepDetail } from '@subwallet/extension-base/types/swap';
3
+ import { SwapFeeInfo, SwapPair, SwapStepDetail } 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";
7
6
  export declare const CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING: Record<string, Chain>;
@@ -11,8 +10,7 @@ export declare const CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING: Record<string,
11
10
  export declare const SWAP_QUOTE_TIMEOUT_MAP: Record<string, number>;
12
11
  export declare const DEFAULT_SWAP_FIRST_STEP: SwapStepDetail;
13
12
  export declare const MOCK_SWAP_FEE: SwapFeeInfo;
13
+ export declare const _PROVIDER_TO_SUPPORTED_PAIR_MAP: Record<string, string[]>;
14
14
  export declare function getSwapAlternativeAsset(swapPair: SwapPair): string | undefined;
15
15
  export declare function getSwapAltToken(chainAsset: _ChainAsset): string | undefined;
16
16
  export declare function calculateSwapRate(fromAmount: string, toAmount: string, fromAsset: _ChainAsset, toAsset: _ChainAsset): number;
17
- export declare function getChainflipEarlyValidationError(error: SwapErrorType, metadata: ChainflipPreValidationMetadata): SwapError;
18
- export declare function getEarlyHydradxValidationError(error: SwapErrorType, metadata: HydradxPreValidationMetadata): SwapError;
@@ -3,10 +3,8 @@
3
3
 
4
4
  import { Assets, Chains } from '@chainflip/sdk/swap';
5
5
  import { COMMON_ASSETS, COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
6
- import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
7
6
  import { _getAssetDecimals } from '@subwallet/extension-base/services/chain-service/utils';
8
- import { SwapErrorType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
9
- import { formatNumber } from '@subwallet/extension-base/utils';
7
+ import { SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
10
8
  import BigN from 'bignumber.js';
11
9
  export const CHAIN_FLIP_TESTNET_EXPLORER = 'https://blocks-perseverance.chainflip.io';
12
10
  export const CHAIN_FLIP_MAINNET_EXPLORER = 'https://scan.chainflip.io';
@@ -44,6 +42,12 @@ export const MOCK_SWAP_FEE = {
44
42
  defaultFeeToken: '',
45
43
  feeOptions: []
46
44
  };
45
+ export const _PROVIDER_TO_SUPPORTED_PAIR_MAP = {
46
+ [SwapProviderId.HYDRADX_MAINNET]: [COMMON_CHAIN_SLUGS.HYDRADX],
47
+ [SwapProviderId.HYDRADX_TESTNET]: [COMMON_CHAIN_SLUGS.HYDRADX_TESTNET],
48
+ [SwapProviderId.CHAIN_FLIP_MAINNET]: [COMMON_CHAIN_SLUGS.POLKADOT, COMMON_CHAIN_SLUGS.ETHEREUM],
49
+ [SwapProviderId.CHAIN_FLIP_TESTNET]: [COMMON_CHAIN_SLUGS.CHAINFLIP_POLKADOT, COMMON_CHAIN_SLUGS.ETHEREUM_SEPOLIA]
50
+ };
47
51
  export function getSwapAlternativeAsset(swapPair) {
48
52
  var _swapPair$metadata;
49
53
  return swapPair === null || swapPair === void 0 ? void 0 : (_swapPair$metadata = swapPair.metadata) === null || _swapPair$metadata === void 0 ? void 0 : _swapPair$metadata.alternativeAsset;
@@ -58,48 +62,4 @@ export function calculateSwapRate(fromAmount, toAmount, fromAsset, toAsset) {
58
62
  const decimalDiff = _getAssetDecimals(toAsset) - _getAssetDecimals(fromAsset);
59
63
  const bnRate = bnFromAmount.div(bnToAmount);
60
64
  return 1 / bnRate.times(10 ** decimalDiff).toNumber();
61
- }
62
- export function getChainflipEarlyValidationError(error, metadata) {
63
- // todo: support more providers
64
- switch (error) {
65
- case SwapErrorType.NOT_MEET_MIN_SWAP:
66
- {
67
- const parsedMinSwapValue = formatNumber(metadata.minSwap.value, metadata.minSwap.decimals);
68
- const message = `Amount too low. Increase your amount above ${parsedMinSwapValue} ${metadata.minSwap.symbol} and try again`;
69
- return new SwapError(error, message);
70
- }
71
- case SwapErrorType.SWAP_EXCEED_ALLOWANCE:
72
- {
73
- if (metadata.maxSwap) {
74
- const parsedMaxSwapValue = formatNumber(metadata.maxSwap.value, metadata.maxSwap.decimals);
75
- return new SwapError(error, `Amount too high. Lower your amount below ${parsedMaxSwapValue} ${metadata.maxSwap.symbol} and try again`);
76
- } else {
77
- return new SwapError(error, 'Amount too high. Lower your amount and try again');
78
- }
79
- }
80
- case SwapErrorType.ASSET_NOT_SUPPORTED:
81
- return new SwapError(error, 'This swap pair is not supported');
82
- case SwapErrorType.UNKNOWN:
83
- return new SwapError(error, `Undefined error. Check your Internet and ${metadata.chain.slug} connection or contact support`);
84
- case SwapErrorType.ERROR_FETCHING_QUOTE:
85
- return new SwapError(error, 'No swap quote found. Adjust your amount or try again later.');
86
- default:
87
- return new SwapError(error);
88
- }
89
- }
90
- export function getEarlyHydradxValidationError(error, metadata) {
91
- switch (error) {
92
- case SwapErrorType.AMOUNT_CANNOT_BE_ZERO:
93
- {
94
- return new SwapError(error, 'Amount too low. Increase your amount above 0 and try again');
95
- }
96
- case SwapErrorType.ASSET_NOT_SUPPORTED:
97
- return new SwapError(error, 'This swap pair is not supported');
98
- case SwapErrorType.UNKNOWN:
99
- return new SwapError(error, `Undefined error. Check your Internet and ${metadata.chain.slug} connection or contact support`);
100
- case SwapErrorType.ERROR_FETCHING_QUOTE:
101
- return new SwapError(error, 'No swap quote found. Adjust your amount or try again later.');
102
- default:
103
- return new SwapError(error);
104
- }
105
65
  }
@@ -18,7 +18,7 @@ export default class TransactionService {
18
18
  private get processingTransactions();
19
19
  getTransaction(id: string): SWTransaction;
20
20
  private checkDuplicate;
21
- generalValidate(validationInput: SWTransactionInput): Promise<SWTransactionResponse>;
21
+ validateTransaction(transactionInput: SWTransactionInput): Promise<SWTransactionResponse>;
22
22
  getTransactionSubject(): BehaviorSubject<Record<string, SWTransaction>>;
23
23
  private fillTransactionDefaultInfo;
24
24
  addTransaction(inputTransaction: SWTransactionInput): Promise<TransactionEmitter>;
@@ -3,11 +3,10 @@
3
3
 
4
4
  import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError';
5
5
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
6
- import { BasicTxErrorType, BasicTxWarningCode, ChainType, EvmProviderErrorType, ExtrinsicStatus, ExtrinsicType, NotificationType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
7
- import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning';
6
+ import { BasicTxErrorType, ChainType, EvmProviderErrorType, ExtrinsicStatus, ExtrinsicType, NotificationType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
8
7
  import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
8
+ import { checkBalanceWithTransactionFee, checkSigningAccountForTransaction, checkSupportForTransaction, estimateFeeForTransaction } from '@subwallet/extension-base/core/logic-validation/transfer';
9
9
  import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getEvmChainId, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
10
- import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils';
11
10
  import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants';
12
11
  import { TRANSACTION_TIMEOUT } from '@subwallet/extension-base/services/transaction-service/constants';
13
12
  import { parseLiquidStakingEvents, parseLiquidStakingFastUnstakeEvents, parseTransferEventLogs, parseXcmEventLogs } from '@subwallet/extension-base/services/transaction-service/event-parser';
@@ -20,14 +19,12 @@ import { mergeTransactionAndSignature } from '@subwallet/extension-base/utils/et
20
19
  import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction';
21
20
  import { BN_ZERO } from '@subwallet/extension-base/utils/number';
22
21
  import keyring from '@subwallet/ui-keyring';
23
- import BigN from 'bignumber.js';
24
22
  import { addHexPrefix } from 'ethereumjs-util';
25
23
  import { ethers } from 'ethers';
26
24
  import EventEmitter from 'eventemitter3';
27
25
  import { t } from 'i18next';
28
26
  import { BehaviorSubject, interval as rxjsInterval } from 'rxjs';
29
27
  import { isHex } from '@polkadot/util';
30
- import { _TRANSFER_CHAIN_GROUP } from "../chain-service/constants.js";
31
28
  export default class TransactionService {
32
29
  transactionSubject = new BehaviorSubject({});
33
30
  watchTransactionSubscribes = {};
@@ -58,134 +55,48 @@ export default class TransactionService {
58
55
  }
59
56
  return [];
60
57
  }
61
- async generalValidate(validationInput) {
62
- const validation = {
63
- ...validationInput,
64
- errors: validationInput.errors || [],
65
- warnings: validationInput.warnings || []
58
+ async validateTransaction(transactionInput) {
59
+ const validationResponse = {
60
+ ...transactionInput,
61
+ status: undefined,
62
+ errors: transactionInput.errors || [],
63
+ warnings: transactionInput.warnings || []
66
64
  };
67
65
  const {
68
66
  additionalValidator,
69
67
  address,
70
68
  chain,
71
- edAsWarning,
72
- extrinsicType,
73
- isTransferAll,
74
- transaction
75
- } = validation;
76
-
77
- // Check duplicate transaction
78
- validation.errors.push(...this.checkDuplicate(validationInput));
69
+ extrinsicType
70
+ } = validationResponse;
71
+ const transaction = transactionInput.transaction;
79
72
 
80
- // Return unsupported error if not found transaction
81
- if (!transaction) {
82
- if (extrinsicType === ExtrinsicType.SEND_NFT) {
83
- validation.errors.push(new TransactionError(BasicTxErrorType.UNSUPPORTED, t('This feature is not yet available for this NFT')));
84
- } else {
85
- validation.errors.push(new TransactionError(BasicTxErrorType.UNSUPPORTED));
86
- }
87
- }
88
- const validationResponse = {
89
- status: undefined,
90
- ...validation
91
- };
73
+ // Check duplicated transaction
74
+ validationResponse.errors.push(...this.checkDuplicate(transactionInput));
92
75
 
93
- // Estimate fee
94
- const estimateFee = {
95
- symbol: '',
96
- decimals: 0,
97
- value: '',
98
- tooHigh: false
99
- };
76
+ // Check support for transaction
77
+ checkSupportForTransaction(validationResponse, transaction);
100
78
  const chainInfo = this.state.chainService.getChainInfoByKey(chain);
101
79
  if (!chainInfo) {
102
80
  validationResponse.errors.push(new TransactionError(BasicTxErrorType.INTERNAL_ERROR, t('Cannot find network')));
103
- } else {
104
- const {
105
- decimals,
106
- symbol
107
- } = _getChainNativeTokenBasicInfo(chainInfo);
108
- estimateFee.decimals = decimals;
109
- estimateFee.symbol = symbol;
110
- if (transaction) {
111
- try {
112
- if (isSubstrateTransaction(transaction)) {
113
- estimateFee.value = (await transaction.paymentInfo(address)).partialFee.toString();
114
- } else {
115
- const web3 = this.state.chainService.getEvmApi(chain);
116
- if (!web3) {
117
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.CHAIN_DISCONNECTED, undefined));
118
- } else {
119
- const gasLimit = await web3.api.eth.estimateGas(transaction);
120
- const priority = await calculateGasFeeParams(web3, chainInfo.slug);
121
- if (priority.baseGasFee) {
122
- const maxFee = priority.maxFeePerGas; // TODO: Need review
123
-
124
- estimateFee.value = maxFee.multipliedBy(gasLimit).toFixed(0);
125
- } else {
126
- estimateFee.value = new BigN(priority.gasPrice).multipliedBy(gasLimit).toFixed(0);
127
- }
128
- estimateFee.tooHigh = priority.busyNetwork;
129
- }
130
- }
131
- } catch (e) {
132
- const error = e;
133
- if (error.message.includes('gas required exceeds allowance') && error.message.includes('insufficient funds')) {
134
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
135
- }
136
- estimateFee.value = '0';
137
- }
138
- }
139
81
  }
140
- validationResponse.estimateFee = estimateFee;
141
-
142
- // Read-only account
143
- const pair = keyring.getPair(address);
144
- if (!pair) {
145
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.INTERNAL_ERROR, t('Unable to find account')));
146
- } else {
147
- var _pair$meta;
148
- if ((_pair$meta = pair.meta) !== null && _pair$meta !== void 0 && _pair$meta.isReadOnly) {
149
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.INTERNAL_ERROR, t('This account is watch-only')));
150
- }
82
+ const evmApi = this.state.chainService.getEvmApi(chainInfo.slug);
83
+ const isNeedEvmApi = transaction && !isSubstrateTransaction(transaction) && !evmApi;
84
+ if (isNeedEvmApi) {
85
+ validationResponse.errors.push(new TransactionError(BasicTxErrorType.CHAIN_DISCONNECTED, undefined));
151
86
  }
152
87
 
153
- // Balance
154
- const transferNative = validationResponse.transferNativeAmount || '0';
88
+ // Estimate fee for transaction
89
+ validationResponse.estimateFee = await estimateFeeForTransaction(validationResponse, transaction, chainInfo, evmApi);
90
+
91
+ // Check account signing transaction
92
+ checkSigningAccountForTransaction(validationResponse);
155
93
  const nativeTokenInfo = this.state.chainService.getNativeTokenInfo(chain);
156
- const balance = await this.state.balanceService.getTokenFreeBalance(address, chain, nativeTokenInfo.slug);
157
- const existentialDeposit = nativeTokenInfo.minAmount || '0';
158
- const feeNum = parseInt(estimateFee.value);
159
- const balanceNum = parseInt(balance.value);
160
- const edNum = parseInt(existentialDeposit);
161
- const transferNativeNum = parseInt(transferNative);
162
- if (!validationInput.skipFeeValidation) {
163
- // TODO
164
- if (!new BigN(balance.value).gt(0)) {
165
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
166
- }
167
- if (transferNativeNum + feeNum > balanceNum) {
168
- if (!isTransferAll) {
169
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
170
- } else {
171
- if ([..._TRANSFER_CHAIN_GROUP.acala, ..._TRANSFER_CHAIN_GROUP.genshiro, ..._TRANSFER_CHAIN_GROUP.bitcountry, ..._TRANSFER_CHAIN_GROUP.statemine].includes(chain)) {
172
- // Chain not have transfer all function
173
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
174
- }
175
- }
176
- }
177
- if (!isTransferAll) {
178
- if (balanceNum - (transferNativeNum + feeNum) < edNum) {
179
- if (edAsWarning) {
180
- validationResponse.warnings.push(new TransactionWarning(BasicTxWarningCode.NOT_ENOUGH_EXISTENTIAL_DEPOSIT));
181
- } else {
182
- validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_EXISTENTIAL_DEPOSIT));
183
- }
184
- }
185
- }
186
- }
94
+ const nativeTokenAvailable = await this.state.balanceService.getTransferableBalance(address, chain, nativeTokenInfo.slug, extrinsicType);
95
+
96
+ // Check available balance against transaction fee
97
+ checkBalanceWithTransactionFee(validationResponse, transactionInput, nativeTokenInfo, nativeTokenAvailable);
187
98
 
188
- // Validate transaction with additionalValidator method
99
+ // Check additional validations
189
100
  additionalValidator && (await additionalValidator(validationResponse));
190
101
  return validationResponse;
191
102
  }
@@ -235,7 +146,7 @@ export default class TransactionService {
235
146
  };
236
147
  }
237
148
  async handleTransaction(transaction) {
238
- const validatedTransaction = await this.generalValidate(transaction);
149
+ const validatedTransaction = await this.validateTransaction(transaction);
239
150
  const stopByErrors = validatedTransaction.errors.length > 0;
240
151
  const stopByWarnings = validatedTransaction.warnings.length > 0 && !validatedTransaction.ignoreWarnings;
241
152
  if (stopByErrors || stopByWarnings) {
@@ -53,4 +53,5 @@ export interface TransactionEventMap {
53
53
  success: (response: TransactionEventResponse) => void;
54
54
  timeout: (response: TransactionEventResponse) => void;
55
55
  }
56
+ export declare type OptionalSWTransaction = SWTransaction['transaction'] | null | undefined;
56
57
  export {};
@@ -1,5 +1,5 @@
1
1
  import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
2
- import { APIItemState } from '@subwallet/extension-base/background/KoniTypes';
2
+ import { _BalanceMetadata, APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
3
3
  import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types';
4
4
  import { ApiPromise } from '@polkadot/api';
5
5
  import { BN } from '@polkadot/util';
@@ -8,20 +8,15 @@ export interface TokenBalanceRaw {
8
8
  frozen: BN;
9
9
  free: BN;
10
10
  }
11
- export interface SubstrateBalance {
12
- reserved?: string;
13
- miscFrozen?: string;
14
- feeFrozen?: string;
15
- }
16
11
  /**
17
12
  * Balance info of a token on an address
18
13
  * @property {string} address - Address
19
14
  * @property {string} tokenSlug - Slug of token
20
15
  * @property {APIItemState} state - State of information
21
16
  * @property {number} [timestamp] - Time to get information
22
- * @property {string} free - Free balance
23
- * @property {string} locked - Locked balance
24
- * @property {SubstrateBalance} [substrateInfo] - Substrate info of balance
17
+ * @property {string} free - Transferable balance
18
+ * @property {string} locked - Locked balance, cannot be transferred, locked here is only meaningful in the context of token transfer
19
+ * @property {metadata} [metadata] - Could be anything, supposed to be generic to handle various contexts
25
20
  */
26
21
  export interface BalanceItem {
27
22
  address: string;
@@ -30,7 +25,7 @@ export interface BalanceItem {
30
25
  timestamp?: number;
31
26
  free: string;
32
27
  locked: string;
33
- substrateInfo?: SubstrateBalance;
28
+ metadata?: _BalanceMetadata;
34
29
  }
35
30
  /** Balance info of all tokens on an address */
36
31
  export declare type BalanceInfo = Record<string, BalanceItem>;
@@ -45,6 +40,7 @@ export interface SubscribeBasePalletBalance {
45
40
  assetMap: Record<string, _ChainAsset>;
46
41
  chainInfo: _ChainInfo;
47
42
  callback: (rs: BalanceItem[]) => void;
43
+ extrinsicType?: ExtrinsicType;
48
44
  }
49
45
  export interface SubscribeSubstratePalletBalance extends SubscribeBasePalletBalance {
50
46
  substrateApi: ApiPromise;
@@ -1,10 +1,4 @@
1
1
  import { BN } from '@polkadot/util';
2
- export interface PalletNominationPoolsPoolMember {
3
- poolId: number;
4
- points: number;
5
- lasRecordedRewardCounter: number;
6
- unbondingEras: Record<string, number>;
7
- }
8
2
  export interface PalletStakingExposureItem {
9
3
  who: string;
10
4
  value: number;