refactor and add pin support to program facades

This commit is contained in:
jonesmarvin8 2026-04-24 22:10:04 -04:00
parent 93a1487553
commit 7b4f973f96
25 changed files with 347 additions and 132 deletions

38
Cargo.lock generated
View File

@ -4011,6 +4011,43 @@ dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "keycard_wallet"
version = "0.1.0"
dependencies = [
"amm_core",
"anyhow",
"async-stream",
"ata_core",
"base58",
"bip39",
"clap",
"common",
"env_logger",
"futures",
"hex",
"humantime",
"humantime-serde",
"indicatif",
"itertools 0.14.0",
"key_protocol",
"log",
"nssa",
"nssa_core",
"optfield",
"pyo3",
"rand 0.8.5",
"sequencer_service_rpc",
"serde",
"serde_json",
"sha2",
"testnet_initial_state",
"thiserror 2.0.18",
"token_core",
"tokio",
"url",
]
[[package]]
name = "lazy-regex"
version = "3.6.0"
@ -9107,6 +9144,7 @@ dependencies = [
"indicatif",
"itertools 0.14.0",
"key_protocol",
"keycard_wallet",
"log",
"nssa",
"nssa_core",

View File

@ -38,6 +38,7 @@ members = [
"examples/program_deployment/methods/guest",
"bedrock_client",
"testnet_initial_state",
"keycard_wallet",
]
[workspace.dependencies]
@ -67,6 +68,7 @@ ata_program = { path = "programs/associated_token_account" }
test_program_methods = { path = "test_program_methods" }
bedrock_client = { path = "bedrock_client" }
testnet_initial_state = { path = "testnet_initial_state" }
keycard_wallet = { path = "keycard_wallet" }
tokio = { version = "1.50", features = [
"net",

View File

@ -134,6 +134,8 @@ async fn amm_public() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 7,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -163,6 +165,8 @@ async fn amm_public() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 7,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -551,6 +555,8 @@ async fn amm_new_pool_using_labels() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 5,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
@ -575,6 +581,8 @@ async fn amm_new_pool_using_labels() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 5,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;

View File

@ -269,6 +269,8 @@ async fn transfer_and_burn_via_ata() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: fund_amount,
from_pin: None,
from_key_path: None,
}),
)
.await?;
@ -501,6 +503,8 @@ async fn transfer_via_ata_private_owner() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: fund_amount,
from_pin: None,
from_key_path: None,
}),
)
.await?;
@ -615,6 +619,8 @@ async fn burn_via_ata_private_owner() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: fund_amount,
from_pin: None,
from_key_path: None,
}),
)
.await?;

View File

@ -31,6 +31,8 @@ async fn private_transfer_to_owned_account() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -72,6 +74,8 @@ async fn private_transfer_to_foreign_account() -> Result<()> {
to_npk: Some(to_npk_string),
to_vpk: Some(hex::encode(to_vpk.0)),
amount: 100,
pin: None,
key_path: None,
});
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -122,6 +126,8 @@ async fn deshielded_transfer_to_public_account() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -187,6 +193,8 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> {
to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)),
to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)),
amount: 100,
pin: None,
key_path: None,
});
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -237,6 +245,8 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -281,6 +291,8 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> {
to_npk: Some(to_npk_string),
to_vpk: Some(hex::encode(to_vpk.0)),
amount: 100,
pin: None,
key_path: None,
});
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -353,6 +365,8 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> {
to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)),
to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)),
amount: 100,
pin: None,
key_path: None,
});
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -399,6 +413,8 @@ async fn initialize_private_account() -> Result<()> {
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
account_id: Some(format_private_account_id(account_id)),
account_label: None,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -456,6 +472,8 @@ async fn private_transfer_using_from_label() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -499,6 +517,8 @@ async fn initialize_private_account_using_label() -> Result<()> {
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
account_id: None,
account_label: Some(label),
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;

View File

@ -24,6 +24,8 @@ async fn successful_transfer_to_existing_account() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -82,6 +84,8 @@ pub async fn successful_transfer_to_new_account() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -120,6 +124,8 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 1_000_000,
pin: None,
key_path: None,
});
let failed_send = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await;
@ -160,6 +166,8 @@ async fn two_consecutive_successful_transfers() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -194,6 +202,8 @@ async fn two_consecutive_successful_transfers() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -238,6 +248,8 @@ async fn initialize_public_account() -> Result<()> {
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
account_id: Some(format_public_account_id(account_id)),
account_label: None,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -279,6 +291,8 @@ async fn successful_transfer_using_from_label() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -326,6 +340,8 @@ async fn successful_transfer_using_to_label() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;

View File

@ -113,6 +113,8 @@ async fn indexer_state_consistency() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -149,6 +151,8 @@ async fn indexer_state_consistency() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -235,6 +239,8 @@ async fn indexer_state_consistency_with_labels() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;

View File

@ -76,6 +76,8 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> {
to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)),
to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)),
amount: 100,
pin: None,
key_path: None,
});
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -152,6 +154,8 @@ async fn restore_keys_from_seed() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 100,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -164,6 +168,8 @@ async fn restore_keys_from_seed() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 101,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -204,6 +210,8 @@ async fn restore_keys_from_seed() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 102,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -216,6 +224,8 @@ async fn restore_keys_from_seed() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 103,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -281,6 +291,8 @@ async fn restore_keys_from_seed() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 10,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -292,6 +304,8 @@ async fn restore_keys_from_seed() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: 11,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;

View File

@ -54,6 +54,8 @@ async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()>
Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to: Some(winner_account_id_formatted),
to_label: None,
pin: None,
key_path: None,
}),
)
.await;
@ -109,6 +111,8 @@ async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<()
Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to: Some(winner_account_id_formatted),
to_label: None,
pin: None,
key_path: None,
}),
)
.await;
@ -141,6 +145,8 @@ async fn claim_pinata_to_existing_public_account() -> Result<()> {
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to: Some(format_public_account_id(ctx.existing_public_accounts()[0])),
to_label: None,
pin: None,
key_path: None,
});
let pinata_balance_pre = ctx
@ -182,6 +188,8 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> {
ctx.existing_private_accounts()[0],
)),
to_label: None,
pin: None,
key_path: None,
});
let pinata_balance_pre = ctx
@ -247,6 +255,8 @@ async fn claim_pinata_to_new_private_account() -> Result<()> {
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
account_id: Some(winner_account_id_formatted.clone()),
account_label: None,
pin: None,
key_path: None,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -263,6 +273,8 @@ async fn claim_pinata_to_new_private_account() -> Result<()> {
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to: Some(winner_account_id_formatted),
to_label: None,
pin: None,
key_path: None,
});
let pinata_balance_pre = ctx

View File

@ -135,6 +135,8 @@ async fn create_and_transfer_public_token() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: transfer_amount,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -180,6 +182,8 @@ async fn create_and_transfer_public_token() -> Result<()> {
holder: Some(format_public_account_id(recipient_account_id)),
holder_label: None,
amount: burn_amount,
holder_pin: None,
holder_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -228,6 +232,8 @@ async fn create_and_transfer_public_token() -> Result<()> {
holder_npk: None,
holder_vpk: None,
amount: mint_amount,
holder_pin: None,
holder_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -373,6 +379,8 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: transfer_amount,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -400,6 +408,8 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> {
holder: Some(format_private_account_id(recipient_account_id)),
holder_label: None,
amount: burn_amount,
holder_pin: None,
holder_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -567,6 +577,8 @@ async fn create_token_with_private_definition() -> Result<()> {
holder_npk: None,
holder_vpk: None,
amount: mint_amount_public,
holder_pin: None,
holder_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -615,6 +627,8 @@ async fn create_token_with_private_definition() -> Result<()> {
holder_npk: None,
holder_vpk: None,
amount: mint_amount_private,
holder_pin: None,
holder_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -757,6 +771,8 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: transfer_amount,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -888,6 +904,8 @@ async fn shielded_token_transfer() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: transfer_amount,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -1014,6 +1032,8 @@ async fn deshielded_token_transfer() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: transfer_amount,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -1149,6 +1169,8 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> {
holder_npk: Some(hex::encode(holder_keys.nullifier_public_key.0)),
holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.0)),
amount: mint_amount,
holder_pin: None,
holder_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@ -1352,6 +1374,8 @@ async fn transfer_token_using_from_label() -> Result<()> {
to_npk: None,
to_vpk: None,
amount: transfer_amount,
from_pin: None,
from_key_path: None,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;

View File

@ -31,7 +31,11 @@ impl WitnessSet {
}
#[must_use]
pub fn from_list(proof: Proof, signatures: &Vec<Signature>, public_keys: &Vec<PublicKey>) -> Self {
pub fn from_list(
proof: Proof,
signatures: &Vec<Signature>,
public_keys: &Vec<PublicKey>,
) -> Self {
assert_eq!(signatures.len(), public_keys.len());
let signatures_and_public_keys = signatures

View File

@ -106,7 +106,7 @@ class KeycardWallet:
public_only = True,
keypath = path
)
# TODO (marvin) clean this up
public_key = public_key.public_key
public_key = VerifyingKey.from_string(public_key[1:], curve=SECP256k1)
public_key = public_key.to_string("compressed")[1:]
@ -117,11 +117,12 @@ class KeycardWallet:
print(f"Error getting public key: {e}")
return None
def sign_message_for_path(self, message: bytes = b"DefaultMessageTestDefaultMessage", path: str = "m/44'/60'/0'/0/0") -> bytes | None:
try:
if not self.card.is_secure_channel_open or not self.card.is_pin_verified:
return None
signature = self.card.sign_with_path(
digest = message,
path = path,

View File

@ -72,7 +72,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public(
let transfer = NativeTokenTransfer(&wallet);
match block_on(transfer.send_public_transfer(from_id, to_id, amount)) {
match block_on(transfer.send_public_transfer(from_id, to_id, amount, &None, &None)) {
Ok(tx_hash) => {
let tx_hash = CString::new(tx_hash.to_string())
.map_or(ptr::null_mut(), std::ffi::CString::into_raw);
@ -566,7 +566,7 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account(
let transfer = NativeTokenTransfer(&wallet);
match block_on(transfer.register_account(account_id)) {
match block_on(transfer.register_account(account_id, &None, &None)) {
Ok(tx_hash) => {
let tx_hash = CString::new(tx_hash.to_string())
.map_or(ptr::null_mut(), std::ffi::CString::into_raw);

View File

@ -40,3 +40,4 @@ async-stream.workspace = true
indicatif = { version = "0.18.3", features = ["improved_unicode"] }
optfield = "0.4.0"
url.workspace = true
keycard_wallet.workspace = true

View File

@ -32,12 +32,15 @@ pub enum AccountSubcommand {
short,
long,
conflicts_with = "account_label",
required_unless_present = "account_label"
)]
account_id: Option<String>,
/// Account label (alternative to --account-id).
#[arg(long, conflicts_with = "account_id")]
account_label: Option<String>,
#[arg(long, conflicts_with = "account_id", conflicts_with = "account_id")]
pin: Option<String>,
#[arg(long, conflicts_with = "account_id", conflicts_with = "account_id")]
key_path: Option<String>,
},
/// Produce new public or private account.
#[command(subcommand)]
@ -191,12 +194,16 @@ impl WalletSubcommand for AccountSubcommand {
keys,
account_id,
account_label,
pin,
key_path,
} => {
let resolved = resolve_id_or_label(
account_id,
account_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&pin,
&key_path,
)?;
let (account_id_str, addr_kind) = parse_addr_with_privacy_prefix(&resolved)?;
@ -407,6 +414,8 @@ impl WalletSubcommand for AccountSubcommand {
account_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let (account_id_str, _) = parse_addr_with_privacy_prefix(&resolved)?;

View File

@ -1,10 +1,11 @@
use anyhow::Result;
use clap::Subcommand;
use keycard_wallet::{KeycardWallet, python_path};
use pyo3::prelude::*;
use crate::{
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand, keycard_wallet::KeycardWallet, python_path},
cli::{SubcommandReturnValue, WalletSubcommand},
};
/// Represents generic chain CLI subcommand.

View File

@ -27,9 +27,7 @@ pub mod account;
pub mod chain;
pub mod config;
pub mod keycard;
pub mod keycard_wallet;
pub mod programs;
pub mod python_path;
pub(crate) trait WalletSubcommand {
async fn handle_subcommand(self, wallet_core: &mut WalletCore)

View File

@ -51,7 +51,7 @@ pub enum AmmProgramAgnosticSubcommand {
#[arg(long)]
balance_a: u128,
#[arg(long)]
balance_b: u128,
balance_b: u128,
},
/// Swap specifying exact input amount.
///
@ -216,18 +216,24 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
user_holding_a_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_b = resolve_id_or_label(
user_holding_b,
user_holding_b_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_lp = resolve_id_or_label(
user_holding_lp,
user_holding_lp_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
@ -282,12 +288,16 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
user_holding_a_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_b = resolve_id_or_label(
user_holding_b,
user_holding_b_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
@ -368,18 +378,24 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
user_holding_a_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_b = resolve_id_or_label(
user_holding_b,
user_holding_b_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_lp = resolve_id_or_label(
user_holding_lp,
user_holding_lp_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;
@ -437,18 +453,24 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
user_holding_a_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_b = resolve_id_or_label(
user_holding_b,
user_holding_b_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let user_holding_lp = resolve_id_or_label(
user_holding_lp,
user_holding_lp_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let (user_holding_a, user_holding_a_privacy) =
parse_addr_with_privacy_prefix(&user_holding_a)?;

View File

@ -1,12 +1,13 @@
use anyhow::Result;
use clap::Subcommand;
use common::transaction::NSSATransaction;
use keycard_wallet::KeycardWallet;
use nssa::AccountId;
use crate::{
AccDecodeData::Decode,
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand, keycard_wallet::KeycardWallet},
cli::{SubcommandReturnValue, WalletSubcommand},
helperfunctions::{
AccountPrivacyKind, parse_addr_with_privacy_prefix, resolve_account_label,
resolve_id_or_label,
@ -85,16 +86,15 @@ impl WalletSubcommand for AuthTransferSubcommand {
pin,
key_path,
} => {
let resolved = if pin.is_none() {
resolve_id_or_label(
// TODO: I'm not sure if the string is correct...
let resolved = resolve_id_or_label(
account_id,
account_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
)?
} else {
String::default()
};
&pin,
&key_path
)?;
let (account_id, addr_privacy) = if pin.is_none() {
parse_addr_with_privacy_prefix(&resolved)?
@ -104,10 +104,14 @@ impl WalletSubcommand for AuthTransferSubcommand {
match addr_privacy {
AccountPrivacyKind::Public => {
// TODO: crucial (Marvin)
let account_id = if pin.is_none() {
account_id.parse()?
} else {
KeycardWallet::get_account_id_for_path_with_connect(&pin.as_ref().expect("TODO"), &key_path.as_ref().expect("TODO"))
KeycardWallet::get_account_id_for_path_with_connect(
&pin.as_ref().expect("TODO"),
&key_path.as_ref().expect("TODO"),
)
};
let tx_hash = NativeTokenTransfer(wallet_core)
@ -159,18 +163,15 @@ impl WalletSubcommand for AuthTransferSubcommand {
pin,
key_path,
} => {
let from = if pin.is_none() {
resolve_id_or_label(
from,
from_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
)?
} else {
KeycardWallet::get_account_id_for_path_with_connect(&pin.as_ref().expect("TODO"), &key_path.as_ref().expect("TODO")).to_string()
};
let from = resolve_id_or_label(
from,
from_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&pin,
&key_path,
)?;
let to = match (to, to_label) {
(v, None) => v,
(None, Some(label)) => Some(resolve_account_label(
@ -202,7 +203,13 @@ impl WalletSubcommand for AuthTransferSubcommand {
match (from_privacy, to_privacy) {
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Public { from, to, amount, pin, key_path }
NativeTokenTransferProgramSubcommand::Public {
from,
to,
amount,
pin,
key_path,
}
}
(AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Private(
@ -255,7 +262,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
to_vpk,
amount,
pin,
key_path
key_path,
},
)
}
@ -474,7 +481,13 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
Self::ShieldedOwned { from, to, amount , pin: _, key_path: _} => {
Self::ShieldedOwned {
from,
to,
amount,
pin: _,
key_path: _,
} => {
let from: AccountId = from.parse().unwrap();
let to: AccountId = to.parse().unwrap();
@ -505,7 +518,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
to_vpk,
amount,
pin: _,
key_path: _
key_path: _,
} => {
let from: AccountId = from.parse().unwrap();
@ -571,8 +584,13 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
Self::Public { from, to, amount, pin, key_path } => {
Self::Public {
from,
to,
amount,
pin,
key_path,
} => {
let from: AccountId = from.parse().unwrap();
let to: AccountId = to.parse().unwrap();

View File

@ -26,6 +26,10 @@ pub enum PinataProgramAgnosticSubcommand {
/// To account label (alternative to --to).
#[arg(long, conflicts_with = "to")]
to_label: Option<String>,
#[arg(long, conflicts_with = "to", conflicts_with = "to_label")]
pin: Option<String>,
#[arg(long, conflicts_with = "to", conflicts_with = "to_label")]
key_path: Option<String>,
},
}
@ -35,15 +39,19 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand {
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
let underlying_subcommand = match self {
Self::Claim { to, to_label } => {
Self::Claim { to, to_label , pin, key_path} => {
let to = resolve_id_or_label(
to,
to_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&pin,
&key_path,
)?;
let (to, to_addr_privacy) = parse_addr_with_privacy_prefix(&to)?;
// TODO: (Marvin) does privacy get marked correctly?
match to_addr_privacy {
AccountPrivacyKind::Public => {
PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim {

View File

@ -76,6 +76,10 @@ pub enum TokenProgramAgnosticSubcommand {
/// amount - amount of balance to move.
#[arg(long)]
amount: u128,
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
from_pin: Option<String>,
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
from_key_path: Option<String>,
},
/// Burn tokens on `holder`, modify `definition`.
///
@ -107,6 +111,10 @@ pub enum TokenProgramAgnosticSubcommand {
/// amount - amount of balance to burn.
#[arg(long)]
amount: u128,
#[arg(long, conflicts_with = "holder", conflicts_with = "holder_label")]
holder_pin: Option<String>,
#[arg(long, conflicts_with = "holder", conflicts_with = "holder_label")]
holder_key_path: Option<String>,
},
/// Mint tokens on `holder`, modify `definition`.
///
@ -142,6 +150,10 @@ pub enum TokenProgramAgnosticSubcommand {
/// amount - amount of balance to mint.
#[arg(long)]
amount: u128,
#[arg(long, conflicts_with = "holder", conflicts_with = "holder_label")]
holder_pin: Option<String>,
#[arg(long, conflicts_with = "holder", conflicts_with = "holder_label")]
holder_key_path: Option<String>,
},
}
@ -164,12 +176,16 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
definition_account_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let supply_account_id = resolve_id_or_label(
supply_account_id,
supply_account_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let (definition_account_id, definition_addr_privacy) =
parse_addr_with_privacy_prefix(&definition_account_id)?;
@ -229,12 +245,16 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
to_npk,
to_vpk,
amount,
from_pin,
from_key_path
} => {
let from = resolve_id_or_label(
from,
from_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&from_pin,
&from_key_path,
)?;
let to = match (to, to_label) {
(v, None) => v,
@ -264,7 +284,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(Some(to), None, None) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
// TODO: (Marvin) return here
match (from_privacy, to_privacy) {
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
TokenProgramSubcommand::Public(
@ -336,24 +356,30 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
holder,
holder_label,
amount,
holder_pin,
holder_key_path,
} => {
let definition = resolve_id_or_label(
definition,
definition_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let holder = resolve_id_or_label(
holder,
holder_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&holder_pin,
&holder_key_path,
)?;
let underlying_subcommand = {
let (definition, definition_privacy) =
parse_addr_with_privacy_prefix(&definition)?;
let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?;
// TODO Marvin return here
match (definition_privacy, holder_privacy) {
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
TokenProgramSubcommand::Public(
@ -404,24 +430,26 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
holder_npk,
holder_vpk,
amount,
holder_pin,
holder_key_path
} => {
let definition = resolve_id_or_label(
definition,
definition_label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&None,
&None,
)?;
let holder = match (holder, holder_label) {
(v, None) => v,
(None, Some(label)) => Some(resolve_account_label(
&label,
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
)?),
(Some(_), Some(_)) => {
anyhow::bail!("Provide only one of --holder or --holder-label")
}
};
let holder = Some(resolve_id_or_label(
holder.clone(),
holder_label.clone(),
&wallet_core.storage.labels,
&wallet_core.storage.user_data,
&holder_pin,
&holder_key_path,
)?);
//TODO return here (Marvin)
let underlying_subcommand = match (holder, holder_npk, holder_vpk) {
(None, None, None) => {
anyhow::bail!(

View File

@ -8,6 +8,8 @@ use nssa_core::account::Nonce;
use rand::{RngCore as _, rngs::OsRng};
use serde::Serialize;
use testnet_initial_state::{PrivateAccountPrivateInitialData, PublicAccountPrivateInitialData};
use keycard_wallet::KeycardWallet;
use crate::{
HOME_DIR_ENV_VAR,
@ -60,10 +62,13 @@ pub fn resolve_id_or_label(
label: Option<String>,
labels: &HashMap<String, Label>,
user_data: &NSSAUserData,
pin: &Option<String>,
key_path: &Option<String>,
) -> Result<String> {
match (id, label) {
(Some(id), None) => Ok(id),
(None, Some(label)) => resolve_account_label(&label, labels, user_data),
match (id, label, pin) {
(Some(id), None, None) => Ok(id),
(None, Some(label), None) => resolve_account_label(&label, labels, user_data),
(None, None, Some(pin)) => Ok(KeycardWallet::get_account_id_for_path_with_connect(pin, key_path.as_ref().expect("TODO")).to_string()),
_ => anyhow::bail!("provide exactly one of account id or account label"),
}
}

View File

@ -16,13 +16,14 @@ use chain_storage::WalletChainStore;
use common::{HashType, transaction::NSSATransaction};
use config::WalletConfig;
use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode as _};
use keycard_wallet::KeycardWallet;
use log::info;
use nssa::{
PublicKey,
Account, AccountId, PrivacyPreservingTransaction, Signature, privacy_preserving_transaction::{
Account, AccountId, PrivacyPreservingTransaction, PublicKey, Signature,
privacy_preserving_transaction::{
circuit::{ProgramWithDependencies, Proof},
message::EncryptedAccountData,
}
},
};
use nssa_core::{
Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData,
@ -32,7 +33,9 @@ use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuil
use tokio::io::AsyncWriteExt as _;
use crate::{
cli::keycard_wallet::KeycardWallet, config::{PersistentStorage, WalletConfigOverrides}, helperfunctions::produce_data_for_storage, poller::TxPoller
config::{PersistentStorage, WalletConfigOverrides},
helperfunctions::produce_data_for_storage,
poller::TxPoller,
};
pub mod chain_storage;
@ -587,23 +590,28 @@ impl WalletCore {
message: &nssa::privacy_preserving_transaction::Message,
proof: Proof,
pin: &String,
key_paths: &[String]
key_paths: &[String],
) -> Result<nssa::privacy_preserving_transaction::witness_set::WitnessSet, ExecutionFailureKind>
{
let mut signatures = Vec::<Signature>::new();
let mut public_keys = Vec::<PublicKey>::new();
let message_bytes: [u8; 32] = {
let v = message.to_bytes();
let mut bytes = [0_u8; 32];
let len = v.len().min(32);
bytes[..len].copy_from_slice(&v[..len]);
bytes
};
let message_bytes: [u8; 32] = {
let v = message.to_bytes();
let mut bytes = [0_u8; 32];
let len = v.len().min(32);
bytes[..len].copy_from_slice(&v[..len]);
bytes
};
for path in key_paths.iter() {
public_keys.push( KeycardWallet::get_public_key_for_path_with_connect(&pin, &path));
signatures.push( KeycardWallet::sign_message_for_path_with_connection(&pin, &path, &message_bytes).expect("Expect a valid signature"));
public_keys.push(KeycardWallet::get_public_key_for_path_with_connect(
&pin, &path,
));
signatures.push(
KeycardWallet::sign_message_for_path_with_connect(&pin, &path, &message_bytes)
.expect("Expect a valid signature"),
);
}
Ok(

View File

@ -1,17 +1,14 @@
use common::{HashType, transaction::NSSATransaction};
use keycard_wallet::KeycardWallet;
use nssa::{
AccountId, PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use pyo3::Python;
use sequencer_service_rpc::RpcClient as _;
use super::NativeTokenTransfer;
use crate::{
ExecutionFailureKind, WalletCore,
cli::{keycard_wallet::KeycardWallet, python_path},
};
use crate::{ExecutionFailureKind, WalletCore};
impl NativeTokenTransfer<'_> {
pub async fn send_public_transfer(
@ -59,21 +56,22 @@ impl NativeTokenTransfer<'_> {
Message::try_new(program_id, account_ids, nonces, balance_to_move).unwrap();
let witness_set = if pin.is_none() {
WalletCore::sign_public_message(self.0, &message, &sign_ids)
.expect("Expect a valid signature")
} else {
// TODO: maybe the issue? (Marvin)
let message_bytes: [u8; 32] = {
let v = message.to_bytes();
let mut bytes = [0_u8; 32];
let len = v.len().min(32);
bytes[..len].copy_from_slice(&v[..len]);
bytes
};
let pub_key = KeycardWallet::get_public_key_for_path_with_connect(&pin.as_ref().expect("TODO"), &key_path.as_ref().expect("TODO"));
let signature = KeycardWallet::sign_message_for_path_with_connection(&pin.as_ref().expect("TODO"), &key_path.as_ref().expect("TODO"), &message_bytes).expect("Expect valid signature");
WitnessSet::from_list(&[signature], &[pub_key])
};
WalletCore::sign_public_message(self.0, &message, &sign_ids)
.expect("Expect a valid signature")
} else {
let pub_key = KeycardWallet::get_public_key_for_path_with_connect(
&pin.as_ref().expect("TODO"),
&key_path.as_ref().expect("TODO"),
);
let signature = KeycardWallet::sign_message_for_path_with_connect(
&pin.as_ref().expect("TODO"),
&key_path.as_ref().expect("TODO"),
&message.hash_message(),
)
.expect("Expect valid signature");
WitnessSet::from_list(&[signature], &[pub_key])
};
let tx = PublicTransaction::new(message, witness_set);
@ -102,16 +100,8 @@ impl NativeTokenTransfer<'_> {
let instruction: u128 = 0;
let account_ids = vec![from];
let program_id = Program::authenticated_transfer_program().id();
let message = Message::try_new(program_id, account_ids, nonces, instruction).unwrap();
let message = Message::try_new(program_id, account_ids, nonces, instruction).expect("Expect a valid Message");
// (Marvin): This really needs to be the ChainIndex
// But, I cannot change that due to Default Accounts.
// Instead, I had introduced a "NEW" sign...which I do not see...
// Correction: I did not need a specific function. Rather, I use `from_list` to combine
// public and signatures together for a WitnessSet.
// The tricky part is that I NEED to do everything with chain-codes... This won't look nice,
// but is feasible.
let witness_set = if pin.is_none() {
let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from);
@ -121,42 +111,18 @@ impl NativeTokenTransfer<'_> {
WitnessSet::for_message(&message, &[signing_key])
} else {
let witness_set = Python::with_gil(|py| {
python_path::add_python_path(py).expect("keycard_wallet.py not found");
let pub_key = KeycardWallet::get_public_key_for_path_with_connect(
pin.as_ref().expect("TODO"),
key_path.as_ref().expect("TODO"),
);
let wallet = KeycardWallet::new(py).expect("Expect keycard wallet");
let is_connected = wallet
.setup_communication(py, pin.as_ref().expect("TODO"))
.expect("Expect a Boolean.");
if is_connected {
println!("\u{2705} Keycard is now connected to wallet.");
} else {
println!("\u{274c} Keycard is not connected to wallet.");
}
// TODO: maybe the issue? (Marvin)
let message: [u8; 32] = {
let v = message.to_bytes();
let mut bytes = [0_u8; 32];
let len = v.len().min(32);
bytes[..len].copy_from_slice(&v[..len]);
bytes
};
let pub_key = wallet
.get_public_key_for_path(py, key_path.as_ref().expect("TODO"))
.expect("Expect a valid public key");
let signature = wallet
.sign_message_for_path(py, key_path.as_ref().expect("TODO"), &message)
.expect("TODO");
let _ = wallet.disconnect(py);
WitnessSet::from_list(&[signature], &[pub_key])
});
witness_set
let signature = KeycardWallet::sign_message_for_path_with_connect(
pin.as_ref().as_ref().expect("TODO"),
key_path.as_ref().expect("TODO"),
&message.hash_message(),
)
.expect("Expect a valid Signature.");
WitnessSet::from_list(&[signature], &[pub_key])
};
let tx = PublicTransaction::new(message, witness_set);

View File

@ -10,7 +10,7 @@ python3 -m pip install pyaes
cd python
git clone --branch lee-schnorr --single-branch https://github.com/bitgamma/keycard-py.git
# git clone --branch lee-schnorr --single-branch https://github.com/bitgamma/keycard-py.git
cd keycard-py
python3 -m venv venv
source venv/bin/activate