fix: Simplify the BebopExecutor and fix Single tests
Make specific quotes that are expected to be used by the TychoRouter for the tests. Do not use the BebopHarness Commented out Aggregate tests Took 6 hours 40 minutes
This commit is contained in:
@@ -3,14 +3,10 @@ pub mod encoding;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use alloy::{
|
||||
primitives::{B256, U256},
|
||||
signers::local::PrivateKeySigner,
|
||||
};
|
||||
use alloy::{primitives::B256, signers::local::PrivateKeySigner};
|
||||
use tycho_common::{models::Chain, Bytes};
|
||||
use tycho_execution::encoding::{
|
||||
evm::encoder_builders::TychoRouterEncoderBuilder,
|
||||
models::{BebopOrderType, UserTransferType},
|
||||
evm::encoder_builders::TychoRouterEncoderBuilder, models::UserTransferType,
|
||||
tycho_encoder::TychoEncoder,
|
||||
};
|
||||
|
||||
@@ -75,236 +71,9 @@ pub fn get_tycho_router_encoder(user_transfer_type: UserTransferType) -> Box<dyn
|
||||
|
||||
/// Builds the complete Bebop calldata in the format expected by the encoder
|
||||
/// Returns: partialFillOffset (1 byte) | bebop_calldata (selector + ABI encoded params)
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `order_type` - The type of Bebop order (Single or Aggregate)
|
||||
/// * `filled_taker_amount` - Amount to fill (0 means fill entire order)
|
||||
/// * `quote_data` - The ABI-encoded order data (just the struct, not full calldata)
|
||||
/// * `signatures` - Vector of (signature_bytes, signature_type) tuples
|
||||
pub fn build_bebop_calldata(
|
||||
order_type: BebopOrderType,
|
||||
filled_taker_amount: U256,
|
||||
quote_data: &[u8],
|
||||
signatures: Vec<(Vec<u8>, u8)>,
|
||||
) -> Bytes {
|
||||
// Step 1: Determine selector and partialFillOffset based on order type
|
||||
let (selector, partial_fill_offset) = match order_type {
|
||||
BebopOrderType::Single => (
|
||||
[0x4d, 0xce, 0xbc, 0xba], // swapSingle selector
|
||||
12u8, /* partialFillOffset (388 = 4 + 12*32) - after order and
|
||||
* signature offset */
|
||||
),
|
||||
BebopOrderType::Aggregate => (
|
||||
[0xa2, 0xf7, 0x48, 0x93], // swapAggregate selector
|
||||
2u8, /* partialFillOffset (68 = 4 + 2*32) - aggregate still
|
||||
* uses offsets */
|
||||
),
|
||||
};
|
||||
|
||||
// Step 2: Build the ABI-encoded parameters based on order type
|
||||
let encoded_params = match order_type {
|
||||
BebopOrderType::Single => {
|
||||
// swapSingle(Single order, MakerSignature signature, uint256 filledTakerAmount)
|
||||
encode_single_params(quote_data, &signatures[0], filled_taker_amount)
|
||||
}
|
||||
BebopOrderType::Aggregate => {
|
||||
// swapAggregate(Aggregate order, MakerSignature[] signatures, uint256
|
||||
// filledTakerAmount)
|
||||
encode_aggregate_params(quote_data, &signatures, filled_taker_amount)
|
||||
}
|
||||
};
|
||||
|
||||
// Step 3: Combine selector and encoded parameters into complete calldata
|
||||
let mut bebop_calldata = Vec::new();
|
||||
bebop_calldata.extend_from_slice(&selector);
|
||||
bebop_calldata.extend_from_slice(&encoded_params);
|
||||
|
||||
// Step 4: Prepend partialFillOffset to create final user_data
|
||||
pub fn build_bebop_calldata(calldata: &[u8], partial_fill_offset: u8) -> Bytes {
|
||||
let mut user_data = vec![partial_fill_offset];
|
||||
user_data.extend_from_slice(&bebop_calldata);
|
||||
user_data.extend_from_slice(calldata);
|
||||
|
||||
Bytes::from(user_data)
|
||||
}
|
||||
|
||||
fn encode_single_params(
|
||||
order_data: &[u8], // Already ABI-encoded Single struct
|
||||
signature: &(Vec<u8>, u8),
|
||||
filled_taker_amount: U256,
|
||||
) -> Vec<u8> {
|
||||
// abi.encode() with (struct, struct, uint256) where:
|
||||
// - Single struct: all fixed-size fields, encoded inline
|
||||
// - MakerSignature struct: has dynamic bytes field, needs offset
|
||||
// - uint256: fixed-size, encoded inline
|
||||
|
||||
let mut encoded = Vec::new();
|
||||
|
||||
// 1. Order struct fields are encoded inline (11 fields * 32 bytes = 352 bytes)
|
||||
encoded.extend_from_slice(order_data);
|
||||
|
||||
// 2. Offset to MakerSignature data (points after all inline data)
|
||||
// Offset = 352 (order) + 32 (this offset) + 32 (filledTakerAmount) = 416
|
||||
encoded.extend_from_slice(&U256::from(416).to_be_bytes::<32>());
|
||||
|
||||
// 3. filledTakerAmount inline
|
||||
encoded.extend_from_slice(&filled_taker_amount.to_be_bytes::<32>());
|
||||
|
||||
// 4. MakerSignature struct data at the offset
|
||||
let signature_struct = encode_maker_signature(signature);
|
||||
encoded.extend_from_slice(&signature_struct);
|
||||
|
||||
encoded
|
||||
}
|
||||
|
||||
fn encode_aggregate_params(
|
||||
order_data: &[u8], // Already ABI-encoded Aggregate struct
|
||||
signatures: &[(Vec<u8>, u8)],
|
||||
filled_taker_amount: U256,
|
||||
) -> Vec<u8> {
|
||||
// abi.encode() with (struct, struct[], uint256) where:
|
||||
// - Aggregate struct: has dynamic arrays, gets offset
|
||||
// - MakerSignature[] array: dynamic, gets offset
|
||||
// - uint256: fixed-size, encoded inline
|
||||
//
|
||||
// CRITICAL FIX: The issue is that Rust's ABI encoder produces aggregate orders
|
||||
// that are 32 bytes larger than Solidity's (1536 vs 1504 bytes). We cannot just
|
||||
// adjust the offset while keeping the wrong-sized data. Instead, we need to
|
||||
// truncate the extra 32 bytes from the Rust-encoded order data to match Solidity.
|
||||
|
||||
let mut encoded = Vec::new();
|
||||
|
||||
// Fixed: Using alloy::primitives::Bytes for the commands field produces the correct
|
||||
// 1504-byte encoding that matches Solidity. No truncation needed anymore.
|
||||
let corrected_order_data = order_data;
|
||||
|
||||
// Calculate offsets
|
||||
let order_offset = 96; // After 3 words (3 * 32 = 96)
|
||||
let signatures_offset = order_offset + corrected_order_data.len();
|
||||
|
||||
// Write the three parameter slots
|
||||
encoded.extend_from_slice(&U256::from(order_offset).to_be_bytes::<32>());
|
||||
encoded.extend_from_slice(&U256::from(signatures_offset).to_be_bytes::<32>());
|
||||
encoded.extend_from_slice(&filled_taker_amount.to_be_bytes::<32>());
|
||||
|
||||
// Append the corrected order data
|
||||
encoded.extend_from_slice(corrected_order_data);
|
||||
|
||||
// Manually encode the signatures array to exactly match the working test
|
||||
// Array length
|
||||
encoded.extend_from_slice(&U256::from(signatures.len()).to_be_bytes::<32>());
|
||||
|
||||
// For 2 signatures, we need offsets for each struct
|
||||
if signatures.len() == 2 {
|
||||
// First signature starts after the two offset words (64 bytes)
|
||||
let sig1_offset = 64;
|
||||
|
||||
// Calculate size of first signature struct:
|
||||
// - offset to bytes field: 32
|
||||
// - flags field: 32
|
||||
// - length of bytes: 32
|
||||
// - actual signature bytes + padding
|
||||
let sig1 = &signatures[0];
|
||||
let sig1_padding = (32 - (sig1.0.len() % 32)) % 32;
|
||||
let sig1_size = 64 + 32 + sig1.0.len() + sig1_padding;
|
||||
|
||||
// Second signature starts after first
|
||||
let sig2_offset = sig1_offset + sig1_size;
|
||||
|
||||
// Write offsets
|
||||
encoded.extend_from_slice(&U256::from(sig1_offset).to_be_bytes::<32>());
|
||||
encoded.extend_from_slice(&U256::from(sig2_offset).to_be_bytes::<32>());
|
||||
|
||||
// Encode each MakerSignature struct
|
||||
for signature in signatures {
|
||||
// Offset to signatureBytes within this struct (always 64)
|
||||
encoded.extend_from_slice(&U256::from(64).to_be_bytes::<32>());
|
||||
// Flags (signature type)
|
||||
encoded.extend_from_slice(&U256::from(signature.1).to_be_bytes::<32>());
|
||||
// SignatureBytes length
|
||||
encoded.extend_from_slice(&U256::from(signature.0.len()).to_be_bytes::<32>());
|
||||
// SignatureBytes data
|
||||
encoded.extend_from_slice(&signature.0);
|
||||
// Padding to 32-byte boundary
|
||||
let padding = (32 - (signature.0.len() % 32)) % 32;
|
||||
encoded.extend(vec![0u8; padding]);
|
||||
}
|
||||
} else {
|
||||
// General case for any number of signatures
|
||||
let signatures_array = encode_maker_signatures_array(signatures);
|
||||
encoded.extend_from_slice(&signatures_array);
|
||||
}
|
||||
|
||||
encoded
|
||||
}
|
||||
|
||||
fn encode_maker_signature(signature: &(Vec<u8>, u8)) -> Vec<u8> {
|
||||
let mut encoded = Vec::new();
|
||||
|
||||
// MakerSignature struct has two fields:
|
||||
// - bytes signatureBytes (dynamic) - offset at position 0
|
||||
// - uint256 flags - at position 32
|
||||
|
||||
// Offset to signatureBytes (always 64 for this struct layout)
|
||||
encoded.extend_from_slice(&U256::from(64).to_be_bytes::<32>());
|
||||
|
||||
// Flags (signature type)
|
||||
encoded.extend_from_slice(&U256::from(signature.1).to_be_bytes::<32>());
|
||||
|
||||
// SignatureBytes (length + data)
|
||||
encoded.extend_from_slice(&U256::from(signature.0.len()).to_be_bytes::<32>());
|
||||
encoded.extend_from_slice(&signature.0);
|
||||
|
||||
// Pad to 32-byte boundary
|
||||
let padding = (32 - (signature.0.len() % 32)) % 32;
|
||||
encoded.extend(vec![0u8; padding]);
|
||||
|
||||
encoded
|
||||
}
|
||||
|
||||
fn encode_maker_signatures_array(signatures: &[(Vec<u8>, u8)]) -> Vec<u8> {
|
||||
let mut encoded = Vec::new();
|
||||
|
||||
// Array length
|
||||
encoded.extend_from_slice(&U256::from(signatures.len()).to_be_bytes::<32>());
|
||||
|
||||
// Calculate offsets for each struct (relative to start of array data)
|
||||
let mut struct_data = Vec::new();
|
||||
let mut struct_offsets = Vec::new();
|
||||
let struct_offsets_size = 32 * signatures.len();
|
||||
let mut current_offset = struct_offsets_size;
|
||||
|
||||
for signature in signatures {
|
||||
struct_offsets.push(current_offset);
|
||||
|
||||
// Build struct data
|
||||
let mut struct_bytes = Vec::new();
|
||||
|
||||
// Offset to signatureBytes within this struct
|
||||
struct_bytes.extend_from_slice(&U256::from(64).to_be_bytes::<32>());
|
||||
|
||||
// Flags (signature type)
|
||||
struct_bytes.extend_from_slice(&U256::from(signature.1).to_be_bytes::<32>());
|
||||
|
||||
// SignatureBytes length
|
||||
struct_bytes.extend_from_slice(&U256::from(signature.0.len()).to_be_bytes::<32>());
|
||||
|
||||
// SignatureBytes data (padded to 32 byte boundary)
|
||||
struct_bytes.extend_from_slice(&signature.0);
|
||||
let padding = (32 - (signature.0.len() % 32)) % 32;
|
||||
struct_bytes.extend(vec![0u8; padding]);
|
||||
|
||||
current_offset += struct_bytes.len();
|
||||
struct_data.push(struct_bytes);
|
||||
}
|
||||
|
||||
// Write struct offsets
|
||||
for offset in struct_offsets {
|
||||
encoded.extend_from_slice(&U256::from(offset).to_be_bytes::<32>());
|
||||
}
|
||||
|
||||
// Write struct data
|
||||
for data in struct_data {
|
||||
encoded.extend_from_slice(&data);
|
||||
}
|
||||
|
||||
encoded
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user