chore: fix single encoding bebop tests
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
SafeERC20
|
SafeERC20
|
||||||
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
import "@openzeppelin/contracts/utils/Address.sol";
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
|
import {console} from "forge-std/Test.sol";
|
||||||
|
|
||||||
/// @dev Bebop settlement interface for PMM RFQ swaps
|
/// @dev Bebop settlement interface for PMM RFQ swaps
|
||||||
interface IBebopSettlement {
|
interface IBebopSettlement {
|
||||||
@@ -147,8 +148,40 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
// 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;
|
||||||
|
|
||||||
|
// Debug: Check msg.sender before settlement call
|
||||||
|
console.log(
|
||||||
|
"BebopExecutor: About to call settlement, msg.sender:", msg.sender
|
||||||
|
);
|
||||||
|
|
||||||
|
// Debug: Let's check what's in the calldata
|
||||||
|
bytes4 selector = _getSelector(finalCalldata);
|
||||||
|
if (selector == SWAP_AGGREGATE_SELECTOR) {
|
||||||
|
// Try to extract taker_address from the aggregate order
|
||||||
|
if (finalCalldata.length > 100) {
|
||||||
|
// Read the offset to the order struct
|
||||||
|
uint256 orderOffset;
|
||||||
|
assembly {
|
||||||
|
orderOffset := mload(add(finalCalldata, 0x24))
|
||||||
|
}
|
||||||
|
// The taker_address is at orderOffset + 4 (selector) + 32 (after expiry)
|
||||||
|
address orderTaker;
|
||||||
|
assembly {
|
||||||
|
orderTaker :=
|
||||||
|
mload(add(finalCalldata, add(0x24, add(orderOffset, 32))))
|
||||||
|
}
|
||||||
|
console.log("Order taker_address in calldata:", orderTaker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use OpenZeppelin's Address library for safe call with value
|
// Use OpenZeppelin's Address library for safe call with value
|
||||||
bebopSettlement.functionCallWithValue(finalCalldata, ethValue);
|
// This will revert if the call fails
|
||||||
|
bytes memory returnData =
|
||||||
|
bebopSettlement.functionCallWithValue(finalCalldata, ethValue);
|
||||||
|
|
||||||
|
// Check if any tokens were actually transferred
|
||||||
|
if (returnData.length > 0) {
|
||||||
|
// Bebop might return some data, log it for debugging
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate actual amount received by the receiver
|
// Calculate actual amount received by the receiver
|
||||||
uint256 balanceAfter = _balanceOf(tokenOut, receiver);
|
uint256 balanceAfter = _balanceOf(tokenOut, receiver);
|
||||||
@@ -170,39 +203,29 @@ contract BebopExecutor is IExecutor, IExecutorErrors, RestrictTransferFrom {
|
|||||||
address receiver
|
address receiver
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Need at least 99 bytes for the minimum fixed fields
|
// Need at least 95 bytes for the minimum fixed fields
|
||||||
// 20 + 20 + 1 + 4 (calldata length) + 1 (offset) + 32 (original amount) + 1 (approval) + 20 (receiver) = 99
|
// 20 + 20 + 1 + 1 (offset) + 32 (original amount) + 1 (approval) + 20 (receiver) = 95
|
||||||
if (data.length < 99) revert BebopExecutor__InvalidDataLength();
|
if (data.length < 95) revert BebopExecutor__InvalidDataLength();
|
||||||
|
|
||||||
// Decode fixed fields
|
// Decode fixed fields
|
||||||
tokenIn = address(bytes20(data[0:20]));
|
tokenIn = address(bytes20(data[0:20]));
|
||||||
tokenOut = address(bytes20(data[20:40]));
|
tokenOut = address(bytes20(data[20:40]));
|
||||||
transferType = TransferType(uint8(data[40]));
|
transferType = TransferType(uint8(data[40]));
|
||||||
|
|
||||||
// Get bebop calldata length and validate
|
|
||||||
uint32 bebopCalldataLength = uint32(bytes4(data[41:45]));
|
|
||||||
if (data.length != 99 + bebopCalldataLength) {
|
|
||||||
revert BebopExecutor__InvalidDataLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract bebop calldata
|
|
||||||
bebopCalldata = data[45:45 + bebopCalldataLength];
|
|
||||||
|
|
||||||
// Extract partial fill offset
|
// Extract partial fill offset
|
||||||
partialFillOffset = uint8(data[45 + bebopCalldataLength]);
|
partialFillOffset = uint8(data[41]);
|
||||||
|
|
||||||
// Extract original amount in
|
// Extract original amount in
|
||||||
originalFilledTakerAmount = uint256(
|
originalFilledTakerAmount = uint256(bytes32(data[42:74]));
|
||||||
bytes32(data[46 + bebopCalldataLength:78 + bebopCalldataLength])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extract approval flag
|
// Extract approval flag
|
||||||
approvalNeeded = data[78 + bebopCalldataLength] != 0;
|
approvalNeeded = data[74] != 0;
|
||||||
|
|
||||||
// Extract receiver address
|
// Extract receiver address
|
||||||
receiver = address(
|
receiver = address(bytes20(data[75:95]));
|
||||||
bytes20(data[79 + bebopCalldataLength:99 + bebopCalldataLength])
|
|
||||||
);
|
// Extract bebop calldata (all remaining bytes)
|
||||||
|
bebopCalldata = data[95:];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Modifies the filledTakerAmount in the bebop calldata to handle slippage
|
/// @dev Modifies the filledTakerAmount in the bebop calldata to handle slippage
|
||||||
|
|||||||
@@ -526,10 +526,9 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
|
|
||||||
// Now using 0.099 WETH to get approximately 200 USDC from UniswapV3
|
// Now using 0.099 WETH to get approximately 200 USDC from UniswapV3
|
||||||
uint256 wethAmount = 99000000000000000; // 0.099 WETH
|
uint256 wethAmount = 99000000000000000; // 0.099 WETH
|
||||||
deal(WETH_ADDR, ALICE, wethAmount);
|
address orderTaker = 0xc5564C13A157E6240659fb81882A28091add8670; // Must match Bebop order taker
|
||||||
uint256 balanceBefore = IERC20(ONDO_ADDR).balanceOf(
|
deal(WETH_ADDR, orderTaker, wethAmount);
|
||||||
0xc5564C13A157E6240659fb81882A28091add8670
|
uint256 balanceBefore = IERC20(ONDO_ADDR).balanceOf(orderTaker);
|
||||||
);
|
|
||||||
|
|
||||||
// Fund the Bebop maker with ONDO and approve settlement
|
// Fund the Bebop maker with ONDO and approve settlement
|
||||||
uint256 ondoAmount = 237212396774431060000; // From the real order
|
uint256 ondoAmount = 237212396774431060000; // From the real order
|
||||||
@@ -537,17 +536,15 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
vm.prank(0xCe79b081c0c924cb67848723ed3057234d10FC6b);
|
vm.prank(0xCe79b081c0c924cb67848723ed3057234d10FC6b);
|
||||||
IERC20(ONDO_ADDR).approve(BEBOP_SETTLEMENT, ondoAmount);
|
IERC20(ONDO_ADDR).approve(BEBOP_SETTLEMENT, ondoAmount);
|
||||||
|
|
||||||
// Approve router
|
// Approve router from the order taker
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(orderTaker);
|
||||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||||
bytes memory callData = loadCallDataFromFile("test_uniswap_v3_bebop");
|
bytes memory callData = loadCallDataFromFile("test_uniswap_v3_bebop");
|
||||||
(bool success,) = tychoRouterAddr.call(callData);
|
(bool success,) = tychoRouterAddr.call(callData);
|
||||||
|
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
uint256 balanceAfter = IERC20(ONDO_ADDR).balanceOf(
|
uint256 balanceAfter = IERC20(ONDO_ADDR).balanceOf(orderTaker);
|
||||||
0xc5564C13A157E6240659fb81882A28091add8670
|
|
||||||
);
|
|
||||||
|
|
||||||
assertTrue(success, "Call Failed");
|
assertTrue(success, "Call Failed");
|
||||||
assertEq(balanceAfter - balanceBefore, ondoAmount);
|
assertEq(balanceAfter - balanceBefore, ondoAmount);
|
||||||
|
|||||||
@@ -197,18 +197,21 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
RestrictTransferFrom.TransferType transferType,
|
RestrictTransferFrom.TransferType transferType,
|
||||||
bytes memory bebopCalldata,
|
uint8 partialFillOffset,
|
||||||
uint256 originalAmountIn,
|
uint256 originalAmountIn,
|
||||||
bool approvalNeeded
|
bool approvalNeeded,
|
||||||
|
address receiver,
|
||||||
|
bytes memory bebopCalldata
|
||||||
) internal pure returns (bytes memory) {
|
) internal pure returns (bytes memory) {
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
uint8(transferType),
|
uint8(transferType),
|
||||||
uint32(bebopCalldata.length),
|
partialFillOffset,
|
||||||
bebopCalldata,
|
|
||||||
originalAmountIn,
|
originalAmountIn,
|
||||||
approvalNeeded ? uint8(1) : uint8(0)
|
approvalNeeded ? uint8(1) : uint8(0),
|
||||||
|
receiver,
|
||||||
|
bebopCalldata
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -69,12 +69,11 @@ contract BebopExecutorHarness is BebopExecutor, Test {
|
|||||||
override
|
override
|
||||||
returns (uint256 calculatedAmount)
|
returns (uint256 calculatedAmount)
|
||||||
{
|
{
|
||||||
console.log(
|
console.log("BebopExecutorHarness::swap called");
|
||||||
"[BebopHarness] swap entry, givenAmount=%s, value=%s",
|
console.log(" Given amount:", givenAmount);
|
||||||
givenAmount,
|
console.log(" Data length:", data.length);
|
||||||
msg.value
|
console.log(" Msg.sender:", msg.sender);
|
||||||
);
|
// Decode the data to get the bebop calldata
|
||||||
// Decode packed params
|
|
||||||
(
|
(
|
||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
@@ -85,168 +84,122 @@ contract BebopExecutorHarness is BebopExecutor, Test {
|
|||||||
bool approvalNeeded,
|
bool approvalNeeded,
|
||||||
address receiver
|
address receiver
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
console.log(
|
|
||||||
"[BebopHarness] decoded tokenIn=%s tokenOut=%s approvalNeeded=%s",
|
|
||||||
tokenIn,
|
|
||||||
tokenOut,
|
|
||||||
approvalNeeded
|
|
||||||
);
|
|
||||||
|
|
||||||
// Trust the encoder-provided receiver when present; if it's zero, fall back to
|
// Extract the selector to determine order type
|
||||||
// decoding the taker from the Bebop order so we still impersonate correctly
|
bytes4 selector = bytes4(bebopCalldata);
|
||||||
bytes4 sel = _getSelector(bebopCalldata);
|
|
||||||
console.log("[BebopHarness] selector computed");
|
|
||||||
console.logBytes4(sel);
|
|
||||||
console.log("[BebopHarness] bebopCalldata len=%s", bebopCalldata.length);
|
|
||||||
address takerAddress = receiver;
|
|
||||||
address outputReceiver = receiver;
|
|
||||||
if (takerAddress == address(0)) {
|
|
||||||
// Decode taker from the order struct inside the Bebop calldata
|
|
||||||
bytes memory withoutSelector = _stripSelector(bebopCalldata);
|
|
||||||
if (sel == SWAP_SINGLE_SELECTOR) {
|
|
||||||
(IBebopSettlement.Single memory order,,) = abi.decode(
|
|
||||||
withoutSelector,
|
|
||||||
(
|
|
||||||
IBebopSettlement.Single,
|
|
||||||
IBebopSettlement.MakerSignature,
|
|
||||||
uint256
|
|
||||||
)
|
|
||||||
);
|
|
||||||
takerAddress = order.taker_address;
|
|
||||||
outputReceiver = order.receiver;
|
|
||||||
} else {
|
|
||||||
(IBebopSettlement.Aggregate memory order,,) = abi.decode(
|
|
||||||
withoutSelector,
|
|
||||||
(
|
|
||||||
IBebopSettlement.Aggregate,
|
|
||||||
IBebopSettlement.MakerSignature[],
|
|
||||||
uint256
|
|
||||||
)
|
|
||||||
);
|
|
||||||
takerAddress = order.taker_address;
|
|
||||||
outputReceiver = order.receiver;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Even if the packed receiver is non-zero, use the order's receiver for correctness
|
|
||||||
bytes memory withoutSelector = _stripSelector(bebopCalldata);
|
|
||||||
if (sel == SWAP_SINGLE_SELECTOR) {
|
|
||||||
(IBebopSettlement.Single memory order,,) = abi.decode(
|
|
||||||
withoutSelector,
|
|
||||||
(
|
|
||||||
IBebopSettlement.Single,
|
|
||||||
IBebopSettlement.MakerSignature,
|
|
||||||
uint256
|
|
||||||
)
|
|
||||||
);
|
|
||||||
outputReceiver = order.receiver;
|
|
||||||
} else {
|
|
||||||
(IBebopSettlement.Aggregate memory order,,) = abi.decode(
|
|
||||||
withoutSelector,
|
|
||||||
(
|
|
||||||
IBebopSettlement.Aggregate,
|
|
||||||
IBebopSettlement.MakerSignature[],
|
|
||||||
uint256
|
|
||||||
)
|
|
||||||
);
|
|
||||||
outputReceiver = order.receiver;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("[BebopHarness] taker=%s", takerAddress);
|
|
||||||
|
|
||||||
// Make sure taker has the input assets and approvals when needed
|
// Extract taker address from the order - Bebop validates msg.sender == order.taker_address
|
||||||
// If the encoder gave us a zero original amount, pull it from the calldata so we can
|
address takerAddress;
|
||||||
// still set the correct fill
|
if (selector == SWAP_SINGLE_SELECTOR) {
|
||||||
uint256 effectiveOriginal = originalFilledTakerAmount;
|
// For single orders with inline encoding, taker_address is at position 36
|
||||||
if (effectiveOriginal == 0) {
|
// Position: 4 (selector) + 352 (inline order) + 32 (signature offset) = 388
|
||||||
// Use the offset to read the filledTakerAmount from calldata; for aggregate, if it's
|
// But we need taker_address which is at: 4 (selector) + 32 (expiry) = 36
|
||||||
// also zero, sum the taker_amounts from the order
|
assembly {
|
||||||
uint256 pos = 4 + uint256(partialFillOffset) * 32;
|
let dataPtr := add(bebopCalldata, 0x20)
|
||||||
if (bebopCalldata.length >= pos + 32) {
|
takerAddress := mload(add(dataPtr, 36))
|
||||||
assembly {
|
|
||||||
effectiveOriginal :=
|
|
||||||
mload(add(add(bebopCalldata, 0x20), pos))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (effectiveOriginal == 0 && sel == SWAP_AGGREGATE_SELECTOR) {
|
} else if (selector == SWAP_AGGREGATE_SELECTOR) {
|
||||||
// Decode order and sum taker_amounts
|
// For aggregate orders, extract taker_address from the calldata
|
||||||
bytes memory withoutSelector = _stripSelector(bebopCalldata);
|
// The aggregate order struct is passed as a calldata parameter
|
||||||
(IBebopSettlement.Aggregate memory order,,) = abi.decode(
|
// We need to read the offset to the order struct, then extract taker_address
|
||||||
withoutSelector,
|
assembly {
|
||||||
(
|
let dataPtr := add(bebopCalldata, 0x20)
|
||||||
IBebopSettlement.Aggregate,
|
// Read the offset to the order struct (first parameter after selector)
|
||||||
IBebopSettlement.MakerSignature[],
|
let orderOffset := mload(add(dataPtr, 0x04))
|
||||||
uint256
|
// The taker_address is at orderOffset + 4 (selector) + 32 (after expiry)
|
||||||
)
|
takerAddress :=
|
||||||
);
|
mload(add(dataPtr, add(0x04, add(orderOffset, 32))))
|
||||||
uint256 sum;
|
|
||||||
for (uint256 i = 0; i < order.taker_amounts.length; i++) {
|
|
||||||
for (uint256 j = 0; j < order.taker_amounts[i].length; j++)
|
|
||||||
{
|
|
||||||
sum += order.taker_amounts[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
effectiveOriginal = sum;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
uint256 actualFilled =
|
|
||||||
effectiveOriginal > givenAmount ? givenAmount : effectiveOriginal;
|
|
||||||
console.log("[BebopHarness] actualFilled=%s", actualFilled);
|
|
||||||
if (tokenIn != address(0)) {
|
|
||||||
// If the router holds the tokens (non-permit path), move them to taker so settlement can pull
|
|
||||||
uint256 routerBalance = IERC20(tokenIn).balanceOf(address(this));
|
|
||||||
console.log(
|
console.log(
|
||||||
"[BebopHarness] router tokenIn balance=%s", routerBalance
|
"Extracted taker address from aggregate order:", takerAddress
|
||||||
);
|
);
|
||||||
if (routerBalance >= actualFilled) {
|
|
||||||
IERC20(tokenIn).safeTransfer(takerAddress, actualFilled);
|
|
||||||
console.log(
|
|
||||||
"[BebopHarness] transferred %s tokenIn to taker",
|
|
||||||
actualFilled
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Approve settlement from taker's perspective
|
|
||||||
vm.stopPrank();
|
|
||||||
vm.startPrank(takerAddress);
|
|
||||||
IERC20(tokenIn).forceApprove(bebopSettlement, type(uint256).max);
|
|
||||||
vm.stopPrank();
|
|
||||||
console.log("[BebopHarness] taker approved settlement for tokenIn");
|
|
||||||
} else {
|
|
||||||
// For native ETH, keep value on the router (delegatecall context) to forward in the settlement call
|
|
||||||
console.log("[BebopHarness] native ETH flow");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build final calldata with adjusted filledTakerAmount
|
// For ERC20 tokens, we need to handle the flow differently
|
||||||
bytes memory finalCalldata = _modifyFilledTakerAmount(
|
// The taker needs to have the tokens and approve the settlement
|
||||||
bebopCalldata, givenAmount, effectiveOriginal, partialFillOffset
|
if (tokenIn != address(0)) {
|
||||||
);
|
// When called via delegatecall from the router, address(this) is the router
|
||||||
console.log("[BebopHarness] finalCalldata len=%s", finalCalldata.length);
|
// So we check the balance of address(this) which will be the router
|
||||||
|
uint256 balance = IERC20(tokenIn).balanceOf(address(this));
|
||||||
|
console.log("Balance of tokenIn at address(this):", balance);
|
||||||
|
console.log("Address(this):", address(this));
|
||||||
|
|
||||||
|
// If we don't have tokens, the taker should have them
|
||||||
|
if (balance < givenAmount) {
|
||||||
|
// Try to transfer from the taker (who should have approved the router)
|
||||||
|
console.log("Transferring from taker to address(this)");
|
||||||
|
IERC20(tokenIn).transferFrom(
|
||||||
|
takerAddress, address(this), givenAmount
|
||||||
|
);
|
||||||
|
balance = IERC20(tokenIn).balanceOf(address(this));
|
||||||
|
console.log("Balance after transfer:", balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the modified filledTakerAmount (what will actually be used)
|
||||||
|
bytes memory modifiedCalldata = _modifyFilledTakerAmount(
|
||||||
|
bebopCalldata,
|
||||||
|
givenAmount,
|
||||||
|
originalFilledTakerAmount,
|
||||||
|
partialFillOffset
|
||||||
|
);
|
||||||
|
|
||||||
|
// Extract the actual filledTakerAmount that will be used
|
||||||
|
uint256 actualFilledAmount = originalFilledTakerAmount > givenAmount
|
||||||
|
? givenAmount
|
||||||
|
: originalFilledTakerAmount;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"Original filled taker amount:", originalFilledTakerAmount
|
||||||
|
);
|
||||||
|
console.log("Actual filled amount to use:", actualFilledAmount);
|
||||||
|
|
||||||
|
// Only transfer what's needed to the taker, keep the rest in router
|
||||||
|
IERC20(tokenIn).transfer(takerAddress, actualFilledAmount);
|
||||||
|
console.log("Transferred tokens to taker:", actualFilledAmount);
|
||||||
|
|
||||||
|
// Check balances after transfer
|
||||||
|
uint256 takerBalance = IERC20(tokenIn).balanceOf(takerAddress);
|
||||||
|
uint256 routerBalance = IERC20(tokenIn).balanceOf(address(this));
|
||||||
|
console.log("After transfer - Taker balance:", takerBalance);
|
||||||
|
console.log(
|
||||||
|
"After transfer - Router balance (dust):", routerBalance
|
||||||
|
);
|
||||||
|
|
||||||
|
// Impersonate the taker and approve settlement for what they have
|
||||||
|
vm.startPrank(takerAddress);
|
||||||
|
IERC20(tokenIn).approve(bebopSettlement, actualFilledAmount);
|
||||||
|
console.log("Taker approved settlement for:", actualFilledAmount);
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
// Check if taker still has the tokens
|
||||||
|
takerBalance = IERC20(tokenIn).balanceOf(takerAddress);
|
||||||
|
console.log("After approval - Taker balance:", takerBalance);
|
||||||
|
|
||||||
|
// Start pranking as taker for the actual swap
|
||||||
|
vm.startPrank(takerAddress);
|
||||||
|
} else {
|
||||||
|
// For ETH, start pranking as taker
|
||||||
|
vm.startPrank(takerAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the actual bebop call details
|
||||||
|
console.log("Calling Bebop settlement with:");
|
||||||
|
console.log(" Taker address:", takerAddress);
|
||||||
|
console.log(" Token in:", tokenIn);
|
||||||
|
console.log(" Token out:", tokenOut);
|
||||||
|
console.log(" Given amount:", givenAmount);
|
||||||
|
console.log(" Receiver:", receiver);
|
||||||
|
console.log(" Bebop calldata length:", bebopCalldata.length);
|
||||||
|
console.log(" Natural msg.sender (no prank):", msg.sender);
|
||||||
|
|
||||||
|
// Call the parent implementation which handles the actual swap
|
||||||
|
// The taker prank is already active from above
|
||||||
|
console.log("About to call _swap, msg.sender is:", msg.sender);
|
||||||
|
console.log("Pranked as taker:", takerAddress);
|
||||||
|
calculatedAmount = _swap(givenAmount, data);
|
||||||
|
|
||||||
// Do the settlement call while impersonating the taker
|
|
||||||
uint256 beforeBal = _balanceOf(tokenOut, outputReceiver);
|
|
||||||
uint256 ethValue = tokenIn == address(0) ? givenAmount : 0;
|
|
||||||
console.log(
|
|
||||||
"[BebopHarness] beforeBal=%s ethValue=%s receiver=%s",
|
|
||||||
beforeBal,
|
|
||||||
ethValue,
|
|
||||||
outputReceiver
|
|
||||||
);
|
|
||||||
vm.startPrank(takerAddress);
|
|
||||||
// No need to warp timestamp here; tests pick valid orders
|
|
||||||
(bool ok, bytes memory ret) =
|
|
||||||
bebopSettlement.call{value: ethValue}(finalCalldata);
|
|
||||||
console.log("[BebopHarness] settlement ok=%s retLen=%s", ok, ret.length);
|
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
require(ok, "Bebop settlement call failed");
|
|
||||||
|
|
||||||
uint256 afterBal = _balanceOf(tokenOut, outputReceiver);
|
console.log("Calculated amount returned:", calculatedAmount);
|
||||||
calculatedAmount = afterBal - beforeBal;
|
|
||||||
console.log(
|
|
||||||
"[BebopHarness] afterBal=%s calculatedAmount=%s",
|
|
||||||
afterBal,
|
|
||||||
calculatedAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
// no-op; keep function end balanced
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user