chore: start implementing test changes related to partialFillOffset and encoded receiver
This commit is contained in:
@@ -114,13 +114,17 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
bytes memory bebopCalldata,
|
bytes memory bebopCalldata,
|
||||||
uint8 partialFillOffset,
|
uint8 partialFillOffset,
|
||||||
uint256 originalFilledTakerAmount,
|
uint256 originalFilledTakerAmount,
|
||||||
bool approvalNeeded
|
bool approvalNeeded,
|
||||||
|
address receiver
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
// Modify the filledTakerAmount in the calldata
|
// Modify the filledTakerAmount in the calldata
|
||||||
// If the filledTakerAmount is the same as the original, the original calldata is returned
|
// If the filledTakerAmount is the same as the original, the original calldata is returned
|
||||||
bytes memory finalCalldata = _modifyFilledTakerAmount(
|
bytes memory finalCalldata = _modifyFilledTakerAmount(
|
||||||
bebopCalldata, givenAmount, originalFilledTakerAmount, partialFillOffset
|
bebopCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalFilledTakerAmount,
|
||||||
|
partialFillOffset
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transfer tokens if needed
|
// Transfer tokens if needed
|
||||||
@@ -134,9 +138,8 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
|
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bebop orders specify the receiver, so we need to check the receiver's balance
|
// Check the receiver's balance before the swap
|
||||||
// We'll use the executor's balance since Bebop should send tokens here for the router to collect
|
uint256 balanceBefore = _balanceOf(tokenOut, receiver);
|
||||||
uint256 balanceBefore = _balanceOf(tokenOut, address(this));
|
|
||||||
|
|
||||||
// Execute the swap with the forwarded calldata
|
// Execute the swap with the forwarded calldata
|
||||||
uint256 ethValue = tokenIn == address(0) ? givenAmount : 0;
|
uint256 ethValue = tokenIn == address(0) ? givenAmount : 0;
|
||||||
@@ -144,8 +147,8 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
// Use OpenZeppelin's Address library for safe call with value
|
// Use OpenZeppelin's Address library for safe call with value
|
||||||
bebopSettlement.functionCallWithValue(finalCalldata, ethValue);
|
bebopSettlement.functionCallWithValue(finalCalldata, ethValue);
|
||||||
|
|
||||||
// Calculate actual amount received by the executor
|
// Calculate actual amount received by the receiver
|
||||||
uint256 balanceAfter = _balanceOf(tokenOut, address(this));
|
uint256 balanceAfter = _balanceOf(tokenOut, receiver);
|
||||||
calculatedAmount = balanceAfter - balanceBefore;
|
calculatedAmount = balanceAfter - balanceBefore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,12 +163,13 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
bytes memory bebopCalldata,
|
bytes memory bebopCalldata,
|
||||||
uint8 partialFillOffset,
|
uint8 partialFillOffset,
|
||||||
uint256 originalFilledTakerAmount,
|
uint256 originalFilledTakerAmount,
|
||||||
bool approvalNeeded
|
bool approvalNeeded,
|
||||||
|
address receiver
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Need at least 79 bytes for the minimum fixed fields
|
// Need at least 99 bytes for the minimum fixed fields
|
||||||
// 20 + 20 + 1 + 4 (calldata length) + 1 (offset) + 32 (original amount) + 1 (approval) = 79
|
// 20 + 20 + 1 + 4 (calldata length) + 1 (offset) + 32 (original amount) + 1 (approval) + 20 (receiver) = 99
|
||||||
if (data.length < 79) revert BebopExecutor__InvalidDataLength();
|
if (data.length < 99) revert BebopExecutor__InvalidDataLength();
|
||||||
|
|
||||||
// Decode fixed fields
|
// Decode fixed fields
|
||||||
tokenIn = address(bytes20(data[0:20]));
|
tokenIn = address(bytes20(data[0:20]));
|
||||||
@@ -174,7 +178,7 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
|
|
||||||
// Get bebop calldata length and validate
|
// Get bebop calldata length and validate
|
||||||
uint32 bebopCalldataLength = uint32(bytes4(data[41:45]));
|
uint32 bebopCalldataLength = uint32(bytes4(data[41:45]));
|
||||||
if (data.length != 79 + bebopCalldataLength) {
|
if (data.length != 99 + bebopCalldataLength) {
|
||||||
revert BebopExecutor__InvalidDataLength();
|
revert BebopExecutor__InvalidDataLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +195,11 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
|
|
||||||
// Extract approval flag
|
// Extract approval flag
|
||||||
approvalNeeded = data[78 + bebopCalldataLength] != 0;
|
approvalNeeded = data[78 + bebopCalldataLength] != 0;
|
||||||
|
|
||||||
|
// Extract receiver address
|
||||||
|
receiver = address(
|
||||||
|
bytes20(data[79 + bebopCalldataLength:99 + bebopCalldataLength])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Modifies the filledTakerAmount in the bebop calldata to handle slippage
|
/// @dev Modifies the filledTakerAmount in the bebop calldata to handle slippage
|
||||||
@@ -210,8 +219,9 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
uint256 filledTakerAmountPos = 4 + uint256(partialFillOffset) * 32;
|
uint256 filledTakerAmountPos = 4 + uint256(partialFillOffset) * 32;
|
||||||
|
|
||||||
// Cap the fill amount at what we actually have available
|
// Cap the fill amount at what we actually have available
|
||||||
uint256 newFilledTakerAmount =
|
uint256 newFilledTakerAmount = originalFilledTakerAmount > givenAmount
|
||||||
originalFilledTakerAmount > givenAmount ? givenAmount : originalFilledTakerAmount;
|
? givenAmount
|
||||||
|
: originalFilledTakerAmount;
|
||||||
|
|
||||||
// If the new filledTakerAmount is the same as the original, return the original calldata
|
// If the new filledTakerAmount is the same as the original, return the original calldata
|
||||||
if (newFilledTakerAmount == originalFilledTakerAmount) {
|
if (newFilledTakerAmount == originalFilledTakerAmount) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -102,7 +102,8 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
||||||
originalAmountIn,
|
originalAmountIn,
|
||||||
uint8(1) // approvalNeeded: true
|
uint8(1), // approvalNeeded: true
|
||||||
|
address(123)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test decoding
|
// Test decoding
|
||||||
@@ -113,7 +114,8 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bytes memory decodedBebopCalldata,
|
bytes memory decodedBebopCalldata,
|
||||||
uint8 decodedPartialFillOffset,
|
uint8 decodedPartialFillOffset,
|
||||||
uint256 decodedOriginalAmountIn,
|
uint256 decodedOriginalAmountIn,
|
||||||
bool decodedApprovalNeeded
|
bool decodedApprovalNeeded,
|
||||||
|
address decodedReceiver
|
||||||
) = bebopExecutor.decodeParams(params);
|
) = bebopExecutor.decodeParams(params);
|
||||||
|
|
||||||
assertEq(tokenIn, USDC_ADDR, "tokenIn mismatch");
|
assertEq(tokenIn, USDC_ADDR, "tokenIn mismatch");
|
||||||
@@ -135,6 +137,7 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
"originalAmountIn mismatch"
|
"originalAmountIn mismatch"
|
||||||
);
|
);
|
||||||
assertTrue(decodedApprovalNeeded, "approvalNeeded should be true");
|
assertTrue(decodedApprovalNeeded, "approvalNeeded should be true");
|
||||||
|
assertEq(decodedReceiver, address(123), "receiver mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single Order Tests
|
// Single Order Tests
|
||||||
@@ -217,18 +220,22 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
||||||
testData.order.taker_amount, // originalAmountIn (matches what encoder would produce)
|
testData.order.taker_amount, // originalAmountIn (matches what encoder would produce)
|
||||||
uint8(1) // approvalNeeded: true
|
uint8(1), // approvalNeeded: true
|
||||||
|
originalTakerAddress // receiver from order
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check initial ONDO balance of receiver
|
||||||
|
uint256 initialOndoBalance = ONDO.balanceOf(originalTakerAddress);
|
||||||
|
|
||||||
uint256 amountOut = bebopExecutor.swap(testData.amountIn, params);
|
uint256 amountOut = bebopExecutor.swap(testData.amountIn, params);
|
||||||
|
|
||||||
// Verify results
|
// Verify results
|
||||||
assertEq(amountOut, testData.expectedAmountOut, "Incorrect amount out");
|
assertEq(amountOut, testData.expectedAmountOut, "Incorrect amount out");
|
||||||
// The harness transfers tokens to the executor to simulate proper flow
|
// Since we're using real order data, tokens go to the original receiver
|
||||||
assertEq(
|
assertEq(
|
||||||
ONDO.balanceOf(address(bebopExecutor)),
|
ONDO.balanceOf(originalTakerAddress) - initialOndoBalance,
|
||||||
testData.expectedAmountOut,
|
testData.expectedAmountOut,
|
||||||
"ONDO should be in executor"
|
"ONDO should be at receiver"
|
||||||
);
|
);
|
||||||
assertEq(
|
assertEq(
|
||||||
USDC.balanceOf(address(bebopExecutor)), 0, "USDC left in executor"
|
USDC.balanceOf(address(bebopExecutor)), 0, "USDC left in executor"
|
||||||
@@ -313,9 +320,13 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
||||||
testData.order.taker_amount, // originalAmountIn (full order amount)
|
testData.order.taker_amount, // originalAmountIn (full order amount)
|
||||||
uint8(1) // approvalNeeded: true
|
uint8(1), // approvalNeeded: true
|
||||||
|
originalTakerAddress // receiver from order
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check initial ONDO balance of receiver
|
||||||
|
uint256 initialOndoBalance = ONDO.balanceOf(originalTakerAddress);
|
||||||
|
|
||||||
uint256 amountOut = bebopExecutor.swap(testData.amountIn, params);
|
uint256 amountOut = bebopExecutor.swap(testData.amountIn, params);
|
||||||
|
|
||||||
// Verify partial fill results
|
// Verify partial fill results
|
||||||
@@ -324,11 +335,11 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
testData.expectedAmountOut,
|
testData.expectedAmountOut,
|
||||||
"Incorrect partial amount out"
|
"Incorrect partial amount out"
|
||||||
);
|
);
|
||||||
// The harness transfers tokens to the executor to simulate proper flow
|
// Since we're using real order data, tokens go to the original receiver
|
||||||
assertEq(
|
assertEq(
|
||||||
ONDO.balanceOf(address(bebopExecutor)),
|
ONDO.balanceOf(originalTakerAddress) - initialOndoBalance,
|
||||||
testData.expectedAmountOut,
|
testData.expectedAmountOut,
|
||||||
"ONDO should be in executor"
|
"ONDO should be at receiver"
|
||||||
);
|
);
|
||||||
assertEq(
|
assertEq(
|
||||||
USDC.balanceOf(address(bebopExecutor)), 0, "USDC left in executor"
|
USDC.balanceOf(address(bebopExecutor)), 0, "USDC left in executor"
|
||||||
@@ -448,9 +459,13 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(2), // partialFillOffset for swapAggregate (68 = 4 + 2*32)
|
uint8(2), // partialFillOffset for swapAggregate (68 = 4 + 2*32)
|
||||||
totalTakerAmount, // originalAmountIn
|
totalTakerAmount, // originalAmountIn
|
||||||
uint8(0) // approvalNeeded: false for native ETH
|
uint8(0), // approvalNeeded: false for native ETH
|
||||||
|
originalTakerAddress // receiver from order
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check initial USDC balance of receiver
|
||||||
|
uint256 initialUsdcBalance = USDC.balanceOf(originalTakerAddress);
|
||||||
|
|
||||||
// Execute the aggregate swap with ETH value
|
// Execute the aggregate swap with ETH value
|
||||||
uint256 amountOut = bebopExecutor.swap{value: totalTakerAmount}(
|
uint256 amountOut = bebopExecutor.swap{value: totalTakerAmount}(
|
||||||
totalTakerAmount, params
|
totalTakerAmount, params
|
||||||
@@ -458,11 +473,11 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
|
|
||||||
// Verify results
|
// Verify results
|
||||||
assertEq(amountOut, totalMakerAmount, "Incorrect amount out");
|
assertEq(amountOut, totalMakerAmount, "Incorrect amount out");
|
||||||
// The harness transfers tokens to the executor to simulate proper flow
|
// Since we're using real order data, tokens go to the original receiver
|
||||||
assertEq(
|
assertEq(
|
||||||
USDC.balanceOf(address(bebopExecutor)),
|
USDC.balanceOf(originalTakerAddress) - initialUsdcBalance,
|
||||||
totalMakerAmount,
|
totalMakerAmount,
|
||||||
"USDC should be in executor"
|
"USDC should be at receiver"
|
||||||
);
|
);
|
||||||
// ETH balance check - the harness may have different balance due to test setup
|
// ETH balance check - the harness may have different balance due to test setup
|
||||||
// Just ensure no excessive ETH is stuck
|
// Just ensure no excessive ETH is stuck
|
||||||
@@ -588,9 +603,13 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(2), // partialFillOffset for swapAggregate (68 = 4 + 2*32)
|
uint8(2), // partialFillOffset for swapAggregate (68 = 4 + 2*32)
|
||||||
totalTakerAmount, // originalAmountIn (full order amount)
|
totalTakerAmount, // originalAmountIn (full order amount)
|
||||||
uint8(0) // approvalNeeded: false for native ETH
|
uint8(0), // approvalNeeded: false for native ETH
|
||||||
|
originalTakerAddress // receiver from order
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check initial USDC balance of receiver
|
||||||
|
uint256 initialUsdcBalance = USDC.balanceOf(originalTakerAddress);
|
||||||
|
|
||||||
// Execute the partial aggregate swap with ETH value
|
// Execute the partial aggregate swap with ETH value
|
||||||
uint256 amountOut = bebopExecutor.swap{value: partialFillAmount}(
|
uint256 amountOut = bebopExecutor.swap{value: partialFillAmount}(
|
||||||
partialFillAmount, params
|
partialFillAmount, params
|
||||||
@@ -600,11 +619,11 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
assertEq(
|
assertEq(
|
||||||
amountOut, expectedPartialOutput, "Incorrect partial amount out"
|
amountOut, expectedPartialOutput, "Incorrect partial amount out"
|
||||||
);
|
);
|
||||||
// The harness transfers tokens to the executor to simulate proper flow
|
// Since we're using real order data, tokens go to the original receiver
|
||||||
assertEq(
|
assertEq(
|
||||||
USDC.balanceOf(address(bebopExecutor)),
|
USDC.balanceOf(originalTakerAddress) - initialUsdcBalance,
|
||||||
expectedPartialOutput,
|
expectedPartialOutput,
|
||||||
"USDC should be in executor"
|
"USDC should be at receiver"
|
||||||
);
|
);
|
||||||
// ETH balance check - the harness may have different balance due to test setup
|
// ETH balance check - the harness may have different balance due to test setup
|
||||||
// Just ensure no excessive ETH is stuck
|
// Just ensure no excessive ETH is stuck
|
||||||
@@ -637,7 +656,8 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
||||||
originalAmountIn,
|
originalAmountIn,
|
||||||
uint8(1) // approvalNeeded: true
|
uint8(1), // approvalNeeded: true
|
||||||
|
address(bebopExecutor)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify valid params work
|
// Verify valid params work
|
||||||
@@ -713,7 +733,8 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
uint8(12), // partialFillOffset for swapSingle (388 = 4 + 12*32)
|
||||||
uint256(200000000), // originalAmountIn
|
uint256(200000000), // originalAmountIn
|
||||||
uint8(1) // approvalNeeded: true
|
uint8(1), // approvalNeeded: true
|
||||||
|
originalTakerAddress // receiver from order
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deal 200 USDC to the executor
|
// Deal 200 USDC to the executor
|
||||||
@@ -727,16 +748,19 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
vm.prank(maker);
|
vm.prank(maker);
|
||||||
ONDO.approve(BEBOP_SETTLEMENT, expectedAmountOut);
|
ONDO.approve(BEBOP_SETTLEMENT, expectedAmountOut);
|
||||||
|
|
||||||
|
// Check initial ONDO balance of receiver
|
||||||
|
uint256 initialOndoBalance = ONDO.balanceOf(originalTakerAddress);
|
||||||
|
|
||||||
// Execute the swap
|
// Execute the swap
|
||||||
uint256 amountOut = bebopExecutor.swap(amountIn, protocolData);
|
uint256 amountOut = bebopExecutor.swap(amountIn, protocolData);
|
||||||
|
|
||||||
// Verify results
|
// Verify results
|
||||||
assertEq(amountOut, expectedAmountOut, "Incorrect amount out");
|
assertEq(amountOut, expectedAmountOut, "Incorrect amount out");
|
||||||
// The harness transfers tokens to the executor to simulate proper flow
|
// Since we're using historical data, tokens go to the original receiver
|
||||||
assertEq(
|
assertEq(
|
||||||
ONDO.balanceOf(address(bebopExecutor)),
|
ONDO.balanceOf(originalTakerAddress) - initialOndoBalance,
|
||||||
expectedAmountOut,
|
expectedAmountOut,
|
||||||
"ONDO should be in executor"
|
"ONDO should be at receiver"
|
||||||
);
|
);
|
||||||
assertEq(
|
assertEq(
|
||||||
USDC.balanceOf(address(bebopExecutor)), 0, "USDC left in executor"
|
USDC.balanceOf(address(bebopExecutor)), 0, "USDC left in executor"
|
||||||
@@ -834,7 +858,8 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
bebopCalldata,
|
bebopCalldata,
|
||||||
uint8(2), // partialFillOffset for swapAggregate (68 = 4 + 2*32)
|
uint8(2), // partialFillOffset for swapAggregate (68 = 4 + 2*32)
|
||||||
ethAmount, // originalAmountIn
|
ethAmount, // originalAmountIn
|
||||||
uint8(0) // approvalNeeded: false for native ETH
|
uint8(0), // approvalNeeded: false for native ETH
|
||||||
|
orderTaker // receiver from order
|
||||||
);
|
);
|
||||||
|
|
||||||
// Fund the two makers from the real transaction with USDC
|
// Fund the two makers from the real transaction with USDC
|
||||||
@@ -854,17 +879,20 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
vm.deal(ALICE, ethAmount);
|
vm.deal(ALICE, ethAmount);
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
|
|
||||||
|
// Check initial USDC balance of receiver
|
||||||
|
uint256 initialUsdcBalance = IERC20(USDC_ADDR).balanceOf(orderTaker);
|
||||||
|
|
||||||
// Execute the swap with native ETH
|
// Execute the swap with native ETH
|
||||||
uint256 amountOut =
|
uint256 amountOut =
|
||||||
bebopExecutor.swap{value: ethAmount}(ethAmount, protocolData);
|
bebopExecutor.swap{value: ethAmount}(ethAmount, protocolData);
|
||||||
|
|
||||||
// Verify results
|
// Verify results
|
||||||
assertEq(amountOut, expAmountOut, "Incorrect amount out");
|
assertEq(amountOut, expAmountOut, "Incorrect amount out");
|
||||||
// The harness transfers tokens to the executor to simulate proper flow
|
// Since we're using historical data, tokens go to the original receiver
|
||||||
assertEq(
|
assertEq(
|
||||||
IERC20(USDC_ADDR).balanceOf(address(bebopExecutor)),
|
IERC20(USDC_ADDR).balanceOf(orderTaker) - initialUsdcBalance,
|
||||||
expAmountOut,
|
expAmountOut,
|
||||||
"USDC should be in executor"
|
"USDC should be at receiver"
|
||||||
);
|
);
|
||||||
// ETH balance check - the harness may have different balance due to test setup
|
// ETH balance check - the harness may have different balance due to test setup
|
||||||
// Just ensure no excessive ETH is stuck
|
// Just ensure no excessive ETH is stuck
|
||||||
@@ -876,202 +904,6 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test exposed_getActualFilledTakerAmount function
|
|
||||||
function testGetActualFilledTakerAmount_FilledLessThanGiven() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// When filledTakerAmount < givenAmount
|
|
||||||
// Should return filledTakerAmount
|
|
||||||
uint256 givenAmount = 1000e18;
|
|
||||||
uint256 filledTakerAmount = 700e18;
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result,
|
|
||||||
filledTakerAmount,
|
|
||||||
"Should return filledTakerAmount when less than givenAmount"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetActualFilledTakerAmount_FilledGreaterThanGiven() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// When filledTakerAmount > givenAmount
|
|
||||||
// Should return givenAmount (capped)
|
|
||||||
uint256 givenAmount = 500e18;
|
|
||||||
uint256 filledTakerAmount = 700e18;
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result,
|
|
||||||
givenAmount,
|
|
||||||
"Should return givenAmount when filledTakerAmount exceeds it"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetActualFilledTakerAmount_FilledEqualsGiven() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// When filledTakerAmount == givenAmount
|
|
||||||
// Should return filledTakerAmount
|
|
||||||
uint256 givenAmount = 700e18;
|
|
||||||
uint256 filledTakerAmount = 700e18;
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result,
|
|
||||||
filledTakerAmount,
|
|
||||||
"Should return filledTakerAmount when equal to givenAmount"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetActualFilledTakerAmount_ZeroGivenAmount() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// When givenAmount is 0
|
|
||||||
// Should always return 0 regardless of filledTakerAmount
|
|
||||||
uint256 givenAmount = 0;
|
|
||||||
uint256 filledTakerAmount = 100e18;
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(result, 0, "Should return 0 when givenAmount is 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetActualFilledTakerAmount_ZeroFilledTakerAmount() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// When filledTakerAmount is 0 (encoder should prevent this, but test edge case)
|
|
||||||
// Should return 0
|
|
||||||
uint256 givenAmount = 1000e18;
|
|
||||||
uint256 filledTakerAmount = 0;
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(result, 0, "Should return 0 when filledTakerAmount is 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetActualFilledTakerAmount_SmallAmounts() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// Test with small amounts (e.g., for tokens with low decimals)
|
|
||||||
uint256 givenAmount = 100; // 100 units
|
|
||||||
uint256 filledTakerAmount = 50; // 50 units
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result, filledTakerAmount, "Should handle small amounts correctly"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test when filledTakerAmount exceeds givenAmount
|
|
||||||
filledTakerAmount = 150;
|
|
||||||
result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result, givenAmount, "Should cap at givenAmount for small amounts"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetActualFilledTakerAmount_MaxUint256Values() public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
// Test with max uint256 values (edge case)
|
|
||||||
uint256 givenAmount = type(uint256).max;
|
|
||||||
uint256 filledTakerAmount = type(uint256).max - 1;
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result, filledTakerAmount, "Should handle max values correctly"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test with filledTakerAmount exceeding givenAmount
|
|
||||||
givenAmount = type(uint256).max - 100;
|
|
||||||
filledTakerAmount = type(uint256).max;
|
|
||||||
result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEq(
|
|
||||||
result,
|
|
||||||
givenAmount,
|
|
||||||
"Should cap at givenAmount even with max filledTakerAmount"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testFuzzGetActualFilledTakerAmount(
|
|
||||||
uint256 givenAmount,
|
|
||||||
uint256 filledTakerAmount
|
|
||||||
) public {
|
|
||||||
// Deploy Bebop executor harness
|
|
||||||
bebopExecutor =
|
|
||||||
new BebopExecutorHarness(BEBOP_SETTLEMENT, PERMIT2_ADDRESS);
|
|
||||||
|
|
||||||
uint256 result = bebopExecutor.exposed_getActualFilledTakerAmount(
|
|
||||||
givenAmount, filledTakerAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the invariants
|
|
||||||
// Result should be min(givenAmount, filledTakerAmount)
|
|
||||||
if (filledTakerAmount > givenAmount) {
|
|
||||||
assertEq(
|
|
||||||
result,
|
|
||||||
givenAmount,
|
|
||||||
"Should return givenAmount when filledTakerAmount > givenAmount"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
assertEq(
|
|
||||||
result,
|
|
||||||
filledTakerAmount,
|
|
||||||
"Should return filledTakerAmount when filledTakerAmount <= givenAmount"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result should never exceed givenAmount
|
|
||||||
assertLe(result, givenAmount, "Result should never exceed givenAmount");
|
|
||||||
|
|
||||||
// Result should never exceed filledTakerAmount
|
|
||||||
assertLe(
|
|
||||||
result,
|
|
||||||
filledTakerAmount,
|
|
||||||
"Result should never exceed filledTakerAmount"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test exposed_modifyFilledTakerAmount function
|
// Test exposed_modifyFilledTakerAmount function
|
||||||
function testModifyFilledTakerAmount_SingleOrder() public {
|
function testModifyFilledTakerAmount_SingleOrder() public {
|
||||||
// Deploy Bebop executor harness
|
// Deploy Bebop executor harness
|
||||||
@@ -1108,7 +940,10 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
|
|
||||||
bytes memory modifiedCalldata = bebopExecutor
|
bytes memory modifiedCalldata = bebopExecutor
|
||||||
.exposed_modifyFilledTakerAmount(
|
.exposed_modifyFilledTakerAmount(
|
||||||
originalCalldata, givenAmount, originalAmountIn, 12 // partialFillOffset for swapSingle
|
originalCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalAmountIn,
|
||||||
|
12 // partialFillOffset for swapSingle
|
||||||
);
|
);
|
||||||
|
|
||||||
// Decode the modified calldata to verify the filledTakerAmount was updated
|
// Decode the modified calldata to verify the filledTakerAmount was updated
|
||||||
@@ -1184,7 +1019,10 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
|
|
||||||
bytes memory modifiedCalldata = bebopExecutor
|
bytes memory modifiedCalldata = bebopExecutor
|
||||||
.exposed_modifyFilledTakerAmount(
|
.exposed_modifyFilledTakerAmount(
|
||||||
originalCalldata, givenAmount, originalAmountIn, 2 // partialFillOffset for swapAggregate
|
originalCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalAmountIn,
|
||||||
|
2 // partialFillOffset for swapAggregate
|
||||||
);
|
);
|
||||||
|
|
||||||
// Decode the modified calldata to verify the filledTakerAmount was updated
|
// Decode the modified calldata to verify the filledTakerAmount was updated
|
||||||
@@ -1243,7 +1081,10 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
// So we'll test that it properly sets the value we want
|
// So we'll test that it properly sets the value we want
|
||||||
bytes memory modifiedCalldata = bebopExecutor
|
bytes memory modifiedCalldata = bebopExecutor
|
||||||
.exposed_modifyFilledTakerAmount(
|
.exposed_modifyFilledTakerAmount(
|
||||||
originalCalldata, givenAmount, originalAmountIn, 12 // partialFillOffset for swapSingle
|
originalCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalAmountIn,
|
||||||
|
12 // partialFillOffset for swapSingle
|
||||||
);
|
);
|
||||||
|
|
||||||
// Extract the new filledTakerAmount
|
// Extract the new filledTakerAmount
|
||||||
@@ -1259,7 +1100,10 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
|||||||
// Normal test - amounts match so calldata should be unchanged
|
// Normal test - amounts match so calldata should be unchanged
|
||||||
bytes memory modifiedCalldata = bebopExecutor
|
bytes memory modifiedCalldata = bebopExecutor
|
||||||
.exposed_modifyFilledTakerAmount(
|
.exposed_modifyFilledTakerAmount(
|
||||||
originalCalldata, givenAmount, originalAmountIn, 12 // partialFillOffset for swapSingle
|
originalCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalAmountIn,
|
||||||
|
12 // partialFillOffset for swapSingle
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEq(
|
assertEq(
|
||||||
|
|||||||
@@ -60,21 +60,13 @@ contract BebopExecutorHarness is BebopExecutor, Test {
|
|||||||
bytes memory bebopCalldata,
|
bytes memory bebopCalldata,
|
||||||
uint8 partialFillOffset,
|
uint8 partialFillOffset,
|
||||||
uint256 originalFilledTakerAmount,
|
uint256 originalFilledTakerAmount,
|
||||||
bool approvalNeeded
|
bool approvalNeeded,
|
||||||
|
address receiver
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No longer needed since we inlined the logic
|
|
||||||
function exposed_getActualFilledTakerAmount(
|
|
||||||
uint256 givenAmount,
|
|
||||||
uint256 filledTakerAmount
|
|
||||||
) external pure returns (uint256 actualFilledTakerAmount) {
|
|
||||||
// Inline the simple logic here for backward compatibility
|
|
||||||
actualFilledTakerAmount = filledTakerAmount > givenAmount ? givenAmount : filledTakerAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expose the internal modifyFilledTakerAmount function for testing
|
// Expose the internal modifyFilledTakerAmount function for testing
|
||||||
function exposed_modifyFilledTakerAmount(
|
function exposed_modifyFilledTakerAmount(
|
||||||
bytes memory bebopCalldata,
|
bytes memory bebopCalldata,
|
||||||
@@ -83,7 +75,10 @@ contract BebopExecutorHarness is BebopExecutor, Test {
|
|||||||
uint8 partialFillOffset
|
uint8 partialFillOffset
|
||||||
) external pure returns (bytes memory) {
|
) external pure returns (bytes memory) {
|
||||||
return _modifyFilledTakerAmount(
|
return _modifyFilledTakerAmount(
|
||||||
bebopCalldata, givenAmount, originalFilledTakerAmount, partialFillOffset
|
bebopCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalFilledTakerAmount,
|
||||||
|
partialFillOffset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +97,8 @@ contract BebopExecutorHarness is BebopExecutor, Test {
|
|||||||
bytes memory bebopCalldata,
|
bytes memory bebopCalldata,
|
||||||
, // partialFillOffset not needed in test harness
|
, // partialFillOffset not needed in test harness
|
||||||
uint256 originalFilledTakerAmount,
|
uint256 originalFilledTakerAmount,
|
||||||
|
, // approvalNeeded not needed in test harness
|
||||||
|
// receiver not needed since we extract it from bebop calldata
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
// Extract taker address, receiver, and expiry from bebop calldata
|
// Extract taker address, receiver, and expiry from bebop calldata
|
||||||
@@ -139,16 +136,13 @@ contract BebopExecutorHarness is BebopExecutor, Test {
|
|||||||
expiry = order.expiry;
|
expiry = order.expiry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline the simple logic since _getActualFilledTakerAmount was removed
|
uint256 actualFilledTakerAmount = originalFilledTakerAmount
|
||||||
uint256 actualFilledTakerAmount =
|
> givenAmount ? givenAmount : originalFilledTakerAmount;
|
||||||
originalFilledTakerAmount > givenAmount ? givenAmount : originalFilledTakerAmount;
|
|
||||||
|
|
||||||
// For testing: transfer tokens from executor to taker address
|
// For testing: transfer tokens from executor to taker address
|
||||||
// This simulates the taker having the tokens with approval
|
// This simulates the taker having the tokens with approval
|
||||||
if (tokenIn != address(0)) {
|
if (tokenIn != address(0)) {
|
||||||
_transfer(
|
// The executor already has the tokens from the test, just transfer to taker
|
||||||
address(this), transferType, tokenIn, actualFilledTakerAmount
|
|
||||||
);
|
|
||||||
IERC20(tokenIn).safeTransfer(takerAddress, actualFilledTakerAmount);
|
IERC20(tokenIn).safeTransfer(takerAddress, actualFilledTakerAmount);
|
||||||
|
|
||||||
// Approve settlement from taker's perspective
|
// Approve settlement from taker's perspective
|
||||||
|
|||||||
Reference in New Issue
Block a user