1372 lines
53 KiB
Rust
Raw Normal View History

2026-05-29 19:54:53 -04:00
use anyhow::{Context as _, Result};
2025-10-13 17:25:36 +03:00
use clap::Subcommand;
use common::transaction::NSSATransaction;
use nssa::AccountId;
2025-10-13 17:25:36 +03:00
2025-10-27 14:32:28 +02:00
use crate::{
2025-12-12 13:40:56 +02:00
AccDecodeData::Decode,
WalletCore,
account::AccountIdWithPrivacy,
cli::{CliAccountMention, SubcommandReturnValue, WalletSubcommand},
program_facades::token::Token,
2025-10-27 14:32:28 +02:00
};
2026-03-10 00:17:43 +03:00
/// Represents generic CLI subcommand for a wallet working with token program.
2025-10-27 14:32:28 +02:00
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramAgnosticSubcommand {
2026-03-10 00:17:43 +03:00
/// Produce a new token.
2025-10-27 14:32:28 +02:00
New {
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
definition_account_id: CliAccountMention,
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
supply_account_id: CliAccountMention,
2025-10-27 14:32:28 +02:00
#[arg(short, long)]
name: String,
#[arg(short, long)]
total_supply: u128,
},
2026-03-10 00:17:43 +03:00
/// Send tokens from one account to another with variable privacy.
2025-10-29 12:02:41 +02:00
///
2026-01-21 17:58:45 -05:00
/// If receiver is private, then `to` and (`to_npk` , `to_vpk`) is a mutually exclusive
2025-11-26 00:27:20 +03:00
/// patterns.
2025-10-29 12:02:41 +02:00
///
2025-11-26 00:27:20 +03:00
/// First is used for owned accounts, second otherwise.
2025-10-27 14:32:28 +02:00
Send {
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
from: CliAccountMention,
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
to: Option<CliAccountMention>,
2026-03-10 00:17:43 +03:00
/// `to_npk` - valid 32 byte hex string.
2026-05-29 19:54:53 -04:00
#[arg(long, conflicts_with = "to_keys")]
2025-10-27 14:32:28 +02:00
to_npk: Option<String>,
2026-05-29 19:54:53 -04:00
/// `to_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes).
#[arg(long, conflicts_with = "to_keys")]
2026-01-21 17:58:45 -05:00
to_vpk: Option<String>,
2026-05-29 19:54:53 -04:00
/// Path to a keys file exported by `wallet account show-keys`, containing npk
/// and vpk on separate lines. Replaces `--to-npk` and `--to-vpk`.
#[arg(long, conflicts_with_all = ["to_npk", "to_vpk"])]
to_keys: Option<String>,
/// Identifier for the recipient's private account (only used when sending to a foreign
2026-05-29 19:54:53 -04:00
/// private account via `--to-npk`/`--to-vpk` or `--to-keys`).
#[arg(long)]
to_identifier: Option<u128>,
2026-03-10 00:17:43 +03:00
/// amount - amount of balance to move.
2025-10-27 14:32:28 +02:00
#[arg(long)]
amount: u128,
},
2025-12-11 14:46:16 +02:00
/// Burn tokens on `holder`, modify `definition`.
///
2026-03-10 00:17:43 +03:00
/// `holder` is owned.
2025-12-11 14:46:16 +02:00
///
2025-12-12 13:40:56 +02:00
/// Also if `definition` is private then it is owned, because
/// we can not modify foreign accounts.
2025-12-11 14:46:16 +02:00
Burn {
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
definition: CliAccountMention,
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
holder: CliAccountMention,
2026-03-10 00:17:43 +03:00
/// amount - amount of balance to burn.
2025-12-11 14:46:16 +02:00
#[arg(long)]
amount: u128,
},
/// Mint tokens on `holder`, modify `definition`.
///
2026-03-10 00:17:43 +03:00
/// `definition` is owned.
2025-12-11 14:46:16 +02:00
///
2026-01-21 17:58:45 -05:00
/// If `holder` is private, then `holder` and (`holder_npk` , `holder_vpk`) is a mutually
2025-12-11 14:46:16 +02:00
/// exclusive patterns.
///
/// First is used for owned accounts, second otherwise.
Mint {
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
definition: CliAccountMention,
/// Either 32 byte base58 account id string with privacy prefix or a label.
#[arg(long)]
holder: Option<CliAccountMention>,
2026-03-10 00:17:43 +03:00
/// `holder_npk` - valid 32 byte hex string.
2026-05-29 19:54:53 -04:00
#[arg(long, conflicts_with = "holder_keys")]
2025-12-11 14:46:16 +02:00
holder_npk: Option<String>,
2026-05-29 19:54:53 -04:00
/// `holder_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes).
#[arg(long, conflicts_with = "holder_keys")]
2026-01-21 17:58:45 -05:00
holder_vpk: Option<String>,
2026-05-29 19:54:53 -04:00
/// Path to a keys file exported by `wallet account show-keys`, containing npk
/// and vpk on separate lines. Replaces `--holder-npk` and `--holder-vpk`.
#[arg(long, conflicts_with_all = ["holder_npk", "holder_vpk"])]
holder_keys: Option<String>,
/// Identifier for the holder's private account (only used when minting to a foreign
2026-05-29 19:54:53 -04:00
/// private account via `--holder-npk`/`--holder-vpk` or `--holder-keys`).
#[arg(long)]
holder_identifier: Option<u128>,
2026-03-10 00:17:43 +03:00
/// amount - amount of balance to mint.
2025-12-11 14:46:16 +02:00
#[arg(long)]
amount: u128,
},
2025-10-27 14:32:28 +02:00
}
impl WalletSubcommand for TokenProgramAgnosticSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::New {
definition_account_id,
supply_account_id,
2025-10-27 14:32:28 +02:00
name,
total_supply,
} => {
let definition_account_id = definition_account_id.resolve(wallet_core.storage())?;
let supply_account_id = supply_account_id.resolve(wallet_core.storage())?;
let underlying_subcommand = match (definition_account_id, supply_account_id) {
(
AccountIdWithPrivacy::Public(definition_account_id),
AccountIdWithPrivacy::Public(supply_account_id),
) => TokenProgramSubcommand::Create(
CreateNewTokenProgramSubcommand::NewPublicDefPublicSupp {
definition_account_id,
supply_account_id,
name,
total_supply,
},
),
(
AccountIdWithPrivacy::Public(definition_account_id),
AccountIdWithPrivacy::Private(supply_account_id),
) => TokenProgramSubcommand::Create(
CreateNewTokenProgramSubcommand::NewPublicDefPrivateSupp {
definition_account_id,
supply_account_id,
name,
total_supply,
},
),
(
AccountIdWithPrivacy::Private(definition_account_id),
AccountIdWithPrivacy::Private(supply_account_id),
) => TokenProgramSubcommand::Create(
CreateNewTokenProgramSubcommand::NewPrivateDefPrivateSupp {
definition_account_id,
supply_account_id,
name,
total_supply,
},
),
(
AccountIdWithPrivacy::Private(definition_account_id),
AccountIdWithPrivacy::Public(supply_account_id),
) => TokenProgramSubcommand::Create(
CreateNewTokenProgramSubcommand::NewPrivateDefPublicSupp {
definition_account_id,
supply_account_id,
name,
total_supply,
},
),
2025-10-27 14:32:28 +02:00
};
underlying_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Send {
2025-10-27 14:32:28 +02:00
from,
to,
to_npk,
2026-01-21 17:58:45 -05:00
to_vpk,
2026-05-29 19:54:53 -04:00
to_keys,
to_identifier,
2025-10-27 14:32:28 +02:00
amount,
} => {
2026-05-29 19:54:53 -04:00
let (to_npk, to_vpk) = if let Some(path) = to_keys {
let (npk_bytes, vpk_bytes) = crate::cli::read_keys_file(&path)?;
(Some(hex::encode(npk_bytes)), Some(hex::encode(vpk_bytes)))
} else {
(to_npk, to_vpk)
};
let from = from.resolve(wallet_core.storage())?;
let to = to
.map(|account_mention| account_mention.resolve(wallet_core.storage()))
.transpose()?;
2026-01-21 17:58:45 -05:00
let underlying_subcommand = match (to, to_npk, to_vpk) {
2025-10-27 14:32:28 +02:00
(None, None, None) => {
anyhow::bail!(
"Provide either account account_id of receiver or their public keys"
2025-10-27 14:32:28 +02:00
);
}
(Some(_), Some(_), Some(_)) => {
anyhow::bail!(
"Provide only one variant: either account account_id of receiver or their public keys"
2025-10-27 14:32:28 +02:00
);
}
(_, Some(_), None) | (_, None, Some(_)) => {
anyhow::bail!("List of public keys is uncomplete");
}
(Some(to), None, None) => match (from, to) {
(AccountIdWithPrivacy::Public(from), AccountIdWithPrivacy::Public(to)) => {
TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::TransferToken {
sender_account_id: from,
recipient_account_id: to,
balance_to_move: amount,
},
)
2025-10-27 14:32:28 +02:00
}
(
AccountIdWithPrivacy::Private(from),
AccountIdWithPrivacy::Private(to),
) => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_account_id: from,
recipient_account_id: to,
balance_to_move: amount,
},
),
(AccountIdWithPrivacy::Private(from), AccountIdWithPrivacy::Public(to)) => {
TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_account_id: from,
recipient_account_id: to,
2025-10-27 14:32:28 +02:00
balance_to_move: amount,
},
)
}
(AccountIdWithPrivacy::Public(from), AccountIdWithPrivacy::Private(to)) => {
TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_account_id: from,
recipient_account_id: to,
2025-10-27 14:32:28 +02:00
balance_to_move: amount,
},
)
2025-10-27 14:32:28 +02:00
}
},
(None, Some(to_npk), Some(to_vpk)) => match from {
AccountIdWithPrivacy::Private(from) => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_account_id: from,
recipient_npk: to_npk,
recipient_vpk: to_vpk,
recipient_identifier: to_identifier,
balance_to_move: amount,
},
),
AccountIdWithPrivacy::Public(from) => TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_account_id: from,
recipient_npk: to_npk,
recipient_vpk: to_vpk,
recipient_identifier: to_identifier,
balance_to_move: amount,
},
),
},
2025-10-27 14:32:28 +02:00
};
2025-12-11 14:46:16 +02:00
underlying_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Burn {
2025-12-11 14:46:16 +02:00
definition,
holder,
amount,
} => {
let definition = definition.resolve(wallet_core.storage())?;
let holder = holder.resolve(wallet_core.storage())?;
let underlying_subcommand = match (definition, holder) {
(
AccountIdWithPrivacy::Public(definition),
AccountIdWithPrivacy::Public(holder),
) => TokenProgramSubcommand::Public(TokenProgramSubcommandPublic::BurnToken {
definition_account_id: definition,
holder_account_id: holder,
amount,
}),
(
AccountIdWithPrivacy::Private(definition),
AccountIdWithPrivacy::Private(holder),
) => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::BurnTokenPrivateOwned {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
(
AccountIdWithPrivacy::Private(definition),
AccountIdWithPrivacy::Public(holder),
) => TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
(
AccountIdWithPrivacy::Public(definition),
AccountIdWithPrivacy::Private(holder),
) => TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::BurnTokenShielded {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
2025-12-11 14:46:16 +02:00
};
underlying_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Mint {
2025-12-11 14:46:16 +02:00
definition,
holder,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
2026-05-29 19:54:53 -04:00
holder_keys,
holder_identifier,
2025-12-11 14:46:16 +02:00
amount,
} => {
2026-05-29 19:54:53 -04:00
let (holder_npk, holder_vpk) = if let Some(path) = holder_keys {
let (npk_bytes, vpk_bytes) = crate::cli::read_keys_file(&path)?;
(Some(hex::encode(npk_bytes)), Some(hex::encode(vpk_bytes)))
} else {
(holder_npk, holder_vpk)
};
let definition = definition.resolve(wallet_core.storage())?;
let holder = holder
.map(|account_mention| account_mention.resolve(wallet_core.storage()))
.transpose()?;
2026-01-21 17:58:45 -05:00
let underlying_subcommand = match (holder, holder_npk, holder_vpk) {
2025-12-11 14:46:16 +02:00
(None, None, None) => {
anyhow::bail!(
"Provide either account account_id of holder or their public keys"
);
}
(Some(_), Some(_), Some(_)) => {
anyhow::bail!(
"Provide only one variant: either account_id of holder or their public keys"
);
}
(_, Some(_), None) | (_, None, Some(_)) => {
anyhow::bail!("List of public keys is uncomplete");
}
(Some(holder), None, None) => match (definition, holder) {
(
AccountIdWithPrivacy::Public(definition),
AccountIdWithPrivacy::Public(holder),
) => TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::MintToken {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
(
AccountIdWithPrivacy::Private(definition),
AccountIdWithPrivacy::Private(holder),
) => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::MintTokenPrivateOwned {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
(
AccountIdWithPrivacy::Private(definition),
AccountIdWithPrivacy::Public(holder),
) => TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::MintTokenDeshielded {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
(
AccountIdWithPrivacy::Public(definition),
AccountIdWithPrivacy::Private(holder),
) => TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::MintTokenShieldedOwned {
definition_account_id: definition,
holder_account_id: holder,
amount,
},
),
},
(None, Some(holder_npk), Some(holder_vpk)) => match definition {
AccountIdWithPrivacy::Private(definition) => {
TokenProgramSubcommand::Private(
2025-12-11 14:46:16 +02:00
TokenProgramSubcommandPrivate::MintTokenPrivateForeign {
definition_account_id: definition,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
holder_identifier,
2025-12-11 14:46:16 +02:00
amount,
},
)
}
AccountIdWithPrivacy::Public(definition) => {
TokenProgramSubcommand::Shielded(
2025-12-11 14:46:16 +02:00
TokenProgramSubcommandShielded::MintTokenShieldedForeign {
definition_account_id: definition,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
holder_identifier,
2025-12-11 14:46:16 +02:00
amount,
},
)
2025-12-11 14:46:16 +02:00
}
},
2025-12-11 14:46:16 +02:00
};
2025-10-27 14:32:28 +02:00
underlying_subcommand.handle_subcommand(wallet_core).await
}
}
}
}
2025-10-13 17:25:36 +03:00
2026-03-10 00:17:43 +03:00
/// Represents generic CLI subcommand for a wallet working with `token_program`.
2025-10-13 17:25:36 +03:00
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommand {
2026-03-10 00:17:43 +03:00
/// Creation of new token.
2025-12-02 15:27:20 +02:00
#[command(subcommand)]
Create(CreateNewTokenProgramSubcommand),
2026-03-10 00:17:43 +03:00
/// Public execution.
2025-10-14 10:18:54 +03:00
#[command(subcommand)]
Public(TokenProgramSubcommandPublic),
2026-03-10 00:17:43 +03:00
/// Private execution.
2025-10-14 10:18:54 +03:00
#[command(subcommand)]
Private(TokenProgramSubcommandPrivate),
2026-03-10 00:17:43 +03:00
/// Deshielded execution.
2025-10-20 09:10:54 +03:00
#[command(subcommand)]
Deshielded(TokenProgramSubcommandDeshielded),
2026-03-10 00:17:43 +03:00
/// Shielded execution.
2025-10-20 09:10:54 +03:00
#[command(subcommand)]
Shielded(TokenProgramSubcommandShielded),
2025-10-14 10:18:54 +03:00
}
2026-03-10 00:17:43 +03:00
/// Represents generic public CLI subcommand for a wallet working with `token_program`.
2025-10-14 10:18:54 +03:00
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandPublic {
2025-11-26 00:27:20 +03:00
// Transfer tokens using the token program
2025-10-13 17:25:36 +03:00
TransferToken {
#[arg(short, long)]
sender_account_id: AccountId,
2025-10-13 17:25:36 +03:00
#[arg(short, long)]
recipient_account_id: AccountId,
2025-10-13 17:25:36 +03:00
#[arg(short, long)]
balance_to_move: u128,
},
2025-12-11 14:46:16 +02:00
// Burn tokens using the token program
BurnToken {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
// Transfer tokens using the token program
MintToken {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
2025-10-14 10:18:54 +03:00
}
2026-03-10 00:17:43 +03:00
/// Represents generic private CLI subcommand for a wallet working with `token_program`.
2025-10-14 10:18:54 +03:00
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandPrivate {
2025-11-26 00:27:20 +03:00
// Transfer tokens using the token program
2025-10-14 10:18:54 +03:00
TransferTokenPrivateOwned {
2025-10-13 17:25:36 +03:00
#[arg(short, long)]
sender_account_id: AccountId,
2025-10-13 17:25:36 +03:00
#[arg(short, long)]
recipient_account_id: AccountId,
2025-10-13 17:25:36 +03:00
#[arg(short, long)]
balance_to_move: u128,
},
2025-11-26 00:27:20 +03:00
// Transfer tokens using the token program
2025-10-13 17:25:36 +03:00
TransferTokenPrivateForeign {
#[arg(short, long)]
sender_account_id: AccountId,
2026-03-10 00:17:43 +03:00
/// `recipient_npk` - valid 32 byte hex string.
2025-10-13 17:25:36 +03:00
#[arg(long)]
recipient_npk: String,
2026-05-29 19:54:53 -04:00
/// `recipient_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes).
2025-10-13 17:25:36 +03:00
#[arg(long)]
2026-01-21 17:58:45 -05:00
recipient_vpk: String,
/// Identifier for the recipient's private account.
#[arg(long)]
recipient_identifier: Option<u128>,
2025-10-13 17:25:36 +03:00
#[arg(short, long)]
balance_to_move: u128,
},
2025-12-11 14:46:16 +02:00
// Burn tokens using the token program
BurnTokenPrivateOwned {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
// Transfer tokens using the token program
MintTokenPrivateOwned {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
// Transfer tokens using the token program
MintTokenPrivateForeign {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_npk: String,
#[arg(short, long)]
2026-01-21 17:58:45 -05:00
holder_vpk: String,
/// Identifier for the holder's private account.
#[arg(long)]
holder_identifier: Option<u128>,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
2025-10-13 17:25:36 +03:00
}
2026-03-10 00:17:43 +03:00
/// Represents deshielded public CLI subcommand for a wallet working with `token_program`.
2025-10-20 09:10:54 +03:00
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandDeshielded {
2025-11-26 00:27:20 +03:00
// Transfer tokens using the token program
2025-10-20 09:10:54 +03:00
TransferTokenDeshielded {
#[arg(short, long)]
sender_account_id: AccountId,
2025-10-20 09:10:54 +03:00
#[arg(short, long)]
recipient_account_id: AccountId,
2025-10-20 09:10:54 +03:00
#[arg(short, long)]
balance_to_move: u128,
},
2025-12-11 14:46:16 +02:00
// Burn tokens using the token program
BurnTokenDeshieldedOwned {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
// Transfer tokens using the token program
MintTokenDeshielded {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
2025-10-20 09:10:54 +03:00
}
2026-03-10 00:17:43 +03:00
/// Represents generic shielded CLI subcommand for a wallet working with `token_program`.
2025-10-20 09:10:54 +03:00
#[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandShielded {
2025-11-26 00:27:20 +03:00
// Transfer tokens using the token program
2025-10-20 09:10:54 +03:00
TransferTokenShieldedOwned {
#[arg(short, long)]
sender_account_id: AccountId,
2025-10-20 09:10:54 +03:00
#[arg(short, long)]
recipient_account_id: AccountId,
2025-10-20 09:10:54 +03:00
#[arg(short, long)]
balance_to_move: u128,
},
2025-11-26 00:27:20 +03:00
// Transfer tokens using the token program
2025-10-20 09:10:54 +03:00
TransferTokenShieldedForeign {
#[arg(short, long)]
sender_account_id: AccountId,
2026-03-10 00:17:43 +03:00
/// `recipient_npk` - valid 32 byte hex string.
2025-10-20 09:10:54 +03:00
#[arg(long)]
recipient_npk: String,
2026-05-29 19:54:53 -04:00
/// `recipient_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes).
2025-10-20 09:10:54 +03:00
#[arg(long)]
2026-01-21 17:58:45 -05:00
recipient_vpk: String,
/// Identifier for the recipient's private account.
#[arg(long)]
recipient_identifier: Option<u128>,
2025-10-20 09:10:54 +03:00
#[arg(short, long)]
balance_to_move: u128,
},
2025-12-11 14:46:16 +02:00
// Burn tokens using the token program
BurnTokenShielded {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
// Transfer tokens using the token program
MintTokenShieldedOwned {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
// Transfer tokens using the token program
MintTokenShieldedForeign {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
holder_npk: String,
#[arg(short, long)]
2026-01-21 17:58:45 -05:00
holder_vpk: String,
/// Identifier for the holder's private account.
#[arg(long)]
holder_identifier: Option<u128>,
2025-12-11 14:46:16 +02:00
#[arg(short, long)]
amount: u128,
},
2025-10-20 09:10:54 +03:00
}
2026-03-10 00:17:43 +03:00
/// Represents generic initialization subcommand for a wallet working with `token_program`.
2025-12-02 15:27:20 +02:00
#[derive(Subcommand, Debug, Clone)]
pub enum CreateNewTokenProgramSubcommand {
2026-03-10 00:17:43 +03:00
/// Create a new token using the token program.
2025-12-02 15:27:20 +02:00
///
2026-03-10 00:17:43 +03:00
/// Definition - public, supply - public.
2025-12-02 15:27:20 +02:00
NewPublicDefPublicSupp {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
supply_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
name: String,
#[arg(short, long)]
total_supply: u128,
},
2026-03-10 00:17:43 +03:00
/// Create a new token using the token program.
2025-12-02 15:27:20 +02:00
///
2026-03-10 00:17:43 +03:00
/// Definition - public, supply - private.
2025-12-02 15:27:20 +02:00
NewPublicDefPrivateSupp {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
supply_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
name: String,
#[arg(short, long)]
total_supply: u128,
},
2026-03-10 00:17:43 +03:00
/// Create a new token using the token program.
2025-12-02 15:27:20 +02:00
///
2026-03-10 00:17:43 +03:00
/// Definition - private, supply - public.
2025-12-02 15:27:20 +02:00
NewPrivateDefPublicSupp {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
supply_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
name: String,
#[arg(short, long)]
total_supply: u128,
},
2026-03-10 00:17:43 +03:00
/// Create a new token using the token program.
2025-12-02 15:27:20 +02:00
///
2026-03-10 00:17:43 +03:00
/// Definition - private, supply - private.
2025-12-02 15:27:20 +02:00
NewPrivateDefPrivateSupp {
#[arg(short, long)]
definition_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
supply_account_id: AccountId,
2025-12-02 15:27:20 +02:00
#[arg(short, long)]
name: String,
#[arg(short, long)]
total_supply: u128,
},
}
2025-10-14 10:18:54 +03:00
impl WalletSubcommand for TokenProgramSubcommandPublic {
2025-10-13 17:25:36 +03:00
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::TransferToken {
sender_account_id,
recipient_account_id,
2025-10-14 10:18:54 +03:00
balance_to_move,
} => {
Token(wallet_core)
.send_transfer_transaction(
sender_account_id,
recipient_account_id,
2025-10-14 10:18:54 +03:00
balance_to_move,
)
.await?;
Ok(SubcommandReturnValue::Empty)
}
2026-03-09 18:27:56 +03:00
Self::BurnToken {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
Token(wallet_core)
.send_burn_transaction(definition_account_id, holder_account_id, amount)
2025-12-11 14:46:16 +02:00
.await?;
Ok(SubcommandReturnValue::Empty)
}
2026-03-09 18:27:56 +03:00
Self::MintToken {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
Token(wallet_core)
.send_mint_transaction(definition_account_id, holder_account_id, amount)
2025-12-11 14:46:16 +02:00
.await?;
Ok(SubcommandReturnValue::Empty)
}
2025-10-14 10:18:54 +03:00
}
}
}
impl WalletSubcommand for TokenProgramSubcommandPrivate {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::TransferTokenPrivateOwned {
sender_account_id,
recipient_account_id,
2025-10-13 17:25:36 +03:00
balance_to_move,
} => {
let (tx_hash, [secret_sender, secret_recipient]) = Token(wallet_core)
.send_transfer_transaction_private_owned_account(
sender_account_id,
recipient_account_id,
balance_to_move,
)
2025-10-15 15:29:28 +03:00
.await?;
2025-10-13 17:25:36 +03:00
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-10-13 17:25:36 +03:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-10-13 17:25:36 +03:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
2025-10-14 10:18:54 +03:00
let acc_decode_data = vec![
2025-12-11 14:46:16 +02:00
Decode(secret_sender, sender_account_id),
Decode(secret_recipient, recipient_account_id),
2025-10-14 10:18:54 +03:00
];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-10-14 10:18:54 +03:00
&acc_decode_data,
)?;
2025-10-13 17:25:36 +03:00
}
wallet_core.store_persistent_data()?;
2025-10-13 17:25:36 +03:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::TransferTokenPrivateForeign {
sender_account_id,
2025-10-13 17:25:36 +03:00
recipient_npk,
2026-01-21 17:58:45 -05:00
recipient_vpk,
recipient_identifier,
2025-10-13 17:25:36 +03:00
balance_to_move,
} => {
let recipient_npk_res = hex::decode(recipient_npk)?;
let mut recipient_npk = [0; 32];
recipient_npk.copy_from_slice(&recipient_npk_res);
let recipient_npk = nssa_core::NullifierPublicKey(recipient_npk);
2026-05-29 19:54:53 -04:00
let recipient_vpk_res = hex::decode(&recipient_vpk).context(
"wallet::cli::programs::token: recipient_vpk must be a valid hex string",
)?;
let recipient_vpk =
nssa_core::encryption::MlKem768EncapsulationKey::from_bytes(recipient_vpk_res)
.map_err(|e| anyhow::anyhow!("{e}"))?;
2025-10-13 17:25:36 +03:00
let (tx_hash, [secret_sender, _]) = Token(wallet_core)
.send_transfer_transaction_private_foreign_account(
sender_account_id,
2025-10-13 17:25:36 +03:00
recipient_npk,
2026-01-21 17:58:45 -05:00
recipient_vpk,
recipient_identifier.unwrap_or_else(rand::random),
2025-10-13 17:25:36 +03:00
balance_to_move,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-10-13 17:25:36 +03:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-10-13 17:25:36 +03:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
2025-12-11 14:46:16 +02:00
let acc_decode_data = vec![Decode(secret_sender, sender_account_id)];
2025-10-13 17:25:36 +03:00
2025-10-14 10:18:54 +03:00
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-10-14 10:18:54 +03:00
&acc_decode_data,
)?;
2025-10-13 17:25:36 +03:00
}
wallet_core.store_persistent_data()?;
2025-10-13 17:25:36 +03:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::BurnTokenPrivateOwned {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
2025-10-20 09:10:54 +03:00
} => {
let (tx_hash, [secret_definition, secret_holder]) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_burn_transaction_private_owned_account(
definition_account_id,
holder_account_id,
amount,
2025-10-20 09:10:54 +03:00
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-10-20 09:10:54 +03:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-10-20 09:10:54 +03:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
2025-12-11 14:46:16 +02:00
let acc_decode_data = vec![
Decode(secret_definition, definition_account_id),
Decode(secret_holder, holder_account_id),
];
2025-10-20 09:10:54 +03:00
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-10-20 09:10:54 +03:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-10-20 09:10:54 +03:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::MintTokenPrivateOwned {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
let (tx_hash, [secret_definition, secret_holder]) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_mint_transaction_private_owned_account(
definition_account_id,
holder_account_id,
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![
Decode(secret_definition, definition_account_id),
Decode(secret_holder, holder_account_id),
];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::MintTokenPrivateForeign {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
holder_identifier,
2025-12-11 14:46:16 +02:00
amount,
} => {
let holder_npk_res = hex::decode(holder_npk)?;
let mut holder_npk = [0; 32];
holder_npk.copy_from_slice(&holder_npk_res);
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
2026-05-29 19:54:53 -04:00
let holder_vpk_res = hex::decode(&holder_vpk).context(
"wallet::cli::programs::token: holder_vpk must be a valid hex string",
)?;
let holder_vpk =
nssa_core::encryption::MlKem768EncapsulationKey::from_bytes(holder_vpk_res)
.map_err(|e| anyhow::anyhow!("{e}"))?;
2025-12-11 14:46:16 +02:00
let (tx_hash, [secret_definition, _]) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_mint_transaction_private_foreign_account(
definition_account_id,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
holder_identifier.unwrap_or_else(rand::random),
2025-12-11 14:46:16 +02:00
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
}
}
}
impl WalletSubcommand for TokenProgramSubcommandDeshielded {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::TransferTokenDeshielded {
2025-12-11 14:46:16 +02:00
sender_account_id,
recipient_account_id,
balance_to_move,
} => {
let (tx_hash, secret_sender) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_transfer_transaction_deshielded(
sender_account_id,
recipient_account_id,
balance_to_move,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![Decode(secret_sender, sender_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::BurnTokenDeshieldedOwned {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
let (tx_hash, secret_definition) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_burn_transaction_deshielded_owned_account(
definition_account_id,
holder_account_id,
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::MintTokenDeshielded {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
let (tx_hash, secret_definition) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_mint_transaction_deshielded(
definition_account_id,
holder_account_id,
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
}
}
}
impl WalletSubcommand for TokenProgramSubcommandShielded {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::TransferTokenShieldedForeign {
sender_account_id,
2025-10-20 09:10:54 +03:00
recipient_npk,
2026-01-21 17:58:45 -05:00
recipient_vpk,
recipient_identifier,
2025-10-20 09:10:54 +03:00
balance_to_move,
} => {
let recipient_npk_res = hex::decode(recipient_npk)?;
let mut recipient_npk = [0; 32];
recipient_npk.copy_from_slice(&recipient_npk_res);
let recipient_npk = nssa_core::NullifierPublicKey(recipient_npk);
2026-05-29 19:54:53 -04:00
let recipient_vpk_res = hex::decode(&recipient_vpk).context(
"wallet::cli::programs::token: recipient_vpk must be a valid hex string",
)?;
let recipient_vpk =
nssa_core::encryption::MlKem768EncapsulationKey::from_bytes(recipient_vpk_res)
.map_err(|e| anyhow::anyhow!("{e}"))?;
2025-10-20 09:10:54 +03:00
let (tx_hash, _) = Token(wallet_core)
.send_transfer_transaction_shielded_foreign_account(
sender_account_id,
2025-10-20 09:10:54 +03:00
recipient_npk,
2026-01-21 17:58:45 -05:00
recipient_vpk,
recipient_identifier.unwrap_or_else(rand::random),
2025-10-20 09:10:54 +03:00
balance_to_move,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-10-20 09:10:54 +03:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-10-20 09:10:54 +03:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
println!("Transaction data is {:?}", tx.message);
}
wallet_core.store_persistent_data()?;
2025-10-20 09:10:54 +03:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::TransferTokenShieldedOwned {
sender_account_id,
recipient_account_id,
2025-10-20 09:10:54 +03:00
balance_to_move,
} => {
let (tx_hash, secret_recipient) = Token(wallet_core)
.send_transfer_transaction_shielded_owned_account(
sender_account_id,
recipient_account_id,
balance_to_move,
)
2025-10-20 09:10:54 +03:00
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-10-20 09:10:54 +03:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-10-20 09:10:54 +03:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
2025-12-11 14:46:16 +02:00
let acc_decode_data = vec![Decode(secret_recipient, recipient_account_id)];
2025-10-20 09:10:54 +03:00
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-10-20 09:10:54 +03:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-10-20 09:10:54 +03:00
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::BurnTokenShielded {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
let (tx_hash, secret_holder) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_burn_transaction_shielded(
definition_account_id,
holder_account_id,
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![Decode(secret_holder, holder_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::MintTokenShieldedOwned {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_account_id,
amount,
} => {
let (tx_hash, secret_holder) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_mint_transaction_shielded_owned_account(
definition_account_id,
holder_account_id,
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![Decode(secret_holder, holder_account_id)];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-11 14:46:16 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::MintTokenShieldedForeign {
2025-12-11 14:46:16 +02:00
definition_account_id,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
holder_identifier,
2025-12-11 14:46:16 +02:00
amount,
} => {
let holder_npk_res = hex::decode(holder_npk)?;
let mut holder_npk = [0; 32];
holder_npk.copy_from_slice(&holder_npk_res);
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
2026-05-29 19:54:53 -04:00
let holder_vpk_res = hex::decode(&holder_vpk).context(
"wallet::cli::programs::token: holder_vpk must be a valid hex string",
)?;
let holder_vpk =
nssa_core::encryption::MlKem768EncapsulationKey::from_bytes(holder_vpk_res)
.map_err(|e| anyhow::anyhow!("{e}"))?;
2025-12-11 14:46:16 +02:00
let (tx_hash, _) = Token(wallet_core)
2025-12-11 14:46:16 +02:00
.send_mint_transaction_shielded_foreign_account(
definition_account_id,
holder_npk,
2026-01-21 17:58:45 -05:00
holder_vpk,
holder_identifier.unwrap_or_else(rand::random),
2025-12-11 14:46:16 +02:00
amount,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-11 14:46:16 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-11 14:46:16 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
println!("Transaction data is {:?}", tx.message);
}
wallet_core.store_persistent_data()?;
2025-12-11 14:46:16 +02:00
2025-10-20 09:10:54 +03:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
}
}
}
2025-12-02 15:27:20 +02:00
impl WalletSubcommand for CreateNewTokenProgramSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::NewPrivateDefPrivateSupp {
2025-12-02 15:27:20 +02:00
definition_account_id,
supply_account_id,
name,
total_supply,
} => {
let (tx_hash, [secret_definition, secret_supply]) = Token(wallet_core)
2025-12-02 15:27:20 +02:00
.send_new_definition_private_owned_definiton_and_supply(
definition_account_id,
supply_account_id,
name,
2025-12-02 15:27:20 +02:00
total_supply,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-02 15:27:20 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-02 15:27:20 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![
2025-12-11 14:46:16 +02:00
Decode(secret_definition, definition_account_id),
Decode(secret_supply, supply_account_id),
2025-12-02 15:27:20 +02:00
];
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-02 15:27:20 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-02 15:27:20 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::NewPrivateDefPublicSupp {
2025-12-02 15:27:20 +02:00
definition_account_id,
supply_account_id,
name,
total_supply,
} => {
let (tx_hash, secret_definition) = Token(wallet_core)
2025-12-02 15:27:20 +02:00
.send_new_definition_private_owned_definiton(
definition_account_id,
supply_account_id,
name,
2025-12-02 15:27:20 +02:00
total_supply,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-02 15:27:20 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-02 15:27:20 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
2025-12-11 14:46:16 +02:00
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
2025-12-02 15:27:20 +02:00
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-02 15:27:20 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-02 15:27:20 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::NewPublicDefPrivateSupp {
2025-12-02 15:27:20 +02:00
definition_account_id,
supply_account_id,
name,
total_supply,
} => {
let (tx_hash, secret_supply) = Token(wallet_core)
2025-12-02 15:27:20 +02:00
.send_new_definition_private_owned_supply(
definition_account_id,
supply_account_id,
name,
2025-12-02 15:27:20 +02:00
total_supply,
)
.await?;
2026-03-14 03:20:37 +03:00
println!("Transaction hash is {tx_hash}");
2025-12-02 15:27:20 +02:00
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
2025-12-02 15:27:20 +02:00
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
2025-12-11 14:46:16 +02:00
let acc_decode_data = vec![Decode(secret_supply, supply_account_id)];
2025-12-02 15:27:20 +02:00
wallet_core.decode_insert_privacy_preserving_transaction_results(
2026-03-03 23:21:08 +03:00
&tx,
2025-12-02 15:27:20 +02:00
&acc_decode_data,
)?;
}
wallet_core.store_persistent_data()?;
2025-12-02 15:27:20 +02:00
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
}
2026-03-09 18:27:56 +03:00
Self::NewPublicDefPublicSupp {
2025-12-02 15:27:20 +02:00
definition_account_id,
supply_account_id,
name,
total_supply,
} => {
Token(wallet_core)
.send_new_definition(
definition_account_id,
supply_account_id,
name,
2025-12-02 15:27:20 +02:00
total_supply,
)
.await?;
Ok(SubcommandReturnValue::Empty)
}
}
}
}
2025-10-14 10:18:54 +03:00
impl WalletSubcommand for TokenProgramSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
2026-03-09 18:27:56 +03:00
Self::Create(creation_subcommand) => {
2025-12-02 15:27:20 +02:00
creation_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Private(private_subcommand) => {
2025-10-14 10:18:54 +03:00
private_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Public(public_subcommand) => {
2025-10-14 10:18:54 +03:00
public_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Deshielded(deshielded_subcommand) => {
2025-10-20 09:10:54 +03:00
deshielded_subcommand.handle_subcommand(wallet_core).await
}
2026-03-09 18:27:56 +03:00
Self::Shielded(shielded_subcommand) => {
2025-10-20 09:10:54 +03:00
shielded_subcommand.handle_subcommand(wallet_core).await
}
2025-10-14 10:18:54 +03:00
}
}
}