test: add uniswap v3 => bebop sequential swap

This commit is contained in:
pedrobergamini
2025-06-07 18:36:01 -03:00
parent 2bac529fc1
commit 68d4d083c3
5 changed files with 156 additions and 27 deletions

View File

@@ -47,5 +47,6 @@ pub static CALLBACK_CONSTRAINED_PROTOCOLS: LazyLock<HashSet<&'static str>> = Laz
set.insert("pancakeswap_v3");
set.insert("uniswap_v4");
set.insert("ekubo_v2");
set.insert("rfq:bebop");
set
});

View File

@@ -585,11 +585,11 @@ pub struct BebopSwapEncoder {
impl BebopSwapEncoder {
/// Validates the component ID format
/// Component format: "bebop"
/// Component format: "bebop-rfq"
fn validate_component_id(component_id: &str) -> Result<(), EncodingError> {
if component_id != "bebop" {
if component_id != "bebop-rfq" {
return Err(EncodingError::FatalError(
"Invalid Bebop component ID format. Expected 'bebop'".to_string(),
"Invalid Bebop component ID format. Expected 'bebop-rfq'".to_string(),
));
}
Ok(())
@@ -1678,7 +1678,7 @@ mod tests {
.insert("signature".into(), Bytes::from(hex::decode("aabbccdd").unwrap()));
let bebop_component = ProtocolComponent {
id: String::from("bebop"),
id: String::from("bebop-rfq"),
protocol_system: String::from("rfq:bebop"),
static_attributes,
..Default::default()
@@ -1759,7 +1759,7 @@ mod tests {
static_attributes.insert("order_type".into(), Bytes::from(vec![1u8])); // Multi order
let bebop_component = ProtocolComponent {
id: String::from("bebop"),
id: String::from("bebop-rfq"),
protocol_system: String::from("rfq:bebop"),
static_attributes,
..Default::default()
@@ -1843,7 +1843,7 @@ mod tests {
static_attributes.insert("order_type".into(), Bytes::from(vec![2u8])); // Aggregate order
let bebop_component = ProtocolComponent {
id: String::from("bebop"),
id: String::from("bebop-rfq"),
protocol_system: String::from("rfq:bebop"),
static_attributes,
..Default::default()

View File

@@ -1917,6 +1917,7 @@ mod tests {
// In this module we test the ability to chain swaps or not. Different protocols are
// tested. The encoded data is used for solidity tests as well
use super::*;
use std::time::{SystemTime, UNIX_EPOCH};
#[test]
fn test_uniswap_v3_uniswap_v2() {
@@ -2260,6 +2261,131 @@ mod tests {
write_calldata_to_file("test_balancer_v2_uniswap_v2", hex_calldata.as_str());
}
#[test]
fn test_uniswap_v3_bebop() {
// Note: This test does not assert anything. It is only used to obtain
// integration test data for our router solidity test.
//
// Performs a sequential swap from WETH to DAI through USDC using USV3 and Bebop RFQ
//
// WETH ───(USV3)──> USDC ───(Bebop RFQ)──> DAI
let weth = weth();
let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
let dai = Bytes::from_str("0x6b175474e89094c44da98b954eedeac495271d0f").unwrap();
// First swap: WETH -> USDC via UniswapV3
let swap_weth_usdc = Swap {
component: ProtocolComponent {
id: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640".to_string(), // WETH-USDC USV3 Pool 0.05%
protocol_system: "uniswap_v3".to_string(),
static_attributes: {
let mut attrs = HashMap::new();
attrs.insert(
"fee".to_string(),
Bytes::from(BigInt::from(500).to_signed_bytes_be()),
);
attrs
},
..Default::default()
},
token_in: weth.clone(),
token_out: usdc.clone(),
split: 0f64,
};
// Second swap: USDC -> DAI via Bebop RFQ
// Create a valid Bebop Single order struct
let expiry = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() + 3600; // Current time + 1 hour
let taker_address = Address::ZERO;
let maker_address =
Address::from_str("0xbbbbbBB520d69a9775E85b458C58c648259FAD5F").unwrap();
let maker_nonce = 1u64;
let taker_token = Address::from_str(&usdc.to_string()).unwrap();
let maker_token = Address::from_str(&dai.to_string()).unwrap();
// For ~2021.75 USDC input (what 1 ETH gives us via USV3), expecting ~2021.75 DAI output
let taker_amount = U256::from_str("2021750881").unwrap(); // 2021.75 USDC (6 decimals)
let maker_amount = U256::from_str("2021750881000000000000").unwrap(); // 2021.75 DAI (18 decimals)
let receiver =
Address::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(); // Alice's address
let packed_commands = U256::ZERO;
// Encode using standard ABI encoding (not packed)
let quote_data = (
expiry,
taker_address,
maker_address,
maker_nonce,
taker_token,
maker_token,
taker_amount,
maker_amount,
receiver,
packed_commands,
U256::from(0u64), // flags as uint256
)
.abi_encode();
let quote_data = Bytes::from(quote_data);
let signature = Bytes::from(hex::decode("aabbccdd").unwrap());
// Create static attributes for the Bebop component
let mut static_attributes: HashMap<String, Bytes> = HashMap::new();
static_attributes.insert("quote_data".into(), quote_data);
static_attributes.insert("signature".into(), signature);
let bebop_component = ProtocolComponent {
id: String::from("bebop-rfq"),
protocol_system: String::from("rfq:bebop"),
static_attributes,
..Default::default()
};
let swap_usdc_dai = Swap {
component: bebop_component,
token_in: usdc.clone(),
token_out: dai.clone(),
split: 0f64,
};
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
let solution = Solution {
exact_out: false,
given_token: weth,
given_amount: BigUint::from_str("1_000000000000000000").unwrap(), // 1 WETH
checked_token: dai,
checked_amount: BigUint::from_str("2021750881000000000000").unwrap(), // Expected ~2021.75 DAI
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2")
.unwrap(),
swaps: vec![swap_weth_usdc, swap_usdc_dai],
..Default::default()
};
let encoded_solution = encoder
.encode_solutions(vec![solution.clone()])
.unwrap()[0]
.clone();
let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap()
.data;
let hex_calldata = encode(&calldata);
write_calldata_to_file("test_uniswapv3_bebop", hex_calldata.as_str());
}
#[test]
fn test_multi_protocol() {
// Note: This test does not assert anything. It is only used to obtain
@@ -3397,7 +3523,7 @@ mod tests {
#[test]
fn test_single_encoding_strategy_bebop() {
// USDC -> (bebop) -> WETH
// USDC -> (Bebop RFQ) -> WETH
let token_in = Bytes::from("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); // USDC
let token_out = Bytes::from("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); // WETH
let amount_in = BigUint::from_str("1000_000000").unwrap(); // 1000 USDC
@@ -3447,7 +3573,7 @@ mod tests {
static_attributes.insert("signature".into(), signature);
let bebop_component = ProtocolComponent {
id: String::from("bebop"),
id: String::from("bebop-rfq"),
protocol_system: String::from("rfq:bebop"),
static_attributes,
..Default::default()