chore: improve test assertion and function ordering
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user