mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-06-02 07:09:29 +00:00
feat!(wallet): SigningGroup merged with AccountManager
This commit is contained in:
parent
89bf1e9422
commit
675fd35664
@ -52,7 +52,6 @@ async fn main() {
|
||||
accounts,
|
||||
Program::serialize_instruction(greeting).unwrap(),
|
||||
&program.into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -60,7 +60,6 @@ async fn main() {
|
||||
accounts,
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&program_with_dependencies,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -106,7 +106,6 @@ async fn main() {
|
||||
accounts,
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&program.into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -148,7 +147,6 @@ async fn main() {
|
||||
accounts,
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&program.into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -139,7 +139,6 @@ async fn spend_private_pda(
|
||||
Program::serialize_instruction((seed, amount, auth_transfer_id))
|
||||
.context("failed to serialize pda_spend_proxy instruction")?,
|
||||
spend_program,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
||||
|
||||
@ -296,7 +296,6 @@ async fn claim_funds_from_vault_to_private(
|
||||
],
|
||||
instruction_data,
|
||||
&program_with_dependencies,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.context("Failed to submit private vault claim transaction")?;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::{AccountId, PrivateKey};
|
||||
use keycard_wallet::{KeycardWallet, python_path};
|
||||
use nssa::{AccountId, PrivateKey, PublicKey, Signature};
|
||||
use nssa_core::{
|
||||
Identifier, InputAccountIdentity, MembershipProof, NullifierPublicKey, NullifierSecretKey,
|
||||
SharedSecretKey,
|
||||
@ -15,6 +16,11 @@ pub enum AccountIdentity {
|
||||
Public(AccountId),
|
||||
/// A public account without signing. Would not try to sign, even if account is owned.
|
||||
PublicNoSign(AccountId),
|
||||
/// A public account from keycard. Mandatory signing.
|
||||
PublicKeycard {
|
||||
account_id: AccountId,
|
||||
key_path: String,
|
||||
},
|
||||
PrivateOwned(AccountId),
|
||||
PrivateForeign {
|
||||
npk: NullifierPublicKey,
|
||||
@ -57,7 +63,10 @@ impl AccountIdentity {
|
||||
/// Note: `PublicNoSign` still counts as public, the variant just suppresses the signing-key
|
||||
/// lookup.
|
||||
pub const fn is_public(&self) -> bool {
|
||||
matches!(&self, Self::Public(_) | Self::PublicNoSign(_))
|
||||
matches!(
|
||||
&self,
|
||||
Self::Public(_) | Self::PublicNoSign(_) | Self::PublicKeycard { .. }
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -86,11 +95,16 @@ enum State {
|
||||
account: AccountWithMetadata,
|
||||
sk: Option<PrivateKey>,
|
||||
},
|
||||
PublicKeycard {
|
||||
account: AccountWithMetadata,
|
||||
key_path: String,
|
||||
},
|
||||
Private(AccountPreparedData),
|
||||
}
|
||||
|
||||
pub struct AccountManager {
|
||||
states: Vec<State>,
|
||||
pin: Option<String>,
|
||||
}
|
||||
|
||||
impl AccountManager {
|
||||
@ -99,6 +113,7 @@ impl AccountManager {
|
||||
accounts: Vec<AccountIdentity>,
|
||||
) -> Result<Self, ExecutionFailureKind> {
|
||||
let mut states = Vec::with_capacity(accounts.len());
|
||||
let mut pin = None;
|
||||
|
||||
for account in accounts {
|
||||
let state = match account {
|
||||
@ -124,6 +139,35 @@ impl AccountManager {
|
||||
|
||||
State::Public { account, sk }
|
||||
}
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id,
|
||||
key_path,
|
||||
} => {
|
||||
let acc = wallet
|
||||
.get_account_public(account_id)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let account = AccountWithMetadata::new(acc.clone(), true, account_id);
|
||||
|
||||
if pin.is_none() {
|
||||
pin = Some(
|
||||
crate::helperfunctions::read_pin()
|
||||
.map_err(|e| {
|
||||
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<
|
||||
pyo3::exceptions::PyRuntimeError,
|
||||
_,
|
||||
>(
|
||||
e.to_string()
|
||||
))
|
||||
})?
|
||||
.as_str()
|
||||
.to_owned(),
|
||||
);
|
||||
}
|
||||
|
||||
State::PublicKeycard { account, key_path }
|
||||
}
|
||||
AccountIdentity::PrivateOwned(account_id) => {
|
||||
let pre = private_key_tree_acc_preparation(wallet, account_id, false).await?;
|
||||
|
||||
@ -214,14 +258,16 @@ impl AccountManager {
|
||||
states.push(state);
|
||||
}
|
||||
|
||||
Ok(Self { states })
|
||||
Ok(Self { states, pin })
|
||||
}
|
||||
|
||||
pub fn pre_states(&self) -> Vec<AccountWithMetadata> {
|
||||
self.states
|
||||
.iter()
|
||||
.map(|state| match state {
|
||||
State::Public { account, .. } => account.clone(),
|
||||
State::Public { account, .. } | State::PublicKeycard { account, .. } => {
|
||||
account.clone()
|
||||
}
|
||||
State::Private(pre) => pre.pre_state.clone(),
|
||||
})
|
||||
.collect()
|
||||
@ -232,6 +278,7 @@ impl AccountManager {
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Public { account, sk } => sk.as_ref().map(|_| account.account.nonce),
|
||||
State::PublicKeycard { account, .. } => Some(account.account.nonce),
|
||||
State::Private(_) => None,
|
||||
})
|
||||
.collect()
|
||||
@ -247,7 +294,7 @@ impl AccountManager {
|
||||
vpk: pre.vpk.clone(),
|
||||
epk: pre.epk.clone(),
|
||||
}),
|
||||
State::Public { .. } => None,
|
||||
State::Public { .. } | State::PublicKeycard { .. } => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -260,7 +307,7 @@ impl AccountManager {
|
||||
self.states
|
||||
.iter()
|
||||
.map(|state| match state {
|
||||
State::Public { .. } => InputAccountIdentity::Public,
|
||||
State::Public { .. } | State::PublicKeycard { .. } => InputAccountIdentity::Public,
|
||||
State::Private(pre) if pre.is_pda => match (pre.nsk, pre.proof.clone()) {
|
||||
(Some(nsk), Some(membership_proof)) => InputAccountIdentity::PrivatePdaUpdate {
|
||||
ssk: pre.ssk,
|
||||
@ -304,21 +351,66 @@ impl AccountManager {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Public { account, .. } => Some(account.account_id),
|
||||
State::Public { account, .. } | State::PublicKeycard { account, .. } => {
|
||||
Some(account.account_id)
|
||||
}
|
||||
State::Private(_) => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn public_account_auth(&self) -> Vec<&PrivateKey> {
|
||||
pub fn public_non_keycard_account_auth(&self) -> Vec<&PrivateKey> {
|
||||
self.states
|
||||
.iter()
|
||||
.filter_map(|state| match state {
|
||||
State::Public { sk, .. } => sk.as_ref(),
|
||||
State::Private(_) => None,
|
||||
State::PublicKeycard { .. } | State::Private(_) => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn sign_message(&self, message_hash: [u8; 32]) -> Result<Vec<(Signature, PublicKey)>> {
|
||||
let mut sigs: Vec<(Signature, PublicKey)> = self
|
||||
.public_non_keycard_account_auth()
|
||||
.into_iter()
|
||||
.map(|key| {
|
||||
(
|
||||
Signature::new(key, &message_hash),
|
||||
PublicKey::new_from_private_key(key),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let keycard_paths = self
|
||||
.states
|
||||
.iter()
|
||||
.fold(vec![], |mut acc, state| match state {
|
||||
State::Private(_) | State::Public { .. } => acc,
|
||||
State::PublicKeycard {
|
||||
account: _,
|
||||
key_path,
|
||||
} => {
|
||||
acc.push(key_path.as_str());
|
||||
acc
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(pin) = self.pin.clone() {
|
||||
pyo3::Python::with_gil(|py| -> pyo3::PyResult<()> {
|
||||
python_path::add_python_path(py)?;
|
||||
let wallet = KeycardWallet::new(py)?;
|
||||
wallet.connect(py, &pin)?;
|
||||
for path in keycard_paths {
|
||||
sigs.push(wallet.sign_message_for_path(py, path, &message_hash)?);
|
||||
}
|
||||
drop(wallet.close_session(py));
|
||||
Ok(())
|
||||
})
|
||||
.map_err(anyhow::Error::from)?;
|
||||
}
|
||||
|
||||
Ok(sigs)
|
||||
}
|
||||
}
|
||||
|
||||
struct AccountPreparedData {
|
||||
|
||||
@ -259,7 +259,6 @@ impl WalletSubcommand for AmmProgramAgnosticSubcommand {
|
||||
max_amount_b,
|
||||
&user_holding_a,
|
||||
&user_holding_b,
|
||||
&user_holding_lp,
|
||||
)
|
||||
.await?;
|
||||
println!("Transaction hash is {tx_hash}");
|
||||
|
||||
@ -16,20 +16,15 @@ use bip39::Mnemonic;
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use config::WalletConfig;
|
||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
||||
use keycard_wallet::KeycardWallet;
|
||||
use log::info;
|
||||
use nssa::{
|
||||
Account, AccountId, PrivacyPreservingTransaction, PublicKey, PublicTransaction, Signature,
|
||||
Account, AccountId, PrivacyPreservingTransaction,
|
||||
privacy_preserving_transaction::{
|
||||
circuit::ProgramWithDependencies, message::EncryptedAccountData,
|
||||
},
|
||||
program::Program,
|
||||
public_transaction::WitnessSet as PublicWitnessSet,
|
||||
};
|
||||
use nssa_core::{
|
||||
Commitment, MembershipProof, SharedSecretKey,
|
||||
account::{AccountWithMetadata, Nonce},
|
||||
program::InstructionData,
|
||||
Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData,
|
||||
};
|
||||
use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder};
|
||||
use storage::Storage;
|
||||
@ -37,10 +32,8 @@ use tokio::io::AsyncWriteExt as _;
|
||||
|
||||
use crate::{
|
||||
account::{AccountIdWithPrivacy, Label},
|
||||
cli::CliAccountMention,
|
||||
config::WalletConfigOverrides,
|
||||
poller::TxPoller,
|
||||
signing::SigningGroup,
|
||||
storage::key_chain::SharedAccountEntry,
|
||||
};
|
||||
|
||||
@ -561,76 +554,15 @@ impl WalletCore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send a public transaction, fetching nonces automatically from
|
||||
/// [`SigningGroup::signing_ids`].
|
||||
pub async fn send_public_tx<T: serde::Serialize>(
|
||||
&self,
|
||||
program: &Program,
|
||||
account_ids: Vec<AccountId>,
|
||||
instruction: T,
|
||||
groups: SigningGroup,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let nonces = self
|
||||
.get_accounts_nonces(groups.signing_ids())
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
self.send_public_tx_with_nonces(program, account_ids, nonces, instruction, groups)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Send a public transaction with caller-supplied nonces.
|
||||
///
|
||||
/// Use this when the caller needs to assemble or augment nonces before submission
|
||||
/// (e.g. injecting a keycard account nonce that was fetched separately).
|
||||
pub async fn send_public_tx_with_nonces<T: serde::Serialize>(
|
||||
&self,
|
||||
program: &Program,
|
||||
account_ids: Vec<AccountId>,
|
||||
nonces: Vec<Nonce>,
|
||||
instruction: T,
|
||||
groups: SigningGroup,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)?;
|
||||
|
||||
let pin = if groups.needs_pin() {
|
||||
crate::helperfunctions::read_pin()
|
||||
.map_err(ExecutionFailureKind::from_anyhow)?
|
||||
.as_str()
|
||||
.to_owned()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let sigs = groups
|
||||
.sign_all(&message.hash(), &pin)
|
||||
.map_err(ExecutionFailureKind::from_anyhow)?;
|
||||
|
||||
let tx = PublicTransaction::new(message, PublicWitnessSet::from_raw_parts(sigs));
|
||||
Ok(self
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_privacy_preserving_tx(
|
||||
&self,
|
||||
accounts: Vec<AccountIdentity>,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
mention: Option<&CliAccountMention>,
|
||||
) -> Result<(HashType, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
self.send_privacy_preserving_tx_with_pre_check(
|
||||
accounts,
|
||||
instruction_data,
|
||||
program,
|
||||
|_| Ok(()),
|
||||
mention,
|
||||
)
|
||||
self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| {
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
@ -640,66 +572,10 @@ impl WalletCore {
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
mention: Option<&CliAccountMention>,
|
||||
) -> Result<(HashType, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
let acc_manager = account_manager::AccountManager::new(self, accounts).await?;
|
||||
|
||||
let mut pre_states = acc_manager.pre_states();
|
||||
|
||||
let (keycard_account, keycard_pin, keycard_path) = if let Some(key_path_str) =
|
||||
mention.and_then(CliAccountMention::key_path)
|
||||
{
|
||||
let pin = crate::helperfunctions::read_pin().map_err(|e| {
|
||||
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<
|
||||
pyo3::exceptions::PyRuntimeError,
|
||||
_,
|
||||
>(e.to_string()))
|
||||
})?;
|
||||
let account_id_str =
|
||||
KeycardWallet::get_public_account_id_for_path_with_connect(&pin, key_path_str)?;
|
||||
let account_id: AccountId = match account_id_str
|
||||
.parse::<AccountIdWithPrivacy>()
|
||||
.expect("`wallet::lib::send_privacy_preserving_tx_with_pre_check`: invalid account id parsed")
|
||||
{
|
||||
AccountIdWithPrivacy::Public(id) | AccountIdWithPrivacy::Private(id) => id,
|
||||
};
|
||||
let account = self
|
||||
.get_account_public(account_id)
|
||||
.await
|
||||
.expect("`wallet::lib::send_privacy_preserving_tx_with_pre_check`: unable to retrieve public account");
|
||||
let pin_str = pin.as_str().to_owned();
|
||||
(
|
||||
Some(AccountWithMetadata {
|
||||
account,
|
||||
is_authorized: true,
|
||||
account_id,
|
||||
}),
|
||||
Some(pin_str),
|
||||
Some(key_path_str.to_owned()),
|
||||
)
|
||||
} else {
|
||||
(None, None, None)
|
||||
};
|
||||
|
||||
let mut nonces: Vec<Nonce> = acc_manager.public_account_nonces().into_iter().collect();
|
||||
|
||||
let mut account_ids: Vec<AccountId> = acc_manager.public_account_ids();
|
||||
|
||||
if let Some(acc) = keycard_account.as_ref() {
|
||||
if acc_manager.public_account_ids().contains(&acc.account_id) {
|
||||
if let Some(pre) = pre_states
|
||||
.iter_mut()
|
||||
.find(|p| p.account_id == acc.account_id)
|
||||
{
|
||||
pre.is_authorized = true;
|
||||
}
|
||||
nonces.push(acc.account.nonce);
|
||||
} else {
|
||||
nonces.push(acc.account.nonce);
|
||||
account_ids.push(acc.account_id);
|
||||
pre_states.push(acc.clone());
|
||||
}
|
||||
}
|
||||
let pre_states = acc_manager.pre_states();
|
||||
|
||||
tx_pre_check(
|
||||
&pre_states
|
||||
@ -714,54 +590,30 @@ impl WalletCore {
|
||||
instruction_data,
|
||||
acc_manager.account_identities(),
|
||||
&program.to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
account_ids,
|
||||
nonces,
|
||||
acc_manager.public_account_ids(),
|
||||
acc_manager.public_account_nonces(),
|
||||
private_account_keys
|
||||
.iter()
|
||||
.map(|keys| (keys.npk, keys.vpk.clone(), keys.epk.clone()))
|
||||
.collect(),
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
|
||||
let message_hash = message.hash();
|
||||
let signatures_public_keys = acc_manager
|
||||
.sign_message(message_hash)
|
||||
.map_err(ExecutionFailureKind::from_anyhow)?;
|
||||
|
||||
let witness_set =
|
||||
if let (Some(pin), Some(path)) = (keycard_pin.as_deref(), keycard_path.as_deref()) {
|
||||
let hash = message.hash();
|
||||
let local_auth = acc_manager.public_account_auth();
|
||||
let mut sigs: Vec<(Signature, PublicKey)> = local_auth
|
||||
.iter()
|
||||
.map(|&key| {
|
||||
(
|
||||
Signature::new(key, &hash),
|
||||
PublicKey::new_from_private_key(key),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let keycard_sig = pyo3::Python::with_gil(|py| {
|
||||
let mut ctx = crate::signing::KeycardSessionContext::new(pin);
|
||||
let result = ctx
|
||||
.get_or_connect(py)
|
||||
.and_then(|w| w.sign_message_for_path(py, path, &hash));
|
||||
ctx.close(py);
|
||||
result
|
||||
})
|
||||
.map_err(ExecutionFailureKind::KeycardError)?;
|
||||
sigs.push(keycard_sig);
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::from_raw_parts(
|
||||
sigs, proof,
|
||||
)
|
||||
} else {
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&acc_manager.public_account_auth(),
|
||||
)
|
||||
};
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::from_raw_parts(
|
||||
signatures_public_keys,
|
||||
proof,
|
||||
);
|
||||
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
let shared_secrets: Vec<_> = private_account_keys
|
||||
@ -816,7 +668,6 @@ impl WalletCore {
|
||||
let account_ids = acc_manager.public_account_ids();
|
||||
let program_id = program.program.id();
|
||||
let nonces = acc_manager.public_account_nonces();
|
||||
let private_keys = acc_manager.public_account_auth();
|
||||
|
||||
let message = nssa::public_transaction::Message::new_preserialized(
|
||||
program_id,
|
||||
@ -825,8 +676,13 @@ impl WalletCore {
|
||||
instruction_data,
|
||||
);
|
||||
|
||||
let message_hash = message.hash();
|
||||
let signatures_public_keys = acc_manager
|
||||
.sign_message(message_hash)
|
||||
.map_err(ExecutionFailureKind::from_anyhow)?;
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys);
|
||||
nssa::public_transaction::WitnessSet::from_raw_parts(signatures_public_keys);
|
||||
|
||||
let tx = nssa::public_transaction::PublicTransaction::new(message, witness_set);
|
||||
|
||||
|
||||
@ -15,10 +15,34 @@ impl Amm<'_> {
|
||||
user_holding_lp: AccountId,
|
||||
balance_a: u128,
|
||||
balance_b: u128,
|
||||
_a_mention: &CliAccountMention,
|
||||
_b_mention: &CliAccountMention,
|
||||
_lp_mention: &CliAccountMention,
|
||||
user_holding_a_mention: &CliAccountMention,
|
||||
user_holding_b_mention: &CliAccountMention,
|
||||
user_holding_lp_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let user_holding_a_identity = user_holding_a_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_a,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let user_holding_b_identity = user_holding_b_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_b,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let user_holding_lp_identity = user_holding_lp_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_lp),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_lp,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
let user_a_acc = self
|
||||
@ -59,9 +83,9 @@ impl Amm<'_> {
|
||||
AccountIdentity::PublicNoSign(vault_holding_a),
|
||||
AccountIdentity::PublicNoSign(vault_holding_b),
|
||||
AccountIdentity::PublicNoSign(pool_lp),
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
AccountIdentity::Public(user_holding_lp),
|
||||
user_holding_a_identity,
|
||||
user_holding_b_identity,
|
||||
user_holding_lp_identity,
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
@ -77,8 +101,8 @@ impl Amm<'_> {
|
||||
swap_amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
_a_mention: &CliAccountMention,
|
||||
_b_mention: &CliAccountMention,
|
||||
user_holding_a_mention: &CliAccountMention,
|
||||
user_holding_b_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
@ -121,13 +145,25 @@ impl Amm<'_> {
|
||||
}
|
||||
|
||||
let user_a_signing_identity = if token_definition_id_in == definition_token_a_id {
|
||||
AccountIdentity::Public(user_holding_a)
|
||||
user_holding_a_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_a,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_a)
|
||||
};
|
||||
|
||||
let user_b_signing_identity = if token_definition_id_in == definition_token_b_id {
|
||||
AccountIdentity::Public(user_holding_b)
|
||||
user_holding_b_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_b,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_b)
|
||||
};
|
||||
@ -155,8 +191,8 @@ impl Amm<'_> {
|
||||
exact_amount_out: u128,
|
||||
max_amount_in: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
_a_mention: &CliAccountMention,
|
||||
_b_mention: &CliAccountMention,
|
||||
user_holding_a_mention: &CliAccountMention,
|
||||
user_holding_b_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
@ -199,13 +235,25 @@ impl Amm<'_> {
|
||||
}
|
||||
|
||||
let user_a_signing_identity = if token_definition_id_in == definition_token_a_id {
|
||||
AccountIdentity::Public(user_holding_a)
|
||||
user_holding_a_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_a,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_a)
|
||||
};
|
||||
|
||||
let user_b_signing_identity = if token_definition_id_in == definition_token_b_id {
|
||||
AccountIdentity::Public(user_holding_b)
|
||||
user_holding_b_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_b,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_b)
|
||||
};
|
||||
@ -234,10 +282,25 @@ impl Amm<'_> {
|
||||
min_amount_liquidity: u128,
|
||||
max_amount_to_add_token_a: u128,
|
||||
max_amount_to_add_token_b: u128,
|
||||
_a_mention: &CliAccountMention,
|
||||
_b_mention: &CliAccountMention,
|
||||
_lp_mention: &CliAccountMention,
|
||||
user_holding_a_mention: &CliAccountMention,
|
||||
user_holding_b_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let user_holding_a_identity = user_holding_a_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_a,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let user_holding_b_identity = user_holding_b_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_b,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
let user_a_acc = self
|
||||
@ -278,8 +341,8 @@ impl Amm<'_> {
|
||||
AccountIdentity::PublicNoSign(vault_holding_a),
|
||||
AccountIdentity::PublicNoSign(vault_holding_b),
|
||||
AccountIdentity::PublicNoSign(pool_lp),
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
user_holding_a_identity,
|
||||
user_holding_b_identity,
|
||||
AccountIdentity::PublicNoSign(user_holding_lp),
|
||||
],
|
||||
instruction_data,
|
||||
@ -297,8 +360,16 @@ impl Amm<'_> {
|
||||
remove_liquidity_amount: u128,
|
||||
min_amount_to_remove_token_a: u128,
|
||||
min_amount_to_remove_token_b: u128,
|
||||
_lp_mention: &CliAccountMention,
|
||||
user_holding_lp_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let user_holding_lp_identity = user_holding_lp_mention.key_path().map_or(
|
||||
AccountIdentity::Public(user_holding_lp),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: user_holding_lp,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
let user_a_acc = self
|
||||
@ -341,7 +412,7 @@ impl Amm<'_> {
|
||||
AccountIdentity::PublicNoSign(pool_lp),
|
||||
AccountIdentity::PublicNoSign(user_holding_a),
|
||||
AccountIdentity::PublicNoSign(user_holding_b),
|
||||
AccountIdentity::Public(user_holding_lp),
|
||||
user_holding_lp_identity,
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
|
||||
@ -16,8 +16,18 @@ impl Ata<'_> {
|
||||
&self,
|
||||
owner_id: AccountId,
|
||||
definition_id: AccountId,
|
||||
_owner_mention: &CliAccountMention,
|
||||
owner_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let owner_identity =
|
||||
owner_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(owner_id), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: owner_id,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let program = Program::ata();
|
||||
let ata_program_id = program.id();
|
||||
let ata_id = get_associated_token_account_id(
|
||||
@ -31,7 +41,7 @@ impl Ata<'_> {
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(owner_id),
|
||||
owner_identity,
|
||||
AccountIdentity::PublicNoSign(definition_id),
|
||||
AccountIdentity::PublicNoSign(ata_id),
|
||||
],
|
||||
@ -47,8 +57,18 @@ impl Ata<'_> {
|
||||
definition_id: AccountId,
|
||||
recipient_id: AccountId,
|
||||
amount: u128,
|
||||
_owner_mention: &CliAccountMention,
|
||||
owner_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let owner_identity =
|
||||
owner_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(owner_id), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: owner_id,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let program = Program::ata();
|
||||
let ata_program_id = program.id();
|
||||
let sender_ata_id = get_associated_token_account_id(
|
||||
@ -65,7 +85,7 @@ impl Ata<'_> {
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(owner_id),
|
||||
owner_identity,
|
||||
AccountIdentity::PublicNoSign(sender_ata_id),
|
||||
AccountIdentity::PublicNoSign(recipient_id),
|
||||
],
|
||||
@ -80,8 +100,18 @@ impl Ata<'_> {
|
||||
owner_id: AccountId,
|
||||
definition_id: AccountId,
|
||||
amount: u128,
|
||||
_owner_mention: &CliAccountMention,
|
||||
owner_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let owner_identity =
|
||||
owner_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(owner_id), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: owner_id,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let program = Program::ata();
|
||||
let ata_program_id = program.id();
|
||||
let holder_ata_id = get_associated_token_account_id(
|
||||
@ -98,7 +128,7 @@ impl Ata<'_> {
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(owner_id),
|
||||
owner_identity,
|
||||
AccountIdentity::PublicNoSign(holder_ata_id),
|
||||
AccountIdentity::PublicNoSign(definition_id),
|
||||
],
|
||||
@ -132,12 +162,7 @@ impl Ata<'_> {
|
||||
];
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
instruction_data,
|
||||
&ata_with_token_dependency(),
|
||||
None,
|
||||
)
|
||||
.send_privacy_preserving_tx(accounts, instruction_data, &ata_with_token_dependency())
|
||||
.await
|
||||
.map(|(hash, mut secrets)| {
|
||||
let secret = secrets.pop().expect("expected owner's secret");
|
||||
@ -174,12 +199,7 @@ impl Ata<'_> {
|
||||
];
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
instruction_data,
|
||||
&ata_with_token_dependency(),
|
||||
None,
|
||||
)
|
||||
.send_privacy_preserving_tx(accounts, instruction_data, &ata_with_token_dependency())
|
||||
.await
|
||||
.map(|(hash, mut secrets)| {
|
||||
let secret = secrets.pop().expect("expected owner's secret");
|
||||
@ -215,12 +235,7 @@ impl Ata<'_> {
|
||||
];
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
instruction_data,
|
||||
&ata_with_token_dependency(),
|
||||
None,
|
||||
)
|
||||
.send_privacy_preserving_tx(accounts, instruction_data, &ata_with_token_dependency())
|
||||
.await
|
||||
.map(|(hash, mut secrets)| {
|
||||
let secret = secrets.pop().expect("expected owner's secret");
|
||||
|
||||
@ -24,7 +24,6 @@ impl NativeTokenTransfer<'_> {
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
|
||||
@ -24,7 +24,6 @@ impl NativeTokenTransfer<'_> {
|
||||
vec![account],
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&Program::authenticated_transfer_program().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -59,7 +58,6 @@ impl NativeTokenTransfer<'_> {
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -93,7 +91,6 @@ impl NativeTokenTransfer<'_> {
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
|
||||
@ -3,7 +3,10 @@ use common::HashType;
|
||||
use nssa::{AccountId, program::Program};
|
||||
|
||||
use super::NativeTokenTransfer;
|
||||
use crate::{ExecutionFailureKind, cli::CliAccountMention, signing::SigningGroup};
|
||||
use crate::{
|
||||
AccountIdentity, ExecutionFailureKind, cli::CliAccountMention,
|
||||
program_facades::native_token_transfer::auth_transfer_preparation,
|
||||
};
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_public_transfer(
|
||||
@ -14,20 +17,33 @@ impl NativeTokenTransfer<'_> {
|
||||
from_mention: &CliAccountMention,
|
||||
to_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let mut groups = SigningGroup::new();
|
||||
groups
|
||||
.add_required(from_mention, from, self.0)
|
||||
.and_then(|()| groups.add_optional(to_mention, to, self.0))
|
||||
.map_err(ExecutionFailureKind::from_anyhow)?;
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
let from_identity =
|
||||
from_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(from), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: from,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let to_identity = to_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(to), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: to,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
self.0
|
||||
.send_public_tx(
|
||||
&Program::authenticated_transfer_program(),
|
||||
vec![from, to],
|
||||
AuthTransferInstruction::Transfer {
|
||||
amount: balance_to_move,
|
||||
},
|
||||
groups,
|
||||
.send_pub_tx_with_pre_check(
|
||||
vec![from_identity, to_identity],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -37,18 +53,21 @@ impl NativeTokenTransfer<'_> {
|
||||
from: AccountId,
|
||||
account_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let mut groups = SigningGroup::new();
|
||||
groups
|
||||
.add_required(account_mention, from, self.0)
|
||||
.map_err(ExecutionFailureKind::from_anyhow)?;
|
||||
let from_identity =
|
||||
account_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(from), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: from,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let program = Program::authenticated_transfer_program();
|
||||
let instruction_data = Program::serialize_instruction(AuthTransferInstruction::Initialize)?;
|
||||
|
||||
self.0
|
||||
.send_public_tx(
|
||||
&Program::authenticated_transfer_program(),
|
||||
vec![from],
|
||||
AuthTransferInstruction::Initialize,
|
||||
groups,
|
||||
)
|
||||
.send_pub_tx(vec![from_identity], instruction_data, &program.into())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,11 +13,21 @@ impl NativeTokenTransfer<'_> {
|
||||
balance_to_move: u128,
|
||||
from_mention: &CliAccountMention,
|
||||
) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_identity =
|
||||
from_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(from), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: from,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
AccountIdentity::Public(from),
|
||||
from_identity,
|
||||
self.0
|
||||
.resolve_private_account(to)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
@ -25,7 +35,6 @@ impl NativeTokenTransfer<'_> {
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
Some(from_mention),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -46,11 +55,21 @@ impl NativeTokenTransfer<'_> {
|
||||
balance_to_move: u128,
|
||||
from_mention: &CliAccountMention,
|
||||
) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_identity =
|
||||
from_mention
|
||||
.key_path()
|
||||
.map_or(AccountIdentity::Public(from), |key_path| {
|
||||
AccountIdentity::PublicKeycard {
|
||||
account_id: from,
|
||||
key_path: key_path.to_owned(),
|
||||
}
|
||||
});
|
||||
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
AccountIdentity::Public(from),
|
||||
from_identity,
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: to_npk,
|
||||
vpk: to_vpk,
|
||||
@ -60,7 +79,6 @@ impl NativeTokenTransfer<'_> {
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
Some(from_mention),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
|
||||
@ -62,7 +62,6 @@ impl Pinata<'_> {
|
||||
],
|
||||
nssa::program::Program::serialize_instruction(solution).unwrap(),
|
||||
&nssa::program::Program::pinata().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
|
||||
@ -14,9 +14,25 @@ impl Token<'_> {
|
||||
supply_account_id: AccountId,
|
||||
name: String,
|
||||
total_supply: u128,
|
||||
_definition_mention: &CliAccountMention,
|
||||
_supply_mention: &CliAccountMention,
|
||||
definition_mention: &CliAccountMention,
|
||||
supply_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let definition_identity = definition_mention.key_path().map_or(
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: definition_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let supply_identity = supply_mention.key_path().map_or(
|
||||
AccountIdentity::Public(supply_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: supply_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::NewFungibleDefinition { name, total_supply };
|
||||
let instruction_data =
|
||||
@ -24,10 +40,7 @@ impl Token<'_> {
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
AccountIdentity::Public(supply_account_id),
|
||||
],
|
||||
vec![definition_identity, supply_identity],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
@ -55,7 +68,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -88,7 +100,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -123,7 +134,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -139,9 +149,25 @@ impl Token<'_> {
|
||||
sender_account_id: AccountId,
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
_sender_mention: &CliAccountMention,
|
||||
_recipient_mention: &CliAccountMention,
|
||||
sender_mention: &CliAccountMention,
|
||||
recipient_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let sender_identity = sender_mention.key_path().map_or(
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: sender_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let recipient_identity = recipient_mention.key_path().map_or(
|
||||
AccountIdentity::Public(recipient_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: recipient_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::Transfer {
|
||||
amount_to_transfer: amount,
|
||||
@ -151,10 +177,7 @@ impl Token<'_> {
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
AccountIdentity::Public(recipient_account_id),
|
||||
],
|
||||
vec![sender_identity, recipient_identity],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
@ -185,7 +208,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -224,7 +246,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -257,7 +278,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -276,6 +296,14 @@ impl Token<'_> {
|
||||
amount: u128,
|
||||
sender_mention: &CliAccountMention,
|
||||
) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> {
|
||||
let sender_identity = sender_mention.key_path().map_or(
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: sender_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let instruction = Instruction::Transfer {
|
||||
amount_to_transfer: amount,
|
||||
};
|
||||
@ -284,14 +312,13 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
sender_identity,
|
||||
self.0
|
||||
.resolve_private_account(recipient_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
Some(sender_mention),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -312,6 +339,14 @@ impl Token<'_> {
|
||||
amount: u128,
|
||||
sender_mention: &CliAccountMention,
|
||||
) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> {
|
||||
let sender_identity = sender_mention.key_path().map_or(
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: sender_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let instruction = Instruction::Transfer {
|
||||
amount_to_transfer: amount,
|
||||
};
|
||||
@ -320,7 +355,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
sender_identity,
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: recipient_npk,
|
||||
vpk: recipient_vpk,
|
||||
@ -329,7 +364,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
Some(sender_mention),
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -346,8 +380,16 @@ impl Token<'_> {
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
_holder_mention: &CliAccountMention,
|
||||
holder_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let holder_identity = holder_mention.key_path().map_or(
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: holder_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::Burn {
|
||||
amount_to_burn: amount,
|
||||
@ -359,7 +401,7 @@ impl Token<'_> {
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(definition_account_id),
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
holder_identity,
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
@ -391,7 +433,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -424,7 +465,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -458,7 +498,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -475,9 +514,25 @@ impl Token<'_> {
|
||||
definition_account_id: AccountId,
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
_definition_mention: &CliAccountMention,
|
||||
_holder_mention: &CliAccountMention,
|
||||
definition_mention: &CliAccountMention,
|
||||
holder_mention: &CliAccountMention,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let definition_identity = definition_mention.key_path().map_or(
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: definition_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let holder_identity = holder_mention.key_path().map_or(
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
|key_path| AccountIdentity::PublicKeycard {
|
||||
account_id: holder_account_id,
|
||||
key_path: key_path.to_owned(),
|
||||
},
|
||||
);
|
||||
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::Mint {
|
||||
amount_to_mint: amount,
|
||||
@ -487,10 +542,7 @@ impl Token<'_> {
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
],
|
||||
vec![definition_identity, holder_identity],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
@ -521,7 +573,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -560,7 +611,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -593,7 +643,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -627,7 +676,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
@ -665,7 +713,6 @@ impl Token<'_> {
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
|
||||
@ -1,119 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use keycard_wallet::{KeycardWallet, python_path};
|
||||
use nssa::{AccountId, PrivateKey, PublicKey, Signature};
|
||||
use pyo3::Python;
|
||||
|
||||
use crate::{WalletCore, cli::CliAccountMention};
|
||||
|
||||
/// Groups transaction signers by type to minimise Python GIL acquisition.
|
||||
///
|
||||
/// Local signers are signed in pure Rust; all keycard signers share a single Python session
|
||||
/// with one `connect` / `close_session` pair.
|
||||
#[derive(Default)]
|
||||
pub struct SigningGroup {
|
||||
local: Vec<(AccountId, PrivateKey)>,
|
||||
keycard: Vec<(AccountId, String)>,
|
||||
}
|
||||
|
||||
impl SigningGroup {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Add a sender. Keycard paths are queued for the hardware session; local accounts
|
||||
/// have their signing key resolved eagerly. Errors if no key is found.
|
||||
pub fn add_required(
|
||||
&mut self,
|
||||
mention: &CliAccountMention,
|
||||
account_id: AccountId,
|
||||
wallet_core: &WalletCore,
|
||||
) -> Result<()> {
|
||||
if let CliAccountMention::KeyPath(path) = mention {
|
||||
self.keycard.push((account_id, path.clone()));
|
||||
return Ok(());
|
||||
}
|
||||
let key = wallet_core
|
||||
.storage()
|
||||
.key_chain()
|
||||
.pub_account_signing_key(account_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("signing key not found for account {account_id}"))?
|
||||
.clone();
|
||||
self.local.push((account_id, key));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a recipient. Same as [`add_required`] but silently skips accounts with no local
|
||||
/// key and no keycard path — they are foreign and require neither a signature nor a nonce.
|
||||
pub fn add_optional(
|
||||
&mut self,
|
||||
mention: &CliAccountMention,
|
||||
account_id: AccountId,
|
||||
wallet_core: &WalletCore,
|
||||
) -> Result<()> {
|
||||
if let CliAccountMention::KeyPath(path) = mention {
|
||||
self.keycard.push((account_id, path.clone()));
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(key) = wallet_core
|
||||
.storage()
|
||||
.key_chain()
|
||||
.pub_account_signing_key(account_id)
|
||||
{
|
||||
self.local.push((account_id, key.clone()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns `true` when a PIN is required (at least one keycard signer is present).
|
||||
#[must_use]
|
||||
pub const fn needs_pin(&self) -> bool {
|
||||
!self.keycard.is_empty()
|
||||
}
|
||||
|
||||
/// Account IDs that require a nonce (every non-foreign signer).
|
||||
#[must_use]
|
||||
pub fn signing_ids(&self) -> Vec<AccountId> {
|
||||
self.local
|
||||
.iter()
|
||||
.map(|(id, _)| *id)
|
||||
.chain(self.keycard.iter().map(|(id, _)| *id))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Sign `hash` for every account in the group.
|
||||
///
|
||||
/// Local accounts are signed in pure Rust. Keycard accounts share one Python session.
|
||||
pub fn sign_all(&self, hash: &[u8; 32], pin: &str) -> Result<Vec<(Signature, PublicKey)>> {
|
||||
let mut sigs: Vec<(Signature, PublicKey)> = self
|
||||
.local
|
||||
.iter()
|
||||
.map(|(_, key)| {
|
||||
(
|
||||
Signature::new(key, hash),
|
||||
PublicKey::new_from_private_key(key),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !self.keycard.is_empty() {
|
||||
pyo3::Python::with_gil(|py| -> pyo3::PyResult<()> {
|
||||
python_path::add_python_path(py)?;
|
||||
let wallet = KeycardWallet::new(py)?;
|
||||
wallet.connect(py, pin)?;
|
||||
for (_, path) in &self.keycard {
|
||||
sigs.push(wallet.sign_message_for_path(py, path, hash)?);
|
||||
}
|
||||
drop(wallet.close_session(py));
|
||||
Ok(())
|
||||
})
|
||||
.map_err(anyhow::Error::from)?;
|
||||
}
|
||||
|
||||
Ok(sigs)
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazily opens and reuses a single Keycard session for all keycard signers in one transaction.
|
||||
pub struct KeycardSessionContext {
|
||||
pin: String,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user