From fe5f72e27825e1b696bc75aa148351bedcc3d5a9 Mon Sep 17 00:00:00 2001 From: pedrobergamini <41773103+pedrobergamini@users.noreply.github.com> Date: Mon, 4 Aug 2025 10:31:15 -0300 Subject: [PATCH] chore: update swap_encoders.rs --- .../evm/swap_encoder/swap_encoders.rs | 611 ++---------------- 1 file changed, 43 insertions(+), 568 deletions(-) diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 84440bc..8298221 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -1,10 +1,6 @@ -use std::{ - collections::{HashMap, HashSet}, - str::FromStr, -}; +use std::{collections::HashMap, str::FromStr}; use alloy::{ - core::sol, primitives::{Address, Bytes as AlloyBytes, U256, U8}, sol_types::SolValue, }; @@ -17,7 +13,7 @@ use crate::encoding::{ approvals::protocol_approvals_manager::ProtocolApprovalsManager, utils::{bytes_to_address, get_static_attribute, pad_to_fixed_size}, }, - models::{BebopOrderType, Chain, EncodingContext, Swap}, + models::{Chain, EncodingContext, Swap}, swap_encoder::SwapEncoder, }; @@ -641,37 +637,6 @@ impl SwapEncoder for BalancerV3SwapEncoder { } } -// Define Bebop order structures for ABI decoding -sol! { - struct BebopSingle { - uint256 expiry; - address taker_address; - address maker_address; - uint256 maker_nonce; - address taker_token; - address maker_token; - uint256 taker_amount; - uint256 maker_amount; - address receiver; - uint256 packed_commands; - uint256 flags; - } - - struct BebopAggregate { - uint256 expiry; - address taker_address; - address[] maker_addresses; - uint256[] maker_nonces; - address[][] taker_tokens; - address[][] maker_tokens; - uint256[][] taker_amounts; - uint256[][] maker_amounts; - address receiver; - bytes commands; - uint256 flags; - } -} - /// Encodes a swap on Bebop (PMM RFQ) through the given executor address. /// /// Bebop uses a Request-for-Quote model where quotes are obtained off-chain @@ -701,59 +666,6 @@ impl BebopSwapEncoder { } Ok(()) } - - /// Analyzes the quote to determine token input/output characteristics - /// Returns (has_many_inputs, has_many_outputs) - fn validate_aggregate_order( - &self, - quote_data: &[u8], - expected_token_out: &Address, - ) -> Result<(), EncodingError> { - // Decode the Aggregate order to validate - let order = BebopAggregate::abi_decode(quote_data).map_err(|e| { - EncodingError::InvalidInput(format!("Failed to decode Bebop Aggregate order: {}", e)) - })?; - - // Validate that we only have one unique input token across all makers - let unique_taker_tokens: HashSet<_> = order - .taker_tokens - .iter() - .flat_map(|tokens| tokens.iter()) - .collect(); - - if unique_taker_tokens.len() != 1 { - return Err(EncodingError::InvalidInput( - "Aggregate orders must have exactly one unique input token across all makers" - .to_string(), - )); - } - - // Validate that all makers provide exactly one output token - for (i, maker_tokens) in order.maker_tokens.iter().enumerate() { - if maker_tokens.len() != 1 { - return Err(EncodingError::InvalidInput(format!( - "Maker {} must provide exactly one output token, found {}", - i, - maker_tokens.len() - ))); - } - } - - // Validate that all makers provide the same output token - let all_same_output = order - .maker_tokens - .iter() - .flat_map(|maker_tokens| maker_tokens.iter()) - .all(|token| token == expected_token_out); - - if !all_same_output { - return Err(EncodingError::InvalidInput( - "All makers must provide the same output token".to_string(), - )); - } - - Ok(()) - } } impl SwapEncoder for BebopSwapEncoder { @@ -808,208 +720,44 @@ impl SwapEncoder for BebopSwapEncoder { // Validate component ID Self::validate_component_id(&swap.component.id)?; - // Extract data from user_data (required for Bebop) + // Extract bebop calldata from user_data (required for Bebop) let user_data = swap.user_data.clone().ok_or_else(|| { - EncodingError::InvalidInput( - "Bebop swaps require user_data with quote and signature".to_string(), - ) + EncodingError::InvalidInput("Bebop swaps require user_data with calldata".to_string()) })?; - // Parse user_data format: - // order_type (1 byte) | filledTakerAmount (32 bytes) | quote_data_length (4 bytes) | - // quote_data | abi_encoded_maker_signatures where abi_encoded_maker_signatures is - // abi.encode(MakerSignature[]) - if user_data.len() < 37 { + // User data should contain the complete Bebop calldata + if user_data.len() < 4 { return Err(EncodingError::InvalidInput( - "User data too short to contain Bebop RFQ data".to_string(), + "User data too short to contain Bebop calldata".to_string(), )); } - let order_type = BebopOrderType::try_from(user_data[0])?; + // The calldata should be for either swapSingle or swapAggregate + let bebop_calldata = user_data.to_vec(); - // Extract filledTakerAmount (32 bytes) - let filled_taker_amount = U256::from_be_slice(&user_data[1..33]); - - let quote_data_len = - u32::from_be_bytes([user_data[33], user_data[34], user_data[35], user_data[36]]) - as usize; - if user_data.len() < 37 + quote_data_len { + // Extract the original filledTakerAmount from the calldata + // Both swapSingle and swapAggregate have filledTakerAmount as the last parameter + // We need at least 4 bytes selector + 32 bytes for filledTakerAmount at the end + if bebop_calldata.len() < 36 { return Err(EncodingError::InvalidInput( - "User data too short to contain quote data".to_string(), + "Bebop calldata too short to contain filledTakerAmount".to_string(), )); } - let quote_data = user_data[37..37 + quote_data_len].to_vec(); - - // Validate Aggregate orders have single token in/out - if order_type == BebopOrderType::Aggregate { - self.validate_aggregate_order("e_data, &token_out)?; - } - - // Decode the ABI-encoded MakerSignature[] array - let maker_sigs_start = 37 + quote_data_len; - let remaining_data = &user_data[maker_sigs_start..]; - - // Need at least 64 bytes for offset (32) and array length (32) - if remaining_data.len() < 64 { - return Err(EncodingError::InvalidInput( - "User data too short to contain MakerSignature array".to_string(), - )); - } - - // Read offset to array (should be 0x20 for single parameter) - let array_offset: usize = U256::from_be_slice(&remaining_data[0..32]) - .try_into() - .map_err(|_| EncodingError::InvalidInput("Array offset too large".to_string()))?; - - if array_offset != 32 { - return Err(EncodingError::InvalidInput( - "Invalid array offset in ABI encoding".to_string(), - )); - } - - // Read array length - let array_length: usize = U256::from_be_slice(&remaining_data[32..64]) - .try_into() - .map_err(|_| EncodingError::InvalidInput("Array length too large".to_string()))?; - - // Validate signature count based on order type - match order_type { - BebopOrderType::Single => { - if array_length != 1 { - return Err(EncodingError::InvalidInput(format!( - "Expected 1 signature for Single order, got {}", - array_length - ))); - } - } - BebopOrderType::Aggregate => { - if array_length == 0 { - return Err(EncodingError::InvalidInput( - "Aggregate order requires at least one signature".to_string(), - )); - } - } - } - - // For aggregate orders, we just pass through the entire ABI-encoded array - // For single orders, we validate and re-encode - let maker_sigs_encoded = if order_type == BebopOrderType::Aggregate { - // For aggregate orders, pass through the entire encoded array - remaining_data.to_vec() - } else { - // For single orders, validate and re-encode the single signature - // Read offset to first (and only) struct - if remaining_data.len() < 96 { - return Err(EncodingError::InvalidInput( - "User data too short to contain struct offset".to_string(), - )); - } - - let struct_offset: usize = U256::from_be_slice(&remaining_data[64..96]) - .try_into() - .map_err(|_| EncodingError::InvalidInput("Struct offset too large".to_string()))?; - - // The struct data starts at the struct_offset - // struct_offset is relative to the start of array data (after the array length) - // Array data starts at position 64 (after offset[32] and length[32]) - // Absolute position = 64 + struct_offset - let struct_start = 64 + struct_offset; - - if remaining_data.len() < struct_start + 64 { - return Err(EncodingError::InvalidInput( - "User data too short to contain MakerSignature struct".to_string(), - )); - } - - // Read the struct fields - // - offset to signatureBytes (32 bytes) - should be 64 - // - flags (32 bytes) - let sig_offset: usize = - U256::from_be_slice(&remaining_data[struct_start..struct_start + 32]) - .try_into() - .map_err(|_| { - EncodingError::InvalidInput("Signature offset too large".to_string()) - })?; - - if sig_offset != 64 { - return Err(EncodingError::InvalidInput(format!( - "Invalid signature offset in struct: expected 64, got {}", - sig_offset - ))); - } - - let flags = U256::from_be_slice(&remaining_data[struct_start + 32..struct_start + 64]); - - // Read signature data - let sig_data_start = struct_start + sig_offset; - if remaining_data.len() < sig_data_start + 32 { - return Err(EncodingError::InvalidInput( - "User data too short to contain signature length".to_string(), - )); - } - - let signature_len: usize = - U256::from_be_slice(&remaining_data[sig_data_start..sig_data_start + 32]) - .try_into() - .map_err(|_| { - EncodingError::InvalidInput("Signature length too large".to_string()) - })?; - - if remaining_data.len() < sig_data_start + 32 + signature_len { - return Err(EncodingError::InvalidInput( - "User data too short to contain signature data".to_string(), - )); - } - - let signature = - remaining_data[sig_data_start + 32..sig_data_start + 32 + signature_len].to_vec(); - - // Re-encode the MakerSignature[] array for the executor - let mut encoded = Vec::new(); - - // Offset to array (always 0x20 for single parameter) - encoded.extend_from_slice(&U256::from(32).to_be_bytes::<32>()); - - // Array length (1 for non-aggregate orders) - encoded.extend_from_slice(&U256::from(1).to_be_bytes::<32>()); - - // Offset to first struct (relative to array data start) - let struct_offset = 32; // After the array length - encoded.extend_from_slice(&U256::from(struct_offset).to_be_bytes::<32>()); - - // Struct data - // - offset to signatureBytes (always 64) - encoded.extend_from_slice(&U256::from(64).to_be_bytes::<32>()); - - // - flags - encoded.extend_from_slice(&flags.to_be_bytes::<32>()); - - // - signatureBytes length - encoded.extend_from_slice(&U256::from(signature.len()).to_be_bytes::<32>()); - - // - signatureBytes data (padded) - encoded.extend_from_slice(&signature); - let padding = (32 - (signature.len() % 32)) % 32; - encoded.extend_from_slice(&vec![0u8; padding]); - - encoded - }; + // Extract the last 32 bytes as the original filledTakerAmount + let original_filled_taker_amount = + U256::from_be_slice(&bebop_calldata[bebop_calldata.len() - 32..]); // Encode packed data for the executor - // Format: token_in | token_out | transfer_type | order_type | filledTakerAmount | - // quote_data_length | quote_data | maker_signatures_length | - // abi_encoded_maker_signatures | approval_needed + // Format: token_in | token_out | transfer_type | bebop_calldata_length | + // bebop_calldata | original_filled_taker_amount | approval_needed let args = ( token_in, token_out, (encoding_context.transfer_type as u8).to_be_bytes(), - (order_type as u8).to_be_bytes(), - filled_taker_amount.to_be_bytes::<32>(), - (quote_data.len() as u32).to_be_bytes(), - "e_data[..], - (maker_sigs_encoded.len() as u32).to_be_bytes(), - &maker_sigs_encoded[..], + (bebop_calldata.len() as u32).to_be_bytes(), + &bebop_calldata[..], + original_filled_taker_amount.to_be_bytes::<32>(), (approval_needed as u8).to_be_bytes(), ); @@ -2081,89 +1829,17 @@ mod tests { use crate::encoding::{evm::utils::write_calldata_to_file, models::TransferType}; #[test] - fn test_encode_bebop_single() { - use alloy::{hex, primitives::Address}; + fn test_encode_bebop_calldata_forwarding() { + use alloy::hex; - // Use mainnet data - // Transaction: https://etherscan.io/tx/0x6279bc970273b6e526e86d9b69133c2ca1277e697ba25375f5e6fc4df50c0c94 - let order_type = BebopOrderType::Single as u8; - - // Create the IBebopSettlement.Single struct data using the exact input data from the tx - let expiry = U256::from(1749483840u64); - let taker_address = - Address::from_str("0xc5564C13A157E6240659fb81882A28091add8670").unwrap(); - let maker_address = - Address::from_str("0xCe79b081c0c924cb67848723ed3057234d10FC6b").unwrap(); - let maker_nonce = U256::from(1749483765992417u64); - let taker_token = - Address::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").unwrap(); // USDC - let maker_token = - Address::from_str("0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3").unwrap(); // ONDO - let taker_amount = U256::from(200000000u64); // 200 USDC - let maker_amount = U256::from_str("237212396774431060000").unwrap(); // 237.21 ONDO - let receiver = taker_address; - let packed_commands = U256::ZERO; - let flags = U256::from_str( - "51915842898789398998206002334703507894664330885127600393944965515693155942400", - ) - .unwrap(); - - // ABI encode the order struct - let quote_data = ( - expiry, - taker_address, - maker_address, - maker_nonce, - taker_token, - maker_token, - taker_amount, - maker_amount, - receiver, - packed_commands, - flags, - ) - .abi_encode(); - - // Real signature from mainnet - let signature = hex::decode("eb5419631614978da217532a40f02a8f2ece37d8cfb94aaa602baabbdefb56b474f4c2048a0f56502caff4ea7411d99eed6027cd67dc1088aaf4181dcb0df7051c").unwrap(); - let signature_type = 0u8; // ETH_SIGN - - // Build ABI-encoded MakerSignature[] array - let flags = U256::from(signature_type); - let mut encoded_maker_sigs = Vec::new(); - - // Offset to array (always 0x20 for single parameter) - encoded_maker_sigs.extend_from_slice(&U256::from(32).to_be_bytes::<32>()); - - // Array length (1 for Single order) - encoded_maker_sigs.extend_from_slice(&U256::from(1).to_be_bytes::<32>()); - - // Offset to first struct (relative to array data start) - encoded_maker_sigs.extend_from_slice(&U256::from(32).to_be_bytes::<32>()); - - // Struct data (MakerSignature has signatureBytes first, then flags) - // - offset to signatureBytes (always 64 since it comes after offset and flags) - encoded_maker_sigs.extend_from_slice(&U256::from(64).to_be_bytes::<32>()); - - // - flags (AFTER the offset, as per struct order) - encoded_maker_sigs.extend_from_slice(&flags.to_be_bytes::<32>()); - - // - signatureBytes length - encoded_maker_sigs.extend_from_slice(&U256::from(signature.len()).to_be_bytes::<32>()); - - // - signatureBytes data (padded) - encoded_maker_sigs.extend_from_slice(&signature); - let padding = (32 - (signature.len() % 32)) % 32; - encoded_maker_sigs.extend_from_slice(&vec![0u8; padding]); - - let filled_taker_amount = U256::ZERO; // 0 means fill entire order - - let mut user_data = Vec::new(); - user_data.push(order_type); - user_data.extend_from_slice(&filled_taker_amount.to_be_bytes::<32>()); - user_data.extend_from_slice(&(quote_data.len() as u32).to_be_bytes()); - user_data.extend_from_slice("e_data); - user_data.extend_from_slice(&encoded_maker_sigs); + // Create mock Bebop calldata for swapSingle + // This would normally come from the Bebop API response + let bebop_calldata = hex::decode( + "47fb5891".to_owned() // swapSingle selector + + "0000000000000000000000000000000000000000000000000000000000000001" // mock order data + + "0000000000000000000000000000000000000000000000000000000000000002" // mock signature data + + "0000000000000000000000000000000000000000000000000000000bebc200" // filledTakerAmount = 200000000 + ).unwrap(); let bebop_component = ProtocolComponent { id: String::from("bebop-rfq"), @@ -2174,16 +1850,17 @@ mod tests { let token_in = Bytes::from("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); // USDC let token_out = Bytes::from("0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"); // ONDO + let swap = Swap { component: bebop_component, token_in: token_in.clone(), token_out: token_out.clone(), split: 0f64, - user_data: Some(Bytes::from(user_data)), + user_data: Some(Bytes::from(bebop_calldata.clone())), }; let encoding_context = EncodingContext { - receiver: Bytes::from("0xc5564C13A157E6240659fb81882A28091add8670"), /* Taker address from tx */ + receiver: Bytes::from("0xc5564C13A157E6240659fb81882A28091add8670"), exact_out: false, router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), @@ -2210,218 +1887,16 @@ mod tests { assert!(hex_swap.contains("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")); // USDC assert!(hex_swap.contains("faba6f8e4a5e8ab82f62fe7c39859fa577269be3")); // ONDO - // Verify it includes the signature - let sig_hex = hex::encode(&signature); - assert!(hex_swap.contains(&sig_hex)); + // Verify it includes the bebop calldata + let calldata_hex = hex::encode(&bebop_calldata); + assert!(hex_swap.contains(&calldata_hex)); - write_calldata_to_file("test_encode_bebop_single", hex_swap.as_str()); - } + // Verify the original amount matches the filledTakerAmount from calldata + assert!( + hex_swap.contains("0000000000000000000000000000000000000000000000000000000bebc200") + ); // 200000000 in hex - #[test] - fn test_encode_bebop_aggregate() { - use alloy::hex; - - // Create user_data for a Bebop Aggregate RFQ quote - let order_type = BebopOrderType::Aggregate as u8; - let signature_type = 0u8; // ETH_SIGN - - // Use real mainnet data from https://etherscan.io/tx/0xec88410136c287280da87d0a37c1cb745f320406ca3ae55c678dec11996c1b1c - // Swap: 0.00985 ETH → 17.969561 USDC - let aggregate_order = BebopAggregate { - expiry: U256::from(1746367285u64), - taker_address: Address::from_str("0x7078B12Ca5B294d95e9aC16D90B7D38238d8F4E6") - .unwrap(), - maker_addresses: vec![ - Address::from_str("0x67336Cec42645F55059EfF241Cb02eA5cC52fF86").unwrap(), - Address::from_str("0xBF19CbF0256f19f39A016a86Ff3551ecC6f2aAFE").unwrap(), - ], - maker_nonces: vec![U256::from(1746367197308u64), U256::from(15460096u64)], - taker_tokens: vec![ - vec![Address::from_str("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").unwrap()], /* WETH for maker 1 */ - vec![Address::from_str("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").unwrap()], /* WETH for maker 2 */ - ], - maker_tokens: vec![ - vec![Address::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").unwrap()], /* USDC from maker 1 */ - vec![Address::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").unwrap()], /* USDC from maker 2 */ - ], - taker_amounts: vec![ - vec![U256::from(5812106401997138u64)], // First maker takes ~0.0058 ETH - vec![U256::from(4037893598002862u64)], // Second maker takes ~0.0040 ETH - ], - maker_amounts: vec![ - vec![U256::from(10607211u64)], // First maker gives ~10.6 USDC - vec![U256::from(7362350u64)], // Second maker gives ~7.36 USDC - ], - receiver: Address::from_str("0x7078B12Ca5B294d95e9aC16D90B7D38238d8F4E6").unwrap(), - commands: hex::decode("00040004").unwrap().into(), - flags: U256::from_str( - "95769172144825922628485191511070792431742484643425438763224908097896054784000", - ) - .unwrap(), - }; - - let quote_data = aggregate_order.abi_encode(); - // Real signatures from mainnet transaction - let sig1 = hex::decode("d5abb425f9bac1f44d48705f41a8ab9cae207517be8553d2c03b06a88995f2f351ab8ce7627a87048178d539dd64fd2380245531a0c8e43fdc614652b1f32fc71c").unwrap(); - let sig2 = hex::decode("f38c698e48a3eac48f184bc324fef0b135ee13705ab38cc0bbf5a792f21002f051e445b9e7d57cf24c35e17629ea35b3263591c4abf8ca87ffa44b41301b89c41b").unwrap(); - - // Build ABI-encoded MakerSignature[] array with 2 signatures - let flags = U256::from(signature_type); - let mut encoded_maker_sigs = Vec::new(); - - // Offset to array (always 0x20 for single parameter) - encoded_maker_sigs.extend_from_slice(&U256::from(32).to_be_bytes::<32>()); - - // Array length (2 for Aggregate order with 2 makers) - encoded_maker_sigs.extend_from_slice(&U256::from(2).to_be_bytes::<32>()); - - // Offsets to structs (relative to array data start) - // First struct at offset 64 (after the 2 offset values) - encoded_maker_sigs.extend_from_slice(&U256::from(64).to_be_bytes::<32>()); - // Second struct will be after first struct's data - // First struct size: 64 (fixed) + 32 (length) + 96 (65 bytes padded) = 192 - encoded_maker_sigs.extend_from_slice(&U256::from(64 + 192).to_be_bytes::<32>()); - - // First struct data (MakerSignature has signatureBytes first, then flags) - // - offset to signatureBytes (always 64) - encoded_maker_sigs.extend_from_slice(&U256::from(64).to_be_bytes::<32>()); - // - flags (AFTER the offset) - encoded_maker_sigs.extend_from_slice(&flags.to_be_bytes::<32>()); - // - signatureBytes length - encoded_maker_sigs.extend_from_slice(&U256::from(sig1.len()).to_be_bytes::<32>()); - // - signatureBytes data (padded) - encoded_maker_sigs.extend_from_slice(&sig1); - let padding1 = (32 - (sig1.len() % 32)) % 32; - encoded_maker_sigs.extend_from_slice(&vec![0u8; padding1]); - - // Second struct data (MakerSignature has signatureBytes first, then flags) - // - offset to signatureBytes (always 64) - encoded_maker_sigs.extend_from_slice(&U256::from(64).to_be_bytes::<32>()); - // - flags (AFTER the offset) - encoded_maker_sigs.extend_from_slice(&flags.to_be_bytes::<32>()); - // - signatureBytes length - encoded_maker_sigs.extend_from_slice(&U256::from(sig2.len()).to_be_bytes::<32>()); - // - signatureBytes data (padded) - encoded_maker_sigs.extend_from_slice(&sig2); - let padding2 = (32 - (sig2.len() % 32)) % 32; - encoded_maker_sigs.extend_from_slice(&vec![0u8; padding2]); - - let filled_taker_amount = U256::from(0u64); // 0 means fill entire order - - let mut user_data = Vec::new(); - user_data.push(order_type); - user_data.extend_from_slice(&filled_taker_amount.to_be_bytes::<32>()); - user_data.extend_from_slice(&(quote_data.len() as u32).to_be_bytes()); - user_data.extend_from_slice("e_data); - user_data.extend_from_slice(&encoded_maker_sigs); - - let bebop_component = ProtocolComponent { - id: String::from("bebop-rfq"), - protocol_system: String::from("rfq:bebop"), - static_attributes: HashMap::new(), - ..Default::default() - }; - - let token_in = Bytes::from(Address::ZERO.as_slice()); // Native ETH - let token_out = Bytes::from("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); // USDC - let swap = Swap { - component: bebop_component, - token_in: token_in.clone(), - token_out: token_out.clone(), - split: 0f64, - user_data: Some(Bytes::from(user_data)), - }; - - let encoding_context = EncodingContext { - receiver: Bytes::from("0x7078B12Ca5B294d95e9aC16D90B7D38238d8F4E6"), /* Taker address from tx */ - exact_out: false, - router_address: Some(Bytes::zero(20)), - group_token_in: token_in.clone(), - group_token_out: token_out.clone(), - transfer_type: TransferType::Transfer, - }; - - let encoder = BebopSwapEncoder::new( - String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), - TychoCoreChain::Ethereum.into(), - Some(HashMap::from([( - "bebop_settlement_address".to_string(), - "0xbbbbbBB520d69a9775E85b458C58c648259FAD5F".to_string(), - )])), - ) - .unwrap(); - - let encoded_swap = encoder - .encode_swap(&swap, &encoding_context) - .unwrap(); - let hex_swap = encode(&encoded_swap); - - // Calculate expected hex for ABI-encoded maker signatures array with 2 signatures - let _expected_abi_maker_sigs = concat!( - // offset to array - "0000000000000000000000000000000000000000000000000000000000000020", - // array length (2) - "0000000000000000000000000000000000000000000000000000000000000002", - // offset to first struct (relative to array data start) - "0000000000000000000000000000000000000000000000000000000000000040", - // offset to second struct (64 + 192 = 256 = 0x100) - "0000000000000000000000000000000000000000000000000000000000000100", - // First struct data: - // - offset to signatureBytes - "0000000000000000000000000000000000000000000000000000000000000040", - // - flags - "0000000000000000000000000000000000000000000000000000000000000000", - // - signatureBytes length (66 = 0x42, actual length of signatures) - "0000000000000000000000000000000000000000000000000000000000000042", - // - signatureBytes (66 bytes padded to 96) - "d5abb425f9bac1f44d48705f41a8ab9cae207517be8553d2c03b06a88995f2f3", - "51ab8ce7627a87048178d539dd64fd2380245531a0c8e43fdc614652b1f32fc7", - "1c00000000000000000000000000000000000000000000000000000000000000", - // Second struct data: - // - offset to signatureBytes - "0000000000000000000000000000000000000000000000000000000000000040", - // - flags - "0000000000000000000000000000000000000000000000000000000000000000", - // - signatureBytes length (66 = 0x42) - "0000000000000000000000000000000000000000000000000000000000000042", - // - signatureBytes (66 bytes padded to 96) - "f38c698e48a3eac48f184bc324fef0b135ee13705ab38cc0bbf5a792f21002f0", - "51e445b9e7d57cf24c35e17629ea35b3263591c4abf8ca87ffa44b41301b89c4", - "1b00000000000000000000000000000000000000000000000000000000000000" - ); - - // The quote data is now an ABI-encoded BebopAggregate struct - // Calculate its actual length - let quote_data_hex = hex::encode("e_data); - let quote_data_length = format!("{:08x}", quote_data.len()); - - let expected_hex = format!( - "{}{}{}{}{}{}{}{}{}{}", - // token in - "0000000000000000000000000000000000000000", - // token out - "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - // transfer type Transfer - "01", - // order type Aggregate (1) - "01", - // filledTakerAmount (0 for full fill) - "0000000000000000000000000000000000000000000000000000000000000000", - // quote data length - "e_data_length, - // quote data - "e_data_hex, - // maker signatures length (0x200 = 512 bytes) - "00000200", - // abi-encoded maker signatures - &encode(&encoded_maker_sigs), - // approval needed - "00" - ); - - assert_eq!(hex_swap, expected_hex); - - write_calldata_to_file("test_encode_bebop_aggregate", hex_swap.as_str()); + write_calldata_to_file("test_encode_bebop_calldata_forwarding", hex_swap.as_str()); } } }