diff --git a/crates/js_api/src/gui/deposits.rs b/crates/js_api/src/gui/deposits.rs index b46fa76bb..e77377d51 100644 --- a/crates/js_api/src/gui/deposits.rs +++ b/crates/js_api/src/gui/deposits.rs @@ -20,7 +20,7 @@ impl DotrainOrderGui { .deployment .deposits .iter() - .find(|dg| dg.token_name == *token) + .find(|dg| dg.token.key == *token) .ok_or(GuiError::DepositTokenNotFound(token.clone()))?; let amount: String = if value.is_preset { gui_deposit @@ -33,7 +33,7 @@ impl DotrainOrderGui { value.value.clone() }; Ok(TokenDeposit { - token: gui_deposit.token_name.clone(), + token: gui_deposit.token.key.clone(), amount, address: gui_deposit.token.address, }) @@ -47,7 +47,7 @@ impl DotrainOrderGui { .deployment .deposits .iter() - .find(|dg| dg.token_name == token) + .find(|dg| dg.token.key == token) .ok_or(GuiError::DepositTokenNotFound(token.clone()))?; let value = if let Some(index) = gui_deposit.presets.iter().position(|p| **p == amount) { @@ -77,7 +77,7 @@ impl DotrainOrderGui { .deployment .deposits .iter() - .find(|dg| dg.token_name == token) + .find(|dg| dg.token.key == token) .ok_or(GuiError::DepositTokenNotFound(token.clone()))?; Ok(gui_deposit.presets.clone()) } diff --git a/crates/js_api/src/gui/mod.rs b/crates/js_api/src/gui/mod.rs index e0b1ce5df..b6dcce7e6 100644 --- a/crates/js_api/src/gui/mod.rs +++ b/crates/js_api/src/gui/mod.rs @@ -94,7 +94,7 @@ impl DotrainOrderGui { } if let Some(select_tokens) = &select_tokens { - if select_tokens.contains_key(&token.token_name) { + if select_tokens.contains_key(&token.token.key) { continue; } } @@ -120,10 +120,8 @@ impl DotrainOrderGui { let (_, gui_deployment) = gui_config .deployments .into_iter() - .find(|(name, _)| name == &self.deployment.deployment_name) - .ok_or(GuiError::DeploymentNotFound( - self.deployment.deployment_name.clone(), - ))?; + .find(|(name, _)| name == &self.deployment.key) + .ok_or(GuiError::DeploymentNotFound(self.deployment.key.clone()))?; self.deployment = gui_deployment.clone(); Ok(()) } diff --git a/crates/js_api/src/gui/order_operations.rs b/crates/js_api/src/gui/order_operations.rs index ebae5703e..2a0b754f8 100644 --- a/crates/js_api/src/gui/order_operations.rs +++ b/crates/js_api/src/gui/order_operations.rs @@ -147,18 +147,14 @@ impl DotrainOrderGui { let calldatas = self .dotrain_order - .generate_approval_calldatas( - &self.deployment.deployment_name, - &owner, - &self.get_deposits_as_map()?, - ) + .generate_approval_calldatas(&self.deployment.key, &owner, &self.get_deposits_as_map()?) .await?; Ok(ApprovalCalldataResult(calldatas)) } fn populate_vault_ids(&mut self) -> Result<(), GuiError> { self.dotrain_order - .populate_vault_ids(&self.deployment.deployment_name, None)?; + .populate_vault_ids(&self.deployment.key, None)?; self.refresh_gui_deployment()?; Ok(()) } @@ -196,7 +192,7 @@ impl DotrainOrderGui { .collect::, GuiError>>()?; let calldatas = self .dotrain_order - .generate_deposit_calldatas(&self.deployment.deployment_name, &token_deposits) + .generate_deposit_calldatas(&self.deployment.key, &token_deposits) .await?; Ok(DepositCalldataResult(calldatas)) } @@ -211,7 +207,7 @@ impl DotrainOrderGui { self.update_config_source_bindings()?; let calldata = self .dotrain_order - .generate_add_order_calldata(&self.deployment.deployment_name) + .generate_add_order_calldata(&self.deployment.key) .await?; Ok(AddOrderCalldataResult(calldata)) } @@ -239,11 +235,11 @@ impl DotrainOrderGui { let mut calls = Vec::new(); let deposit_calldatas = self .dotrain_order - .generate_deposit_calldatas(&self.deployment.deployment_name, &token_deposits) + .generate_deposit_calldatas(&self.deployment.key, &token_deposits) .await?; let add_order_calldata = self .dotrain_order - .generate_add_order_calldata(&self.deployment.deployment_name) + .generate_add_order_calldata(&self.deployment.key) .await?; calls.push(Bytes::copy_from_slice(&add_order_calldata)); @@ -264,7 +260,7 @@ impl DotrainOrderGui { vault_id: String, ) -> Result<(), GuiError> { self.dotrain_order.set_vault_id( - &self.deployment.deployment_name, + &self.deployment.key, is_input, index, U256::from_str(&vault_id)?, diff --git a/crates/js_api/src/gui/state_management.rs b/crates/js_api/src/gui/state_management.rs index bba5aa1d1..e4c930733 100644 --- a/crates/js_api/src/gui/state_management.rs +++ b/crates/js_api/src/gui/state_management.rs @@ -49,7 +49,7 @@ impl DotrainOrderGui { .deployment .deposits .iter() - .find(|dg| dg.token_name == *k) + .find(|dg| dg.token.key == *k) .ok_or(GuiError::DepositTokenNotFound(k.clone()))?; let preset = if v.is_preset { let id = gui_deposit diff --git a/crates/settings/src/config.rs b/crates/settings/src/config.rs index 43676d8c4..2a22f5396 100644 --- a/crates/settings/src/config.rs +++ b/crates/settings/src/config.rs @@ -128,7 +128,12 @@ impl TryFrom for Config { let tokens = item .tokens .into_iter() - .map(|(name, token)| Ok((name, Arc::new(token.try_into_token(&networks)?)))) + .map(|(name, token)| { + Ok(( + name.clone(), + Arc::new(token.try_into_token(&name, &networks)?), + )) + }) .collect::>, ParseConfigSourceError>>()?; let deployers = item diff --git a/crates/settings/src/gui.rs b/crates/settings/src/gui.rs index 3d0f3ccf3..c1ba4bf07 100644 --- a/crates/settings/src/gui.rs +++ b/crates/settings/src/gui.rs @@ -1,7 +1,17 @@ -use crate::{Deployment, Token, TokenRef}; +use crate::{ + yaml::{ + default_document, get_hash_value, optional_hash, optional_string, optional_vec, + require_string, require_vec, YamlError, YamlParsableHash, YamlParseableValue, + }, + Deployment, Token, TokenRef, +}; use alloy::primitives::{ruint::ParseError, utils::UnitsError}; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; +use strict_yaml_rust::StrictYaml; use thiserror::Error; use typeshare::typeshare; @@ -89,7 +99,6 @@ impl GuiConfigSource { Ok(GuiDeposit { token: token.clone(), - token_name: deposit_source.token.clone(), presets: deposit_source.presets.clone(), }) }) @@ -127,8 +136,9 @@ impl GuiConfigSource { Ok(( deployment_name.clone(), GuiDeployment { + document: default_document(), + key: deployment_name.to_string(), deployment, - deployment_name: deployment_name.to_string(), name: deployment_source.name.clone(), description: deployment_source.description.clone(), deposits, @@ -178,9 +188,7 @@ impl_all_wasm_traits!(GuiPreset); #[cfg_attr(target_family = "wasm", derive(Tsify))] pub struct GuiDeposit { #[typeshare(typescript(type = "Token"))] - #[cfg_attr(target_family = "wasm", tsify(type = "Erc20"))] pub token: Arc, - pub token_name: String, #[cfg_attr(target_family = "wasm", tsify(type = "string[]"))] pub presets: Vec, } @@ -188,12 +196,14 @@ pub struct GuiDeposit { impl_all_wasm_traits!(GuiDeposit); #[typeshare] -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(target_family = "wasm", derive(Tsify))] pub struct GuiDeployment { + #[serde(skip, default = "default_document")] + pub document: Arc>, + pub key: String, #[typeshare(typescript(type = "Deployment"))] pub deployment: Arc, - pub deployment_name: String, pub name: String, pub description: String, pub deposits: Vec, @@ -203,6 +213,18 @@ pub struct GuiDeployment { #[cfg(target_family = "wasm")] impl_all_wasm_traits!(GuiDeployment); +impl PartialEq for GuiDeployment { + fn eq(&self, other: &Self) -> bool { + self.key == other.key + && self.deployment == other.deployment + && self.name == other.name + && self.description == other.description + && self.deposits == other.deposits + && self.fields == other.fields + && self.select_tokens == other.select_tokens + } +} + #[typeshare] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[cfg_attr(target_family = "wasm", derive(Tsify))] @@ -226,16 +248,215 @@ pub struct Gui { #[cfg(target_family = "wasm")] impl_all_wasm_traits!(Gui); +impl Gui {} + +impl YamlParseableValue for Gui { + fn parse_from_yaml(_: Arc>) -> Result { + Err(YamlError::InvalidTraitFunction) + } + + fn parse_from_yaml_optional( + document: Arc>, + ) -> Result, YamlError> { + let document_read = document.read().map_err(|_| YamlError::ReadLockError)?; + + if let Some(gui) = optional_hash(&document_read, "gui") { + let name = require_string( + get_hash_value(gui, "name", Some("name field missing in gui".to_string()))?, + None, + Some("name field must be a string in gui".to_string()), + )?; + + let description = require_string( + get_hash_value( + gui, + "description", + Some("description field missing in gui".to_string()), + )?, + None, + Some("description field must be a string in gui".to_string()), + )?; + + let deployments = gui + .get(&StrictYaml::String("deployments".to_string())) + .ok_or(YamlError::ParseError( + "deployments field missing in gui".to_string(), + ))? + .as_hash() + .ok_or(YamlError::ParseError( + "deployments field must be a map in gui".to_string(), + ))?; + let gui_deployments = deployments + .iter() + .map(|(deployment_name, deployment_yaml)| { + let deployment_name = deployment_name.as_str().unwrap_or_default().to_string(); + + let deployment = + Deployment::parse_from_yaml(document.clone(), &deployment_name)?; + + let name = require_string( + deployment_yaml, + Some("name"), + Some(format!( + "name string missing in gui deployment: {deployment_name}" + )), + )?; + + let description = require_string( + deployment_yaml, + Some("description"), + Some(format!( + "description string missing in gui deployment: {deployment_name}" + )), + )?; + + let deposits = require_vec( + deployment_yaml, + "deposits", + Some(format!( + "deposits list missing in gui deployment: {deployment_name}", + )), + )?.iter().enumerate().map(|(deposit_index, deposit_value)| { + let token = Token::parse_from_yaml(document.clone(), &require_string( + deposit_value, + Some("token"), + Some(format!( + "token string missing for deposit index: {deposit_index} in gui deployment: {deployment_name}", + )), + )?)?; + + let presets = require_vec( + deposit_value, + "presets", + Some(format!( + "presets list missing for deposit index: {deposit_index} in gui deployment: {deployment_name}", + )), + )? + .iter() + .enumerate() + .map(|(preset_index, preset_yaml)| { + Ok(preset_yaml.as_str().ok_or(YamlError::ParseError(format!( + "preset value must be a string for preset list index: {preset_index} for deposit index: {deposit_index} in gui deployment: {deployment_name}", + )))?.to_string()) + }) + .collect::, YamlError>>()?; + + let gui_deposit = GuiDeposit { + token: Arc::new(token), + presets, + }; + Ok(gui_deposit) + }) + .collect::, YamlError>>()?; + + let fields = require_vec( + deployment_yaml, + "fields", + Some(format!( + "fields list missing in gui deployment: {deployment_name}" + )), + )?.iter().enumerate().map(|(field_index, field_yaml)| { + let binding = require_string( + field_yaml, + Some("binding"), + Some(format!( + "binding string missing for field index: {field_index} in gui deployment: {deployment_name}", + )), + )?; + + let name = require_string( + field_yaml, + Some("name"), + Some(format!( + "name string missing for field index: {field_index} in gui deployment: {deployment_name}", + )), + )?; + + let description = optional_string(field_yaml, "description"); + + let presets = match optional_vec(field_yaml, "presets") { + Some(p) => Some(p.iter().enumerate().map(|(preset_index, preset_yaml)| { + let name = optional_string(preset_yaml, "name"); + let value = require_string( + preset_yaml, + Some("value"), + Some(format!( + "preset value must be a string for preset index: {preset_index} for field index: {field_index} in gui deployment: {deployment_name}", + )) + )?; + + let gui_preset = GuiPreset { + id: (preset_index as u8 + 1).to_string(), + name, + value, + }; + Ok(gui_preset) + }) + .collect::, YamlError>>()?), + None => None, + }; + + let gui_field_definition = GuiFieldDefinition { + binding, + name, + description, + presets + }; + Ok(gui_field_definition) + }) + .collect::, YamlError>>()?; + + let select_tokens = match optional_vec(deployment_yaml, "select-tokens") { + Some(tokens) => Some( + tokens + .iter() + .enumerate() + .map(|(select_token_index, select_token_value)| { + Ok(select_token_value.as_str().ok_or(YamlError::ParseError(format!( + "select-token value must be a string for select-token index: {select_token_index} in gui deployment: {deployment_name}", + )))?.to_string()) + }) + .collect::, YamlError>>()?, + ), + None => None, + }; + + let gui_deployment = GuiDeployment { + document: document.clone(), + key: deployment_name.clone(), + deployment: Arc::new(deployment), + name, + description, + deposits, + fields, + select_tokens, + }; + Ok((deployment_name, gui_deployment)) + }) + .collect::, YamlError>>()?; + + let gui: Gui = Gui { + name, + description, + deployments: gui_deployments, + }; + Ok(Some(gui)) + } else { + Ok(None) + } + } +} + #[cfg(test)] mod tests { - use std::sync::RwLock; - use super::*; use crate::{ test::{mock_deployer, mock_network, mock_token}, + yaml::tests::get_document, Order, Scenario, }; use alloy::primitives::Address; + use std::sync::RwLock; use strict_yaml_rust::StrictYaml; #[test] @@ -383,4 +604,409 @@ mod tests { Some(vec!["test-token".to_string()]) ); } + + #[test] + fn test_parse_gui_from_yaml() { + let yaml = r#" +gui: + test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("name field missing in gui".to_string()) + ); + let yaml = r#" +gui: + name: + - test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("name field must be a string in gui".to_string()) + ); + let yaml = r#" +gui: + name: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("name field must be a string in gui".to_string()) + ); + + let yaml = r#" +gui: + name: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("description field missing in gui".to_string()) + ); + let yaml = r#" +gui: + name: test + description: + - test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("description field must be a string in gui".to_string()) + ); + let yaml = r#" +gui: + name: test + description: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("description field must be a string in gui".to_string()) + ); + + let yaml = r#" +gui: + name: test + description: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("deployments field missing in gui".to_string()) + ); + let yaml = r#" +gui: + name: test + description: test + deployments: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("deployments field must be a map in gui".to_string()) + ); + let yaml = r#" +gui: + name: test + description: test + deployments: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("deployments field must be a map in gui".to_string()) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(yaml)).unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("missing field: deployments".to_string()) + ); + + let yaml_prefix = r#" +networks: + network1: + rpc: https://eth.llamarpc.com + chain-id: 1 +deployers: + deployer1: + address: 0x0000000000000000000000000000000000000000 + network: network1 +scenarios: + scenario1: + bindings: + test: test + deployer: deployer1 +tokens: + token1: + address: 0x0000000000000000000000000000000000000001 + network: network1 + token2: + address: 0x0000000000000000000000000000000000000002 + network: network1 +orders: + order1: + inputs: + - token: token1 + outputs: + - token: token2 + deployer: deployer1 +deployments: + deployment1: + scenario: scenario1 + order: order1 +"#; + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("name string missing in gui deployment: deployment1".to_string()) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: deployment1 +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "description string missing in gui deployment: deployment1".to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: some name + description: some description +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "deposits list missing in gui deployment: deployment1".to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "token string missing for deposit index: 0 in gui deployment: deployment1" + .to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!(error, YamlError::KeyNotFound("test".to_string())); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "presets list missing for deposit index: 0 in gui deployment: deployment1" + .to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 + presets: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "preset value must be a string for preset list index: 0 for deposit index: 0 in gui deployment: deployment1" + .to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 + presets: + - "1" +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError("fields list missing in gui deployment: deployment1".to_string()) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 + presets: + - "1" + fields: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "binding string missing for field index: 0 in gui deployment: deployment1" + .to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 + presets: + - "1" + fields: + - binding: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "name string missing for field index: 0 in gui deployment: deployment1".to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 + presets: + - "1" + fields: + - binding: test + name: test + presets: + - value: + - test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "preset value must be a string for preset index: 0 for field index: 0 in gui deployment: deployment1" + .to_string() + ) + ); + + let yaml = r#" +gui: + name: test + description: test + deployments: + deployment1: + name: test + description: test + deposits: + - token: token1 + presets: + - "1" + fields: + - binding: test + name: test + presets: + - value: test + select-tokens: + - test: test +"#; + let error = Gui::parse_from_yaml_optional(get_document(&format!("{yaml_prefix}{yaml}"))) + .unwrap_err(); + assert_eq!( + error, + YamlError::ParseError( + "select-token value must be a string for select-token index: 0 in gui deployment: deployment1" + .to_string() + ) + ); + } } diff --git a/crates/settings/src/token.rs b/crates/settings/src/token.rs index 361645078..616e05dee 100644 --- a/crates/settings/src/token.rs +++ b/crates/settings/src/token.rs @@ -170,6 +170,7 @@ pub enum ParseTokenConfigSourceError { impl TokenConfigSource { pub fn try_into_token( self, + name: &str, networks: &HashMap>, ) -> Result { let network_ref = networks @@ -181,7 +182,7 @@ impl TokenConfigSource { Ok(Token { document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))), - key: self.network.clone(), + key: name.to_string(), network: network_ref, address: self.address, decimals: self.decimals, @@ -216,7 +217,7 @@ mod tests { symbol: Some("TTK".to_string()), }; - let token = token_string.try_into_token(&networks); + let token = token_string.try_into_token("TestNetwork", &networks); assert!(token.is_ok()); let token = token.unwrap(); @@ -243,7 +244,7 @@ mod tests { symbol: None, }; - let token = token_string.try_into_token(&networks); + let token = token_string.try_into_token("TestNetwork", &networks); assert!(token.is_ok()); let token = token.unwrap(); @@ -270,7 +271,7 @@ mod tests { symbol: None, }; - let token = token_string.try_into_token(&networks); + let token = token_string.try_into_token("TestNetwork", &networks); assert!(token.is_err()); assert_eq!( diff --git a/crates/settings/src/yaml/dotrain.rs b/crates/settings/src/yaml/dotrain.rs index d33848445..b95386aee 100644 --- a/crates/settings/src/yaml/dotrain.rs +++ b/crates/settings/src/yaml/dotrain.rs @@ -1,5 +1,5 @@ use super::*; -use crate::{Deployment, Order, Scenario}; +use crate::{Deployment, Gui, Order, Scenario}; use std::sync::{Arc, RwLock}; #[derive(Debug, Clone)] @@ -48,6 +48,10 @@ impl DotrainYaml { pub fn get_deployment(&self, key: &str) -> Result { Deployment::parse_from_yaml(self.document.clone(), key) } + + pub fn get_gui(&self) -> Result, YamlError> { + Gui::parse_from_yaml_optional(self.document.clone()) + } } #[cfg(test)] @@ -106,6 +110,25 @@ mod tests { deployment1: order: order1 scenario: scenario1 + gui: + name: Test gui + description: Test description + deployments: + deployment1: + name: Test deployment + description: Test description + deposits: + - token: token1 + presets: + - 100 + - 2000 + fields: + - binding: key1 + name: Binding test + presets: + - value: value2 + select-tokens: + - token2 "#; #[test] @@ -159,5 +182,31 @@ mod tests { deployment.scenario, dotrain_yaml.get_scenario("scenario1").unwrap().into() ); + + let gui = dotrain_yaml.get_gui().unwrap().unwrap(); + assert_eq!(gui.name, "Test gui"); + assert_eq!(gui.description, "Test description"); + assert_eq!(gui.deployments.len(), 1); + let deployment = gui.deployments.get("deployment1").unwrap(); + assert_eq!(deployment.name, "Test deployment"); + assert_eq!(deployment.description, "Test description"); + assert_eq!(deployment.deposits.len(), 1); + let deposit = &deployment.deposits[0]; + assert_eq!( + *deposit.token.as_ref(), + ob_yaml.get_token("token1").unwrap() + ); + assert_eq!(deposit.presets.len(), 2); + assert_eq!(deposit.presets[0], "100".to_string()); + assert_eq!(deposit.presets[1], "2000".to_string()); + assert_eq!(deployment.fields.len(), 1); + let field = &deployment.fields[0]; + assert_eq!(field.binding, "key1"); + assert_eq!(field.name, "Binding test"); + let presets = field.presets.as_ref().unwrap(); + assert_eq!(presets[0].value, "value2"); + let select_tokens = deployment.select_tokens.as_ref().unwrap(); + assert_eq!(select_tokens.len(), 1); + assert_eq!(select_tokens[0], "token2"); } } diff --git a/crates/settings/src/yaml/mod.rs b/crates/settings/src/yaml/mod.rs index 064b4794e..aa01e7a0f 100644 --- a/crates/settings/src/yaml/mod.rs +++ b/crates/settings/src/yaml/mod.rs @@ -55,6 +55,14 @@ pub trait YamlParsableString { ) -> Result, YamlError>; } +pub trait YamlParseableValue: Sized { + fn parse_from_yaml(document: Arc>) -> Result; + + fn parse_from_yaml_optional( + document: Arc>, + ) -> Result, YamlError>; +} + #[derive(Debug, Error)] pub enum YamlError { #[error(transparent)] diff --git a/packages/orderbook/test/js_api/gui.test.ts b/packages/orderbook/test/js_api/gui.test.ts index 7a8277069..2ed43b5a1 100644 --- a/packages/orderbook/test/js_api/gui.test.ts +++ b/packages/orderbook/test/js_api/gui.test.ts @@ -285,8 +285,8 @@ describe('Rain Orderbook JS API Package Bindgen Tests - Gui', async function () const deployments: AvailableDeployments = await DotrainOrderGui.getAvailableDeployments(dotrainWithGui); assert.equal(deployments.length, 2); - assert.equal(deployments[0].deployment_name, 'other-deployment'); - assert.equal(deployments[1].deployment_name, 'some-deployment'); + assert.equal(deployments[0].key, 'other-deployment'); + assert.equal(deployments[1].key, 'some-deployment'); }); it('should return error if gui config is not found', async () => { @@ -592,7 +592,7 @@ describe('Rain Orderbook JS API Package Bindgen Tests - Gui', async function () describe('state management tests', async () => { let serializedState = - 'H4sIAAAAAAAA_3WNTQrCQAyFWxXRW7gWlGTS-enOI3iFmUlGilBBu_D4KmZcCH1ZfPnjvVPzVUYj5AQNMjsAxi55-ZQtErlPb5jchRwpkrfkgxUOQJQSlVAIF-qzVaZh5GG8HLDVBbQb7c53eci0w329PNFQZ50PPcSUWcrc_G9umqqlEgFq4Fo53a4y4u9zpbRwdC829a_U_QAAAA=='; + 'H4sIAAAAAAAA_3WNSwoCMRBEZ1REb-FaULrz6-mdR_AKyaQjgxBBZ-HxFey4EKzNq_5Qdeo-kkxkTeRCo3MefYzENoBACVJ49FIgcWRHLhV624Gt-AHZoQSGYBaas1WmqeapXg7Y6wL6jbrzXR4y73DfLk801vlAA0NMY5byb_4NN13TUokArXCtnG9Xqfj9XCk9HMMLsIlnw_0AAAA='; let gui: DotrainOrderGui; beforeAll(async () => { mockServer diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index ac0a3e33b..c9a40f161 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -54,9 +54,9 @@ await DotrainOrderGui.getAvailableDeployments(dotrain); availableDeployments = Object.fromEntries( deployments.map((deployment) => [ - deployment.deployment_name, + deployment.key, { - label: deployment.deployment_name, + label: deployment.key, deployment } ]) @@ -314,7 +314,7 @@ }} on:change={({ detail }) => { gui?.saveDeposit( - deposit.token_name, + deposit.token.key, detail.value === 'custom' ? '' : detail.value || '' ); gui = gui; @@ -337,12 +337,12 @@ - {#if gui?.isDepositPreset(deposit.token_name) === false} + {#if gui?.isDepositPreset(deposit.token.key) === false} { if (currentTarget instanceof HTMLInputElement) { - gui?.saveDeposit(deposit.token_name, currentTarget.value); + gui?.saveDeposit(deposit.token.key, currentTarget.value); } }} />