This puts too much burden on the user. Instead, specify native and wrapped tokens as methods which return hardcoded values.
159 lines
6.1 KiB
Rust
159 lines
6.1 KiB
Rust
use std::str::FromStr;
|
|
|
|
use num_bigint::BigUint;
|
|
use tycho_core::{
|
|
dto::{Chain as TychoCoreChain, ProtocolComponent},
|
|
Bytes,
|
|
};
|
|
use tycho_execution::encoding::{
|
|
evm::{
|
|
strategy_encoder::strategy_encoder_registry::EVMStrategyEncoderRegistry,
|
|
tycho_encoder::EVMTychoEncoder,
|
|
},
|
|
models::{Chain, Solution, Swap},
|
|
strategy_encoder::StrategyEncoderRegistry,
|
|
tycho_encoder::TychoEncoder,
|
|
};
|
|
|
|
fn main() {
|
|
// Setup variables
|
|
let router_address = "0x1234567890abcdef1234567890abcdef12345678".to_string();
|
|
let signer_pk =
|
|
Some("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string());
|
|
let user_address = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2")
|
|
.expect("Failed to create user address");
|
|
let executors_file_path = "src/encoding/config/executor_addresses.json";
|
|
|
|
let eth_chain = Chain::from(TychoCoreChain::Ethereum);
|
|
// Initialize the encoder
|
|
let strategy_encoder_registry =
|
|
EVMStrategyEncoderRegistry::new(eth_chain.clone(), executors_file_path, signer_pk.clone())
|
|
.expect("Failed to create strategy encoder registry");
|
|
let encoder = EVMTychoEncoder::new(strategy_encoder_registry, router_address, eth_chain)
|
|
.expect("Failed to create encoder");
|
|
|
|
// ------------------- Encode a simple swap -------------------
|
|
|
|
// Prepare data to encode. We will encode a simple swap from WETH to USDC
|
|
// First we need to create a swap object
|
|
let weth = Bytes::from_str("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
|
|
.expect("Failed to create WETH address");
|
|
let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")
|
|
.expect("Failed to create USDC address");
|
|
|
|
let simple_swap = Swap {
|
|
// The protocol component data comes from tycho-indexer
|
|
component: ProtocolComponent {
|
|
id: "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc".to_string(),
|
|
protocol_system: "uniswap_v2".to_string(),
|
|
..Default::default()
|
|
},
|
|
token_in: weth.clone(),
|
|
token_out: usdc.clone(),
|
|
// Split defines the fraction of the amount to be swapped. A value of 0 indicates 100% of
|
|
// the amount or the total remaining balance.
|
|
split: 0f64,
|
|
};
|
|
|
|
// Then we create a solution object with the previous swap
|
|
let solution = Solution {
|
|
sender: user_address.clone(),
|
|
receiver: user_address.clone(),
|
|
given_token: weth.clone(),
|
|
given_amount: BigUint::from_str("1_000000000000000000").expect("Failed to create amount"),
|
|
checked_token: usdc.clone(),
|
|
exact_out: false, // it's an exact in solution
|
|
check_amount: None, // the amount out will not be checked in execution
|
|
swaps: vec![simple_swap],
|
|
..Default::default()
|
|
};
|
|
|
|
// Encode the solution
|
|
let tx = encoder
|
|
.encode_router_calldata(vec![solution.clone()])
|
|
.expect("Failed to encode router calldata")[0]
|
|
.clone();
|
|
println!(" ====== Simple swap WETH -> USDC ======");
|
|
println!(
|
|
"The simple swap encoded transaction should be sent to address {:?} with the value of {:?} and the \
|
|
following encoded data: {:?}",
|
|
tx.to,
|
|
tx.value,
|
|
hex::encode(tx.data)
|
|
);
|
|
|
|
// ------------------- Encode a swap with multiple splits -------------------
|
|
// To illustrate a more complex solution, we will encode a swap from WETH to USDC with multiple
|
|
// splits. Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
|
|
//
|
|
// ┌──(USV2)──> WBTC ───(USV2)──> USDC
|
|
// WETH ─┤
|
|
// └──(USV2)──> DAI ───(USV2)──> USDC
|
|
//
|
|
|
|
let wbtc = Bytes::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599")
|
|
.expect("Failed to create WBTC address");
|
|
let dai = Bytes::from_str("0x6b175474e89094c44da98b954eedeac495271d0f")
|
|
.expect("Failed to create DAI address");
|
|
|
|
let swap_weth_dai = Swap {
|
|
component: ProtocolComponent {
|
|
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
|
protocol_system: "uniswap_v2".to_string(),
|
|
..Default::default()
|
|
},
|
|
token_in: weth.clone(),
|
|
token_out: dai.clone(),
|
|
split: 0.5f64,
|
|
};
|
|
let swap_weth_wbtc = Swap {
|
|
component: ProtocolComponent {
|
|
id: "0xBb2b8038a1640196FbE3e38816F3e67Cba72D940".to_string(),
|
|
protocol_system: "uniswap_v2".to_string(),
|
|
..Default::default()
|
|
},
|
|
token_in: weth.clone(),
|
|
token_out: wbtc.clone(),
|
|
// This represents the remaining 50%, but to avoid any rounding errors we set this to
|
|
// 0 to signify "the remainder of the WETH value". It should still be very close to 50%
|
|
split: 0f64,
|
|
};
|
|
let swap_dai_usdc = Swap {
|
|
component: ProtocolComponent {
|
|
id: "0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5".to_string(),
|
|
protocol_system: "uniswap_v2".to_string(),
|
|
..Default::default()
|
|
},
|
|
token_in: dai.clone(),
|
|
token_out: usdc.clone(),
|
|
split: 0f64,
|
|
};
|
|
let swap_wbtc_usdc = Swap {
|
|
component: ProtocolComponent {
|
|
id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(),
|
|
protocol_system: "uniswap_v2".to_string(),
|
|
..Default::default()
|
|
},
|
|
token_in: wbtc.clone(),
|
|
token_out: usdc.clone(),
|
|
split: 0f64,
|
|
};
|
|
let mut complex_solution = solution.clone();
|
|
complex_solution.swaps = vec![swap_weth_dai, swap_weth_wbtc, swap_dai_usdc, swap_wbtc_usdc];
|
|
|
|
// Encode the solution
|
|
let complex_tx = encoder
|
|
.encode_router_calldata(vec![complex_solution])
|
|
.expect("Failed to encode router calldata")[0]
|
|
.clone();
|
|
|
|
println!(" ====== Complex split swap WETH -> USDC ======");
|
|
println!(
|
|
"The complex solution encoded transaction should be sent to address {:?} with the value of {:?} and the \
|
|
following encoded data: {:?}",
|
|
complex_tx.to,
|
|
complex_tx.value,
|
|
hex::encode(complex_tx.data)
|
|
);
|
|
}
|