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