Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 79 additions & 49 deletions crates/js_api/src/gui/order_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use alloy::{
primitives::{utils::parse_units, Bytes, U256},
sol_types::SolCall,
};
use rain_orderbook_app_settings::{order::OrderIOCfg, orderbook::OrderbookCfg};
use rain_orderbook_app_settings::{
order::{OrderIOCfg, VaultType},
orderbook::OrderbookCfg,
};
use rain_orderbook_bindings::OrderBook::multicallCall;
use rain_orderbook_common::{
add_order::AddOrderArgs, deposit::DepositArgs, transaction::TransactionArgs,
Expand Down Expand Up @@ -56,7 +59,8 @@ impl_wasm_traits!(DepositAndAddOrderCalldataResult);

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Tsify)]
pub struct IOVaultIds(
#[tsify(type = "Map<string, (string | undefined)[]>")] pub HashMap<String, Vec<Option<U256>>>,
#[tsify(type = "Map<string, Map<string, string | undefined>>")]
pub HashMap<String, HashMap<String, Option<U256>>>,
);
impl_wasm_traits!(IOVaultIds);

Expand Down Expand Up @@ -517,38 +521,40 @@ impl DotrainOrderGui {
/// ## Examples
///
/// ```javascript
/// const result1 = gui.setVaultId(true, 0, "42");
/// const result1 = gui.setVaultId("input", "token1", "42");
/// if (result1.error) {
/// console.error("Error:", result1.error.readableMsg);
/// return;
/// }
/// const result2 = gui.setVaultId(false, 0, "43");
/// const result3 = gui.setVaultId(false, 0, undefined);
/// const result2 = gui.setVaultId("output", "token2", "43");
/// const result3 = gui.setVaultId("output", "token2", undefined);
/// ```
#[wasm_export(js_name = "setVaultId", unchecked_return_type = "void")]
pub fn set_vault_id(
&mut self,
#[wasm_export(param_description = "True for input vaults, false for output vaults")]
is_input: bool,
#[wasm_export(param_description = "Zero-based index in the inputs/outputs array")]
index: u8,
#[wasm_export(param_description = "Vault ID number as string, or None to clear")]
#[wasm_export(param_description = "Vault type: 'input' or 'output'")] r#type: VaultType,
#[wasm_export(param_description = "Token key to identify which token to set vault for")]
token: String,
#[wasm_export(
js_name = "vaultId",
param_description = "Vault ID number as string. Omit to clear vault ID"
)]
vault_id: Option<String>,
) -> Result<(), GuiError> {
let deployment = self.get_current_deployment()?;
self.dotrain_order
.dotrain_yaml()
.get_order(&deployment.deployment.order.key)?
.update_vault_id(is_input, index, vault_id)?;
.update_vault_id(r#type, token, vault_id)?;

self.execute_state_update_callback()?;
Ok(())
}

/// Gets all configured vault IDs for inputs and outputs.
///
/// Returns the current vault ID configuration showing which vaults are
/// assigned to each input and output token position.
/// Returns a map with 'input' and 'output' keys, where each value is a map
/// of token keys to their configured vault IDs (or undefined if not set).
///
/// ## Examples
///
Expand All @@ -559,41 +565,47 @@ impl DotrainOrderGui {
/// return;
/// }
///
/// // key is either 'input' or 'output'
/// // value is either undefined or the vault ID
/// for (const [key, value] of result.value) {
/// console.log("Key:", key);
/// console.log("Value:", value);
/// // Access input token vault IDs
/// for (const [tokenKey, vaultId] of result.value.get('input')) {
/// console.log(`Input token ${tokenKey} uses vault ${vaultId || 'none'}`);
/// }
///
/// // Access output token vault IDs
/// for (const [tokenKey, vaultId] of result.value.get('output')) {
/// console.log(`Output token ${tokenKey} uses vault ${vaultId || 'none'}`);
/// }
/// ```
#[wasm_export(
js_name = "getVaultIds",
unchecked_return_type = "IOVaultIds",
return_description = "Map with 'input' and 'output' arrays of vault IDs"
return_description = "Map with 'input' and 'output' keys containing token-to-vault-ID maps"
)]
pub fn get_vault_ids(&self) -> Result<IOVaultIds, GuiError> {
let deployment = self.get_current_deployment()?;

let mut input_map = HashMap::new();
for input in deployment.deployment.order.inputs.iter() {
let token_key = input
.token
.as_ref()
.map(|t| t.key.clone())
.ok_or(GuiError::SelectTokensNotSet)?;
input_map.insert(token_key, input.vault_id);
}

let mut output_map = HashMap::new();
for output in deployment.deployment.order.outputs.iter() {
let token_key = output
.token
.as_ref()
.map(|t| t.key.clone())
.ok_or(GuiError::SelectTokensNotSet)?;
output_map.insert(token_key, output.vault_id);
}

let map = HashMap::from([
(
"input".to_string(),
deployment
.deployment
.order
.inputs
.iter()
.map(|input| input.vault_id)
.collect(),
),
(
"output".to_string(),
deployment
.deployment
.order
.outputs
.iter()
.map(|output| output.vault_id)
.collect(),
),
("input".to_string(), input_map),
("output".to_string(), output_map),
]);
Ok(IOVaultIds(map))
}
Expand Down Expand Up @@ -622,7 +634,10 @@ impl DotrainOrderGui {
)]
pub fn has_any_vault_id(&self) -> Result<bool, GuiError> {
let map = self.get_vault_ids()?;
Ok(map.0.values().any(|ids| ids.iter().any(|id| id.is_some())))
Ok(map
.0
.values()
.any(|token_map| token_map.values().any(|vault_id| vault_id.is_some())))
}

#[wasm_export(skip)]
Expand Down Expand Up @@ -851,30 +866,45 @@ mod tests {
let gui = initialize_gui(None).await;
let res = gui.get_vault_ids().unwrap();
assert_eq!(res.0.len(), 2);
assert_eq!(res.0["input"][0], Some(U256::from(1)));
assert_eq!(res.0["output"][0], Some(U256::from(1)));
assert_eq!(res.0["input"]["token1"], Some(U256::from(1)));
assert_eq!(res.0["output"]["token2"], Some(U256::from(1)));

let mut gui = initialize_gui(Some("other-deployment".to_string())).await;

let res = gui.get_vault_ids().unwrap();
assert_eq!(res.0.len(), 2);
assert_eq!(res.0["input"][0], None);
assert_eq!(res.0["output"][0], None);
assert_eq!(res.0["input"]["token1"], None);
assert_eq!(res.0["output"]["token1"], None);

gui.set_vault_id(true, 0, Some("999".to_string())).unwrap();
gui.set_vault_id(false, 0, Some("888".to_string())).unwrap();
gui.set_vault_id(
VaultType::Input,
"token1".to_string(),
Some("999".to_string()),
)
.unwrap();
gui.set_vault_id(
VaultType::Output,
"token1".to_string(),
Some("888".to_string()),
)
.unwrap();

let res = gui.get_vault_ids().unwrap();
assert_eq!(res.0.len(), 2);
assert_eq!(res.0["input"][0], Some(U256::from(999)));
assert_eq!(res.0["output"][0], Some(U256::from(888)));
assert_eq!(res.0["input"]["token1"], Some(U256::from(999)));
assert_eq!(res.0["output"]["token1"], Some(U256::from(888)));
}

#[wasm_bindgen_test]
async fn test_has_any_vault_id() {
let mut gui = initialize_gui(Some("other-deployment".to_string())).await;
assert!(!gui.has_any_vault_id().unwrap());
gui.set_vault_id(true, 0, Some("1".to_string())).unwrap();
gui.set_vault_id(
VaultType::Input,
"token1".to_string(),
Some("1".to_string()),
)
.unwrap();
assert!(gui.has_any_vault_id().unwrap());
}

Expand Down
66 changes: 48 additions & 18 deletions crates/js_api/src/gui/state_management.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use super::*;
use rain_orderbook_app_settings::{gui::GuiDepositCfg, order::OrderIOCfg, token::TokenCfg};
use rain_orderbook_app_settings::{
gui::GuiDepositCfg,
order::{OrderIOCfg, VaultType},
token::TokenCfg,
};
use sha2::{Digest, Sha256};
use std::sync::{Arc, RwLock};
use strict_yaml_rust::StrictYaml;
Expand All @@ -21,7 +25,7 @@ struct SerializedGuiState {
field_values: BTreeMap<String, GuiPresetCfg>,
deposits: BTreeMap<String, GuiPresetCfg>,
select_tokens: BTreeMap<String, TokenCfg>,
vault_ids: BTreeMap<(bool, u8), Option<String>>,
vault_ids: BTreeMap<(VaultType, String), Option<String>>,
dotrain_hash: String,
selected_deployment: String,
}
Expand Down Expand Up @@ -68,16 +72,15 @@ impl DotrainOrderGui {
documents: Vec<Arc<RwLock<StrictYaml>>>,
order_key: &str,
is_input: bool,
) -> Result<BTreeMap<(bool, u8), Option<String>>, GuiError> {
) -> Result<BTreeMap<(VaultType, String), Option<String>>, GuiError> {
let mut vault_ids = BTreeMap::new();
for (i, vault_id) in OrderCfg::parse_vault_ids(documents, order_key, is_input)?
.iter()
.enumerate()
{
vault_ids.insert(
(is_input, i as u8),
vault_id.as_ref().map(|v| v.to_string()),
);
let r#type = if is_input {
VaultType::Input
} else {
VaultType::Output
};
for (token, vault_id) in OrderCfg::parse_vault_ids(documents, order_key, r#type)? {
vault_ids.insert((r#type, token), vault_id.as_ref().map(|v| v.to_string()));
}
Ok(vault_ids)
}
Expand Down Expand Up @@ -407,9 +410,10 @@ mod tests {
};
use alloy::primitives::U256;
use js_sys::{eval, Reflect};
use rain_orderbook_app_settings::order::VaultType;
use wasm_bindgen_test::wasm_bindgen_test;

const SERIALIZED_STATE: &str = "H4sIAAAAAAAA_21PXWvCMBRt3NgY7EkGexrsByw0NW4zwh7GVlEsflF9LVqDStOktBG__oQ_Wao3FcX7cM85ycnNPSXrVE-Ak4WcLuQMO5apO0CHkGtTBcEBsQpmyAOgVhGX9Na0285L9QwqUzHHkuuVSiPz7g1wrnVSt22hwrGYq0zXa6T2aadJiJep2OUOlHdkvnb95gvQcnW03l81VEaPcO3nO7xTdG90u0NLRZRiYIUxdFYOYx9A_8mwr3wvGHu-q4JGP6v2esuuiL4G21Z3HTDXpd7f7zel8fDn1STlgocaH-PjKU-E2sRc6gN7v9qEqAEAAA==";
const SERIALIZED_STATE: &str = "H4sIAAAAAAAA_21Q22rCQBDN2tJS6JMU-lToB3TJJmtbV-hDaVNaGrwRfQ0aF5VsdkOy4u0n_GSJzkYMzsOcM3vOzgxTs45xBziey8lcTrFjmbgCdAipmlwED8QqmSE3gFrFXNJL3S47z6t7qHKVcCy5XqosNv-eAGdapy3bFioaiZnKdatJmq92lkZ4kYlt4UBFRma0F_w-AK03hqtdJaE6ugU5KHZ4puja1P9tWrNOcbarUw5wGENV1S1Vl7EXoN9k0FOBH478wFPhTy9vdLuLjojf-pu_zipknkf9r893SpPBx6O5BBc80vjQFE94KtQ64VLvAVF2uCfIAQAA";

#[wasm_bindgen_test]
async fn test_serialize_state() {
Expand All @@ -429,8 +433,18 @@ mod tests {
.unwrap();
gui.set_field_value("binding-2".to_string(), "0".to_string())
.unwrap();
gui.set_vault_id(true, 0, Some("199".to_string())).unwrap();
gui.set_vault_id(false, 0, Some("299".to_string())).unwrap();
gui.set_vault_id(
VaultType::Input,
"token1".to_string(),
Some("199".to_string()),
)
.unwrap();
gui.set_vault_id(
VaultType::Output,
"token2".to_string(),
Some("299".to_string()),
)
.unwrap();

let state = gui.serialize_state().unwrap();
assert!(!state.is_empty());
Expand Down Expand Up @@ -462,8 +476,14 @@ mod tests {
}
);
let vault_ids = gui.get_vault_ids().unwrap().0;
assert_eq!(vault_ids.get("input").unwrap()[0], Some(U256::from(199)));
assert_eq!(vault_ids.get("output").unwrap()[0], Some(U256::from(299)));
assert_eq!(
vault_ids.get("input").unwrap()["token1"],
Some(U256::from(199))
);
assert_eq!(
vault_ids.get("output").unwrap()["token2"],
Some(U256::from(299))
);
}

#[wasm_bindgen_test]
Expand Down Expand Up @@ -526,8 +546,18 @@ mod tests {
.unwrap();
gui.set_field_value("binding-2".to_string(), "582.1".to_string())
.unwrap();
gui.set_vault_id(true, 0, Some("199".to_string())).unwrap();
gui.set_vault_id(false, 0, Some("299".to_string())).unwrap();
gui.set_vault_id(
VaultType::Input,
"token1".to_string(),
Some("199".to_string()),
)
.unwrap();
gui.set_vault_id(
VaultType::Output,
"token2".to_string(),
Some("299".to_string()),
)
.unwrap();

let callback_called = Reflect::get(&global, &JsValue::from_str("callbackCalled"))
.expect("should have callbackCalled flag on globalThis");
Expand Down
Loading