add wallet generation to solana
This commit is contained in:
parent
10cda7824c
commit
e28047de92
|
@ -1067,6 +1067,7 @@ dependencies = [
|
|||
name = "icepick-solana"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ed25519-dalek 1.0.1",
|
||||
"icepick-module",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ed25519-dalek = "=1.0.1"
|
||||
icepick-module = { version = "0.1.0", path = "../../icepick-module" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
|
|
|
@ -3,6 +3,7 @@ use icepick_module::{
|
|||
Module,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_sdk::signer::Signer;
|
||||
use std::str::FromStr;
|
||||
|
||||
// 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)]
|
||||
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)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Transfer {
|
||||
|
@ -45,6 +56,8 @@ pub struct Request {
|
|||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(tag = "operation", content = "values", rename_all = "kebab-case")]
|
||||
pub enum Operation {
|
||||
GenerateWallet(GenerateWallet),
|
||||
GetWalletAddress(GetWalletAddress),
|
||||
Transfer(Transfer),
|
||||
Sign(Sign),
|
||||
}
|
||||
|
@ -92,6 +105,21 @@ impl Module for Solana {
|
|||
r#type: ArgumentType::Required,
|
||||
};
|
||||
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 {
|
||||
name: "transfer".to_string(),
|
||||
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> {
|
||||
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 {
|
||||
amount,
|
||||
from_account,
|
||||
|
@ -167,7 +216,10 @@ impl Module for Solana {
|
|||
match (&fee_payer, &fee_payer_address) {
|
||||
(Some(payer), Some(address)) => {
|
||||
// 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) => {
|
||||
// Use the transaction account
|
||||
|
@ -186,7 +238,9 @@ impl Module for Solana {
|
|||
);
|
||||
let transaction = solana_sdk::transaction::Transaction::new_unsigned(message);
|
||||
// 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![];
|
||||
requested_accounts.push(from_account | 1 << 31);
|
||||
if let Some((account, _)) = &payer_account_and_pk {
|
||||
|
@ -197,11 +251,11 @@ impl Module for Solana {
|
|||
"derivation-accounts": requested_accounts,
|
||||
}))
|
||||
}
|
||||
Operation::Sign(Sign {}) => {
|
||||
Operation::Sign(_) => {
|
||||
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");
|
||||
let keys = request.derived_keys.unwrap_or_default();
|
||||
let _keys = request.derived_keys.unwrap_or_default();
|
||||
Ok(serde_json::json!({
|
||||
"blob": []
|
||||
}))
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
|
||||
pub fn get_command(bin_name: &str) -> (&str, Vec<&str>) {
|
||||
if std::env::vars().any(|(k, _)| &k == "ICEPICK_USE_CARGO") {
|
||||
("cargo", vec!["run", "--bin", bin_name, "--"])
|
||||
("cargo", vec!["run", "-q", "--bin", bin_name, "--"])
|
||||
} else {
|
||||
(bin_name, vec![])
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue