diff --git a/crates/icepick/src/cli/mod.rs b/crates/icepick/src/cli/mod.rs index 5d90a2b..b540375 100644 --- a/crates/icepick/src/cli/mod.rs +++ b/crates/icepick/src/cli/mod.rs @@ -49,13 +49,25 @@ pub fn derive_keys( #[derive(Serialize, Deserialize, Debug)] struct ModuleConfig { + /// The name of the module. name: String, + + /// The name of the command used to invoke the module. If not given, the default would be + /// `format!("icepick-{name}")`, using the name of the module. command_name: Option, - algorithm: keyfork_derive_util::request::DerivationAlgorithm, + /// The bip32 derivation algorithm. This is currently used for deriving keys from Keyfork, but + /// may be passed to modules within the workflow to provide additional context, such as the + /// algorithm for a generic signer. + algorithm: Option, + + /// The bip44 derivation prefix. This is currently used for deriving keys from Keyfork directly + /// within Icepick, but may be passed to modules within the workflow to provide additional + /// context, such as a module for deriving keys. #[serde(with = "serde_derivation")] - derivation_prefix: keyfork_derive_util::DerivationPath, + derivation_prefix: Option, + /// All workflows for a module. #[serde(rename = "workflow", default)] workflows: Vec, } @@ -65,21 +77,28 @@ mod serde_derivation { use serde::{Deserialize, Deserializer, Serializer}; use std::str::FromStr; - pub fn serialize(p: &DerivationPath, serializer: S) -> Result + pub fn serialize(p: &Option, serializer: S) -> Result where S: Serializer, { - let path = p.to_string(); - serializer.serialize_str(&path) + if let Some(p) = p { + let path = p.to_string(); + serializer.serialize_str(&path) + } else { + serializer.serialize_none() + } } - pub fn deserialize<'de, D>(deserializer: D) -> Result + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { use serde::de::Error; - String::deserialize(deserializer) - .and_then(|string| DerivationPath::from_str(&string).map_err(Error::custom)) + + let opt_string = Option::::deserialize(deserializer)?; + opt_string + .map(|string| DerivationPath::from_str(&string).map_err(Error::custom)) + .transpose() } } @@ -249,7 +268,11 @@ pub fn do_cli_thing() { let accounts: Vec = serde_json::from_value(accounts.clone()) .expect("valid derivation_accounts"); - derived_keys.extend(derive_keys(&algo, &path, &accounts)); + derived_keys.extend(derive_keys( + &algo.expect("a module requested keys but didn't provide algorithm"), + &path.expect("a module requested keys but didn't provide prefix"), + &accounts, + )); } let json = serde_json::json!({ diff --git a/crates/icepick/src/cli/workflow.rs b/crates/icepick/src/cli/workflow.rs index 256f640..8d857ac 100644 --- a/crates/icepick/src/cli/workflow.rs +++ b/crates/icepick/src/cli/workflow.rs @@ -198,7 +198,14 @@ impl Workflow { .expect("could not find module config"); let algo = &config.algorithm; let path_prefix = &config.derivation_prefix; - derived_keys.extend(derive_keys(algo, path_prefix, &derivation_accounts)); + derived_keys.extend(derive_keys( + algo.as_ref() + .expect("a module requested keys but didn't provide algorithm"), + path_prefix + .as_ref() + .expect("a module requested keys but didn't provide prefix"), + &derivation_accounts, + )); derivation_accounts.clear(); // Prepare all inputs for the operation invocation