CREATE2 callback validation; init code storage contracts
This commit is contained in:
151
test/GasTest.sol
151
test/GasTest.sol
@@ -13,11 +13,13 @@ import {ERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.s
|
||||
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {Funding} from "../src/Funding.sol";
|
||||
import {IPartyPlanner} from "../src/IPartyPlanner.sol";
|
||||
import {IPartyPool} from "../src/IPartyPool.sol";
|
||||
import {IPartySwapCallback} from "../src/IPartySwapCallback.sol";
|
||||
import {LMSRStabilized} from "../src/LMSRStabilized.sol";
|
||||
import {PartyPlanner} from "../src/PartyPlanner.sol";
|
||||
import {PartySwapCallbackVerifier} from "../src/PartySwapCallbackVerifier.sol";
|
||||
import {Deploy} from "./Deploy.sol";
|
||||
import {TestERC20, FlashBorrower} from "./GasTest.sol";
|
||||
import {TestERC20, GasHarness, FlashBorrower} from "./GasTest.sol";
|
||||
|
||||
/* solhint-disable erc20-unchecked-transfer */
|
||||
|
||||
@@ -103,12 +105,58 @@ contract TestERC20 is ERC20 {
|
||||
}
|
||||
}
|
||||
|
||||
contract GasHarness is IPartySwapCallback {
|
||||
// In order to compare like-for-like, we need to include the token transfers in a single external function for gas measurement
|
||||
|
||||
using SafeERC20 for ERC20;
|
||||
|
||||
IPartyPlanner immutable private planner;
|
||||
|
||||
constructor(IPartyPlanner planner_) {
|
||||
planner = planner_;
|
||||
}
|
||||
|
||||
function swapApproval(
|
||||
IPartyPool pool, IERC20 tokenIn, address /*payer*/, bytes4 fundingSelector, address receiver, uint256 inputTokenIndex,
|
||||
uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice, uint256 deadline, bool unwrap
|
||||
) external payable returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
|
||||
// pool moves coins
|
||||
tokenIn.approve(address(pool), type(uint256).max);
|
||||
(amountIn, amountOut, inFee) = pool.swap{value:msg.value}(address(this), fundingSelector, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, unwrap, '');
|
||||
tokenIn.approve(address(pool), 0);
|
||||
}
|
||||
|
||||
function swapPrefund(
|
||||
IPartyPool pool, address /*payer*/, bytes4 fundingSelector, address receiver, uint256 inputTokenIndex,
|
||||
uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice, uint256 deadline, bool unwrap
|
||||
) external payable returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
|
||||
// Prefund the pool
|
||||
IERC20(pool.token(inputTokenIndex)).transfer(address(pool), maxAmountIn);
|
||||
return pool.swap{value:msg.value}(address(0), fundingSelector, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, unwrap, '');
|
||||
}
|
||||
|
||||
function swapCallback(
|
||||
IPartyPool pool, address /*payer*/, bytes4 /*fundingSelector*/, address receiver, uint256 inputTokenIndex,
|
||||
uint256 outputTokenIndex, uint256 maxAmountIn, int128 limitPrice, uint256 deadline, bool unwrap
|
||||
) external payable returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
|
||||
return pool.swap{value:msg.value}(address(this), this.liquidityPartySwapCallback.selector, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, unwrap, '');
|
||||
}
|
||||
|
||||
function liquidityPartySwapCallback(bytes32 nonce, IERC20 token, uint256 amount, bytes memory) external {
|
||||
PartySwapCallbackVerifier.verifyCallback(planner, nonce);
|
||||
token.transfer(msg.sender, amount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @notice Gas testing contract for PartyPool - contains all gas measurement tests
|
||||
contract GasTest is Test {
|
||||
using ABDKMath64x64 for int128;
|
||||
using SafeERC20 for TestERC20;
|
||||
|
||||
PartyPlanner internal planner;
|
||||
GasHarness internal harness;
|
||||
|
||||
IPartyPlanner internal planner;
|
||||
IPartyPool internal pool2;
|
||||
IPartyPool internal pool10;
|
||||
IPartyPool internal pool20;
|
||||
@@ -138,6 +186,7 @@ contract GasTest is Test {
|
||||
|
||||
// Mint initial balances for pool initialization and test users
|
||||
token.mint(address(this), INIT_BAL);
|
||||
token.mint(address(harness), INIT_BAL);
|
||||
token.mint(alice, INIT_BAL);
|
||||
token.mint(bob, INIT_BAL);
|
||||
}
|
||||
@@ -165,7 +214,7 @@ contract GasTest is Test {
|
||||
}
|
||||
|
||||
/// @notice Helper to create a pool with the stable-pair optimization enabled
|
||||
function createPoolStable(uint256 numTokens) internal returns (IPartyPool) {
|
||||
function createPoolStable(uint256 numTokens) internal returns (IPartyPool pool) {
|
||||
// Deploy _tokens dynamically
|
||||
address[] memory tokens = new address[](numTokens);
|
||||
uint256[] memory bases = new uint256[](numTokens);
|
||||
@@ -178,6 +227,7 @@ contract GasTest is Test {
|
||||
|
||||
// Mint initial balances for pool initialization and test users
|
||||
token.mint(address(this), INIT_BAL);
|
||||
token.mint(address(harness), INIT_BAL);
|
||||
token.mint(alice, INIT_BAL);
|
||||
token.mint(bob, INIT_BAL);
|
||||
}
|
||||
@@ -191,17 +241,15 @@ contract GasTest is Test {
|
||||
ierc20Tokens[i] = IERC20(tokens[i]);
|
||||
}
|
||||
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage);
|
||||
IPartyPool newPool = Deploy.newPartyPool(address(this), poolName, poolName, ierc20Tokens, computedKappa, feePpm, feePpm, true);
|
||||
|
||||
// Transfer initial deposit amounts into pool before initial mint
|
||||
uint256[] memory initialBalances = new uint256[](numTokens);
|
||||
for (uint256 i = 0; i < numTokens; i++) {
|
||||
TestERC20(tokens[i]).transfer(address(newPool), INIT_BAL);
|
||||
initialBalances[i] = INIT_BAL;
|
||||
ierc20Tokens[i].approve(address(planner), INIT_BAL);
|
||||
}
|
||||
|
||||
// Perform initial mint (initial deposit); receiver is this contract
|
||||
newPool.initialMint(address(this), 0);
|
||||
|
||||
return newPool;
|
||||
vm.prank(planner.owner());
|
||||
(pool, ) = planner.newPool(poolName, poolName, ierc20Tokens, computedKappa, feePpm, feePpm, true,
|
||||
address(this), address(this), initialBalances, 0, 0);
|
||||
}
|
||||
|
||||
function setUp() public {
|
||||
@@ -210,6 +258,8 @@ contract GasTest is Test {
|
||||
|
||||
planner = Deploy.newPartyPlanner();
|
||||
|
||||
harness = new GasHarness(planner);
|
||||
|
||||
// Configure LMSR parameters similar to other tests: trade size 1% of asset -> 0.01, slippage 0.001
|
||||
tradeFrac = ABDKMath64x64.divu(100, 10_000); // 0.01
|
||||
targetSlippage = ABDKMath64x64.divu(10, 10_000); // 0.001
|
||||
@@ -238,39 +288,35 @@ contract GasTest is Test {
|
||||
|
||||
/// @notice Helper function: perform 10 swaps back-and-forth between the first two _tokens.
|
||||
function _performSwapGasTest(IPartyPool testPool) internal {
|
||||
_performSwapGasTest(testPool, Funding.APPROVALS);
|
||||
_performSwapGasTest(testPool, Funding.APPROVAL);
|
||||
}
|
||||
|
||||
function sendTokensCallback(IERC20 token, uint256 amount) external {
|
||||
// verify the caller
|
||||
require(planner.getPoolSupported(msg.sender), 'Not a LiqP pool');
|
||||
token.transferFrom( alice, msg.sender, amount);
|
||||
|
||||
function _doSwap(
|
||||
IPartyPool pool,
|
||||
address payer,
|
||||
bytes4 fundingSelector,
|
||||
address receiver,
|
||||
uint256 inputTokenIndex,
|
||||
uint256 outputTokenIndex,
|
||||
uint256 maxAmountIn,
|
||||
int128 limitPrice,
|
||||
uint256 deadline,
|
||||
bool unwrap
|
||||
) internal returns (uint256 amountIn, uint256 amountOut, uint256 inFee) {
|
||||
if (fundingSelector == Funding.APPROVAL)
|
||||
return harness.swapApproval{value:msg.value}(pool, pool.token(inputTokenIndex), payer, fundingSelector, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, unwrap);
|
||||
if (fundingSelector == Funding.PREFUNDING) {
|
||||
pool.token(inputTokenIndex).transfer(address(harness), maxAmountIn);
|
||||
return harness.swapPrefund{value:msg.value}(pool, payer, fundingSelector, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, unwrap);
|
||||
}
|
||||
else
|
||||
return harness.swapCallback{value:msg.value}(pool, payer, fundingSelector, receiver, inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, deadline, unwrap);
|
||||
}
|
||||
|
||||
function _performSwapGasTest(IPartyPool testPool, bytes4 fundingSelector) internal {
|
||||
IERC20[] memory tokens = testPool.allTokens();
|
||||
require(tokens.length >= 2, "Pool must have at least 2 tokens");
|
||||
address payer;
|
||||
address spender;
|
||||
|
||||
if (fundingSelector == Funding.PREFUNDING) {
|
||||
payer = address(this);
|
||||
spender = address(this);
|
||||
}
|
||||
else if (fundingSelector == Funding.APPROVALS) {
|
||||
payer = alice;
|
||||
spender = address(testPool);
|
||||
}
|
||||
else {
|
||||
payer = address(this);
|
||||
spender = address(this);
|
||||
}
|
||||
TestERC20 token0 = TestERC20(address(tokens[0]));
|
||||
TestERC20 token1 = TestERC20(address(tokens[1]));
|
||||
vm.prank(alice);
|
||||
token0.approve(spender, type(uint256).max);
|
||||
vm.prank(alice);
|
||||
token1.approve(spender, type(uint256).max);
|
||||
|
||||
uint256 maxIn = 10_000;
|
||||
|
||||
@@ -278,15 +324,11 @@ contract GasTest is Test {
|
||||
vm.startPrank(alice);
|
||||
for (uint256 i = 0; i < 20; i++) {
|
||||
if (i % 2 == 0) {
|
||||
if (fundingSelector == Funding.PREFUNDING)
|
||||
token0.transfer(address(testPool), maxIn);
|
||||
// swap token0 -> token1
|
||||
testPool.swap(payer, fundingSelector, alice, 0, 1, maxIn, 0, 0, false);
|
||||
_doSwap(testPool, alice, fundingSelector, alice, 0, 1, maxIn, 0, 0, false);
|
||||
} else {
|
||||
// swap token1 -> token0
|
||||
if (fundingSelector == Funding.PREFUNDING)
|
||||
token1.transfer(address(testPool), maxIn);
|
||||
testPool.swap(payer, fundingSelector, alice, 1, 0, maxIn, 0, 0, false);
|
||||
_doSwap( testPool, alice, fundingSelector, alice, 1, 0, maxIn, 0, 0, false);
|
||||
}
|
||||
// shake up the bits
|
||||
maxIn *= 787;
|
||||
@@ -306,20 +348,29 @@ contract GasTest is Test {
|
||||
}
|
||||
|
||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 10-token pool using the callback funding method.
|
||||
function testSwapGasCallback() public {
|
||||
_performSwapGasTest(pool10, this.sendTokensCallback.selector);
|
||||
function testSwapGasCallback10() public {
|
||||
_performSwapGasTest(pool10, IPartySwapCallback.liquidityPartySwapCallback.selector);
|
||||
}
|
||||
|
||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 10-token pool using the callback funding method.
|
||||
function testSwapGasPrefunding() public {
|
||||
function testSwapGasPrefunding10() public {
|
||||
_performSwapGasTest(pool10, Funding.PREFUNDING);
|
||||
}
|
||||
|
||||
function testSwapGasPrefunding20() public {
|
||||
_performSwapGasTest(pool20, Funding.PREFUNDING);
|
||||
}
|
||||
|
||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 20-token pool.
|
||||
function testSwapGasTwenty() public {
|
||||
_performSwapGasTest(pool20);
|
||||
}
|
||||
|
||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 10-token pool using the callback funding method.
|
||||
function testSwapGasCallback20() public {
|
||||
_performSwapGasTest(pool20, IPartySwapCallback.liquidityPartySwapCallback.selector);
|
||||
}
|
||||
|
||||
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 100-token pool.
|
||||
function testSwapGasFifty() public {
|
||||
_performSwapGasTest(pool50);
|
||||
@@ -331,6 +382,12 @@ contract GasTest is Test {
|
||||
_performSwapGasTest(stablePair);
|
||||
}
|
||||
|
||||
/// @notice Gas measurement: perform 10 swaps back-and-forth on a 2-token stable pair (stable-path enabled)
|
||||
function testSwapGasPrefundingSP() public {
|
||||
IPartyPool stablePair = createPoolStable(2);
|
||||
_performSwapGasTest(stablePair, IPartySwapCallback.liquidityPartySwapCallback.selector);
|
||||
}
|
||||
|
||||
/// @notice Gas-style test: alternate swapMint then burnSwap on a 2-token stable pair
|
||||
function testSwapMintBurnSwapGasStablePair() public {
|
||||
IPartyPool stablePair = createPoolStable(2);
|
||||
|
||||
Reference in New Issue
Block a user