per-asset fees

This commit is contained in:
tim
2025-10-29 18:22:23 -04:00
parent 86410c9a91
commit 20758cfb35
18 changed files with 475 additions and 164 deletions

View File

@@ -131,8 +131,6 @@ library LMSRStabilized {
int128 a,
int128 limitPrice
) internal pure returns (int128 amountIn, int128 amountOut) {
require(i < nAssets && j < nAssets, "LMSR: idx");
// Initialize amountIn to full amount (will be adjusted if limit price is hit)
amountIn = a;
@@ -140,48 +138,37 @@ library LMSRStabilized {
int128 sizeMetric = _computeSizeMetric(qInternal);
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
require(b > int128(0), "LMSR: b<=0");
// Precompute reciprocal of b to avoid repeated divisions
int128 invB = ABDKMath64x64.div(ONE, b);
// Guard: output asset must have non-zero effective weight to avoid degenerate/div-by-zero-like conditions
require(qInternal[j] > int128(0), "LMSR: e_j==0");
// Compute r0 = exp((q_i - q_j) / b) directly using invB
int128 r0 = _exp(qInternal[i].sub(qInternal[j]).mul(invB));
require(r0 > int128(0), "LMSR: r0<=0"); // equivalent to e_j > 0 check
// If a positive limitPrice is given, determine whether the full `a` would
// push the marginal price p_i/p_j beyond the limit; if so, truncate `a`.
// Marginal price ratio evolves as r(t) = r0 * exp(t/b) (since e_i multiplies by exp(t/b))
if (limitPrice > int128(0)) {
// r0 must be positive; if r0 == 0 then no risk of exceeding limit by increasing r.
require(r0 >= int128(0), "LMSR: r0<0");
if (r0 == int128(0)) {
// console2.log("r0 == 0 (input asset has zero weight), no limit truncation needed");
// If limitPrice <= current price, we revert (caller must choose a limit > current price to allow any fill)
if (limitPrice <= r0) {
revert("LMSR: limitPrice <= current price");
}
// Compute a_limit directly from ln(limit / r0): a_limit = b * ln(limit / r0)
int128 ratioLimitOverR0 = limitPrice.div(r0);
require(ratioLimitOverR0 > int128(0), "LMSR: ratio<=0");
int128 aLimitOverB = _ln(ratioLimitOverR0); // > 0
// aLimit = b * aLimitOverB
int128 aLimit64 = b.mul(aLimitOverB);
// If computed aLimit is less than the requested a, use the truncated value.
if (aLimit64 < a) {
amountIn = aLimit64; // Store the truncated input amount
a = aLimit64; // Use truncated amount for calculations
} else {
// If limitPrice <= current price, we revert (caller must choose a limit > current price to allow any fill)
if (limitPrice <= r0) {
revert("LMSR: limitPrice <= current price");
}
// Compute a_limit directly from ln(limit / r0): a_limit = b * ln(limit / r0)
int128 ratioLimitOverR0 = limitPrice.div(r0);
require(ratioLimitOverR0 > int128(0), "LMSR: ratio<=0");
int128 aLimitOverB = _ln(ratioLimitOverR0); // > 0
// aLimit = b * aLimitOverB
int128 aLimit64 = b.mul(aLimitOverB);
// If computed aLimit is less than the requested a, use the truncated value.
if (aLimit64 < a) {
amountIn = aLimit64; // Store the truncated input amount
a = aLimit64; // Use truncated amount for calculations
} else {
// console2.log("Not truncating: aLimit64 >= a");
}
// no truncation needed
}
}
@@ -255,28 +242,19 @@ library LMSRStabilized {
uint256 j,
int128 limitPrice
) internal pure returns (int128 amountIn, int128 amountOut) {
require(i < nAssets && j < nAssets, "LMSR: idx");
require(limitPrice > int128(0), "LMSR: limitPrice <= 0");
// Compute b and ensure positivity before deriving invB
int128 sizeMetric = _computeSizeMetric(qInternal);
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
require(b > int128(0), "LMSR: b<=0");
// Precompute reciprocal of b to avoid repeated divisions
int128 invB = ABDKMath64x64.div(ONE, b);
// Guard: output asset must have non-zero effective weight to avoid degenerate/div-by-zero-like conditions
require(qInternal[j] > int128(0), "LMSR: e_j==0");
// Compute r0 = exp((q_i - q_j) / b) directly using invB
int128 r0 = _exp(qInternal[i].sub(qInternal[j]).mul(invB));
// Mirror swapAmountsForExactInput behavior: treat invalid r0 as an error condition.
// Revert if r0 is non-positive (no finite trade under a price limit).
require(r0 > int128(0), "LMSR: r0<=0");
// If current price already exceeds or equals limit, revert the same way swapAmountsForExactInput does.
if (r0 >= limitPrice) {
revert("LMSR: limitPrice <= current price");