@mento-protocol/mento-sdk 3.2.6 → 3.2.7-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -83,6 +83,67 @@ export function splitAmount(amountIn, splitRatio) {
|
|
|
83
83
|
const amountB = amountIn - amountA;
|
|
84
84
|
return { amountA, amountB };
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Off-chain mirror of Router.sol's quoteAddLiquidity / _quoteZapLiquidity logic.
|
|
88
|
+
*
|
|
89
|
+
* Given desired amounts and pool reserves, returns the (amountA, amountB) the
|
|
90
|
+
* router will actually deposit when adding liquidity. Used to predict the exact
|
|
91
|
+
* `amountAMin` / `amountBMin` the contract will check against post-swap reserves.
|
|
92
|
+
*
|
|
93
|
+
* @param amountADesired - Desired amount of tokenA
|
|
94
|
+
* @param amountBDesired - Desired amount of tokenB
|
|
95
|
+
* @param reserveA - Reserve of tokenA at the moment liquidity is added
|
|
96
|
+
* @param reserveB - Reserve of tokenB at the moment liquidity is added
|
|
97
|
+
*/
|
|
98
|
+
export function quoteAddLiquidityFromReserves(amountADesired, amountBDesired, reserveA, reserveB) {
|
|
99
|
+
if (reserveA === 0n && reserveB === 0n) {
|
|
100
|
+
return { amountA: amountADesired, amountB: amountBDesired };
|
|
101
|
+
}
|
|
102
|
+
if (reserveA === 0n || reserveB === 0n) {
|
|
103
|
+
// Mirrors Router.sol's InsufficientLiquidity revert. Caller can fall back.
|
|
104
|
+
return { amountA: 0n, amountB: 0n };
|
|
105
|
+
}
|
|
106
|
+
const amountBOptimal = (amountADesired * reserveB) / reserveA;
|
|
107
|
+
if (amountBOptimal <= amountBDesired) {
|
|
108
|
+
return { amountA: amountADesired, amountB: amountBOptimal };
|
|
109
|
+
}
|
|
110
|
+
const amountAOptimal = (amountBDesired * reserveA) / reserveB;
|
|
111
|
+
return { amountA: amountAOptimal, amountB: amountBDesired };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Computes the net delta a single-hop zap swap applies to a target pool's
|
|
115
|
+
* reserves. Returns `{delta0, delta1}` to add to the pool's pre-swap reserves
|
|
116
|
+
* to obtain the reserves the router will see when it runs `_quoteZapLiquidity`.
|
|
117
|
+
*
|
|
118
|
+
* Only single-hop routes whose factory matches the target pool's factory and
|
|
119
|
+
* whose `(from, to)` are `(token0, token1)` (in either direction) are
|
|
120
|
+
* considered. Multi-hop routes and routes through other pools have no effect
|
|
121
|
+
* on the target pool's reserves and return `{0, 0}`.
|
|
122
|
+
*
|
|
123
|
+
* Note: Multi-hop routes that traverse the target pool as an intermediate hop
|
|
124
|
+
* are intentionally not handled here — they are uncommon for single-sided zaps
|
|
125
|
+
* and would require per-hop amounts from `getAmountsOut`.
|
|
126
|
+
*/
|
|
127
|
+
export function computeTargetPoolImpact(routes, amountIn, amountOut, token0, token1, factoryAddr) {
|
|
128
|
+
if (routes.length !== 1) {
|
|
129
|
+
return { delta0: 0n, delta1: 0n };
|
|
130
|
+
}
|
|
131
|
+
const route = routes[0];
|
|
132
|
+
if (route.factory.toLowerCase() !== factoryAddr.toLowerCase()) {
|
|
133
|
+
return { delta0: 0n, delta1: 0n };
|
|
134
|
+
}
|
|
135
|
+
const fromLower = route.from.toLowerCase();
|
|
136
|
+
const toLower = route.to.toLowerCase();
|
|
137
|
+
const t0 = token0.toLowerCase();
|
|
138
|
+
const t1 = token1.toLowerCase();
|
|
139
|
+
if (fromLower === t0 && toLower === t1) {
|
|
140
|
+
return { delta0: amountIn, delta1: -amountOut };
|
|
141
|
+
}
|
|
142
|
+
if (fromLower === t1 && toLower === t0) {
|
|
143
|
+
return { delta0: -amountOut, delta1: amountIn };
|
|
144
|
+
}
|
|
145
|
+
return { delta0: 0n, delta1: 0n };
|
|
146
|
+
}
|
|
86
147
|
/**
|
|
87
148
|
* Estimates minimum LP tokens from zap in amounts.
|
|
88
149
|
*
|
|
@@ -2,7 +2,7 @@ import { ROUTER_ABI } from '../../core/abis';
|
|
|
2
2
|
import { getContractAddress } from '../../core/constants';
|
|
3
3
|
import { validateAddress } from '../../utils/validation';
|
|
4
4
|
import { buildApprovalParams, getAllowance, calculateMinAmount, getPoolInfo, getPoolSnapshot } from './liquidityHelpers';
|
|
5
|
-
import { encodeZapInCall, findZapInRoutes, splitAmount, estimateLiquidityFromZapIn, } from './zapHelpers';
|
|
5
|
+
import { encodeZapInCall, findZapInRoutes, splitAmount, estimateLiquidityFromZapIn, quoteAddLiquidityFromReserves, computeTargetPoolImpact, } from './zapHelpers';
|
|
6
6
|
// ========== ZAP IN OPERATIONS ==========
|
|
7
7
|
/**
|
|
8
8
|
* Builds a complete zap in transaction including approval if needed
|
|
@@ -66,8 +66,27 @@ async function prepareZapInContextInternal(publicClient, chainId, poolService, r
|
|
|
66
66
|
functionName: 'generateZapInParams',
|
|
67
67
|
args: [token0, token1, factoryAddr, amountInA, amountInB, routesA, routesB],
|
|
68
68
|
}));
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
// Re-quote amountAMin / amountBMin against POST-swap reserves.
|
|
70
|
+
//
|
|
71
|
+
// `generateZapInParams` calls `quoteAddLiquidity` with the pool's *current*
|
|
72
|
+
// reserves, but on-chain `_quoteZapLiquidity` runs *after* the zap's internal
|
|
73
|
+
// swap, which moves the same pool when tokenIn is one of the pool tokens.
|
|
74
|
+
// Applying user slippage on top of a pre-swap minimum makes the contract
|
|
75
|
+
// reject any non-trivial amount because the deterministic price impact of
|
|
76
|
+
// the swap alone exceeds the slippage budget. Predict the post-swap reserves
|
|
77
|
+
// and re-derive the minimums so that user slippage only covers real drift
|
|
78
|
+
// between quote-time and execution.
|
|
79
|
+
const impactA = computeTargetPoolImpact(routesA, amountInA, amountOutMinA, token0, token1, factoryAddr);
|
|
80
|
+
const impactB = computeTargetPoolImpact(routesB, amountInB, amountOutMinB, token0, token1, factoryAddr);
|
|
81
|
+
const projectedReserveA = poolSnapshot.reserve0 + impactA.delta0 + impactB.delta0;
|
|
82
|
+
const projectedReserveB = poolSnapshot.reserve1 + impactA.delta1 + impactB.delta1;
|
|
83
|
+
const useReserveA = projectedReserveA > 0n ? projectedReserveA : poolSnapshot.reserve0;
|
|
84
|
+
const useReserveB = projectedReserveB > 0n ? projectedReserveB : poolSnapshot.reserve1;
|
|
85
|
+
const projected = quoteAddLiquidityFromReserves(amountOutMinA, amountOutMinB, useReserveA, useReserveB);
|
|
86
|
+
const baselineAmountAMin = projected.amountA > 0n ? projected.amountA : amountAMin;
|
|
87
|
+
const baselineAmountBMin = projected.amountB > 0n ? projected.amountB : amountBMin;
|
|
88
|
+
const finalAmountAMin = calculateMinAmount(baselineAmountAMin, options.slippageTolerance);
|
|
89
|
+
const finalAmountBMin = calculateMinAmount(baselineAmountBMin, options.slippageTolerance);
|
|
71
90
|
const finalAmountOutMinA = calculateMinAmount(amountOutMinA, options.slippageTolerance);
|
|
72
91
|
const finalAmountOutMinB = calculateMinAmount(amountOutMinB, options.slippageTolerance);
|
|
73
92
|
const expectedLiquidity = estimateLiquidityFromZapIn(finalAmountOutMinA, finalAmountOutMinB, poolSnapshot.reserve0, poolSnapshot.reserve1, poolSnapshot.totalSupply);
|
|
@@ -47,6 +47,40 @@ export declare function splitAmount(amountIn: bigint, splitRatio: number): {
|
|
|
47
47
|
amountA: bigint;
|
|
48
48
|
amountB: bigint;
|
|
49
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Off-chain mirror of Router.sol's quoteAddLiquidity / _quoteZapLiquidity logic.
|
|
52
|
+
*
|
|
53
|
+
* Given desired amounts and pool reserves, returns the (amountA, amountB) the
|
|
54
|
+
* router will actually deposit when adding liquidity. Used to predict the exact
|
|
55
|
+
* `amountAMin` / `amountBMin` the contract will check against post-swap reserves.
|
|
56
|
+
*
|
|
57
|
+
* @param amountADesired - Desired amount of tokenA
|
|
58
|
+
* @param amountBDesired - Desired amount of tokenB
|
|
59
|
+
* @param reserveA - Reserve of tokenA at the moment liquidity is added
|
|
60
|
+
* @param reserveB - Reserve of tokenB at the moment liquidity is added
|
|
61
|
+
*/
|
|
62
|
+
export declare function quoteAddLiquidityFromReserves(amountADesired: bigint, amountBDesired: bigint, reserveA: bigint, reserveB: bigint): {
|
|
63
|
+
amountA: bigint;
|
|
64
|
+
amountB: bigint;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Computes the net delta a single-hop zap swap applies to a target pool's
|
|
68
|
+
* reserves. Returns `{delta0, delta1}` to add to the pool's pre-swap reserves
|
|
69
|
+
* to obtain the reserves the router will see when it runs `_quoteZapLiquidity`.
|
|
70
|
+
*
|
|
71
|
+
* Only single-hop routes whose factory matches the target pool's factory and
|
|
72
|
+
* whose `(from, to)` are `(token0, token1)` (in either direction) are
|
|
73
|
+
* considered. Multi-hop routes and routes through other pools have no effect
|
|
74
|
+
* on the target pool's reserves and return `{0, 0}`.
|
|
75
|
+
*
|
|
76
|
+
* Note: Multi-hop routes that traverse the target pool as an intermediate hop
|
|
77
|
+
* are intentionally not handled here — they are uncommon for single-sided zaps
|
|
78
|
+
* and would require per-hop amounts from `getAmountsOut`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function computeTargetPoolImpact(routes: RouterRoute[], amountIn: bigint, amountOut: bigint, token0: Address, token1: Address, factoryAddr: Address): {
|
|
81
|
+
delta0: bigint;
|
|
82
|
+
delta1: bigint;
|
|
83
|
+
};
|
|
50
84
|
/**
|
|
51
85
|
* Estimates minimum LP tokens from zap in amounts.
|
|
52
86
|
*
|
|
@@ -5,6 +5,8 @@ exports.encodeZapOutCall = encodeZapOutCall;
|
|
|
5
5
|
exports.findZapInRoutes = findZapInRoutes;
|
|
6
6
|
exports.findZapOutRoutes = findZapOutRoutes;
|
|
7
7
|
exports.splitAmount = splitAmount;
|
|
8
|
+
exports.quoteAddLiquidityFromReserves = quoteAddLiquidityFromReserves;
|
|
9
|
+
exports.computeTargetPoolImpact = computeTargetPoolImpact;
|
|
8
10
|
exports.estimateLiquidityFromZapIn = estimateLiquidityFromZapIn;
|
|
9
11
|
const viem_1 = require("viem");
|
|
10
12
|
const abis_1 = require("../../core/abis");
|
|
@@ -91,6 +93,67 @@ function splitAmount(amountIn, splitRatio) {
|
|
|
91
93
|
const amountB = amountIn - amountA;
|
|
92
94
|
return { amountA, amountB };
|
|
93
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Off-chain mirror of Router.sol's quoteAddLiquidity / _quoteZapLiquidity logic.
|
|
98
|
+
*
|
|
99
|
+
* Given desired amounts and pool reserves, returns the (amountA, amountB) the
|
|
100
|
+
* router will actually deposit when adding liquidity. Used to predict the exact
|
|
101
|
+
* `amountAMin` / `amountBMin` the contract will check against post-swap reserves.
|
|
102
|
+
*
|
|
103
|
+
* @param amountADesired - Desired amount of tokenA
|
|
104
|
+
* @param amountBDesired - Desired amount of tokenB
|
|
105
|
+
* @param reserveA - Reserve of tokenA at the moment liquidity is added
|
|
106
|
+
* @param reserveB - Reserve of tokenB at the moment liquidity is added
|
|
107
|
+
*/
|
|
108
|
+
function quoteAddLiquidityFromReserves(amountADesired, amountBDesired, reserveA, reserveB) {
|
|
109
|
+
if (reserveA === 0n && reserveB === 0n) {
|
|
110
|
+
return { amountA: amountADesired, amountB: amountBDesired };
|
|
111
|
+
}
|
|
112
|
+
if (reserveA === 0n || reserveB === 0n) {
|
|
113
|
+
// Mirrors Router.sol's InsufficientLiquidity revert. Caller can fall back.
|
|
114
|
+
return { amountA: 0n, amountB: 0n };
|
|
115
|
+
}
|
|
116
|
+
const amountBOptimal = (amountADesired * reserveB) / reserveA;
|
|
117
|
+
if (amountBOptimal <= amountBDesired) {
|
|
118
|
+
return { amountA: amountADesired, amountB: amountBOptimal };
|
|
119
|
+
}
|
|
120
|
+
const amountAOptimal = (amountBDesired * reserveA) / reserveB;
|
|
121
|
+
return { amountA: amountAOptimal, amountB: amountBDesired };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Computes the net delta a single-hop zap swap applies to a target pool's
|
|
125
|
+
* reserves. Returns `{delta0, delta1}` to add to the pool's pre-swap reserves
|
|
126
|
+
* to obtain the reserves the router will see when it runs `_quoteZapLiquidity`.
|
|
127
|
+
*
|
|
128
|
+
* Only single-hop routes whose factory matches the target pool's factory and
|
|
129
|
+
* whose `(from, to)` are `(token0, token1)` (in either direction) are
|
|
130
|
+
* considered. Multi-hop routes and routes through other pools have no effect
|
|
131
|
+
* on the target pool's reserves and return `{0, 0}`.
|
|
132
|
+
*
|
|
133
|
+
* Note: Multi-hop routes that traverse the target pool as an intermediate hop
|
|
134
|
+
* are intentionally not handled here — they are uncommon for single-sided zaps
|
|
135
|
+
* and would require per-hop amounts from `getAmountsOut`.
|
|
136
|
+
*/
|
|
137
|
+
function computeTargetPoolImpact(routes, amountIn, amountOut, token0, token1, factoryAddr) {
|
|
138
|
+
if (routes.length !== 1) {
|
|
139
|
+
return { delta0: 0n, delta1: 0n };
|
|
140
|
+
}
|
|
141
|
+
const route = routes[0];
|
|
142
|
+
if (route.factory.toLowerCase() !== factoryAddr.toLowerCase()) {
|
|
143
|
+
return { delta0: 0n, delta1: 0n };
|
|
144
|
+
}
|
|
145
|
+
const fromLower = route.from.toLowerCase();
|
|
146
|
+
const toLower = route.to.toLowerCase();
|
|
147
|
+
const t0 = token0.toLowerCase();
|
|
148
|
+
const t1 = token1.toLowerCase();
|
|
149
|
+
if (fromLower === t0 && toLower === t1) {
|
|
150
|
+
return { delta0: amountIn, delta1: -amountOut };
|
|
151
|
+
}
|
|
152
|
+
if (fromLower === t1 && toLower === t0) {
|
|
153
|
+
return { delta0: -amountOut, delta1: amountIn };
|
|
154
|
+
}
|
|
155
|
+
return { delta0: 0n, delta1: 0n };
|
|
156
|
+
}
|
|
94
157
|
/**
|
|
95
158
|
* Estimates minimum LP tokens from zap in amounts.
|
|
96
159
|
*
|
|
@@ -72,8 +72,27 @@ async function prepareZapInContextInternal(publicClient, chainId, poolService, r
|
|
|
72
72
|
functionName: 'generateZapInParams',
|
|
73
73
|
args: [token0, token1, factoryAddr, amountInA, amountInB, routesA, routesB],
|
|
74
74
|
}));
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// Re-quote amountAMin / amountBMin against POST-swap reserves.
|
|
76
|
+
//
|
|
77
|
+
// `generateZapInParams` calls `quoteAddLiquidity` with the pool's *current*
|
|
78
|
+
// reserves, but on-chain `_quoteZapLiquidity` runs *after* the zap's internal
|
|
79
|
+
// swap, which moves the same pool when tokenIn is one of the pool tokens.
|
|
80
|
+
// Applying user slippage on top of a pre-swap minimum makes the contract
|
|
81
|
+
// reject any non-trivial amount because the deterministic price impact of
|
|
82
|
+
// the swap alone exceeds the slippage budget. Predict the post-swap reserves
|
|
83
|
+
// and re-derive the minimums so that user slippage only covers real drift
|
|
84
|
+
// between quote-time and execution.
|
|
85
|
+
const impactA = (0, zapHelpers_1.computeTargetPoolImpact)(routesA, amountInA, amountOutMinA, token0, token1, factoryAddr);
|
|
86
|
+
const impactB = (0, zapHelpers_1.computeTargetPoolImpact)(routesB, amountInB, amountOutMinB, token0, token1, factoryAddr);
|
|
87
|
+
const projectedReserveA = poolSnapshot.reserve0 + impactA.delta0 + impactB.delta0;
|
|
88
|
+
const projectedReserveB = poolSnapshot.reserve1 + impactA.delta1 + impactB.delta1;
|
|
89
|
+
const useReserveA = projectedReserveA > 0n ? projectedReserveA : poolSnapshot.reserve0;
|
|
90
|
+
const useReserveB = projectedReserveB > 0n ? projectedReserveB : poolSnapshot.reserve1;
|
|
91
|
+
const projected = (0, zapHelpers_1.quoteAddLiquidityFromReserves)(amountOutMinA, amountOutMinB, useReserveA, useReserveB);
|
|
92
|
+
const baselineAmountAMin = projected.amountA > 0n ? projected.amountA : amountAMin;
|
|
93
|
+
const baselineAmountBMin = projected.amountB > 0n ? projected.amountB : amountBMin;
|
|
94
|
+
const finalAmountAMin = (0, liquidityHelpers_1.calculateMinAmount)(baselineAmountAMin, options.slippageTolerance);
|
|
95
|
+
const finalAmountBMin = (0, liquidityHelpers_1.calculateMinAmount)(baselineAmountBMin, options.slippageTolerance);
|
|
77
96
|
const finalAmountOutMinA = (0, liquidityHelpers_1.calculateMinAmount)(amountOutMinA, options.slippageTolerance);
|
|
78
97
|
const finalAmountOutMinB = (0, liquidityHelpers_1.calculateMinAmount)(amountOutMinB, options.slippageTolerance);
|
|
79
98
|
const expectedLiquidity = (0, zapHelpers_1.estimateLiquidityFromZapIn)(finalAmountOutMinA, finalAmountOutMinB, poolSnapshot.reserve0, poolSnapshot.reserve1, poolSnapshot.totalSupply);
|
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": "3.2.
|
|
4
|
+
"version": "3.2.7-beta.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Mento Labs",
|
|
7
7
|
"keywords": [
|
|
@@ -80,5 +80,11 @@
|
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"viem": "^2.21.44"
|
|
83
|
+
},
|
|
84
|
+
"pnpm": {
|
|
85
|
+
"onlyBuiltDependencies": [
|
|
86
|
+
"esbuild",
|
|
87
|
+
"unrs-resolver"
|
|
88
|
+
]
|
|
83
89
|
}
|
|
84
90
|
}
|