feat: use clap for cli and resolve pr comments

This commit is contained in:
royvardhan
2025-02-06 18:30:52 +05:30
parent b93856073c
commit a5166f282d
7 changed files with 181 additions and 69 deletions

115
Cargo.lock generated
View File

@@ -647,6 +647,56 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
"once_cell",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.95" version = "1.0.95"
@@ -1298,6 +1348,46 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "clap"
version = "4.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.96",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]] [[package]]
name = "coins-ledger" name = "coins-ledger"
version = "0.12.0" version = "0.12.0"
@@ -1321,6 +1411,12 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
] ]
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]] [[package]]
name = "const-hex" name = "const-hex"
version = "1.14.0" version = "1.14.0"
@@ -2342,6 +2438,12 @@ version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@@ -3752,6 +3854,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.25.0" version = "0.25.0"
@@ -4238,6 +4346,7 @@ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-sol-types", "alloy-sol-types",
"chrono", "chrono",
"clap",
"dotenv", "dotenv",
"hex", "hex",
"lazy_static", "lazy_static",
@@ -4358,6 +4467,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "utoipa" name = "utoipa"
version = "4.2.3" version = "4.2.3"

View File

@@ -19,6 +19,7 @@ serde_json = "1.0.135"
thiserror = "1.0.69" thiserror = "1.0.69"
tokio = { version = "1.38.0", features = ["full"] } tokio = { version = "1.38.0", features = ["full"] }
chrono = "0.4.39" chrono = "0.4.39"
clap = { version = "4.5.3", features = ["derive"] }
alloy = { version = "0.9.2", features = ["providers", "rpc-types-eth", "eip712", "signer-local"], optional = true } alloy = { version = "0.9.2", features = ["providers", "rpc-types-eth", "eip712", "signer-local"], optional = true }
alloy-sol-types = { version = "0.8.14", optional = true } alloy-sol-types = { version = "0.8.14", optional = true }

View File

@@ -6,27 +6,34 @@ Tycho Execution makes it easy to trade on different DEXs by handling the complex
custom code for each DEX, you get a simple, ready-to-use tool that generates the necessary data to execute trades. It's custom code for each DEX, you get a simple, ready-to-use tool that generates the necessary data to execute trades. It's
designed to be safe, straightforward, and quick to set up, so anyone can start trading without extra effort. designed to be safe, straightforward, and quick to set up, so anyone can start trading without extra effort.
## Usage Guide ## Bin Usage Guide
### Encoding Transactions ### Encoding Transactions
To encode a transaction, you can pipe a JSON payload to the `tycho-encode` binary: To encode a transaction, you can pipe a JSON payload to the binary:
```bash ```bash
echo '<json_payload>' | cargo run --bin tycho-encode echo '<solution_payload>' | cargo run
``` ```
#### Example #### Example
Here's a complete example that encodes a swap from WETH to DAI using Uniswap V2: Here's a complete example that encodes a swap from WETH to DAI using Uniswap V2:
First build the project:
```bash ```bash
echo '{"sender":"0x1234567890123456789012345678901234567890","receiver":"0x1234567890123456789012345678901234567890","given_token":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","given_amount":"1000000000000000000","checked_token":"0x6B175474E89094C44Da98b954EedeAC495271d0F","exact_out":false,"slippage":0.01,"expected_amount":"1000000000000000000","check_amount":"990000000000000000","router_address":"0xaa820C29648D5EA543d712cC928377Bd7206a0E7","swaps":[{"component":{"id":"0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640","protocol_system":"uniswap_v2","protocol_type_name":"UniswapV2Pool","chain":"ethereum","tokens":["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"],"contract_ids":["0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"],"static_attributes":{"factory":"0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f"},"change":"Update","creation_tx":"0x0000000000000000000000000000000000000000000000000000000000000000","created_at":"2024-02-28T12:00:00"},"token_in":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","token_out":"0x6B175474E89094C44Da98b954EedeAC495271d0F","split":1.0}],"direct_execution":false}' | cargo run cargo build --release
``` ```
#### JSON Payload Structure After that, you can use the binary directly:
```bash
echo '{"sender":"0x1234567890123456789012345678901234567890","receiver":"0x1234567890123456789012345678901234567890","given_token":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","given_amount":"1000000000000000000","checked_token":"0x6B175474E89094C44Da98b954EedeAC495271d0F","exact_out":false,"slippage":0.01,"expected_amount":"1000000000000000000","check_amount":"990000000000000000","router_address":"0xaa820C29648D5EA543d712cC928377Bd7206a0E7","swaps":[{"component":{"id":"0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640","protocol_system":"uniswap_v2","protocol_type_name":"UniswapV2Pool","chain":"ethereum","tokens":["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"],"contract_ids":["0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"],"static_attributes":{"factory":"0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f"},"change":"Update","creation_tx":"0x0000000000000000000000000000000000000000000000000000000000000000","created_at":"2024-02-28T12:00:00"},"token_in":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","token_out":"0x6B175474E89094C44Da98b954EedeAC495271d0F","split":1.0}],"direct_execution":true}' | cargo run --release
```
The input JSON payload requires the following fields:
#### JSON Payload Structure: Solution struct
The `Solution` struct is composed of the following fields:
- `sender`: The address initiating the transaction - `sender`: The address initiating the transaction
- `receiver`: The address receiving the output tokens - `receiver`: The address receiving the output tokens

45
src/bin/lib/cli.rs Normal file
View File

@@ -0,0 +1,45 @@
pub use clap::Parser;
pub const DEFAULT_ROUTER_ADDRESS: &str = "0xaa820C29648D5EA543d712cC928377Bd7206a0E7";
#[derive(Parser)]
/// Encode swap transactions for the Tycho router
///
/// Reads a JSON object from stdin with the following structure:
/// ```json
/// {
/// "sender": "0x...",
/// "receiver": "0x...",
/// "given_token": "0x...",
/// "given_amount": "123...",
/// "checked_token": "0x...",
/// "exact_out": false,
/// "slippage": 0.01,
/// "expected_amount": "123...",
/// "check_amount": "123...",
/// "swaps": [{
/// "component": {
/// "id": "...",
/// "protocol_system": "...",
/// "protocol_type_name": "...",
/// "chain": "ethereum",
/// "tokens": ["0x..."],
/// "contract_ids": ["0x..."],
/// "static_attributes": {"key": "0x..."}
/// },
/// "token_in": "0x...",
/// "token_out": "0x...",
/// "split": 1.0
/// }],
/// "router_address": "0x...",
/// "direct_execution": false
/// }
/// ```
pub struct Cli {
/// Router contract address to use for encoding transactions
#[arg(default_value = DEFAULT_ROUTER_ADDRESS)]
pub router_address: String,
/// Private key for signing approvals (required when direct_execution is false)
#[arg(short, long)]
pub private_key: Option<String>,
}

View File

@@ -1,37 +0,0 @@
pub const HELP_TEXT: &str = "\
USAGE:
tycho-encode [ROUTER_ADDRESS] [PRIVATE_KEY]
ARGS:
ROUTER_ADDRESS The address of the router contract [default: 0x1234567890123456789012345678901234567890]
PRIVATE_KEY The private key for signing Permit2 approvals (required when direct_execution is false)
The program reads a JSON object from stdin containing the swap details and outputs the encoded transaction.
The JSON object should have the following structure:
{
\"sender\": \"0x...\",
\"receiver\": \"0x...\",
\"given_token\": \"0x...\",
\"given_amount\": \"123...\",
\"checked_token\": \"0x...\",
\"exact_out\": false,
\"slippage\": 0.01,
\"expected_amount\": \"123...\",
\"check_amount\": \"123...\",
\"swaps\": [{
\"component\": {
\"id\": \"...\",
\"protocol_system\": \"...\",
\"protocol_type_name\": \"...\",
\"chain\": \"ethereum\",
\"tokens\": [\"0x...\"],
\"contract_ids\": [\"0x...\"],
\"static_attributes\": {\"key\": \"0x...\"}
},
\"token_in\": \"0x...\",
\"token_out\": \"0x...\",
\"split\": 1.0
}],
\"router_address\": \"0x...\",
\"direct_execution\": false
}";

View File

@@ -1,5 +1,6 @@
use std::io::{self, Read}; use std::io::{self, Read};
use clap::Parser;
use serde_json::Value; use serde_json::Value;
use tycho_core::dto::Chain; use tycho_core::dto::Chain;
use tycho_execution::encoding::{ use tycho_execution::encoding::{
@@ -13,32 +14,15 @@ use tycho_execution::encoding::{
}; };
mod lib { mod lib {
pub mod help; pub mod cli;
} }
const DEFAULT_ROUTER_ADDRESS: &str = "0xaa820C29648D5EA543d712cC928377Bd7206a0E7"; use lib::cli::Cli;
const DEFAULT_EXECUTORS_FILE_PATH: &str = "src/encoding/config/executor_addresses.json"; const DEFAULT_EXECUTORS_FILE_PATH: &str = "src/encoding/config/executor_addresses.json";
const DEFAULT_PRIVATE_KEY: &str =
"0x938f4da9d3a947a4a6c53cfd8fcdd876641d6a4519243820b648af0bc3e67f7c";
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().collect(); let cli = Cli::parse();
// Show help text if requested
if args.len() > 1 && (args[1] == "-h" || args[1] == "--help") {
println!("{}", lib::help::HELP_TEXT);
return Ok(());
}
let router_address = args
.get(1)
.map(|s| s.as_str())
.unwrap_or(DEFAULT_ROUTER_ADDRESS);
let private_key = args
.get(2)
.map(|s| s.to_string())
.or_else(|| Some(DEFAULT_PRIVATE_KEY.to_string()));
// Read from stdin until EOF // Read from stdin until EOF
let mut buffer = String::new(); let mut buffer = String::new();
@@ -47,13 +31,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.map_err(|e| format!("Failed to read from stdin: {}", e))?; .map_err(|e| format!("Failed to read from stdin: {}", e))?;
if buffer.trim().is_empty() { if buffer.trim().is_empty() {
eprintln!("Error: No input provided"); return Err("No input provided. Expected JSON input on stdin.".into());
eprintln!("{}", lib::help::HELP_TEXT);
std::process::exit(1);
} }
// Encode the solution // Encode the solution
let encoded = encode_swaps(&buffer, router_address, private_key)?; let encoded = encode_swaps(&buffer, &cli.router_address, cli.private_key)?;
// Output the encoded result as JSON to stdout // Output the encoded result as JSON to stdout
println!( println!(

View File

@@ -5,7 +5,6 @@ use tycho_core::{dto::ProtocolComponent, Bytes};
use crate::encoding::serde_primitives::{biguint_string, biguint_string_option}; use crate::encoding::serde_primitives::{biguint_string, biguint_string_option};
#[derive(Clone, Default, Debug, Deserialize, Serialize)] #[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct Solution { pub struct Solution {
/// Address of the sender. /// Address of the sender.
pub sender: Bytes, pub sender: Bytes,