chore: refactor Aggregate orders, fix Single orders integration tests and calldata generation
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@src/executors/BebopExecutor.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
/**
|
||||
* @title BebopSettlementMock
|
||||
* @notice Mock Bebop settlement contract that skips taker_address validation
|
||||
* @dev This is used for testing purposes to work around the msg.sender == taker_address check
|
||||
* while maintaining all other Bebop settlement logic
|
||||
*/
|
||||
contract BebopSettlementMock {
|
||||
error InvalidSignature();
|
||||
error OrderExpired();
|
||||
error InsufficientMakerBalance();
|
||||
|
||||
// Nonce tracking to prevent replay attacks
|
||||
mapping(address => mapping(uint256 => bool)) public makerNonceUsed;
|
||||
|
||||
function swapSingle(
|
||||
IBebopSettlement.Single calldata order,
|
||||
IBebopSettlement.MakerSignature calldata makerSignature,
|
||||
uint256 filledTakerAmount
|
||||
) external payable {
|
||||
// Check order expiry
|
||||
if (block.timestamp > order.expiry) revert OrderExpired();
|
||||
|
||||
// Check nonce hasn't been used
|
||||
if (makerNonceUsed[order.maker_address][order.maker_nonce]) {
|
||||
revert InvalidSignature();
|
||||
}
|
||||
|
||||
// IMPORTANT: We skip the taker_address validation that would normally be here:
|
||||
// if (msg.sender != order.taker_address) revert InvalidCaller();
|
||||
|
||||
// For testing, we'll do a simplified signature validation
|
||||
// In reality, Bebop would validate the full order signature
|
||||
// Accept both proper 65-byte signatures and test placeholders
|
||||
if (makerSignature.signatureBytes.length < 4) {
|
||||
revert InvalidSignature();
|
||||
}
|
||||
|
||||
// Mark nonce as used
|
||||
makerNonceUsed[order.maker_address][order.maker_nonce] = true;
|
||||
|
||||
// Calculate amounts
|
||||
uint256 actualTakerAmount =
|
||||
filledTakerAmount == 0 ? order.taker_amount : filledTakerAmount;
|
||||
uint256 actualMakerAmount = filledTakerAmount == 0
|
||||
? order.maker_amount
|
||||
: (order.maker_amount * filledTakerAmount) / order.taker_amount;
|
||||
|
||||
// Transfer taker tokens from msg.sender to maker
|
||||
if (order.taker_token == address(0)) {
|
||||
// ETH transfer
|
||||
require(msg.value == actualTakerAmount, "Incorrect ETH amount");
|
||||
payable(order.maker_address).transfer(actualTakerAmount);
|
||||
} else {
|
||||
// ERC20 transfer
|
||||
IERC20(order.taker_token).transferFrom(
|
||||
msg.sender, order.maker_address, actualTakerAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Transfer maker tokens from maker to receiver
|
||||
if (order.maker_token == address(0)) {
|
||||
// ETH transfer - this shouldn't happen in practice
|
||||
revert("ETH output not supported");
|
||||
} else {
|
||||
// In the real contract, maker would need to have tokens and approve
|
||||
// For testing, we'll check if maker has balance, if not we assume they're funded
|
||||
uint256 makerBalance =
|
||||
IERC20(order.maker_token).balanceOf(order.maker_address);
|
||||
if (makerBalance < actualMakerAmount) {
|
||||
revert InsufficientMakerBalance();
|
||||
}
|
||||
|
||||
// Transfer from maker to receiver
|
||||
// This assumes the maker has pre-approved the settlement contract
|
||||
IERC20(order.maker_token).transferFrom(
|
||||
order.maker_address, order.receiver, actualMakerAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function swapAggregate(
|
||||
IBebopSettlement.Aggregate calldata order,
|
||||
IBebopSettlement.MakerSignature[] calldata makerSignatures,
|
||||
uint256 filledTakerAmount
|
||||
) external payable {
|
||||
// Check order expiry
|
||||
if (block.timestamp > order.expiry) revert OrderExpired();
|
||||
|
||||
// Check we have at least one maker
|
||||
if (makerSignatures.length == 0) revert InvalidSignature();
|
||||
|
||||
// For testing, we'll do a simplified signature validation
|
||||
for (uint256 i = 0; i < makerSignatures.length; i++) {
|
||||
if (makerSignatures[i].signatureBytes.length < 4) {
|
||||
revert InvalidSignature();
|
||||
}
|
||||
}
|
||||
|
||||
// Aggregate orders only support full fills
|
||||
require(
|
||||
filledTakerAmount == 0,
|
||||
"Partial fills not supported for aggregate orders"
|
||||
);
|
||||
|
||||
// Transfer taker tokens from msg.sender to makers
|
||||
for (uint256 i = 0; i < order.taker_tokens.length; i++) {
|
||||
uint256 takerAmount = order.taker_amounts[i];
|
||||
// Split proportionally among makers
|
||||
for (uint256 j = 0; j < order.maker_addresses.length; j++) {
|
||||
uint256 makerShare = takerAmount / order.maker_addresses.length;
|
||||
if (j == order.maker_addresses.length - 1) {
|
||||
// Last maker gets any remainder
|
||||
makerShare = takerAmount
|
||||
- (makerShare * (order.maker_addresses.length - 1));
|
||||
}
|
||||
IERC20(order.taker_tokens[i]).transferFrom(
|
||||
msg.sender, order.maker_addresses[j], makerShare
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer maker tokens from each maker to receiver
|
||||
for (uint256 i = 0; i < order.maker_addresses.length; i++) {
|
||||
address maker = order.maker_addresses[i];
|
||||
|
||||
// Fund maker with tokens if they don't have enough (for testing)
|
||||
for (uint256 j = 0; j < order.maker_tokens[i].length; j++) {
|
||||
address token = order.maker_tokens[i][j];
|
||||
uint256 amount = order.maker_amounts[i][j];
|
||||
|
||||
uint256 makerBalance = IERC20(token).balanceOf(maker);
|
||||
if (makerBalance < amount) {
|
||||
revert InsufficientMakerBalance();
|
||||
}
|
||||
|
||||
// Transfer from maker to receiver
|
||||
IERC20(token).transferFrom(maker, order.receiver, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user