chore: improve test assertion and function ordering

This commit is contained in:
pedrobergamini
2025-06-23 14:38:57 -03:00
parent 7cf3f268c1
commit 80c2ef7881
3 changed files with 182 additions and 173 deletions

View File

@@ -140,161 +140,6 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
}
}
/**
* @dev Determines the actual taker amount to be filled for a Bebop order
* @notice This function handles two scenarios:
* 1. When filledTakerAmount is 0: Uses the full order amount if givenAmount is sufficient,
* otherwise returns givenAmount to partially fill the order
* 2. When filledTakerAmount > 0: Caps the fill at the minimum of filledTakerAmount and givenAmount
* to ensure we don't attempt to fill more than available
* @param givenAmount The amount of tokens available from the router for this swap
* @param orderTakerAmount The full taker amount specified in the Bebop order
* @param filledTakerAmount The requested fill amount (0 means fill entire order)
* @return actualFilledTakerAmount The amount that will actually be filled
*/
function _getActualFilledTakerAmount(
uint256 givenAmount,
uint256 orderTakerAmount,
uint256 filledTakerAmount
) internal pure returns (uint256 actualFilledTakerAmount) {
actualFilledTakerAmount = filledTakerAmount == 0
? (givenAmount >= orderTakerAmount ? orderTakerAmount : givenAmount)
: (filledTakerAmount > givenAmount ? givenAmount : filledTakerAmount);
}
/// @dev Executes a Single RFQ swap through Bebop settlement
function _executeSingleRFQ(
address tokenIn,
address tokenOut,
TransferType transferType,
uint256 givenAmount,
uint256 filledTakerAmount,
bytes memory quoteData,
bytes memory makerSignaturesData,
bool approvalNeeded
) internal virtual returns (uint256 amountOut) {
// Decode the order from quoteData
IBebopSettlement.Single memory order =
abi.decode(quoteData, (IBebopSettlement.Single));
// Decode the MakerSignature array (should contain exactly 1 signature for Single orders)
IBebopSettlement.MakerSignature[] memory signatures =
abi.decode(makerSignaturesData, (IBebopSettlement.MakerSignature[]));
// Validate that there is exactly one maker signature
if (signatures.length != 1) {
revert BebopExecutor__InvalidInput();
}
// Get the maker signature from the first and only element of the array
IBebopSettlement.MakerSignature memory sig = signatures[0];
uint256 actualFilledTakerAmount = _getActualFilledTakerAmount(
givenAmount, order.taker_amount, filledTakerAmount
);
if (tokenIn != address(0)) {
// Transfer tokens to executor
_transfer(address(this), transferType, tokenIn, givenAmount);
}
// Approve Bebop settlement to spend tokens if needed
if (approvalNeeded) {
// slither-disable-next-line unused-return
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
}
// Record balances before swap to calculate amountOut
uint256 balanceBefore = tokenOut == address(0)
? order.receiver.balance
: IERC20(tokenOut).balanceOf(order.receiver);
// Execute the swap with ETH value if needed
uint256 ethValue = tokenIn == address(0) ? actualFilledTakerAmount : 0;
// Use swapSingle since tokens are in the executor with approval
// slither-disable-next-line arbitrary-send-eth
IBebopSettlement(bebopSettlement).swapSingle{value: ethValue}(
order, sig, actualFilledTakerAmount
);
// Calculate actual amount received
uint256 balanceAfter = tokenOut == address(0)
? order.receiver.balance
: IERC20(tokenOut).balanceOf(order.receiver);
amountOut = balanceAfter - balanceBefore;
}
/// @dev Executes an Aggregate RFQ swap through Bebop settlement
function _executeAggregateRFQ(
address tokenIn,
address tokenOut,
TransferType transferType,
uint256 givenAmount,
uint256 filledTakerAmount,
bytes memory quoteData,
bytes memory makerSignaturesData,
bool approvalNeeded
) internal virtual returns (uint256 amountOut) {
// Decode the Aggregate order
IBebopSettlement.Aggregate memory order =
abi.decode(quoteData, (IBebopSettlement.Aggregate));
// Decode the MakerSignature array (can contain multiple signatures for Aggregate orders)
IBebopSettlement.MakerSignature[] memory signatures =
abi.decode(makerSignaturesData, (IBebopSettlement.MakerSignature[]));
// Aggregate orders should have at least one signature
if (signatures.length == 0) {
revert BebopExecutor__InvalidInput();
}
// 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
);
if (tokenIn != address(0)) {
// Transfer tokens to executor
_transfer(address(this), transferType, tokenIn, givenAmount);
}
// Approve Bebop settlement to spend tokens if needed
if (approvalNeeded) {
// slither-disable-next-line unused-return
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
}
// Record balance before swap
uint256 balanceBefore = tokenOut == address(0)
? order.receiver.balance
: IERC20(tokenOut).balanceOf(order.receiver);
// Execute the swap
uint256 ethValue = tokenIn == address(0) ? actualFilledTakerAmount : 0;
// Execute the swap (tokens are in executor, approved to settlement)
// slither-disable-next-line arbitrary-send-eth
IBebopSettlement(bebopSettlement).swapAggregate{value: ethValue}(
order, signatures, actualFilledTakerAmount
);
// Calculate actual amount received
uint256 balanceAfter = tokenOut == address(0)
? order.receiver.balance
: IERC20(tokenOut).balanceOf(order.receiver);
amountOut = balanceAfter - balanceBefore;
}
/// @dev Decodes the packed calldata
function _decodeData(bytes calldata data)
internal
@@ -349,4 +194,165 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
// Extract approval flag
approvalNeeded = data[82 + quoteDataLength + makerSignaturesLength] != 0;
}
/// @dev Executes a Single RFQ swap through Bebop settlement
function _executeSingleRFQ(
address tokenIn,
address tokenOut,
TransferType transferType,
uint256 givenAmount,
uint256 filledTakerAmount,
bytes memory quoteData,
bytes memory makerSignaturesData,
bool approvalNeeded
) internal virtual returns (uint256 amountOut) {
// Decode the order from quoteData
IBebopSettlement.Single memory order =
abi.decode(quoteData, (IBebopSettlement.Single));
// Decode the MakerSignature array (should contain exactly 1 signature for Single orders)
IBebopSettlement.MakerSignature[] memory signatures =
abi.decode(makerSignaturesData, (IBebopSettlement.MakerSignature[]));
// Validate that there is exactly one maker signature
if (signatures.length != 1) {
revert BebopExecutor__InvalidInput();
}
// Get the maker signature from the first and only element of the array
IBebopSettlement.MakerSignature memory sig = signatures[0];
uint256 actualFilledTakerAmount = _getActualFilledTakerAmount(
givenAmount, order.taker_amount, filledTakerAmount
);
if (tokenIn != address(0)) {
// Transfer tokens to executor
_transfer(address(this), transferType, tokenIn, givenAmount);
}
// Approve Bebop settlement to spend tokens if needed
if (approvalNeeded) {
// slither-disable-next-line unused-return
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
}
// Record balances before swap to calculate amountOut
uint256 balanceBefore = _balanceOf(tokenOut, order.receiver);
// Execute the swap with ETH value if needed
uint256 ethValue = tokenIn == address(0) ? actualFilledTakerAmount : 0;
// Use swapSingle since tokens are in the executor with approval
// slither-disable-next-line arbitrary-send-eth
IBebopSettlement(bebopSettlement).swapSingle{value: ethValue}(
order, sig, actualFilledTakerAmount
);
// Calculate actual amount received
uint256 balanceAfter = _balanceOf(tokenOut, order.receiver);
amountOut = balanceAfter - balanceBefore;
}
/// @dev Executes an Aggregate RFQ swap through Bebop settlement
function _executeAggregateRFQ(
address tokenIn,
address tokenOut,
TransferType transferType,
uint256 givenAmount,
uint256 filledTakerAmount,
bytes memory quoteData,
bytes memory makerSignaturesData,
bool approvalNeeded
) internal virtual returns (uint256 amountOut) {
// Decode the Aggregate order
IBebopSettlement.Aggregate memory order =
abi.decode(quoteData, (IBebopSettlement.Aggregate));
// Decode the MakerSignature array (can contain multiple signatures for Aggregate orders)
IBebopSettlement.MakerSignature[] memory signatures =
abi.decode(makerSignaturesData, (IBebopSettlement.MakerSignature[]));
// Aggregate orders should have at least one signature
if (signatures.length == 0) {
revert BebopExecutor__InvalidInput();
}
// 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
);
if (tokenIn != address(0)) {
// Transfer tokens to executor
_transfer(address(this), transferType, tokenIn, givenAmount);
}
// Approve Bebop settlement to spend tokens if needed
if (approvalNeeded) {
// slither-disable-next-line unused-return
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
}
// Record balance before swap
uint256 balanceBefore = _balanceOf(tokenOut, order.receiver);
// Execute the swap
uint256 ethValue = tokenIn == address(0) ? actualFilledTakerAmount : 0;
// Execute the swap (tokens are in executor, approved to settlement)
// slither-disable-next-line arbitrary-send-eth
IBebopSettlement(bebopSettlement).swapAggregate{value: ethValue}(
order, signatures, actualFilledTakerAmount
);
// Calculate actual amount received
uint256 balanceAfter = _balanceOf(tokenOut, order.receiver);
amountOut = balanceAfter - balanceBefore;
}
/**
* @dev Determines the actual taker amount to be filled for a Bebop order
* @notice This function handles two scenarios:
* 1. When filledTakerAmount is 0: Uses the full order amount if givenAmount is sufficient,
* otherwise returns givenAmount to partially fill the order
* 2. When filledTakerAmount > 0: Caps the fill at the minimum of filledTakerAmount and givenAmount
* to ensure we don't attempt to fill more than available
* @param givenAmount The amount of tokens available from the router for this swap
* @param orderTakerAmount The full taker amount specified in the Bebop order
* @param filledTakerAmount The requested fill amount (0 means fill entire order)
* @return actualFilledTakerAmount The amount that will actually be filled
*/
function _getActualFilledTakerAmount(
uint256 givenAmount,
uint256 orderTakerAmount,
uint256 filledTakerAmount
) internal pure returns (uint256 actualFilledTakerAmount) {
actualFilledTakerAmount = filledTakerAmount == 0
? (givenAmount >= orderTakerAmount ? orderTakerAmount : givenAmount)
: (filledTakerAmount > givenAmount ? givenAmount : filledTakerAmount);
}
/// @dev Returns the balance of a token or ETH for an account
/// @param token The token address, or address(0) for ETH
/// @param account The account to get the balance of
/// @return balance The balance of the token or ETH for the account
function _balanceOf(address token, address account)
internal
view
returns (uint256)
{
return token == address(0)
? account.balance
: IERC20(token).balanceOf(account);
}
}