From 75ef134e73a05e4a225b153652539400f3a2effd Mon Sep 17 00:00:00 2001 From: pedrobergamini <41773103+pedrobergamini@users.noreply.github.com> Date: Mon, 4 Aug 2025 14:00:04 -0300 Subject: [PATCH] chore: add filter / map loop for taker_amount calculation --- .../evm/swap_encoder/swap_encoders.rs | 118 +++++++++++++++++- 1 file changed, 115 insertions(+), 3 deletions(-) diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 8298221..92ae6a8 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -668,6 +668,84 @@ impl BebopSwapEncoder { } } +/// Extract the total taker amount from a Bebop aggregate order calldata +fn extract_aggregate_taker_amount(bebop_calldata: &[u8]) -> Option { + // Minimum size check: 4 (selector) + 32 (order offset) + 32 (signatures offset) + 32 (filledTakerAmount) = 100 bytes + // This ensures we can safely read the offset to the order parameter + if bebop_calldata.len() < 100 { + return None; + } + + // Read the offset to the order struct (first parameter) + let order_offset = U256::from_be_slice(&bebop_calldata[4..36]).to::() + 4; + + // The Aggregate struct fields (all offsets are relative to the start of the struct): + // 0: expiry (32 bytes) + // 1: taker_address (32 bytes) + // 2: offset to maker_addresses array (32 bytes) + // 3: offset to maker_nonces array (32 bytes) + // 4: offset to taker_tokens array (32 bytes) + // 5: offset to maker_tokens array (32 bytes) + // 6: offset to taker_amounts array (32 bytes) <- we need this + + if bebop_calldata.len() <= order_offset + 224 { + return None; + } + + let taker_amounts_offset = + U256::from_be_slice(&bebop_calldata[order_offset + 192..order_offset + 224]).to::(); + let taker_amounts_data_offset = order_offset + taker_amounts_offset; + + // Read the taker_amounts 2D array + if bebop_calldata.len() <= taker_amounts_data_offset + 32 { + return None; + } + + // First 32 bytes is the array length (number of makers) + let num_makers = U256::from_be_slice( + &bebop_calldata[taker_amounts_data_offset..taker_amounts_data_offset + 32], + ) + .to::(); + + let total_taker_amount = (0..num_makers) + // turn each maker-offset word into an absolute data offset + .filter_map(|idx| { + let word_start = taker_amounts_data_offset + 32 + idx * 32; + if bebop_calldata.len() <= word_start + 32 { + return None; + } + let rel = + U256::from_be_slice(&bebop_calldata[word_start..word_start + 32]).to::(); + Some(taker_amounts_data_offset + rel) + }) + // for every maker, accumulate its taker_amounts array + .map(|maker_data_off| { + if bebop_calldata.len() <= maker_data_off + 32 { + return U256::ZERO; + } + let num_amounts = + U256::from_be_slice(&bebop_calldata[maker_data_off..maker_data_off + 32]) + .to::(); + + (0..num_amounts) + .filter_map(|j| { + let amount_off = maker_data_off + 32 + j * 32; + if bebop_calldata.len() < amount_off + 32 { + return None; + } + Some(U256::from_be_slice(&bebop_calldata[amount_off..amount_off + 32])) + }) + .fold(U256::ZERO, |acc, amt| acc.saturating_add(amt)) + }) + .fold(U256::ZERO, |acc, maker_sum| acc.saturating_add(maker_sum)); + + if total_taker_amount > U256::ZERO { + Some(total_taker_amount) + } else { + None + } +} + impl SwapEncoder for BebopSwapEncoder { fn new( executor_address: String, @@ -744,9 +822,43 @@ impl SwapEncoder for BebopSwapEncoder { )); } - // Extract the last 32 bytes as the original filledTakerAmount - let original_filled_taker_amount = - U256::from_be_slice(&bebop_calldata[bebop_calldata.len() - 32..]); + // Extract the original filledTakerAmount, using the order's taker_amount if it's zero + let original_filled_taker_amount = { + let filled_amount = U256::from_be_slice(&bebop_calldata[bebop_calldata.len() - 32..]); + + if filled_amount != U256::ZERO { + filled_amount + } else { + // Extract taker_amount from the order based on the function selector + let selector = &bebop_calldata[0..4]; + + // swapSingle selector: 0x47fb5891 + // swapAggregate selector: 0x80d2cf33 + const SWAP_SINGLE_SELECTOR: [u8; 4] = [0x47, 0xfb, 0x58, 0x91]; + const SWAP_AGGREGATE_SELECTOR: [u8; 4] = [0x80, 0xd2, 0xcf, 0x33]; + + if selector == SWAP_SINGLE_SELECTOR { + // For swapSingle, decode the Single struct to get taker_amount + // The Single struct is the first parameter after the selector + // Single struct has fields in order: expiry, taker_address, maker_address, + // maker_nonce, taker_token, maker_token, taker_amount, maker_amount, etc. + // taker_amount is at position 6 (0-indexed), so offset is 4 + 32*6 = 196 + if bebop_calldata.len() >= 228 { + U256::from_be_slice(&bebop_calldata[196..228]) + } else { + U256::ZERO + } + } else if selector == SWAP_AGGREGATE_SELECTOR { + // For swapAggregate, we need to sum all taker_amounts + // The calldata structure is: selector(4) + offset_to_order(32) + + // offset_to_signatures(32) + filledTakerAmount(32) + order_data + + // signatures_data + extract_aggregate_taker_amount(&bebop_calldata).unwrap_or(U256::ZERO) + } else { + U256::ZERO + } + } + }; // Encode packed data for the executor // Format: token_in | token_out | transfer_type | bebop_calldata_length |