cached pair fees

This commit is contained in:
tim
2025-10-31 12:32:05 -04:00
parent dd9b7474a6
commit 89e67ba69b
3 changed files with 31 additions and 17 deletions

View File

@@ -58,7 +58,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
function fees() external view returns (uint256[] memory) { return _fees; }
/// @notice Effective combined fee in ppm for (i as input, j as output)
function fee(uint256 i, uint256 j) external view returns (uint256) { return _pairFeePpm(i,j); }
function fee(uint256 i, uint256 j) external view returns (uint256) { return _pairFeePpmView(i,j); }
/// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts.
uint256 private immutable FLASH_FEE_PPM;
@@ -240,7 +240,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 maxAmountIn,
int128 limitPrice
) external view returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
(uint256 grossIn, uint256 outUint,,,, uint256 feeUint) = _quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
(uint256 grossIn, uint256 outUint,,,, uint256 feeUint) = _quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, _pairFeePpmView(inputTokenIndex, outputTokenIndex));
return (grossIn, outUint, feeUint);
}
@@ -259,7 +259,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
// Compute amounts using the same path as views
(uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalUsed, int128 amountOutInternal, , uint256 feeUint) =
_quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
_quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, _pairFeePpm(inputTokenIndex, outputTokenIndex));
// Cache token references for fewer SLOADs
IERC20 tokenIn = _tokens[inputTokenIndex];
@@ -309,7 +309,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 inputTokenIndex,
uint256 outputTokenIndex,
uint256 maxAmountIn,
int128 limitPrice
int128 limitPrice,
uint256 feePpm
) internal view
returns (
uint256 grossIn,
@@ -321,8 +322,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
)
{
// Estimate max net input (fee on gross rounded up, then subtract)
uint256 pairFeePpm = _pairFeePpm(inputTokenIndex, outputTokenIndex);
(, uint256 netUintForSwap) = _computeFee(maxAmountIn, pairFeePpm);
(, uint256 netUintForSwap) = _computeFee(maxAmountIn, feePpm);
// Convert to internal (floor)
int128 deltaInternalI = _uintToInternalFloor(netUintForSwap, _bases[inputTokenIndex]);
@@ -338,8 +338,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
// Compute gross transfer including fee on the used input (ceil)
feeUint = 0;
grossIn = amountInUintNoFee;
if (pairFeePpm > 0) {
feeUint = _ceilFee(amountInUintNoFee, pairFeePpm);
if (feePpm > 0) {
feeUint = _ceilFee(amountInUintNoFee, feePpm);
grossIn += feeUint;
}

View File

@@ -1,15 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import "./NativeWrapper.sol";
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
import {ERC20Internal} from "./ERC20Internal.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {LMSRStabilized} from "./LMSRStabilized.sol";
import {PartyPoolHelpers} from "./PartyPoolHelpers.sol";
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {ERC20Internal} from "./ERC20Internal.sol";
import {LMSRStabilized} from "./LMSRStabilized.sol";
import {NativeWrapper} from "./NativeWrapper.sol";
import {OwnableInternal} from "./OwnableInternal.sol";
import {PartyPoolHelpers} from "./PartyPoolHelpers.sol";
/// @notice Abstract base contract that contains storage and internal helpers only.
/// No external/public functions here.
@@ -26,6 +26,7 @@ abstract contract PartyPoolBase is OwnableInternal, ERC20Internal, ReentrancyGua
/// @notice Per-asset swap fees in ppm. Fees are applied on input for swaps; see helpers for composition rules.
uint256[] internal _fees;
mapping( uint256 => uint256 ) internal _pairFees;
//
// Internal state
@@ -92,12 +93,22 @@ abstract contract PartyPoolBase is OwnableInternal, ERC20Internal, ReentrancyGua
// We implement this as: ceil( fi + fj - (fi*fj)/1e6 ) for the real-valued expression.
// For integer arithmetic with fi,fj in ppm this is equal to: fi + fj - floor( (fi*fj)/1e6 ).
// So we compute prod = fi * fj, prodDiv = prod / 1e6 (floor), and return fi + fj - prodDiv.
function _pairFeePpm(uint256 i, uint256 j) internal view returns (uint256) {
function _pairFeePpmView(uint256 i, uint256 j) internal view returns (uint256) {
uint256 fi = _fees[i];
uint256 fj = _fees[j];
return fi + fj - fi * fj / 1_000_000;
}
function _pairFeePpm(uint256 i, uint256 j) internal returns (uint256 fee) {
uint256 key = 1000 * i + j;
fee = _pairFees[key];
if (fee == 0) {
// store fee in cache
fee = _pairFeePpmView(i,j);
_pairFees[key] = fee;
}
}
// Convert uint token amount -> internal 64.64 (floor). Uses ABDKMath64x64.divu which truncates.
function _uintToInternalFloor(uint256 amount, uint256 base) internal pure returns (int128) {
// internal = amount / base (as Q64.64)