add wallet generation to solana

This commit is contained in:
Ryan Heywood 2024-11-26 17:06:58 -05:00
parent 10cda7824c
commit e28047de92
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
4 changed files with 62 additions and 6 deletions

1
Cargo.lock generated
View File

@ -1067,6 +1067,7 @@ dependencies = [
name = "icepick-solana" name = "icepick-solana"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ed25519-dalek 1.0.1",
"icepick-module", "icepick-module",
"serde", "serde",
"serde_json", "serde_json",

View File

@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
ed25519-dalek = "=1.0.1"
icepick-module = { version = "0.1.0", path = "../../icepick-module" } icepick-module = { version = "0.1.0", path = "../../icepick-module" }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true serde_json.workspace = true

View File

@ -3,6 +3,7 @@ use icepick_module::{
Module, Module,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use solana_sdk::signer::Signer;
use std::str::FromStr; use std::str::FromStr;
// How does this not exist in solana_sdk. // How does this not exist in solana_sdk.
@ -11,6 +12,16 @@ const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error {} pub enum Error {}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct GenerateWallet {
account: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct GetWalletAddress {}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct Transfer { pub struct Transfer {
@ -45,6 +56,8 @@ pub struct Request {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "operation", content = "values", rename_all = "kebab-case")] #[serde(tag = "operation", content = "values", rename_all = "kebab-case")]
pub enum Operation { pub enum Operation {
GenerateWallet(GenerateWallet),
GetWalletAddress(GetWalletAddress),
Transfer(Transfer), Transfer(Transfer),
Sign(Sign), Sign(Sign),
} }
@ -92,6 +105,21 @@ impl Module for Solana {
r#type: ArgumentType::Required, r#type: ArgumentType::Required,
}; };
vec![ vec![
icepick_module::help::Operation {
name: "generate-wallet".to_string(),
description: "Generate the derivation index for a wallet.".to_string(),
arguments: vec![Argument {
name: "account".to_string(),
description: "The derivation account used for generating the wallet."
.to_string(),
r#type: ArgumentType::Optional,
}],
},
icepick_module::help::Operation {
name: "get-wallet-address".to_string(),
description: "Get the address for a given wallet.".to_string(),
arguments: vec![],
},
icepick_module::help::Operation { icepick_module::help::Operation {
name: "transfer".to_string(), name: "transfer".to_string(),
description: "Transfer SOL from a Keyfork wallet to an external wallet." description: "Transfer SOL from a Keyfork wallet to an external wallet."
@ -142,6 +170,27 @@ impl Module for Solana {
fn handle_request(request: Self::Request) -> Result<serde_json::Value, Self::Error> { fn handle_request(request: Self::Request) -> Result<serde_json::Value, Self::Error> {
match request.operation { match request.operation {
Operation::GenerateWallet(GenerateWallet { account }) => {
let account = u32::from_str(&account).expect("account index");
Ok(serde_json::json!({
"blob": null,
"derivation-accounts": [(account | 1 << 31)],
}))
}
Operation::GetWalletAddress(_) => {
use ed25519_dalek::{PublicKey, SecretKey};
// NOTE: panics if doesn't exist
let key = request.derived_keys.unwrap()[0];
let secret_key = SecretKey::from_bytes(&key).unwrap();
let mut bytes = [0u8; 64];
bytes[..32].clone_from_slice(&key);
bytes[32..].clone_from_slice(PublicKey::from(&secret_key).as_bytes());
let pk = solana_sdk::signer::keypair::Keypair::from_bytes(&bytes).unwrap();
let pk = pk.pubkey();
Ok(serde_json::json!({
"blob": pk.to_string(),
}))
}
Operation::Transfer(Transfer { Operation::Transfer(Transfer {
amount, amount,
from_account, from_account,
@ -167,7 +216,10 @@ impl Module for Solana {
match (&fee_payer, &fee_payer_address) { match (&fee_payer, &fee_payer_address) {
(Some(payer), Some(address)) => { (Some(payer), Some(address)) => {
// Use the provided account // Use the provided account
Some((u32::from_str(payer).unwrap(), Pubkey::from_str(address).unwrap())) Some((
u32::from_str(payer).unwrap(),
Pubkey::from_str(address).unwrap(),
))
} }
(None, None) => { (None, None) => {
// Use the transaction account // Use the transaction account
@ -186,7 +238,9 @@ impl Module for Solana {
); );
let transaction = solana_sdk::transaction::Transaction::new_unsigned(message); let transaction = solana_sdk::transaction::Transaction::new_unsigned(message);
// TODO: error handling from_str // TODO: error handling from_str
let from_account = from_account.and_then(|a| u32::from_str(&a).ok()).unwrap_or(0); let from_account = from_account
.and_then(|a| u32::from_str(&a).ok())
.unwrap_or(0);
let mut requested_accounts = vec![]; let mut requested_accounts = vec![];
requested_accounts.push(from_account | 1 << 31); requested_accounts.push(from_account | 1 << 31);
if let Some((account, _)) = &payer_account_and_pk { if let Some((account, _)) = &payer_account_and_pk {
@ -197,11 +251,11 @@ impl Module for Solana {
"derivation-accounts": requested_accounts, "derivation-accounts": requested_accounts,
})) }))
} }
Operation::Sign(Sign {}) => { Operation::Sign(_) => {
let blob = request.blob.expect("passed in instruction blob"); let blob = request.blob.expect("passed in instruction blob");
let transaction: solana_sdk::transaction::Transaction = let _transaction: solana_sdk::transaction::Transaction =
serde_json::from_value(blob).expect("valid message blob"); serde_json::from_value(blob).expect("valid message blob");
let keys = request.derived_keys.unwrap_or_default(); let _keys = request.derived_keys.unwrap_or_default();
Ok(serde_json::json!({ Ok(serde_json::json!({
"blob": [] "blob": []
})) }))

View File

@ -8,7 +8,7 @@ use std::{
pub fn get_command(bin_name: &str) -> (&str, Vec<&str>) { pub fn get_command(bin_name: &str) -> (&str, Vec<&str>) {
if std::env::vars().any(|(k, _)| &k == "ICEPICK_USE_CARGO") { if std::env::vars().any(|(k, _)| &k == "ICEPICK_USE_CARGO") {
("cargo", vec!["run", "--bin", bin_name, "--"]) ("cargo", vec!["run", "-q", "--bin", bin_name, "--"])
} else { } else {
(bin_name, vec![]) (bin_name, vec![])
} }