2026-03-13 22:38:23 +03:00
|
|
|
use common::{HashType, transaction::NSSATransaction};
|
2026-04-24 22:10:04 -04:00
|
|
|
use keycard_wallet::KeycardWallet;
|
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-04-24 22:10:04 -04:00
|
|
|
use crate::{ExecutionFailureKind, WalletCore};
|
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-04-30 19:02:33 -04:00
|
|
|
from_key_path: Option<&str>,
|
|
|
|
|
to_key_path: Option<&str>,
|
2026-03-13 22:38:23 +03:00
|
|
|
) -> Result<HashType, ExecutionFailureKind> {
|
2026-03-04 18:42:33 +03:00
|
|
|
let balance = self
|
|
|
|
|
.0
|
|
|
|
|
.get_account_balance(from)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(ExecutionFailureKind::SequencerError)?;
|
2025-09-22 16:38:25 +03:00
|
|
|
|
2026-04-28 14:13:04 -04:00
|
|
|
if balance < balance_to_move {
|
|
|
|
|
return Err(ExecutionFailureKind::InsufficientFundsError);
|
|
|
|
|
}
|
2026-03-27 21:43:28 +03:00
|
|
|
|
2026-04-28 14:13:04 -04:00
|
|
|
let account_ids = vec![from, to];
|
|
|
|
|
let program_id = Program::authenticated_transfer_program().id();
|
2026-04-21 13:40:15 -04:00
|
|
|
|
2026-04-30 19:02:33 -04:00
|
|
|
let nonces = self
|
2026-04-28 20:48:02 -04:00
|
|
|
.0
|
2026-04-30 19:02:33 -04:00
|
|
|
.get_accounts_nonces(account_ids.clone())
|
2026-04-28 20:48:02 -04:00
|
|
|
.await
|
|
|
|
|
.map_err(ExecutionFailureKind::SequencerError)?;
|
2026-04-21 13:40:15 -04:00
|
|
|
|
2026-04-30 19:02:33 -04:00
|
|
|
let message = Message::try_new(program_id, account_ids, nonces, balance_to_move)
|
|
|
|
|
.map_err(ExecutionFailureKind::TransactionBuildError)?;
|
|
|
|
|
|
|
|
|
|
let witness_set = if let Some(from_key_path) = from_key_path {
|
|
|
|
|
let pin = crate::helperfunctions::read_pin().map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(
|
|
|
|
|
e.to_string(),
|
|
|
|
|
))
|
|
|
|
|
})?;
|
|
|
|
|
let msg_hash = message.hash_message();
|
|
|
|
|
let (from_sig, from_pk) =
|
|
|
|
|
KeycardWallet::sign_message_for_path_with_connect(&pin, from_key_path, &msg_hash)?;
|
|
|
|
|
if let Some(to_key_path) = to_key_path {
|
|
|
|
|
let (to_sig, to_pk) = KeycardWallet::sign_message_for_path_with_connect(
|
|
|
|
|
&pin,
|
|
|
|
|
to_key_path,
|
|
|
|
|
&msg_hash,
|
|
|
|
|
)?;
|
|
|
|
|
WitnessSet::from_list(&[from_sig, to_sig], &[from_pk, to_pk])
|
|
|
|
|
} else {
|
|
|
|
|
WitnessSet::from_list(&[from_sig], &[from_pk])
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2026-04-30 19:05:18 -04:00
|
|
|
// Silently skips accounts without signing keys
|
|
|
|
|
let witness_set = WalletCore::sign_public_message(self.0, &message, &sign_ids)
|
|
|
|
|
.expect("`WalletCore::sign_public_message()` failed to produce a signature for a NativeTokenTransfer.");
|
2026-04-30 19:02:33 -04:00
|
|
|
};
|
2025-09-22 16:38:25 +03:00
|
|
|
|
2026-04-28 14:13:04 -04:00
|
|
|
let tx = PublicTransaction::new(message, witness_set);
|
|
|
|
|
|
|
|
|
|
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-04-30 19:02:33 -04:00
|
|
|
key_path: Option<&str>,
|
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
|
|
|
|
|
|
|
|
let instruction: u128 = 0;
|
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-04-26 21:29:54 -04:00
|
|
|
let message = Message::try_new(program_id, account_ids, nonces, instruction)
|
2026-04-30 19:02:33 -04:00
|
|
|
.map_err(ExecutionFailureKind::TransactionBuildError)?;
|
|
|
|
|
|
|
|
|
|
let witness_set = if let Some(key_path) = key_path {
|
|
|
|
|
let pin = crate::helperfunctions::read_pin().map_err(|e| {
|
|
|
|
|
ExecutionFailureKind::KeycardError(pyo3::PyErr::new::<PyRuntimeError, _>(
|
|
|
|
|
e.to_string(),
|
|
|
|
|
))
|
|
|
|
|
})?;
|
|
|
|
|
let (signature, pub_key) = KeycardWallet::sign_message_for_path_with_connect(
|
|
|
|
|
&pin,
|
|
|
|
|
key_path,
|
|
|
|
|
&message.hash_message(),
|
|
|
|
|
)?;
|
|
|
|
|
WitnessSet::from_list(&[signature], &[pub_key])
|
|
|
|
|
} else {
|
2026-04-23 17:45:43 -04:00
|
|
|
let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from);
|
|
|
|
|
|
|
|
|
|
let Some(signing_key) = signing_key else {
|
|
|
|
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
|
|
|
|
};
|
2025-10-10 17:47:23 -03:00
|
|
|
|
2026-04-23 17:45:43 -04:00
|
|
|
WitnessSet::for_message(&message, &[signing_key])
|
|
|
|
|
};
|
2025-10-10 17:47:23 -03: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
|
|
|
}
|