2026-05-14 21:19:25 -04:00
|
|
|
use authenticated_transfer_core::Instruction as AuthTransferInstruction;
|
2026-03-13 22:38:23 +03:00
|
|
|
use common::{HashType, transaction::NSSATransaction};
|
2025-10-03 15:59:27 -03:00
|
|
|
use nssa::{
|
2025-11-24 17:09:30 +03:00
|
|
|
AccountId, PublicTransaction,
|
2025-10-03 15:59:27 -03:00
|
|
|
program::Program,
|
|
|
|
|
public_transaction::{Message, WitnessSet},
|
|
|
|
|
};
|
2026-04-30 19:02:33 -04:00
|
|
|
use pyo3::exceptions::PyRuntimeError;
|
2026-03-13 22:38:23 +03:00
|
|
|
use sequencer_service_rpc::RpcClient as _;
|
2025-09-22 16:38:25 +03:00
|
|
|
|
2025-11-30 01:57:59 +03:00
|
|
|
use super::NativeTokenTransfer;
|
2026-05-14 21:19:25 -04:00
|
|
|
use crate::{
|
2026-05-15 09:07:35 -04:00
|
|
|
ExecutionFailureKind, cli::CliAccountMention, helperfunctions::read_pin,
|
2026-05-14 21:19:25 -04:00
|
|
|
signing::KeycardSessionContext,
|
|
|
|
|
};
|
2025-09-22 16:38:25 +03:00
|
|
|
|
2025-11-30 01:57:59 +03:00
|
|
|
impl NativeTokenTransfer<'_> {
|
|
|
|
|
pub async fn send_public_transfer(
|
2025-09-22 16:38:25 +03:00
|
|
|
&self,
|
2025-11-24 17:09:30 +03:00
|
|
|
from: AccountId,
|
|
|
|
|
to: AccountId,
|
2025-09-22 16:38:25 +03:00
|
|
|
balance_to_move: u128,
|
2026-05-14 21:19:25 -04:00
|
|
|
from_mention: &CliAccountMention,
|
|
|
|
|
to_mention: &CliAccountMention,
|
2026-03-13 22:38:23 +03:00
|
|
|
) -> Result<HashType, ExecutionFailureKind> {
|
2026-05-15 09:07:35 -04:00
|
|
|
let from_signer = from_mention.to_signer(self.0).map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))
|
|
|
|
|
})?;
|
|
|
|
|
let to_signer = to_mention.to_recipient_signer(self.0).map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))
|
|
|
|
|
})?;
|
2026-05-14 21:19:25 -04:00
|
|
|
|
2026-04-28 14:13:04 -04:00
|
|
|
let account_ids = vec![from, to];
|
2026-05-14 21:19:25 -04:00
|
|
|
let signing_ids: Vec<AccountId> = if to_signer.needs_signature() {
|
|
|
|
|
vec![from, to]
|
|
|
|
|
} else {
|
|
|
|
|
vec![from]
|
|
|
|
|
};
|
2026-04-21 13:40:15 -04:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
let program_id = Program::authenticated_transfer_program().id();
|
2026-04-30 19:02:33 -04:00
|
|
|
let nonces = self
|
2026-04-28 20:48:02 -04:00
|
|
|
.0
|
2026-05-14 21:19:25 -04:00
|
|
|
.get_accounts_nonces(signing_ids)
|
2026-04-28 20:48:02 -04:00
|
|
|
.await
|
|
|
|
|
.map_err(ExecutionFailureKind::SequencerError)?;
|
2026-04-21 13:40:15 -04:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
let message = Message::try_new(
|
|
|
|
|
program_id,
|
|
|
|
|
account_ids,
|
|
|
|
|
nonces,
|
2026-05-15 09:07:35 -04:00
|
|
|
AuthTransferInstruction::Transfer {
|
|
|
|
|
amount: balance_to_move,
|
|
|
|
|
},
|
2026-05-14 21:19:25 -04:00
|
|
|
)
|
|
|
|
|
.map_err(ExecutionFailureKind::TransactionBuildError)?;
|
|
|
|
|
|
|
|
|
|
let pin = if from_mention.is_keycard() || to_mention.is_keycard() {
|
|
|
|
|
read_pin()
|
2026-05-15 09:07:35 -04:00
|
|
|
.map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(
|
|
|
|
|
e.to_string(),
|
|
|
|
|
))
|
|
|
|
|
})?
|
2026-05-14 21:19:25 -04:00
|
|
|
.as_str()
|
|
|
|
|
.to_owned()
|
2026-04-30 19:02:33 -04:00
|
|
|
} else {
|
2026-05-14 21:19:25 -04:00
|
|
|
String::new()
|
2026-04-30 19:02:33 -04:00
|
|
|
};
|
2025-09-22 16:38:25 +03:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
let witness_set = pyo3::Python::with_gil(|py| -> pyo3::PyResult<WitnessSet> {
|
|
|
|
|
let mut ctx = KeycardSessionContext::new(&pin);
|
|
|
|
|
let hash = message.hash();
|
|
|
|
|
|
|
|
|
|
let (from_sig, from_pk) = from_signer
|
|
|
|
|
.sign(self.0, &mut ctx, py, &hash)
|
|
|
|
|
.expect("from signer always produces a signature")
|
|
|
|
|
.map_err(|e| pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
|
|
|
|
|
|
|
|
|
|
let sigs_and_keys = match to_signer
|
|
|
|
|
.sign(self.0, &mut ctx, py, &hash)
|
|
|
|
|
.transpose()
|
|
|
|
|
.map_err(|e| pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))?
|
|
|
|
|
{
|
|
|
|
|
Some((to_sig, to_pk)) => vec![(from_sig, from_pk), (to_sig, to_pk)],
|
|
|
|
|
None => vec![(from_sig, from_pk)],
|
|
|
|
|
};
|
2026-04-28 14:13:04 -04:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
ctx.close(py);
|
|
|
|
|
Ok(WitnessSet::from_raw_parts(sigs_and_keys))
|
|
|
|
|
})
|
|
|
|
|
.map_err(ExecutionFailureKind::KeycardError)?;
|
|
|
|
|
|
|
|
|
|
let tx = PublicTransaction::new(message, witness_set);
|
2026-04-28 14:13:04 -04:00
|
|
|
Ok(self
|
|
|
|
|
.0
|
|
|
|
|
.sequencer_client
|
|
|
|
|
.send_transaction(NSSATransaction::Public(tx))
|
|
|
|
|
.await?)
|
2025-09-22 16:38:25 +03:00
|
|
|
}
|
2025-10-10 17:47:23 -03:00
|
|
|
|
2025-11-30 01:57:59 +03:00
|
|
|
pub async fn register_account(
|
2025-10-10 17:47:23 -03:00
|
|
|
&self,
|
2025-11-24 17:09:30 +03:00
|
|
|
from: AccountId,
|
2026-05-14 21:19:25 -04:00
|
|
|
account_mention: &CliAccountMention,
|
2026-03-13 22:38:23 +03:00
|
|
|
) -> Result<HashType, ExecutionFailureKind> {
|
2026-03-04 18:42:33 +03:00
|
|
|
let nonces = self
|
|
|
|
|
.0
|
|
|
|
|
.get_accounts_nonces(vec![from])
|
|
|
|
|
.await
|
|
|
|
|
.map_err(ExecutionFailureKind::SequencerError)?;
|
2025-10-10 17:47:23 -03:00
|
|
|
|
2025-11-24 17:09:30 +03:00
|
|
|
let account_ids = vec![from];
|
2025-10-10 17:47:23 -03:00
|
|
|
let program_id = Program::authenticated_transfer_program().id();
|
2026-05-14 21:19:25 -04:00
|
|
|
let message = Message::try_new(
|
|
|
|
|
program_id,
|
|
|
|
|
account_ids,
|
|
|
|
|
nonces,
|
|
|
|
|
AuthTransferInstruction::Initialize,
|
|
|
|
|
)
|
|
|
|
|
.map_err(ExecutionFailureKind::TransactionBuildError)?;
|
|
|
|
|
|
2026-05-15 09:07:35 -04:00
|
|
|
let signer = account_mention.to_signer(self.0).map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))
|
|
|
|
|
})?;
|
2026-05-14 21:19:25 -04:00
|
|
|
|
|
|
|
|
let pin = if account_mention.is_keycard() {
|
|
|
|
|
read_pin()
|
2026-05-15 09:07:35 -04:00
|
|
|
.map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(
|
|
|
|
|
e.to_string(),
|
|
|
|
|
))
|
|
|
|
|
})?
|
2026-05-14 21:19:25 -04:00
|
|
|
.as_str()
|
|
|
|
|
.to_owned()
|
2026-04-30 19:02:33 -04:00
|
|
|
} else {
|
2026-05-14 21:19:25 -04:00
|
|
|
String::new()
|
|
|
|
|
};
|
2026-04-23 17:45:43 -04:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
let witness_set = pyo3::Python::with_gil(|py| -> pyo3::PyResult<WitnessSet> {
|
|
|
|
|
let mut ctx = KeycardSessionContext::new(&pin);
|
|
|
|
|
let hash = message.hash();
|
2025-10-10 17:47:23 -03:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
let (sig, pk) = signer
|
|
|
|
|
.sign(self.0, &mut ctx, py, &hash)
|
|
|
|
|
.expect("account signer always produces a signature")
|
|
|
|
|
.map_err(|e| pyo3::PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
|
2025-10-10 17:47:23 -03:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
ctx.close(py);
|
|
|
|
|
Ok(WitnessSet::from_raw_parts(vec![(sig, pk)]))
|
|
|
|
|
})
|
|
|
|
|
.map_err(ExecutionFailureKind::KeycardError)?;
|
2025-10-10 17:47:23 -03:00
|
|
|
|
2026-05-14 21:19:25 -04:00
|
|
|
let tx = PublicTransaction::new(message, witness_set);
|
2026-03-13 22:38:23 +03:00
|
|
|
Ok(self
|
|
|
|
|
.0
|
|
|
|
|
.sequencer_client
|
|
|
|
|
.send_transaction(NSSATransaction::Public(tx))
|
|
|
|
|
.await?)
|
2025-10-10 17:47:23 -03:00
|
|
|
}
|
2025-09-22 16:38:25 +03:00
|
|
|
}
|