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