@mento-protocol/mento-sdk 1.0.1 → 1.0.3

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/dist/esm/mento.js CHANGED
@@ -9,9 +9,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { BiPoolManager__factory, Broker__factory, IBreakerBox__factory, IBroker__factory, IExchangeProvider__factory, } from '@mento-protocol/mento-core-ts';
11
11
  import { Signer } from 'ethers';
12
- import { getBrokerAddressFromRegistry, getSymbolFromTokenAddress, increaseAllowance, validateSigner, validateSignerOrProvider, } from './utils';
13
12
  import { getLimits, getLimitsConfig, getLimitsState } from './limits';
13
+ import { getBrokerAddressFromRegistry, getChainId, getSymbolFromTokenAddress, increaseAllowance, validateSigner, validateSignerOrProvider, } from './utils';
14
14
  import { strict as assert } from 'assert';
15
+ import { IMentoRouter__factory } from 'mento-router-ts';
16
+ import { getAddress } from './constants/addresses';
17
+ import { getCachedTradablePairs } from './constants/tradablePairs';
15
18
  export class Mento {
16
19
  /**
17
20
  * This constructor is private, use the static create or createWithParams methods
@@ -20,9 +23,10 @@ export class Mento {
20
23
  * @param brokerAddress the address of the broker contract
21
24
  * @param exchanges exchange data for the broker
22
25
  */
23
- constructor(signerOrProvider, brokerAddress, exchanges) {
26
+ constructor(signerOrProvider, brokerAddress, routerAddress, exchanges) {
24
27
  this.signerOrProvider = signerOrProvider;
25
28
  this.broker = IBroker__factory.connect(brokerAddress, signerOrProvider);
29
+ this.router = IMentoRouter__factory.connect(routerAddress, signerOrProvider);
26
30
  this.exchanges = exchanges || [];
27
31
  }
28
32
  /**
@@ -34,7 +38,7 @@ export class Mento {
34
38
  static create(signerOrProvider) {
35
39
  return __awaiter(this, void 0, void 0, function* () {
36
40
  validateSignerOrProvider(signerOrProvider);
37
- return new Mento(signerOrProvider, yield getBrokerAddressFromRegistry(signerOrProvider));
41
+ return new Mento(signerOrProvider, yield getBrokerAddressFromRegistry(signerOrProvider), yield getAddress('MentoRouter', yield getChainId(signerOrProvider)));
38
42
  });
39
43
  }
40
44
  /**
@@ -45,9 +49,9 @@ export class Mento {
45
49
  * @param exchanges the exchanges data for the broker
46
50
  * @returns a new Mento object instance
47
51
  */
48
- static createWithParams(signerOrProvider, brokerAddr, exchanges) {
52
+ static createWithParams(signerOrProvider, brokerAddr, routerAddr, exchanges) {
49
53
  validateSignerOrProvider(signerOrProvider);
50
- return new Mento(signerOrProvider, brokerAddr, exchanges);
54
+ return new Mento(signerOrProvider, brokerAddr, routerAddr, exchanges);
51
55
  }
52
56
  /**
53
57
  * Returns a new Mento instance connected to the given signer
@@ -56,55 +60,241 @@ export class Mento {
56
60
  */
57
61
  connectSigner(signer) {
58
62
  validateSigner(signer);
59
- return new Mento(signer, this.broker.address, this.exchanges);
63
+ return new Mento(signer, this.broker.address, this.router.address, this.exchanges);
60
64
  }
61
65
  /**
62
- * Returns a list of all the pairs that can be traded on Mento
63
- * @returns The list of tradeable pairs in the form of [{address, symbol}]
66
+ * Get tradable pairs for backwards compatibility
67
+ * @returns an array of Asset pairs
64
68
  */
65
- getTradeablePairs() {
69
+ getTradablePairs(options) {
70
+ var _a;
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ return (yield this.getTradablePairsWithPath({ cached: (_a = options === null || options === void 0 ? void 0 : options.cached) !== null && _a !== void 0 ? _a : true })).map((pair) => pair.assets);
73
+ });
74
+ }
75
+ /**
76
+ * Returns a list of all tradable pairs on Mento via direct exchanges.
77
+ * Each pair is represented using the TradablePair interface, with its id
78
+ * (a concatenation of the two asset symbols in alphabetical order),
79
+ * the two Asset objects, and a path (an array with a single direct exchange hop).
80
+ * @returns An array of direct TradablePair objects.
81
+ */
82
+ getDirectPairs() {
66
83
  return __awaiter(this, void 0, void 0, function* () {
67
84
  const exchanges = yield this.getExchanges();
68
- const pairs = [];
85
+ // Map from pair id (symbol-symbol) to its TradablePair
86
+ const directPairsMap = new Map();
69
87
  for (const exchange of exchanges) {
70
- const asset0 = exchange.assets[0];
71
- const asset1 = exchange.assets[1];
72
- const symbols = yield Promise.all([
73
- getSymbolFromTokenAddress(asset0, this.signerOrProvider),
74
- getSymbolFromTokenAddress(asset1, this.signerOrProvider),
75
- ]);
76
- pairs.push([
77
- { address: asset0, symbol: symbols[0] },
78
- { address: asset1, symbol: symbols[1] },
88
+ const [token0, token1] = exchange.assets;
89
+ const [symbol0, symbol1] = yield Promise.all([
90
+ getSymbolFromTokenAddress(token0, this.signerOrProvider),
91
+ getSymbolFromTokenAddress(token1, this.signerOrProvider),
79
92
  ]);
93
+ // Determine canonical order by symbol
94
+ let assets;
95
+ let pairId;
96
+ if (symbol0 <= symbol1) {
97
+ assets = [
98
+ { address: token0, symbol: symbol0 },
99
+ { address: token1, symbol: symbol1 },
100
+ ];
101
+ pairId = `${symbol0}-${symbol1}`;
102
+ }
103
+ else {
104
+ assets = [
105
+ { address: token1, symbol: symbol1 },
106
+ { address: token0, symbol: symbol0 },
107
+ ];
108
+ pairId = `${symbol1}-${symbol0}`;
109
+ }
110
+ const pathEntry = {
111
+ providerAddr: exchange.providerAddr,
112
+ id: exchange.id,
113
+ assets: exchange.assets,
114
+ };
115
+ if (directPairsMap.has(pairId)) {
116
+ directPairsMap.get(pairId).path.push(pathEntry);
117
+ }
118
+ else {
119
+ directPairsMap.set(pairId, { id: pairId, assets, path: [pathEntry] });
120
+ }
121
+ }
122
+ return Array.from(directPairsMap.values());
123
+ });
124
+ }
125
+ /**
126
+ * Returns a list of all tradable pairs on Mento, including those achievable
127
+ * via two-hop routes. For two-hop pairs, the path will contain two exchange hops.
128
+ * Each TradablePair contains an id (the concatenation of the two asset symbols in alphabetical order),
129
+ * the two Asset objects, and an array of exchange details for each hop.
130
+ * @returns An array of TradablePair objects representing available trade routes.
131
+ */
132
+ getTradablePairsWithPath(options) {
133
+ return __awaiter(this, void 0, void 0, function* () {
134
+ // Get tradable pairs from cache if available.
135
+ if (options === null || options === void 0 ? void 0 : options.cached) {
136
+ const value = getCachedTradablePairs(yield getChainId(this.signerOrProvider));
137
+ if (value) {
138
+ return value;
139
+ }
80
140
  }
81
- return pairs;
141
+ // Retrieve direct pairs first.
142
+ const directPairs = yield this.getDirectPairs();
143
+ // Build helper maps:
144
+ // assetMap: maps token address to its Asset details.
145
+ const assetMap = new Map();
146
+ // directPathMap: maps a sorted pair of token addresses (by address) to a direct exchange hop.
147
+ const directPathMap = new Map();
148
+ // graph: maps a token address to the set of addresses it connects to directly.
149
+ const graph = new Map();
150
+ for (const pair of directPairs) {
151
+ const [assetA, assetB] = pair.assets;
152
+ assetMap.set(assetA.address, assetA);
153
+ assetMap.set(assetB.address, assetB);
154
+ const sortedAddresses = [assetA.address, assetB.address].sort().join('-');
155
+ if (!directPathMap.has(sortedAddresses)) {
156
+ // Use the first available direct hop for the connectivity graph.
157
+ directPathMap.set(sortedAddresses, pair.path[0]);
158
+ }
159
+ if (!graph.has(assetA.address))
160
+ graph.set(assetA.address, new Set());
161
+ if (!graph.has(assetB.address))
162
+ graph.set(assetB.address, new Set());
163
+ graph.get(assetA.address).add(assetB.address);
164
+ graph.get(assetB.address).add(assetA.address);
165
+ }
166
+ // Initialize tradablePairsMap with direct pairs keyed by their id (symbol-symbol).
167
+ const tradablePairsMap = new Map();
168
+ for (const pair of directPairs) {
169
+ tradablePairsMap.set(pair.id, pair);
170
+ }
171
+ // Generate two-hop pairs using the connectivity graph.
172
+ // For each potential route: start -> intermediate -> end, add a two-hop pair
173
+ // only if no direct route (i.e. same symbol pair) exists.
174
+ for (const [start, neighbors] of graph.entries()) {
175
+ for (const intermediate of neighbors) {
176
+ const secondHopNeighbors = graph.get(intermediate);
177
+ if (!secondHopNeighbors)
178
+ continue;
179
+ for (const end of secondHopNeighbors) {
180
+ if (end === start)
181
+ continue; // Avoid self-loop.
182
+ const assetStart = assetMap.get(start);
183
+ const assetEnd = assetMap.get(end);
184
+ if (!assetStart || !assetEnd)
185
+ continue;
186
+ // Determine canonical pair id based on asset symbols.
187
+ const sortedSymbols = [assetStart.symbol, assetEnd.symbol].sort();
188
+ const pairId = `${sortedSymbols[0]}-${sortedSymbols[1]}`;
189
+ if (tradablePairsMap.has(pairId))
190
+ continue; // Skip if a direct pair exists.
191
+ // Retrieve the direct hops for the two segments.
192
+ const hop1Key = [start, intermediate].sort().join('-');
193
+ const hop2Key = [intermediate, end].sort().join('-');
194
+ const hop1 = directPathMap.get(hop1Key);
195
+ const hop2 = directPathMap.get(hop2Key);
196
+ if (!hop1 || !hop2)
197
+ continue;
198
+ let assets;
199
+ if (assetStart.symbol <= assetEnd.symbol) {
200
+ assets = [assetStart, assetEnd];
201
+ }
202
+ else {
203
+ assets = [assetEnd, assetStart];
204
+ }
205
+ tradablePairsMap.set(pairId, {
206
+ id: pairId,
207
+ assets,
208
+ path: [hop1, hop2],
209
+ });
210
+ }
211
+ }
212
+ }
213
+ return Array.from(tradablePairsMap.values());
82
214
  });
83
215
  }
84
216
  /**
85
- * Returns the amount of tokenIn to be sold to buy amountOut of tokenOut
217
+ * Returns the amount of tokenIn to be sold to buy amountOut of tokenOut.
218
+ * If the provided tradablePair has a single (direct) pricing path, then direct pricing is used.
219
+ * Otherwise, routed pricing via the MentoRouter is applied.
86
220
  * @param tokenIn the token to be sold
87
221
  * @param tokenOut the token to be bought
88
- * @param amountOut the amount of tokenOut to be bought
222
+ * @param amountOut the desired amount of tokenOut to be obtained
223
+ * @param tradablePair the TradablePair object containing the pricing path information
89
224
  * @returns the amount of tokenIn to be sold
90
225
  */
91
- getAmountIn(tokenIn, tokenOut, amountOut) {
226
+ getAmountIn(tokenIn, tokenOut, amountOut, tradablePair) {
92
227
  return __awaiter(this, void 0, void 0, function* () {
93
- const exchange = yield this.getExchangeForTokens(tokenIn, tokenOut);
94
- return this.broker.getAmountIn(exchange.providerAddr, exchange.id, tokenIn, tokenOut, amountOut);
228
+ if (!tradablePair) {
229
+ tradablePair = yield this.findPairForTokens(tokenIn, tokenOut);
230
+ }
231
+ if (tradablePair.path.length === 1) {
232
+ return this.getAmountInDirect(tokenIn, tokenOut, amountOut, tradablePair);
233
+ }
234
+ else {
235
+ return this.getAmountInRouted(tokenIn, tokenOut, amountOut, tradablePair);
236
+ }
95
237
  });
96
238
  }
97
239
  /**
98
- * Returns the amount of tokenOut to be bought by selling amountIn of tokenIn
240
+ * Returns the amount of tokenOut to be bought by selling amountIn of tokenIn.
241
+ * If the provided tradablePair has a single (direct) pricing path, then direct pricing is used.
242
+ * Otherwise, routed pricing via the MentoRouter is applied.
99
243
  * @param tokenIn the token to be sold
100
244
  * @param tokenOut the token to be bought
101
245
  * @param amountIn the amount of tokenIn to be sold
246
+ * @param tradablePair the TradablePair object containing the pricing path information
102
247
  * @returns the amount of tokenOut to be bought
103
248
  */
104
- getAmountOut(tokenIn, tokenOut, amountIn) {
249
+ getAmountOut(tokenIn, tokenOut, amountIn, tradablePair) {
105
250
  return __awaiter(this, void 0, void 0, function* () {
106
- const exchange = yield this.getExchangeForTokens(tokenIn, tokenOut);
107
- return this.broker.getAmountOut(exchange.providerAddr, exchange.id, tokenIn, tokenOut, amountIn);
251
+ if (!tradablePair) {
252
+ tradablePair = yield this.findPairForTokens(tokenIn, tokenOut);
253
+ }
254
+ if (tradablePair.path.length === 1) {
255
+ return this.getAmountOutDirect(tokenIn, tokenOut, amountIn, tradablePair);
256
+ }
257
+ else {
258
+ return this.getAmountOutRouted(tokenIn, tokenOut, amountIn, tradablePair);
259
+ }
260
+ });
261
+ }
262
+ /**
263
+ * Internal method for direct pricing: retrieves the exchange for the given tokens
264
+ * and returns the amountIn using the broker.
265
+ */
266
+ getAmountInDirect(tokenIn, tokenOut, amountOut, tradablePair) {
267
+ return __awaiter(this, void 0, void 0, function* () {
268
+ return this.broker.getAmountIn(tradablePair.path[0].providerAddr, tradablePair.path[0].id, tokenIn, tokenOut, amountOut);
269
+ });
270
+ }
271
+ /**
272
+ * Internal method for direct pricing: retrieves the exchange for the given tokens
273
+ * and returns the amountOut using the broker.
274
+ */
275
+ getAmountOutDirect(tokenIn, tokenOut, amountIn, tradablePair) {
276
+ return __awaiter(this, void 0, void 0, function* () {
277
+ return this.broker.getAmountOut(tradablePair.path[0].providerAddr, tradablePair.path[0].id, tokenIn, tokenOut, amountIn);
278
+ });
279
+ }
280
+ /**
281
+ * Internal method for routed pricing: uses the MentoRouter to determine the required tokenIn
282
+ * for obtaining amountOut through a multi-hop route specified in tradablePair.path.
283
+ */
284
+ getAmountInRouted(tokenIn, tokenOut, amountOut, tradablePair) {
285
+ return __awaiter(this, void 0, void 0, function* () {
286
+ const steps = this.buildSteps(tokenIn, tokenOut, tradablePair);
287
+ return this.router.getAmountIn(amountOut, steps);
288
+ });
289
+ }
290
+ /**
291
+ * Internal method for routed pricing: uses the MentoRouter to determine the amountOut
292
+ * obtainable by selling amountIn through a multi-hop route specified in tradablePair.path.
293
+ */
294
+ getAmountOutRouted(tokenIn, tokenOut, amountIn, tradablePair) {
295
+ return __awaiter(this, void 0, void 0, function* () {
296
+ const steps = this.buildSteps(tokenIn, tokenOut, tradablePair);
297
+ return this.router.getAmountOut(amountIn, steps);
108
298
  });
109
299
  }
110
300
  /**
@@ -113,10 +303,12 @@ export class Mento {
113
303
  * @param amount the amount to increase the allowance by
114
304
  * @returns the populated TransactionRequest object
115
305
  */
116
- increaseTradingAllowance(token, amount) {
306
+ increaseTradingAllowance(tokenIn, amount, tradablePair) {
117
307
  return __awaiter(this, void 0, void 0, function* () {
118
- const spender = this.broker.address;
119
- const tx = yield increaseAllowance(token, spender, amount, this.signerOrProvider);
308
+ const spender = !tradablePair || (tradablePair === null || tradablePair === void 0 ? void 0 : tradablePair.path.length) == 1
309
+ ? this.broker.address
310
+ : this.router.address;
311
+ const tx = yield increaseAllowance(tokenIn, spender, amount, this.signerOrProvider);
120
312
  if (Signer.isSigner(this.signerOrProvider)) {
121
313
  // The contract call doesn't populate all of the signer fields, so we need an extra call for the signer
122
314
  return this.signerOrProvider.populateTransaction(tx);
@@ -127,47 +319,125 @@ export class Mento {
127
319
  });
128
320
  }
129
321
  /**
130
- * Returns a token swap populated tx object with a fixed amount of tokenIn and a minimum amount of tokenOut
131
- * Submitting the transaction to execute the swap is left to the consumer
322
+ * Returns a token swap populated tx object with a fixed amount of tokenIn and a minimum amount of tokenOut.
323
+ * If the tradablePair contains a single-hop route, a direct swap is executed using swapExactTokensForTokens on the broker.
324
+ * Otherwise, a routed swap is executed via the router.
132
325
  * @param tokenIn the token to be sold
133
326
  * @param tokenOut the token to be bought
134
327
  * @param amountIn the amount of tokenIn to be sold
135
328
  * @param amountOutMin the minimum amount of tokenOut to be bought
329
+ * @param tradablePair the tradable pair details to determine routing
136
330
  * @returns the populated TransactionRequest object
137
331
  */
138
- swapIn(tokenIn, tokenOut, amountIn, amountOutMin) {
332
+ swapIn(tokenIn, tokenOut, amountIn, amountOutMin, tradablePair) {
139
333
  return __awaiter(this, void 0, void 0, function* () {
140
- const exchange = yield this.getExchangeForTokens(tokenIn, tokenOut);
141
- const tx = yield this.broker.populateTransaction.swapIn(exchange.providerAddr, exchange.id, tokenIn, tokenOut, amountIn, amountOutMin);
142
- if (Signer.isSigner(this.signerOrProvider)) {
143
- // The contract call doesn't populate all of the signer fields, so we need an extra call for the signer
144
- return this.signerOrProvider.populateTransaction(tx);
334
+ if (!tradablePair) {
335
+ tradablePair = yield this.findPairForTokens(tokenIn, tokenOut);
336
+ }
337
+ if (tradablePair.path.length === 1) {
338
+ return this.swapInDirect(tokenIn, tokenOut, amountIn, amountOutMin);
145
339
  }
146
340
  else {
147
- return tx;
341
+ return this.swapInRouted(tokenIn, tokenOut, amountIn, amountOutMin, tradablePair);
148
342
  }
149
343
  });
150
344
  }
345
+ swapInDirect(tokenIn, tokenOut, amountIn, amountOutMin) {
346
+ return __awaiter(this, void 0, void 0, function* () {
347
+ const exchange = yield this.getExchangeForTokens(tokenIn, tokenOut);
348
+ const tx = yield this.broker.populateTransaction.swapIn(exchange.providerAddr, exchange.id, tokenIn, tokenOut, amountIn, amountOutMin);
349
+ return Signer.isSigner(this.signerOrProvider)
350
+ ? this.signerOrProvider.populateTransaction(tx)
351
+ : tx;
352
+ });
353
+ }
354
+ swapInRouted(tokenIn, tokenOut, amountIn, amountOutMin, tradablePair) {
355
+ return __awaiter(this, void 0, void 0, function* () {
356
+ const steps = this.buildSteps(tokenIn, tokenOut, tradablePair);
357
+ const tx = yield this.router.populateTransaction.swapExactTokensForTokens(amountIn, amountOutMin, steps);
358
+ return Signer.isSigner(this.signerOrProvider)
359
+ ? this.signerOrProvider.populateTransaction(tx)
360
+ : tx;
361
+ });
362
+ }
151
363
  /**
152
- * Returns a token swap populated tx object with a maximum amount of tokenIn and a fixed amount of tokenOut
153
- * Submitting the transaction to execute the swap is left to the consumer
364
+ * Returns a token swap populated tx object with a maximum amount of tokenIn and a fixed amount of tokenOut.
365
+ * If the tradablePair contains a single-hop route, a direct swap is executed using swapTokensForExactTokens on the broker.
366
+ * Otherwise, a routed swap is executed via the router.
154
367
  * @param tokenIn the token to be sold
155
368
  * @param tokenOut the token to be bought
156
369
  * @param amountOut the amount of tokenOut to be bought
157
370
  * @param amountInMax the maximum amount of tokenIn to be sold
158
371
  * @returns the populated TransactionRequest object
159
372
  */
160
- swapOut(tokenIn, tokenOut, amountOut, amountInMax) {
373
+ swapOut(tokenIn, tokenOut, amountOut, amountInMax, tradablePair) {
374
+ return __awaiter(this, void 0, void 0, function* () {
375
+ if (!tradablePair) {
376
+ tradablePair = yield this.findPairForTokens(tokenIn, tokenOut);
377
+ }
378
+ if (tradablePair.path.length === 1) {
379
+ return this.swapOutDirect(tokenIn, tokenOut, amountOut, amountInMax);
380
+ }
381
+ else {
382
+ return this.swapOutRouted(tokenIn, tokenOut, amountOut, amountInMax, tradablePair);
383
+ }
384
+ });
385
+ }
386
+ swapOutDirect(tokenIn, tokenOut, amountOut, amountInMax) {
161
387
  return __awaiter(this, void 0, void 0, function* () {
162
388
  const exchange = yield this.getExchangeForTokens(tokenIn, tokenOut);
163
389
  const tx = yield this.broker.populateTransaction.swapOut(exchange.providerAddr, exchange.id, tokenIn, tokenOut, amountOut, amountInMax);
164
- if (Signer.isSigner(this.signerOrProvider)) {
165
- // The contract call doesn't populate all of the signer fields, so we need an extra call for the signer
166
- return this.signerOrProvider.populateTransaction(tx);
390
+ return Signer.isSigner(this.signerOrProvider)
391
+ ? this.signerOrProvider.populateTransaction(tx)
392
+ : tx;
393
+ });
394
+ }
395
+ swapOutRouted(tokenIn, tokenOut, amountOut, amountInMax, tradablePair) {
396
+ return __awaiter(this, void 0, void 0, function* () {
397
+ const steps = this.buildSteps(tokenIn, tokenOut, tradablePair);
398
+ const tx = yield this.router.populateTransaction.swapTokensForExactTokens(amountOut, amountInMax, steps);
399
+ return Signer.isSigner(this.signerOrProvider)
400
+ ? this.signerOrProvider.populateTransaction(tx)
401
+ : tx;
402
+ });
403
+ }
404
+ /**
405
+ * Helper method to build the steps for a routed swap, ensuring proper token ordering
406
+ * through the path segments
407
+ */
408
+ buildSteps(tokenIn, tokenOut, tradablePair) {
409
+ let path = [...tradablePair.path];
410
+ if (path[0].assets.includes(tokenOut)) {
411
+ path = path.reverse();
412
+ }
413
+ return path.map((step, idx) => {
414
+ const isFirstStep = idx === 0;
415
+ const isLastStep = idx === tradablePair.path.length - 1;
416
+ const prevStep = idx > 0 ? tradablePair.path[idx - 1] : null;
417
+ // For first step, ensure assetIn is tokenIn
418
+ // For middle steps, ensure assetIn matches previous step's assetOut
419
+ // For last step, ensure assetOut is tokenOut
420
+ let [assetIn, assetOut] = step.assets;
421
+ if (isFirstStep && assetIn !== tokenIn) {
422
+ ;
423
+ [assetIn, assetOut] = [assetOut, assetIn];
167
424
  }
168
- else {
169
- return tx;
425
+ else if (!isFirstStep &&
426
+ !isLastStep &&
427
+ assetIn !== prevStep.assets[1]) {
428
+ ;
429
+ [assetIn, assetOut] = [assetOut, assetIn];
430
+ }
431
+ else if (isLastStep && assetOut !== tokenOut) {
432
+ ;
433
+ [assetIn, assetOut] = [assetOut, assetIn];
170
434
  }
435
+ return {
436
+ exchangeProvider: step.providerAddr,
437
+ exchangeId: step.id,
438
+ assetIn,
439
+ assetOut,
440
+ };
171
441
  });
172
442
  }
173
443
  /**
@@ -177,6 +447,32 @@ export class Mento {
177
447
  getBroker() {
178
448
  return this.broker;
179
449
  }
450
+ /**
451
+ * Finds a tradable pair for the given input and output tokens
452
+ * @param tokenIn the input token address
453
+ * @param tokenOut the output token address
454
+ * @returns the tradable pair containing the path between the tokens
455
+ * @throws if no path is found between the tokens
456
+ */
457
+ findPairForTokens(tokenIn, tokenOut) {
458
+ return __awaiter(this, void 0, void 0, function* () {
459
+ const pair = (yield this.getTradablePairsWithPath()).find((p) =>
460
+ // Direct path
461
+ (p.path.length === 1 &&
462
+ p.path[0].assets.includes(tokenIn) &&
463
+ p.path[0].assets.includes(tokenOut)) ||
464
+ // Routed path
465
+ (p.path.length === 2 &&
466
+ ((p.path[0].assets.includes(tokenIn) &&
467
+ p.path[1].assets.includes(tokenOut)) ||
468
+ (p.path[0].assets.includes(tokenOut) &&
469
+ p.path[1].assets.includes(tokenIn)))));
470
+ if (!pair) {
471
+ throw new Error(`No tradable pair found for tokens ${tokenIn} and ${tokenOut}`);
472
+ }
473
+ return pair;
474
+ });
475
+ }
180
476
  /**
181
477
  * Returns the list of exchanges available in Mento (cached)
182
478
  * @returns the list of exchanges
@@ -6,6 +6,7 @@ export type ContractAddresses = {
6
6
  MentoToken: string;
7
7
  TimelockController: string;
8
8
  Locking: string;
9
+ MentoRouter: string;
9
10
  Broker: string;
10
11
  BiPoolManager: string;
11
12
  BreakerBox: string;
@@ -1,5 +1,11 @@
1
1
  import { BigNumberish, providers, Signer } from 'ethers';
2
2
  import { Address } from './interfaces';
3
+ /**
4
+ * Gets the chain ID from a signer or provider
5
+ * @param signerOrProvider an ethers provider or signer
6
+ * @returns the chain ID
7
+ */
8
+ export declare function getChainId(signerOrProvider: Signer | providers.Provider): Promise<number>;
3
9
  /**
4
10
  * Ensures that given signer is truly a a connected signer
5
11
  * @param signer an ethers signer
package/dist/esm/utils.js CHANGED
@@ -8,6 +8,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { constants, Contract, providers, Signer } from 'ethers';
11
+ /**
12
+ * Gets the chain ID from a signer or provider
13
+ * @param signerOrProvider an ethers provider or signer
14
+ * @returns the chain ID
15
+ */
16
+ export function getChainId(signerOrProvider) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const provider = Signer.isSigner(signerOrProvider)
19
+ ? signerOrProvider.provider
20
+ : signerOrProvider;
21
+ return (yield provider.getNetwork()).chainId;
22
+ });
23
+ }
11
24
  /**
12
25
  * Ensures that given signer is truly a a connected signer
13
26
  * @param signer an ethers signer
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mento-protocol/mento-sdk",
3
3
  "description": "Official SDK for interacting with the Mento Protocol",
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
5
  "license": "MIT",
6
6
  "author": "Mento Labs",
7
7
  "keywords": [
@@ -30,7 +30,8 @@
30
30
  "prettier": "prettier --config ./.prettierrc.json --write **/*.{json,md,js,ts,yml}",
31
31
  "size": "size-limit",
32
32
  "test": "jest --runInBand --verbose",
33
- "coverage": "jest --coverage"
33
+ "coverage": "jest --coverage",
34
+ "cacheTradablePairs": "ts-node scripts/cacheTradablePairs.ts"
34
35
  },
35
36
  "husky": {
36
37
  "hooks": {
@@ -77,7 +78,8 @@
77
78
  "typescript": "^4.9.5"
78
79
  },
79
80
  "dependencies": {
80
- "@mento-protocol/mento-core-ts": "^0.2.0"
81
+ "@mento-protocol/mento-core-ts": "^0.2.0",
82
+ "mento-router-ts": "^0.2.0"
81
83
  },
82
84
  "peerDependencies": {
83
85
  "ethers": "^5.7"