This commit is contained in:
Marvin Jones 2026-06-17 17:34:11 -04:00
parent c8c9ced421
commit 935a925fe9
18 changed files with 366 additions and 356 deletions

View File

@ -4,10 +4,6 @@ use leptos::prelude::*;
use leptos_router::components::A; use leptos_router::components::A;
#[component] #[component]
#[expect(
clippy::needless_pass_by_value,
reason = "Leptos component props are passed by value by framework convention"
)]
pub fn AccountNonceList(account_ids: Vec<AccountId>, nonces: Vec<u128>) -> impl IntoView { pub fn AccountNonceList(account_ids: Vec<AccountId>, nonces: Vec<u128>) -> impl IntoView {
view! { view! {
<div class="accounts-list"> <div class="accounts-list">

View File

@ -1,5 +1,10 @@
pub use account_nonce_list::AccountNonceList;
pub use account_preview::AccountPreview; pub use account_preview::AccountPreview;
pub use block_preview::BlockPreview; pub use block_preview::BlockPreview;
pub use search_results::SearchResultsView;
pub use transaction_details::{
PrivacyPreservingTxDetails, ProgramDeploymentTxDetails, PublicTxDetails,
};
pub use transaction_preview::TransactionPreview; pub use transaction_preview::TransactionPreview;
pub mod account_nonce_list; pub mod account_nonce_list;
@ -8,9 +13,3 @@ pub mod block_preview;
pub mod search_results; pub mod search_results;
pub mod transaction_details; pub mod transaction_details;
pub mod transaction_preview; pub mod transaction_preview;
pub use account_nonce_list::AccountNonceList;
pub use search_results::SearchResultsView;
pub use transaction_details::{
PrivacyPreservingTxDetails, ProgramDeploymentTxDetails, PublicTxDetails,
};

View File

@ -5,10 +5,6 @@ use crate::api::SearchResults;
/// Search results view component /// Search results view component
#[component] #[component]
#[expect(
clippy::needless_pass_by_value,
reason = "Leptos component props are passed by value by framework convention"
)]
pub fn SearchResultsView(results: SearchResults) -> impl IntoView { pub fn SearchResultsView(results: SearchResults) -> impl IntoView {
let SearchResults { let SearchResults {
blocks, blocks,

View File

@ -8,10 +8,6 @@ use super::AccountNonceList;
/// Public transaction details component /// Public transaction details component
#[component] #[component]
#[expect(
clippy::needless_pass_by_value,
reason = "Leptos component props are passed by value by framework convention"
)]
pub fn PublicTxDetails(tx: PublicTransaction) -> impl IntoView { pub fn PublicTxDetails(tx: PublicTransaction) -> impl IntoView {
let PublicTransaction { let PublicTransaction {
hash: _, hash: _,
@ -65,10 +61,6 @@ pub fn PublicTxDetails(tx: PublicTransaction) -> impl IntoView {
/// Privacy-preserving transaction details component /// Privacy-preserving transaction details component
#[component] #[component]
#[expect(
clippy::needless_pass_by_value,
reason = "Leptos component props are passed by value by framework convention"
)]
pub fn PrivacyPreservingTxDetails(tx: PrivacyPreservingTransaction) -> impl IntoView { pub fn PrivacyPreservingTxDetails(tx: PrivacyPreservingTransaction) -> impl IntoView {
let PrivacyPreservingTransaction { let PrivacyPreservingTransaction {
hash: _, hash: _,
@ -137,15 +129,8 @@ pub fn PrivacyPreservingTxDetails(tx: PrivacyPreservingTransaction) -> impl Into
/// Program deployment transaction details component /// Program deployment transaction details component
#[component] #[component]
#[expect(
clippy::needless_pass_by_value,
reason = "Leptos component props are passed by value by framework convention"
)]
pub fn ProgramDeploymentTxDetails(tx: ProgramDeploymentTransaction) -> impl IntoView { pub fn ProgramDeploymentTxDetails(tx: ProgramDeploymentTransaction) -> impl IntoView {
let ProgramDeploymentTransaction { let ProgramDeploymentTransaction { hash: _, message } = tx;
hash: _,
message,
} = tx;
let ProgramDeploymentMessage { bytecode } = message; let ProgramDeploymentMessage { bytecode } = message;
let bytecode_len = bytecode.len(); let bytecode_len = bytecode.len();

View File

@ -4,8 +4,10 @@ use indexer_service_protocol::{HashType, Transaction};
use leptos::prelude::*; use leptos::prelude::*;
use leptos_router::hooks::use_params_map; use leptos_router::hooks::use_params_map;
use crate::api; use crate::{
use crate::components::{PrivacyPreservingTxDetails, ProgramDeploymentTxDetails, PublicTxDetails}; api,
components::{PrivacyPreservingTxDetails, ProgramDeploymentTxDetails, PublicTxDetails},
};
/// Transaction page component /// Transaction page component
#[component] #[component]

View File

@ -211,17 +211,6 @@ mod tests {
use super::*; use super::*;
#[test]
fn correct_startup() {
let home = tempdir().unwrap();
let storage = IndexerStore::open_db(home.as_ref()).unwrap();
let final_id = storage.get_last_block_id().unwrap();
assert_eq!(final_id, None);
}
struct TestFixture { struct TestFixture {
storage: IndexerStore, storage: IndexerStore,
from: AccountId, from: AccountId,
@ -229,6 +218,10 @@ mod tests {
_home: tempfile::TempDir, _home: tempfile::TempDir,
} }
#[expect(
clippy::arithmetic_side_effects,
reason = "test helper with bounded inputs"
)]
async fn store_with_transfer_blocks( async fn store_with_transfer_blocks(
block_count: u64, block_count: u64,
prev_hash: Option<common::HashType>, prev_hash: Option<common::HashType>,
@ -244,7 +237,11 @@ mod tests {
let mut prev_hash = prev_hash; let mut prev_hash = prev_hash;
for i in 0..block_count { for i in 0..block_count {
let tx = common::test_utils::create_transaction_native_token_transfer( let tx = common::test_utils::create_transaction_native_token_transfer(
from, u128::from(i), to, 10, &sign_key, from,
u128::from(i),
to,
10,
&sign_key,
); );
let block_id = i + 1; let block_id = i + 1;
@ -260,7 +257,23 @@ mod tests {
.unwrap(); .unwrap();
} }
TestFixture { storage, from, to, _home: home } TestFixture {
storage,
from,
to,
_home: home,
}
}
#[test]
fn correct_startup() {
let home = tempdir().unwrap();
let storage = IndexerStore::open_db(home.as_ref()).unwrap();
let final_id = storage.get_last_block_id().unwrap();
assert_eq!(final_id, None);
} }
#[tokio::test] #[tokio::test]
@ -313,7 +326,12 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn account_state_at_block() { async fn account_state_at_block() {
let TestFixture { storage, from, to, _home } = store_with_transfer_blocks(10, None).await; let TestFixture {
storage,
from,
to,
_home,
} = store_with_transfer_blocks(10, None).await;
let acc1_at_1 = storage.account_state_at_block(&from, 1).unwrap(); let acc1_at_1 = storage.account_state_at_block(&from, 1).unwrap();
let acc2_at_1 = storage.account_state_at_block(&to, 1).unwrap(); let acc2_at_1 = storage.account_state_at_block(&to, 1).unwrap();

View File

@ -247,6 +247,10 @@ fn normalize_keycard_signature(py_signature: Vec<u8>) -> PyResult<[u8; 64]> {
} }
} }
#[expect(
clippy::needless_pass_by_value,
reason = "Zeroizing<Vec<u8>> is consumed to ensure the source is zeroed on drop"
)]
fn zeroizing_fixed_bytes<const N: usize>( fn zeroizing_fixed_bytes<const N: usize>(
label: &str, label: &str,
raw: Zeroizing<Vec<u8>>, raw: Zeroizing<Vec<u8>>,

View File

@ -36,6 +36,7 @@ pub mod config;
pub mod mock; pub mod mock;
/// The origin of a transaction. /// The origin of a transaction.
#[derive(Clone, Copy)]
pub enum TransactionOrigin { pub enum TransactionOrigin {
/// Basic transactions submitted by users via RPC. /// Basic transactions submitted by users via RPC.
User, User,
@ -69,20 +70,17 @@ impl<BP: BlockPublisherTrait> SequencerCore<BP> {
/// assumed to represent the correct latest state consistent with Bedrock-finalized data. /// assumed to represent the correct latest state consistent with Bedrock-finalized data.
/// If no database is found, the sequencer performs a fresh start from genesis, /// If no database is found, the sequencer performs a fresh start from genesis,
/// initializing its state with the accounts defined in the configuration file. /// initializing its state with the accounts defined in the configuration file.
fn open_or_create_store( fn open_or_create_store(config: &SequencerConfig) -> (SequencerStore, lee::V03State, Block) {
config: &SequencerConfig,
) -> (SequencerStore, lee::V03State, Block) {
let signing_key = lee::PrivateKey::try_new(config.signing_key).unwrap(); let signing_key = lee::PrivateKey::try_new(config.signing_key).unwrap();
let db_path = config.home.join("rocksdb"); let db_path = config.home.join("rocksdb");
if db_path.exists() { if db_path.exists() {
let store = let store = SequencerStore::open_db(&db_path, signing_key).unwrap_or_else(|err| {
SequencerStore::open_db(&db_path, signing_key.clone()).unwrap_or_else(|err| { panic!(
panic!( "Failed to open database at {} with error: {err}",
"Failed to open database at {} with error: {err}", db_path.display()
db_path.display() )
) });
});
let state = store let state = store
.get_lee_state() .get_lee_state()
.expect("Failed to read state from store"); .expect("Failed to read state from store");
@ -381,11 +379,7 @@ impl<BP: BlockPublisherTrait> SequencerCore<BP> {
} }
self.state self.state
.transition_from_public_transaction( .transition_from_public_transaction(public_tx, block_height, timestamp)
public_tx,
block_height,
timestamp,
)
.context("Failed to execute sequencer-generated transaction")?; .context("Failed to execute sequencer-generated transaction")?;
} }
} }

View File

@ -226,23 +226,25 @@ impl AccountManager {
} }
prepare_public_keycard_state(wallet, account_id, key_path).await? prepare_public_keycard_state(wallet, account_id, key_path).await?
} }
AccountIdentity::PrivateOwned(account_id) => { AccountIdentity::PrivateOwned(account_id) => State::Private(
State::Private(private_key_tree_acc_preparation(wallet, account_id, false).await?) private_key_tree_acc_preparation(wallet, account_id, false).await?,
} ),
AccountIdentity::PrivateForeign { AccountIdentity::PrivateForeign {
npk, npk,
vpk, vpk,
identifier, identifier,
} => State::Private(private_foreign_acc_preparation(npk, vpk, identifier)), } => State::Private(private_foreign_acc_preparation(npk, vpk, identifier)),
AccountIdentity::PrivatePdaOwned(account_id) => { AccountIdentity::PrivatePdaOwned(account_id) => State::Private(
State::Private(private_key_tree_acc_preparation(wallet, account_id, true).await?) private_key_tree_acc_preparation(wallet, account_id, true).await?,
} ),
AccountIdentity::PrivatePdaForeign { AccountIdentity::PrivatePdaForeign {
account_id, account_id,
npk, npk,
vpk, vpk,
identifier, identifier,
} => State::Private(private_pda_foreign_acc_preparation(account_id, npk, vpk, identifier)), } => State::Private(private_pda_foreign_acc_preparation(
account_id, npk, vpk, identifier,
)),
AccountIdentity::PrivateShared { AccountIdentity::PrivateShared {
nsk, nsk,
npk, npk,
@ -251,7 +253,10 @@ impl AccountManager {
} => { } => {
let account_id = lee::AccountId::from((&npk, identifier)); let account_id = lee::AccountId::from((&npk, identifier));
State::Private( State::Private(
private_shared_acc_preparation(wallet, account_id, nsk, npk, vpk, identifier, false).await?, private_shared_acc_preparation(
wallet, account_id, nsk, npk, vpk, identifier, false,
)
.await?,
) )
} }
AccountIdentity::PrivatePdaShared { AccountIdentity::PrivatePdaShared {
@ -261,7 +266,10 @@ impl AccountManager {
vpk, vpk,
identifier, identifier,
} => State::Private( } => State::Private(
private_shared_acc_preparation(wallet, account_id, nsk, npk, vpk, identifier, true).await?, private_shared_acc_preparation(
wallet, account_id, nsk, npk, vpk, identifier, true,
)
.await?,
), ),
}; };
@ -459,7 +467,7 @@ async fn prepare_public_state(
} else { } else {
None None
}; };
let account = AccountWithMetadata::new(acc.clone(), sk.is_some(), account_id); let account = AccountWithMetadata::new(acc, sk.is_some(), account_id);
Ok(State::Public { account, sk }) Ok(State::Public { account, sk })
} }
@ -472,7 +480,7 @@ async fn prepare_public_keycard_state(
.get_account_public(account_id) .get_account_public(account_id)
.await .await
.map_err(ExecutionFailureKind::SequencerError)?; .map_err(ExecutionFailureKind::SequencerError)?;
let account = AccountWithMetadata::new(acc.clone(), true, account_id); let account = AccountWithMetadata::new(acc, true, account_id);
Ok(State::PublicKeycard { account, key_path }) Ok(State::PublicKeycard { account, key_path })
} }

View File

@ -126,7 +126,7 @@ pub enum NewSubcommand {
} }
impl NewSubcommand { impl NewSubcommand {
async fn handle_public( fn handle_public(
cci: Option<ChainIndex>, cci: Option<ChainIndex>,
label: Option<Label>, label: Option<Label>,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
@ -151,9 +151,7 @@ impl NewSubcommand {
.add_label(label, AccountIdWithPrivacy::Public(account_id))?; .add_label(label, AccountIdWithPrivacy::Public(account_id))?;
} }
println!( println!("Generated new account with account_id Public/{account_id} at path {chain_index}");
"Generated new account with account_id Public/{account_id} at path {chain_index}"
);
println!("With pk {}", hex::encode(public_key.value())); println!("With pk {}", hex::encode(public_key.value()));
wallet_core.store_persistent_data()?; wallet_core.store_persistent_data()?;
@ -161,7 +159,7 @@ impl NewSubcommand {
Ok(SubcommandReturnValue::RegisterAccount { account_id }) Ok(SubcommandReturnValue::RegisterAccount { account_id })
} }
async fn handle_private( fn handle_private(
cci: Option<ChainIndex>, cci: Option<ChainIndex>,
label: Option<Label>, label: Option<Label>,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
@ -199,8 +197,8 @@ impl NewSubcommand {
Ok(SubcommandReturnValue::RegisterAccount { account_id }) Ok(SubcommandReturnValue::RegisterAccount { account_id })
} }
async fn handle_private_gms( fn handle_private_gms(
group: Label, group: &Label,
label: Option<Label>, label: Option<Label>,
pda: bool, pda: bool,
seed: Option<String>, seed: Option<String>,
@ -214,8 +212,7 @@ impl NewSubcommand {
let info = if pda { let info = if pda {
let seed_hex = seed.context("--seed is required for PDA accounts")?; let seed_hex = seed.context("--seed is required for PDA accounts")?;
let pid_hex = let pid_hex = program_id.context("--program-id is required for PDA accounts")?;
program_id.context("--program-id is required for PDA accounts")?;
let seed_bytes: [u8; 32] = hex::decode(&seed_hex) let seed_bytes: [u8; 32] = hex::decode(&seed_hex)
.context("Invalid seed hex")? .context("Invalid seed hex")?
@ -259,7 +256,7 @@ impl NewSubcommand {
}) })
} }
async fn handle_private_accounts_key( fn handle_private_accounts_key(
cci: Option<ChainIndex>, cci: Option<ChainIndex>,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
@ -289,12 +286,8 @@ impl WalletSubcommand for NewSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
Self::Public { cci, label } => { Self::Public { cci, label } => Self::handle_public(cci, label, wallet_core),
Self::handle_public(cci, label, wallet_core).await Self::Private { cci, label } => Self::handle_private(cci, label, wallet_core),
}
Self::Private { cci, label } => {
Self::handle_private(cci, label, wallet_core).await
}
Self::PrivateGms { Self::PrivateGms {
group, group,
label, label,
@ -302,12 +295,16 @@ impl WalletSubcommand for NewSubcommand {
seed, seed,
program_id, program_id,
identifier, identifier,
} => { } => Self::handle_private_gms(
Self::handle_private_gms(group, label, pda, seed, program_id, identifier, wallet_core).await &group,
} label,
Self::PrivateAccountsKey { cci } => { pda,
Self::handle_private_accounts_key(cci, wallet_core).await seed,
} program_id,
identifier,
wallet_core,
),
Self::PrivateAccountsKey { cci } => Self::handle_private_accounts_key(cci, wallet_core),
} }
} }
} }
@ -317,7 +314,7 @@ impl AccountSubcommand {
raw: bool, raw: bool,
keys: bool, keys: bool,
account_id: CliAccountMention, account_id: CliAccountMention,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let resolved = account_id.resolve(wallet_core.storage())?; let resolved = account_id.resolve(wallet_core.storage())?;
wallet_core wallet_core
@ -387,25 +384,20 @@ impl AccountSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_list( async fn handle_list(long: bool, wallet_core: &WalletCore) -> Result<SubcommandReturnValue> {
long: bool,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
let key_chain = &wallet_core.storage.key_chain(); let key_chain = &wallet_core.storage.key_chain();
let storage = wallet_core.storage(); let storage = wallet_core.storage();
let format_with_label = let format_with_label = |id: AccountIdWithPrivacy, chain_index: Option<&ChainIndex>| {
|id: AccountIdWithPrivacy, chain_index: Option<&ChainIndex>| { let id_str = chain_index.map_or_else(|| id.to_string(), |cci| format!("{cci} {id}"));
let id_str =
chain_index.map_or_else(|| id.to_string(), |cci| format!("{cci} {id}"));
let labels = storage.labels_for_account(id).format(", ").to_string(); let labels = storage.labels_for_account(id).format(", ").to_string();
if labels.is_empty() { if labels.is_empty() {
id_str id_str
} else { } else {
format!("{id_str} [{labels}]") format!("{id_str} [{labels}]")
} }
}; };
if !long { if !long {
let accounts = key_chain let accounts = key_chain
@ -456,9 +448,9 @@ impl AccountSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_label( fn handle_label(
account_id: CliAccountMention, account_id: &CliAccountMention,
label: Label, label: &Label,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let account_id = account_id.resolve(wallet_core.storage())?; let account_id = account_id.resolve(wallet_core.storage())?;
@ -474,9 +466,9 @@ impl AccountSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_show_keys( fn handle_show_keys(
account_id: CliAccountMention, account_id: &CliAccountMention,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let resolved = account_id.resolve(wallet_core.storage())?; let resolved = account_id.resolve(wallet_core.storage())?;
let AccountIdWithPrivacy::Private(account_id) = resolved else { let AccountIdWithPrivacy::Private(account_id) = resolved else {
@ -524,14 +516,12 @@ impl WalletSubcommand for AccountSubcommand {
} }
Self::List { long } => Self::handle_list(long, wallet_core).await, Self::List { long } => Self::handle_list(long, wallet_core).await,
Self::Label { account_id, label } => { Self::Label { account_id, label } => {
Self::handle_label(account_id, label, wallet_core).await Self::handle_label(&account_id, &label, wallet_core)
} }
Self::Import(import_subcommand) => { Self::Import(import_subcommand) => {
import_subcommand.handle_subcommand(wallet_core).await import_subcommand.handle_subcommand(wallet_core).await
} }
Self::ShowKeys { account_id } => { Self::ShowKeys { account_id } => Self::handle_show_keys(&account_id, wallet_core),
Self::handle_show_keys(account_id, wallet_core).await
}
} }
} }
} }

View File

@ -24,10 +24,10 @@ pub enum ConfigSubcommand {
} }
impl ConfigSubcommand { impl ConfigSubcommand {
async fn handle_get( fn handle_get(
all: bool, all: bool,
key: Option<String>, key: Option<String>,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let config = wallet_core.config(); let config = wallet_core.config();
if all { if all {
@ -109,11 +109,8 @@ impl ConfigSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_description( fn handle_description(key: &str, _wallet_core: &WalletCore) -> SubcommandReturnValue {
key: String, match key {
_wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match key.as_str() {
"override_rust_log" => { "override_rust_log" => {
println!("Value of variable RUST_LOG to override, affects logging"); println!("Value of variable RUST_LOG to override, affects logging");
} }
@ -151,7 +148,7 @@ impl ConfigSubcommand {
} }
} }
Ok(SubcommandReturnValue::Empty) SubcommandReturnValue::Empty
} }
} }
@ -161,9 +158,9 @@ impl WalletSubcommand for ConfigSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
Self::Get { all, key } => Self::handle_get(all, key, wallet_core).await, Self::Get { all, key } => Self::handle_get(all, key, wallet_core),
Self::Set { key, value } => Self::handle_set(key, value, wallet_core).await, Self::Set { key, value } => Self::handle_set(key, value, wallet_core).await,
Self::Description { key } => Self::handle_description(key, wallet_core).await, Self::Description { key } => Ok(Self::handle_description(&key, wallet_core)),
} }
} }
} }

View File

@ -50,11 +50,11 @@ pub enum GroupSubcommand {
} }
impl GroupSubcommand { impl GroupSubcommand {
async fn handle_new(name: Label, wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_new(name: &Label, wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
if wallet_core if wallet_core
.storage() .storage()
.key_chain() .key_chain()
.group_key_holder(&name) .group_key_holder(name)
.is_some() .is_some()
{ {
anyhow::bail!("Group '{name}' already exists"); anyhow::bail!("Group '{name}' already exists");
@ -68,7 +68,7 @@ impl GroupSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_list(wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_list(wallet_core: &WalletCore) -> SubcommandReturnValue {
let mut empty = true; let mut empty = true;
let holders_iter = wallet_core.storage().key_chain().group_key_holders_iter(); let holders_iter = wallet_core.storage().key_chain().group_key_holders_iter();
for (name, _) in holders_iter { for (name, _) in holders_iter {
@ -78,11 +78,11 @@ impl GroupSubcommand {
if empty { if empty {
println!("No groups found"); println!("No groups found");
} }
Ok(SubcommandReturnValue::Empty) SubcommandReturnValue::Empty
} }
async fn handle_remove(name: Label, wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_remove(name: &Label, wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
if wallet_core.remove_group_key_holder(&name).is_none() { if wallet_core.remove_group_key_holder(name).is_none() {
anyhow::bail!("Group '{name}' not found"); anyhow::bail!("Group '{name}' not found");
} }
@ -91,37 +91,35 @@ impl GroupSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_invite( fn handle_invite(
name: Label, name: &Label,
key: String, key: &str,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let holder = wallet_core let holder = wallet_core
.storage() .storage()
.key_chain() .key_chain()
.group_key_holder(&name) .group_key_holder(name)
.context(format!("Group '{name}' not found"))?; .context(format!("Group '{name}' not found"))?;
let key_bytes = hex::decode(&key).context("Invalid key hex")?; let key_bytes = hex::decode(key).context("Invalid key hex")?;
let recipient_key = let recipient_key =
key_protocol::key_management::group_key_holder::SealingPublicKey::from_bytes( key_protocol::key_management::group_key_holder::SealingPublicKey::from_bytes(key_bytes);
key_bytes,
);
let sealed = holder.seal_for(&recipient_key); let sealed = holder.seal_for(&recipient_key);
println!("{}", hex::encode(&sealed)); println!("{}", hex::encode(&sealed));
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_join( fn handle_join(
name: Label, name: &Label,
sealed: String, sealed: &str,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
if wallet_core if wallet_core
.storage() .storage()
.key_chain() .key_chain()
.group_key_holder(&name) .group_key_holder(name)
.is_some() .is_some()
{ {
anyhow::bail!("Group '{name}' already exists"); anyhow::bail!("Group '{name}' already exists");
@ -133,7 +131,7 @@ impl GroupSubcommand {
.sealing_secret_key() .sealing_secret_key()
.context("No sealing key found. Run 'wallet group new-sealing-key' first.")?; .context("No sealing key found. Run 'wallet group new-sealing-key' first.")?;
let sealed_bytes = hex::decode(&sealed).context("Invalid sealed hex")?; let sealed_bytes = hex::decode(sealed).context("Invalid sealed hex")?;
let holder = GroupKeyHolder::unseal(&sealed_bytes, sealing_key) let holder = GroupKeyHolder::unseal(&sealed_bytes, sealing_key)
.map_err(|e| anyhow::anyhow!("Failed to unseal: {e:?}"))?; .map_err(|e| anyhow::anyhow!("Failed to unseal: {e:?}"))?;
@ -145,7 +143,7 @@ impl GroupSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_new_sealing_key(wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_new_sealing_key(wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
if wallet_core if wallet_core
.storage() .storage()
.key_chain() .key_chain()
@ -181,12 +179,12 @@ impl WalletSubcommand for GroupSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
Self::New { name } => Self::handle_new(name, wallet_core).await, Self::New { name } => Self::handle_new(&name, wallet_core),
Self::List => Self::handle_list(wallet_core).await, Self::List => Ok(Self::handle_list(wallet_core)),
Self::Remove { name } => Self::handle_remove(name, wallet_core).await, Self::Remove { name } => Self::handle_remove(&name, wallet_core),
Self::Invite { name, key } => Self::handle_invite(name, key, wallet_core).await, Self::Invite { name, key } => Self::handle_invite(&name, &key, wallet_core),
Self::Join { name, sealed } => Self::handle_join(name, sealed, wallet_core).await, Self::Join { name, sealed } => Self::handle_join(&name, &sealed, wallet_core),
Self::NewSealingKey => Self::handle_new_sealing_key(wallet_core).await, Self::NewSealingKey => Self::handle_new_sealing_key(wallet_core),
} }
} }
} }

View File

@ -38,16 +38,16 @@ pub enum KeycardSubcommand {
} }
impl KeycardSubcommand { impl KeycardSubcommand {
async fn handle_available(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_available(_wallet_core: &mut WalletCore) -> SubcommandReturnValue {
Python::attach(|py| { Python::attach(|py| {
python_path::add_python_path(py) python_path::add_python_path(py)
.expect("`wallet::keycard::available`: unable to setup python path"); .expect("`wallet::keycard::available`: unable to setup python path");
let wallet = KeycardWallet::new(py) let wallet = KeycardWallet::new(py)
.expect("`wallet::keycard::available`: invalid data received for pin"); .expect("`wallet::keycard::available`: invalid data received for pin");
let available = wallet.is_unpaired_keycard_available(py).expect( let available = wallet
"`wallet::keycard::available`: received invalid data from Keycard wrapper", .is_unpaired_keycard_available(py)
); .expect("`wallet::keycard::available`: received invalid data from Keycard wrapper");
if available { if available {
println!("\u{2705} Keycard is available."); println!("\u{2705} Keycard is available.");
@ -56,10 +56,10 @@ impl KeycardSubcommand {
} }
}); });
Ok(SubcommandReturnValue::Empty) SubcommandReturnValue::Empty
} }
async fn handle_connect(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_connect(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
let pin = read_pin()?; let pin = read_pin()?;
Python::attach(|py| { Python::attach(|py| {
@ -80,7 +80,7 @@ impl KeycardSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_disconnect(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_disconnect(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
let pin = read_pin()?; let pin = read_pin()?;
Python::attach(|py| { Python::attach(|py| {
@ -105,7 +105,7 @@ impl KeycardSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_init(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_init(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
let pin = read_pin()?; let pin = read_pin()?;
Python::attach(|py| { Python::attach(|py| {
@ -128,7 +128,7 @@ impl KeycardSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
async fn handle_load(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> { fn handle_load(_wallet_core: &mut WalletCore) -> Result<SubcommandReturnValue> {
let pin = read_pin()?; let pin = read_pin()?;
let mnemonic = read_mnemonic()?; let mnemonic = read_mnemonic()?;
@ -156,8 +156,8 @@ impl KeycardSubcommand {
} }
#[cfg(feature = "keycard-debug")] #[cfg(feature = "keycard-debug")]
async fn handle_get_private_keys( fn handle_get_private_keys(
key_path: String, key_path: &str,
reveal: bool, reveal: bool,
_wallet_core: &mut WalletCore, _wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
@ -173,9 +173,8 @@ impl KeycardSubcommand {
Any terminal log, scrollback, or screen recording captures these keys." Any terminal log, scrollback, or screen recording captures these keys."
); );
let pin = read_pin()?; let pin = read_pin()?;
let (nsk, vsk) = let (nsk, vsk) = KeycardWallet::get_private_keys_for_path_with_connect(&pin, key_path)
KeycardWallet::get_private_keys_for_path_with_connect(&pin, &key_path) .map_err(anyhow::Error::from)?;
.map_err(anyhow::Error::from)?;
println!("NSK: {}", hex::encode(*nsk)); println!("NSK: {}", hex::encode(*nsk));
println!("VSK: {}", hex::encode(*vsk)); println!("VSK: {}", hex::encode(*vsk));
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
@ -188,14 +187,14 @@ impl WalletSubcommand for KeycardSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
Self::Available => Self::handle_available(wallet_core).await, Self::Available => Ok(Self::handle_available(wallet_core)),
Self::Connect => Self::handle_connect(wallet_core).await, Self::Connect => Self::handle_connect(wallet_core),
Self::Disconnect => Self::handle_disconnect(wallet_core).await, Self::Disconnect => Self::handle_disconnect(wallet_core),
Self::Init => Self::handle_init(wallet_core).await, Self::Init => Self::handle_init(wallet_core),
Self::Load => Self::handle_load(wallet_core).await, Self::Load => Self::handle_load(wallet_core),
#[cfg(feature = "keycard-debug")] #[cfg(feature = "keycard-debug")]
Self::GetPrivateKeys { key_path, reveal } => { Self::GetPrivateKeys { key_path, reveal } => {
Self::handle_get_private_keys(key_path, reveal, wallet_core).await Self::handle_get_private_keys(&key_path, reveal, wallet_core)
} }
} }
} }

View File

@ -125,7 +125,7 @@ impl AmmProgramAgnosticSubcommand {
user_holding_lp: CliAccountMention, user_holding_lp: CliAccountMention,
balance_a: u128, balance_a: u128,
balance_b: u128, balance_b: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let a_id = user_holding_a.resolve(wallet_core.storage())?; let a_id = user_holding_a.resolve(wallet_core.storage())?;
let b_id = user_holding_b.resolve(wallet_core.storage())?; let b_id = user_holding_b.resolve(wallet_core.storage())?;
@ -162,7 +162,7 @@ impl AmmProgramAgnosticSubcommand {
amount_in: u128, amount_in: u128,
min_amount_out: u128, min_amount_out: u128,
token_definition: AccountId, token_definition: AccountId,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let a_id = user_holding_a.resolve(wallet_core.storage())?; let a_id = user_holding_a.resolve(wallet_core.storage())?;
let b_id = user_holding_b.resolve(wallet_core.storage())?; let b_id = user_holding_b.resolve(wallet_core.storage())?;
@ -194,7 +194,7 @@ impl AmmProgramAgnosticSubcommand {
exact_amount_out: u128, exact_amount_out: u128,
max_amount_in: u128, max_amount_in: u128,
token_definition: AccountId, token_definition: AccountId,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let a_id = user_holding_a.resolve(wallet_core.storage())?; let a_id = user_holding_a.resolve(wallet_core.storage())?;
let b_id = user_holding_b.resolve(wallet_core.storage())?; let b_id = user_holding_b.resolve(wallet_core.storage())?;
@ -227,7 +227,7 @@ impl AmmProgramAgnosticSubcommand {
min_amount_lp: u128, min_amount_lp: u128,
max_amount_a: u128, max_amount_a: u128,
max_amount_b: u128, max_amount_b: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let a_id = user_holding_a.resolve(wallet_core.storage())?; let a_id = user_holding_a.resolve(wallet_core.storage())?;
let b_id = user_holding_b.resolve(wallet_core.storage())?; let b_id = user_holding_b.resolve(wallet_core.storage())?;
@ -266,7 +266,7 @@ impl AmmProgramAgnosticSubcommand {
balance_lp: u128, balance_lp: u128,
min_amount_a: u128, min_amount_a: u128,
min_amount_b: u128, min_amount_b: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let a_id = user_holding_a.resolve(wallet_core.storage())?; let a_id = user_holding_a.resolve(wallet_core.storage())?;
let b_id = user_holding_b.resolve(wallet_core.storage())?; let b_id = user_holding_b.resolve(wallet_core.storage())?;

View File

@ -69,18 +69,18 @@ pub enum AtaSubcommand {
} }
impl AtaSubcommand { impl AtaSubcommand {
async fn handle_address( fn handle_address(
owner: AccountId, owner: AccountId,
token_definition: AccountId, token_definition: AccountId,
_wallet_core: &mut WalletCore, _wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> SubcommandReturnValue {
let ata_program_id = programs::ata().id(); let ata_program_id = programs::ata().id();
let ata_id = associated_token_account_core::get_associated_token_account_id( let ata_id = associated_token_account_core::get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&associated_token_account_core::compute_ata_seed(owner, token_definition), &associated_token_account_core::compute_ata_seed(owner, token_definition),
); );
println!("{ata_id}"); println!("{ata_id}");
Ok(SubcommandReturnValue::Empty) SubcommandReturnValue::Empty
} }
async fn handle_create( async fn handle_create(
@ -106,9 +106,7 @@ impl AtaSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret, owner_id)])
Decode(secret, owner_id),
])
.await .await
} }
} }
@ -145,9 +143,7 @@ impl AtaSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret, from_id)])
Decode(secret, from_id),
])
.await .await
} }
} }
@ -181,9 +177,7 @@ impl AtaSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret, holder_id)])
Decode(secret, holder_id),
])
.await .await
} }
} }
@ -192,7 +186,7 @@ impl AtaSubcommand {
async fn handle_list( async fn handle_list(
owner: AccountId, owner: AccountId,
token_definition: Vec<AccountId>, token_definition: Vec<AccountId>,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let ata_program_id = programs::ata().id(); let ata_program_id = programs::ata().id();
@ -211,8 +205,7 @@ impl AtaSubcommand {
TokenHolding::Fungible { balance, .. } => { TokenHolding::Fungible { balance, .. } => {
println!("ATA {ata_id} (definition {def}): balance {balance}"); println!("ATA {ata_id} (definition {def}): balance {balance}");
} }
TokenHolding::NftMaster { .. } TokenHolding::NftMaster { .. } | TokenHolding::NftPrintedCopy { .. } => {
| TokenHolding::NftPrintedCopy { .. } => {
println!("ATA {ata_id} (definition {def}): unsupported token type"); println!("ATA {ata_id} (definition {def}): unsupported token type");
} }
} }
@ -232,7 +225,7 @@ impl WalletSubcommand for AtaSubcommand {
Self::Address { Self::Address {
owner, owner,
token_definition, token_definition,
} => Self::handle_address(owner, token_definition, wallet_core).await, } => Ok(Self::handle_address(owner, token_definition, wallet_core)),
Self::Create { Self::Create {
owner, owner,
token_definition, token_definition,

View File

@ -74,14 +74,16 @@ impl AuthTransferSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret, account_id)])
Decode(secret, account_id),
])
.await .await
} }
} }
} }
#[expect(
clippy::too_many_arguments,
reason = "extracted match arm with many destructured fields"
)]
async fn handle_send( async fn handle_send(
from_account: CliAccountMention, from_account: CliAccountMention,
to_account: Option<CliAccountMention>, to_account: Option<CliAccountMention>,
@ -107,9 +109,7 @@ impl AuthTransferSubcommand {
.transpose()?; .transpose()?;
let underlying_subcommand = match (to, to_npk, to_vpk) { let underlying_subcommand = match (to, to_npk, to_vpk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( anyhow::bail!("Provide either account account_id of receiver or their public keys");
"Provide either account account_id of receiver or their public keys"
);
} }
(Some(_), Some(_), Some(_)) => { (Some(_), Some(_), Some(_)) => {
anyhow::bail!( anyhow::bail!(
@ -128,16 +128,15 @@ impl AuthTransferSubcommand {
amount, amount,
} }
} }
( (AccountIdWithPrivacy::Private(from), AccountIdWithPrivacy::Private(to)) => {
AccountIdWithPrivacy::Private(from), NativeTokenTransferProgramSubcommand::Private(
AccountIdWithPrivacy::Private(to), NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
) => NativeTokenTransferProgramSubcommand::Private( from,
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { to,
from, amount,
to, },
amount, )
}, }
),
(AccountIdWithPrivacy::Private(from), AccountIdWithPrivacy::Public(to)) => { (AccountIdWithPrivacy::Private(from), AccountIdWithPrivacy::Public(to)) => {
NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount } NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount }
} }
@ -197,8 +196,17 @@ impl WalletSubcommand for AuthTransferSubcommand {
to_identifier, to_identifier,
amount, amount,
} => { } => {
Self::handle_send(from, to, to_npk, to_vpk, to_keys, to_identifier, amount, wallet_core) Self::handle_send(
.await from,
to,
to_npk,
to_vpk,
to_keys,
to_identifier,
amount,
wallet_core,
)
.await
} }
} }
} }
@ -332,10 +340,10 @@ impl NativeTokenTransferProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_from, from), tx_hash,
Decode(secret_to, to), &[Decode(secret_from, from), Decode(secret_to, to)],
]) )
.await .await
} }
@ -360,9 +368,7 @@ impl NativeTokenTransferProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret_from, from)])
Decode(secret_from, from),
])
.await .await
} }
} }
@ -383,8 +389,15 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
to_identifier, to_identifier,
amount, amount,
} => { } => {
Self::handle_private_foreign(from, to_npk, to_vpk, to_identifier, amount, wallet_core) Self::handle_private_foreign(
.await from,
to_npk,
to_vpk,
to_identifier,
amount,
wallet_core,
)
.await
} }
} }
} }
@ -398,17 +411,11 @@ impl NativeTokenTransferProgramSubcommandShielded {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let (tx_hash, secret) = NativeTokenTransfer(wallet_core) let (tx_hash, secret) = NativeTokenTransfer(wallet_core)
.send_shielded_transfer( .send_shielded_transfer(from.expect("from set during Send dispatch"), to, amount)
from.expect("from set during Send dispatch"),
to,
amount,
)
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret, to)])
Decode(secret, to),
])
.await .await
} }
@ -418,7 +425,7 @@ impl NativeTokenTransferProgramSubcommandShielded {
to_vpk: String, to_vpk: String,
to_identifier: Option<u128>, to_identifier: Option<u128>,
amount: u128, amount: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let (to_npk, to_vpk) = crate::cli::decode_npk_vpk(&to_npk, &to_vpk)?; let (to_npk, to_vpk) = crate::cli::decode_npk_vpk(&to_npk, &to_vpk)?;
@ -456,8 +463,15 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
to_identifier, to_identifier,
amount, amount,
} => { } => {
Self::handle_shielded_foreign(from, to_npk, to_vpk, to_identifier, amount, wallet_core) Self::handle_shielded_foreign(
.await from,
to_npk,
to_vpk,
to_identifier,
amount,
wallet_core,
)
.await
} }
} }
} }
@ -475,9 +489,7 @@ impl NativeTokenTransferProgramSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret, from)])
Decode(secret, from),
])
.await .await
} }
@ -485,7 +497,7 @@ impl NativeTokenTransferProgramSubcommand {
from: Option<AccountIdentity>, from: Option<AccountIdentity>,
to: Option<AccountIdentity>, to: Option<AccountIdentity>,
amount: u128, amount: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let tx_hash = NativeTokenTransfer(wallet_core) let tx_hash = NativeTokenTransfer(wallet_core)
.send_public_transfer( .send_public_transfer(

View File

@ -181,7 +181,9 @@ impl TokenProgramAgnosticSubcommand {
(AccountIdWithPrivacy::Public(_), AccountIdWithPrivacy::Public(_)) => { (AccountIdWithPrivacy::Public(_), AccountIdWithPrivacy::Public(_)) => {
TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::TransferToken { TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::TransferToken {
sender_account_id: from_mention, sender_account_id: from_mention,
recipient_account_id: to_mention.expect("`wallet::cli::programs::token::Send`: Invalid to_mention account provided"), recipient_account_id: to_mention.expect(
"`wallet::cli::programs::token::Send`: Invalid to_mention account provided",
),
balance_to_move: amount, balance_to_move: amount,
}) })
} }
@ -245,6 +247,10 @@ impl TokenProgramAgnosticSubcommand {
} }
} }
#[expect(
clippy::too_many_arguments,
reason = "extracted match arm with many destructured fields"
)]
async fn handle_send( async fn handle_send(
from: CliAccountMention, from: CliAccountMention,
to: Option<CliAccountMention>, to: Option<CliAccountMention>,
@ -270,9 +276,7 @@ impl TokenProgramAgnosticSubcommand {
.transpose()?; .transpose()?;
let underlying_subcommand = match (to, to_npk, to_vpk) { let underlying_subcommand = match (to, to_npk, to_vpk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( anyhow::bail!("Provide either account account_id of receiver or their public keys");
"Provide either account account_id of receiver or their public keys"
);
} }
(Some(_), Some(_), Some(_)) => { (Some(_), Some(_), Some(_)) => {
anyhow::bail!( anyhow::bail!(
@ -310,36 +314,33 @@ impl TokenProgramAgnosticSubcommand {
amount, amount,
}) })
} }
( (AccountIdWithPrivacy::Private(definition), AccountIdWithPrivacy::Private(holder)) => {
AccountIdWithPrivacy::Private(definition), TokenProgramSubcommand::Private(
AccountIdWithPrivacy::Private(holder), TokenProgramSubcommandPrivate::BurnTokenPrivateOwned {
) => TokenProgramSubcommand::Private( definition_account_id: definition,
TokenProgramSubcommandPrivate::BurnTokenPrivateOwned { holder_account_id: holder,
definition_account_id: definition, amount,
holder_account_id: holder, },
amount, )
}, }
), (AccountIdWithPrivacy::Private(definition), AccountIdWithPrivacy::Public(holder)) => {
( TokenProgramSubcommand::Deshielded(
AccountIdWithPrivacy::Private(definition), TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned {
AccountIdWithPrivacy::Public(holder), definition_account_id: definition,
) => TokenProgramSubcommand::Deshielded( holder_account_id: holder,
TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned { amount,
definition_account_id: definition, },
holder_account_id: holder, )
amount, }
}, (AccountIdWithPrivacy::Public(definition), AccountIdWithPrivacy::Private(holder)) => {
), TokenProgramSubcommand::Shielded(
( TokenProgramSubcommandShielded::BurnTokenShielded {
AccountIdWithPrivacy::Public(definition), definition_account_id: definition,
AccountIdWithPrivacy::Private(holder), holder_account_id: holder,
) => TokenProgramSubcommand::Shielded( amount,
TokenProgramSubcommandShielded::BurnTokenShielded { },
definition_account_id: definition, )
holder_account_id: holder, }
amount,
},
),
}; };
underlying_subcommand.handle_subcommand(wallet_core).await underlying_subcommand.handle_subcommand(wallet_core).await
@ -390,7 +391,7 @@ impl TokenProgramAgnosticSubcommand {
} }
} }
fn route_mint_foreign( const fn route_mint_foreign(
definition: AccountIdWithPrivacy, definition: AccountIdWithPrivacy,
holder_npk: String, holder_npk: String,
holder_vpk: String, holder_vpk: String,
@ -419,6 +420,10 @@ impl TokenProgramAgnosticSubcommand {
} }
} }
#[expect(
clippy::too_many_arguments,
reason = "extracted match arm with many destructured fields"
)]
async fn handle_mint( async fn handle_mint(
definition: CliAccountMention, definition: CliAccountMention,
holder: Option<CliAccountMention>, holder: Option<CliAccountMention>,
@ -444,9 +449,7 @@ impl TokenProgramAgnosticSubcommand {
.transpose()?; .transpose()?;
let underlying_subcommand = match (holder, holder_npk, holder_vpk) { let underlying_subcommand = match (holder, holder_npk, holder_vpk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( anyhow::bail!("Provide either account account_id of holder or their public keys");
"Provide either account account_id of holder or their public keys"
);
} }
(Some(_), Some(_), Some(_)) => { (Some(_), Some(_), Some(_)) => {
anyhow::bail!( anyhow::bail!(
@ -459,9 +462,13 @@ impl TokenProgramAgnosticSubcommand {
(Some(holder), None, None) => { (Some(holder), None, None) => {
Self::route_mint_owned(definition, holder, def_mention, holder_mention, amount) Self::route_mint_owned(definition, holder, def_mention, holder_mention, amount)
} }
(None, Some(holder_npk), Some(holder_vpk)) => { (None, Some(holder_npk), Some(holder_vpk)) => Self::route_mint_foreign(
Self::route_mint_foreign(definition, holder_npk, holder_vpk, holder_identifier, amount) definition,
} holder_npk,
holder_vpk,
holder_identifier,
amount,
),
}; };
underlying_subcommand.handle_subcommand(wallet_core).await underlying_subcommand.handle_subcommand(wallet_core).await
@ -499,7 +506,14 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
amount, amount,
} => { } => {
Self::handle_send( Self::handle_send(
from, to, to_npk, to_vpk, to_keys, to_identifier, amount, wallet_core, from,
to,
to_npk,
to_vpk,
to_keys,
to_identifier,
amount,
wallet_core,
) )
.await .await
} }
@ -803,14 +817,12 @@ impl TokenProgramSubcommandPublic {
sender_account_id: CliAccountMention, sender_account_id: CliAccountMention,
recipient_account_id: CliAccountMention, recipient_account_id: CliAccountMention,
balance_to_move: u128, balance_to_move: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let sender = sender_account_id.resolve(wallet_core.storage())?; let sender = sender_account_id.resolve(wallet_core.storage())?;
let recipient = recipient_account_id.resolve(wallet_core.storage())?; let recipient = recipient_account_id.resolve(wallet_core.storage())?;
let ( let (AccountIdWithPrivacy::Public(sender_id), AccountIdWithPrivacy::Public(recipient_id)) =
AccountIdWithPrivacy::Public(sender_id), (sender, recipient)
AccountIdWithPrivacy::Public(recipient_id),
) = (sender, recipient)
else { else {
anyhow::bail!( anyhow::bail!(
"`TokenProgramSubcommandPublic::TransferToken`: Unexpected private account received." "`TokenProgramSubcommandPublic::TransferToken`: Unexpected private account received."
@ -832,7 +844,7 @@ impl TokenProgramSubcommandPublic {
definition_account_id: AccountId, definition_account_id: AccountId,
holder_account_id: CliAccountMention, holder_account_id: CliAccountMention,
amount: u128, amount: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let holder = holder_account_id.resolve(wallet_core.storage())?; let holder = holder_account_id.resolve(wallet_core.storage())?;
let AccountIdWithPrivacy::Public(holder_id) = holder else { let AccountIdWithPrivacy::Public(holder_id) = holder else {
@ -856,7 +868,7 @@ impl TokenProgramSubcommandPublic {
definition_account_id: CliAccountMention, definition_account_id: CliAccountMention,
holder_account_id: CliAccountMention, holder_account_id: CliAccountMention,
amount: u128, amount: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let definition = definition_account_id.resolve(wallet_core.storage())?; let definition = definition_account_id.resolve(wallet_core.storage())?;
let holder = holder_account_id.resolve(wallet_core.storage())?; let holder = holder_account_id.resolve(wallet_core.storage())?;
@ -904,16 +916,26 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
holder_account_id, holder_account_id,
amount, amount,
} => { } => {
Self::handle_burn_token(definition_account_id, holder_account_id, amount, wallet_core) Self::handle_burn_token(
.await definition_account_id,
holder_account_id,
amount,
wallet_core,
)
.await
} }
Self::MintToken { Self::MintToken {
definition_account_id, definition_account_id,
holder_account_id, holder_account_id,
amount, amount,
} => { } => {
Self::handle_mint_token(definition_account_id, holder_account_id, amount, wallet_core) Self::handle_mint_token(
.await definition_account_id,
holder_account_id,
amount,
wallet_core,
)
.await
} }
} }
} }
@ -935,10 +957,13 @@ impl TokenProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_sender, sender_account_id), tx_hash,
Decode(secret_recipient, recipient_account_id), &[
]) Decode(secret_sender, sender_account_id),
Decode(secret_recipient, recipient_account_id),
],
)
.await .await
} }
@ -964,9 +989,7 @@ impl TokenProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret_sender, sender_account_id)])
Decode(secret_sender, sender_account_id),
])
.await .await
} }
@ -985,10 +1008,13 @@ impl TokenProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
Decode(secret_holder, holder_account_id), &[
]) Decode(secret_definition, definition_account_id),
Decode(secret_holder, holder_account_id),
],
)
.await .await
} }
@ -1007,10 +1033,13 @@ impl TokenProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
Decode(secret_holder, holder_account_id), &[
]) Decode(secret_definition, definition_account_id),
Decode(secret_holder, holder_account_id),
],
)
.await .await
} }
@ -1022,8 +1051,7 @@ impl TokenProgramSubcommandPrivate {
amount: u128, amount: u128,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let (holder_npk, holder_vpk) = let (holder_npk, holder_vpk) = crate::cli::decode_npk_vpk(&holder_npk, &holder_vpk)?;
crate::cli::decode_npk_vpk(&holder_npk, &holder_vpk)?;
let (tx_hash, [secret_definition, _]) = Token(wallet_core) let (tx_hash, [secret_definition, _]) = Token(wallet_core)
.send_mint_transaction_private_foreign_account( .send_mint_transaction_private_foreign_account(
@ -1036,9 +1064,10 @@ impl TokenProgramSubcommandPrivate {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
]) &[Decode(secret_definition, definition_account_id)],
)
.await .await
} }
} }
@ -1142,9 +1171,7 @@ impl TokenProgramSubcommandDeshielded {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret_sender, sender_account_id)])
Decode(secret_sender, sender_account_id),
])
.await .await
} }
@ -1163,9 +1190,10 @@ impl TokenProgramSubcommandDeshielded {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
]) &[Decode(secret_definition, definition_account_id)],
)
.await .await
} }
@ -1176,17 +1204,14 @@ impl TokenProgramSubcommandDeshielded {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let (tx_hash, secret_definition) = Token(wallet_core) let (tx_hash, secret_definition) = Token(wallet_core)
.send_mint_transaction_deshielded( .send_mint_transaction_deshielded(definition_account_id, holder_account_id, amount)
definition_account_id,
holder_account_id,
amount,
)
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
]) &[Decode(secret_definition, definition_account_id)],
)
.await .await
} }
} }
@ -1282,9 +1307,10 @@ impl TokenProgramSubcommandShielded {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_recipient, recipient_account_id), tx_hash,
]) &[Decode(secret_recipient, recipient_account_id)],
)
.await .await
} }
@ -1295,17 +1321,11 @@ impl TokenProgramSubcommandShielded {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let (tx_hash, secret_holder) = Token(wallet_core) let (tx_hash, secret_holder) = Token(wallet_core)
.send_burn_transaction_shielded( .send_burn_transaction_shielded(definition_account_id, holder_account_id, amount)
definition_account_id,
holder_account_id,
amount,
)
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret_holder, holder_account_id)])
Decode(secret_holder, holder_account_id),
])
.await .await
} }
@ -1324,9 +1344,7 @@ impl TokenProgramSubcommandShielded {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret_holder, holder_account_id)])
Decode(secret_holder, holder_account_id),
])
.await .await
} }
@ -1338,8 +1356,7 @@ impl TokenProgramSubcommandShielded {
amount: u128, amount: u128,
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let (holder_npk, holder_vpk) = let (holder_npk, holder_vpk) = crate::cli::decode_npk_vpk(&holder_npk, &holder_vpk)?;
crate::cli::decode_npk_vpk(&holder_npk, &holder_vpk)?;
let (tx_hash, _) = Token(wallet_core) let (tx_hash, _) = Token(wallet_core)
.send_mint_transaction_shielded_foreign_account( .send_mint_transaction_shielded_foreign_account(
@ -1458,10 +1475,13 @@ impl CreateNewTokenProgramSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
Decode(secret_supply, supply_account_id), &[
]) Decode(secret_definition, definition_account_id),
Decode(secret_supply, supply_account_id),
],
)
.await .await
} }
@ -1482,9 +1502,10 @@ impl CreateNewTokenProgramSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(
Decode(secret_definition, definition_account_id), tx_hash,
]) &[Decode(secret_definition, definition_account_id)],
)
.await .await
} }
@ -1505,9 +1526,7 @@ impl CreateNewTokenProgramSubcommand {
.await?; .await?;
wallet_core wallet_core
.poll_and_finalize_pp_transaction(tx_hash, &[ .poll_and_finalize_pp_transaction(tx_hash, &[Decode(secret_supply, supply_account_id)])
Decode(secret_supply, supply_account_id),
])
.await .await
} }
@ -1516,7 +1535,7 @@ impl CreateNewTokenProgramSubcommand {
supply_account_id: CliAccountMention, supply_account_id: CliAccountMention,
name: String, name: String,
total_supply: u128, total_supply: u128,
wallet_core: &mut WalletCore, wallet_core: &WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let definition = definition_account_id.resolve(wallet_core.storage())?; let definition = definition_account_id.resolve(wallet_core.storage())?;
let supply = supply_account_id.resolve(wallet_core.storage())?; let supply = supply_account_id.resolve(wallet_core.storage())?;

View File

@ -545,7 +545,7 @@ impl WalletCore {
} }
pub(crate) async fn poll_and_finalize_public_transaction( pub(crate) async fn poll_and_finalize_public_transaction(
&mut self, &self,
tx_hash: HashType, tx_hash: HashType,
) -> Result<cli::SubcommandReturnValue> { ) -> Result<cli::SubcommandReturnValue> {
println!("Transaction hash is {tx_hash}"); println!("Transaction hash is {tx_hash}");