@subwallet/extension-base 1.2.2-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.
- package/background/KoniTypes.d.ts +4 -0
- package/cjs/core/logic-validation/earning.js +47 -0
- package/cjs/core/logic-validation/swap.js +99 -0
- package/cjs/core/logic-validation/transfer.js +219 -0
- package/cjs/core/substrate/nominationpools-pallet.js +12 -0
- package/cjs/core/substrate/system-pallet.js +78 -0
- package/cjs/koni/api/dotsama/transfer.js +49 -4
- package/cjs/koni/api/staking/bonding/utils.js +1 -1
- package/cjs/koni/api/xcm/index.js +30 -2
- package/cjs/koni/background/handlers/Extension.js +135 -245
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/helpers/group.js +4 -27
- package/cjs/services/balance-service/helpers/subscribe/index.js +2 -30
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +41 -80
- package/cjs/services/balance-service/index.js +11 -9
- package/cjs/services/chain-service/index.js +0 -1
- package/cjs/services/chain-service/utils/index.js +6 -0
- package/cjs/services/earning-service/handlers/base.js +1 -1
- package/cjs/services/earning-service/handlers/special.js +11 -12
- package/cjs/services/swap-service/handler/base-handler.js +28 -44
- package/cjs/services/swap-service/handler/chainflip-handler.js +23 -21
- package/cjs/services/swap-service/handler/hydradx-handler.js +40 -38
- package/cjs/services/swap-service/index.js +6 -0
- package/cjs/services/swap-service/utils.js +8 -49
- package/cjs/services/transaction-service/index.js +66 -155
- package/core/logic-validation/earning.d.ts +10 -0
- package/core/logic-validation/earning.js +37 -0
- package/core/logic-validation/swap.d.ts +8 -0
- package/core/logic-validation/swap.js +89 -0
- package/core/logic-validation/transfer.d.ts +16 -0
- package/core/logic-validation/transfer.js +206 -0
- package/core/substrate/nominationpools-pallet.d.ts +7 -0
- package/core/substrate/nominationpools-pallet.js +6 -0
- package/core/substrate/system-pallet.d.ts +27 -0
- package/core/substrate/system-pallet.js +71 -0
- package/koni/api/dotsama/transfer.d.ts +3 -1
- package/koni/api/dotsama/transfer.js +44 -1
- package/koni/api/staking/bonding/relayChain.d.ts +2 -1
- package/koni/api/staking/bonding/utils.js +1 -1
- package/koni/api/xcm/index.d.ts +2 -0
- package/koni/api/xcm/index.js +27 -1
- package/koni/background/handlers/Extension.d.ts +5 -5
- package/koni/background/handlers/Extension.js +111 -221
- package/package.json +34 -9
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/group.js +4 -27
- package/services/balance-service/helpers/subscribe/index.d.ts +2 -1
- package/services/balance-service/helpers/subscribe/index.js +2 -30
- package/services/balance-service/helpers/subscribe/substrate/index.d.ts +2 -1
- package/services/balance-service/helpers/subscribe/substrate/index.js +26 -64
- package/services/balance-service/index.d.ts +7 -6
- package/services/balance-service/index.js +12 -10
- package/services/chain-service/index.js +0 -1
- package/services/chain-service/utils/index.d.ts +1 -0
- package/services/chain-service/utils/index.js +4 -0
- package/services/earning-service/handlers/base.js +1 -1
- package/services/earning-service/handlers/nomination-pool/index.d.ts +2 -1
- package/services/earning-service/handlers/special.js +11 -12
- package/services/swap-service/handler/base-handler.d.ts +3 -2
- package/services/swap-service/handler/base-handler.js +26 -42
- package/services/swap-service/handler/chainflip-handler.d.ts +2 -1
- package/services/swap-service/handler/chainflip-handler.js +4 -2
- package/services/swap-service/handler/hydradx-handler.d.ts +2 -1
- package/services/swap-service/handler/hydradx-handler.js +7 -5
- package/services/swap-service/index.js +7 -1
- package/services/swap-service/utils.d.ts +2 -4
- package/services/swap-service/utils.js +7 -47
- package/services/transaction-service/index.d.ts +1 -1
- package/services/transaction-service/index.js +30 -119
- package/services/transaction-service/types.d.ts +1 -0
- package/types/balance/index.d.ts +6 -10
- 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,
|
|
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
|
|
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,
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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,
|
|
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
|
|
62
|
-
const
|
|
63
|
-
...
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
//
|
|
81
|
-
|
|
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
|
-
//
|
|
94
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
//
|
|
154
|
-
|
|
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
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
//
|
|
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.
|
|
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 {};
|
package/types/balance/index.d.ts
CHANGED
|
@@ -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 -
|
|
23
|
-
* @property {string} locked - Locked balance
|
|
24
|
-
* @property {
|
|
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
|
-
|
|
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;
|