diff --git a/crates/by-chain/icepick-solana/src/lib.rs b/crates/by-chain/icepick-solana/src/lib.rs index a230cd9..12c7097 100644 --- a/crates/by-chain/icepick-solana/src/lib.rs +++ b/crates/by-chain/icepick-solana/src/lib.rs @@ -106,29 +106,24 @@ impl std::fmt::Display for Cluster { } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct GetBlockhash { cluster: Option, } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct GenerateWallet { account: Option, } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct GetWalletAddress {} #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct GetTokenInfo { token: String, } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct Transfer { amount: String, to_address: String, @@ -140,7 +135,6 @@ pub struct Transfer { } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct CreateTokenAccount { funder_address: Option, wallet_address: String, @@ -148,7 +142,6 @@ pub struct CreateTokenAccount { } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct TransferToken { amount: String, token_address: String, @@ -162,19 +155,16 @@ pub struct TransferToken { } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct Sign { blockhash: String, } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct Broadcast { cluster: Option, } #[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "kebab-case")] pub struct Request { // NOTE: Can't use the proper XPrv type from Keyfork because Solana's a big stinky // and adds in its own derivation constructs that cause type conflicts. @@ -188,7 +178,7 @@ pub struct Request { } #[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "operation", content = "values", rename_all = "kebab-case")] +#[serde(tag = "operation", content = "values")] pub enum Operation { GetBlockhash(GetBlockhash), GenerateWallet(GenerateWallet), @@ -406,14 +396,16 @@ impl Module for Solana { let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url); let response = client.get_latest_blockhash().unwrap(); Ok(serde_json::json!({ - "blob": response.to_string(), + "blob": { + "blockhash": response.to_string(), + }, })) } Operation::GenerateWallet(GenerateWallet { account }) => { let account = u32::from_str(account.as_deref().unwrap_or("0")).unwrap(); Ok(serde_json::json!({ - "blob": null, - "derivation-accounts": [(account | 1 << 31)], + "blob": {}, + "derivation_accounts": [(account | 1 << 31)], })) } Operation::GetWalletAddress(_) => { @@ -422,7 +414,9 @@ impl Module for Solana { let keypair = Self::keypair_from_bytes(key); let pubkey = keypair.pubkey(); Ok(serde_json::json!({ - "blob": pubkey.to_string(), + "blob": { + "pubkey": pubkey.to_string(), + } })) } Operation::GetTokenInfo(GetTokenInfo { token }) => { @@ -442,7 +436,8 @@ impl Module for Solana { } }), None => serde_json::json!({ - "blob": null, + "blob": {}, + "error": "key was not found!", }), }) } @@ -499,8 +494,10 @@ impl Module for Solana { requested_accounts.push(*account | 1 << 31); } Ok(serde_json::json!({ - "blob": transaction, - "derivation-accounts": requested_accounts, + "blob": { + "transaction": transaction, + }, + "derivation_accounts": requested_accounts, })) } Operation::CreateTokenAccount(CreateTokenAccount { @@ -528,8 +525,10 @@ impl Module for Solana { let transaction = solana_sdk::transaction::Transaction::new_unsigned(message); #[allow(clippy::identity_op)] Ok(serde_json::json!({ - "blob": transaction, - "derivation-accounts": [0u32 | 1 << 31], + "blob": { + "transaction": transaction, + }, + "derivation_accounts": [0u32 | 1 << 31], })) } Operation::TransferToken(TransferToken { @@ -619,14 +618,19 @@ impl Module for Solana { #[allow(clippy::identity_op)] Ok(serde_json::json!({ - "blob": transaction, - "derivation-accounts": [0u32 | 1 << 31], + "blob": { + "transaction": transaction, + }, + "derivation_accounts": [0u32 | 1 << 31], })) } Operation::Sign(Sign { blockhash }) => { - let blob = request.blob.expect("passed in instruction blob"); + let transaction = request + .blob + .and_then(|b| b.get("transaction").cloned()) + .expect("was given transaction"); let mut transaction: solana_sdk::transaction::Transaction = - serde_json::from_value(blob).expect("valid message blob"); + serde_json::from_value(transaction).expect("valid message blob"); let keys = request .derived_keys .unwrap_or_default() @@ -639,16 +643,21 @@ impl Module for Solana { .try_sign(&keys, hash) .expect("not enough keys provided"); Ok(serde_json::json!({ - "blob": transaction, + "blob": { + "transaction": transaction, + } })) } Operation::Broadcast(Broadcast { cluster }) => { let cluster = cluster.unwrap_or(Cluster::MainnetBeta); let cluster_url = format!("https://api.{cluster}.solana.com"); - let blob = request.blob.expect("passed in instruction blob"); + let transaction = request + .blob + .and_then(|b| b.get("transaction").cloned()) + .expect("was given transaction"); let transaction: solana_sdk::transaction::Transaction = - serde_json::from_value(blob).expect("valid message blob"); + serde_json::from_value(transaction).expect("valid message blob"); transaction.verify().expect("invalid signatures"); let client = solana_rpc_client::rpc_client::RpcClient::new(cluster_url); let _simulated_response = client.simulate_transaction(&transaction).unwrap(); diff --git a/crates/icepick/src/cli/mod.rs b/crates/icepick/src/cli/mod.rs index d0f51a1..4eeb0e0 100644 --- a/crates/icepick/src/cli/mod.rs +++ b/crates/icepick/src/cli/mod.rs @@ -124,7 +124,7 @@ pub fn do_cli_thing() { let derivation_accounts = cli_input .as_ref() - .and_then(|json| json.get("derivation-accounts")); + .and_then(|json| json.get("derivation_accounts")); let matches = icepick_command.get_matches(); if let Some((module, matches)) = matches.subcommand() { @@ -134,44 +134,77 @@ pub fn do_cli_thing() { .find(|(name, ..)| *name == module) .and_then(|(.., operations)| operations.iter().find(|o| o.name == subcommand)) { - let mut args = std::collections::HashMap::<&String, Option<&String>>::with_capacity( + let mut args = std::collections::HashMap::>::with_capacity( operation.arguments.len(), ); for arg in &operation.arguments { - args.insert(&arg.name, matches.get_one::(&arg.name)); + args.insert( + arg.name.replace('-', "_"), + matches.get_one::(&arg.name), + ); } - let (algo, path) = config.modules.iter().find_map(|fmodule| { - if fmodule.name == module { - return Some((fmodule.algorithm.clone(), fmodule.derivation_prefix.clone())) - } - None - }).unwrap(); + let (algo, path) = config + .modules + .iter() + .find_map(|fmodule| { + if fmodule.name == module { + return Some(( + fmodule.algorithm.clone(), + fmodule.derivation_prefix.clone(), + )); + } + None + }) + .unwrap(); let mut derived_keys: Vec> = vec![]; if let Some(accounts) = derivation_accounts { let accounts: Vec = serde_json::from_value(accounts.clone()) - .expect("valid derivation-accounts"); + .expect("valid derivation_accounts"); let mut client = keyforkd_client::Client::discover_socket().expect("keyforkd started"); for account in accounts { - let request = keyfork_derive_util::request::DerivationRequest::new(algo.clone(), &path.clone().chain_push(account)); + let request = keyfork_derive_util::request::DerivationRequest::new( + algo.clone(), + &path.clone().chain_push(account), + ); let request = keyforkd_models::Request::Derivation(request); let response = client.request(&request).expect("valid derivation"); match response { - keyforkd_models::Response::Derivation(keyfork_derive_util::request::DerivationResponse { data, .. }) => { + keyforkd_models::Response::Derivation( + keyfork_derive_util::request::DerivationResponse { data, .. }, + ) => { derived_keys.push(data.to_vec()); - }, + } _ => panic!("Unexpected response"), } } } + // in the event this is not PascalCase, this would be false. + // we set this to true to capitalize the first character. + let mut last_char_was_dash = true; + let subcommand = subcommand + .chars() + .filter_map(|c| { + if last_char_was_dash { + last_char_was_dash = false; + return Some(c.to_ascii_uppercase()); + } + if c == '-' { + last_char_was_dash = true; + None + } else { + Some(c) + } + }) + .collect::(); let json = serde_json::json!({ "operation": subcommand, "values": args, - "derived-keys": derived_keys, + "derived_keys": derived_keys, "blob": blob, }); let bin = commands diff --git a/e2e-tests/solana/online.sh b/e2e-tests/solana/online.sh index 45ec5ed..6191b2f 100644 --- a/e2e-tests/solana/online.sh +++ b/e2e-tests/solana/online.sh @@ -11,7 +11,7 @@ printf "%s" "Amount of token to transfer: " read token_amount echo "Acquiring blockhash..." -blockhash="$(icepick sol get-blockhash --cluster devnet | jq -r .blob)" +blockhash="$(icepick sol get-blockhash --cluster devnet | jq -r .blob.blockhash)" echo "Saving information to file"