more gas optimization; protocol fee enabled by default in tests

This commit is contained in:
tim
2025-10-14 14:53:22 -04:00
parent dd009cb561
commit eab01554e1
5 changed files with 53 additions and 48 deletions

View File

@@ -24,8 +24,8 @@ Naturally multi-asset, Liquidity Party altcoin pools provide direct, one-hop swa
| Assets | Pairs | Swap Gas | Mint Gas |
|-------:|------:|---------:|----------:|
| 2 | 1 | 132,000 | 143,000 |
| 2* | 1 | 119,000 | 143,000 |
| 2 | 1 | 131,000 | 143,000 |
| 2* | 1 | 118,000 | 143,000 |
| 10 | 45 | 142,000 | 412,000 |
| 20 | 190 | 157,000 | 749,000 |
| 50 | 1225 | 199,000 | 1,760,000 |

View File

@@ -11,6 +11,8 @@ import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
import {PartyPoolViewer} from "./PartyPoolViewer.sol";
library Deploy {
address internal constant PROTOCOL_FEE_RECEIVER = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; // dev account #1
uint256 internal constant PROTOCOL_FEE_PPM = 100_000; // 10%
function newPartyPlanner() internal returns (PartyPlanner) {
return new PartyPlanner(
@@ -18,8 +20,8 @@ library Deploy {
new PartyPoolMintImpl(),
new PartyPoolDeployer(),
new PartyPoolBalancedPairDeployer(),
0, // protocolFeePpm = 0 for deploy helper
address(0) // protocolFeeAddress = address(0) for deploy helper
PROTOCOL_FEE_PPM,
PROTOCOL_FEE_RECEIVER
);
}
@@ -33,10 +35,6 @@ library Deploy {
uint256 _flashFeePpm,
bool _stable
) internal returns (PartyPool) {
// default protocol fee/off parameters (per your instruction) - set to 0 / address(0)
uint256 protocolFeePpm = 0;
address protocolAddr = address(0);
return _stable && tokens_.length == 2 ?
new PartyPoolBalancedPair(
name_,
@@ -46,8 +44,8 @@ library Deploy {
_kappa,
_swapFeePpm,
_flashFeePpm,
protocolFeePpm,
protocolAddr,
PROTOCOL_FEE_PPM,
PROTOCOL_FEE_RECEIVER,
new PartyPoolSwapImpl(),
new PartyPoolMintImpl()
) :
@@ -59,8 +57,8 @@ library Deploy {
_kappa,
_swapFeePpm,
_flashFeePpm,
protocolFeePpm,
protocolAddr,
PROTOCOL_FEE_PPM,
PROTOCOL_FEE_RECEIVER,
new PartyPoolSwapImpl(),
new PartyPoolMintImpl()
);

View File

@@ -146,8 +146,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
/// @inheritdoc IPartyPool
function initialMint(address receiver, uint256 lpTokens) external
returns (uint256 lpMinted) {
bytes memory data = abi.encodeWithSignature(
"initialMint(address,uint256,int128)",
bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.initialMint.selector,
receiver,
lpTokens,
KAPPA
@@ -164,8 +164,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
function mint(address payer, address receiver, uint256 lpTokenAmount, uint256 deadline) external
returns (uint256 lpMinted) {
bytes memory data = abi.encodeWithSignature(
"mint(address,address,uint256,uint256)",
bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.mint.selector,
payer,
receiver,
lpTokenAmount,
@@ -183,8 +183,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline) external
returns (uint256[] memory withdrawAmounts) {
bytes memory data = abi.encodeWithSignature(
"burn(address,address,uint256,uint256)",
bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.burn.selector,
payer,
receiver,
lpAmount,
@@ -226,11 +226,19 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
(uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalUsed, int128 amountOutInternal, , uint256 feeUint) =
_quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
// Transfer tokens
tokens[inputTokenIndex].safeTransferFrom(payer, address(this), totalTransferAmount);
uint256 balIAfter = IERC20(tokens[inputTokenIndex]).balanceOf(address(this));
tokens[outputTokenIndex].safeTransfer(receiver, amountOutUint);
uint256 balJAfter = IERC20(tokens[outputTokenIndex]).balanceOf(address(this));
// Cache token references for fewer SLOADs
IERC20 tokenIn = tokens[inputTokenIndex];
IERC20 tokenOut = tokens[outputTokenIndex];
// Transfer tokens in
tokenIn.safeTransferFrom(payer, address(this), totalTransferAmount);
// Compute on-chain balances as: onchain = cached + owed (+/- transfer)
uint256 balIAfter = cachedUintBalances[inputTokenIndex] + protocolFeesOwed[inputTokenIndex] + totalTransferAmount;
uint256 balJAfter = cachedUintBalances[outputTokenIndex] + protocolFeesOwed[outputTokenIndex] - amountOutUint;
// Transfer output to receiver
tokenOut.safeTransfer(receiver, amountOutUint);
// Accrue protocol share (floor) from the fee on input token
if (PROTOCOL_FEE_PPM > 0 && feeUint > 0) {
@@ -240,14 +248,17 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
}
}
// Update cached uint balances for i and j using effective balances (onchain - owed)
_recordCachedBalance(inputTokenIndex, balIAfter);
_recordCachedBalance(outputTokenIndex, balJAfter);
// Inline _recordCachedBalance: ensure onchain >= owed then set cached = onchain - owed
require(balIAfter >= protocolFeesOwed[inputTokenIndex], "balance < protocol owed");
cachedUintBalances[inputTokenIndex] = balIAfter - protocolFeesOwed[inputTokenIndex];
require(balJAfter >= protocolFeesOwed[outputTokenIndex], "balance < protocol owed");
cachedUintBalances[outputTokenIndex] = balJAfter - protocolFeesOwed[outputTokenIndex];
// Apply swap to LMSR state with the internal amounts actually used
lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalUsed, amountOutInternal);
emit Swap(payer, receiver, tokens[inputTokenIndex], tokens[outputTokenIndex], totalTransferAmount, amountOutUint);
emit Swap(payer, receiver, tokenIn, tokenOut, totalTransferAmount, amountOutUint);
return (totalTransferAmount, amountOutUint, feeUint);
}
@@ -275,8 +286,6 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
)
{
uint256 n = tokens.length;
require(inputTokenIndex < n && outputTokenIndex < n, "swap: idx");
require(maxAmountIn > 0, "swap: input zero");
// Estimate max net input (fee on gross rounded up, then subtract)
(, uint256 netUintForSwap) = _computeFee(maxAmountIn, SWAP_FEE_PPM);
@@ -316,8 +325,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
int128 limitPrice,
uint256 deadline
) external returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
bytes memory data = abi.encodeWithSignature(
'swapToLimit(address,address,uint256,uint256,int128,uint256,uint256,uint256)',
bytes memory data = abi.encodeWithSelector(
PartyPoolSwapImpl.swapToLimit.selector,
payer,
receiver,
inputTokenIndex,
@@ -347,8 +356,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
uint256 maxAmountIn,
uint256 deadline
) external returns (uint256 lpMinted) {
bytes memory data = abi.encodeWithSignature(
"swapMint(address,address,uint256,uint256,uint256,uint256,uint256)",
bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.swapMint.selector,
payer,
receiver,
inputTokenIndex,
@@ -377,8 +386,8 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
uint256 inputTokenIndex,
uint256 deadline
) external returns (uint256 amountOutUint) {
bytes memory data = abi.encodeWithSignature(
"burnSwap(address,address,uint256,uint256,uint256,uint256,uint256)",
bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.burnSwap.selector,
payer,
receiver,
lpAmount,
@@ -422,13 +431,15 @@ contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
}
}
require(token.transfer(address(receiver), amount));
token.safeTransfer(address(receiver), amount);
require(receiver.onFlashLoan(msg.sender, address(token), amount, fee, data) == FLASH_CALLBACK_SUCCESS);
require(token.transferFrom(address(receiver), address(this), amount + fee));
token.safeTransferFrom(address(receiver), address(this), amount + fee);
// Update cached balance for the borrowed token
uint256 balAfter = token.balanceOf(address(this));
_recordCachedBalance(tokenIndex, balAfter);
// Inline _recordCachedBalance logic
require(balAfter >= protocolFeesOwed[tokenIndex], "balance < protocol owed");
cachedUintBalances[tokenIndex] = balAfter - protocolFeesOwed[tokenIndex];
return true;
}

View File

@@ -78,11 +78,4 @@ abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard, PartyPoolHelp
return floorValue;
}
/// @dev Helper to record cached balances as effectiveBalance = onchain - owed. Reverts if owed > onchain.
function _recordCachedBalance(uint256 idx, uint256 onchainBal) internal {
uint256 owed = protocolFeesOwed[idx];
require(onchainBal >= owed, "balance < protocol owed");
cachedUintBalances[idx] = onchainBal - owed;
}
}

View File

@@ -87,9 +87,12 @@ contract PartyPoolSwapImpl is PartyPoolBase {
}
}
// Update caches to effective balances
_recordCachedBalance(inputTokenIndex, balIAfter);
_recordCachedBalance(outputTokenIndex, balJAfter);
// Update caches to effective balances (inline _recordCachedBalance)
require(balIAfter >= protocolFeesOwed[inputTokenIndex], "balance < protocol owed");
cachedUintBalances[inputTokenIndex] = balIAfter - protocolFeesOwed[inputTokenIndex];
require(balJAfter >= protocolFeesOwed[outputTokenIndex], "balance < protocol owed");
cachedUintBalances[outputTokenIndex] = balJAfter - protocolFeesOwed[outputTokenIndex];
// Apply swap to LMSR state with the internal amounts
lmsr.applySwap(inputTokenIndex, outputTokenIndex, amountInInternalMax, amountOutInternal);