@lifi/sdk 1.4.1 → 1.5.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/CHANGELOG.md +7 -0
- package/dist/Lifi.d.ts +7 -0
- package/dist/Lifi.js +72 -30
- package/dist/cjs/Lifi.d.ts +7 -0
- package/dist/cjs/Lifi.js +72 -30
- package/dist/cjs/execution/StatusManager.d.ts +2 -2
- package/dist/cjs/execution/StatusManager.js +14 -7
- package/dist/cjs/execution/StepExecutor.d.ts +4 -2
- package/dist/cjs/execution/StepExecutor.js +27 -16
- package/dist/cjs/execution/allowance.execute.d.ts +2 -2
- package/dist/cjs/execution/allowance.execute.js +14 -21
- package/dist/cjs/execution/bridges/bridge.execute.d.ts +2 -2
- package/dist/cjs/execution/bridges/bridge.execute.js +101 -90
- package/dist/cjs/execution/exchanges/swap.execute.d.ts +2 -2
- package/dist/cjs/execution/exchanges/swap.execute.js +38 -52
- package/dist/cjs/execution/switchChain.js +3 -3
- package/dist/cjs/helpers.js +1 -1
- package/dist/cjs/services/ConfigService.js +1 -0
- package/dist/cjs/types/internal.types.d.ts +5 -1
- package/dist/cjs/utils/parseError.js +4 -5
- package/dist/cjs/utils/preRestart.js +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/execution/StatusManager.d.ts +2 -2
- package/dist/execution/StatusManager.js +14 -7
- package/dist/execution/StepExecutor.d.ts +4 -2
- package/dist/execution/StepExecutor.js +27 -16
- package/dist/execution/allowance.execute.d.ts +2 -2
- package/dist/execution/allowance.execute.js +14 -21
- package/dist/execution/bridges/bridge.execute.d.ts +2 -2
- package/dist/execution/bridges/bridge.execute.js +102 -91
- package/dist/execution/exchanges/swap.execute.d.ts +2 -2
- package/dist/execution/exchanges/swap.execute.js +39 -53
- package/dist/execution/switchChain.js +3 -3
- package/dist/helpers.js +1 -1
- package/dist/services/ConfigService.js +1 -0
- package/dist/types/internal.types.d.ts +5 -1
- package/dist/utils/parseError.js +4 -5
- package/dist/utils/preRestart.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +9 -9
|
@@ -10,26 +10,37 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { BridgeExecutionManager } from './bridges/bridge.execute';
|
|
11
11
|
import { SwapExecutionManager } from './exchanges/swap.execute';
|
|
12
12
|
import { switchChain } from './switchChain';
|
|
13
|
-
|
|
13
|
+
// Please be careful when changing the defaults as it may break the behavior (e.g., background execution)
|
|
14
|
+
const defaultInteractionSettings = {
|
|
15
|
+
allowInteraction: true,
|
|
14
16
|
allowUpdates: true,
|
|
17
|
+
stopExecution: false,
|
|
15
18
|
};
|
|
16
19
|
export class StepExecutor {
|
|
17
20
|
constructor(statusManager, settings) {
|
|
18
21
|
this.swapExecutionManager = new SwapExecutionManager();
|
|
19
22
|
this.bridgeExecutionManager = new BridgeExecutionManager();
|
|
23
|
+
this.allowUserInteraction = true;
|
|
20
24
|
this.executionStopped = false;
|
|
21
|
-
this.
|
|
22
|
-
const
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
25
|
+
this.setInteraction = (settings) => {
|
|
26
|
+
const interactionSettings = Object.assign(Object.assign({}, defaultInteractionSettings), settings);
|
|
27
|
+
this.allowUserInteraction = interactionSettings.allowInteraction;
|
|
28
|
+
this.swapExecutionManager.allowInteraction(interactionSettings.allowInteraction);
|
|
29
|
+
this.bridgeExecutionManager.allowInteraction(interactionSettings.allowInteraction);
|
|
30
|
+
this.statusManager.allowUpdates(interactionSettings.allowUpdates);
|
|
31
|
+
this.executionStopped = interactionSettings.stopExecution;
|
|
32
|
+
};
|
|
33
|
+
// TODO: add checkChain method and update signer inside executors
|
|
34
|
+
// This can come in handy when we execute multiple routes simultaneously and
|
|
35
|
+
// should be sure that we are on the right chain when waiting for transactions.
|
|
36
|
+
this.checkChain = () => {
|
|
37
|
+
throw new Error('checkChain is not implemented.');
|
|
27
38
|
};
|
|
28
39
|
this.executeStep = (signer, step) => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
//
|
|
30
|
-
const updatedSigner = yield switchChain(signer, this.statusManager, step, this.settings.switchChainHook,
|
|
40
|
+
// Make sure that the chain is still correct
|
|
41
|
+
const updatedSigner = yield switchChain(signer, this.statusManager, step, this.settings.switchChainHook, this.allowUserInteraction);
|
|
31
42
|
if (!updatedSigner) {
|
|
32
|
-
//
|
|
43
|
+
// Chain switch was not successful, stop execution here
|
|
33
44
|
return step;
|
|
34
45
|
}
|
|
35
46
|
signer = updatedSigner;
|
|
@@ -46,24 +57,24 @@ export class StepExecutor {
|
|
|
46
57
|
}
|
|
47
58
|
return step;
|
|
48
59
|
});
|
|
49
|
-
this.executeSwap = (signer, step) =>
|
|
60
|
+
this.executeSwap = (signer, step) => {
|
|
50
61
|
const swapParams = {
|
|
51
62
|
signer,
|
|
52
63
|
step,
|
|
53
64
|
settings: this.settings,
|
|
54
65
|
statusManager: this.statusManager,
|
|
55
66
|
};
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
this.executeCross = (signer, step) =>
|
|
67
|
+
return this.swapExecutionManager.execute(swapParams);
|
|
68
|
+
};
|
|
69
|
+
this.executeCross = (signer, step) => {
|
|
59
70
|
const crossParams = {
|
|
60
71
|
signer,
|
|
61
72
|
step,
|
|
62
73
|
settings: this.settings,
|
|
63
74
|
statusManager: this.statusManager,
|
|
64
75
|
};
|
|
65
|
-
return
|
|
66
|
-
}
|
|
76
|
+
return this.bridgeExecutionManager.execute(crossParams);
|
|
77
|
+
};
|
|
67
78
|
this.statusManager = statusManager;
|
|
68
79
|
this.settings = settings;
|
|
69
80
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Signer } from 'ethers';
|
|
2
|
-
import { Chain,
|
|
2
|
+
import { Chain, InternalExecutionSettings, Step } from '../types';
|
|
3
3
|
import { StatusManager } from './StatusManager';
|
|
4
|
-
export declare const checkAllowance: (signer: Signer, step: Step,
|
|
4
|
+
export declare const checkAllowance: (signer: Signer, step: Step, statusManager: StatusManager, settings: InternalExecutionSettings, chain: Chain, allowUserInteraction?: boolean) => Promise<void>;
|
|
@@ -12,39 +12,33 @@ import { constants } from 'ethers';
|
|
|
12
12
|
import { getApproved, setApproval } from '../allowance/utils';
|
|
13
13
|
import { getProvider } from '../utils/getProvider';
|
|
14
14
|
import { parseError } from '../utils/parseError';
|
|
15
|
-
export const checkAllowance = (signer, step,
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
// -> set currentExecution
|
|
20
|
-
let allowanceProcess = statusManager.findOrCreateProcess('TOKEN_ALLOWANCE', step);
|
|
21
|
-
// -> check allowance
|
|
15
|
+
export const checkAllowance = (signer, step, statusManager, settings, chain, allowUserInteraction = false) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
// Ask the user to set an allowance
|
|
17
|
+
let allowanceProcess = statusManager.findOrCreateProcess(step, 'TOKEN_ALLOWANCE');
|
|
18
|
+
// Check allowance
|
|
22
19
|
try {
|
|
23
|
-
if (allowanceProcess.txHash) {
|
|
24
|
-
|
|
20
|
+
if (allowanceProcess.txHash && allowanceProcess.status !== 'DONE') {
|
|
21
|
+
if (allowanceProcess.status !== 'PENDING') {
|
|
22
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'PENDING');
|
|
23
|
+
}
|
|
25
24
|
yield getProvider(signer).waitForTransaction(allowanceProcess.txHash);
|
|
26
25
|
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
27
|
-
// TODO: Do we need this check?
|
|
28
|
-
}
|
|
29
|
-
else if (allowanceProcess.status === 'DONE') {
|
|
30
|
-
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
31
26
|
}
|
|
32
27
|
else {
|
|
33
|
-
const approved = yield getApproved(signer,
|
|
34
|
-
if (new BigNumber(
|
|
28
|
+
const approved = yield getApproved(signer, step.action.fromToken.address, step.estimate.approvalAddress);
|
|
29
|
+
if (new BigNumber(step.action.fromAmount).gt(approved)) {
|
|
35
30
|
if (!allowUserInteraction) {
|
|
36
31
|
return;
|
|
37
32
|
}
|
|
38
|
-
const approvalAmount = infiniteApproval
|
|
33
|
+
const approvalAmount = settings.infiniteApproval
|
|
39
34
|
? constants.MaxUint256.toString()
|
|
40
|
-
:
|
|
41
|
-
const approveTx = yield setApproval(signer,
|
|
42
|
-
// update currentExecution
|
|
35
|
+
: step.action.fromAmount;
|
|
36
|
+
const approveTx = yield setApproval(signer, step.action.fromToken.address, step.estimate.approvalAddress, approvalAmount);
|
|
43
37
|
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'PENDING', {
|
|
44
38
|
txHash: approveTx.hash,
|
|
45
39
|
txLink: chain.metamask.blockExplorerUrls[0] + 'tx/' + approveTx.hash,
|
|
46
40
|
});
|
|
47
|
-
//
|
|
41
|
+
// Wait for the transcation
|
|
48
42
|
yield approveTx.wait();
|
|
49
43
|
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
50
44
|
}
|
|
@@ -54,7 +48,6 @@ export const checkAllowance = (signer, step, chain, token, amount, spenderAddres
|
|
|
54
48
|
}
|
|
55
49
|
}
|
|
56
50
|
catch (e) {
|
|
57
|
-
// -> set status
|
|
58
51
|
if (e.code === 'TRANSACTION_REPLACED' && e.replacement) {
|
|
59
52
|
yield transactionReplaced(e.replacement, allowanceProcess, step, chain, statusManager);
|
|
60
53
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Execution } from '@lifi/types';
|
|
2
2
|
import { ExecuteCrossParams } from '../../types';
|
|
3
3
|
export declare class BridgeExecutionManager {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
allowUserInteraction: boolean;
|
|
5
|
+
allowInteraction: (value: boolean) => void;
|
|
6
6
|
execute: ({ signer, step, statusManager, settings, }: ExecuteCrossParams) => Promise<Execution>;
|
|
7
7
|
}
|
|
@@ -7,13 +7,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { constants } from 'ethers';
|
|
11
10
|
import ApiService from '../../services/ApiService';
|
|
12
11
|
import ChainsService from '../../services/ChainsService';
|
|
13
12
|
import { LifiErrorCode, TransactionError } from '../../utils/errors';
|
|
14
13
|
import { getProvider } from '../../utils/getProvider';
|
|
15
14
|
import { getTransactionFailedMessage, parseError } from '../../utils/parseError';
|
|
16
|
-
import { personalizeStep } from '../../utils/utils';
|
|
15
|
+
import { isZeroAddress, personalizeStep } from '../../utils/utils';
|
|
17
16
|
import { checkAllowance } from '../allowance.execute';
|
|
18
17
|
import { balanceCheck } from '../balanceCheck.execute';
|
|
19
18
|
import { stepComparison } from '../stepComparison';
|
|
@@ -21,98 +20,125 @@ import { switchChain } from '../switchChain';
|
|
|
21
20
|
import { getSubstatusMessage, waitForReceivingTransaction } from '../utils';
|
|
22
21
|
export class BridgeExecutionManager {
|
|
23
22
|
constructor() {
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
23
|
+
this.allowUserInteraction = true;
|
|
24
|
+
this.allowInteraction = (value) => {
|
|
25
|
+
this.allowUserInteraction = value;
|
|
27
26
|
};
|
|
28
27
|
this.execute = ({ signer, step, statusManager, settings, }) => __awaiter(this, void 0, void 0, function* () {
|
|
29
28
|
var _a, _b, _c, _d;
|
|
30
|
-
const { action, estimate } = step;
|
|
31
29
|
step.execution = statusManager.initExecutionObject(step);
|
|
32
30
|
const chainsService = ChainsService.getInstance();
|
|
33
|
-
const fromChain = yield chainsService.getChainById(action.fromChainId);
|
|
34
|
-
const toChain = yield chainsService.getChainById(action.toChainId);
|
|
35
|
-
// STEP 1: Check
|
|
36
|
-
// approval still needed?
|
|
31
|
+
const fromChain = yield chainsService.getChainById(step.action.fromChainId);
|
|
32
|
+
const toChain = yield chainsService.getChainById(step.action.toChainId);
|
|
33
|
+
// STEP 1: Check allowance
|
|
37
34
|
const oldCrossProcess = step.execution.process.find((p) => p.type === 'CROSS_CHAIN');
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
35
|
+
// Check token approval only if fromToken is not the native token => no approval needed in that case
|
|
36
|
+
if (!(oldCrossProcess === null || oldCrossProcess === void 0 ? void 0 : oldCrossProcess.txHash) &&
|
|
37
|
+
!isZeroAddress(step.action.fromToken.address)) {
|
|
38
|
+
yield checkAllowance(signer, step, statusManager, settings, fromChain, this.allowUserInteraction);
|
|
43
39
|
}
|
|
44
|
-
// STEP 2: Get
|
|
45
|
-
let crossChainProcess = statusManager.findOrCreateProcess('CROSS_CHAIN'
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
// STEP 2: Get transaction
|
|
41
|
+
let crossChainProcess = statusManager.findOrCreateProcess(step, 'CROSS_CHAIN');
|
|
42
|
+
if (crossChainProcess.status !== 'DONE') {
|
|
43
|
+
try {
|
|
44
|
+
let transaction;
|
|
45
|
+
if (crossChainProcess.txHash) {
|
|
46
|
+
// Make sure that the chain is still correct
|
|
47
|
+
const updatedSigner = yield switchChain(signer, statusManager, step, settings.switchChainHook, this.allowUserInteraction);
|
|
48
|
+
if (!updatedSigner) {
|
|
49
|
+
// Chain switch was not successful, stop execution here
|
|
50
|
+
return step.execution;
|
|
51
|
+
}
|
|
52
|
+
signer = updatedSigner;
|
|
53
|
+
// Load exiting transaction
|
|
54
|
+
transaction = yield getProvider(signer).getTransaction(crossChainProcess.txHash);
|
|
59
55
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
else {
|
|
57
|
+
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'STARTED');
|
|
58
|
+
// Check balance
|
|
59
|
+
yield balanceCheck(signer, step);
|
|
60
|
+
// Create new transaction
|
|
61
|
+
if (!step.transactionRequest) {
|
|
62
|
+
const personalizedStep = yield personalizeStep(signer, step);
|
|
63
|
+
const updatedStep = yield ApiService.getStepTransaction(personalizedStep);
|
|
64
|
+
step = Object.assign(Object.assign({}, (yield stepComparison(statusManager, personalizedStep, updatedStep, settings.acceptSlippageUpdateHook, this.allowUserInteraction))), { execution: step.execution });
|
|
65
|
+
}
|
|
66
|
+
const { transactionRequest } = step;
|
|
67
|
+
if (!transactionRequest) {
|
|
68
|
+
throw new TransactionError(LifiErrorCode.TransactionUnprepared, 'Unable to prepare transaction.');
|
|
69
|
+
}
|
|
70
|
+
// STEP 3: Send the transaction
|
|
71
|
+
// Make sure that the chain is still correct
|
|
72
|
+
const updatedSigner = yield switchChain(signer, statusManager, step, settings.switchChainHook, this.allowUserInteraction);
|
|
73
|
+
if (!updatedSigner) {
|
|
74
|
+
// Chain switch was not successful, stop execution here
|
|
75
|
+
return step.execution;
|
|
76
|
+
}
|
|
77
|
+
signer = updatedSigner;
|
|
78
|
+
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'ACTION_REQUIRED');
|
|
79
|
+
if (!this.allowUserInteraction) {
|
|
80
|
+
return step.execution;
|
|
81
|
+
}
|
|
82
|
+
// Submit the transaction
|
|
83
|
+
transaction = yield signer.sendTransaction(transactionRequest);
|
|
84
|
+
// STEP 4: Wait for the transaction
|
|
85
|
+
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'PENDING', {
|
|
86
|
+
txHash: transaction.hash,
|
|
87
|
+
txLink: fromChain.metamask.blockExplorerUrls[0] +
|
|
88
|
+
'tx/' +
|
|
89
|
+
transaction.hash,
|
|
90
|
+
});
|
|
63
91
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
yield transaction.wait();
|
|
93
|
+
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'DONE');
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
if (e.code === 'TRANSACTION_REPLACED' && e.replacement) {
|
|
97
|
+
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'DONE', {
|
|
98
|
+
txHash: e.replacement.hash,
|
|
99
|
+
txLink: fromChain.metamask.blockExplorerUrls[0] +
|
|
100
|
+
'tx/' +
|
|
101
|
+
e.replacement.hash,
|
|
102
|
+
});
|
|
70
103
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
104
|
+
else {
|
|
105
|
+
const error = yield parseError(e, step, crossChainProcess);
|
|
106
|
+
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'FAILED', {
|
|
107
|
+
error: {
|
|
108
|
+
message: error.message,
|
|
109
|
+
htmlMessage: error.htmlMessage,
|
|
110
|
+
code: error.code,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
statusManager.updateExecution(step, 'FAILED');
|
|
114
|
+
throw error;
|
|
75
115
|
}
|
|
76
|
-
tx = yield signer.sendTransaction(transactionRequest);
|
|
77
|
-
// STEP 4: Wait for Transaction ///////////////////////////////////////////
|
|
78
|
-
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'PENDING', {
|
|
79
|
-
txHash: tx.hash,
|
|
80
|
-
txLink: fromChain.metamask.blockExplorerUrls[0] + 'tx/' + tx.hash,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
yield tx.wait();
|
|
84
|
-
}
|
|
85
|
-
catch (e) {
|
|
86
|
-
if (e.code === 'TRANSACTION_REPLACED' && e.replacement) {
|
|
87
|
-
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'PENDING', {
|
|
88
|
-
txHash: e.replacement.hash,
|
|
89
|
-
txLink: fromChain.metamask.blockExplorerUrls[0] +
|
|
90
|
-
'tx/' +
|
|
91
|
-
e.replacement.hash,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
const error = yield parseError(e, step, crossChainProcess);
|
|
96
|
-
crossChainProcess = statusManager.updateProcess(step, crossChainProcess.type, 'FAILED', {
|
|
97
|
-
error: {
|
|
98
|
-
message: error.message,
|
|
99
|
-
htmlMessage: error.htmlMessage,
|
|
100
|
-
code: error.code,
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
statusManager.updateExecution(step, 'FAILED');
|
|
104
|
-
throw error;
|
|
105
116
|
}
|
|
106
117
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
let receivingChainProcess = statusManager.findOrCreateProcess('RECEIVING_CHAIN', step, 'PENDING');
|
|
118
|
+
// STEP 5: Wait for the receiving chain
|
|
119
|
+
let receivingChainProcess = statusManager.findOrCreateProcess(step, 'RECEIVING_CHAIN', 'PENDING');
|
|
110
120
|
let statusResponse;
|
|
111
121
|
try {
|
|
112
122
|
if (!crossChainProcess.txHash) {
|
|
113
123
|
throw new Error('Transaction hash is undefined.');
|
|
114
124
|
}
|
|
115
125
|
statusResponse = yield waitForReceivingTransaction(crossChainProcess.txHash, statusManager, receivingChainProcess.type, step);
|
|
126
|
+
receivingChainProcess = statusManager.updateProcess(step, receivingChainProcess.type, 'DONE', {
|
|
127
|
+
substatus: statusResponse.substatus,
|
|
128
|
+
substatusMessage: statusResponse.substatusMessage ||
|
|
129
|
+
getSubstatusMessage(statusResponse.status, statusResponse.substatus),
|
|
130
|
+
txHash: (_a = statusResponse.receiving) === null || _a === void 0 ? void 0 : _a.txHash,
|
|
131
|
+
txLink: toChain.metamask.blockExplorerUrls[0] +
|
|
132
|
+
'tx/' +
|
|
133
|
+
((_b = statusResponse.receiving) === null || _b === void 0 ? void 0 : _b.txHash),
|
|
134
|
+
});
|
|
135
|
+
statusManager.updateExecution(step, 'DONE', {
|
|
136
|
+
fromAmount: statusResponse.sending.amount,
|
|
137
|
+
toAmount: (_c = statusResponse.receiving) === null || _c === void 0 ? void 0 : _c.amount,
|
|
138
|
+
toToken: (_d = statusResponse.receiving) === null || _d === void 0 ? void 0 : _d.token,
|
|
139
|
+
gasUsed: statusResponse.sending.gasUsed,
|
|
140
|
+
gasPrice: statusResponse.sending.gasPrice,
|
|
141
|
+
});
|
|
116
142
|
}
|
|
117
143
|
catch (e) {
|
|
118
144
|
receivingChainProcess = statusManager.updateProcess(step, receivingChainProcess.type, 'FAILED', {
|
|
@@ -123,24 +149,9 @@ export class BridgeExecutionManager {
|
|
|
123
149
|
},
|
|
124
150
|
});
|
|
125
151
|
statusManager.updateExecution(step, 'FAILED');
|
|
152
|
+
console.warn(e);
|
|
126
153
|
throw e;
|
|
127
154
|
}
|
|
128
|
-
receivingChainProcess = statusManager.updateProcess(step, receivingChainProcess.type, 'DONE', {
|
|
129
|
-
substatus: statusResponse.substatus,
|
|
130
|
-
substatusMessage: statusResponse.substatusMessage ||
|
|
131
|
-
getSubstatusMessage(statusResponse.status, statusResponse.substatus),
|
|
132
|
-
txHash: (_a = statusResponse.receiving) === null || _a === void 0 ? void 0 : _a.txHash,
|
|
133
|
-
txLink: toChain.metamask.blockExplorerUrls[0] +
|
|
134
|
-
'tx/' +
|
|
135
|
-
((_b = statusResponse.receiving) === null || _b === void 0 ? void 0 : _b.txHash),
|
|
136
|
-
});
|
|
137
|
-
statusManager.updateExecution(step, 'DONE', {
|
|
138
|
-
fromAmount: statusResponse.sending.amount,
|
|
139
|
-
toAmount: (_c = statusResponse.receiving) === null || _c === void 0 ? void 0 : _c.amount,
|
|
140
|
-
toToken: (_d = statusResponse.receiving) === null || _d === void 0 ? void 0 : _d.token,
|
|
141
|
-
gasUsed: statusResponse.sending.gasUsed,
|
|
142
|
-
gasPrice: statusResponse.sending.gasPrice,
|
|
143
|
-
});
|
|
144
155
|
// DONE
|
|
145
156
|
return step.execution;
|
|
146
157
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Execution } from '@lifi/types';
|
|
2
2
|
import { ExecuteSwapParams } from '../../types';
|
|
3
3
|
export declare class SwapExecutionManager {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
allowUserInteraction: boolean;
|
|
5
|
+
allowInteraction: (value: boolean) => void;
|
|
6
6
|
execute: ({ signer, step, statusManager, settings, }: ExecuteSwapParams) => Promise<Execution>;
|
|
7
7
|
}
|
|
@@ -7,13 +7,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { constants } from 'ethers';
|
|
11
10
|
import ApiService from '../../services/ApiService';
|
|
12
11
|
import ChainsService from '../../services/ChainsService';
|
|
13
12
|
import { LifiErrorCode, TransactionError } from '../../utils/errors';
|
|
14
13
|
import { getProvider } from '../../utils/getProvider';
|
|
15
14
|
import { getTransactionFailedMessage, parseError } from '../../utils/parseError';
|
|
16
|
-
import { personalizeStep } from '../../utils/utils';
|
|
15
|
+
import { isZeroAddress, personalizeStep } from '../../utils/utils';
|
|
17
16
|
import { checkAllowance } from '../allowance.execute';
|
|
18
17
|
import { balanceCheck } from '../balanceCheck.execute';
|
|
19
18
|
import { stepComparison } from '../stepComparison';
|
|
@@ -21,86 +20,72 @@ import { switchChain } from '../switchChain';
|
|
|
21
20
|
import { waitForReceivingTransaction } from '../utils';
|
|
22
21
|
export class SwapExecutionManager {
|
|
23
22
|
constructor() {
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
23
|
+
this.allowUserInteraction = true;
|
|
24
|
+
this.allowInteraction = (value) => {
|
|
25
|
+
this.allowUserInteraction = value;
|
|
27
26
|
};
|
|
28
27
|
this.execute = ({ signer, step, statusManager, settings, }) => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
// setup
|
|
30
28
|
var _a, _b, _c, _d;
|
|
31
|
-
const { action, estimate } = step;
|
|
32
29
|
step.execution = statusManager.initExecutionObject(step);
|
|
33
30
|
const chainsService = ChainsService.getInstance();
|
|
34
|
-
const fromChain = yield chainsService.getChainById(action.fromChainId);
|
|
35
|
-
//
|
|
36
|
-
if (action.fromToken.address
|
|
37
|
-
yield checkAllowance(signer, step,
|
|
31
|
+
const fromChain = yield chainsService.getChainById(step.action.fromChainId);
|
|
32
|
+
// STEP 1: Check allowance
|
|
33
|
+
if (!isZeroAddress(step.action.fromToken.address)) {
|
|
34
|
+
yield checkAllowance(signer, step, statusManager, settings, fromChain, this.allowUserInteraction);
|
|
38
35
|
}
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
let
|
|
42
|
-
// -> swapping
|
|
43
|
-
let tx;
|
|
36
|
+
// STEP 2: Get transaction
|
|
37
|
+
let swapProcess = statusManager.findOrCreateProcess(step, 'SWAP');
|
|
38
|
+
let transaction;
|
|
44
39
|
try {
|
|
45
40
|
if (swapProcess.txHash) {
|
|
46
|
-
//
|
|
47
|
-
|
|
41
|
+
// Make sure that the chain is still correct
|
|
42
|
+
const updatedSigner = yield switchChain(signer, statusManager, step, settings.switchChainHook, this.allowUserInteraction);
|
|
43
|
+
if (!updatedSigner) {
|
|
44
|
+
// Chain switch was not successful, stop execution here
|
|
45
|
+
return step.execution;
|
|
46
|
+
}
|
|
47
|
+
signer = updatedSigner;
|
|
48
|
+
// Load exiting transaction
|
|
49
|
+
transaction = yield getProvider(signer).getTransaction(swapProcess.txHash);
|
|
48
50
|
}
|
|
49
51
|
else {
|
|
50
|
-
|
|
52
|
+
swapProcess = statusManager.updateProcess(step, swapProcess.type, 'STARTED');
|
|
53
|
+
// Check balance
|
|
51
54
|
yield balanceCheck(signer, step);
|
|
52
|
-
//
|
|
55
|
+
// Create new transaction
|
|
53
56
|
if (!step.transactionRequest) {
|
|
54
57
|
const personalizedStep = yield personalizeStep(signer, step);
|
|
55
58
|
const updatedStep = yield ApiService.getStepTransaction(personalizedStep);
|
|
56
|
-
step = Object.assign(Object.assign({}, (yield stepComparison(statusManager, personalizedStep, updatedStep, settings.acceptSlippageUpdateHook, this.
|
|
59
|
+
step = Object.assign(Object.assign({}, (yield stepComparison(statusManager, personalizedStep, updatedStep, settings.acceptSlippageUpdateHook, this.allowUserInteraction))), { execution: step.execution });
|
|
57
60
|
}
|
|
58
61
|
const { transactionRequest } = step;
|
|
59
62
|
if (!transactionRequest) {
|
|
60
63
|
throw new TransactionError(LifiErrorCode.TransactionUnprepared, 'Unable to prepare transaction.');
|
|
61
64
|
}
|
|
62
|
-
//
|
|
63
|
-
|
|
65
|
+
// STEP 3: Send the transaction
|
|
66
|
+
// Make sure that the chain is still correct
|
|
67
|
+
const updatedSigner = yield switchChain(signer, statusManager, step, settings.switchChainHook, this.allowUserInteraction);
|
|
64
68
|
if (!updatedSigner) {
|
|
65
|
-
//
|
|
69
|
+
// Chain switch was not successful, stop execution here
|
|
66
70
|
return step.execution;
|
|
67
71
|
}
|
|
68
72
|
signer = updatedSigner;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return step.execution; // stop before user interaction is needed
|
|
73
|
+
swapProcess = statusManager.updateProcess(step, swapProcess.type, 'ACTION_REQUIRED');
|
|
74
|
+
if (!this.allowUserInteraction) {
|
|
75
|
+
return step.execution;
|
|
73
76
|
}
|
|
74
|
-
//
|
|
75
|
-
|
|
77
|
+
// Submit the transaction
|
|
78
|
+
transaction = yield signer.sendTransaction(transactionRequest);
|
|
76
79
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
error: {
|
|
82
|
-
message: error.message,
|
|
83
|
-
htmlMessage: error.htmlMessage,
|
|
84
|
-
code: error.code,
|
|
85
|
-
},
|
|
80
|
+
// STEP 4: Wait for the transaction
|
|
81
|
+
swapProcess = statusManager.updateProcess(step, swapProcess.type, 'PENDING', {
|
|
82
|
+
txLink: fromChain.metamask.blockExplorerUrls[0] + 'tx/' + transaction.hash,
|
|
83
|
+
txHash: transaction.hash,
|
|
86
84
|
});
|
|
87
|
-
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
// Wait for Transaction
|
|
91
|
-
swapProcess = statusManager.updateProcess(step, swapProcess.type, 'PENDING', {
|
|
92
|
-
txLink: fromChain.metamask.blockExplorerUrls[0] + 'tx/' + tx.hash,
|
|
93
|
-
txHash: tx.hash,
|
|
94
|
-
});
|
|
95
|
-
// -> waiting
|
|
96
|
-
let receipt;
|
|
97
|
-
try {
|
|
98
|
-
receipt = yield tx.wait();
|
|
85
|
+
yield transaction.wait();
|
|
99
86
|
}
|
|
100
87
|
catch (e) {
|
|
101
|
-
// -> set status
|
|
102
88
|
if (e.code === 'TRANSACTION_REPLACED' && e.replacement) {
|
|
103
|
-
receipt = e.replacement;
|
|
104
89
|
swapProcess = statusManager.updateProcess(step, swapProcess.type, 'PENDING', {
|
|
105
90
|
txHash: e.replacement.hash,
|
|
106
91
|
txLink: fromChain.metamask.blockExplorerUrls[0] +
|
|
@@ -121,6 +106,7 @@ export class SwapExecutionManager {
|
|
|
121
106
|
throw error;
|
|
122
107
|
}
|
|
123
108
|
}
|
|
109
|
+
// STEP 5: Wait for the receiving chain
|
|
124
110
|
let statusResponse;
|
|
125
111
|
try {
|
|
126
112
|
if (!swapProcess.txHash) {
|
|
@@ -26,8 +26,8 @@ export const switchChain = (signer, statusManager, step, switchChainHook, allowU
|
|
|
26
26
|
}
|
|
27
27
|
// -> set status message
|
|
28
28
|
step.execution = statusManager.initExecutionObject(step);
|
|
29
|
-
statusManager.updateExecution(step, '
|
|
30
|
-
let switchProcess = statusManager.findOrCreateProcess('SWITCH_CHAIN',
|
|
29
|
+
statusManager.updateExecution(step, 'ACTION_REQUIRED');
|
|
30
|
+
let switchProcess = statusManager.findOrCreateProcess(step, 'SWITCH_CHAIN', 'ACTION_REQUIRED');
|
|
31
31
|
if (!allowUserInteraction) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
@@ -45,7 +45,7 @@ export const switchChain = (signer, statusManager, step, switchChainHook, allowU
|
|
|
45
45
|
switchProcess = statusManager.updateProcess(step, switchProcess.type, 'FAILED', {
|
|
46
46
|
error: {
|
|
47
47
|
message: error.message,
|
|
48
|
-
code:
|
|
48
|
+
code: LifiErrorCode.ChainSwitchError,
|
|
49
49
|
},
|
|
50
50
|
});
|
|
51
51
|
statusManager.updateExecution(step, 'FAILED');
|
package/dist/helpers.js
CHANGED
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { name, version } from './version';
|
|
11
11
|
const ethereumRequest = (method, params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12
12
|
// If ethereum.request() exists, the provider is probably EIP-1193 compliant.
|
|
13
|
-
if (!ethereum ||
|
|
13
|
+
if (!(ethereum === null || ethereum === void 0 ? void 0 : ethereum.request)) {
|
|
14
14
|
throw new Error('Provider not available.');
|
|
15
15
|
}
|
|
16
16
|
return ethereum.request({
|
|
@@ -14,6 +14,7 @@ const DefaultExecutionSettings = {
|
|
|
14
14
|
switchChainHook: () => Promise.resolve(undefined),
|
|
15
15
|
acceptSlippageUpdateHook: () => Promise.resolve(undefined),
|
|
16
16
|
infiniteApproval: false,
|
|
17
|
+
executeInBackground: false,
|
|
17
18
|
};
|
|
18
19
|
export default class ConfigService {
|
|
19
20
|
constructor() {
|
|
@@ -64,12 +64,14 @@ export interface ExecutionSettings {
|
|
|
64
64
|
switchChainHook?: SwitchChainHook;
|
|
65
65
|
acceptSlippageUpdateHook?: AcceptSlippageUpdateHook;
|
|
66
66
|
infiniteApproval?: boolean;
|
|
67
|
+
executeInBackground?: boolean;
|
|
67
68
|
}
|
|
68
69
|
export interface InternalExecutionSettings extends ExecutionSettings {
|
|
69
70
|
updateCallback: CallbackFunction;
|
|
70
71
|
switchChainHook: SwitchChainHook;
|
|
71
72
|
acceptSlippageUpdateHook: AcceptSlippageUpdateHook;
|
|
72
73
|
infiniteApproval: boolean;
|
|
74
|
+
executeInBackground: boolean;
|
|
73
75
|
}
|
|
74
76
|
export declare type EnforcedObjectProperties<T> = T & {
|
|
75
77
|
[P in keyof T]-?: T[P];
|
|
@@ -81,7 +83,9 @@ export declare type RevokeTokenData = {
|
|
|
81
83
|
token: Token;
|
|
82
84
|
approvalAddress: string;
|
|
83
85
|
};
|
|
84
|
-
export interface
|
|
86
|
+
export interface InteractionSettings {
|
|
87
|
+
allowInteraction?: boolean;
|
|
85
88
|
allowUpdates?: boolean;
|
|
89
|
+
stopExecution?: boolean;
|
|
86
90
|
}
|
|
87
91
|
export {};
|