feat: Adapt SplitSwapStrategyEncoder to have optional permit2 logic

- If the signer_pk is not passed -> use the swap method that expects the tokens to be already in the Router
- If it is passed -> compute permit2 and use swap method that does the token in transfer
- Extend builder to have another shortcut
- Add integration test with contract
- Update bin (and simplified it) and quickstart

--- don't change below this line ---
ENG-4255 Took 1 hour 51 minutes

Took 2 minutes

Took 7 seconds
This commit is contained in:
Diana Carvalho
2025-02-20 17:14:49 +00:00
parent 30a7d5bbe4
commit 20e6419a20
6 changed files with 213 additions and 92 deletions

View File

@@ -1,11 +1,9 @@
use std::io::{self, Read};
use clap::{Parser, Subcommand};
use serde_json::Value;
use tycho_core::models::Chain;
use tycho_execution::encoding::{
errors::EncodingError, evm::encoder_builder::EVMEncoderBuilder, models::Solution,
tycho_encoder::TychoEncoder,
evm::encoder_builder::EVMEncoderBuilder, models::Solution, tycho_encoder::TychoEncoder,
};
#[derive(Parser)]
@@ -52,6 +50,11 @@ pub enum Commands {
TychoRouter {
#[arg(short, long)]
config_path: Option<String>,
},
/// Use the Tycho router encoding strategy with Permit2 approval and token in transfer
TychoRouterPermit2 {
#[arg(short, long)]
config_path: Option<String>,
#[arg(short, long)]
swapper_pk: String,
},
@@ -64,6 +67,7 @@ pub enum Commands {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
let chain = Chain::Ethereum;
// Read from stdin until EOF
let mut buffer = String::new();
@@ -74,16 +78,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if buffer.trim().is_empty() {
return Err("No input provided. Expected JSON input on stdin.".into());
}
let solution: Solution = serde_json::from_str(&buffer)?;
// Encode the solution
let encoded = match cli.command {
Commands::TychoRouter { config_path, swapper_pk } => {
encode_swaps(&buffer, config_path, Some(swapper_pk), true)?
}
Commands::DirectExecution { config_path } => {
encode_swaps(&buffer, config_path, None, false)?
let mut builder = EVMEncoderBuilder::new().chain(chain);
builder = match cli.command {
Commands::TychoRouter { config_path } => builder.tycho_router(config_path)?,
Commands::TychoRouterPermit2 { config_path, swapper_pk } => {
builder.tycho_router_with_permit2(config_path, swapper_pk)?
}
Commands::DirectExecution { config_path } => builder.direct_execution(config_path)?,
};
let encoder = builder.build()?;
let transactions = encoder.encode_router_calldata(vec![solution])?;
let encoded = serde_json::json!({
"to": format!("0x{}", hex::encode(&transactions[0].to)),
"value": format!("0x{}", hex::encode(transactions[0].value.to_bytes_be())),
"data": format!("0x{}", hex::encode(&transactions[0].data)),
});
// Output the encoded result as JSON to stdout
println!(
"{}",
@@ -93,32 +105,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
fn encode_swaps(
input: &str,
config_path: Option<String>,
swapper_pk: Option<String>,
use_tycho_router: bool,
) -> Result<Value, EncodingError> {
let solution: Solution = serde_json::from_str(input)?;
let chain = Chain::Ethereum;
let mut builder = EVMEncoderBuilder::new().chain(chain);
builder = if use_tycho_router {
let private_key = swapper_pk.ok_or(EncodingError::FatalError(
"Swapper private key is required for tycho_router".to_string(),
))?;
builder.tycho_router(private_key, config_path)?
} else {
builder.direct_execution(config_path)?
};
let encoder = builder.build()?;
let transactions = encoder.encode_router_calldata(vec![solution])?;
Ok(serde_json::json!({
"to": format!("0x{}", hex::encode(&transactions[0].to)),
"value": format!("0x{}", hex::encode(transactions[0].value.to_bytes_be())),
"data": format!("0x{}", hex::encode(&transactions[0].data)),
}))
}