Liquidity Party execution
This commit is contained in:
165
foundry/test/protocols/LiquidityParty.t.sol
Normal file
165
foundry/test/protocols/LiquidityParty.t.sol
Normal file
@@ -0,0 +1,165 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import {
|
||||
IERC20
|
||||
} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||
import {
|
||||
SafeERC20
|
||||
} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {RestrictTransferFrom} from "../../src/RestrictTransferFrom.sol";
|
||||
import {
|
||||
LiquidityPartyExecutor,
|
||||
IPartyPool
|
||||
} from "../../src/executors/LiquidityPartyExecutor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||
import {TestUtils} from "../TestUtils.sol";
|
||||
import {LiquidityPartyExecutorExposed} from "./LiquidityParty.t.sol";
|
||||
|
||||
contract LiquidityPartyExecutorExposed is LiquidityPartyExecutor {
|
||||
constructor(address _permit2) LiquidityPartyExecutor(_permit2) {}
|
||||
|
||||
function decodeParams(bytes calldata data)
|
||||
external
|
||||
pure
|
||||
returns (
|
||||
IPartyPool pool,
|
||||
address tokenIn,
|
||||
uint8 indexIn,
|
||||
uint8 indexOut,
|
||||
TransferType transferType,
|
||||
address receiver
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
}
|
||||
}
|
||||
|
||||
contract LiquidityPartyExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
LiquidityPartyExecutorExposed private executor;
|
||||
IPartyPool private constant POOL =
|
||||
IPartyPool(0x2A804e94500AE379ee0CcC423a67B07cc0aF548C);
|
||||
IERC20 private constant INPUT_TOKEN =
|
||||
IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // WETH
|
||||
uint8 private constant INPUT_INDEX = 3;
|
||||
uint256 private constant AMOUNT_IN = 30428379889; // 30 gwei, 0.1% of the pool's WETH
|
||||
IERC20 private constant OUTPUT_TOKEN =
|
||||
IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE); // SHIB
|
||||
uint8 private constant OUTPUT_INDEX = 9;
|
||||
uint256 private constant EXPECTED_AMOUNT_OUT = 11480220066406156603; // about 115 SHIB
|
||||
uint256 private constant FORK_BLOCK = 23978797;
|
||||
|
||||
function setUp() public {
|
||||
vm.createSelectFork(vm.rpcUrl("mainnet"), FORK_BLOCK);
|
||||
executor = new LiquidityPartyExecutorExposed(PERMIT2_ADDRESS);
|
||||
}
|
||||
|
||||
function testDecodeParams() public view {
|
||||
bytes memory params = abi.encodePacked(
|
||||
POOL,
|
||||
INPUT_TOKEN,
|
||||
INPUT_INDEX,
|
||||
OUTPUT_INDEX,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
(
|
||||
IPartyPool pool,
|
||||
address tokenIn,
|
||||
uint8 indexIn,
|
||||
uint8 indexOut,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver
|
||||
) = executor.decodeParams(params);
|
||||
|
||||
assertEq(address(pool), address(POOL));
|
||||
assertEq(address(tokenIn), address(INPUT_TOKEN));
|
||||
assertEq(indexIn, INPUT_INDEX);
|
||||
assertEq(indexOut, OUTPUT_INDEX);
|
||||
assertEq(
|
||||
uint8(transferType),
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
assertEq(receiver, ALICE);
|
||||
}
|
||||
|
||||
function testDecodeParamsInvalidDataLength() public {
|
||||
bytes memory invalidParams =
|
||||
abi.encodePacked(WETH_ADDR, address(2), address(3));
|
||||
vm.expectRevert();
|
||||
executor.decodeParams(invalidParams);
|
||||
}
|
||||
|
||||
function testSwapWithTransfer() public {
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
POOL,
|
||||
INPUT_TOKEN,
|
||||
INPUT_INDEX,
|
||||
OUTPUT_INDEX,
|
||||
BOB,
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
deal(address(INPUT_TOKEN), address(executor), AMOUNT_IN);
|
||||
uint256 amountOut = executor.swap(AMOUNT_IN, protocolData);
|
||||
|
||||
assertEq(amountOut, EXPECTED_AMOUNT_OUT);
|
||||
assertGe(OUTPUT_TOKEN.balanceOf(BOB), EXPECTED_AMOUNT_OUT);
|
||||
}
|
||||
|
||||
function testSwapNoTransfer() public {
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
POOL,
|
||||
INPUT_TOKEN,
|
||||
INPUT_INDEX,
|
||||
OUTPUT_INDEX,
|
||||
BOB,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
deal(address(INPUT_TOKEN), address(this), AMOUNT_IN);
|
||||
/// forge-lint: disable-next-line(erc20-unchecked-transfer)
|
||||
INPUT_TOKEN.transfer(address(POOL), AMOUNT_IN);
|
||||
uint256 amountOut = executor.swap(AMOUNT_IN, protocolData);
|
||||
|
||||
assertEq(amountOut, EXPECTED_AMOUNT_OUT);
|
||||
assertGe(OUTPUT_TOKEN.balanceOf(BOB), EXPECTED_AMOUNT_OUT);
|
||||
}
|
||||
|
||||
function testSwapIntegration() public {
|
||||
bytes memory protocolData =
|
||||
loadCallDataFromFile("test_encode_liquidityparty");
|
||||
deal(address(INPUT_TOKEN), address(executor), AMOUNT_IN);
|
||||
uint256 amountOut = executor.swap(AMOUNT_IN, protocolData);
|
||||
|
||||
uint256 finalBalance = OUTPUT_TOKEN.balanceOf(BOB);
|
||||
assertEq(amountOut, EXPECTED_AMOUNT_OUT);
|
||||
assertGe(finalBalance, amountOut);
|
||||
}
|
||||
|
||||
function testSwapFailureKilledPool() public {
|
||||
// Killed pools should not even appear as protocol components, but we test an attempted swap anyway.
|
||||
// This address is a pool that was killed (permanent redeem-only mode)
|
||||
address killedPool = address(0xC0A908477FFeff658699182bEB5EcaF1D46B3ddB);
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
killedPool,
|
||||
INPUT_TOKEN,
|
||||
INPUT_INDEX,
|
||||
OUTPUT_INDEX,
|
||||
BOB,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
deal(address(INPUT_TOKEN), address(executor), AMOUNT_IN);
|
||||
vm.expectRevert();
|
||||
executor.swap(AMOUNT_IN, protocolData);
|
||||
}
|
||||
|
||||
function testExportContract() public {
|
||||
exportRuntimeBytecode(address(executor), "LiquidityParty");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user