diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/README.md b/README.md index 97d4f41..1c489c5 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,13 @@ BRIDGE_TOKEN="USDT" # USDT COMISSION="10" # if COMISSION == "1"-> 0.01% SOLVER_ID="" # Given by Composable COMPOSABLE_ENDPOINT="" # ws IP address Given by Composable +ALLOWED_TRANSFERS="ethereum,solana,ethereum-solana,solana-ethereum" ``` + +In the example above `ALLOWED_TRANSFER` allows for all possible domains at the moment. +If you want to ignore some incoming intents (e.g. because you cannot handle them well), +remove the appropriate elements from the list. + ## Step 2: Run the Solver To run the solver, use the following command: ```sh diff --git a/example_solver/.env.example b/example_solver/.env.example index b72a077..851e03a 100644 --- a/example_solver/.env.example +++ b/example_solver/.env.example @@ -6,4 +6,5 @@ SOLANA_KEYPAIR="" BRIDGE_TOKEN="USDT" # USDT COMISSION="200" # if COMISSION == "1"-> 0.01% SOLVER_ID="" # Given by Composable -COMPOSABLE_ENDPOINT="" # ws IP address Given by Composable \ No newline at end of file +COMPOSABLE_ENDPOINT="" # ws IP address Given by Composable +ALLOWED_TRANSFERS="ethereum,solana,ethereum-solana,solana-ethereum" \ No newline at end of file diff --git a/example_solver/src/chains/mod.rs b/example_solver/src/chains/mod.rs index b2fc4b2..a3b1bb1 100644 --- a/example_solver/src/chains/mod.rs +++ b/example_solver/src/chains/mod.rs @@ -84,13 +84,62 @@ pub struct PostIntentInfo { pub outputs: OperationOutput, } -#[derive(Debug, PartialEq, Eq, Hash, EnumString, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, EnumString, Serialize, Deserialize)] #[strum(serialize_all = "lowercase")] -enum Blockchain { +pub enum Blockchain { Ethereum, Solana, } +#[derive(Debug, PartialEq, Eq)] +pub struct TransferDir { + pub src: Blockchain, + pub dst: Blockchain, +} + +impl<'a> TryFrom<&'a str> for TransferDir { + type Error = &'a str; + + fn try_from(value: &'a str) -> Result { + let parts: Vec<&str> = value.split("-").collect(); + match parts.len() { + 1 => { + let chn = Blockchain::from_str(parts[0]).map_err(|_| parts[0])?; + Ok(TransferDir { src: chn.clone(), dst: chn }) + }, + 2 => { + let src = Blockchain::from_str(parts[0]).map_err(|_| parts[0])?; + let dst = Blockchain::from_str(parts[1]).map_err(|_| parts[1])?; + Ok(TransferDir { src, dst }) + }, + _ => Err(value), + } + } +} + +impl TransferDir { + pub fn all() -> Vec { + vec![ + Self { + src: Blockchain::Solana, + dst: Blockchain::Solana, + }, + Self { + src: Blockchain::Solana, + dst: Blockchain::Ethereum, + }, + Self { + src: Blockchain::Ethereum, + dst: Blockchain::Solana, + }, + Self { + src: Blockchain::Ethereum, + dst: Blockchain::Ethereum, + }, + ] + } +} + #[derive(Debug, PartialEq, Eq, Hash, EnumString, Serialize, Deserialize)] #[strum(serialize_all = "UPPERCASE")] enum Token { diff --git a/example_solver/src/main.rs b/example_solver/src/main.rs index c254746..086009f 100644 --- a/example_solver/src/main.rs +++ b/example_solver/src/main.rs @@ -12,13 +12,14 @@ use crate::chains::SOLVER_ADDRESSES; use crate::chains::SOLVER_ID; use crate::chains::SOLVER_PRIVATE_KEY; use crate::routers::get_simulate_swap_intent; -use chains::create_keccak256_signature; +use chains::{create_keccak256_signature, Blockchain, TransferDir}; use ethers::types::U256; use futures::{SinkExt, StreamExt}; use serde_json::json; use serde_json::Value; use spl_associated_token_account::get_associated_token_address; use std::env; +use std::str::FromStr; use tokio_tungstenite::connect_async; use tokio_tungstenite::tungstenite::protocol::Message; @@ -37,6 +38,12 @@ async fn main() { "solver_addresses": SOLVER_ADDRESSES, } }); + let allowed_transfers: Vec = env::var("ALLOWED_TRANSFERS") + .map(|s| { + let strs = s.split(','); + strs.map(|s| TransferDir::try_from(s).unwrap()).collect() + }) + .unwrap_or(TransferDir::all()); create_keccak256_signature(&mut json_data, SOLVER_PRIVATE_KEY.to_string()) .await @@ -79,6 +86,17 @@ async fn main() { let intent_value: Value = serde_json::from_str(&intent_str).unwrap(); let intent_info: PostIntentInfo = serde_json::from_value(intent_value).unwrap(); + let trasfer_dir = TransferDir { + src: Blockchain::from_str(&intent_info.src_chain) + .expect("Unrecognized source chain"), + dst: Blockchain::from_str(&intent_info.dst_chain) + .expect("Unrecognized destination chain"), + }; + if ! allowed_transfers.contains(&trasfer_dir) { + println!("Transfer not allowed: {:?}", intent_info); + continue; + } + // calculate best quote let final_amount = get_simulate_swap_intent( &intent_info, @@ -87,7 +105,7 @@ async fn main() { &String::from("USDT"), ) .await; - + // decide if participate or not let mut amount_out_min = U256::zero(); if let OperationOutput::SwapTransfer(transfer_output) = &intent_info.outputs { @@ -158,13 +176,16 @@ async fn main() { .await .unwrap(); } else if intent.dst_chain == "ethereum" { - handle_ethereum_execution(&intent, U256::from_dec_str(intent_id).unwrap(), amount, intent.src_chain == intent.dst_chain) - .await - .unwrap(); + handle_ethereum_execution( + &intent, + U256::from_dec_str(intent_id).unwrap(), + amount, + intent.src_chain == intent.dst_chain, + ) + .await + .unwrap(); } else if intent.dst_chain == "mantis" { - handle_mantis_execution(&intent, intent_id) - .await - .unwrap(); + handle_mantis_execution(&intent, intent_id).await.unwrap(); } // ws_sender.send(Message::text(msg)).await.expect("Failed to send message");