fix: Move Bebop tests according to new setup
Encoding: integration tests are now separate and inside their own test folder Execution: the final integration test should be inside of the protocol test file now and not in TychoRouterProtocolIntegration.t.sol. For this I had to move the BebopExecutionHarness.t.sol outside of the Bebop test file (because of imports) Took 24 minutes # Commit time for manual adjustment: # Took 2 minutes
This commit is contained in:
182
foundry/test/protocols/BebopExecutionHarness.t.sol
Normal file
182
foundry/test/protocols/BebopExecutionHarness.t.sol
Normal file
@@ -0,0 +1,182 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import "../../src/executors/BebopExecutor.sol";
|
||||
import {Test, console} from "forge-std/Test.sol";
|
||||
|
||||
contract BebopExecutorHarness is BebopExecutor, Test {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
constructor(address _bebopSettlement, address _permit2)
|
||||
BebopExecutor(_bebopSettlement, _permit2)
|
||||
{}
|
||||
|
||||
// Expose the internal decodeData function for testing
|
||||
function decodeParams(bytes calldata data)
|
||||
external
|
||||
pure
|
||||
returns (
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
BebopExecutor.OrderType orderType,
|
||||
uint256 filledTakerAmount,
|
||||
bytes memory quoteData,
|
||||
bytes memory makerSignaturesData,
|
||||
bool // approvalNeeded - unused in test harness
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
}
|
||||
|
||||
// Expose the internal getActualFilledTakerAmount function for testing
|
||||
function exposed_getActualFilledTakerAmount(
|
||||
uint256 givenAmount,
|
||||
uint256 orderTakerAmount,
|
||||
uint256 filledTakerAmount
|
||||
) external pure returns (uint256 actualFilledTakerAmount) {
|
||||
return _getActualFilledTakerAmount(
|
||||
givenAmount, orderTakerAmount, filledTakerAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Override to prank the taker address before calling the real settlement
|
||||
function _executeSingleRFQ(
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
TransferType transferType,
|
||||
uint256 givenAmount,
|
||||
uint256 filledTakerAmount,
|
||||
bytes memory quoteData,
|
||||
bytes memory makerSignaturesData,
|
||||
bool approvalNeeded
|
||||
) internal virtual override returns (uint256 amountOut) {
|
||||
// Decode the order from quoteData
|
||||
IBebopSettlement.Single memory order =
|
||||
abi.decode(quoteData, (IBebopSettlement.Single));
|
||||
|
||||
uint256 actualFilledTakerAmount = _getActualFilledTakerAmount(
|
||||
givenAmount, order.taker_amount, filledTakerAmount
|
||||
);
|
||||
|
||||
// For testing: transfer tokens from executor to taker address
|
||||
// This simulates the taker having the tokens with approval
|
||||
if (tokenIn != address(0)) {
|
||||
_transfer(
|
||||
address(this), transferType, tokenIn, actualFilledTakerAmount
|
||||
);
|
||||
IERC20(tokenIn).safeTransfer(
|
||||
order.taker_address, actualFilledTakerAmount
|
||||
);
|
||||
|
||||
// Approve settlement from taker's perspective
|
||||
// Stop any existing prank first
|
||||
vm.stopPrank();
|
||||
vm.startPrank(order.taker_address);
|
||||
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
|
||||
vm.stopPrank();
|
||||
} else {
|
||||
vm.stopPrank();
|
||||
// For native ETH, send it to the taker address
|
||||
payable(order.taker_address).transfer(actualFilledTakerAmount);
|
||||
}
|
||||
|
||||
// IMPORTANT: Prank as the taker address to pass the settlement validation
|
||||
vm.stopPrank();
|
||||
vm.startPrank(order.taker_address);
|
||||
|
||||
// Set block timestamp to ensure order is valid regardless of fork block
|
||||
uint256 currentTimestamp = block.timestamp;
|
||||
vm.warp(order.expiry - 1); // Set timestamp to just before expiry
|
||||
|
||||
// Execute the single swap, let's test the actual settlement logic
|
||||
amountOut = super._executeSingleRFQ(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
TransferType.None, // We set transfer type to none for testing in order to keep the taker's balance unchanged as it will execute the swap
|
||||
givenAmount,
|
||||
filledTakerAmount,
|
||||
quoteData,
|
||||
makerSignaturesData,
|
||||
approvalNeeded
|
||||
);
|
||||
|
||||
// Restore original timestamp
|
||||
vm.warp(currentTimestamp);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
// Override to execute aggregate orders through the real settlement
|
||||
function _executeAggregateRFQ(
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
TransferType transferType,
|
||||
uint256 givenAmount,
|
||||
uint256 filledTakerAmount,
|
||||
bytes memory quoteData,
|
||||
bytes memory makerSignaturesData,
|
||||
bool approvalNeeded
|
||||
) internal virtual override returns (uint256 amountOut) {
|
||||
// Decode the Aggregate order
|
||||
IBebopSettlement.Aggregate memory order =
|
||||
abi.decode(quoteData, (IBebopSettlement.Aggregate));
|
||||
|
||||
// For aggregate orders, calculate total taker amount across all amounts of the 2D array
|
||||
uint256 totalTakerAmount = 0;
|
||||
for (uint256 i = 0; i < order.taker_amounts.length; i++) {
|
||||
for (uint256 j = 0; j < order.taker_amounts[i].length; j++) {
|
||||
totalTakerAmount += order.taker_amounts[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
uint256 actualFilledTakerAmount = _getActualFilledTakerAmount(
|
||||
givenAmount, totalTakerAmount, filledTakerAmount
|
||||
);
|
||||
|
||||
// For testing: transfer tokens from executor to taker address
|
||||
// This simulates the taker having the tokens with approval
|
||||
if (tokenIn != address(0)) {
|
||||
_transfer(
|
||||
address(this), transferType, tokenIn, actualFilledTakerAmount
|
||||
);
|
||||
IERC20(tokenIn).safeTransfer(
|
||||
order.taker_address, actualFilledTakerAmount
|
||||
);
|
||||
|
||||
// Approve settlement from taker's perspective
|
||||
// Stop any existing prank first
|
||||
vm.stopPrank();
|
||||
vm.startPrank(order.taker_address);
|
||||
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
|
||||
vm.stopPrank();
|
||||
} else {
|
||||
vm.stopPrank();
|
||||
// For native ETH, send it to the taker address
|
||||
payable(order.taker_address).transfer(actualFilledTakerAmount);
|
||||
}
|
||||
|
||||
// IMPORTANT: Prank as the taker address to pass the settlement validation
|
||||
vm.stopPrank();
|
||||
vm.startPrank(order.taker_address);
|
||||
|
||||
// Set block timestamp to ensure order is valid regardless of fork block
|
||||
uint256 currentTimestamp = block.timestamp;
|
||||
vm.warp(order.expiry - 1); // Set timestamp to just before expiry
|
||||
|
||||
// Execute the aggregate swap, let's test the actual settlement logic
|
||||
amountOut = super._executeAggregateRFQ(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
TransferType.None, // We set transfer type to none for testing in order to keep the taker's balance unchanged as it will execute the swap
|
||||
givenAmount,
|
||||
filledTakerAmount,
|
||||
quoteData,
|
||||
makerSignaturesData,
|
||||
approvalNeeded
|
||||
);
|
||||
|
||||
// Restore original timestamp
|
||||
vm.warp(currentTimestamp);
|
||||
vm.stopPrank();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user