@subwallet/extension-base 1.3.31-0 → 1.3.32-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/background/KoniTypes.d.ts +70 -3
- package/background/KoniTypes.js +14 -0
- package/background/errors/CardanoProviderError.d.ts +6 -0
- package/background/errors/CardanoProviderError.js +61 -0
- package/background/types.d.ts +2 -2
- package/cjs/background/KoniTypes.js +16 -1
- package/cjs/background/errors/CardanoProviderError.js +67 -0
- package/cjs/constants/index.js +4 -1
- package/cjs/core/logic-validation/request.js +50 -3
- package/cjs/koni/api/contract-handler/evm/web3.js +21 -0
- package/cjs/koni/api/staking/bonding/utils.js +24 -3
- package/cjs/koni/background/handlers/Extension.js +115 -107
- package/cjs/koni/background/handlers/State.js +228 -5
- package/cjs/koni/background/handlers/Tabs.js +277 -55
- package/cjs/packageInfo.js +1 -1
- package/cjs/page/cardano/cips/cip30.js +63 -0
- package/cjs/page/cardano/cips/index.js +20 -0
- package/cjs/page/cardano/index.js +41 -0
- package/cjs/page/{SubWalleEvmProvider.js → evm/index.js} +2 -2
- package/cjs/page/index.js +9 -4
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +33 -1
- package/cjs/services/balance-service/transfer/xcm/acrossBridge/index.js +6 -2
- package/cjs/services/balance-service/transfer/xcm/index.js +2 -0
- package/cjs/services/chain-service/handler/CardanoApi.js +33 -0
- package/cjs/services/chain-service/index.js +31 -0
- package/cjs/services/chain-service/utils/patch.js +1 -1
- package/cjs/services/earning-service/handlers/liquid-staking/stella-swap.js +3 -3
- package/cjs/services/earning-service/handlers/native-staking/dtao.js +2 -2
- package/cjs/services/earning-service/handlers/native-staking/mythos.js +42 -8
- package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +1 -1
- package/cjs/services/earning-service/handlers/native-staking/tao.js +13 -13
- package/cjs/services/earning-service/handlers/nomination-pool/index.js +1 -1
- package/cjs/services/migration-service/scripts/MigrateAuthUrls.js +1 -1
- package/cjs/services/request-service/constants.js +3 -1
- package/cjs/services/request-service/handler/AuthRequestHandler.js +38 -5
- package/cjs/services/request-service/handler/CardanoRequestHandler.js +45 -3
- package/cjs/services/request-service/helper/index.js +419 -1
- package/cjs/services/swap-service/handler/asset-hub/handler.js +1 -1
- package/cjs/services/swap-service/handler/base-handler.js +81 -21
- package/cjs/services/swap-service/handler/hydradx-handler.js +1 -1
- package/cjs/services/swap-service/handler/uniswap-handler.js +274 -45
- package/cjs/services/swap-service/index.js +33 -11
- package/cjs/services/swap-service/utils.js +15 -2
- package/cjs/utils/auth.js +2 -1
- package/cjs/utils/cardano.js +20 -0
- package/cjs/utils/index.js +4 -4
- package/constants/index.d.ts +1 -0
- package/constants/index.js +1 -0
- package/core/logic-validation/request.d.ts +6 -2
- package/core/logic-validation/request.js +51 -5
- package/koni/api/contract-handler/evm/web3.d.ts +2 -0
- package/koni/api/contract-handler/evm/web3.js +19 -0
- package/koni/api/staking/bonding/utils.d.ts +2 -1
- package/koni/api/staking/bonding/utils.js +23 -3
- package/koni/background/handlers/Extension.js +7 -2
- package/koni/background/handlers/State.d.ts +6 -1
- package/koni/background/handlers/State.js +223 -4
- package/koni/background/handlers/Tabs.d.ts +11 -1
- package/koni/background/handlers/Tabs.js +242 -19
- package/package.json +62 -42
- package/packageInfo.js +1 -1
- package/page/cardano/cips/cip30.d.ts +22 -0
- package/page/cardano/cips/cip30.js +55 -0
- package/page/cardano/cips/index.d.ts +3 -0
- package/page/cardano/cips/index.js +7 -0
- package/page/cardano/index.d.ts +13 -0
- package/page/cardano/index.js +34 -0
- package/page/{SubWalleEvmProvider.d.ts → evm/index.d.ts} +3 -2
- package/page/{SubWalleEvmProvider.js → evm/index.js} +1 -1
- package/page/index.d.ts +3 -2
- package/page/index.js +6 -2
- package/page/{Accounts.d.ts → substrate/Accounts.d.ts} +1 -1
- package/page/{Metadata.d.ts → substrate/Metadata.d.ts} +1 -1
- package/page/{PostMessageProvider.d.ts → substrate/PostMessageProvider.d.ts} +1 -1
- package/page/{Signer.d.ts → substrate/Signer.d.ts} +1 -1
- package/page/{Injected.d.ts → substrate/index.d.ts} +1 -1
- package/services/balance-service/helpers/subscribe/cardano/types.d.ts +14 -0
- package/services/balance-service/helpers/subscribe/substrate/index.js +34 -2
- package/services/balance-service/transfer/xcm/acrossBridge/index.d.ts +4 -0
- package/services/balance-service/transfer/xcm/acrossBridge/index.js +4 -1
- package/services/balance-service/transfer/xcm/index.js +2 -0
- package/services/chain-service/handler/CardanoApi.d.ts +3 -1
- package/services/chain-service/handler/CardanoApi.js +33 -0
- package/services/chain-service/index.d.ts +5 -1
- package/services/chain-service/index.js +32 -1
- package/services/chain-service/utils/patch.js +1 -1
- package/services/earning-service/handlers/liquid-staking/stella-swap.js +3 -3
- package/services/earning-service/handlers/native-staking/dtao.js +2 -2
- package/services/earning-service/handlers/native-staking/mythos.js +42 -8
- package/services/earning-service/handlers/native-staking/relay-chain.js +1 -1
- package/services/earning-service/handlers/native-staking/tao.js +14 -14
- package/services/earning-service/handlers/nomination-pool/index.js +1 -1
- package/services/migration-service/scripts/MigrateAuthUrls.js +1 -1
- package/services/request-service/constants.js +3 -1
- package/services/request-service/handler/AuthRequestHandler.js +40 -7
- package/services/request-service/handler/CardanoRequestHandler.d.ts +2 -0
- package/services/request-service/handler/CardanoRequestHandler.js +45 -3
- package/services/request-service/helper/index.d.ts +54 -0
- package/services/request-service/helper/index.js +406 -1
- package/services/request-service/types.d.ts +3 -1
- package/services/swap-service/handler/asset-hub/handler.js +1 -1
- package/services/swap-service/handler/base-handler.d.ts +3 -1
- package/services/swap-service/handler/base-handler.js +82 -22
- package/services/swap-service/handler/hydradx-handler.js +1 -1
- package/services/swap-service/handler/uniswap-handler.d.ts +5 -0
- package/services/swap-service/handler/uniswap-handler.js +275 -46
- package/services/swap-service/index.js +34 -12
- package/services/swap-service/utils.d.ts +3 -2
- package/services/swap-service/utils.js +13 -1
- package/types/swap/index.d.ts +1 -0
- package/types/transaction/process.d.ts +2 -0
- package/utils/auth.js +3 -2
- package/utils/cardano.d.ts +2 -0
- package/utils/cardano.js +12 -0
- package/utils/index.d.ts +1 -1
- package/utils/index.js +1 -1
- package/cjs/utils/canDerive.js +0 -12
- package/utils/canDerive.d.ts +0 -2
- package/utils/canDerive.js +0 -6
- /package/cjs/page/{Accounts.js → substrate/Accounts.js} +0 -0
- /package/cjs/page/{Metadata.js → substrate/Metadata.js} +0 -0
- /package/cjs/page/{PostMessageProvider.js → substrate/PostMessageProvider.js} +0 -0
- /package/cjs/page/{Signer.js → substrate/Signer.js} +0 -0
- /package/cjs/page/{Injected.js → substrate/index.js} +0 -0
- /package/page/{Accounts.js → substrate/Accounts.js} +0 -0
- /package/page/{Metadata.js → substrate/Metadata.js} +0 -0
- /package/page/{PostMessageProvider.js → substrate/PostMessageProvider.js} +0 -0
- /package/page/{Signer.js → substrate/Signer.js} +0 -0
- /package/page/{Injected.js → substrate/index.js} +0 -0
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
5
|
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
6
|
import { validateTypedSignMessageDataV3V4 } from '@subwallet/extension-base/core/logic-validation';
|
|
7
|
+
import { estimateTxFee, getERC20Allowance, getERC20SpendingApprovalTx } from '@subwallet/extension-base/koni/api/contract-handler/evm/web3';
|
|
8
|
+
import { createAcrossBridgeExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
|
|
9
|
+
import { SpokePoolMapping } from '@subwallet/extension-base/services/balance-service/transfer/xcm/acrossBridge';
|
|
7
10
|
import { BasicTxErrorType, CommonStepType, DynamicSwapType, FeeOptionKey, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types';
|
|
8
11
|
import { _reformatAddressWithChain } from '@subwallet/extension-base/utils';
|
|
12
|
+
import { getId } from '@subwallet/extension-base/utils/getId';
|
|
9
13
|
import BigNumber from 'bignumber.js';
|
|
10
|
-
import { _getContractAddressOfToken, _isNativeToken } from "../../chain-service/utils/index.js";
|
|
14
|
+
import { _getAssetOriginChain, _getChainNativeTokenSlug, _getContractAddressOfToken, _getEvmChainId, _isNativeToken } from "../../chain-service/utils/index.js";
|
|
11
15
|
import { calculateGasFeeParams } from "../../fee-service/utils/index.js";
|
|
12
16
|
import { SwapBaseHandler } from "./base-handler.js";
|
|
13
17
|
const API_URL = 'https://trade-api.gateway.uniswap.org/v1';
|
|
@@ -59,41 +63,121 @@ export class UniswapHandler {
|
|
|
59
63
|
return this.swapBaseHandler.providerInfo;
|
|
60
64
|
}
|
|
61
65
|
generateOptimalProcessV2(params) {
|
|
62
|
-
|
|
66
|
+
const stepFuncList = [];
|
|
67
|
+
/**
|
|
68
|
+
* approve - permit - swap or
|
|
69
|
+
* approve - permit - swap - approve - bridge
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
params.path.forEach(step => {
|
|
73
|
+
if (step.action === DynamicSwapType.SWAP) {
|
|
74
|
+
stepFuncList.push(...[this.getApprovalStep.bind(this), this.getPermitStep.bind(this), this.getSubmitStep.bind(this)]);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (step.action === DynamicSwapType.BRIDGE) {
|
|
78
|
+
stepFuncList.push(...[this.getApprovalStep.bind(this), this.getBridgeStep.bind(this)]);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`Error generating optimal process: Action ${step.action} is not supported`);
|
|
82
|
+
});
|
|
83
|
+
return this.swapBaseHandler.generateOptimalProcessV2(params, stepFuncList);
|
|
63
84
|
}
|
|
64
85
|
async getApprovalStep(params, stepIndex) {
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
quote
|
|
71
|
-
} = params.selectedQuote.metadata;
|
|
72
|
-
const checkApprovalResponse = await fetchCheckApproval(walletAddress, fromAmount, quote);
|
|
73
|
-
const approval = checkApprovalResponse.approval;
|
|
74
|
-
if (approval) {
|
|
75
|
-
let spender = '';
|
|
76
|
-
try {
|
|
77
|
-
const valueLength = 40;
|
|
78
|
-
spender = approval.data.slice(-(valueLength * 2), -valueLength);
|
|
79
|
-
} catch (e) {
|
|
80
|
-
// Empty
|
|
81
|
-
}
|
|
82
|
-
const metadata = {
|
|
83
|
-
tokenApprove: inputTokenInfo.slug,
|
|
84
|
-
contractAddress: _getContractAddressOfToken(inputTokenInfo),
|
|
85
|
-
spenderAddress: spender
|
|
86
|
-
};
|
|
87
|
-
const submitStep = {
|
|
88
|
-
name: 'Approve token',
|
|
89
|
-
type: CommonStepType.TOKEN_APPROVAL,
|
|
90
|
-
metadata: metadata
|
|
91
|
-
};
|
|
92
|
-
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]);
|
|
93
|
-
}
|
|
86
|
+
if (stepIndex === 0) {
|
|
87
|
+
return this.getApproveSwap(params);
|
|
88
|
+
}
|
|
89
|
+
if (stepIndex === 3) {
|
|
90
|
+
return this.getApproveBridge(params);
|
|
94
91
|
}
|
|
95
92
|
return Promise.resolve(undefined);
|
|
96
93
|
}
|
|
94
|
+
async getApproveSwap(params) {
|
|
95
|
+
const selectedQuote = params.selectedQuote;
|
|
96
|
+
if (!selectedQuote) {
|
|
97
|
+
return Promise.resolve(undefined);
|
|
98
|
+
}
|
|
99
|
+
const quoteMetadata = selectedQuote.metadata.quote;
|
|
100
|
+
const sender = quoteMetadata.swapper;
|
|
101
|
+
const sendingValue = quoteMetadata.input.amount;
|
|
102
|
+
const fromTokenInfo = this.chainService.getAssetBySlug(selectedQuote.pair.from);
|
|
103
|
+
const checkApprovalResponse = await fetchCheckApproval(sender, sendingValue, quoteMetadata);
|
|
104
|
+
const approval = checkApprovalResponse.approval;
|
|
105
|
+
if (!approval) {
|
|
106
|
+
return Promise.resolve(undefined);
|
|
107
|
+
}
|
|
108
|
+
let spender = '';
|
|
109
|
+
try {
|
|
110
|
+
const valueLength = 40;
|
|
111
|
+
spender = approval.data.slice(-(valueLength * 2), -valueLength);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
// Empty
|
|
114
|
+
}
|
|
115
|
+
const submitStep = {
|
|
116
|
+
name: 'Approve token for swap',
|
|
117
|
+
type: CommonStepType.TOKEN_APPROVAL,
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
metadata: {
|
|
120
|
+
tokenApprove: fromTokenInfo.slug,
|
|
121
|
+
contractAddress: _getContractAddressOfToken(fromTokenInfo),
|
|
122
|
+
spenderAddress: spender,
|
|
123
|
+
owner: sender,
|
|
124
|
+
amount: sendingValue,
|
|
125
|
+
isUniswapApprove: true
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
return Promise.resolve([submitStep, selectedQuote.feeInfo]); // todo: wrong feeInfo, please check
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async getApproveBridge(params) {
|
|
132
|
+
const quote = params.selectedQuote;
|
|
133
|
+
if (!quote) {
|
|
134
|
+
return Promise.resolve(undefined);
|
|
135
|
+
}
|
|
136
|
+
const sendingAmount = quote.toAmount;
|
|
137
|
+
const senderAddress = params.request.address;
|
|
138
|
+
const fromTokenInfo = this.chainService.getAssetBySlug(quote.pair.to);
|
|
139
|
+
const fromChainInfo = this.chainService.getChainInfoByKey(_getAssetOriginChain(fromTokenInfo));
|
|
140
|
+
const fromChainId = _getEvmChainId(fromChainInfo);
|
|
141
|
+
const evmApi = this.chainService.getEvmApi(fromChainInfo.slug);
|
|
142
|
+
const tokenContract = _getContractAddressOfToken(fromTokenInfo);
|
|
143
|
+
if (_isNativeToken(fromTokenInfo)) {
|
|
144
|
+
return Promise.resolve(undefined);
|
|
145
|
+
}
|
|
146
|
+
if (!fromChainId) {
|
|
147
|
+
throw Error('Error getting Evm chain Id');
|
|
148
|
+
}
|
|
149
|
+
const spokePoolAddress = SpokePoolMapping[fromChainId].SpokePool.address;
|
|
150
|
+
const allowance = await getERC20Allowance(spokePoolAddress, senderAddress, tokenContract, evmApi);
|
|
151
|
+
if (allowance && BigNumber(allowance).gt(sendingAmount)) {
|
|
152
|
+
return Promise.resolve(undefined);
|
|
153
|
+
}
|
|
154
|
+
const tx = await getERC20SpendingApprovalTx(spokePoolAddress, senderAddress, tokenContract, evmApi);
|
|
155
|
+
const evmFeeInfo = await this.feeService.subscribeChainFee(getId(), fromTokenInfo.originChain, 'evm');
|
|
156
|
+
const estimatedFee = await estimateTxFee(tx, evmApi, evmFeeInfo);
|
|
157
|
+
const nativeTokenSlug = _getChainNativeTokenSlug(fromChainInfo);
|
|
158
|
+
const feeInfo = {
|
|
159
|
+
feeComponent: [{
|
|
160
|
+
feeType: SwapFeeType.NETWORK_FEE,
|
|
161
|
+
amount: estimatedFee,
|
|
162
|
+
tokenSlug: nativeTokenSlug
|
|
163
|
+
}],
|
|
164
|
+
defaultFeeToken: nativeTokenSlug,
|
|
165
|
+
feeOptions: [nativeTokenSlug]
|
|
166
|
+
};
|
|
167
|
+
const submitStep = {
|
|
168
|
+
name: 'Approve token for bridge',
|
|
169
|
+
type: CommonStepType.TOKEN_APPROVAL,
|
|
170
|
+
// @ts-ignore
|
|
171
|
+
metadata: {
|
|
172
|
+
tokenApprove: fromTokenInfo.slug,
|
|
173
|
+
contractAddress: tokenContract,
|
|
174
|
+
spenderAddress: spokePoolAddress,
|
|
175
|
+
amount: sendingAmount,
|
|
176
|
+
owner: senderAddress
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return Promise.resolve([submitStep, feeInfo]);
|
|
180
|
+
}
|
|
97
181
|
async getPermitStep(params, stepIndex) {
|
|
98
182
|
if (params.selectedQuote && params.selectedQuote.metadata.permitData) {
|
|
99
183
|
const submitStep = {
|
|
@@ -116,11 +200,22 @@ export class UniswapHandler {
|
|
|
116
200
|
return Promise.resolve(undefined);
|
|
117
201
|
}
|
|
118
202
|
async getSubmitStep(params, stepIndex) {
|
|
119
|
-
|
|
203
|
+
const {
|
|
204
|
+
path,
|
|
205
|
+
request,
|
|
206
|
+
selectedQuote
|
|
207
|
+
} = params;
|
|
208
|
+
|
|
209
|
+
// stepIndex is not corresponding index in path, because uniswap include approval and permit step
|
|
210
|
+
const stepData = path.find(action => action.action === DynamicSwapType.SWAP);
|
|
211
|
+
if (!stepData || !stepData.pair) {
|
|
212
|
+
return Promise.resolve(undefined);
|
|
213
|
+
}
|
|
214
|
+
if (!selectedQuote) {
|
|
120
215
|
return Promise.resolve(undefined);
|
|
121
216
|
}
|
|
122
|
-
const originTokenInfo = this.chainService.getAssetBySlug(
|
|
123
|
-
const destinationTokenInfo = this.chainService.getAssetBySlug(
|
|
217
|
+
const originTokenInfo = this.chainService.getAssetBySlug(selectedQuote.pair.from);
|
|
218
|
+
const destinationTokenInfo = this.chainService.getAssetBySlug(selectedQuote.pair.to);
|
|
124
219
|
const originChain = this.chainService.getChainInfoByKey(originTokenInfo.originChain);
|
|
125
220
|
const destinationChain = this.chainService.getChainInfoByKey(destinationTokenInfo.originChain);
|
|
126
221
|
const submitStep = {
|
|
@@ -128,16 +223,99 @@ export class UniswapHandler {
|
|
|
128
223
|
type: SwapStepType.SWAP,
|
|
129
224
|
// @ts-ignore
|
|
130
225
|
metadata: {
|
|
131
|
-
sendingValue:
|
|
132
|
-
expectedReceive:
|
|
226
|
+
sendingValue: request.fromAmount.toString(),
|
|
227
|
+
expectedReceive: selectedQuote.toAmount,
|
|
133
228
|
originTokenInfo,
|
|
134
229
|
destinationTokenInfo,
|
|
135
|
-
sender: _reformatAddressWithChain(
|
|
136
|
-
receiver: _reformatAddressWithChain(
|
|
230
|
+
sender: _reformatAddressWithChain(request.address, originChain),
|
|
231
|
+
receiver: _reformatAddressWithChain(request.recipient || request.address, destinationChain),
|
|
137
232
|
version: 2
|
|
138
233
|
}
|
|
139
234
|
};
|
|
140
|
-
return Promise.resolve([submitStep,
|
|
235
|
+
return Promise.resolve([submitStep, selectedQuote.feeInfo]);
|
|
236
|
+
}
|
|
237
|
+
async getBridgeStep(params, stepIndex) {
|
|
238
|
+
const {
|
|
239
|
+
path,
|
|
240
|
+
request,
|
|
241
|
+
selectedQuote
|
|
242
|
+
} = params;
|
|
243
|
+
|
|
244
|
+
// stepIndex is not corresponding index in path, because uniswap include approval and permit step
|
|
245
|
+
const bridgePairInfo = path.find(action => action.action === DynamicSwapType.BRIDGE);
|
|
246
|
+
if (!bridgePairInfo || !bridgePairInfo.pair) {
|
|
247
|
+
return Promise.resolve(undefined);
|
|
248
|
+
}
|
|
249
|
+
if (!selectedQuote) {
|
|
250
|
+
return Promise.resolve(undefined);
|
|
251
|
+
}
|
|
252
|
+
const fromTokenInfo = this.chainService.getAssetBySlug(bridgePairInfo.pair.from);
|
|
253
|
+
const toTokenInfo = this.chainService.getAssetBySlug(bridgePairInfo.pair.to);
|
|
254
|
+
const fromChainInfo = this.chainService.getChainInfoByKey(fromTokenInfo.originChain);
|
|
255
|
+
const toChainInfo = this.chainService.getChainInfoByKey(toTokenInfo.originChain);
|
|
256
|
+
if (!fromChainInfo || !toChainInfo || !fromChainInfo || !toChainInfo) {
|
|
257
|
+
throw Error('Token or chain not found');
|
|
258
|
+
}
|
|
259
|
+
const senderAddress = _reformatAddressWithChain(request.address, fromChainInfo);
|
|
260
|
+
const receiverAddress = _reformatAddressWithChain(request.recipient || request.address, toChainInfo);
|
|
261
|
+
const sendingValue = BigNumber(selectedQuote.toAmount).div(1.02).toFixed(0, 1);
|
|
262
|
+
try {
|
|
263
|
+
const evmApi = await this.chainService.getEvmApi(fromChainInfo.slug).isReady;
|
|
264
|
+
const feeInfo = await this.feeService.subscribeChainFee(getId(), fromTokenInfo.originChain, 'evm');
|
|
265
|
+
const tx = await createAcrossBridgeExtrinsic({
|
|
266
|
+
originTokenInfo: fromTokenInfo,
|
|
267
|
+
destinationTokenInfo: toTokenInfo,
|
|
268
|
+
originChain: fromChainInfo,
|
|
269
|
+
destinationChain: toChainInfo,
|
|
270
|
+
evmApi,
|
|
271
|
+
feeInfo,
|
|
272
|
+
// Mock sending value to get payment info
|
|
273
|
+
sendingValue,
|
|
274
|
+
sender: senderAddress,
|
|
275
|
+
recipient: receiverAddress
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// // todo: wait until this ready to get destination fee. the real receiveAmount is deduce by this fee
|
|
279
|
+
// const acrossQuote = await getAcrossQuote({
|
|
280
|
+
// destinationChain: toChainInfo,
|
|
281
|
+
// destinationTokenInfo: toTokenInfo,
|
|
282
|
+
// originChain: fromChainInfo,
|
|
283
|
+
// originTokenInfo: fromTokenInfo,
|
|
284
|
+
// recipient: receiverAddress,
|
|
285
|
+
// sender: senderAddress,
|
|
286
|
+
// sendingValue,
|
|
287
|
+
// feeInfo
|
|
288
|
+
// });
|
|
289
|
+
|
|
290
|
+
const estimatedBridgeFee = await estimateTxFee(tx, evmApi, feeInfo);
|
|
291
|
+
const expectedReceive = BigNumber(sendingValue).minus(estimatedBridgeFee).toFixed(0, 1);
|
|
292
|
+
const fee = {
|
|
293
|
+
feeComponent: [{
|
|
294
|
+
feeType: SwapFeeType.NETWORK_FEE,
|
|
295
|
+
amount: estimatedBridgeFee,
|
|
296
|
+
tokenSlug: _getChainNativeTokenSlug(fromChainInfo)
|
|
297
|
+
}],
|
|
298
|
+
defaultFeeToken: _getChainNativeTokenSlug(fromChainInfo),
|
|
299
|
+
feeOptions: [_getChainNativeTokenSlug(fromChainInfo)]
|
|
300
|
+
};
|
|
301
|
+
const step = {
|
|
302
|
+
// @ts-ignore
|
|
303
|
+
metadata: {
|
|
304
|
+
sendingValue: sendingValue,
|
|
305
|
+
expectedReceive,
|
|
306
|
+
originTokenInfo: fromTokenInfo,
|
|
307
|
+
destinationTokenInfo: toTokenInfo,
|
|
308
|
+
receiver: receiverAddress,
|
|
309
|
+
sender: senderAddress
|
|
310
|
+
},
|
|
311
|
+
name: `Transfer ${fromTokenInfo.symbol} from ${fromChainInfo.name}`,
|
|
312
|
+
type: CommonStepType.XCM
|
|
313
|
+
};
|
|
314
|
+
return [step, fee];
|
|
315
|
+
} catch (e) {
|
|
316
|
+
console.error('Error creating bridge step', e);
|
|
317
|
+
throw new Error(e.message);
|
|
318
|
+
}
|
|
141
319
|
}
|
|
142
320
|
async handleSwapProcess(params) {
|
|
143
321
|
const {
|
|
@@ -150,6 +328,8 @@ export class UniswapHandler {
|
|
|
150
328
|
return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED));
|
|
151
329
|
case CommonStepType.TOKEN_APPROVAL:
|
|
152
330
|
return this.tokenApproveSpending(params);
|
|
331
|
+
case CommonStepType.XCM:
|
|
332
|
+
return this.swapBaseHandler.handleBridgeStep(params, 'across');
|
|
153
333
|
case SwapStepType.SWAP:
|
|
154
334
|
return this.handleSubmitStep(params);
|
|
155
335
|
case SwapStepType.PERMIT:
|
|
@@ -159,13 +339,29 @@ export class UniswapHandler {
|
|
|
159
339
|
}
|
|
160
340
|
}
|
|
161
341
|
async tokenApproveSpending(params) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
342
|
+
const approveStep = params.process.steps[params.currentStep].metadata;
|
|
343
|
+
if (!approveStep || !approveStep.tokenApprove || !approveStep.contractAddress || !approveStep.spenderAddress) {
|
|
344
|
+
throw new Error('Approval spending metadata error');
|
|
345
|
+
}
|
|
346
|
+
if (approveStep.isUniswapApprove) {
|
|
347
|
+
return this.approveSpendingSwap(params, approveStep);
|
|
348
|
+
}
|
|
349
|
+
return this.approveSpendingBridge(approveStep);
|
|
350
|
+
}
|
|
351
|
+
async approveSpendingSwap(params, approveStep) {
|
|
352
|
+
const fromAsset = this.chainService.getAssetBySlug(approveStep.tokenApprove);
|
|
353
|
+
const sender = approveStep.owner;
|
|
354
|
+
const sendingValue = approveStep.amount;
|
|
355
|
+
if (!sender || !sendingValue) {
|
|
356
|
+
throw new Error('Sender or value is not found');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// todo: move quote param to metadata;
|
|
360
|
+
|
|
165
361
|
const {
|
|
166
362
|
quote
|
|
167
363
|
} = params.quote.metadata;
|
|
168
|
-
const checkApprovalResponse = await fetchCheckApproval(
|
|
364
|
+
const checkApprovalResponse = await fetchCheckApproval(sender, sendingValue, quote);
|
|
169
365
|
let transactionConfig = {};
|
|
170
366
|
const approval = checkApprovalResponse.approval;
|
|
171
367
|
if (approval) {
|
|
@@ -201,6 +397,34 @@ export class UniswapHandler {
|
|
|
201
397
|
chainType: ChainType.EVM
|
|
202
398
|
});
|
|
203
399
|
}
|
|
400
|
+
async approveSpendingBridge(approveStep) {
|
|
401
|
+
const fromAsset = this.chainService.getAssetBySlug(approveStep.tokenApprove);
|
|
402
|
+
const fromChain = _getAssetOriginChain(fromAsset);
|
|
403
|
+
const evmApi = this.chainService.getEvmApi(fromAsset.originChain);
|
|
404
|
+
const sender = approveStep.owner;
|
|
405
|
+
const sendingValue = approveStep.amount;
|
|
406
|
+
if (!sender) {
|
|
407
|
+
throw new Error('Sender or value is not found');
|
|
408
|
+
}
|
|
409
|
+
const spenderAddress = approveStep.spenderAddress;
|
|
410
|
+
const contractAddress = approveStep.contractAddress;
|
|
411
|
+
const transactionConfig = await getERC20SpendingApprovalTx(spenderAddress, sender, contractAddress, evmApi);
|
|
412
|
+
const _data = {
|
|
413
|
+
spenderAddress: approveStep.spenderAddress,
|
|
414
|
+
contractAddress: approveStep.contractAddress,
|
|
415
|
+
amount: sendingValue,
|
|
416
|
+
owner: sender,
|
|
417
|
+
chain: fromChain
|
|
418
|
+
};
|
|
419
|
+
return Promise.resolve({
|
|
420
|
+
txChain: fromChain,
|
|
421
|
+
extrinsicType: ExtrinsicType.TOKEN_SPENDING_APPROVAL,
|
|
422
|
+
extrinsic: transactionConfig,
|
|
423
|
+
txData: _data,
|
|
424
|
+
transferNativeAmount: '0',
|
|
425
|
+
chainType: ChainType.EVM
|
|
426
|
+
});
|
|
427
|
+
}
|
|
204
428
|
async handleSubmitStep(params) {
|
|
205
429
|
const fromAsset = this.chainService.getAssetBySlug(params.quote.pair.from);
|
|
206
430
|
const {
|
|
@@ -234,6 +458,8 @@ export class UniswapHandler {
|
|
|
234
458
|
const transactionResponse = await postTransactionResponse.json();
|
|
235
459
|
extrinsic = transactionResponse.swap;
|
|
236
460
|
} else if (routing === 'DUTCH_LIMIT' || routing === 'DUTCH_V2') {
|
|
461
|
+
// todo: update condition and add handle exception
|
|
462
|
+
// UniswapX, UniswapX_V2, and UniswapX_V3 are alternately referred to as DutchQuote, DutchQuoteV2, and DutchQuoteV3
|
|
237
463
|
postTransactionResponse = await fetch(`${API_URL}/order`, {
|
|
238
464
|
method: 'POST',
|
|
239
465
|
headers: {
|
|
@@ -325,17 +551,20 @@ export class UniswapHandler {
|
|
|
325
551
|
const swapXcm = actionList === JSON.stringify([DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
326
552
|
const xcmSwap = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP]);
|
|
327
553
|
const xcmSwapXcm = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
328
|
-
const swapIndex = params.process.steps.findIndex(step => step.type === SwapStepType.SWAP);
|
|
329
|
-
|
|
554
|
+
const swapIndex = params.process.steps.findIndex(step => step.type === SwapStepType.SWAP);
|
|
555
|
+
const bridgeIndex = params.process.steps.findIndex(step => step.type === CommonStepType.XCM);
|
|
330
556
|
if (swapIndex <= -1) {
|
|
331
557
|
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
332
558
|
}
|
|
559
|
+
if (swapXcm && bridgeIndex <= -1) {
|
|
560
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
561
|
+
}
|
|
333
562
|
if (swap) {
|
|
334
563
|
return this.swapBaseHandler.validateSwapOnlyProcess(params, swapIndex); // todo: create interface for input request
|
|
335
564
|
}
|
|
336
565
|
|
|
337
566
|
if (swapXcm) {
|
|
338
|
-
return
|
|
567
|
+
return this.swapBaseHandler.validateSwapXcmProcess(params, swapIndex, bridgeIndex);
|
|
339
568
|
}
|
|
340
569
|
if (xcmSwap) {
|
|
341
570
|
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
@@ -12,7 +12,7 @@ import { _getAssetOriginChain, _getChainSubstrateAddressPrefix } from '@subwalle
|
|
|
12
12
|
import { AssetHubSwapHandler } from '@subwallet/extension-base/services/swap-service/handler/asset-hub';
|
|
13
13
|
import { ChainflipSwapHandler } from '@subwallet/extension-base/services/swap-service/handler/chainflip-handler';
|
|
14
14
|
import { HydradxHandler } from '@subwallet/extension-base/services/swap-service/handler/hydradx-handler';
|
|
15
|
-
import { findAllBridgeDestinations, findBridgeTransitDestination, findSwapTransitDestination, getBridgeStep,
|
|
15
|
+
import { findAllBridgeDestinations, findBridgeTransitDestination, findSwapTransitDestination, getBridgeStep, getSupportedSwapChains, getSwapAltToken, getSwapStep, getTokenPairFromStep, isChainsHasSameProvider, processStepsToPathActions, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
|
|
16
16
|
import { BasicTxErrorType, DynamicSwapType } from '@subwallet/extension-base/types';
|
|
17
17
|
import { DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
|
|
18
18
|
import { _SUPPORTED_SWAP_PROVIDERS, SwapErrorType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
|
|
@@ -110,16 +110,22 @@ export class SwapService {
|
|
|
110
110
|
path,
|
|
111
111
|
swapQuoteResponse
|
|
112
112
|
} = await this.getLatestQuoteFromSwapRequest(request);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
console.group('Swap Logger');
|
|
114
|
+
console.log('path', path);
|
|
115
|
+
console.log('swapQuoteResponse', swapQuoteResponse);
|
|
116
|
+
let optimalProcess;
|
|
117
|
+
try {
|
|
118
|
+
optimalProcess = await this.generateOptimalProcessV2({
|
|
119
|
+
request,
|
|
120
|
+
selectedQuote: swapQuoteResponse.optimalQuote,
|
|
121
|
+
path
|
|
122
|
+
});
|
|
123
|
+
} catch (e) {
|
|
124
|
+
throw new Error(e.message);
|
|
125
|
+
}
|
|
119
126
|
console.log('optimalProcess', optimalProcess);
|
|
120
|
-
console.
|
|
121
|
-
if (optimalProcess.steps
|
|
122
|
-
// minus the fill info step
|
|
127
|
+
console.groupEnd();
|
|
128
|
+
if (JSON.stringify(processStepsToPathActions(optimalProcess.steps)) !== JSON.stringify(optimalProcess.path.map(e => e.action))) {
|
|
123
129
|
throw new Error('Swap pair is not found');
|
|
124
130
|
}
|
|
125
131
|
return {
|
|
@@ -135,7 +141,7 @@ export class SwapService {
|
|
|
135
141
|
pair
|
|
136
142
|
} = request;
|
|
137
143
|
// todo: control provider tighter
|
|
138
|
-
const supportSwapChains =
|
|
144
|
+
const supportSwapChains = getSupportedSwapChains();
|
|
139
145
|
const fromToken = this.chainService.getAssetBySlug(pair.from);
|
|
140
146
|
const toToken = this.chainService.getAssetBySlug(pair.to);
|
|
141
147
|
const fromChain = _getAssetOriginChain(fromToken);
|
|
@@ -237,10 +243,26 @@ export class SwapService {
|
|
|
237
243
|
return [[], undefined];
|
|
238
244
|
}
|
|
239
245
|
async getLatestQuoteFromSwapRequest(request) {
|
|
240
|
-
|
|
246
|
+
var _subwalletApiSdk$swap2;
|
|
247
|
+
const availablePath = await ((_subwalletApiSdk$swap2 = subwalletApiSdk.swapApi) === null || _subwalletApiSdk$swap2 === void 0 ? void 0 : _subwalletApiSdk$swap2.findAvailablePath(request));
|
|
248
|
+
if (!availablePath) {
|
|
249
|
+
throw Error('No available path');
|
|
250
|
+
}
|
|
251
|
+
const {
|
|
252
|
+
path
|
|
253
|
+
} = availablePath;
|
|
254
|
+
const swapAction = path.find(step => step.action === DynamicSwapType.SWAP);
|
|
255
|
+
const directSwapRequest = swapAction ? {
|
|
256
|
+
...request,
|
|
257
|
+
address: _reformatAddressWithChain(request.address, this.chainService.getChainInfoByKey(_getAssetOriginChain(this.chainService.getAssetBySlug(swapAction.pair.from)))),
|
|
258
|
+
pair: swapAction.pair
|
|
259
|
+
} : undefined;
|
|
241
260
|
if (!directSwapRequest) {
|
|
242
261
|
throw Error('Swap pair is not found');
|
|
243
262
|
}
|
|
263
|
+
if (path.length > 1 && path.map(action => action.action).includes(DynamicSwapType.BRIDGE)) {
|
|
264
|
+
directSwapRequest.isCrossChain = true;
|
|
265
|
+
}
|
|
244
266
|
const swapQuoteResponse = await this.getLatestDirectQuotes(directSwapRequest);
|
|
245
267
|
return {
|
|
246
268
|
path,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _AssetRef, _ChainAsset } from '@subwallet/chain-list/types';
|
|
2
|
-
import { CommonStepDetail, DynamicSwapAction } from '@subwallet/extension-base/types';
|
|
2
|
+
import { CommonStepDetail, DynamicSwapAction, DynamicSwapType } from '@subwallet/extension-base/types';
|
|
3
3
|
import { SwapPair } from '@subwallet/extension-base/types/swap';
|
|
4
4
|
export declare const CHAIN_FLIP_TESTNET_EXPLORER = "https://blocks-perseverance.chainflip.io";
|
|
5
5
|
export declare const CHAIN_FLIP_MAINNET_EXPLORER = "https://scan.chainflip.io";
|
|
@@ -8,7 +8,7 @@ export declare const SIMPLE_SWAP_SUPPORTED_TESTNET_ASSET_MAPPING: Record<string,
|
|
|
8
8
|
export declare const SWAP_QUOTE_TIMEOUT_MAP: Record<string, number>;
|
|
9
9
|
export declare const _PROVIDER_TO_SUPPORTED_PAIR_MAP: Record<string, string[]>;
|
|
10
10
|
export declare const FEE_RATE_MULTIPLIER: Record<string, number>;
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function getSupportedSwapChains(): string[];
|
|
12
12
|
export declare function getSwapAlternativeAsset(swapPair: SwapPair): string | undefined;
|
|
13
13
|
export declare function getSwapAltToken(chainAsset: _ChainAsset): string | undefined;
|
|
14
14
|
export declare function calculateSwapRate(fromAmount: string, toAmount: string, fromAsset: _ChainAsset, toAsset: _ChainAsset): number;
|
|
@@ -38,4 +38,5 @@ export declare function getFirstAmountFromSteps(steps: CommonStepDetail[]): stri
|
|
|
38
38
|
export declare function getChainRouteFromSteps(steps: CommonStepDetail[]): string[];
|
|
39
39
|
export declare function getTokenPairFromStep(steps: CommonStepDetail[]): SwapPair | undefined;
|
|
40
40
|
export declare function getSwapChainsFromPath(path: DynamicSwapAction[]): string[];
|
|
41
|
+
export declare function processStepsToPathActions(steps: CommonStepDetail[]): DynamicSwapType[];
|
|
41
42
|
export declare const DEFAULT_EXCESS_AMOUNT_WEIGHT = 1.04;
|
|
@@ -42,7 +42,7 @@ export const FEE_RATE_MULTIPLIER = {
|
|
|
42
42
|
medium: 1.2,
|
|
43
43
|
high: 2
|
|
44
44
|
};
|
|
45
|
-
export function
|
|
45
|
+
export function getSupportedSwapChains() {
|
|
46
46
|
return [...new Set(Object.values(_PROVIDER_TO_SUPPORTED_PAIR_MAP).flat())];
|
|
47
47
|
}
|
|
48
48
|
export function getSwapAlternativeAsset(swapPair) {
|
|
@@ -236,4 +236,16 @@ export function getSwapChainsFromPath(path) {
|
|
|
236
236
|
});
|
|
237
237
|
return swapChains;
|
|
238
238
|
}
|
|
239
|
+
export function processStepsToPathActions(steps) {
|
|
240
|
+
const path = [];
|
|
241
|
+
for (const step of steps) {
|
|
242
|
+
if (step.type === CommonStepType.XCM) {
|
|
243
|
+
path.push(DynamicSwapType.BRIDGE);
|
|
244
|
+
}
|
|
245
|
+
if (step.type === SwapStepType.SWAP) {
|
|
246
|
+
path.push(DynamicSwapType.SWAP);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return path;
|
|
250
|
+
}
|
|
239
251
|
export const DEFAULT_EXCESS_AMOUNT_WEIGHT = 1.04; // add 2%
|
package/types/swap/index.d.ts
CHANGED
package/utils/auth.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { getKeypairTypeByAddress } from '@subwallet/keyring';
|
|
5
|
-
import { EthereumKeypairTypes, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types';
|
|
5
|
+
import { CardanoKeypairTypes, EthereumKeypairTypes, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types';
|
|
6
6
|
export const isAddressValidWithAuthType = (address, accountAuthTypes) => {
|
|
7
7
|
const keypairType = getKeypairTypeByAddress(address);
|
|
8
8
|
const validTypes = {
|
|
9
9
|
evm: EthereumKeypairTypes,
|
|
10
10
|
substrate: SubstrateKeypairTypes,
|
|
11
|
-
ton: TonKeypairTypes
|
|
11
|
+
ton: TonKeypairTypes,
|
|
12
|
+
cardano: CardanoKeypairTypes
|
|
12
13
|
};
|
|
13
14
|
return !!(accountAuthTypes !== null && accountAuthTypes !== void 0 && accountAuthTypes.some(authType => {
|
|
14
15
|
var _validTypes$authType;
|
package/utils/cardano.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright 2019-2022 @polkadot/extension authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { Address } from '@emurgo/cardano-serialization-lib-nodejs';
|
|
5
|
+
export const convertCardanoAddressToHex = bech32Address => {
|
|
6
|
+
const addr = Address.from_bech32(bech32Address);
|
|
7
|
+
return addr.to_hex();
|
|
8
|
+
};
|
|
9
|
+
export const convertCardanoHexToBech32 = hexAddress => {
|
|
10
|
+
const addr = Address.from_hex(hexAddress);
|
|
11
|
+
return addr.to_bech32();
|
|
12
|
+
};
|
package/utils/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { CrowdloanParaState, NetworkJson } from '@subwallet/extension-base/backg
|
|
|
4
4
|
import { AccountAuthType } from '@subwallet/extension-base/background/types';
|
|
5
5
|
import { AccountJson } from '@subwallet/extension-base/types';
|
|
6
6
|
import { BN } from '@polkadot/util';
|
|
7
|
-
export { canDerive } from './canDerive';
|
|
8
7
|
export * from './mv3';
|
|
9
8
|
export * from './fetch';
|
|
9
|
+
export { convertCardanoAddressToHex } from './cardano';
|
|
10
10
|
export declare const notDef: (x: any) => boolean;
|
|
11
11
|
export declare const isDef: (x: any) => boolean;
|
|
12
12
|
export declare const nonEmptyArr: (x: any) => boolean;
|
package/utils/index.js
CHANGED
|
@@ -9,9 +9,9 @@ import { decodeAddress, encodeAddress, isCardanoAddress, isTonAddress } from '@s
|
|
|
9
9
|
import { t } from 'i18next';
|
|
10
10
|
import { assert, BN, hexToU8a, isHex } from '@polkadot/util';
|
|
11
11
|
import { ethereumEncode, isEthereumAddress } from '@polkadot/util-crypto';
|
|
12
|
-
export { canDerive } from "./canDerive.js";
|
|
13
12
|
export * from "./mv3.js";
|
|
14
13
|
export * from "./fetch.js";
|
|
14
|
+
export { convertCardanoAddressToHex } from "./cardano.js";
|
|
15
15
|
export const notDef = x => x === null || typeof x === 'undefined';
|
|
16
16
|
export const isDef = x => !notDef(x);
|
|
17
17
|
export const nonEmptyArr = x => Array.isArray(x) && x.length > 0;
|
package/cjs/utils/canDerive.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.canDerive = canDerive;
|
|
7
|
-
// Copyright 2019-2022 @polkadot/extension authors & contributors
|
|
8
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
9
|
-
|
|
10
|
-
function canDerive(type) {
|
|
11
|
-
return !!type && ['ed25519', 'sr25519', 'ecdsa', 'ethereum'].includes(type);
|
|
12
|
-
}
|
package/utils/canDerive.d.ts
DELETED
package/utils/canDerive.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|