diff --git a/Cargo.lock b/Cargo.lock index 1ca2a6b..5c76227 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2442,6 +2442,7 @@ dependencies = [ "cw-multi-test", "cw-orch", "derive_more", + "displaydoc", "env_logger", "itertools 0.12.1", "log", diff --git a/Cargo.toml b/Cargo.toml index 45e935e..6c37db5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ todo = "warn" let_unit_value = "allow" [workspace.dependencies] - +displaydoc = { version = "^0.2.0", default-features = false } cvm = { path = "./crates/cvm", default-features = false } blackbox_rs = { path = "./node/blackbox_rs", default-features = false } cvm-route = { path = "./crates/cvm-route", default-features = false } diff --git a/mantis/node/Cargo.toml b/mantis/node/Cargo.toml index ebfcfa2..78746d1 100644 --- a/mantis/node/Cargo.toml +++ b/mantis/node/Cargo.toml @@ -24,6 +24,7 @@ cw-mantis-order = { workspace = true, features = [ "std", ] } +displaydoc = { workspace = true } cw-cvm-outpost = { workspace = true, features = ["std"] } cw-cvm-executor = { workspace = true, features = ["std"] } diff --git a/mantis/node/src/error.rs b/mantis/node/src/error.rs new file mode 100644 index 0000000..7a0d641 --- /dev/null +++ b/mantis/node/src/error.rs @@ -0,0 +1,13 @@ +use cosmwasm_std::Uint128; + +#[derive(Debug, displaydoc::Display)] +pub enum MantisError { + /// `{order_id}` Matching order not found + MatchingOrderNotFound { order_id: Uint128 }, + /// `{order_id}` Cow fill badly found because `{reason}` + CowFillBadlyFound { order_id: Uint128, reason: String }, + /// Blackbox error: `{reason}` + BlackboxError { reason: String }, +} + +impl std::error::Error for MantisError {} diff --git a/mantis/node/src/lib.rs b/mantis/node/src/lib.rs index c988ec4..09fb0c0 100644 --- a/mantis/node/src/lib.rs +++ b/mantis/node/src/lib.rs @@ -1,4 +1,5 @@ #![feature(let_chains)] +pub mod error; pub mod mantis; pub mod prelude; pub mod solver; diff --git a/mantis/node/src/mantis/blackbox/mod.rs b/mantis/node/src/mantis/blackbox/mod.rs index f4aa92c..31868bb 100644 --- a/mantis/node/src/mantis/blackbox/mod.rs +++ b/mantis/node/src/mantis/blackbox/mod.rs @@ -9,7 +9,7 @@ use cvm_runtime::{ use cw_cvm_outpost::msg::CvmGlt; use cw_mantis_order::{CrossChainPart, OrderItem, SolutionSubMsg}; -use crate::solver::router::shortest_path; +use crate::{error::MantisError, solver::router::shortest_path}; use super::{ cosmos::client::Tip, @@ -88,9 +88,9 @@ pub async fn get_routes( input: IntentBankInput, cvm_glt: &GetConfigResponse, salt: &[u8], -) -> Vec { +) -> Result, MantisError> { if route_provider == "shortest_path" { - return shortest_path::route(cvm_glt, input, salt); + Ok(shortest_path::route(cvm_glt, input, salt)) } else { let blackbox: Client = Client::new(route_provider); let mut route = blackbox @@ -102,13 +102,22 @@ pub async fn get_routes( input.out_asset_id.to_string().as_str().into(), ) .await - .expect("route found") + .map_err(|x| MantisError::BlackboxError { + reason: x.to_string(), + })? .into_inner() .pop() - .expect("at least one route"); + .ok_or(MantisError::BlackboxError { + reason: "no routes".to_string(), + })?; log::info!("route: {:?}", route); - build_instructions(input.order_accounts, &route.next[0], cvm_glt, salt) + Ok(build_instructions( + input.order_accounts, + &route.next[0], + cvm_glt, + salt, + )) } } @@ -180,9 +189,6 @@ pub async fn solve>( let cows_per_pair = find_cows(&active_orders); let mut msgs = vec![]; - // this we do just to avoid one pair to fail all others, really need to handle all errors gracefully or run solver(thread/process) per pair (i am for second) - let cows_per_pair = cows_per_pair.into_iter().take(1).collect::>(); - for pair_solution in cows_per_pair { let salt = super::cosmos::cvm::calculate_salt(signing_key, tip, pair_solution.ab.clone()); let cvm_program = if let Some(ref cvm_glt) = cvm_glt { @@ -195,6 +201,13 @@ pub async fn solve>( ) .await; + if cvm_program.is_err() { + log::error!("cvm_program error: {:?}", cvm_program); + continue; + } + + let cvm_program = cvm_program.expect("qed"); + Some(cvm_program) } else { None @@ -230,21 +243,21 @@ async fn intent_banks_to_cvm_program( cvm_glt: &cw_cvm_outpost::msg::GetConfigResponse, router_api: &str, salt: &Vec, -) -> CvmProgram { +) -> Result { let intents = IntentBankInput::find_intent_amount( pair_solution.cows.as_ref(), all_orders, pair_solution.optimal_price, cvm_glt, pair_solution.ab.clone(), - ); + )?; log::info!(target:"mantis::solver::", "intents: {:?}", intents); let mut instructions = vec![]; for intent in intents.into_iter().filter(|x| x.in_asset_amount.0.gt(&0)) { - let mut cvm_routes = get_routes(router_api, intent, cvm_glt, salt.as_ref()).await; + let mut cvm_routes = get_routes(router_api, intent, cvm_glt, salt.as_ref()).await?; instructions.append(&mut cvm_routes); } @@ -254,5 +267,5 @@ async fn intent_banks_to_cvm_program( tag: salt.to_vec(), instructions, }; - cvm_program + Ok(cvm_program) } diff --git a/mantis/node/src/mantis/solve.rs b/mantis/node/src/mantis/solve.rs index 8098b08..bd87f1b 100644 --- a/mantis/node/src/mantis/solve.rs +++ b/mantis/node/src/mantis/solve.rs @@ -8,6 +8,7 @@ use mantis_cw::{DenomPair, OrderCoinPair}; use num_rational::Ratio; use crate::{ + error::MantisError, prelude::*, solver::cows::{orderbook::OrderList, solution::Solution}, }; @@ -43,7 +44,7 @@ impl IntentBankInput { optimal_ratio: Ratio, cvm_glt: &GetConfigResponse, pair: DenomPair, - ) -> Vec { + ) -> Result, MantisError> { // native calculations let mut pair = OrderCoinPair::zero(pair.a, pair.b); let mut a_to_b = Vec::new(); @@ -55,11 +56,16 @@ impl IntentBankInput { let mut order = orders .iter() .find(|x| x.order_id == cow.order_id) - .expect("order") + .ok_or(MantisError::MatchingOrderNotFound { + order_id: cow.order_id, + })? .clone(); order .fill(cow.cow_out_amount, optimal_ratio.into()) - .expect("off chain"); + .map_err(|x| MantisError::CowFillBadlyFound { + order_id: cow.order_id, + reason: x.to_string(), + })?; pair.add(&order.given); if order.given.denom == pair.a.denom { @@ -106,7 +112,7 @@ impl IntentBankInput { IntentBankInput::new(b_asset, pair.b.amount.into(), a_asset, a_received.collect()); intents.push(intent); } - intents + Ok(intents) } }