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