@xchainjs/xchain-thorchain-amm 0.8.21 → 1.0.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/lib/index.esm.js CHANGED
@@ -1,19 +1,19 @@
1
- import { Client as Client$9, defaultAvaxParams, AVAXChain } from '@xchainjs/xchain-avax';
2
- import { Client as Client$5, BNBChain } from '@xchainjs/xchain-binance';
3
- import { Client as Client$1, defaultBTCParams, BTCChain } from '@xchainjs/xchain-bitcoin';
4
- import { Client, defaultBchParams, BCHChain } from '@xchainjs/xchain-bitcoincash';
5
- import { Client as Client$a, defaultBscParams, BSCChain } from '@xchainjs/xchain-bsc';
6
- import { Protocol, FeeOption } from '@xchainjs/xchain-client';
7
- import { Client as Client$6, GAIAChain } from '@xchainjs/xchain-cosmos';
8
- import { Client as Client$2, defaultDogeParams, DOGEChain } from '@xchainjs/xchain-doge';
9
- import { Client as Client$8, defaultEthParams, ETHChain } from '@xchainjs/xchain-ethereum';
10
- import { Client as Client$3, defaultLtcParams, LTCChain } from '@xchainjs/xchain-litecoin';
11
- import { Client as Client$7, MAYAChain } from '@xchainjs/xchain-mayachain';
12
- import { Client as Client$4, THORChain } from '@xchainjs/xchain-thorchain';
13
- import { eqAsset, getContractAddressFromAsset, baseAmount, assetFromString } from '@xchainjs/xchain-util';
14
- import { abi, MAX_APPROVAL } from '@xchainjs/xchain-evm';
1
+ import { AssetAVAX, Client as Client$5, defaultAvaxParams } from '@xchainjs/xchain-avax';
2
+ import { AssetBNB, Client as Client$8 } from '@xchainjs/xchain-binance';
3
+ import { Client, defaultBTCParams } from '@xchainjs/xchain-bitcoin';
4
+ import { Client as Client$1, defaultBchParams } from '@xchainjs/xchain-bitcoincash';
5
+ import { AssetBSC, Client as Client$6, defaultBscParams } from '@xchainjs/xchain-bsc';
6
+ import { Protocol, Network } from '@xchainjs/xchain-client';
7
+ import { AssetATOM, Client as Client$7 } from '@xchainjs/xchain-cosmos';
8
+ import { Client as Client$3, defaultDogeParams } from '@xchainjs/xchain-doge';
9
+ import { AssetETH, Client as Client$4, defaultEthParams } from '@xchainjs/xchain-ethereum';
10
+ import { Client as Client$2, defaultLtcParams } from '@xchainjs/xchain-litecoin';
11
+ import { THORChain, Client as Client$9, defaultClientConfig } from '@xchainjs/xchain-thorchain';
12
+ import { ThorchainQuery, ThorchainCache, Thornode } from '@xchainjs/xchain-thorchain-query';
13
+ import { Wallet } from '@xchainjs/xchain-wallet';
14
+ import { abi } from '@xchainjs/xchain-evm';
15
+ import { getContractAddressFromAsset } from '@xchainjs/xchain-util';
15
16
  import { ethers } from 'ethers';
16
- import { ThorchainQuery } from '@xchainjs/xchain-thorchain-query';
17
17
 
18
18
  /******************************************************************************
19
19
  Copyright (c) Microsoft Corporation.
@@ -40,803 +40,128 @@ function __awaiter(thisArg, _arguments, P, generator) {
40
40
  });
41
41
  }
42
42
 
43
- const FIFTEEN_MIN_IN_SECS = 15 * 60;
44
- class EvmHelper {
45
- constructor(client, thorchainCache) {
46
- this.evmClient = client;
47
- this.client = client;
48
- this.thorchainCache = thorchainCache;
49
- }
50
- /**
51
- * Transaction to THORChain inbound address.
52
- *
53
- * @param {DepositParams} params The transaction options.
54
- * @returns {TxHash} The transaction hash.
55
- *
56
- * @throws {"halted chain"} Thrown if chain is halted.
57
- * @throws {"halted trading"} Thrown if trading is halted.
58
- * @throws {"amount is not approved"} Thrown if the amount is not allowed to spend
59
- * @throws {"router address is not defined"} Thrown if router address is not defined
60
- */
61
- sendDeposit(params) {
62
- return __awaiter(this, void 0, void 0, function* () {
63
- const inboundAsgard = (yield this.thorchainCache.getInboundDetails())[params.asset.chain];
64
- if (!(inboundAsgard === null || inboundAsgard === void 0 ? void 0 : inboundAsgard.router)) {
65
- throw new Error('router address is not defined');
66
- }
67
- if (!(inboundAsgard === null || inboundAsgard === void 0 ? void 0 : inboundAsgard.address)) {
68
- throw new Error('Vault address is not defined');
69
- }
70
- const address = yield this.client.getAddressAsync(params.walletIndex);
71
- const gasPrice = yield this.evmClient.estimateGasPrices(Protocol.THORCHAIN);
72
- if (eqAsset(params.asset, this.evmClient.config.gasAsset)) {
73
- // simple transfer
74
- return yield this.evmClient.transfer({
75
- walletIndex: params.walletIndex || 0,
76
- asset: params.asset,
77
- amount: params.amount,
78
- recipient: inboundAsgard.address,
79
- memo: params.memo,
80
- gasPrice: gasPrice.fast,
81
- });
82
- }
83
- else {
84
- //erc-20 must be depsited to the router
85
- const isApprovedResult = yield this.isTCRouterApprovedToSpend(params.asset, params.amount, params.walletIndex);
86
- if (!isApprovedResult) {
87
- throw new Error('The amount is not allowed to spend');
88
- }
89
- const contractAddress = getContractAddressFromAsset(params.asset);
90
- const checkSummedContractAddress = ethers.utils.getAddress(contractAddress);
91
- const latestBlockTimeUnixSecs = (yield this.evmClient.getProvider().getBlock('latest')).timestamp;
92
- const expiry = latestBlockTimeUnixSecs + FIFTEEN_MIN_IN_SECS;
93
- const depositParams = [
94
- inboundAsgard.address,
95
- checkSummedContractAddress,
96
- params.amount.amount().toFixed(),
97
- params.memo,
98
- expiry,
99
- ];
100
- const routerContract = new ethers.Contract(inboundAsgard.router, abi.router);
101
- const gasLimit = '160000';
102
- const unsignedTx = yield routerContract.populateTransaction.depositWithExpiry(...depositParams, {
103
- from: address,
104
- value: 0,
105
- gasPrice: gasPrice.fast.amount().toFixed(),
106
- gasLimit: gasLimit,
107
- });
108
- const { hash } = yield this.evmClient.getWallet(params.walletIndex).sendTransaction(unsignedTx);
109
- return hash;
110
- }
111
- });
112
- }
113
- isTCRouterApprovedToSpend(asset, amount, walletIndex = 0) {
114
- return __awaiter(this, void 0, void 0, function* () {
115
- const router = yield this.thorchainCache.getRouterAddressForChain(asset.chain);
116
- const contractAddress = getContractAddressFromAsset(asset);
117
- return yield this.evmClient.isApproved({
118
- amount: amount,
119
- spenderAddress: router,
120
- contractAddress,
121
- walletIndex: walletIndex,
122
- });
123
- });
124
- }
125
- approveTCRouterToSpend(asset, amount = MAX_APPROVAL, walletIndex = 0) {
126
- return __awaiter(this, void 0, void 0, function* () {
127
- const contractAddress = getContractAddressFromAsset(asset);
128
- const router = yield this.thorchainCache.getRouterAddressForChain(asset.chain);
129
- const decimals = yield this.thorchainCache.midgardQuery.getDecimalForAsset(asset);
130
- const approveParams = {
131
- contractAddress,
132
- spenderAddress: router,
133
- amount: baseAmount(amount.toString(), decimals),
134
- walletIndex,
135
- };
136
- return yield this.evmClient.approve(approveParams);
137
- });
138
- }
139
- }
140
-
141
43
  /**
142
- * Wallet Class for managing all xchain-* wallets with a mnemonic seed.
44
+ * Check if a chain is EVM and supported by the protocol
45
+ * @param {Chain} chain to check
46
+ * @returns true if chain is EVM, otherwise, false
143
47
  */
144
- class Wallet {
145
- /**
146
- * Contructor to create a Wallet
147
- *
148
- * @param phrase - mnemonic phrase
149
- * @param thorchainCache - an instance of the ThorchainCache (could be pointing to stagenet,testnet,mainnet)
150
- * @param chainConfigs - Config by chain
151
- * @returns Wallet
152
- */
153
- constructor(phrase, thorchainQuery, chainConfigs = {}) {
154
- this.thorchainQuery = thorchainQuery;
155
- const settings = { network: this.thorchainQuery.thorchainCache.midgardQuery.midgardCache.midgard.network, phrase };
156
- this.clients = {
157
- BCH: new Client(Object.assign(Object.assign(Object.assign({}, defaultBchParams), chainConfigs[BCHChain]), settings)),
158
- BTC: new Client$1(Object.assign(Object.assign(Object.assign({}, defaultBTCParams), chainConfigs[BTCChain]), settings)),
159
- DOGE: new Client$2(Object.assign(Object.assign(Object.assign({}, defaultDogeParams), chainConfigs[DOGEChain]), settings)),
160
- LTC: new Client$3(Object.assign(Object.assign(Object.assign({}, defaultLtcParams), chainConfigs[LTCChain]), settings)),
161
- THOR: new Client$4(Object.assign(Object.assign({}, chainConfigs[THORChain]), settings)),
162
- BNB: new Client$5(Object.assign(Object.assign({}, chainConfigs[BNBChain]), settings)),
163
- GAIA: new Client$6(Object.assign(Object.assign({}, chainConfigs[GAIAChain]), settings)),
164
- MAYA: new Client$7(Object.assign(Object.assign({}, chainConfigs[MAYAChain]), settings)),
165
- ETH: new Client$8(Object.assign(Object.assign(Object.assign({}, defaultEthParams), chainConfigs[ETHChain]), settings)),
166
- AVAX: new Client$9(Object.assign(Object.assign(Object.assign({}, defaultAvaxParams), chainConfigs[AVAXChain]), settings)),
167
- BSC: new Client$a(Object.assign(Object.assign(Object.assign({}, defaultBscParams), chainConfigs[BSCChain]), settings)),
168
- };
169
- this.evmHelpers = {
170
- ETH: new EvmHelper(this.clients.ETH, this.thorchainQuery.thorchainCache),
171
- BSC: new EvmHelper(this.clients.BSC, this.thorchainQuery.thorchainCache),
172
- AVAX: new EvmHelper(this.clients.AVAX, this.thorchainQuery.thorchainCache),
173
- };
174
- }
175
- /**
176
- * Fetch balances for all wallets
177
- *
178
- * @returns AllBalances[]
179
- */
180
- getAllBalances() {
181
- return __awaiter(this, void 0, void 0, function* () {
182
- const allBalances = [];
183
- for (const [chain, client] of Object.entries(this.clients)) {
184
- const address = yield client.getAddressAsync(0);
185
- try {
186
- const balances = yield client.getBalance(address);
187
- allBalances.push({ chain, address, balances });
188
- }
189
- catch (err) {
190
- allBalances.push({ chain, address, balances: err.message });
191
- }
192
- }
193
- return allBalances;
194
- });
195
- }
196
- /**
197
- * Executes a Swap from THORChainAMM.doSwap()
198
- *
199
- * @param swap object with all the required details for a swap.
200
- * @returns transaction details and explorer url
201
- * @see ThorchainAMM.doSwap()
202
- */
203
- executeSwap(swap) {
204
- return __awaiter(this, void 0, void 0, function* () {
205
- yield this.validateSwap(swap);
206
- if (swap.input.asset.chain === THORChain || swap.input.asset.synth) {
207
- return yield this.swapRuneTo(swap);
208
- }
209
- else {
210
- return yield this.swapNonRune(swap);
211
- }
212
- });
213
- }
214
- /** Validate swap object
215
- *
216
- * @param swap - swap parameters
217
- */
218
- validateSwap(swap) {
219
- return __awaiter(this, void 0, void 0, function* () {
220
- const errors = [];
221
- const isThorchainDestinationAsset = swap.destinationAsset.synth || swap.destinationAsset.chain === THORChain;
222
- const chain = isThorchainDestinationAsset ? THORChain : swap.destinationAsset.chain;
223
- // check address
224
- if (swap.destinationAddress && !this.clients[chain].validateAddress(swap.destinationAddress)) {
225
- errors.push(`destinationAddress ${swap.destinationAddress} is not a valid address`);
226
- }
227
- // Affiliate address should be THORName or THORAddress
228
- const checkAffiliateAddress = swap.memo.split(':');
229
- if (checkAffiliateAddress.length > 4) {
230
- const affiliateAddress = checkAffiliateAddress[4];
231
- if (affiliateAddress.length > 0) {
232
- const isValidThorchainAddress = this.clients[THORChain].validateAddress(affiliateAddress);
233
- const isValidThorname = this.isThorname(affiliateAddress);
234
- if (!(isValidThorchainAddress || isValidThorname))
235
- errors.push(`affiliateAddress ${affiliateAddress} is not a valid THOR address`);
236
- }
237
- }
238
- // if input == synth return errors.
239
- if (swap.input.asset.synth)
240
- return errors;
241
- if (this.isERC20Asset(swap.input.asset)) {
242
- const isApprovedResult = yield this.evmHelpers[swap.input.asset.chain].isTCRouterApprovedToSpend(swap.input.asset, swap.input.baseAmount, swap.walletIndex);
243
- if (!isApprovedResult) {
244
- errors.push('TC router has not been approved to spend this amount');
245
- }
246
- }
247
- return errors;
248
- });
249
- }
250
- isThorname(name) {
251
- return __awaiter(this, void 0, void 0, function* () {
252
- const thornameDetails = yield this.thorchainQuery.thorchainCache.midgardQuery.midgardCache.midgard.getTHORNameDetails(name); // Update when thorchainCache expose getTHORNameDetails method
253
- return thornameDetails !== undefined;
254
- });
255
- }
256
- /** Function handles all swaps from Rune to asset
257
- *
258
- * @param swap - swap parameters
259
- * @returns - tx submitted object
260
- */
261
- swapRuneTo(swap) {
262
- return __awaiter(this, void 0, void 0, function* () {
263
- const thorClient = this.clients.THOR;
264
- const hash = yield thorClient.deposit({
265
- amount: swap.input.baseAmount,
266
- asset: swap.input.asset,
267
- memo: swap.memo,
268
- });
269
- return { hash, url: this.clients.THOR.getExplorerTxUrl(hash) };
270
- });
271
- }
272
- /** Function handles all swaps from Non Rune
273
- *
274
- * @param swap - swap object
275
- * @returns - TxSubmitted object
276
- */
277
- swapNonRune(swap) {
278
- return __awaiter(this, void 0, void 0, function* () {
279
- const client = this.clients[swap.input.asset.chain];
280
- const inbound = (yield this.thorchainQuery.thorchainCache.getInboundDetails())[swap.input.asset.chain];
281
- if (!(inbound === null || inbound === void 0 ? void 0 : inbound.address))
282
- throw Error(`no asgard address found for ${swap.input.asset.chain}`);
283
- if (this.isEVMChain(swap.input.asset)) {
284
- const params = {
285
- walletIndex: 0,
286
- asset: swap.input.asset,
287
- amount: swap.input.baseAmount,
288
- feeOption: swap.feeOption || FeeOption.Fast,
289
- memo: swap.memo,
290
- };
291
- const hash = yield this.evmHelpers[swap.input.asset.chain].sendDeposit(params);
292
- return { hash, url: client.getExplorerTxUrl(hash) };
293
- }
294
- else {
295
- const params = {
296
- walletIndex: 0,
297
- asset: swap.input.asset,
298
- amount: swap.input.baseAmount,
299
- recipient: inbound.address,
300
- memo: swap.memo,
301
- };
302
- const hash = yield client.transfer(params);
303
- return { hash, url: client.getExplorerTxUrl(hash) };
304
- }
305
- });
306
- }
307
- /** Function handles liquidity Add
308
- * BASED OFF https://dev.thorchain.or›g/thorchain-dev/network/memos
309
- * @param params input parameters needed to add liquidity
310
- * @returns transaction details submitted
311
- */
312
- addLiquidity(params) {
313
- return __awaiter(this, void 0, void 0, function* () {
314
- const assetClient = this.clients[params.asset.asset.chain];
315
- const inboundAsgard = (yield this.thorchainQuery.thorchainCache.getInboundDetails())[params.asset.asset.chain]
316
- .address;
317
- const thorchainClient = this.clients[params.rune.asset.chain];
318
- const addressRune = yield thorchainClient.getAddressAsync();
319
- const addressAsset = yield assetClient.getAddressAsync();
320
- // const waitTimeSeconds = params.waitTimeSeconds
321
- let constructedMemo = '';
322
- const txSubmitted = [];
323
- // symmetrical add
324
- if (params.asset.assetAmount.gt(0) && params.rune.assetAmount.gt(0)) {
325
- constructedMemo = `+:${params.assetPool}:${addressRune}`;
326
- txSubmitted.push(yield this.addAssetLP(params, constructedMemo, assetClient, inboundAsgard));
327
- constructedMemo = `+:${params.assetPool}:${addressAsset}`;
328
- txSubmitted.push(yield this.addRuneLP(params, constructedMemo, thorchainClient));
329
- return txSubmitted;
330
- }
331
- else if (params.asset.assetAmount.gt(0) && params.rune.assetAmount.eq(0)) {
332
- // asymmetrical asset only
333
- constructedMemo = `+:${params.assetPool}`;
334
- txSubmitted.push(yield this.addAssetLP(params, constructedMemo, assetClient, inboundAsgard));
335
- return txSubmitted;
336
- }
337
- else {
338
- // asymmetrical rune only
339
- constructedMemo = `+:${params.assetPool}`;
340
- txSubmitted.push(yield this.addRuneLP(params, constructedMemo, thorchainClient));
341
- return txSubmitted;
342
- }
343
- });
344
- }
345
- /** Function handles liquidity Withdraw
346
- *
347
- * @param params - parameters required for liquidity position
348
- * @returns object with tx response, url and wait time in seconds
349
- */
350
- withdrawLiquidity(params) {
351
- return __awaiter(this, void 0, void 0, function* () {
352
- const assetClient = this.clients[params.assetFee.asset.chain];
353
- const inboundAsgard = (yield this.thorchainQuery.thorchainCache.getInboundDetails())[params.assetFee.asset.chain]
354
- .address;
355
- // const waitTimeSeconds = params.waitTimeSeconds
356
- const thorchainClient = this.clients[params.runeFee.asset.chain];
357
- const basisPoints = (params.percentage * 100).toFixed(); // convert to basis points
358
- let constructedMemo = '';
359
- const txSubmitted = [];
360
- if (params.assetAddress && params.runeAddress) {
361
- constructedMemo = `-:${params.assetPool}:${basisPoints}`;
362
- txSubmitted.push(yield this.withdrawAssetLP(params, constructedMemo, assetClient, inboundAsgard));
363
- constructedMemo = `-:${params.assetPool}:${basisPoints}`;
364
- txSubmitted.push(yield this.withdrawRuneLP(params, constructedMemo, thorchainClient));
365
- return txSubmitted;
366
- }
367
- else if (params.assetAddress && !params.runeAddress) {
368
- // asymmetrical asset only
369
- constructedMemo = `-:${params.assetPool}:${basisPoints}`;
370
- txSubmitted.push(yield this.withdrawAssetLP(params, constructedMemo, assetClient, inboundAsgard));
371
- return txSubmitted;
372
- }
373
- else {
374
- // asymmetrical rune only
375
- constructedMemo = `-:${params.assetPool}:${basisPoints}`;
376
- txSubmitted.push(yield this.withdrawRuneLP(params, constructedMemo, thorchainClient));
377
- return txSubmitted;
378
- }
379
- });
380
- }
381
- /**
382
- *
383
- * @param assetAmount - amount to add
384
- * @param memo - memo required
385
- * @param waitTimeSeconds - expected wait for the transaction to be processed
386
- * @returns
387
- */
388
- addSavers(assetAmount, memo, toAddress) {
389
- return __awaiter(this, void 0, void 0, function* () {
390
- const assetClient = this.clients[assetAmount.asset.chain];
391
- if (this.isEVMChain(assetAmount.asset)) {
392
- const addParams = {
393
- wallIndex: 0,
394
- asset: assetAmount.asset,
395
- amount: assetAmount.baseAmount,
396
- feeOption: FeeOption.Fast,
397
- memo: memo,
398
- };
399
- const evmHelper = new EvmHelper(assetClient, this.thorchainQuery.thorchainCache);
400
- const hash = yield evmHelper.sendDeposit(addParams);
401
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
402
- }
403
- else if (this.isUTXOChain(assetAmount.asset)) {
404
- const feeRates = yield assetClient.getFeeRates(Protocol.THORCHAIN);
405
- const addParams = {
406
- wallIndex: 0,
407
- asset: assetAmount.asset,
408
- amount: assetAmount.baseAmount,
409
- recipient: toAddress,
410
- memo: memo,
411
- feeRate: feeRates.fast,
412
- };
413
- try {
414
- const hash = yield assetClient.transfer(addParams);
415
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
416
- }
417
- catch (err) {
418
- const hash = JSON.stringify(err);
419
- return { hash, url: assetClient.getExplorerAddressUrl(assetClient.getAddress()) };
420
- }
421
- }
422
- else {
423
- const addParams = {
424
- wallIndex: 0,
425
- asset: assetAmount.asset,
426
- amount: assetAmount.baseAmount,
427
- recipient: toAddress,
428
- memo: memo,
429
- };
430
- try {
431
- const hash = yield assetClient.transfer(addParams);
432
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
433
- }
434
- catch (err) {
435
- const hash = JSON.stringify(err);
436
- return { hash, url: assetClient.getExplorerAddressUrl(assetClient.getAddress()) };
437
- }
438
- }
439
- });
440
- }
441
- /**
442
- *
443
- * @param assetAmount - amount to withdraw
444
- * @param memo - memo required
445
- * @param waitTimeSeconds - expected wait for the transaction to be processed
446
- * @returns
447
- */
448
- withdrawSavers(assetAmount, memo, toAddress) {
48
+ const isProtocolEVMChain = (chain) => {
49
+ return [AssetETH.chain, AssetBSC.chain, AssetAVAX.chain].includes(chain);
50
+ };
51
+ /**
52
+ * Check if asset is ERC20
53
+ * @param {Asset} asset to check
54
+ * @returns true if asset is ERC20, otherwise, false
55
+ */
56
+ const isProtocolERC20Asset = (asset) => {
57
+ return isProtocolEVMChain(asset.chain)
58
+ ? ![AssetETH.symbol, AssetAVAX.symbol, AssetBSC.symbol].includes(asset.symbol)
59
+ : false;
60
+ };
61
+ /**
62
+ * Check if a chain is EVM and supported by the protocol
63
+ * @param {Chain} chain to check
64
+ * @returns true if chain is EVM, otherwise, false
65
+ */
66
+ const isProtocolBFTChain = (chain) => {
67
+ return [AssetBNB.chain, AssetATOM.chain].includes(chain);
68
+ };
69
+
70
+ class ThorchainAction {
71
+ static makeAction(actionParams) {
449
72
  return __awaiter(this, void 0, void 0, function* () {
450
- const assetClient = this.clients[assetAmount.asset.chain];
451
- if (this.isEVMChain(assetAmount.asset)) {
452
- const addParams = {
453
- wallIndex: 0,
454
- asset: assetAmount.asset,
455
- amount: assetAmount.baseAmount,
456
- feeOption: FeeOption.Fast,
457
- memo: memo,
458
- };
459
- const evmHelper = new EvmHelper(assetClient, this.thorchainQuery.thorchainCache);
460
- const hash = yield evmHelper.sendDeposit(addParams);
461
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
462
- }
463
- else if (this.isUTXOChain(assetAmount.asset)) {
464
- const feeRates = yield assetClient.getFeeRates(Protocol.THORCHAIN);
465
- const addParams = {
466
- wallIndex: 0,
467
- asset: assetAmount.asset,
468
- amount: assetAmount.baseAmount,
469
- recipient: toAddress,
470
- memo: memo,
471
- feeRate: feeRates.fast,
472
- };
473
- try {
474
- const hash = yield assetClient.transfer(addParams);
475
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
476
- }
477
- catch (err) {
478
- const hash = JSON.stringify(err);
479
- return { hash, url: yield assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
480
- }
481
- }
482
- else {
483
- const addParams = {
484
- wallIndex: 0,
485
- asset: assetAmount.asset,
486
- amount: assetAmount.baseAmount,
487
- recipient: toAddress,
488
- memo: memo,
489
- };
490
- try {
491
- const hash = yield assetClient.transfer(addParams);
492
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
493
- }
494
- catch (err) {
495
- const hash = JSON.stringify(err);
496
- return { hash, url: yield assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
497
- }
498
- }
73
+ return this.isNonProtocolParams(actionParams)
74
+ ? this.makeNonProtocolAction(actionParams)
75
+ : this.makeProtocolAction(actionParams);
499
76
  });
500
77
  }
501
- loanOpen(params) {
78
+ static makeProtocolAction({ wallet, assetAmount, memo }) {
502
79
  return __awaiter(this, void 0, void 0, function* () {
503
- const assetClient = this.clients[params.amount.asset.chain];
504
- if (this.isEVMChain(params.amount.asset)) {
505
- const addParams = {
506
- wallIndex: 0,
507
- asset: params.amount.asset,
508
- amount: params.amount.baseAmount,
509
- feeOption: FeeOption.Fast,
510
- memo: params.memo,
511
- };
512
- const evmHelper = new EvmHelper(assetClient, this.thorchainQuery.thorchainCache);
513
- const hash = yield evmHelper.sendDeposit(addParams);
514
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
515
- }
516
- else if (this.isUTXOChain(params.amount.asset)) {
517
- const feeRates = yield assetClient.getFeeRates(Protocol.THORCHAIN);
518
- const addParams = {
519
- wallIndex: 0,
520
- asset: params.amount.asset,
521
- amount: params.amount.baseAmount,
522
- recipient: params.toAddress,
523
- memo: params.memo,
524
- feeRate: feeRates.fast,
525
- };
526
- try {
527
- const hash = yield assetClient.transfer(addParams);
528
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
529
- }
530
- catch (err) {
531
- const hash = JSON.stringify(err);
532
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
533
- }
534
- }
535
- else {
536
- const addParams = {
537
- wallIndex: 0,
538
- asset: params.amount.asset,
539
- amount: params.amount.baseAmount,
540
- recipient: params.toAddress,
541
- memo: params.memo,
542
- };
543
- try {
544
- const hash = yield assetClient.transfer(addParams);
545
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
546
- }
547
- catch (err) {
548
- const hash = JSON.stringify(err);
549
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
550
- }
551
- }
80
+ const hash = yield wallet.deposit({ asset: assetAmount.asset, amount: assetAmount.baseAmount, memo });
81
+ return {
82
+ hash,
83
+ url: yield wallet.getExplorerTxUrl(assetAmount.asset.chain, hash),
84
+ };
552
85
  });
553
86
  }
554
- loanClose(params) {
555
- return __awaiter(this, void 0, void 0, function* () {
556
- const assetClient = this.clients[params.amount.asset.chain];
557
- if (this.isEVMChain(params.amount.asset)) {
558
- const addParams = {
559
- wallIndex: 0,
560
- asset: params.amount.asset,
561
- amount: params.amount.baseAmount,
562
- feeOption: FeeOption.Fast,
563
- memo: params.memo,
564
- };
565
- const evmHelper = new EvmHelper(assetClient, this.thorchainQuery.thorchainCache);
566
- const hash = yield evmHelper.sendDeposit(addParams);
567
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
568
- }
569
- else if (this.isUTXOChain(params.amount.asset)) {
570
- const feeRates = yield assetClient.getFeeRates(Protocol.THORCHAIN);
571
- const addParams = {
572
- wallIndex: 0,
573
- asset: params.amount.asset,
574
- amount: params.amount.baseAmount,
575
- recipient: params.toAddress,
576
- memo: params.memo,
577
- feeRate: feeRates.average,
578
- };
579
- try {
580
- const hash = yield assetClient.transfer(addParams);
581
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
582
- }
583
- catch (err) {
584
- const hash = JSON.stringify(err);
585
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
87
+ static makeNonProtocolAction({ wallet, assetAmount, recipient, memo, }) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ // Non ERC20 swaps
90
+ if (!isProtocolERC20Asset(assetAmount.asset)) {
91
+ if (isProtocolBFTChain(assetAmount.asset.chain)) {
92
+ const hash = yield wallet.transfer({
93
+ asset: assetAmount.asset,
94
+ amount: assetAmount.baseAmount,
95
+ recipient,
96
+ memo,
97
+ });
98
+ return {
99
+ hash,
100
+ url: yield wallet.getExplorerTxUrl(assetAmount.asset.chain, hash),
101
+ };
586
102
  }
587
- }
588
- else {
589
- const addParams = {
590
- wallIndex: 0,
591
- asset: params.amount.asset,
592
- amount: params.amount.baseAmount,
593
- recipient: params.toAddress,
594
- memo: params.memo,
103
+ const feeRates = yield wallet.getFeeRates(assetAmount.asset.chain, Protocol.THORCHAIN);
104
+ const hash = yield wallet.transfer(isProtocolEVMChain(assetAmount.asset.chain)
105
+ ? {
106
+ asset: assetAmount.asset,
107
+ amount: assetAmount.baseAmount,
108
+ recipient,
109
+ memo,
110
+ gasPrice: feeRates.fast,
111
+ }
112
+ : {
113
+ asset: assetAmount.asset,
114
+ amount: assetAmount.baseAmount,
115
+ recipient,
116
+ memo,
117
+ feeRate: feeRates.fast,
118
+ });
119
+ return {
120
+ hash,
121
+ url: yield wallet.getExplorerTxUrl(assetAmount.asset.chain, hash),
595
122
  };
596
- try {
597
- const hash = yield assetClient.transfer(addParams);
598
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
599
- }
600
- catch (err) {
601
- const hash = JSON.stringify(err);
602
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
603
- }
604
- }
605
- });
606
- }
607
- /**
608
- * Register a THORName with a default expirity of one year. By default chain and chainAddress is getting from wallet instance and is BTC.
609
- * By default owner is getting from wallet
610
- * @param thorname - Name to register
611
- * @param chain - Chain to add alias
612
- * @param chainAddress - Address to add to chain alias
613
- * @param owner - Owner address (rune address)
614
- * @param preferredAsset - referred asset
615
- * @param expirity - expirity of the domain in MILLISECONDS
616
- * @param isUpdate - true only if the domain is already register and you want to update its data
617
- * @returns memo and value of deposit
618
- */
619
- registerThorname(params) {
620
- return __awaiter(this, void 0, void 0, function* () {
621
- const chainClient = this.clients[params.chain || BTCChain];
622
- const thorClient = this.clients.THOR;
623
- if (!chainClient || !thorClient) {
624
- throw Error('Can not find a wallet client');
625
123
  }
626
- const thornameEstimation = yield this.thorchainQuery.estimateThorname(Object.assign(Object.assign({}, params), { chain: params.chain || BTCChain, chainAddress: params.chainAddress || (yield chainClient.getAddressAsync()), owner: params.owner || (yield thorClient.getAddressAsync()) }));
627
- const castedThorClient = thorClient;
628
- const result = yield castedThorClient.deposit({
629
- asset: thornameEstimation.value.asset,
630
- amount: thornameEstimation.value.baseAmount,
631
- memo: thornameEstimation.memo,
124
+ // ERC20 swaps
125
+ const thorchainQuery = new ThorchainQuery(new ThorchainCache(new Thornode(wallet.getNetwork())));
126
+ const inboundDetails = yield thorchainQuery.getChainInboundDetails(assetAmount.asset.chain);
127
+ if (!inboundDetails.router)
128
+ throw Error(`Unknown router for ${assetAmount.asset.chain} chain`);
129
+ const contractAddress = getContractAddressFromAsset(assetAmount.asset);
130
+ const checkSummedContractAddress = ethers.utils.getAddress(contractAddress);
131
+ const expiration = Math.floor(new Date(new Date().getTime() + 15 * 60000).getTime() / 1000);
132
+ const depositParams = [
133
+ recipient,
134
+ checkSummedContractAddress,
135
+ assetAmount.baseAmount.amount().toFixed(),
136
+ memo,
137
+ expiration,
138
+ ];
139
+ const routerContract = new ethers.Contract(inboundDetails.router, abi.router);
140
+ const chainWallet = wallet.getChainWallet(assetAmount.asset.chain);
141
+ const gasPrices = yield wallet.getFeeRates(assetAmount.asset.chain);
142
+ const unsignedTx = yield routerContract.populateTransaction.depositWithExpiry(...depositParams, {
143
+ from: wallet.getAddress(assetAmount.asset.chain),
144
+ value: 0,
145
+ gasPrice: gasPrices.fast.amount().toFixed(),
146
+ gasLimit: '160000',
632
147
  });
633
- return result;
634
- });
635
- }
636
- /**
637
- * Register a THORName with a default expirity of one year. By default chain and chainAddress is getting from wallet instance and is BTC.
638
- * By default owner is getting from wallet
639
- * @param thorname - Name to register
640
- * @param chain - Chain to add alias
641
- * @param chainAddress - Address to add to chain alias
642
- * @param owner - Owner address (rune address)
643
- * @param preferredAsset - referred asset
644
- * @param expirity - expirity of the domain in MILLISECONDS
645
- * @returns memo and value of deposit
646
- */
647
- updateThorname(params) {
648
- return __awaiter(this, void 0, void 0, function* () {
649
- const chainClient = this.clients[params.chain || BTCChain];
650
- const thorClient = this.clients.THOR;
651
- if (!chainClient || !thorClient) {
652
- throw Error('Can not find a wallet client');
653
- }
654
- const thornameDetail = yield this.thorchainQuery.getThornameDetails(params.thorname);
655
- if ((thornameDetail === null || thornameDetail === void 0 ? void 0 : thornameDetail.owner) !== (yield thorClient.getAddressAsync())) {
656
- throw Error('You cannot update a domain that is not yours');
657
- }
658
- const thornameEstimation = yield this.thorchainQuery.estimateThorname(Object.assign(Object.assign({}, params), { chain: params.chain || BTCChain, isUpdate: true, preferredAsset: params.preferredAsset || assetFromString(thornameDetail.preferredAsset), chainAddress: params.chainAddress || (yield chainClient.getAddressAsync()) }));
659
- const castedThorClient = thorClient;
660
- const result = yield castedThorClient.deposit({
661
- asset: thornameEstimation.value.asset,
662
- amount: thornameEstimation.value.baseAmount,
663
- memo: thornameEstimation.memo,
664
- });
665
- return result;
666
- });
667
- }
668
- /** Function handles liquidity add for all non rune assets
669
- *
670
- * @param params - parameters for add liquidity
671
- * @param constructedMemo - memo needed for thorchain
672
- * @param waitTimeSeconds - wait time for the tx to be confirmed
673
- * @param assetClient - passing XchainClient
674
- * @param inboundAsgard - inbound Asgard address for the LP
675
- * @returns - tx object
676
- */
677
- addAssetLP(params, constructedMemo, assetClient, inboundAsgard) {
678
- return __awaiter(this, void 0, void 0, function* () {
679
- if (this.isEVMChain(params.asset.asset)) {
680
- const addParams = {
681
- wallIndex: 0,
682
- asset: params.asset.asset,
683
- amount: params.asset.baseAmount,
684
- feeOption: FeeOption.Fast,
685
- memo: constructedMemo,
686
- };
687
- const evmHelper = new EvmHelper(assetClient, this.thorchainQuery.thorchainCache);
688
- const hash = yield evmHelper.sendDeposit(addParams);
689
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
690
- }
691
- else if (this.isUTXOChain(params.asset.asset)) {
692
- const feeRates = yield assetClient.getFeeRates(Protocol.THORCHAIN);
693
- const addParams = {
694
- wallIndex: 0,
695
- asset: params.asset.asset,
696
- amount: params.asset.baseAmount,
697
- recipient: inboundAsgard,
698
- memo: constructedMemo,
699
- feeRate: feeRates.fast,
700
- };
701
- try {
702
- const hash = yield assetClient.transfer(addParams);
703
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
704
- }
705
- catch (err) {
706
- const hash = JSON.stringify(err);
707
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
708
- }
709
- }
710
- else {
711
- const addParams = {
712
- wallIndex: 0,
713
- asset: params.asset.asset,
714
- amount: params.asset.baseAmount,
715
- recipient: inboundAsgard,
716
- memo: constructedMemo,
717
- };
718
- try {
719
- const hash = yield assetClient.transfer(addParams);
720
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
721
- }
722
- catch (err) {
723
- const hash = JSON.stringify(err);
724
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
725
- }
726
- }
727
- });
728
- }
729
- /** Function handles liquidity Withdraw for Non rune assets
730
- *
731
- * @param params - parameters for withdraw liquidity
732
- * @param constructedMemo - memo needed for thorchain execution
733
- * @param assetClient - asset client to call transfer
734
- * @param waitTimeSeconds - return back estimated wait
735
- * @param inboundAsgard - destination address
736
- * @returns - tx object
737
- */
738
- withdrawAssetLP(params, constructedMemo, assetClient, inboundAsgard) {
739
- return __awaiter(this, void 0, void 0, function* () {
740
- if (this.isEVMChain(params.assetFee.asset)) {
741
- const withdrawParams = {
742
- wallIndex: 0,
743
- asset: params.assetFee.asset,
744
- amount: params.assetFee.baseAmount,
745
- feeOption: FeeOption.Fast,
746
- memo: constructedMemo,
747
- };
748
- const evmHelper = new EvmHelper(assetClient, this.thorchainQuery.thorchainCache);
749
- const hash = yield evmHelper.sendDeposit(withdrawParams);
750
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
751
- }
752
- else if (this.isUTXOChain(params.assetFee.asset)) {
753
- const feeRates = yield assetClient.getFeeRates(Protocol.THORCHAIN);
754
- const withdrawParams = {
755
- wallIndex: 0,
756
- asset: params.assetFee.asset,
757
- amount: params.assetFee.baseAmount,
758
- recipient: inboundAsgard,
759
- memo: constructedMemo,
760
- feeRate: feeRates.fast,
761
- };
762
- try {
763
- const hash = yield assetClient.transfer(withdrawParams);
764
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
765
- }
766
- catch (err) {
767
- const hash = JSON.stringify(err);
768
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
769
- }
770
- }
771
- else {
772
- const withdrawParams = {
773
- wallIndex: 0,
774
- asset: params.assetFee.asset,
775
- amount: params.assetFee.baseAmount,
776
- recipient: inboundAsgard,
777
- memo: constructedMemo,
778
- };
779
- try {
780
- const hash = yield assetClient.transfer(withdrawParams);
781
- return { hash, url: assetClient.getExplorerTxUrl(hash) };
782
- }
783
- catch (err) {
784
- const hash = JSON.stringify(err);
785
- return { hash, url: assetClient.getExplorerAddressUrl(yield assetClient.getAddressAsync()) };
786
- }
787
- }
788
- });
789
- }
790
- /** Function handles liquidity Add for Rune only
791
- *
792
- * @param params - deposit parameters
793
- * @param memo - memo needed to withdraw lp
794
- * @returns - tx object
795
- */
796
- addRuneLP(params, memo, thorchainClient) {
797
- return __awaiter(this, void 0, void 0, function* () {
798
- const thorClient = this.clients.THOR;
799
- const addParams = {
800
- asset: params.rune.asset,
801
- amount: params.rune.baseAmount,
802
- memo: memo,
803
- };
804
- const hash = yield thorClient.deposit(addParams);
805
- return { hash, url: thorchainClient.getExplorerTxUrl(hash) };
806
- });
807
- }
808
- /** Function handles liquidity Withdraw for Rune only
809
- *
810
- * @param params - withdraw parameters
811
- * @param memo - memo needed to withdraw lp
812
- * @returns - tx object
813
- */
814
- withdrawRuneLP(params, memo, thorchainClient) {
815
- return __awaiter(this, void 0, void 0, function* () {
816
- const thorClient = this.clients.THOR;
817
- const addParams = {
818
- asset: params.runeFee.asset,
819
- amount: params.runeFee.baseAmount,
820
- memo: memo,
148
+ const { hash } = yield chainWallet.sendTransaction(unsignedTx);
149
+ return {
150
+ hash,
151
+ url: yield wallet.getExplorerTxUrl(assetAmount.asset.chain, hash),
821
152
  };
822
- const hash = yield thorClient.deposit(addParams);
823
- return { hash, url: thorchainClient.getExplorerTxUrl(hash) };
824
153
  });
825
154
  }
826
- isERC20Asset(asset) {
827
- const isGasAsset = ['ETH', 'BSC', 'AVAX'].includes(asset.symbol);
828
- return this.isEVMChain(asset) && !isGasAsset;
829
- }
830
- isEVMChain(asset) {
831
- const isEvmChain = ['ETH', 'BSC', 'AVAX'].includes(asset.chain);
832
- return isEvmChain;
833
- }
834
- isUTXOChain(asset) {
835
- return ['BTC', 'BCH', 'DOGE'].includes(asset.chain);
155
+ static isNonProtocolParams(params) {
156
+ if ((params.assetAmount.asset.chain === THORChain || params.assetAmount.asset.synth) &&
157
+ 'address' in params &&
158
+ !!params.address) {
159
+ throw Error('Inconsistent params. Native actions do not support recipient');
160
+ }
161
+ return params.assetAmount.asset.chain !== THORChain && !params.assetAmount.asset.synth;
836
162
  }
837
163
  }
838
164
 
839
- const defaultQuery = new ThorchainQuery();
840
165
  /**
841
166
  * THORChain Class for interacting with THORChain.
842
167
  * Recommended main class to use for swapping with THORChain
@@ -844,79 +169,144 @@ const defaultQuery = new ThorchainQuery();
844
169
  */
845
170
  class ThorchainAMM {
846
171
  /**
847
- * Contructor to create a ThorchainAMM
172
+ * Constructor to create a ThorchainAMM instance
848
173
  *
849
174
  * @param thorchainQuery - an instance of the ThorchainQuery
850
175
  * @returns ThorchainAMM
851
176
  */
852
- constructor(thorchainQuery = defaultQuery) {
177
+ constructor(thorchainQuery = new ThorchainQuery(), wallet = new Wallet({
178
+ BTC: new Client(Object.assign(Object.assign({}, defaultBTCParams), { network: Network.Mainnet })),
179
+ BCH: new Client$1(Object.assign(Object.assign({}, defaultBchParams), { network: Network.Mainnet })),
180
+ LTC: new Client$2(Object.assign(Object.assign({}, defaultLtcParams), { network: Network.Mainnet })),
181
+ DOGE: new Client$3(Object.assign(Object.assign({}, defaultDogeParams), { network: Network.Mainnet })),
182
+ ETH: new Client$4(Object.assign(Object.assign({}, defaultEthParams), { network: Network.Mainnet })),
183
+ AVAX: new Client$5(Object.assign(Object.assign({}, defaultAvaxParams), { network: Network.Mainnet })),
184
+ BSC: new Client$6(Object.assign(Object.assign({}, defaultBscParams), { network: Network.Mainnet })),
185
+ GAIA: new Client$7({ network: Network.Mainnet }),
186
+ BNB: new Client$8({ network: Network.Mainnet }),
187
+ THOR: new Client$9(Object.assign(Object.assign({}, defaultClientConfig), { network: Network.Mainnet })),
188
+ })) {
853
189
  this.thorchainQuery = thorchainQuery;
190
+ this.wallet = wallet;
854
191
  }
855
192
  /**
856
- * Provides a swap estimate for the given swap detail. Will check the params for errors before trying to get the estimate.
857
- * Uses current pool data, works out inbound and outboud fee, affiliate fees and works out the expected wait time for the swap (in and out)
858
- *
859
- * @param params - amount to swap
193
+ * * Provides an estimate for a swap based on the given swap details.
194
+ * Checks the parameters for errors before attempting to retrieve the estimate.
195
+ * Utilizes current pool data to calculate inbound and outbound fees, affiliate fees,
196
+ * and the expected wait time for the swap (inbound and outbound).
197
+ * @param params Parameters for the swap, including the amount to swap.
860
198
 
861
- * @returns The SwapEstimate
199
+ * @returns The estimated swap details.
862
200
  */
863
- estimateSwap({ fromAsset, amount, destinationAsset, destinationAddress, affiliateAddress = '', interfaceID = `555`, affiliateBps = 0, toleranceBps, wallet, walletIndex, }) {
201
+ estimateSwap({ fromAddress, fromAsset, amount, destinationAsset, destinationAddress, affiliateAddress = '', affiliateBps = 0, toleranceBps, }) {
864
202
  return __awaiter(this, void 0, void 0, function* () {
865
- let errors = [];
866
- if (wallet) {
867
- const params = {
868
- input: amount,
869
- destinationAsset,
870
- destinationAddress,
871
- memo: '',
872
- waitTimeSeconds: 100,
873
- walletIndex,
874
- };
875
- errors = yield wallet.validateSwap(params);
876
- }
203
+ const errors = yield this.validateSwap({
204
+ fromAddress,
205
+ fromAsset,
206
+ amount,
207
+ destinationAsset,
208
+ destinationAddress,
209
+ });
877
210
  const estimate = yield this.thorchainQuery.quoteSwap({
878
211
  fromAsset,
879
212
  amount,
880
213
  destinationAsset,
881
214
  destinationAddress,
882
215
  affiliateAddress,
883
- interfaceID,
884
216
  affiliateBps,
885
217
  toleranceBps,
886
218
  });
219
+ // Add any validation errors to the estimate
887
220
  estimate.txEstimate.errors.push(...errors);
888
- estimate.txEstimate.canSwap = errors.length == 0;
221
+ estimate.txEstimate.canSwap = estimate.txEstimate.errors.length === 0;
889
222
  return estimate;
890
223
  });
891
224
  }
892
225
  /**
893
- * Conducts a swap with the given inputs. Should be called after estimateSwap() to ensure the swap is valid
226
+ * Validate swap params
227
+ * @param {QuoteSwapParams} quoteSwapParams Swap params
228
+ * @returns {string[]} the reasons the swap can not be done. If it is empty there are no reason to avoid the swap
229
+ */
230
+ validateSwap({ fromAsset, fromAddress, destinationAsset, destinationAddress, amount, affiliateAddress, affiliateBps, }) {
231
+ return __awaiter(this, void 0, void 0, function* () {
232
+ const errors = [];
233
+ if (destinationAddress && !this.wallet.validateAddress(destinationAsset.chain, destinationAddress)) {
234
+ errors.push(`destinationAddress ${destinationAddress} is not a valid address`);
235
+ }
236
+ if (affiliateAddress) {
237
+ const isThorAddress = this.wallet.validateAddress(THORChain, affiliateAddress);
238
+ const isThorname = !!(yield this.thorchainQuery.thorchainCache.midgardQuery.midgardCache.midgard.getTHORNameDetails(affiliateAddress));
239
+ if (!(isThorAddress || isThorname))
240
+ errors.push(`affiliateAddress ${affiliateAddress} is not a valid THOR address`);
241
+ }
242
+ if (affiliateBps && (affiliateBps < 0 || affiliateBps > 10000)) {
243
+ errors.push(`affiliateBps ${affiliateBps} out of range [0 - 10000]`);
244
+ }
245
+ if (isProtocolERC20Asset(fromAsset) && fromAddress) {
246
+ const approveErrors = yield this.isRouterApprovedToSpend({
247
+ asset: fromAsset,
248
+ address: fromAddress,
249
+ amount,
250
+ });
251
+ errors.push(...approveErrors);
252
+ }
253
+ return errors;
254
+ });
255
+ }
256
+ /**
257
+ * Conducts a swap with the given inputs. This method should be called after estimateSwap() to ensure the swap is valid.
894
258
  *
895
- * @param wallet - wallet to use
896
- * @param params - swap params
897
- * @returns {SwapSubmitted} - Tx Hash, URL of BlockExplorer and expected wait time.
259
+ * @param wallet - The wallet to use for the swap.
260
+ * @param params - The swap parameters.
261
+ * @returns {SwapSubmitted} - The transaction hash, URL of BlockExplorer, and expected wait time.
898
262
  */
899
- doSwap(wallet, params) {
263
+ doSwap({ fromAsset, fromAddress, amount, destinationAsset, destinationAddress, affiliateAddress, affiliateBps, toleranceBps, }) {
900
264
  return __awaiter(this, void 0, void 0, function* () {
901
- // Thorchain-query call satisfies the data needed for executeSwap to be called.
902
- const txDetails = yield this.thorchainQuery.quoteSwap(params);
265
+ // Retrieve swap details from ThorchainQuery to ensure validity
266
+ const txDetails = yield this.thorchainQuery.quoteSwap({
267
+ fromAsset,
268
+ fromAddress,
269
+ amount,
270
+ destinationAsset,
271
+ destinationAddress,
272
+ affiliateAddress,
273
+ affiliateBps,
274
+ toleranceBps,
275
+ });
903
276
  if (!txDetails.txEstimate.canSwap) {
904
277
  throw Error(txDetails.txEstimate.errors.join('\n'));
905
278
  }
906
- return yield wallet.executeSwap({
907
- input: params.amount,
908
- destinationAsset: params.destinationAsset,
909
- destinationAddress: params.destinationAddress,
279
+ // Execute the swap using Thorchain action
280
+ return ThorchainAction.makeAction({
281
+ wallet: this.wallet,
282
+ assetAmount: amount,
910
283
  memo: txDetails.memo,
911
- walletIndex: params.walletIndex,
912
- feeOption: params.feeOption,
284
+ recipient: txDetails.toAddress,
913
285
  });
914
286
  });
915
287
  }
916
288
  /**
917
- * Wraps estimate from thorchain query
918
- * @param params - estimate add liquidity
919
- * @returns - Estimate add lp object
289
+ * Validate if the asset router is allowed to spend the asset amount in name of the address
290
+ * @param {IsApprovedParams} isApprovedParams contains the asset and the amount the router is supposed to spend
291
+ * int name of address
292
+ * @returns {string[]} the reasons the router of the asset is not allowed to spend the amount. If it is empty, the asset router is allowed to spend the amount
293
+ */
294
+ isRouterApprovedToSpend({ asset, amount, address }) {
295
+ return __awaiter(this, void 0, void 0, function* () {
296
+ const errors = [];
297
+ const inboundDetails = yield this.thorchainQuery.getChainInboundDetails(asset.chain);
298
+ if (!inboundDetails.router)
299
+ throw Error(`Unknown router address for ${asset.chain}`);
300
+ const isApprovedResult = yield this.wallet.isApproved(asset, amount.baseAmount, address, inboundDetails.router);
301
+ if (!isApprovedResult)
302
+ errors.push('Thorchain router has not been approved to spend this amount');
303
+ return errors;
304
+ });
305
+ }
306
+ /**
307
+ * Wraps the estimate from ThorchainQuery for adding liquidity.
308
+ * @param params - The parameters for estimating adding liquidity.
309
+ * @returns - The estimated liquidity addition object.
920
310
  */
921
311
  estimateAddLiquidity(params) {
922
312
  return __awaiter(this, void 0, void 0, function* () {
@@ -924,9 +314,9 @@ class ThorchainAMM {
924
314
  });
925
315
  }
926
316
  /**
927
- * Wraps estimate withdraw from thorchain query
928
- * @param params - estimate withdraw liquidity
929
- * @returns - Estimate withdraw lp object
317
+ * Wraps the estimate from ThorchainQuery for withdrawing liquidity.
318
+ * @param params - The parameters for estimating withdrawing liquidity.
319
+ * @returns - The estimated liquidity withdrawal object.
930
320
  */
931
321
  estimateWithdrawLiquidity(params) {
932
322
  return __awaiter(this, void 0, void 0, function* () {
@@ -934,36 +324,75 @@ class ThorchainAMM {
934
324
  });
935
325
  }
936
326
  /**
937
- *
938
- * @param wallet - wallet class
939
- * @param params - liquidity parameters
327
+ * If there is no existing liquidity position, it is created automatically.
328
+ * @param wallet - Wallet class
329
+ * @param params - Liquidity parameter
940
330
  * @returns
941
331
  */
942
- addLiquidityPosition(wallet, params) {
332
+ addLiquidityPosition(params) {
943
333
  return __awaiter(this, void 0, void 0, function* () {
944
334
  // Check amounts are greater than fees and use return estimated wait
945
335
  const checkLPAdd = yield this.thorchainQuery.estimateAddLP(params);
946
336
  if (!checkLPAdd.canAdd)
947
337
  throw Error(`${checkLPAdd.errors}`);
948
- return yield wallet.addLiquidity({
338
+ const inboundAsgard = (yield this.thorchainQuery.thorchainCache.getInboundDetails())[params.asset.asset.chain]
339
+ .address;
340
+ const addressRune = yield this.wallet.getAddress(THORChain);
341
+ const addressAsset = yield this.wallet.getAddress(params.asset.asset.chain);
342
+ // const waitTimeSeconds = params.waitTimeSeconds
343
+ const txSubmitted = [];
344
+ const addLiquidity = {
949
345
  asset: params.asset,
950
346
  rune: params.rune,
951
347
  waitTimeSeconds: checkLPAdd.estimatedWaitSeconds,
952
348
  assetPool: checkLPAdd.assetPool,
953
- });
349
+ };
350
+ // symmetrical add
351
+ if (params.asset.assetAmount.gt(0) && params.rune.assetAmount.gt(0)) {
352
+ txSubmitted.push(yield ThorchainAction.makeAction({
353
+ wallet: this.wallet,
354
+ memo: `+:${checkLPAdd.assetPool}:${addressRune}`,
355
+ assetAmount: addLiquidity.asset,
356
+ recipient: inboundAsgard,
357
+ }));
358
+ txSubmitted.push(yield ThorchainAction.makeAction({
359
+ wallet: this.wallet,
360
+ memo: `+:${checkLPAdd.assetPool}:${addressAsset}`,
361
+ assetAmount: addLiquidity.rune,
362
+ }));
363
+ return txSubmitted;
364
+ }
365
+ else if (params.asset.assetAmount.gt(0) && params.rune.assetAmount.eq(0)) {
366
+ // asymmetrical asset only
367
+ txSubmitted.push(yield ThorchainAction.makeAction({
368
+ wallet: this.wallet,
369
+ memo: `+:${checkLPAdd.assetPool}`,
370
+ assetAmount: addLiquidity.asset,
371
+ recipient: inboundAsgard,
372
+ }));
373
+ return txSubmitted;
374
+ }
375
+ else {
376
+ // asymmetrical rune only
377
+ txSubmitted.push(yield ThorchainAction.makeAction({
378
+ wallet: this.wallet,
379
+ memo: `+:${checkLPAdd.assetPool}`,
380
+ assetAmount: addLiquidity.asset,
381
+ }));
382
+ return txSubmitted;
383
+ }
954
384
  });
955
385
  }
956
386
  /**
957
- *
958
- * @param params - liquidity parameters
959
- * @param wallet - wallet needed to perform tx
960
- * @return
387
+ * Withdraws liquidity from a position.
388
+ * @param params - The wallet to perform the transaction.
389
+ * @return - The array of transaction submissions.
961
390
  */
962
- withdrawLiquidityPosition(wallet, params) {
391
+ withdrawLiquidityPosition(params) {
963
392
  return __awaiter(this, void 0, void 0, function* () {
964
- // Caution Dust Limits: BTC,BCH,LTC chains 10k sats; DOGE 1m Sats; ETH 0 wei; THOR 0 RUNE.
393
+ // Caution Dust Limits: BTC, BCH, LTC chains: 10k sats; DOGE: 1m Sats; ETH: 0 wei; THOR: 0 RUNE.
965
394
  const withdrawParams = yield this.thorchainQuery.estimateWithdrawLP(params);
966
- return yield wallet.withdrawLiquidity({
395
+ const withdrawLiquidity = {
967
396
  assetFee: withdrawParams.inbound.fees.asset,
968
397
  runeFee: withdrawParams.inbound.fees.rune,
969
398
  waitTimeSeconds: withdrawParams.estimatedWaitSeconds,
@@ -971,13 +400,50 @@ class ThorchainAMM {
971
400
  assetPool: withdrawParams.assetPool,
972
401
  assetAddress: withdrawParams.assetAddress,
973
402
  runeAddress: withdrawParams.runeAddress,
974
- });
403
+ };
404
+ const inboundAsgard = (yield this.thorchainQuery.thorchainCache.getInboundDetails())[withdrawLiquidity.assetFee.asset.chain].address;
405
+ // const waitTimeSeconds = params.waitTimeSeconds
406
+ const basisPoints = (withdrawLiquidity.percentage * 100).toFixed(); // convert to basis points
407
+ const txSubmitted = [];
408
+ if (withdrawLiquidity.assetAddress && withdrawLiquidity.runeAddress) {
409
+ txSubmitted.push(yield ThorchainAction.makeAction({
410
+ wallet: this.wallet,
411
+ memo: `-:${withdrawLiquidity.assetPool}:${basisPoints}`,
412
+ assetAmount: withdrawLiquidity.assetFee,
413
+ recipient: inboundAsgard,
414
+ }));
415
+ txSubmitted.push(yield ThorchainAction.makeAction({
416
+ wallet: this.wallet,
417
+ memo: `-:${withdrawLiquidity.assetPool}:${basisPoints}`,
418
+ assetAmount: withdrawLiquidity.runeFee,
419
+ }));
420
+ return txSubmitted;
421
+ }
422
+ else if (withdrawLiquidity.assetAddress && !withdrawLiquidity.runeAddress) {
423
+ // asymmetrical asset only
424
+ txSubmitted.push(yield ThorchainAction.makeAction({
425
+ wallet: this.wallet,
426
+ memo: `-:${withdrawLiquidity.assetPool}:${basisPoints}`,
427
+ assetAmount: withdrawLiquidity.assetFee,
428
+ recipient: inboundAsgard,
429
+ }));
430
+ return txSubmitted;
431
+ }
432
+ else {
433
+ // asymmetrical rune only
434
+ txSubmitted.push(yield ThorchainAction.makeAction({
435
+ wallet: this.wallet,
436
+ memo: `-:${withdrawLiquidity.assetPool}:${basisPoints}`,
437
+ assetAmount: withdrawLiquidity.runeFee,
438
+ }));
439
+ return txSubmitted;
440
+ }
975
441
  });
976
442
  }
977
443
  /**
978
- *
979
- * @param addAssetAmount
980
- * @returns
444
+ * Estimates adding to a saver.
445
+ * @param addAssetAmount The amount to add to the saver.
446
+ * @returns The estimated addition to the saver object.
981
447
  */
982
448
  estimateAddSaver(addAssetAmount) {
983
449
  return __awaiter(this, void 0, void 0, function* () {
@@ -985,9 +451,9 @@ class ThorchainAMM {
985
451
  });
986
452
  }
987
453
  /**
988
- *
989
- * @param withdrawParams
990
- * @returns
454
+ * Estimates withdrawing from a saver.
455
+ * @param withdrawParams The parameters for withdrawing from the saver.
456
+ * @returns The estimated withdrawal from the saver object.
991
457
  */
992
458
  estimateWithdrawSaver(withdrawParams) {
993
459
  return __awaiter(this, void 0, void 0, function* () {
@@ -995,9 +461,9 @@ class ThorchainAMM {
995
461
  });
996
462
  }
997
463
  /**
998
- *
999
- * @param getsaver
1000
- * @returns
464
+ * Retrieves the position of a saver.
465
+ * @param getsaver The parameters to retrieve the saver position.
466
+ * @returns The saver position object.
1001
467
  */
1002
468
  getSaverPosition(getsaver) {
1003
469
  return __awaiter(this, void 0, void 0, function* () {
@@ -1005,37 +471,46 @@ class ThorchainAMM {
1005
471
  });
1006
472
  }
1007
473
  /**
1008
- *
474
+ * Adds assets to a saver.
1009
475
  * @param wallet - wallet needed to execute tx
1010
- * @param addAssetAmount - asset amount being added to savers
1011
- * @returns - submitted tx
476
+ * @param addAssetAmount - The amount to add to the saver.
477
+ * @returns - The submitted transaction.
1012
478
  */
1013
- addSaver(wallet, addAssetAmount) {
479
+ addSaver(addAssetAmount) {
1014
480
  return __awaiter(this, void 0, void 0, function* () {
1015
481
  const addEstimate = yield this.thorchainQuery.estimateAddSaver(addAssetAmount);
1016
482
  if (!addEstimate.canAddSaver)
1017
483
  throw Error(`Cannot add to savers`);
1018
- return yield wallet.addSavers(addAssetAmount, addEstimate.memo, addEstimate.toAddress);
484
+ return ThorchainAction.makeAction({
485
+ wallet: this.wallet,
486
+ recipient: addEstimate.toAddress,
487
+ assetAmount: addAssetAmount,
488
+ memo: addEstimate.memo,
489
+ });
1019
490
  });
1020
491
  }
1021
492
  /**
1022
- *
1023
- * @param wallet - wallet to execute the transaction
1024
- * @param withdrawParams - params needed for withdraw
1025
- * @returns
493
+ * Withdraws assets from a saver.
494
+ * @param withdrawParams - The parameters for withdrawing from the saver.
495
+ * @returns The submitted transaction.
1026
496
  */
1027
- withdrawSaver(wallet, withdrawParams) {
497
+ withdrawSaver(withdrawParams) {
1028
498
  return __awaiter(this, void 0, void 0, function* () {
1029
499
  const withdrawEstimate = yield this.thorchainQuery.estimateWithdrawSaver(withdrawParams);
1030
500
  if (withdrawEstimate.errors.length > 0)
1031
501
  throw Error(`${withdrawEstimate.errors}`);
1032
- return yield wallet.withdrawSavers(withdrawEstimate.dustAmount, withdrawEstimate.memo, withdrawEstimate.toAddress);
502
+ return ThorchainAction.makeAction({
503
+ wallet: this.wallet,
504
+ recipient: withdrawEstimate.toAddress,
505
+ assetAmount: withdrawEstimate.dustAmount,
506
+ memo: withdrawEstimate.memo,
507
+ });
1033
508
  });
1034
509
  }
1035
510
  /**
1036
- *
1037
- * @param loanOpenParams
1038
- * @returns
511
+ * Retrieves a quote for opening a loan.
512
+ * @param loanOpenParams The parameters for opening the loan.
513
+ * @returns The quote for opening the loan.
1039
514
  */
1040
515
  getLoanQuoteOpen(loanOpenParams) {
1041
516
  return __awaiter(this, void 0, void 0, function* () {
@@ -1043,9 +518,9 @@ class ThorchainAMM {
1043
518
  });
1044
519
  }
1045
520
  /**
1046
- *
1047
- * @param loanCloseParams
1048
- * @returns
521
+ * Retrieves a quote for closing a loan.
522
+ * @param loanCloseParams The parameters for closing the loan.
523
+ * @returns The quote for closing the loan.
1049
524
  */
1050
525
  getLoanQuoteClose(loanCloseParams) {
1051
526
  return __awaiter(this, void 0, void 0, function* () {
@@ -1053,45 +528,46 @@ class ThorchainAMM {
1053
528
  });
1054
529
  }
1055
530
  /**
1056
- *
1057
- * @param wallet - wallet needed to execute transaction
1058
- * @param loanOpenParams - params needed to open the loan
1059
- * @returns - submitted tx
531
+ * Opens a loan.
532
+ * @param loanOpenParams - The parameters for opening the loan.
533
+ * @returns - The submitted transaction.
1060
534
  */
1061
- addLoan(wallet, loanOpenParams) {
535
+ addLoan(loanOpenParams) {
1062
536
  return __awaiter(this, void 0, void 0, function* () {
1063
537
  const loanOpen = yield this.thorchainQuery.getLoanQuoteOpen(loanOpenParams);
1064
538
  if (loanOpen.errors.length > 0)
1065
539
  throw Error(`${loanOpen.errors}`);
1066
- return yield wallet.loanOpen({
540
+ return ThorchainAction.makeAction({
541
+ wallet: this.wallet,
1067
542
  memo: `${loanOpen.memo}`,
1068
- amount: loanOpenParams.amount,
1069
- toAddress: `${loanOpen.inboundAddress}`,
543
+ recipient: `${loanOpen.inboundAddress}`,
544
+ assetAmount: loanOpenParams.amount,
1070
545
  });
1071
546
  });
1072
547
  }
1073
548
  /**
1074
- *
1075
- * @param wallet - wallet to execute the transaction
1076
- * @param loanCloseParams - params needed for withdrawing the loan
1077
- * @returns
549
+ * Withdraws assets from a loan.
550
+ * @param loanCloseParams - The parameters for withdrawing from the loan.
551
+ * @returns The submitted transaction.
1078
552
  */
1079
- withdrawLoan(wallet, loanCloseParams) {
553
+ withdrawLoan(loanCloseParams) {
1080
554
  return __awaiter(this, void 0, void 0, function* () {
1081
555
  const withdrawLoan = yield this.thorchainQuery.getLoanQuoteClose(loanCloseParams);
556
+ // Checks if there are any errors in the quote
1082
557
  if (withdrawLoan.errors.length > 0)
1083
558
  throw Error(`${withdrawLoan.errors}`);
1084
- return yield wallet.loanClose({
559
+ return ThorchainAction.makeAction({
560
+ wallet: this.wallet,
1085
561
  memo: `${withdrawLoan.memo}`,
1086
- amount: loanCloseParams.amount,
1087
- toAddress: `${withdrawLoan.inboundAddress}`,
562
+ recipient: `${withdrawLoan.inboundAddress}`,
563
+ assetAmount: loanCloseParams.amount,
1088
564
  });
1089
565
  });
1090
566
  }
1091
567
  /**
1092
- * Get all Thornames and its data associated owned by an address
1093
- * @param address - address
1094
- * @returns thornames data
568
+ * Retrieves all Thornames and their associated data owned by an address.
569
+ * @param address - The address to retrieve Thornames for.
570
+ * @returns The Thornames data.
1095
571
  */
1096
572
  getThornamesByAddress(address) {
1097
573
  return __awaiter(this, void 0, void 0, function* () {
@@ -1100,4 +576,4 @@ class ThorchainAMM {
1100
576
  }
1101
577
  }
1102
578
 
1103
- export { ThorchainAMM, Wallet };
579
+ export { ThorchainAMM };