@alcorexchange/alcor-swap-sdk 1.0.18 → 1.0.19

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.
@@ -28,4 +28,5 @@ export declare class CurrencyAmount<T extends Currency> extends Fraction {
28
28
  toExact(format?: object): string;
29
29
  toAsset(...args: any[]): string;
30
30
  toExtendedAsset(...args: any[]): string;
31
+ toExtendedAssetObject(...args: any[]): object;
31
32
  }
@@ -76,5 +76,8 @@ class CurrencyAmount extends fraction_1.Fraction {
76
76
  toExtendedAsset(...args) {
77
77
  return `${this.toFixed(...args)} ${this.currency.symbol}@${this.currency.contract}`;
78
78
  }
79
+ toExtendedAssetObject(...args) {
80
+ return { quantity: `${this.toFixed(...args)} ${this.currency.symbol}`, contract: this.currency.contract };
81
+ }
79
82
  }
80
83
  exports.CurrencyAmount = CurrencyAmount;
@@ -116,6 +116,7 @@ export declare class Trade<TInput extends Currency, TOutput extends Currency, TT
116
116
  * @returns The route
117
117
  */
118
118
  static fromRoute<TInput extends Currency, TOutput extends Currency, TTradeType extends TradeType>(route: Route<TInput, TOutput>, amount: TTradeType extends TradeType.EXACT_INPUT ? CurrencyAmount<TInput> : CurrencyAmount<TOutput>, tradeType: TTradeType): Promise<Trade<TInput, TOutput, TTradeType>>;
119
+ static fromRouteReadOnly<TInput extends Currency, TOutput extends Currency, TTradeType extends TradeType>(nodes: string[], route: Route<TInput, TOutput>, amount: TTradeType extends TradeType.EXACT_INPUT ? CurrencyAmount<TInput> : CurrencyAmount<TOutput>, tradeType: TTradeType): Promise<Trade<TInput, TOutput, TTradeType>>;
119
120
  /**
120
121
  * Constructs a trade from routes by simulating swaps
121
122
  *
@@ -221,4 +222,6 @@ export declare class Trade<TInput extends Currency, TOutput extends Currency, TT
221
222
  static bestTradeExactOut<TInput extends Currency, TOutput extends Currency>(pools: Pool[], currencyIn: TInput, currencyAmountOut: CurrencyAmount<TOutput>, { maxNumResults, maxHops }?: BestTradeOptions, currentPools?: Pool[], nextAmountOut?: CurrencyAmount<Currency>, bestTrades?: Trade<TInput, TOutput, TradeType.EXACT_OUTPUT>[]): Promise<Trade<TInput, TOutput, TradeType.EXACT_OUTPUT>[]>;
222
223
  static bestTradeExactIn2<TInput extends Currency, TOutput extends Currency>(routes: Route<TInput, TOutput>[], pools: Pool[], currencyAmountIn: CurrencyAmount<TInput>, maxNumResults?: number): Promise<Trade<TInput, TOutput, TradeType.EXACT_INPUT>[]>;
223
224
  static bestTradeExactOut2<TInput extends Currency, TOutput extends Currency>(routes: Route<TInput, TOutput>[], pools: Pool[], currencyAmountOut: CurrencyAmount<TOutput>, maxNumResults?: number): Promise<Trade<TInput, TOutput, TradeType.EXACT_OUTPUT>[]>;
225
+ static bestTradeExactInReadOnly<TInput extends Currency, TOutput extends Currency>(nodes: string[], routes: Route<TInput, TOutput>[], currencyAmountIn: CurrencyAmount<TInput>, maxNumResults?: number): Promise<Trade<TInput, TOutput, TradeType.EXACT_INPUT>[]>;
226
+ static bestTradeExactOutReadOnly<TInput extends Currency, TOutput extends Currency>(nodes: string[], routes: Route<TInput, TOutput>[], currencyAmountOut: CurrencyAmount<TOutput>, maxNumResults?: number): Promise<Trade<TInput, TOutput, TradeType.EXACT_OUTPUT>[]>;
224
227
  }
@@ -18,6 +18,7 @@ const fractions_1 = require("./fractions");
18
18
  const utils_1 = require("../utils");
19
19
  const internalConstants_1 = require("../internalConstants");
20
20
  const route_1 = require("./route");
21
+ const computeAllRoutes_1 = require("../utils/computeAllRoutes");
21
22
  /**
22
23
  * Trades comparator, an extension of the input output comparator that also considers other dimensions of the trade in ranking them
23
24
  * @template TInput The input token, either Ether or an ERC-20
@@ -201,6 +202,28 @@ class Trade {
201
202
  });
202
203
  });
203
204
  }
205
+ static fromRouteReadOnly(nodes, route, amount, tradeType) {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ let inputAmount;
208
+ let outputAmount;
209
+ if (tradeType === internalConstants_1.TradeType.EXACT_INPUT) {
210
+ (0, tiny_invariant_1.default)(amount.currency.equals(route.input), 'INPUT');
211
+ inputAmount = fractions_1.CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
212
+ const value = yield (0, computeAllRoutes_1.callReadOnlySwapCalculation)(nodes, tradeType, inputAmount, fractions_1.CurrencyAmount.fromRawAmount(route.output, 0), route.pools.map(p => p.id));
213
+ outputAmount = fractions_1.CurrencyAmount.fromRawAmount(route.output, value);
214
+ }
215
+ else {
216
+ (0, tiny_invariant_1.default)(amount.currency.equals(route.output), 'OUTPUT');
217
+ outputAmount = fractions_1.CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator);
218
+ const value = yield (0, computeAllRoutes_1.callReadOnlySwapCalculation)(nodes, tradeType, fractions_1.CurrencyAmount.fromRawAmount(route.input, 0), outputAmount, route.pools.map(p => p.id));
219
+ inputAmount = fractions_1.CurrencyAmount.fromRawAmount(route.input, value);
220
+ }
221
+ return new Trade({
222
+ routes: [{ inputAmount, outputAmount, route }],
223
+ tradeType
224
+ });
225
+ });
226
+ }
204
227
  /**
205
228
  * Constructs a trade from routes by simulating swaps
206
229
  *
@@ -494,5 +517,36 @@ class Trade {
494
517
  return bestTrades;
495
518
  });
496
519
  }
520
+ static bestTradeExactInReadOnly(nodes, routes, currencyAmountIn, maxNumResults = 1) {
521
+ return __awaiter(this, void 0, void 0, function* () {
522
+ const bestTrades = [];
523
+ const requests = routes.map(r => {
524
+ return Trade.fromRouteReadOnly(nodes, r, currencyAmountIn, internalConstants_1.TradeType.EXACT_INPUT);
525
+ });
526
+ const trades = yield Promise.all(requests);
527
+ for (const trade of trades) {
528
+ if (!trade.inputAmount.greaterThan(0) || !trade.priceImpact.greaterThan(0)) {
529
+ continue;
530
+ }
531
+ (0, utils_1.sortedInsert)(bestTrades, trade, maxNumResults, tradeComparator);
532
+ }
533
+ return bestTrades;
534
+ });
535
+ }
536
+ static bestTradeExactOutReadOnly(nodes, routes, currencyAmountOut, maxNumResults = 1) {
537
+ return __awaiter(this, void 0, void 0, function* () {
538
+ const bestTrades = [];
539
+ const requests = routes.map(r => {
540
+ return Trade.fromRouteReadOnly(nodes, r, currencyAmountOut, internalConstants_1.TradeType.EXACT_OUTPUT);
541
+ });
542
+ const trades = yield Promise.all(requests);
543
+ for (const trade of trades) {
544
+ if (!trade.inputAmount.greaterThan(0) || !trade.priceImpact.greaterThan(0))
545
+ continue;
546
+ (0, utils_1.sortedInsert)(bestTrades, trade, maxNumResults, tradeComparator);
547
+ }
548
+ return bestTrades;
549
+ });
550
+ }
497
551
  }
498
552
  exports.Trade = Trade;
@@ -1,2 +1,4 @@
1
- import { Token, Pool, Route } from '../entities';
1
+ import { TradeType } from '../internalConstants';
2
+ import { Token, Pool, Route, Currency, CurrencyAmount } from '../entities';
2
3
  export declare function computeAllRoutes(tokenIn: Token, tokenOut: Token, pools: Pool[], maxHops: number): Route<Token, Token>[];
4
+ export declare function callReadOnlySwapCalculation<TInput extends Currency, TOutput extends Currency, TTradeType extends TradeType>(nodes: string[], tradeType: TTradeType, inToken: CurrencyAmount<TInput>, outToken: CurrencyAmount<TOutput>, poolIds: number[]): Promise<any>;
@@ -1,6 +1,21 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
2
14
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.computeAllRoutes = void 0;
15
+ exports.callReadOnlySwapCalculation = exports.computeAllRoutes = void 0;
16
+ const node_fetch_1 = __importDefault(require("node-fetch"));
17
+ const antelope_1 = require("@wharfkit/antelope");
18
+ const internalConstants_1 = require("../internalConstants");
4
19
  const entities_1 = require("../entities");
5
20
  function computeAllRoutes(tokenIn, tokenOut, pools, maxHops) {
6
21
  const poolsUsed = Array(pools.length).fill(false);
@@ -37,3 +52,38 @@ function computeAllRoutes(tokenIn, tokenOut, pools, maxHops) {
37
52
  return routes;
38
53
  }
39
54
  exports.computeAllRoutes = computeAllRoutes;
55
+ const abiCache = {};
56
+ function callReadOnlySwapCalculation(nodes, tradeType, inToken, outToken, poolIds) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ const name = tradeType == internalConstants_1.TradeType.EXACT_INPUT ? 'swapexactin' : 'swapexactout';
59
+ // TODO add failover
60
+ const node = nodes[0];
61
+ // TODO Retry logic
62
+ const rpc = new antelope_1.APIClient({ url: node, fetch: node_fetch_1.default });
63
+ const info = yield rpc.v1.chain.get_info();
64
+ const header = info.getTransactionHeader();
65
+ if (!abiCache[node])
66
+ abiCache[node] = (yield rpc.v1.chain.get_abi('amminterface')).abi;
67
+ const abi = abiCache[node];
68
+ const action = antelope_1.Action.from({
69
+ authorization: [],
70
+ account: 'amminterface',
71
+ name,
72
+ data: {
73
+ inToken: inToken.toExtendedAssetObject(),
74
+ outToken: outToken.toExtendedAssetObject(),
75
+ poolIds,
76
+ }
77
+ }, abi);
78
+ const transaction = antelope_1.Transaction.from(Object.assign(Object.assign({}, header), { actions: [action] }));
79
+ try {
80
+ const res = yield rpc.v1.chain.send_read_only_transaction(transaction);
81
+ const outQuantity = res.processed.action_traces[0].return_value_data.quantity;
82
+ return outQuantity.split(' ')[0].replace('.', '');
83
+ }
84
+ catch (e) {
85
+ return '0';
86
+ }
87
+ });
88
+ }
89
+ exports.callReadOnlySwapCalculation = callReadOnlySwapCalculation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alcorexchange/alcor-swap-sdk",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -126,4 +126,8 @@ export class CurrencyAmount<T extends Currency> extends Fraction {
126
126
  public toExtendedAsset(...args): string {
127
127
  return `${this.toFixed(...args)} ${this.currency.symbol}@${this.currency.contract}`
128
128
  }
129
+
130
+ public toExtendedAssetObject(...args): object {
131
+ return { quantity: `${this.toFixed(...args)} ${this.currency.symbol}`, contract: this.currency.contract }
132
+ }
129
133
  }
@@ -7,6 +7,7 @@ import { Token } from './token'
7
7
  import { ONE, ZERO, TradeType } from '../internalConstants'
8
8
  import { Pool } from './pool'
9
9
  import { Route } from './route'
10
+ import { callReadOnlySwapCalculation } from '../utils/computeAllRoutes'
10
11
 
11
12
  /**
12
13
  * Trades comparator, an extension of the input output comparator that also considers other dimensions of the trade in ranking them
@@ -267,6 +268,51 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
267
268
  })
268
269
  }
269
270
 
271
+ public static async fromRouteReadOnly<TInput extends Currency, TOutput extends Currency, TTradeType extends TradeType>(
272
+ nodes: string[],
273
+ route: Route<TInput, TOutput>,
274
+ amount: TTradeType extends TradeType.EXACT_INPUT ? CurrencyAmount<TInput> : CurrencyAmount<TOutput>,
275
+ tradeType: TTradeType
276
+ ): Promise<Trade<TInput, TOutput, TTradeType>> {
277
+ let inputAmount: CurrencyAmount<TInput>
278
+ let outputAmount: CurrencyAmount<TOutput>
279
+
280
+ if (tradeType === TradeType.EXACT_INPUT) {
281
+ invariant(amount.currency.equals(route.input), 'INPUT')
282
+
283
+ inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator)
284
+
285
+ const value = await callReadOnlySwapCalculation(
286
+ nodes,
287
+ tradeType,
288
+ inputAmount,
289
+ CurrencyAmount.fromRawAmount(route.output, 0),
290
+ route.pools.map(p => p.id),
291
+ )
292
+
293
+ outputAmount = CurrencyAmount.fromRawAmount(route.output, value)
294
+ } else {
295
+ invariant(amount.currency.equals(route.output), 'OUTPUT')
296
+
297
+ outputAmount = CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator)
298
+
299
+ const value = await callReadOnlySwapCalculation(
300
+ nodes,
301
+ tradeType,
302
+ CurrencyAmount.fromRawAmount(route.input, 0),
303
+ outputAmount,
304
+ route.pools.map(p => p.id),
305
+ )
306
+
307
+ inputAmount = CurrencyAmount.fromRawAmount(route.input, value)
308
+ }
309
+
310
+ return new Trade({
311
+ routes: [{ inputAmount, outputAmount, route }],
312
+ tradeType
313
+ })
314
+ }
315
+
270
316
  /**
271
317
  * Constructs a trade from routes by simulating swaps
272
318
  *
@@ -716,4 +762,72 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
716
762
 
717
763
  return bestTrades
718
764
  }
765
+
766
+ public static async bestTradeExactInReadOnly<TInput extends Currency, TOutput extends Currency>(
767
+ nodes: string[],
768
+ routes: Route<TInput, TOutput>[],
769
+ currencyAmountIn: CurrencyAmount<TInput>,
770
+ maxNumResults = 1,
771
+ ): Promise<Trade<TInput, TOutput, TradeType.EXACT_INPUT>[]> {
772
+ const bestTrades: Trade<TInput, TOutput, TradeType.EXACT_INPUT>[] = []
773
+
774
+ const requests = routes.map(r => {
775
+ return Trade.fromRouteReadOnly(
776
+ nodes,
777
+ r,
778
+ currencyAmountIn,
779
+ TradeType.EXACT_INPUT
780
+ )
781
+ })
782
+
783
+ const trades = await Promise.all(requests)
784
+
785
+ for (const trade of trades) {
786
+ if (!trade.inputAmount.greaterThan(0) || !trade.priceImpact.greaterThan(0)) {
787
+ continue
788
+ }
789
+
790
+ sortedInsert(
791
+ bestTrades,
792
+ trade,
793
+ maxNumResults,
794
+ tradeComparator
795
+ )
796
+ }
797
+
798
+ return bestTrades
799
+ }
800
+
801
+ public static async bestTradeExactOutReadOnly<TInput extends Currency, TOutput extends Currency>(
802
+ nodes: string[],
803
+ routes: Route<TInput, TOutput>[],
804
+ currencyAmountOut: CurrencyAmount<TOutput>,
805
+ maxNumResults = 1,
806
+ ): Promise<Trade<TInput, TOutput, TradeType.EXACT_OUTPUT>[]> {
807
+ const bestTrades: Trade<TInput, TOutput, TradeType.EXACT_OUTPUT>[] = []
808
+
809
+ const requests = routes.map(r => {
810
+ return Trade.fromRouteReadOnly(
811
+ nodes,
812
+ r,
813
+ currencyAmountOut,
814
+ TradeType.EXACT_OUTPUT
815
+ )
816
+ })
817
+
818
+ const trades = await Promise.all(requests)
819
+
820
+ for (const trade of trades) {
821
+ if (!trade.inputAmount.greaterThan(0) || !trade.priceImpact.greaterThan(0)) continue
822
+
823
+ sortedInsert(
824
+ bestTrades,
825
+ trade,
826
+ maxNumResults,
827
+ tradeComparator
828
+ )
829
+ }
830
+
831
+ return bestTrades
832
+ }
719
833
  }
@@ -1,4 +1,8 @@
1
- import { Token, Pool, Route } from '../entities';
1
+ import fetch from 'node-fetch'
2
+ import { APIClient, Action, Transaction } from '@wharfkit/antelope'
3
+
4
+ import { TradeType } from '../internalConstants'
5
+ import { Token, Pool, Route, Currency, CurrencyAmount } from '../entities';
2
6
 
3
7
  export function computeAllRoutes(
4
8
  tokenIn: Token,
@@ -62,3 +66,52 @@ export function computeAllRoutes(
62
66
 
63
67
  return routes;
64
68
  }
69
+
70
+ const abiCache = {}
71
+ export async function callReadOnlySwapCalculation<TInput extends Currency, TOutput extends Currency, TTradeType extends TradeType>(
72
+ nodes: string[],
73
+ tradeType: TTradeType,
74
+ inToken: CurrencyAmount<TInput>,
75
+ outToken: CurrencyAmount<TOutput>,
76
+ poolIds: number[],
77
+ ) {
78
+
79
+ const name = tradeType == TradeType.EXACT_INPUT ? 'swapexactin' : 'swapexactout'
80
+
81
+ // TODO add failover
82
+ const node = nodes[0]
83
+
84
+ // TODO Retry logic
85
+ const rpc = new APIClient({ url: node, fetch })
86
+ const info = await rpc.v1.chain.get_info()
87
+ const header = info.getTransactionHeader()
88
+
89
+ if (!abiCache[node]) abiCache[node] = (await rpc.v1.chain.get_abi('amminterface')).abi
90
+
91
+ const abi = abiCache[node]
92
+
93
+ const action = Action.from({
94
+ authorization: [], // No authorizations
95
+ account: 'amminterface',
96
+ name,
97
+ data: {
98
+ inToken: inToken.toExtendedAssetObject(),
99
+ outToken: outToken.toExtendedAssetObject(),
100
+ poolIds,
101
+ }
102
+ }, abi)
103
+
104
+ const transaction = Transaction.from({
105
+ ...header,
106
+ actions: [action],
107
+ })
108
+
109
+ try {
110
+ const res: any = await rpc.v1.chain.send_read_only_transaction(transaction)
111
+ const outQuantity = res.processed.action_traces[0].return_value_data.quantity
112
+
113
+ return outQuantity.split(' ')[0].replace('.', '')
114
+ } catch (e) {
115
+ return '0'
116
+ }
117
+ }