@subwallet/extension-base 1.3.17-0 → 1.3.18-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 (127) hide show
  1. package/background/KoniTypes.d.ts +7 -2
  2. package/cjs/constants/index.js +6 -3
  3. package/cjs/core/logic-validation/request.js +26 -19
  4. package/cjs/core/logic-validation/transfer.js +18 -17
  5. package/cjs/koni/api/contract-handler/evm/web3.js +3 -3
  6. package/cjs/koni/background/handlers/Extension.js +269 -123
  7. package/cjs/koni/background/handlers/State.js +1 -8
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +1 -1
  10. package/cjs/services/balance-service/index.js +13 -0
  11. package/cjs/services/balance-service/transfer/smart-contract.js +47 -33
  12. package/cjs/services/balance-service/transfer/token.js +5 -4
  13. package/cjs/services/balance-service/transfer/xcm/availBridge.js +14 -18
  14. package/cjs/services/balance-service/transfer/xcm/index.js +30 -61
  15. package/cjs/services/balance-service/transfer/xcm/polygonBridge.js +13 -17
  16. package/cjs/services/balance-service/transfer/xcm/posBridge.js +20 -21
  17. package/cjs/services/balance-service/transfer/xcm/snowBridge.js +7 -7
  18. package/cjs/services/balance-service/transfer/xcm/utils.js +2 -2
  19. package/cjs/services/chain-service/constants.js +3 -3
  20. package/cjs/services/earning-service/handlers/liquid-staking/stella-swap.js +7 -12
  21. package/cjs/services/earning-service/handlers/special.js +15 -4
  22. package/cjs/services/fee-service/interfaces.js +1 -0
  23. package/cjs/services/fee-service/service.js +111 -0
  24. package/cjs/services/fee-service/utils/index.js +99 -113
  25. package/cjs/services/storage-service/db-stores/Balance.js +3 -0
  26. package/cjs/services/swap-service/handler/asset-hub/handler.js +23 -7
  27. package/cjs/services/swap-service/handler/asset-hub/router.js +1 -1
  28. package/cjs/services/swap-service/handler/asset-hub/utils.js +4 -4
  29. package/cjs/services/swap-service/handler/base-handler.js +3 -1
  30. package/cjs/services/swap-service/handler/chainflip-handler.js +26 -5
  31. package/cjs/services/swap-service/handler/hydradx-handler.js +23 -8
  32. package/cjs/services/swap-service/handler/simpleswap-handler.js +24 -4
  33. package/cjs/services/swap-service/index.js +8 -8
  34. package/cjs/services/transaction-service/index.js +23 -3
  35. package/cjs/types/balance/transfer.js +1 -0
  36. package/cjs/types/fee/base.js +1 -0
  37. package/cjs/types/fee/evm.js +16 -1
  38. package/cjs/types/fee/index.js +37 -4
  39. package/cjs/types/fee/option.js +1 -0
  40. package/cjs/types/fee/subscription.js +1 -0
  41. package/cjs/types/fee/substrate.js +1 -0
  42. package/cjs/types/fee/ton.js +1 -0
  43. package/cjs/utils/fee/combine.js +50 -0
  44. package/cjs/utils/fee/index.js +27 -0
  45. package/cjs/utils/fee/transfer.js +374 -0
  46. package/cjs/utils/index.js +12 -0
  47. package/constants/index.d.ts +1 -0
  48. package/constants/index.js +1 -0
  49. package/core/logic-validation/request.js +17 -10
  50. package/core/logic-validation/transfer.d.ts +5 -5
  51. package/core/logic-validation/transfer.js +20 -19
  52. package/core/substrate/xcm-parser.d.ts +1 -1
  53. package/koni/api/contract-handler/evm/web3.js +3 -3
  54. package/koni/background/handlers/Extension.d.ts +3 -3
  55. package/koni/background/handlers/Extension.js +253 -107
  56. package/koni/background/handlers/State.js +1 -8
  57. package/package.json +55 -5
  58. package/packageInfo.js +1 -1
  59. package/services/balance-service/helpers/subscribe/substrate/index.js +1 -1
  60. package/services/balance-service/index.d.ts +1 -0
  61. package/services/balance-service/index.js +13 -0
  62. package/services/balance-service/transfer/smart-contract.d.ts +24 -4
  63. package/services/balance-service/transfer/smart-contract.js +45 -33
  64. package/services/balance-service/transfer/token.js +6 -5
  65. package/services/balance-service/transfer/xcm/availBridge.d.ts +3 -2
  66. package/services/balance-service/transfer/xcm/availBridge.js +11 -15
  67. package/services/balance-service/transfer/xcm/index.d.ts +12 -11
  68. package/services/balance-service/transfer/xcm/index.js +29 -58
  69. package/services/balance-service/transfer/xcm/polygonBridge.d.ts +4 -3
  70. package/services/balance-service/transfer/xcm/polygonBridge.js +13 -17
  71. package/services/balance-service/transfer/xcm/posBridge.d.ts +4 -3
  72. package/services/balance-service/transfer/xcm/posBridge.js +18 -19
  73. package/services/balance-service/transfer/xcm/snowBridge.d.ts +2 -1
  74. package/services/balance-service/transfer/xcm/snowBridge.js +7 -7
  75. package/services/balance-service/transfer/xcm/utils.js +2 -2
  76. package/services/chain-service/constants.js +3 -3
  77. package/services/earning-service/handlers/liquid-staking/stella-swap.js +7 -12
  78. package/services/earning-service/handlers/special.js +15 -4
  79. package/services/fee-service/interfaces.d.ts +5 -0
  80. package/services/fee-service/interfaces.js +1 -0
  81. package/services/fee-service/service.d.ts +4 -1
  82. package/services/fee-service/service.js +111 -0
  83. package/services/fee-service/utils/index.d.ts +8 -2
  84. package/services/fee-service/utils/index.js +92 -108
  85. package/services/storage-service/db-stores/Balance.d.ts +1 -0
  86. package/services/storage-service/db-stores/Balance.js +3 -0
  87. package/services/swap-service/handler/asset-hub/handler.d.ts +2 -1
  88. package/services/swap-service/handler/asset-hub/handler.js +23 -7
  89. package/services/swap-service/handler/asset-hub/router.js +2 -2
  90. package/services/swap-service/handler/asset-hub/utils.d.ts +1 -1
  91. package/services/swap-service/handler/asset-hub/utils.js +2 -2
  92. package/services/swap-service/handler/base-handler.d.ts +4 -1
  93. package/services/swap-service/handler/base-handler.js +3 -1
  94. package/services/swap-service/handler/chainflip-handler.d.ts +2 -1
  95. package/services/swap-service/handler/chainflip-handler.js +25 -4
  96. package/services/swap-service/handler/hydradx-handler.d.ts +2 -1
  97. package/services/swap-service/handler/hydradx-handler.js +22 -7
  98. package/services/swap-service/handler/simpleswap-handler.d.ts +2 -1
  99. package/services/swap-service/handler/simpleswap-handler.js +24 -4
  100. package/services/swap-service/index.js +8 -8
  101. package/services/transaction-service/index.js +23 -3
  102. package/services/transaction-service/types.d.ts +5 -4
  103. package/types/balance/transfer.d.ts +25 -0
  104. package/types/balance/transfer.js +1 -0
  105. package/types/fee/base.d.ts +8 -0
  106. package/types/fee/base.js +1 -0
  107. package/types/fee/evm.d.ts +46 -16
  108. package/types/fee/evm.js +10 -1
  109. package/types/fee/index.d.ts +4 -1
  110. package/types/fee/index.js +4 -1
  111. package/types/fee/option.d.ts +8 -0
  112. package/types/fee/option.js +1 -0
  113. package/types/fee/subscription.d.ts +12 -0
  114. package/types/fee/subscription.js +1 -0
  115. package/types/fee/substrate.d.ts +15 -0
  116. package/types/fee/substrate.js +1 -0
  117. package/types/fee/ton.d.ts +18 -0
  118. package/types/fee/ton.js +1 -0
  119. package/types/transaction/request.d.ts +13 -3
  120. package/utils/fee/combine.d.ts +12 -0
  121. package/utils/fee/combine.js +42 -0
  122. package/utils/fee/index.d.ts +2 -0
  123. package/utils/fee/index.js +5 -0
  124. package/utils/fee/transfer.d.ts +22 -0
  125. package/utils/fee/transfer.js +363 -0
  126. package/utils/index.d.ts +1 -0
  127. package/utils/index.js +1 -0
@@ -6,6 +6,11 @@ import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-se
6
6
  import { BehaviorSubject } from 'rxjs';
7
7
  export default class FeeService {
8
8
  evmFeeSubject = new BehaviorSubject({});
9
+ chainFeeSubscriptionMap = {
10
+ evm: {},
11
+ substrate: {},
12
+ ton: {}
13
+ };
9
14
  constructor(state) {
10
15
  this.state = state;
11
16
  this.useInfura = true;
@@ -60,4 +65,110 @@ export default class FeeService {
60
65
  clearInterval(interval);
61
66
  };
62
67
  }
68
+ subscribeChainFee(id, chain, type, callback) {
69
+ return new Promise(resolve => {
70
+ const _callback = value => {
71
+ if (value) {
72
+ callback === null || callback === void 0 ? void 0 : callback(value);
73
+ resolve(value);
74
+ }
75
+ };
76
+ const feeSubscription = this.chainFeeSubscriptionMap[type][chain];
77
+ if (feeSubscription) {
78
+ const observer = feeSubscription.observer;
79
+ _callback(observer.getValue());
80
+
81
+ // If have callback, just subscribe
82
+ if (callback) {
83
+ const subscription = observer.subscribe({
84
+ next: _callback
85
+ });
86
+ this.chainFeeSubscriptionMap[type][chain].subscription[id] = () => {
87
+ if (!subscription.closed) {
88
+ subscription.unsubscribe();
89
+ }
90
+ };
91
+ }
92
+ } else {
93
+ const observer = new BehaviorSubject(undefined);
94
+ const subscription = observer.subscribe({
95
+ next: _callback
96
+ });
97
+ let cancel = false;
98
+ let interval;
99
+ const update = () => {
100
+ if (cancel) {
101
+ clearInterval(interval);
102
+ } else {
103
+ const api = this.state.getEvmApi(chain);
104
+ if (api) {
105
+ calculateGasFeeParams(api, chain).then(info => {
106
+ observer.next(info);
107
+ }).catch(e => {
108
+ console.warn(`Cannot get fee param for ${chain}`, e);
109
+ observer.next({
110
+ type: 'evm',
111
+ gasPrice: '0',
112
+ baseGasFee: undefined,
113
+ options: undefined
114
+ });
115
+ });
116
+ } else {
117
+ observer.next({
118
+ type: type,
119
+ busyNetwork: false,
120
+ options: {
121
+ slow: {
122
+ tip: '0'
123
+ },
124
+ average: {
125
+ tip: '0'
126
+ },
127
+ fast: {
128
+ tip: '0'
129
+ },
130
+ default: 'slow'
131
+ }
132
+ });
133
+ clearInterval(interval);
134
+ }
135
+ }
136
+ };
137
+ update();
138
+
139
+ // If have callback, just subscribe
140
+ if (callback) {
141
+ interval = setInterval(update, 15 * 1000);
142
+ const unsub = () => {
143
+ cancel = true;
144
+ observer.complete();
145
+ clearInterval(interval);
146
+ };
147
+ this.chainFeeSubscriptionMap[type][chain] = {
148
+ observer,
149
+ subscription: {
150
+ [id]: () => {
151
+ if (!subscription.closed) {
152
+ subscription.unsubscribe();
153
+ }
154
+ }
155
+ },
156
+ unsubscribe: unsub
157
+ };
158
+ }
159
+ }
160
+ });
161
+ }
162
+ unsubscribeChainFee(id, chain, type) {
163
+ const subscription = this.chainFeeSubscriptionMap[type][chain];
164
+ if (subscription) {
165
+ const unsub = subscription.subscription[id];
166
+ unsub && unsub();
167
+ delete subscription.subscription[id];
168
+ if (Object.keys(subscription.subscription).length === 0) {
169
+ subscription.unsubscribe();
170
+ delete this.chainFeeSubscriptionMap[type][chain];
171
+ }
172
+ }
173
+ }
63
174
  }
@@ -1,8 +1,14 @@
1
+ import { _ChainAsset } from '@subwallet/chain-list/types';
1
2
  import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types';
2
- import { EvmFeeInfo, InfuraFeeInfo } from '@subwallet/extension-base/types';
3
- export declare const parseInfuraFee: (info: InfuraFeeInfo) => EvmFeeInfo;
3
+ import { EvmEIP1559FeeOption, EvmFeeInfo, InfuraFeeInfo, InfuraThresholdInfo } from '@subwallet/extension-base/types';
4
+ import BigN from 'bignumber.js';
5
+ import { ApiPromise } from '@polkadot/api';
6
+ export declare const FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE = 105;
7
+ export declare const parseInfuraFee: (info: InfuraFeeInfo, threshold: InfuraThresholdInfo) => EvmFeeInfo;
4
8
  export declare const fetchInfuraFeeData: (chainId: number, infuraAuth?: string) => Promise<EvmFeeInfo | null>;
5
9
  export declare const fetchSubWalletFeeData: (chainId: number, networkKey: string) => Promise<EvmFeeInfo | null>;
6
10
  export declare const fetchOnlineFeeData: (chainId: number, networkKey: string, useInfura?: boolean) => Promise<EvmFeeInfo | null>;
7
11
  export declare const recalculateGasPrice: (_price: string, chain: string) => string;
12
+ export declare const getEIP1559GasFee: (baseFee: BigN, maxPriorityFee: BigN, blockNumber: number, blockTime: number) => EvmEIP1559FeeOption;
8
13
  export declare const calculateGasFeeParams: (web3: _EvmApi, networkKey: string, useOnline?: boolean, useInfura?: boolean) => Promise<EvmFeeInfo>;
14
+ export declare const calculateToAmountByReservePool: (api: ApiPromise, fromToken: _ChainAsset, toToken: _ChainAsset, fromAmount: string) => Promise<string>;
@@ -2,64 +2,84 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { GAS_PRICE_RATIO, NETWORK_MULTI_GAS_FEE } from '@subwallet/extension-base/constants';
5
+ import { estimateTokensForPool, getReserveForPool } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
5
6
  import { BN_WEI, BN_ZERO } from '@subwallet/extension-base/utils';
6
7
  import BigN from 'bignumber.js';
7
8
  import { POLYGON_GAS_INDEXER } from "../../balance-service/transfer/xcm/polygonBridge.js";
8
9
  const INFURA_API_KEY = process.env.INFURA_API_KEY || '';
9
10
  const INFURA_API_KEY_SECRET = process.env.INFURA_API_KEY_SECRET || '';
10
11
  const INFURA_AUTH = 'Basic ' + Buffer.from(INFURA_API_KEY + ':' + INFURA_API_KEY_SECRET).toString('base64');
11
- export const parseInfuraFee = info => {
12
+ export const FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE = 105; // percentage
13
+
14
+ export const parseInfuraFee = (info, threshold) => {
12
15
  const base = new BigN(info.estimatedBaseFee).multipliedBy(BN_WEI);
13
- const low = new BigN(info.low.suggestedMaxPriorityFeePerGas).multipliedBy(BN_WEI);
14
- const busyNetwork = base.gt(BN_ZERO) ? low.dividedBy(base).gte(0.3) : false;
15
- const data = !busyNetwork ? info.low : info.medium;
16
+ const thresholdBN = new BigN(threshold.busyThreshold).multipliedBy(BN_WEI);
17
+ const busyNetwork = thresholdBN.gte(BN_ZERO) ? base.gt(thresholdBN) : false;
16
18
  return {
17
19
  busyNetwork,
18
20
  gasPrice: undefined,
19
- baseGasFee: base,
20
- maxFeePerGas: new BigN(data.suggestedMaxFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP),
21
- maxPriorityFeePerGas: new BigN(data.suggestedMaxPriorityFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP)
21
+ baseGasFee: base.toFixed(0),
22
+ type: 'evm',
23
+ options: {
24
+ slow: {
25
+ maxFeePerGas: new BigN(info.low.suggestedMaxFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP).toFixed(0),
26
+ maxPriorityFeePerGas: new BigN(info.low.suggestedMaxPriorityFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP).toFixed(0),
27
+ maxWaitTimeEstimate: info.low.maxWaitTimeEstimate || 0,
28
+ minWaitTimeEstimate: info.low.minWaitTimeEstimate || 0
29
+ },
30
+ average: {
31
+ maxFeePerGas: new BigN(info.medium.suggestedMaxFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP).toFixed(0),
32
+ maxPriorityFeePerGas: new BigN(info.medium.suggestedMaxPriorityFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP).toFixed(0),
33
+ maxWaitTimeEstimate: info.medium.maxWaitTimeEstimate || 0,
34
+ minWaitTimeEstimate: info.medium.minWaitTimeEstimate || 0
35
+ },
36
+ fast: {
37
+ maxFeePerGas: new BigN(info.high.suggestedMaxFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP).toFixed(0),
38
+ maxPriorityFeePerGas: new BigN(info.high.suggestedMaxPriorityFeePerGas).multipliedBy(BN_WEI).integerValue(BigN.ROUND_UP).toFixed(0),
39
+ maxWaitTimeEstimate: info.high.maxWaitTimeEstimate || 0,
40
+ minWaitTimeEstimate: info.high.minWaitTimeEstimate || 0
41
+ },
42
+ default: busyNetwork ? 'average' : 'slow'
43
+ }
22
44
  };
23
45
  };
24
46
  export const fetchInfuraFeeData = async (chainId, infuraAuth) => {
25
- return await new Promise(resolve => {
26
- const baseUrl = 'https://gas.api.infura.io/networks/{{chainId}}/suggestedGasFees';
27
- const url = baseUrl.replaceAll('{{chainId}}', chainId.toString());
28
- fetch(url, {
29
- method: 'GET',
30
- headers: {
31
- Authorization: infuraAuth || INFURA_AUTH
32
- }
33
- }).then(rs => {
34
- return rs.json();
35
- }).then(info => {
36
- resolve(parseInfuraFee(info));
37
- }).catch(e => {
38
- console.warn(e);
39
- resolve(null);
40
- });
41
- });
47
+ const baseUrl = 'https://gas.api.infura.io/networks/{{chainId}}/suggestedGasFees';
48
+ const baseThressholdUrl = 'https://gas.api.infura.io/networks/{{chainId}}/busyThreshold';
49
+ // const baseFeeHistoryUrl = 'https://gas.api.infura.io/networks/{{chainId}}/baseFeeHistory';
50
+ // const baseFeePercentileUrl = 'https://gas.api.infura.io/networks/{{chainId}}/baseFeePercentile';
51
+ const feeUrl = baseUrl.replaceAll('{{chainId}}', chainId.toString());
52
+ const thressholdUrl = baseThressholdUrl.replaceAll('{{chainId}}', chainId.toString());
53
+ try {
54
+ const [feeResp, thressholdResp] = await Promise.all([feeUrl, thressholdUrl].map(url => {
55
+ return fetch(url, {
56
+ method: 'GET',
57
+ headers: {
58
+ Authorization: INFURA_AUTH
59
+ }
60
+ });
61
+ }));
62
+
63
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
64
+ const [feeInfo, thresholdInfo] = await Promise.all([feeResp.json(), thressholdResp.json()]);
65
+ return parseInfuraFee(feeInfo, thresholdInfo);
66
+ } catch (e) {
67
+ console.warn(e);
68
+ return null;
69
+ }
42
70
  };
43
71
  export const fetchSubWalletFeeData = async (chainId, networkKey) => {
44
72
  return await new Promise(resolve => {
45
73
  const baseUrl = 'https://api-cache.subwallet.app/sw-evm-gas/{{chain}}';
46
74
  const url = baseUrl.replaceAll('{{chain}}', networkKey);
75
+
76
+ // TODO: Update the logo to follow the new estimateFee format or move the logic to the backend
47
77
  fetch(url, {
48
78
  method: 'GET'
49
79
  }).then(rs => {
50
80
  return rs.json();
51
81
  }).then(info => {
52
- if (info.gasPrice !== undefined) {
53
- resolve(info);
54
- } else {
55
- resolve({
56
- busyNetwork: info.busyNetwork,
57
- gasPrice: info.gasPrice,
58
- baseGasFee: new BigN(info.baseGasFee),
59
- maxFeePerGas: new BigN(info.maxFeePerGas),
60
- maxPriorityFeePerGas: new BigN(info.maxPriorityFeePerGas)
61
- });
62
- }
82
+ resolve(info);
63
83
  }).catch(e => {
64
84
  console.warn(e);
65
85
  resolve(null);
@@ -81,7 +101,17 @@ export const recalculateGasPrice = (_price, chain) => {
81
101
  const needMulti = NETWORK_MULTI_GAS_FEE.includes(chain) || NETWORK_MULTI_GAS_FEE.includes('*');
82
102
  return needMulti ? new BigN(_price).multipliedBy(GAS_PRICE_RATIO).toFixed(0) : _price;
83
103
  };
84
- export const calculateGasFeeParams = async (web3, networkKey, useOnline = true, useInfura = false) => {
104
+ export const getEIP1559GasFee = (baseFee, maxPriorityFee, blockNumber, blockTime) => {
105
+ // https://www.blocknative.com/blog/eip-1559-fees
106
+ const maxFee = baseFee.multipliedBy(1.2).plus(maxPriorityFee);
107
+ return {
108
+ maxFeePerGas: maxFee.toFixed(0),
109
+ maxPriorityFeePerGas: maxPriorityFee.toFixed(0),
110
+ minWaitTimeEstimate: blockTime * (blockNumber - 2),
111
+ maxWaitTimeEstimate: blockTime * blockNumber
112
+ };
113
+ };
114
+ export const calculateGasFeeParams = async (web3, networkKey, useOnline = true, useInfura = true) => {
85
115
  if (useOnline) {
86
116
  try {
87
117
  const chainId = await web3.api.eth.getChainId();
@@ -98,19 +128,19 @@ export const calculateGasFeeParams = async (web3, networkKey, useOnline = true,
98
128
  const gasResponse = await fetch(`${gasDomain}`).then(res => res.json());
99
129
  const gasPriceInWei = gasResponse.standard * 1e9 + 200000;
100
130
  return {
131
+ type: 'evm',
101
132
  gasPrice: gasPriceInWei.toString(),
102
- maxFeePerGas: undefined,
103
- maxPriorityFeePerGas: undefined,
104
133
  baseGasFee: undefined,
105
- busyNetwork: false
134
+ busyNetwork: false,
135
+ options: undefined
106
136
  };
107
137
  }
108
138
  const numBlock = 20;
109
- const rewardPercent = [];
110
- for (let i = 0; i <= 100; i = i + 5) {
111
- rewardPercent.push(i);
112
- }
139
+ const rewardPercent = [25, 50, 75];
113
140
  const history = await web3.api.eth.getFeeHistory(numBlock, 'latest', rewardPercent);
141
+ const currentBlock = history.oldestBlock - 1;
142
+ const [newBlock, oldBlock] = await Promise.all([web3.api.eth.getBlock(currentBlock), web3.api.eth.getBlock(currentBlock - numBlock)]);
143
+ const blockTime = Number((BigInt(newBlock.timestamp || 0) - BigInt(oldBlock.timestamp || 0)) / BigInt(numBlock) * BigInt(1000));
114
144
  const baseGasFee = new BigN(history.baseFeePerGas[history.baseFeePerGas.length - 1]); // Last element is latest
115
145
 
116
146
  const blocksBusy = history.reward.reduce((previous, rewards, currentIndex) => {
@@ -128,80 +158,34 @@ export const calculateGasFeeParams = async (web3, networkKey, useOnline = true,
128
158
  }, 0);
129
159
  const busyNetwork = blocksBusy >= numBlock / 2; // True, if half of block is busy
130
160
 
131
- const maxPriorityFeePerGas = history.reward.reduce((previous, rewards) => {
132
- let firstBN = BN_ZERO;
133
- let firstIndex = 0;
134
-
135
- /* Get first priority which greater than 0 */
136
- for (let i = 0; i < rewards.length; i++) {
137
- firstIndex = i;
138
- const current = rewards[i];
139
- const currentBN = new BigN(current);
140
- if (currentBN.gt(BN_ZERO)) {
141
- firstBN = currentBN;
142
- break;
143
- }
144
- }
145
- let secondBN = firstBN;
146
-
147
- /* Get second priority which greater than first priority */
148
- for (let i = firstIndex; i < rewards.length; i++) {
149
- const current = rewards[i];
150
- const currentBN = new BigN(current);
151
- if (currentBN.gt(firstBN)) {
152
- secondBN = currentBN;
153
- break;
154
- }
155
- }
156
- let current;
157
- if (busyNetwork) {
158
- current = secondBN.dividedBy(2).gte(firstBN) ? firstBN : secondBN; // second too larger than first (> 2 times), use first else use second
159
- } else {
160
- current = firstBN;
161
- }
162
- if (busyNetwork) {
163
- /* Get max value */
164
- return current.gte(previous) ? current : previous; // get max priority
165
- } else {
166
- /* Get min value which greater than 0 */
167
- if (previous.eq(BN_ZERO)) {
168
- return current; // get min priority
169
- } else if (current.eq(BN_ZERO)) {
170
- return previous;
171
- }
172
- return current.lte(previous) ? current : previous; // get min priority
173
- }
174
- }, BN_ZERO);
175
- if (maxPriorityFeePerGas.eq(BN_ZERO)) {
176
- const _price = await web3.api.eth.getGasPrice();
177
- const gasPrice = recalculateGasPrice(_price, networkKey);
178
- return {
179
- gasPrice,
180
- maxFeePerGas: undefined,
181
- maxPriorityFeePerGas: undefined,
182
- baseGasFee: undefined,
183
- busyNetwork: false
184
- };
185
- }
186
-
187
- /* Max gas = (base + priority) * 1.5 (if not busy or 2 when busy); */
188
- const maxFeePerGas = baseGasFee.plus(maxPriorityFeePerGas).multipliedBy(busyNetwork ? 2 : 1.5).decimalPlaces(0);
161
+ const slowPriorityFee = history.reward.reduce((previous, rewards) => previous.plus(rewards[0]), BN_ZERO).dividedBy(numBlock).decimalPlaces(0);
162
+ const averagePriorityFee = history.reward.reduce((previous, rewards) => previous.plus(rewards[1]), BN_ZERO).dividedBy(numBlock).decimalPlaces(0);
163
+ const fastPriorityFee = history.reward.reduce((previous, rewards) => previous.plus(rewards[2]), BN_ZERO).dividedBy(numBlock).decimalPlaces(0);
189
164
  return {
165
+ type: 'evm',
190
166
  gasPrice: undefined,
191
- maxFeePerGas,
192
- maxPriorityFeePerGas,
193
- baseGasFee,
194
- busyNetwork
167
+ baseGasFee: baseGasFee.toString(),
168
+ busyNetwork,
169
+ options: {
170
+ slow: getEIP1559GasFee(baseGasFee, slowPriorityFee, 10, blockTime),
171
+ average: getEIP1559GasFee(baseGasFee, averagePriorityFee, 5, blockTime),
172
+ fast: getEIP1559GasFee(baseGasFee, fastPriorityFee, 3, blockTime),
173
+ default: busyNetwork ? 'average' : 'slow'
174
+ }
195
175
  };
196
176
  } catch (e) {
197
177
  const _price = await web3.api.eth.getGasPrice();
198
178
  const gasPrice = recalculateGasPrice(_price, networkKey);
199
179
  return {
180
+ type: 'evm',
181
+ busyNetwork: false,
200
182
  gasPrice,
201
- maxFeePerGas: undefined,
202
- maxPriorityFeePerGas: undefined,
203
183
  baseGasFee: undefined,
204
- busyNetwork: false
184
+ options: undefined
205
185
  };
206
186
  }
187
+ };
188
+ export const calculateToAmountByReservePool = async (api, fromToken, toToken, fromAmount) => {
189
+ const reserve = await getReserveForPool(api, fromToken, toToken);
190
+ return estimateTokensForPool(fromAmount, reserve);
207
191
  };
@@ -3,6 +3,7 @@ import { IBalance } from '../databases';
3
3
  import BaseStoreWithAddress from '../db-stores/BaseStoreWithAddress';
4
4
  export default class BalanceStore extends BaseStoreWithAddress<IBalance> {
5
5
  getBalanceMapByAddresses(addresses: string): Promise<BalanceItem[]>;
6
+ getBalanceHasAmount(address: string, chain: string): Promise<BalanceItem[]>;
6
7
  removeBySlugs(tokenSlugs: string[]): Promise<number>;
7
8
  removeByAddresses(addresses: string[]): Promise<number>;
8
9
  checkBalanceByTokens(tokens: string[], filterFunc: (i: IBalance) => boolean): Promise<number>;
@@ -6,6 +6,9 @@ export default class BalanceStore extends BaseStoreWithAddress {
6
6
  async getBalanceMapByAddresses(addresses) {
7
7
  return this.table.where('address').anyOf(addresses).toArray();
8
8
  }
9
+ async getBalanceHasAmount(address, chain) {
10
+ return this.table.filter(item => item.address === address && item.free !== '0' && item.tokenSlug.startsWith(chain)).toArray();
11
+ }
9
12
  async removeBySlugs(tokenSlugs) {
10
13
  return this.table.where('tokenSlug').anyOfIgnoreCase(tokenSlugs).delete();
11
14
  }
@@ -2,6 +2,7 @@ import { SwapError } from '@subwallet/extension-base/background/errors/SwapError
2
2
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
3
3
  import { BalanceService } from '@subwallet/extension-base/services/balance-service';
4
4
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
5
+ import FeeService from '@subwallet/extension-base/services/fee-service/service';
5
6
  import { BaseStepDetail, CommonOptimalPath, CommonStepFeeInfo } from '@subwallet/extension-base/types/service-base';
6
7
  import { AssetHubSwapEarlyValidation, OptimalSwapPathParams, SwapProviderId, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
7
8
  import { SwapBaseInterface } from '../base-handler';
@@ -11,7 +12,7 @@ export declare class AssetHubSwapHandler implements SwapBaseInterface {
11
12
  private router;
12
13
  isReady: boolean;
13
14
  providerSlug: SwapProviderId;
14
- constructor(chainService: ChainService, balanceService: BalanceService, chain: string);
15
+ constructor(chainService: ChainService, balanceService: BalanceService, feeService: FeeService, chain: string);
15
16
  get chainService(): ChainService;
16
17
  get balanceService(): BalanceService;
17
18
  get providerInfo(): import("@subwallet/extension-base/types").SwapProvider;
@@ -11,20 +11,22 @@ import { convertSwapRate, getSwapAlternativeAsset, SWAP_QUOTE_TIMEOUT_MAP } from
11
11
  import { BasicTxErrorType } from '@subwallet/extension-base/types';
12
12
  import { CommonStepType } from '@subwallet/extension-base/types/service-base';
13
13
  import { SwapErrorType, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
14
+ import { getId } from '@subwallet/extension-base/utils/getId';
14
15
  import BigN from 'bignumber.js';
15
16
  import { SwapBaseHandler } from "../base-handler.js";
16
17
  import { AssetHubRouter } from "./router.js";
17
18
  const PAH_LOW_LIQUIDITY_THRESHOLD = 0.15;
18
19
  export class AssetHubSwapHandler {
19
20
  isReady = false;
20
- constructor(chainService, balanceService, chain) {
21
+ constructor(chainService, balanceService, feeService, chain) {
21
22
  const chainInfo = chainService.getChainInfoByKey(chain);
22
23
  const providerSlug = chain === 'statemint' ? SwapProviderId.POLKADOT_ASSET_HUB : chain === 'statemine' ? SwapProviderId.KUSAMA_ASSET_HUB : SwapProviderId.ROCOCO_ASSET_HUB;
23
24
  this.swapBaseHandler = new SwapBaseHandler({
24
25
  balanceService,
25
26
  chainService,
26
27
  providerName: chainInfo.name,
27
- providerSlug
28
+ providerSlug,
29
+ feeService
28
30
  });
29
31
  this.providerSlug = providerSlug;
30
32
  this.chain = chain;
@@ -75,6 +77,7 @@ export class AssetHubSwapHandler {
75
77
  }
76
78
  try {
77
79
  const alternativeChainInfo = this.chainService.getChainInfoByKey(alternativeAsset.originChain);
80
+ const originalChainInfo = this.chainService.getChainInfoByKey(this.chain);
78
81
  const step = {
79
82
  metadata: {
80
83
  sendingValue: bnAmount.toString(),
@@ -85,13 +88,18 @@ export class AssetHubSwapHandler {
85
88
  type: CommonStepType.XCM
86
89
  };
87
90
  const xcmOriginSubstrateApi = await this.chainService.getSubstrateApi(alternativeAsset.originChain).isReady;
91
+ const id = getId();
92
+ const feeInfo = await this.swapBaseHandler.feeService.subscribeChainFee(id, alternativeChainInfo.slug, 'substrate');
88
93
  const xcmTransfer = await createXcmExtrinsic({
89
94
  originTokenInfo: alternativeAsset,
90
95
  destinationTokenInfo: fromAsset,
91
96
  sendingValue: bnAmount.toString(),
92
97
  recipient: params.request.address,
93
- chainInfoMap: this.chainService.getChainInfoMap(),
94
- substrateApi: xcmOriginSubstrateApi
98
+ sender: params.request.address,
99
+ feeInfo: feeInfo,
100
+ substrateApi: xcmOriginSubstrateApi,
101
+ destinationChain: originalChainInfo,
102
+ originChain: alternativeChainInfo
95
103
  });
96
104
  const _xcmFeeInfo = await xcmTransfer.paymentInfo(params.request.address);
97
105
  const xcmFeeInfo = _xcmFeeInfo.toPrimitive();
@@ -106,6 +114,7 @@ export class AssetHubSwapHandler {
106
114
  };
107
115
  return [step, fee];
108
116
  } catch (e) {
117
+ console.error('Error creating xcm step', e);
109
118
  return undefined;
110
119
  }
111
120
  }
@@ -120,7 +129,7 @@ export class AssetHubSwapHandler {
120
129
  return Promise.resolve(undefined);
121
130
  }
122
131
  generateOptimalProcess(params) {
123
- return this.swapBaseHandler.generateOptimalProcess(params, [this.getXcmStep, this.getSubmitStep]);
132
+ return this.swapBaseHandler.generateOptimalProcess(params, [this.getXcmStep.bind(this), this.getSubmitStep.bind(this)]);
124
133
  }
125
134
  async getSwapQuote(request) {
126
135
  const fromAsset = this.chainService.getAssetBySlug(request.pair.from);
@@ -178,12 +187,16 @@ export class AssetHubSwapHandler {
178
187
  const alternativeAssetSlug = getSwapAlternativeAsset(pair);
179
188
  const originAsset = this.chainService.getAssetBySlug(alternativeAssetSlug);
180
189
  const destinationAsset = this.chainService.getAssetBySlug(pair.from);
190
+ const originChain = this.chainService.getChainInfoByKey(originAsset.originChain);
191
+ const destinationChain = this.chainService.getChainInfoByKey(destinationAsset.originChain);
181
192
  const substrateApi = this.chainService.getSubstrateApi(originAsset.originChain);
182
193
  const chainApi = await substrateApi.isReady;
183
194
  const destinationAssetBalance = await this.balanceService.getTransferableBalance(params.address, destinationAsset.originChain, destinationAsset.slug);
184
195
  const xcmFee = params.process.totalFee[params.currentStep];
185
196
  const bnAmount = new BigN(params.quote.fromAmount);
186
197
  const bnDestinationAssetBalance = new BigN(destinationAssetBalance.value);
198
+ const id = getId();
199
+ const feeInfo = await this.swapBaseHandler.feeService.subscribeChainFee(id, originChain.slug, 'substrate');
187
200
  let bnTotalAmount = bnAmount.minus(bnDestinationAssetBalance);
188
201
  if (_isNativeToken(originAsset)) {
189
202
  const bnXcmFee = new BigN(xcmFee.feeComponent[0].amount); // xcm fee is paid in native token but swap token is not always native token
@@ -195,8 +208,11 @@ export class AssetHubSwapHandler {
195
208
  destinationTokenInfo: destinationAsset,
196
209
  sendingValue: bnTotalAmount.toString(),
197
210
  recipient: params.address,
198
- chainInfoMap: this.chainService.getChainInfoMap(),
199
- substrateApi: chainApi
211
+ substrateApi: chainApi,
212
+ sender: params.address,
213
+ originChain: originChain,
214
+ destinationChain: destinationChain,
215
+ feeInfo
200
216
  });
201
217
  const xcmData = {
202
218
  originNetworkKey: originAsset.originChain,
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { _getTokenMinAmount } from '@subwallet/extension-base/services/chain-service/utils';
5
- import { buildSwapExtrinsic, checkLiquidityForPath, checkMinAmountForPath, estimatePriceImpactPct, estimateRateAfter, estimateRateForPath, estimateTokensForPath, getReserveForPath } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
5
+ import { buildSwapExtrinsic, checkLiquidityForPath, checkMinAmountForPath, estimatePriceImpactPct, estimateRateAfterForPath, estimateRateForPath, estimateTokensForPath, getReserveForPath } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
6
6
  import { SwapErrorType } from '@subwallet/extension-base/types/swap';
7
7
  import BigN from 'bignumber.js';
8
8
  export class AssetHubRouter {
@@ -38,7 +38,7 @@ export class AssetHubRouter {
38
38
  const reserves = await getReserveForPath(api, paths);
39
39
  const amounts = estimateTokensForPath(amount, reserves);
40
40
  const marketRate = estimateRateForPath(reserves);
41
- const marketRateAfter = estimateRateAfter(amount, reserves);
41
+ const marketRateAfter = estimateRateAfterForPath(amount, reserves);
42
42
  const priceImpactPct = estimatePriceImpactPct(marketRate, marketRateAfter);
43
43
  const errors = [];
44
44
 
@@ -9,7 +9,7 @@ export declare const estimateTokensForPool: (amount: string, reserves: [string,
9
9
  export declare const estimateTokensForPath: (amount: string, reserves: Array<[string, string]>) => string[];
10
10
  export declare const estimateRateForPath: (reserves: Array<[string, string]>) => string;
11
11
  export declare const estimateActualRate: (amount: string, reserves: Array<[string, string]>) => string;
12
- export declare const estimateRateAfter: (amount: string, reserves: Array<[string, string]>) => string;
12
+ export declare const estimateRateAfterForPath: (amount: string, reserves: Array<[string, string]>) => string;
13
13
  export declare const estimatePriceImpactPct: (marketRate: string, marketRateAfter: string) => string;
14
14
  export declare const checkLiquidityForPool: (amount: string, reserve1: string, reserve2: string) => SwapErrorType | undefined;
15
15
  export declare const checkLiquidityForPath: (amounts: string[], reserves: Array<[string, string]>) => SwapErrorType | undefined;
@@ -34,7 +34,7 @@ export const getReserveForPath = async (api, paths) => {
34
34
  return await Promise.all(pairs.map(async ([asset1, asset2]) => getReserveForPool(api, asset1, asset2)));
35
35
  };
36
36
  export const estimateTokensForPool = (amount, reserves) => {
37
- if (amount === '0') {
37
+ if (!amount || amount === '0') {
38
38
  return '0';
39
39
  }
40
40
  return new BigN(amount).times(reserves[1]).div(reserves[0]).integerValue(BigN.ROUND_DOWN).toString();
@@ -68,7 +68,7 @@ export const estimateActualRate = (amount, reserves) => {
68
68
  }
69
69
  return result.toString();
70
70
  };
71
- export const estimateRateAfter = (amount, reserves) => {
71
+ export const estimateRateAfterForPath = (amount, reserves) => {
72
72
  const m = new BigN(amount);
73
73
  const reserve = reserves[0];
74
74
  const x = new BigN(reserve[0]);
@@ -2,6 +2,7 @@ import { SwapError } from '@subwallet/extension-base/background/errors/SwapError
2
2
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
3
3
  import { BalanceService } from '@subwallet/extension-base/services/balance-service';
4
4
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
5
+ import FeeService from '@subwallet/extension-base/services/fee-service/service';
5
6
  import { BaseStepDetail, CommonOptimalPath, CommonStepFeeInfo } from '@subwallet/extension-base/types/service-base';
6
7
  import { GenSwapStepFunc, OptimalSwapPathParams, SwapEarlyValidation, SwapProvider, SwapProviderId, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
7
8
  export interface SwapBaseInterface {
@@ -21,13 +22,15 @@ export interface SwapBaseHandlerInitParams {
21
22
  providerName: string;
22
23
  chainService: ChainService;
23
24
  balanceService: BalanceService;
25
+ feeService: FeeService;
24
26
  }
25
27
  export declare class SwapBaseHandler {
26
28
  private readonly providerSlug;
27
29
  private readonly providerName;
28
30
  chainService: ChainService;
29
31
  balanceService: BalanceService;
30
- constructor({ balanceService, chainService, providerName, providerSlug }: SwapBaseHandlerInitParams);
32
+ feeService: FeeService;
33
+ constructor({ balanceService, chainService, feeService, providerName, providerSlug }: SwapBaseHandlerInitParams);
31
34
  generateOptimalProcess(params: OptimalSwapPathParams, genStepFuncList: GenSwapStepFunc[]): Promise<CommonOptimalPath>;
32
35
  validateXcmStep(params: ValidateSwapProcessParams, stepIndex: number): Promise<TransactionError[]>;
33
36
  validateTokenApproveStep(params: ValidateSwapProcessParams, stepIndex: number): Promise<TransactionError[]>;
@@ -15,6 +15,7 @@ export class SwapBaseHandler {
15
15
  constructor({
16
16
  balanceService,
17
17
  chainService,
18
+ feeService,
18
19
  providerName,
19
20
  providerSlug
20
21
  }) {
@@ -22,6 +23,7 @@ export class SwapBaseHandler {
22
23
  this.providerSlug = providerSlug;
23
24
  this.chainService = chainService;
24
25
  this.balanceService = balanceService;
26
+ this.feeService = feeService;
25
27
  }
26
28
 
27
29
  // public abstract getSwapQuote(request: SwapRequest): Promise<SwapQuote | SwapError>;
@@ -32,7 +34,7 @@ export class SwapBaseHandler {
32
34
  };
33
35
  try {
34
36
  for (const genStepFunc of genStepFuncList) {
35
- const step = await genStepFunc.bind(this, params)();
37
+ const step = await genStepFunc(params);
36
38
  if (step) {
37
39
  result.steps.push({
38
40
  id: result.steps.length,
@@ -4,6 +4,7 @@ import { SwapError } from '@subwallet/extension-base/background/errors/SwapError
4
4
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
5
5
  import { BalanceService } from '@subwallet/extension-base/services/balance-service';
6
6
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
7
+ import FeeService from '@subwallet/extension-base/services/fee-service/service';
7
8
  import { SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
8
9
  import { BaseStepDetail, CommonOptimalPath, CommonStepFeeInfo } from '@subwallet/extension-base/types/service-base';
9
10
  import { OptimalSwapPathParams, SwapEarlyValidation, SwapProviderId, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
@@ -13,7 +14,7 @@ export declare class ChainflipSwapHandler implements SwapBaseInterface {
13
14
  private readonly isTestnet;
14
15
  private swapBaseHandler;
15
16
  providerSlug: SwapProviderId;
16
- constructor(chainService: ChainService, balanceService: BalanceService, isTestnet?: boolean);
17
+ constructor(chainService: ChainService, balanceService: BalanceService, feeService: FeeService, isTestnet?: boolean);
17
18
  get chainService(): ChainService;
18
19
  get balanceService(): BalanceService;
19
20
  get providerInfo(): import("@subwallet/extension-base/types").SwapProvider;