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

@@ -8,6 +8,7 @@ import {IPartyPool} from "./IPartyPool.sol";
import {NativeWrapper} from "./NativeWrapper.sol";
import {LMSRStabilized} from "./LMSRStabilized.sol";
import {PartyPoolBase} from "./PartyPoolBase.sol";
import {IERC3156FlashBorrower} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
/// @title PartyPoolSwapMintImpl - Implementation contract for swapMint and burnSwap functions
/// @notice This contract contains the swapMint and burnSwap implementation that will be called via delegatecall
@@ -19,6 +20,48 @@ contract PartyPoolSwapImpl is PartyPoolBase {
constructor(NativeWrapper wrapper_) PartyPoolBase(wrapper_) {}
bytes32 internal constant FLASH_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
function flashLoan(
IERC3156FlashBorrower receiver,
address tokenAddr,
uint256 amount,
bytes calldata data,
uint256 flashFeePpm,
uint256 protocolFeePpm
) external nonReentrant killable returns (bool) {
IERC20 token = IERC20(tokenAddr);
require(amount <= token.balanceOf(address(this)), "flash: amount > balance");
uint256 tokenIndex = _tokenAddressToIndexPlusOne[token];
require(tokenIndex != 0, 'flash: token not in pool');
tokenIndex -= 1;
(uint256 flashFee, ) = _computeFee(amount, flashFeePpm);
// Compute protocol share of flash fee
uint256 protoShare = 0;
if (protocolFeePpm > 0 && flashFee > 0) {
protoShare = (flashFee * protocolFeePpm) / 1_000_000; // floor
if (protoShare > 0) {
_protocolFeesOwed[tokenIndex] += protoShare;
}
}
_sendTokenTo(token, address(receiver), amount, false);
require(
receiver.onFlashLoan(msg.sender, address(token), amount, flashFee, data) == FLASH_CALLBACK_SUCCESS,
'flash: callback'
);
_receiveTokenFrom(address(receiver), token, amount + flashFee);
// Update cached balance for the borrowed token
uint256 balAfter = token.balanceOf(address(this));
require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed");
_cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex];
emit IPartyPool.Flash(msg.sender, receiver, token, amount, flashFee - protoShare, protoShare);
return true;
}
function swapToLimitAmounts(
uint256 inputTokenIndex,
uint256 outputTokenIndex,
@@ -27,7 +70,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
int128 kappa,
int128[] memory qInternal,
uint256 swapFeePpm
) external pure returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
) external pure returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
// Compute internal maxima at the price limit
(int128 amountInInternal, int128 amountOutInternal) = LMSRStabilized.swapAmountsForPriceLimit(
bases.length, kappa, qInternal,
@@ -37,11 +80,11 @@ contract PartyPoolSwapImpl is PartyPoolBase {
uint256 amountInUintNoFee = _internalToUintCeil(amountInInternal, bases[inputTokenIndex]);
require(amountInUintNoFee > 0, "swapToLimit: input zero");
fee = 0;
inFee = 0;
amountIn = amountInUintNoFee;
if (swapFeePpm > 0) {
fee = _ceilFee(amountInUintNoFee, swapFeePpm);
amountIn += fee;
inFee = _ceilFee(amountInUintNoFee, swapFeePpm);
amountIn += inFee;
}
amountOut = _internalToUintFloor(amountOutInternal, bases[outputTokenIndex]);
@@ -59,7 +102,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
bool unwrap,
uint256 swapFeePpm,
uint256 protocolFeePpm
) external payable native killable nonReentrant returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
) external payable native killable nonReentrant returns (uint256 amountInUsed, uint256 amountOut, uint256 inFee) {
uint256 n = _tokens.length;
require(inputTokenIndex < n && outputTokenIndex < n, "swapToLimit: idx");
require(limitPrice > int128(0), "swapToLimit: limit <= 0");