diff --git a/nssa/program_methods/guest/src/bin/authenticated_transfer.rs b/nssa/program_methods/guest/src/bin/authenticated_transfer.rs index 210e3f0..3336ea9 100644 --- a/nssa/program_methods/guest/src/bin/authenticated_transfer.rs +++ b/nssa/program_methods/guest/src/bin/authenticated_transfer.rs @@ -1,4 +1,7 @@ -use nssa_core::program::{ProgramInput, read_nssa_inputs, write_nssa_outputs}; +use nssa_core::{ + account::Account, + program::{ProgramInput, read_nssa_inputs, write_nssa_outputs}, +}; /// A transfer of balance program. /// To be used both in public and private contexts. @@ -10,28 +13,40 @@ fn main() { instruction: balance_to_move, } = read_nssa_inputs(); - // Continue only if input_accounts is an array of two elements - let [sender, receiver] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, - }; + if pre_states.len() == 1 { + // Claim account + let account_to_claim = pre_states[0].account.clone(); + let is_authorized = pre_states[0].is_authorized; + if account_to_claim == Account::default() && balance_to_move == 0 && is_authorized { + write_nssa_outputs(pre_states, vec![account_to_claim]); + } else { + panic!("Invalid params"); + } + } else { + // Transfer - // Continue only if the sender has authorized this operation - if !sender.is_authorized { - return; + // Continue only if input_accounts is an array of two elements + let [sender, receiver] = match pre_states.try_into() { + Ok(array) => array, + Err(_) => return, + }; + + // Continue only if the sender has authorized this operation + if !sender.is_authorized { + return; + } + + // Continue only if the sender has enough balance + if sender.account.balance < balance_to_move { + return; + } + + // Create accounts post states, with updated balances + let mut sender_post = sender.account.clone(); + let mut receiver_post = receiver.account.clone(); + sender_post.balance -= balance_to_move; + receiver_post.balance += balance_to_move; + + write_nssa_outputs(vec![sender, receiver], vec![sender_post, receiver_post]); } - - // Continue only if the sender has enough balance - if sender.account.balance < balance_to_move { - return; - } - - // Create accounts post states, with updated balances - let mut sender_post = sender.account.clone(); - let mut receiver_post = receiver.account.clone(); - sender_post.balance -= balance_to_move; - receiver_post.balance += balance_to_move; - - write_nssa_outputs(vec![sender, receiver], vec![sender_post, receiver_post]); } - diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index 2ec5eae..8041aa0 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -15,12 +15,12 @@ pub mod public_transaction; mod signature; mod state; -pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; pub use nssa_core::account::{Account, AccountId}; pub use nssa_core::address::Address; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, }; +pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; pub use public_transaction::PublicTransaction; pub use signature::PrivateKey; pub use signature::PublicKey; diff --git a/nssa/src/program.rs b/nssa/src/program.rs index b229241..f6df8fe 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -1,11 +1,11 @@ -use nssa_core::{ - account::{Account, AccountWithMetadata}, - program::{InstructionData, ProgramId, ProgramOutput}, -}; use crate::program_methods::{ AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, TOKEN_ID, }; +use nssa_core::{ + account::{Account, AccountWithMetadata}, + program::{InstructionData, ProgramId, ProgramOutput}, +}; use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use serde::Serialize; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 12505ff..859a2ed 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -11,7 +11,7 @@ use anyhow::Result; use chain_storage::WalletChainStore; use config::WalletConfig; use log::info; -use nssa::{program::Program, Account, Address}; +use nssa::{Account, Address, program::Program}; use clap::{Parser, Subcommand}; use nssa_core::Commitment; @@ -379,7 +379,9 @@ pub enum Command { }, // Check the wallet can connect to the node and builtin local programs // match the remote versions - CheckHealth { } + CheckHealth {}, + // Register a public account owned by the authenticated transfer program + RegisterAccountForAuthenticatedTransfer {}, } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config @@ -850,9 +852,14 @@ pub async fn execute_subcommand(command: Command) -> Result { - let remote_program_ids = wallet_core.sequencer_client.get_program_ids().await.expect("Error fetching program ids"); - let Some(authenticated_transfer_id) = remote_program_ids.get("authenticated_transfer") else { + Command::CheckHealth {} => { + let remote_program_ids = wallet_core + .sequencer_client + .get_program_ids() + .await + .expect("Error fetching program ids"); + let Some(authenticated_transfer_id) = remote_program_ids.get("authenticated_transfer") + else { panic!("Missing authenticated transfer ID from remote"); }; if authenticated_transfer_id != &Program::authenticated_transfer_program().id() { @@ -873,6 +880,25 @@ pub async fn execute_subcommand(command: Command) -> Result { + let addr = wallet_core.create_new_account_public(); + + println!("Generated new account with addr {addr}"); + + let path = wallet_core.store_persistent_accounts()?; + + println!("Stored persistent accounts at {path:#?}"); + + let res = wallet_core + .register_account_under_authenticated_transfers_programs(addr) + .await?; + + println!("Results of tx send is {res:#?}"); + + let _transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?; + SubcommandReturnValue::Empty } }; diff --git a/wallet/src/token_transfers/public.rs b/wallet/src/token_transfers/public.rs index 22d50eb..80db91d 100644 --- a/wallet/src/token_transfers/public.rs +++ b/wallet/src/token_transfers/public.rs @@ -42,4 +42,30 @@ impl WalletCore { Err(ExecutionFailureKind::InsufficientFundsError) } } + + pub async fn register_account_under_authenticated_transfers_programs( + &self, + from: Address, + ) -> Result { + let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else { + return Err(ExecutionFailureKind::SequencerError); + }; + + let instruction:u128 = 0; + let addresses = vec![from]; + let program_id = Program::authenticated_transfer_program().id(); + let message = Message::try_new(program_id, addresses, nonces, instruction).unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, &[signing_key]); + + let tx = PublicTransaction::new(message, witness_set); + + Ok(self.sequencer_client.send_tx_public(tx).await?) + } }