@lifi/sdk 1.1.2 → 1.1.5
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 +11 -0
- package/dist/Lifi.js +179 -285
- package/dist/allowance/index.js +56 -148
- package/dist/allowance/utils.js +51 -116
- package/dist/balances/index.js +29 -92
- package/dist/balances/utils.js +108 -218
- package/dist/cjs/Lifi.d.ts +200 -0
- package/dist/cjs/Lifi.js +376 -0
- package/dist/cjs/allowance/index.d.ts +22 -0
- package/dist/cjs/allowance/index.js +78 -0
- package/dist/cjs/allowance/utils.d.ts +14 -0
- package/dist/cjs/allowance/utils.js +82 -0
- package/dist/cjs/balances/index.d.ts +11 -0
- package/dist/cjs/balances/index.js +46 -0
- package/dist/cjs/balances/utils.d.ts +5 -0
- package/dist/cjs/balances/utils.js +150 -0
- package/dist/cjs/connectors.d.ts +6 -0
- package/dist/cjs/connectors.js +77 -0
- package/dist/cjs/execution/StatusManager.d.ts +65 -0
- package/dist/cjs/execution/StatusManager.js +167 -0
- package/dist/cjs/execution/StepExecutor.d.ts +15 -0
- package/dist/cjs/execution/StepExecutor.js +74 -0
- package/dist/cjs/execution/allowance.execute.d.ts +4 -0
- package/dist/cjs/execution/allowance.execute.js +97 -0
- package/dist/cjs/execution/balanceCheck.execute.d.ts +3 -0
- package/dist/cjs/execution/balanceCheck.execute.js +48 -0
- package/dist/cjs/execution/bridges/bridge.execute.d.ts +7 -0
- package/dist/cjs/execution/bridges/bridge.execute.js +154 -0
- package/dist/cjs/execution/exchanges/swap.execute.d.ts +7 -0
- package/dist/cjs/execution/exchanges/swap.execute.js +164 -0
- package/dist/cjs/execution/index.d.ts +1 -0
- package/dist/cjs/execution/index.js +17 -0
- package/dist/cjs/execution/stepComparison.d.ts +14 -0
- package/dist/cjs/execution/stepComparison.js +46 -0
- package/dist/cjs/execution/switchChain.d.ts +16 -0
- package/dist/cjs/execution/switchChain.js +58 -0
- package/dist/cjs/execution/utils.d.ts +6 -0
- package/dist/cjs/execution/utils.js +137 -0
- package/dist/cjs/helpers.d.ts +18 -0
- package/dist/cjs/helpers.js +54 -0
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/services/ApiService.d.ts +15 -0
- package/dist/cjs/services/ApiService.js +272 -0
- package/dist/cjs/services/ChainsService.d.ts +11 -0
- package/dist/cjs/services/ChainsService.js +54 -0
- package/dist/cjs/services/ConfigService.d.ts +23 -0
- package/dist/cjs/services/ConfigService.js +98 -0
- package/dist/cjs/typeguards.d.ts +4 -0
- package/dist/cjs/typeguards.js +53 -0
- package/dist/cjs/types/ERC20.d.ts +22 -0
- package/dist/cjs/types/ERC20.js +53 -0
- package/dist/cjs/types/index.d.ts +4 -0
- package/dist/cjs/types/index.js +22 -0
- package/dist/cjs/types/internal.types.d.ts +85 -0
- package/dist/cjs/types/internal.types.js +2 -0
- package/dist/cjs/utils/errors.d.ts +75 -0
- package/dist/cjs/utils/errors.js +115 -0
- package/dist/cjs/utils/getProvider.d.ts +3 -0
- package/dist/cjs/utils/getProvider.js +11 -0
- package/dist/cjs/utils/multicall.d.ts +10 -0
- package/dist/cjs/utils/multicall.js +77 -0
- package/dist/cjs/utils/multicallAbi.json +313 -0
- package/dist/cjs/utils/parseError.d.ts +38 -0
- package/dist/cjs/utils/parseError.js +141 -0
- package/dist/cjs/utils/preRestart.d.ts +2 -0
- package/dist/cjs/utils/preRestart.js +31 -0
- package/dist/cjs/utils/utils.d.ts +26 -0
- package/dist/cjs/utils/utils.js +120 -0
- package/dist/connectors.js +50 -133
- package/dist/execution/StatusManager.js +34 -41
- package/dist/execution/StepExecutor.js +54 -123
- package/dist/execution/allowance.execute.js +76 -142
- package/dist/execution/balanceCheck.execute.js +29 -74
- package/dist/execution/bridges/bridge.execute.js +132 -221
- package/dist/execution/exchanges/swap.execute.js +142 -225
- package/dist/execution/index.js +1 -17
- package/dist/execution/stepComparison.js +22 -61
- package/dist/execution/switchChain.js +33 -81
- package/dist/execution/utils.js +60 -119
- package/dist/helpers.js +15 -53
- package/dist/index.js +6 -25
- package/dist/services/ApiService.js +248 -385
- package/dist/services/ChainsService.js +29 -89
- package/dist/services/ConfigService.js +47 -86
- package/dist/typeguards.js +13 -21
- package/dist/types/ERC20.js +1 -4
- package/dist/types/index.js +4 -22
- package/dist/types/internal.types.js +1 -2
- package/dist/utils/errors.js +47 -93
- package/dist/utils/getProvider.js +3 -7
- package/dist/utils/multicall.js +61 -117
- package/dist/utils/parseError.js +73 -141
- package/dist/utils/preRestart.js +14 -21
- package/dist/utils/utils.js +47 -130
- package/package.json +34 -11
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
16
|
+
const ethers_1 = require("ethers");
|
|
17
|
+
const connectors_1 = require("../connectors");
|
|
18
|
+
const multicall_1 = require("../utils/multicall");
|
|
19
|
+
const utils_1 = require("../utils/utils");
|
|
20
|
+
const balanceAbi = [
|
|
21
|
+
{
|
|
22
|
+
constant: true,
|
|
23
|
+
inputs: [{ name: 'who', type: 'address' }],
|
|
24
|
+
name: 'balanceOf',
|
|
25
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
26
|
+
payable: false,
|
|
27
|
+
stateMutability: 'view',
|
|
28
|
+
type: 'function',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
constant: true,
|
|
32
|
+
inputs: [{ name: 'addr', type: 'address' }],
|
|
33
|
+
name: 'getEthBalance',
|
|
34
|
+
outputs: [{ name: 'balance', type: 'uint256' }],
|
|
35
|
+
payable: false,
|
|
36
|
+
stateMutability: 'view',
|
|
37
|
+
type: 'function',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
const getBalances = (walletAddress, tokens) => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
|
+
if (tokens.length === 0) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const { chainId } = tokens[0];
|
|
45
|
+
tokens.forEach((token) => {
|
|
46
|
+
if (token.chainId !== chainId) {
|
|
47
|
+
// eslint-disable-next-line no-console
|
|
48
|
+
console.warn(`Requested tokens have to be on same chain.`);
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
if ((yield (0, connectors_1.getMulticallAddress)(chainId)) && tokens.length > 1) {
|
|
53
|
+
return getBalancesFromProviderUsingMulticall(walletAddress, tokens);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return getBalancesFromProvider(walletAddress, tokens);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const getBalancesFromProviderUsingMulticall = (walletAddress, tokens) => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
+
// Configuration
|
|
61
|
+
const { chainId } = tokens[0];
|
|
62
|
+
const multicallAddress = yield (0, connectors_1.getMulticallAddress)(chainId);
|
|
63
|
+
if (!multicallAddress) {
|
|
64
|
+
throw new Error('No multicallAddress found for the given chain.');
|
|
65
|
+
}
|
|
66
|
+
return executeMulticall(walletAddress, tokens, multicallAddress, chainId);
|
|
67
|
+
});
|
|
68
|
+
const executeMulticall = (walletAddress, tokens, multicallAddress, chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
|
+
// Collect calls we want to make
|
|
70
|
+
const calls = [];
|
|
71
|
+
tokens.map((token) => {
|
|
72
|
+
if ((0, utils_1.isZeroAddress)(token.address)) {
|
|
73
|
+
calls.push({
|
|
74
|
+
address: multicallAddress,
|
|
75
|
+
name: 'getEthBalance',
|
|
76
|
+
params: [walletAddress],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
calls.push({
|
|
81
|
+
address: token.address,
|
|
82
|
+
name: 'balanceOf',
|
|
83
|
+
params: [walletAddress],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const res = yield fetchViaMulticall(calls, balanceAbi, chainId, multicallAddress);
|
|
88
|
+
if (!res.length) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
return tokens.map((token, i) => {
|
|
92
|
+
const amount = new bignumber_js_1.default(res[i].amount.toString() || '0')
|
|
93
|
+
.shiftedBy(-token.decimals)
|
|
94
|
+
.toFixed();
|
|
95
|
+
return Object.assign(Object.assign({}, token), { amount: amount || '0', blockNumber: res[i].blockNumber });
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
const fetchViaMulticall = (calls, abi, chainId, multicallAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
const result = yield (0, multicall_1.fetchDataUsingMulticall)(calls, abi, chainId, multicallAddress);
|
|
100
|
+
return result.map(({ data, blockNumber }) => ({
|
|
101
|
+
amount: data ? data : new bignumber_js_1.default(0),
|
|
102
|
+
blockNumber,
|
|
103
|
+
}));
|
|
104
|
+
});
|
|
105
|
+
const getBalancesFromProvider = (walletAddress, tokens) => __awaiter(void 0, void 0, void 0, function* () {
|
|
106
|
+
const chainId = tokens[0].chainId;
|
|
107
|
+
const rpc = yield (0, connectors_1.getRpcProvider)(chainId);
|
|
108
|
+
const tokenAmountPromises = tokens.map((token) => __awaiter(void 0, void 0, void 0, function* () {
|
|
109
|
+
let amount = '0';
|
|
110
|
+
let blockNumber;
|
|
111
|
+
try {
|
|
112
|
+
const balance = yield getBalanceFromProvider(walletAddress, token.address, chainId, rpc);
|
|
113
|
+
amount = new bignumber_js_1.default(balance.amount.toString())
|
|
114
|
+
.shiftedBy(-token.decimals)
|
|
115
|
+
.toString();
|
|
116
|
+
blockNumber = balance.blockNumber;
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
// eslint-disable-next-line no-console
|
|
120
|
+
console.warn(e);
|
|
121
|
+
}
|
|
122
|
+
return Object.assign(Object.assign({}, token), { amount,
|
|
123
|
+
blockNumber });
|
|
124
|
+
}));
|
|
125
|
+
return Promise.all(tokenAmountPromises);
|
|
126
|
+
});
|
|
127
|
+
const getBalanceFromProvider = (walletAddress, assetId, chainId, provider) => __awaiter(void 0, void 0, void 0, function* () {
|
|
128
|
+
const blockNumber = yield getCurrentBlockNumber(chainId);
|
|
129
|
+
let balance;
|
|
130
|
+
if ((0, utils_1.isZeroAddress)(assetId)) {
|
|
131
|
+
balance = yield provider.getBalance(walletAddress, blockNumber);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const contract = new ethers_1.ethers.Contract(assetId, ['function balanceOf(address owner) view returns (uint256)'], provider);
|
|
135
|
+
balance = yield contract.balanceOf(walletAddress, {
|
|
136
|
+
blockTag: blockNumber,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
amount: balance,
|
|
141
|
+
blockNumber,
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
const getCurrentBlockNumber = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
145
|
+
const rpc = yield (0, connectors_1.getRpcProvider)(chainId);
|
|
146
|
+
return rpc.getBlockNumber();
|
|
147
|
+
});
|
|
148
|
+
exports.default = {
|
|
149
|
+
getBalances,
|
|
150
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ChainId } from './types';
|
|
2
|
+
import { FallbackProvider } from '@ethersproject/providers';
|
|
3
|
+
export declare const getRpcUrl: (chainId: ChainId, archive?: boolean) => Promise<string>;
|
|
4
|
+
export declare const getRpcUrls: (chainId: ChainId, archive?: boolean) => Promise<string[]>;
|
|
5
|
+
export declare const getRpcProvider: (chainId: number, archive?: boolean) => Promise<FallbackProvider>;
|
|
6
|
+
export declare const getMulticallAddress: (chainId: ChainId) => Promise<string | undefined>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getMulticallAddress = exports.getRpcProvider = exports.getRpcUrls = exports.getRpcUrl = void 0;
|
|
16
|
+
const ethers_1 = require("ethers");
|
|
17
|
+
const _1 = require(".");
|
|
18
|
+
const types_1 = require("./types");
|
|
19
|
+
const ConfigService_1 = __importDefault(require("./services/ConfigService"));
|
|
20
|
+
// cached providers
|
|
21
|
+
const chainProviders = {};
|
|
22
|
+
// Archive RPC Provider
|
|
23
|
+
const archiveRpcs = {
|
|
24
|
+
[types_1.ChainId.ETH]: 'https://speedy-nodes-nyc.moralis.io/5ed6053dc39eba789ff466c9/eth/mainnet/archive',
|
|
25
|
+
[types_1.ChainId.BSC]: 'https://speedy-nodes-nyc.moralis.io/5ed6053dc39eba789ff466c9/bsc/mainnet/archive',
|
|
26
|
+
[types_1.ChainId.POL]: 'https://speedy-nodes-nyc.moralis.io/5ed6053dc39eba789ff466c9/polygon/mainnet/archive',
|
|
27
|
+
[types_1.ChainId.FTM]: 'https://speedy-nodes-nyc.moralis.io/5ed6053dc39eba789ff466c9/fantom/mainnet',
|
|
28
|
+
};
|
|
29
|
+
// RPC Urls
|
|
30
|
+
const getRpcUrl = (chainId, archive = false) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
+
const rpcUrls = yield (0, exports.getRpcUrls)(chainId, archive);
|
|
32
|
+
return rpcUrls[0];
|
|
33
|
+
});
|
|
34
|
+
exports.getRpcUrl = getRpcUrl;
|
|
35
|
+
const getRpcUrls = (chainId, archive = false) => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
+
if (archive && archiveRpcs[chainId]) {
|
|
37
|
+
return [archiveRpcs[chainId]];
|
|
38
|
+
}
|
|
39
|
+
const configService = ConfigService_1.default.getInstance();
|
|
40
|
+
const config = yield configService.getConfigAsync();
|
|
41
|
+
return config.rpcs[chainId];
|
|
42
|
+
});
|
|
43
|
+
exports.getRpcUrls = getRpcUrls;
|
|
44
|
+
const getRandomProvider = (providerList) => {
|
|
45
|
+
const index = (0, _1.getRandomNumber)(0, providerList.length - 1);
|
|
46
|
+
return providerList[index];
|
|
47
|
+
};
|
|
48
|
+
// Provider
|
|
49
|
+
const getRpcProvider = (chainId, archive = false) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
if (archive && archiveRpcs[chainId]) {
|
|
51
|
+
// return archive PRC, but don't cache it
|
|
52
|
+
return new ethers_1.providers.FallbackProvider([
|
|
53
|
+
new ethers_1.providers.StaticJsonRpcProvider(yield (0, exports.getRpcUrl)(chainId, archive), chainId),
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
56
|
+
if (!chainProviders[chainId]) {
|
|
57
|
+
chainProviders[chainId] = [];
|
|
58
|
+
const urls = yield (0, exports.getRpcUrls)(chainId, archive);
|
|
59
|
+
urls.forEach((url) => {
|
|
60
|
+
chainProviders[chainId].push(new ethers_1.providers.FallbackProvider([
|
|
61
|
+
new ethers_1.providers.StaticJsonRpcProvider(url, chainId),
|
|
62
|
+
]));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (!chainProviders[chainId].length) {
|
|
66
|
+
throw new _1.ServerError(`Unable to configure provider for chain ${chainId}`);
|
|
67
|
+
}
|
|
68
|
+
return getRandomProvider(chainProviders[chainId]);
|
|
69
|
+
});
|
|
70
|
+
exports.getRpcProvider = getRpcProvider;
|
|
71
|
+
// Multicall
|
|
72
|
+
const getMulticallAddress = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
const configService = ConfigService_1.default.getInstance();
|
|
74
|
+
const config = yield configService.getConfigAsync();
|
|
75
|
+
return config.multicallAddresses[chainId];
|
|
76
|
+
});
|
|
77
|
+
exports.getMulticallAddress = getMulticallAddress;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Execution, InternalExecutionSettings, Process, ProcessType, Route, Status, Step, Token } from '../types';
|
|
2
|
+
interface Receipt {
|
|
3
|
+
fromAmount?: string;
|
|
4
|
+
toAmount?: string;
|
|
5
|
+
toToken?: Token;
|
|
6
|
+
gasUsed?: string;
|
|
7
|
+
gasPrice?: string;
|
|
8
|
+
}
|
|
9
|
+
declare type InternalUpdateRouteCallback = (route: Route) => void;
|
|
10
|
+
declare type OptionalParameters = Partial<Pick<Process, 'doneAt' | 'failedAt' | 'txHash' | 'txLink' | 'error' | 'substatus' | 'substatusMessage'>>;
|
|
11
|
+
/**
|
|
12
|
+
* Manages status updates of a route and provides various functions for tracking processes
|
|
13
|
+
* @param {Route} route The route this StatusManger belongs to.
|
|
14
|
+
* @param {InternalExecutionSettings} settings The ExecutionSettings for this route.
|
|
15
|
+
* @param {InternalUpdateRouteCallback} internalUpdateRouteCallback Internal callback to propage route changes.
|
|
16
|
+
* @return {StatusManager} An instance of StatusManager.
|
|
17
|
+
*/
|
|
18
|
+
export declare class StatusManager {
|
|
19
|
+
private readonly route;
|
|
20
|
+
private readonly settings;
|
|
21
|
+
private readonly internalUpdateRouteCallback;
|
|
22
|
+
private shouldUpdate;
|
|
23
|
+
constructor(route: Route, settings: InternalExecutionSettings, internalUpdateRouteCallback: InternalUpdateRouteCallback);
|
|
24
|
+
/**
|
|
25
|
+
* Initializes the execution object of a Step.
|
|
26
|
+
* @param {Step} step The current step in execution
|
|
27
|
+
* @return {Execution} The initialized execution object for this step and a function to update this step
|
|
28
|
+
*/
|
|
29
|
+
initExecutionObject: (step: Step) => Execution;
|
|
30
|
+
/**
|
|
31
|
+
* Updates the execution object of a Step.
|
|
32
|
+
* @param {Step} step The current step in execution
|
|
33
|
+
* @param {Status} status The status for the execution
|
|
34
|
+
* @param {Receipt} receipt Optional. Information about received tokens
|
|
35
|
+
* @return {Step} The step with the updated execution object
|
|
36
|
+
*/
|
|
37
|
+
updateExecution(step: Step, status: Status, receipt?: Receipt): Step;
|
|
38
|
+
/**
|
|
39
|
+
* Create and push a new process into the execution.
|
|
40
|
+
* @param {ProcessType} type Type of the process. Used to identify already existing processes.
|
|
41
|
+
* @param {Step} step The step that should contain the new process.
|
|
42
|
+
* @param {Status} status By default created procces is set to the STARTED status. We can override new process with the needed status.
|
|
43
|
+
* @return {Process}
|
|
44
|
+
*/
|
|
45
|
+
findOrCreateProcess: (type: ProcessType, step: Step, status?: Status) => Process;
|
|
46
|
+
/**
|
|
47
|
+
* Update a process object.
|
|
48
|
+
* @param {Step} step The step where the process should be updated
|
|
49
|
+
* @param {ProcessType} type The process type to update
|
|
50
|
+
* @param {Status} status The status the process gets.
|
|
51
|
+
* @param {object} [params] Additional parameters to append to the process.
|
|
52
|
+
* @return {Process} The update process
|
|
53
|
+
*/
|
|
54
|
+
updateProcess: (step: Step, type: ProcessType, status: Status, params?: OptionalParameters) => Process;
|
|
55
|
+
/**
|
|
56
|
+
* Remove a process from the execution
|
|
57
|
+
* @param {Step} step The step where the process should be removed from
|
|
58
|
+
* @param {ProcessType} type The process type to remove
|
|
59
|
+
* @return {void}
|
|
60
|
+
*/
|
|
61
|
+
removeProcess: (step: Step, type: ProcessType) => void;
|
|
62
|
+
updateStepInRoute: (step: Step) => Step;
|
|
63
|
+
setShouldUpdate(value: boolean): void;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatusManager = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const utils_1 = require("../utils/utils");
|
|
6
|
+
const utils_2 = require("./utils");
|
|
7
|
+
/**
|
|
8
|
+
* Manages status updates of a route and provides various functions for tracking processes
|
|
9
|
+
* @param {Route} route The route this StatusManger belongs to.
|
|
10
|
+
* @param {InternalExecutionSettings} settings The ExecutionSettings for this route.
|
|
11
|
+
* @param {InternalUpdateRouteCallback} internalUpdateRouteCallback Internal callback to propage route changes.
|
|
12
|
+
* @return {StatusManager} An instance of StatusManager.
|
|
13
|
+
*/
|
|
14
|
+
class StatusManager {
|
|
15
|
+
constructor(route, settings, internalUpdateRouteCallback) {
|
|
16
|
+
this.shouldUpdate = true;
|
|
17
|
+
/**
|
|
18
|
+
* Initializes the execution object of a Step.
|
|
19
|
+
* @param {Step} step The current step in execution
|
|
20
|
+
* @return {Execution} The initialized execution object for this step and a function to update this step
|
|
21
|
+
*/
|
|
22
|
+
this.initExecutionObject = (step) => {
|
|
23
|
+
const currentExecution = step.execution || (0, utils_1.deepClone)(types_1.emptyExecution);
|
|
24
|
+
if (!step.execution) {
|
|
25
|
+
step.execution = currentExecution;
|
|
26
|
+
step.execution.status = 'PENDING';
|
|
27
|
+
this.updateStepInRoute(step);
|
|
28
|
+
}
|
|
29
|
+
// Change status to PENDING after resuming from FAILED
|
|
30
|
+
if (currentExecution.status === 'FAILED') {
|
|
31
|
+
currentExecution.status = 'PENDING';
|
|
32
|
+
this.updateStepInRoute(step);
|
|
33
|
+
}
|
|
34
|
+
return currentExecution;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Create and push a new process into the execution.
|
|
38
|
+
* @param {ProcessType} type Type of the process. Used to identify already existing processes.
|
|
39
|
+
* @param {Step} step The step that should contain the new process.
|
|
40
|
+
* @param {Status} status By default created procces is set to the STARTED status. We can override new process with the needed status.
|
|
41
|
+
* @return {Process}
|
|
42
|
+
*/
|
|
43
|
+
this.findOrCreateProcess = (type, step, status) => {
|
|
44
|
+
if (!step.execution || !step.execution.process) {
|
|
45
|
+
throw new Error("Execution hasn't been initialized.");
|
|
46
|
+
}
|
|
47
|
+
const process = step.execution.process.find((p) => p.type === type);
|
|
48
|
+
if (process) {
|
|
49
|
+
return process;
|
|
50
|
+
}
|
|
51
|
+
const newProcess = {
|
|
52
|
+
type: type,
|
|
53
|
+
startedAt: Date.now(),
|
|
54
|
+
message: (0, utils_2.getProcessMessage)(type, status !== null && status !== void 0 ? status : 'STARTED'),
|
|
55
|
+
status: status !== null && status !== void 0 ? status : 'STARTED',
|
|
56
|
+
};
|
|
57
|
+
step.execution.process.push(newProcess);
|
|
58
|
+
this.updateStepInRoute(step);
|
|
59
|
+
return newProcess;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Update a process object.
|
|
63
|
+
* @param {Step} step The step where the process should be updated
|
|
64
|
+
* @param {ProcessType} type The process type to update
|
|
65
|
+
* @param {Status} status The status the process gets.
|
|
66
|
+
* @param {object} [params] Additional parameters to append to the process.
|
|
67
|
+
* @return {Process} The update process
|
|
68
|
+
*/
|
|
69
|
+
this.updateProcess = (step, type, status, params) => {
|
|
70
|
+
var _a;
|
|
71
|
+
if (!step.execution) {
|
|
72
|
+
throw new Error("Can't update an empty step execution.");
|
|
73
|
+
}
|
|
74
|
+
const currentProcess = (_a = step === null || step === void 0 ? void 0 : step.execution) === null || _a === void 0 ? void 0 : _a.process.find((p) => p.type === type);
|
|
75
|
+
if (!currentProcess) {
|
|
76
|
+
throw new Error("Can't find a process for the given type.");
|
|
77
|
+
}
|
|
78
|
+
switch (status) {
|
|
79
|
+
case 'CANCELLED':
|
|
80
|
+
currentProcess.doneAt = Date.now();
|
|
81
|
+
break;
|
|
82
|
+
case 'FAILED':
|
|
83
|
+
currentProcess.doneAt = Date.now();
|
|
84
|
+
step.execution.status = 'FAILED';
|
|
85
|
+
break;
|
|
86
|
+
case 'DONE':
|
|
87
|
+
currentProcess.doneAt = Date.now();
|
|
88
|
+
break;
|
|
89
|
+
case 'PENDING':
|
|
90
|
+
step.execution.status = 'PENDING';
|
|
91
|
+
break;
|
|
92
|
+
case 'ACTION_REQUIRED':
|
|
93
|
+
step.execution.status = 'ACTION_REQUIRED';
|
|
94
|
+
break;
|
|
95
|
+
case 'CHAIN_SWITCH_REQUIRED':
|
|
96
|
+
step.execution.status = 'CHAIN_SWITCH_REQUIRED';
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
currentProcess.status = status;
|
|
102
|
+
currentProcess.message = (0, utils_2.getProcessMessage)(type, status);
|
|
103
|
+
// set extra parameters or overwritte the standard params set in the switch statement
|
|
104
|
+
if (params) {
|
|
105
|
+
for (const [key, value] of Object.entries(params)) {
|
|
106
|
+
currentProcess[key] = value;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
this.updateStepInRoute(step); // updates the step in the route
|
|
110
|
+
return currentProcess;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Remove a process from the execution
|
|
114
|
+
* @param {Step} step The step where the process should be removed from
|
|
115
|
+
* @param {ProcessType} type The process type to remove
|
|
116
|
+
* @return {void}
|
|
117
|
+
*/
|
|
118
|
+
this.removeProcess = (step, type) => {
|
|
119
|
+
if (!step.execution) {
|
|
120
|
+
throw new Error("Execution hasn't been initialized.");
|
|
121
|
+
}
|
|
122
|
+
const index = step.execution.process.findIndex((p) => p.type === type);
|
|
123
|
+
step.execution.process.splice(index, 1);
|
|
124
|
+
this.updateStepInRoute(step);
|
|
125
|
+
};
|
|
126
|
+
this.updateStepInRoute = (step) => {
|
|
127
|
+
if (!this.shouldUpdate) {
|
|
128
|
+
return step;
|
|
129
|
+
}
|
|
130
|
+
const stepIndex = this.route.steps.findIndex((routeStep) => routeStep.id === step.id);
|
|
131
|
+
if (stepIndex === -1) {
|
|
132
|
+
throw new Error("Couldn't find a step to update.");
|
|
133
|
+
}
|
|
134
|
+
this.route.steps[stepIndex] = Object.assign(this.route.steps[stepIndex], step);
|
|
135
|
+
this.settings.updateCallback(this.route);
|
|
136
|
+
this.internalUpdateRouteCallback(this.route);
|
|
137
|
+
return this.route.steps[stepIndex];
|
|
138
|
+
};
|
|
139
|
+
this.route = route;
|
|
140
|
+
this.settings = settings;
|
|
141
|
+
this.internalUpdateRouteCallback = internalUpdateRouteCallback;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Updates the execution object of a Step.
|
|
145
|
+
* @param {Step} step The current step in execution
|
|
146
|
+
* @param {Status} status The status for the execution
|
|
147
|
+
* @param {Receipt} receipt Optional. Information about received tokens
|
|
148
|
+
* @return {Step} The step with the updated execution object
|
|
149
|
+
*/
|
|
150
|
+
updateExecution(step, status, receipt) {
|
|
151
|
+
if (!step.execution) {
|
|
152
|
+
throw Error("Can't update empty execution.");
|
|
153
|
+
}
|
|
154
|
+
step.execution.status = status;
|
|
155
|
+
if (receipt) {
|
|
156
|
+
step.execution.fromAmount = receipt.fromAmount;
|
|
157
|
+
step.execution.toAmount = receipt.toAmount;
|
|
158
|
+
step.execution.toToken = receipt.toToken;
|
|
159
|
+
}
|
|
160
|
+
this.updateStepInRoute(step);
|
|
161
|
+
return step;
|
|
162
|
+
}
|
|
163
|
+
setShouldUpdate(value) {
|
|
164
|
+
this.shouldUpdate = value;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.StatusManager = StatusManager;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Signer } from 'ethers';
|
|
2
|
+
import { HaltingSettings, InternalExecutionSettings, Step } from '../types';
|
|
3
|
+
import { StatusManager } from './StatusManager';
|
|
4
|
+
export declare class StepExecutor {
|
|
5
|
+
settings: InternalExecutionSettings;
|
|
6
|
+
statusManager: StatusManager;
|
|
7
|
+
private swapExecutionManager;
|
|
8
|
+
private bridgeExecutionManager;
|
|
9
|
+
executionStopped: boolean;
|
|
10
|
+
constructor(statusManager: StatusManager, settings: InternalExecutionSettings);
|
|
11
|
+
stopStepExecution: (settings?: HaltingSettings) => void;
|
|
12
|
+
executeStep: (signer: Signer, step: Step) => Promise<Step>;
|
|
13
|
+
private executeSwap;
|
|
14
|
+
private executeCross;
|
|
15
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.StepExecutor = void 0;
|
|
13
|
+
const bridge_execute_1 = require("./bridges/bridge.execute");
|
|
14
|
+
const swap_execute_1 = require("./exchanges/swap.execute");
|
|
15
|
+
const switchChain_1 = require("./switchChain");
|
|
16
|
+
const defaultExecutionHaltSettings = {
|
|
17
|
+
allowUpdates: true,
|
|
18
|
+
};
|
|
19
|
+
class StepExecutor {
|
|
20
|
+
constructor(statusManager, settings) {
|
|
21
|
+
this.swapExecutionManager = new swap_execute_1.SwapExecutionManager();
|
|
22
|
+
this.bridgeExecutionManager = new bridge_execute_1.BridgeExecutionManager();
|
|
23
|
+
this.executionStopped = false;
|
|
24
|
+
this.stopStepExecution = (settings) => {
|
|
25
|
+
const haltingSettings = Object.assign(Object.assign({}, defaultExecutionHaltSettings), settings);
|
|
26
|
+
this.swapExecutionManager.setShouldContinue(false);
|
|
27
|
+
this.bridgeExecutionManager.setShouldContinue(false);
|
|
28
|
+
this.statusManager.setShouldUpdate(haltingSettings.allowUpdates);
|
|
29
|
+
this.executionStopped = true;
|
|
30
|
+
};
|
|
31
|
+
this.executeStep = (signer, step) => __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
// check if signer is for correct chain
|
|
33
|
+
const updatedSigner = yield (0, switchChain_1.switchChain)(signer, this.statusManager, step, this.settings.switchChainHook, !this.executionStopped);
|
|
34
|
+
if (!updatedSigner) {
|
|
35
|
+
// chain switch was not successful, stop execution here
|
|
36
|
+
return step;
|
|
37
|
+
}
|
|
38
|
+
signer = updatedSigner;
|
|
39
|
+
switch (step.type) {
|
|
40
|
+
case 'lifi':
|
|
41
|
+
case 'cross':
|
|
42
|
+
yield this.executeCross(signer, step);
|
|
43
|
+
break;
|
|
44
|
+
case 'swap':
|
|
45
|
+
yield this.executeSwap(signer, step);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
throw new Error('Unsupported step type.');
|
|
49
|
+
}
|
|
50
|
+
return step;
|
|
51
|
+
});
|
|
52
|
+
this.executeSwap = (signer, step) => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
const swapParams = {
|
|
54
|
+
signer,
|
|
55
|
+
step,
|
|
56
|
+
settings: this.settings,
|
|
57
|
+
statusManager: this.statusManager,
|
|
58
|
+
};
|
|
59
|
+
return yield this.swapExecutionManager.execute(swapParams);
|
|
60
|
+
});
|
|
61
|
+
this.executeCross = (signer, step) => __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const crossParams = {
|
|
63
|
+
signer,
|
|
64
|
+
step,
|
|
65
|
+
settings: this.settings,
|
|
66
|
+
statusManager: this.statusManager,
|
|
67
|
+
};
|
|
68
|
+
return yield this.bridgeExecutionManager.execute(crossParams);
|
|
69
|
+
});
|
|
70
|
+
this.statusManager = statusManager;
|
|
71
|
+
this.settings = settings;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.StepExecutor = StepExecutor;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Signer } from 'ethers';
|
|
2
|
+
import { Chain, Step, Token } from '../types';
|
|
3
|
+
import { StatusManager } from './StatusManager';
|
|
4
|
+
export declare const checkAllowance: (signer: Signer, step: Step, chain: Chain, token: Token, amount: string, spenderAddress: string, statusManager: StatusManager, infiniteApproval?: boolean, allowUserInteraction?: boolean) => Promise<void>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.checkAllowance = void 0;
|
|
16
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
17
|
+
const ethers_1 = require("ethers");
|
|
18
|
+
const utils_1 = require("../allowance/utils");
|
|
19
|
+
const getProvider_1 = require("../utils/getProvider");
|
|
20
|
+
const parseError_1 = require("../utils/parseError");
|
|
21
|
+
const checkAllowance = (signer, step, chain, token, amount, spenderAddress, statusManager, infiniteApproval = false, allowUserInteraction = false
|
|
22
|
+
// eslint-disable-next-line max-params
|
|
23
|
+
) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
// Ask user to set allowance
|
|
25
|
+
// -> set currentExecution
|
|
26
|
+
let allowanceProcess = statusManager.findOrCreateProcess('TOKEN_ALLOWANCE', step);
|
|
27
|
+
// -> check allowance
|
|
28
|
+
try {
|
|
29
|
+
if (allowanceProcess.txHash) {
|
|
30
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'PENDING');
|
|
31
|
+
yield (0, getProvider_1.getProvider)(signer).waitForTransaction(allowanceProcess.txHash);
|
|
32
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
33
|
+
// TODO: Do we need this check?
|
|
34
|
+
}
|
|
35
|
+
else if (allowanceProcess.status === 'DONE') {
|
|
36
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const approved = yield (0, utils_1.getApproved)(signer, token.address, spenderAddress);
|
|
40
|
+
if (new bignumber_js_1.default(amount).gt(approved)) {
|
|
41
|
+
if (!allowUserInteraction) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const approvalAmount = infiniteApproval
|
|
45
|
+
? ethers_1.constants.MaxUint256.toString()
|
|
46
|
+
: amount;
|
|
47
|
+
const approveTx = yield (0, utils_1.setApproval)(signer, token.address, spenderAddress, approvalAmount);
|
|
48
|
+
// update currentExecution
|
|
49
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'PENDING', {
|
|
50
|
+
txHash: approveTx.hash,
|
|
51
|
+
txLink: chain.metamask.blockExplorerUrls[0] + 'tx/' + approveTx.hash,
|
|
52
|
+
});
|
|
53
|
+
// wait for transcation
|
|
54
|
+
yield approveTx.wait();
|
|
55
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
// -> set status
|
|
64
|
+
if (e.code === 'TRANSACTION_REPLACED' && e.replacement) {
|
|
65
|
+
yield transactionReplaced(e.replacement, allowanceProcess, step, chain, statusManager);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const error = yield (0, parseError_1.parseError)(e, step, allowanceProcess);
|
|
69
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'FAILED', {
|
|
70
|
+
error: {
|
|
71
|
+
message: error.message,
|
|
72
|
+
htmlMessage: error.htmlMessage,
|
|
73
|
+
code: error.code,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
statusManager.updateExecution(step, 'FAILED');
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
exports.checkAllowance = checkAllowance;
|
|
82
|
+
const transactionReplaced = (replacementTx, allowanceProcess, step, chain, statusManager) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
try {
|
|
84
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'PENDING', {
|
|
85
|
+
txHash: replacementTx.hash,
|
|
86
|
+
txLink: chain.metamask.blockExplorerUrls[0] + 'tx/' + replacementTx.hash,
|
|
87
|
+
});
|
|
88
|
+
yield replacementTx.wait();
|
|
89
|
+
allowanceProcess = statusManager.updateProcess(step, allowanceProcess.type, 'DONE');
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
if (e.code === 'TRANSACTION_REPLACED' && e.replacement) {
|
|
93
|
+
yield transactionReplaced(e.replacement, allowanceProcess, step, chain, statusManager);
|
|
94
|
+
}
|
|
95
|
+
throw e;
|
|
96
|
+
}
|
|
97
|
+
});
|