2025-11-26 00:27:20 +03:00
use std ::collections ::{ HashMap , HashSet } ;
use nssa_core ::{
Commitment , CommitmentSetDigest , DUMMY_COMMITMENT , MembershipProof , Nullifier ,
account ::{ Account , AccountId } ,
program ::ProgramId ,
} ;
2025-08-06 20:05:04 -03:00
use crate ::{
2025-09-30 15:30:28 -03:00
error ::NssaError , merkle_tree ::MerkleTree ,
2025-08-14 15:34:21 -03:00
privacy_preserving_transaction ::PrivacyPreservingTransaction , program ::Program ,
2025-10-15 17:25:26 -03:00
program_deployment_transaction ::ProgramDeploymentTransaction ,
2025-08-14 15:34:21 -03:00
public_transaction ::PublicTransaction ,
2025-08-06 20:05:04 -03:00
} ;
2025-08-14 15:34:21 -03:00
2025-11-12 19:55:02 -03:00
pub const MAX_NUMBER_CHAINED_CALLS : usize = 10 ;
2025-08-25 07:44:56 -03:00
pub ( crate ) struct CommitmentSet {
merkle_tree : MerkleTree ,
commitments : HashMap < Commitment , usize > ,
2025-08-27 16:24:20 -03:00
root_history : HashSet < CommitmentSetDigest > ,
2025-08-25 07:44:56 -03:00
}
2025-08-14 15:34:21 -03:00
impl CommitmentSet {
2025-08-22 10:34:09 -03:00
pub ( crate ) fn digest ( & self ) -> CommitmentSetDigest {
2025-08-25 07:44:56 -03:00
self . merkle_tree . root ( )
2025-08-14 15:34:21 -03:00
}
2025-09-05 20:48:56 -04:00
/// Queries the `CommitmentSet` for a membership proof of commitment
2025-08-27 16:24:20 -03:00
pub fn get_proof_for ( & self , commitment : & Commitment ) -> Option < MembershipProof > {
2025-08-25 07:44:56 -03:00
let index = * self . commitments . get ( commitment ) ? ;
2025-08-27 16:24:20 -03:00
self . merkle_tree
2025-08-25 07:44:56 -03:00
. get_authentication_path_for ( index )
2025-08-27 16:24:20 -03:00
. map ( | path | ( index , path ) )
2025-08-14 15:34:21 -03:00
}
2025-08-18 14:28:26 -03:00
2025-09-05 20:48:47 -04:00
/// Inserts a list of commitments to the `CommitmentSet`.
2025-08-22 13:42:37 -03:00
pub ( crate ) fn extend ( & mut self , commitments : & [ Commitment ] ) {
2025-08-25 07:44:56 -03:00
for commitment in commitments . iter ( ) . cloned ( ) {
let index = self . merkle_tree . insert ( commitment . to_byte_array ( ) ) ;
self . commitments . insert ( commitment , index ) ;
2025-08-22 10:34:09 -03:00
}
2025-08-25 09:22:59 -03:00
self . root_history . insert ( self . digest ( ) ) ;
2025-08-22 10:34:09 -03:00
}
2025-08-18 14:28:26 -03:00
fn contains ( & self , commitment : & Commitment ) -> bool {
2025-08-25 07:44:56 -03:00
self . commitments . contains_key ( commitment )
}
2025-09-05 20:48:26 -04:00
/// Initializes an empty `CommitmentSet` with a given capacity.
2025-09-05 16:38:34 -04:00
/// If the capacity is not a power_of_two, then capacity is taken
2025-09-05 16:21:46 -04:00
/// to be the next power_of_two.
2025-08-25 07:44:56 -03:00
pub ( crate ) fn with_capacity ( capacity : usize ) -> CommitmentSet {
Self {
merkle_tree : MerkleTree ::with_capacity ( capacity ) ,
commitments : HashMap ::new ( ) ,
2025-08-25 09:22:59 -03:00
root_history : HashSet ::new ( ) ,
2025-08-25 07:44:56 -03:00
}
2025-08-18 14:28:26 -03:00
}
2025-08-14 15:34:21 -03:00
}
2025-08-18 07:39:41 -03:00
2025-08-14 15:34:21 -03:00
type NullifierSet = HashSet < Nullifier > ;
2025-08-06 20:05:04 -03:00
2025-10-16 16:24:18 -03:00
pub struct V02State {
2025-11-24 17:09:30 +03:00
public_state : HashMap < AccountId , Account > ,
2025-08-27 16:24:20 -03:00
private_state : ( CommitmentSet , NullifierSet ) ,
2025-10-14 17:15:04 -03:00
programs : HashMap < ProgramId , Program > ,
2025-08-06 20:05:04 -03:00
}
2025-10-16 16:24:18 -03:00
impl V02State {
2025-09-18 15:59:17 +03:00
pub fn new_with_genesis_accounts (
2025-11-24 17:09:30 +03:00
initial_data : & [ ( AccountId , u128 ) ] ,
2025-09-18 15:59:17 +03:00
initial_commitments : & [ nssa_core ::Commitment ] ,
) -> Self {
2025-08-10 00:53:53 -03:00
let authenticated_transfer_program = Program ::authenticated_transfer_program ( ) ;
2025-08-07 15:19:06 -03:00
let public_state = initial_data
2025-08-09 19:20:19 -03:00
. iter ( )
. copied ( )
2025-11-24 17:09:30 +03:00
. map ( | ( account_id , balance ) | {
2025-08-09 18:40:32 -03:00
let account = Account {
2025-08-09 19:20:19 -03:00
balance ,
2025-08-10 00:53:53 -03:00
program_owner : authenticated_transfer_program . id ( ) ,
2025-08-09 18:40:32 -03:00
.. Account ::default ( )
} ;
2025-11-24 17:09:30 +03:00
( account_id , account )
2025-08-07 15:19:06 -03:00
} )
. collect ( ) ;
2025-08-08 16:19:50 -03:00
2025-09-18 15:59:17 +03:00
let mut private_state = CommitmentSet ::with_capacity ( 32 ) ;
2025-10-03 20:44:29 -03:00
private_state . extend ( & [ DUMMY_COMMITMENT ] ) ;
2025-09-18 15:59:17 +03:00
private_state . extend ( initial_commitments ) ;
2025-08-10 09:57:10 -03:00
let mut this = Self {
2025-08-08 16:19:50 -03:00
public_state ,
2025-09-18 15:59:17 +03:00
private_state : ( private_state , NullifierSet ::new ( ) ) ,
2025-10-14 17:15:04 -03:00
programs : HashMap ::new ( ) ,
2025-08-10 09:57:10 -03:00
} ;
this . insert_program ( Program ::authenticated_transfer_program ( ) ) ;
2025-09-12 15:18:25 -03:00
this . insert_program ( Program ::token ( ) ) ;
2025-12-17 14:21:36 +02:00
this . insert_program ( Program ::amm ( ) ) ;
2025-08-10 09:57:10 -03:00
this
}
2025-08-12 21:27:27 -03:00
pub ( crate ) fn insert_program ( & mut self , program : Program ) {
2025-10-14 17:15:04 -03:00
self . programs . insert ( program . id ( ) , program ) ;
2025-08-07 15:19:06 -03:00
}
2025-08-09 19:49:07 -03:00
pub fn transition_from_public_transaction (
& mut self ,
tx : & PublicTransaction ,
) -> Result < ( ) , NssaError > {
2025-08-14 16:20:09 -03:00
let state_diff = tx . validate_and_produce_public_state_diff ( self ) ? ;
2025-08-06 20:05:04 -03:00
2025-11-24 17:09:30 +03:00
for ( account_id , post ) in state_diff . into_iter ( ) {
let current_account = self . get_account_by_id_mut ( account_id ) ;
2025-08-14 14:48:20 -03:00
2025-08-06 20:05:04 -03:00
* current_account = post ;
}
2025-11-24 17:09:30 +03:00
for account_id in tx . signer_account_ids ( ) {
let current_account = self . get_account_by_id_mut ( account_id ) ;
2025-08-06 20:05:04 -03:00
current_account . nonce + = 1 ;
}
2025-08-09 20:35:44 -03:00
2025-08-06 20:05:04 -03:00
Ok ( ( ) )
}
2025-08-14 15:34:21 -03:00
pub fn transition_from_privacy_preserving_transaction (
& mut self ,
tx : & PrivacyPreservingTransaction ,
) -> Result < ( ) , NssaError > {
// 1. Verify the transaction satisfies acceptance criteria
2025-08-14 16:20:09 -03:00
let public_state_diff = tx . validate_and_produce_public_state_diff ( self ) ? ;
2025-08-14 15:34:21 -03:00
let message = tx . message ( ) ;
// 2. Add new commitments
2025-08-21 10:19:08 -03:00
self . private_state . 0. extend ( & message . new_commitments ) ;
2025-08-14 15:34:21 -03:00
// 3. Add new nullifiers
2025-08-25 09:22:59 -03:00
let new_nullifiers = message
. new_nullifiers
. iter ( )
. cloned ( )
. map ( | ( nullifier , _ ) | nullifier )
. collect ::< Vec < Nullifier > > ( ) ;
self . private_state . 1. extend ( new_nullifiers ) ;
2025-08-14 15:34:21 -03:00
// 4. Update public accounts
2025-11-24 17:09:30 +03:00
for ( account_id , post ) in public_state_diff . into_iter ( ) {
let current_account = self . get_account_by_id_mut ( account_id ) ;
2025-08-14 15:34:21 -03:00
* current_account = post ;
}
2025-12-11 08:59:28 -05:00
// 5. Increment nonces for public signers
for account_id in tx . signer_account_ids ( ) {
let current_account = self . get_account_by_id_mut ( account_id ) ;
current_account . nonce + = 1 ;
}
2025-08-14 15:34:21 -03:00
Ok ( ( ) )
}
2025-10-15 17:25:26 -03:00
pub fn transition_from_program_deployment_transaction (
& mut self ,
tx : & ProgramDeploymentTransaction ,
) -> Result < ( ) , NssaError > {
let program = tx . validate_and_produce_public_state_diff ( self ) ? ;
self . insert_program ( program ) ;
Ok ( ( ) )
}
2025-11-24 17:09:30 +03:00
fn get_account_by_id_mut ( & mut self , account_id : AccountId ) -> & mut Account {
self . public_state . entry ( account_id ) . or_default ( )
2025-08-06 20:05:04 -03:00
}
2025-11-24 17:09:30 +03:00
pub fn get_account_by_id ( & self , account_id : & AccountId ) -> Account {
2025-08-06 20:05:04 -03:00
self . public_state
2025-11-24 17:09:30 +03:00
. get ( account_id )
2025-08-06 20:05:04 -03:00
. cloned ( )
. unwrap_or ( Account ::default ( ) )
}
2025-08-27 16:24:20 -03:00
pub fn get_proof_for_commitment ( & self , commitment : & Commitment ) -> Option < MembershipProof > {
self . private_state . 0. get_proof_for ( commitment )
}
2025-10-15 17:25:26 -03:00
pub ( crate ) fn programs ( & self ) -> & HashMap < ProgramId , Program > {
2025-10-14 17:15:04 -03:00
& self . programs
2025-08-06 20:05:04 -03:00
}
2025-08-14 16:20:09 -03:00
pub fn commitment_set_digest ( & self ) -> CommitmentSetDigest {
self . private_state . 0. digest ( )
}
pub ( crate ) fn check_commitments_are_new (
& self ,
new_commitments : & [ Commitment ] ,
) -> Result < ( ) , NssaError > {
2025-08-18 14:28:26 -03:00
for commitment in new_commitments . iter ( ) {
if self . private_state . 0. contains ( commitment ) {
return Err ( NssaError ::InvalidInput (
" Commitment already seen " . to_string ( ) ,
) ) ;
}
}
Ok ( ( ) )
2025-08-14 16:20:09 -03:00
}
2025-08-25 09:22:59 -03:00
pub ( crate ) fn check_nullifiers_are_valid (
2025-08-14 16:20:09 -03:00
& self ,
2025-08-25 09:22:59 -03:00
new_nullifiers : & [ ( Nullifier , CommitmentSetDigest ) ] ,
2025-08-14 16:20:09 -03:00
) -> Result < ( ) , NssaError > {
2025-08-25 09:22:59 -03:00
for ( nullifier , digest ) in new_nullifiers . iter ( ) {
2025-08-18 14:28:26 -03:00
if self . private_state . 1. contains ( nullifier ) {
return Err ( NssaError ::InvalidInput (
" Nullifier already seen " . to_string ( ) ,
) ) ;
}
2025-08-25 09:22:59 -03:00
if ! self . private_state . 0. root_history . contains ( digest ) {
return Err ( NssaError ::InvalidInput (
" Unrecognized commitment set digest " . to_string ( ) ,
) ) ;
}
2025-08-18 14:28:26 -03:00
}
Ok ( ( ) )
2025-08-14 16:20:09 -03:00
}
2025-08-06 20:05:04 -03:00
}
2025-08-13 01:33:11 -03:00
2025-09-05 23:45:44 -03:00
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
2025-10-16 16:24:18 -03:00
impl V02State {
2025-11-24 17:09:30 +03:00
pub fn add_pinata_program ( & mut self , account_id : AccountId ) {
2025-09-04 17:05:12 -03:00
self . insert_program ( Program ::pinata ( ) ) ;
self . public_state . insert (
2025-11-24 17:09:30 +03:00
account_id ,
2025-09-04 17:05:12 -03:00
Account {
program_owner : Program ::pinata ( ) . id ( ) ,
balance : 1500 ,
// Difficulty: 3
2025-12-05 17:16:41 +03:00
data : vec ! [ 3 ; 33 ] . try_into ( ) . expect ( " should fit " ) ,
2025-09-04 17:05:12 -03:00
nonce : 0 ,
} ,
) ;
}
2025-11-28 11:10:00 -03:00
pub fn add_pinata_token_program ( & mut self , account_id : AccountId ) {
self . insert_program ( Program ::pinata_token ( ) ) ;
self . public_state . insert (
account_id ,
Account {
program_owner : Program ::pinata_token ( ) . id ( ) ,
// Difficulty: 3
2025-12-05 02:17:09 +03:00
data : vec ! [ 3 ; 33 ] . try_into ( ) . expect ( " should fit " ) ,
2025-11-28 11:10:00 -03:00
.. Account ::default ( )
} ,
) ;
}
2025-09-04 17:05:12 -03:00
}
2025-08-13 01:33:11 -03:00
#[ cfg(test) ]
2025-08-22 12:29:45 -03:00
pub mod tests {
2025-08-13 01:33:11 -03:00
use std ::collections ::HashMap ;
2025-11-26 00:27:20 +03:00
use nssa_core ::{
Commitment , Nullifier , NullifierPublicKey , NullifierSecretKey , SharedSecretKey ,
2025-12-05 02:17:09 +03:00
account ::{ Account , AccountId , AccountWithMetadata , Nonce , data ::Data } ,
2025-11-26 00:27:20 +03:00
encryption ::{ EphemeralPublicKey , IncomingViewingPublicKey , Scalar } ,
2025-11-27 13:49:56 -03:00
program ::{ PdaSeed , ProgramId } ,
2025-11-26 00:27:20 +03:00
} ;
2025-08-13 01:33:11 -03:00
use crate ::{
2025-11-24 17:09:30 +03:00
PublicKey , PublicTransaction , V02State ,
2025-08-21 14:32:57 -03:00
error ::NssaError ,
2025-09-02 12:38:31 -03:00
execute_and_prove ,
2025-08-21 14:32:57 -03:00
privacy_preserving_transaction ::{
2025-11-22 16:39:56 -03:00
PrivacyPreservingTransaction ,
circuit ::{ self , ProgramWithDependencies } ,
message ::Message ,
witness_set ::WitnessSet ,
2025-12-09 14:42:58 -05:00
} ,
program ::Program ,
2025-11-22 16:39:56 -03:00
public_transaction ,
2025-12-09 14:42:58 -05:00
signature ::PrivateKey ,
state ::MAX_NUMBER_CHAINED_CALLS ,
2025-08-13 01:33:11 -03:00
} ;
2025-08-26 14:53:02 -03:00
2025-08-13 01:33:11 -03:00
fn transfer_transaction (
2025-11-24 17:09:30 +03:00
from : AccountId ,
2025-08-13 01:33:11 -03:00
from_key : PrivateKey ,
nonce : u128 ,
2025-11-24 17:09:30 +03:00
to : AccountId ,
2025-08-13 01:33:11 -03:00
balance : u128 ,
) -> PublicTransaction {
2025-11-24 17:09:30 +03:00
let account_ids = vec! [ from , to ] ;
2025-08-13 01:33:11 -03:00
let nonces = vec! [ nonce ] ;
let program_id = Program ::authenticated_transfer_program ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , account_ids , nonces , balance ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ & from_key ] ) ;
PublicTransaction ::new ( message , witness_set )
}
#[ test ]
fn test_new_with_genesis ( ) {
let key1 = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
let key2 = PrivateKey ::try_new ( [ 2 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let addr1 = AccountId ::from ( & PublicKey ::new_from_private_key ( & key1 ) ) ;
let addr2 = AccountId ::from ( & PublicKey ::new_from_private_key ( & key2 ) ) ;
2025-08-13 13:42:00 +03:00
let initial_data = [ ( addr1 , 100 u128 ) , ( addr2 , 151 u128 ) ] ;
2025-09-12 17:13:37 -03:00
let authenticated_transfers_program = Program ::authenticated_transfer_program ( ) ;
2025-08-13 01:33:11 -03:00
let expected_public_state = {
let mut this = HashMap ::new ( ) ;
this . insert (
addr1 ,
Account {
balance : 100 ,
2025-09-12 17:13:37 -03:00
program_owner : authenticated_transfers_program . id ( ) ,
2025-08-13 01:33:11 -03:00
.. Account ::default ( )
} ,
) ;
this . insert (
addr2 ,
Account {
balance : 151 ,
2025-09-12 17:13:37 -03:00
program_owner : authenticated_transfers_program . id ( ) ,
2025-08-13 01:33:11 -03:00
.. Account ::default ( )
} ,
) ;
this
} ;
let expected_builtin_programs = {
let mut this = HashMap ::new ( ) ;
2025-09-12 17:13:37 -03:00
this . insert (
authenticated_transfers_program . id ( ) ,
authenticated_transfers_program ,
) ;
this . insert ( Program ::token ( ) . id ( ) , Program ::token ( ) ) ;
2025-08-13 01:33:11 -03:00
this
} ;
2025-10-16 16:24:18 -03:00
let state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) ;
2025-08-13 01:33:11 -03:00
assert_eq! ( state . public_state , expected_public_state ) ;
2025-10-14 17:15:04 -03:00
assert_eq! ( state . programs , expected_builtin_programs ) ;
2025-08-13 01:33:11 -03:00
}
#[ test ]
fn test_insert_program ( ) {
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] ) ;
2025-08-13 01:33:11 -03:00
let program_to_insert = Program ::simple_balance_transfer ( ) ;
let program_id = program_to_insert . id ( ) ;
2025-10-14 17:15:04 -03:00
assert! ( ! state . programs . contains_key ( & program_id ) ) ;
2025-08-13 01:33:11 -03:00
state . insert_program ( program_to_insert ) ;
2025-10-14 17:15:04 -03:00
assert! ( state . programs . contains_key ( & program_id ) ) ;
2025-08-13 01:33:11 -03:00
}
#[ test ]
2025-11-24 17:09:30 +03:00
fn test_get_account_by_account_id_non_default_account ( ) {
2025-08-13 01:33:11 -03:00
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
let initial_data = [ ( account_id , 100 u128 ) ] ;
2025-10-16 16:24:18 -03:00
let state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) ;
2025-11-24 17:09:30 +03:00
let expected_account = state . public_state . get ( & account_id ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
2025-11-24 17:09:30 +03:00
let account = state . get_account_by_id ( & account_id ) ;
2025-08-13 01:33:11 -03:00
assert_eq! ( & account , expected_account ) ;
}
#[ test ]
2025-11-24 17:09:30 +03:00
fn test_get_account_by_account_id_default_account ( ) {
let addr2 = AccountId ::new ( [ 0 ; 32 ] ) ;
2025-10-16 16:24:18 -03:00
let state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] ) ;
2025-08-13 01:33:11 -03:00
let expected_account = Account ::default ( ) ;
2025-11-24 17:09:30 +03:00
let account = state . get_account_by_id ( & addr2 ) ;
2025-08-13 01:33:11 -03:00
assert_eq! ( account , expected_account ) ;
}
#[ test ]
fn test_builtin_programs_getter ( ) {
2025-10-16 16:24:18 -03:00
let state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] ) ;
2025-08-13 01:33:11 -03:00
2025-10-15 17:25:26 -03:00
let builtin_programs = state . programs ( ) ;
2025-08-13 01:33:11 -03:00
2025-10-14 17:15:04 -03:00
assert_eq! ( builtin_programs , & state . programs ) ;
2025-08-13 01:33:11 -03:00
}
#[ test ]
fn transition_from_authenticated_transfer_program_invocation_default_account_destination ( ) {
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
let initial_data = [ ( account_id , 100 ) ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) ;
2025-11-24 17:09:30 +03:00
let from = account_id ;
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
assert_eq! ( state . get_account_by_id ( & to ) , Account ::default ( ) ) ;
2025-08-13 01:33:11 -03:00
let balance_to_move = 5 ;
2025-08-13 14:15:05 +03:00
let tx = transfer_transaction ( from , key , 0 , to , balance_to_move ) ;
2025-08-13 01:33:11 -03:00
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
assert_eq! ( state . get_account_by_id ( & from ) . balance , 95 ) ;
assert_eq! ( state . get_account_by_id ( & to ) . balance , 5 ) ;
assert_eq! ( state . get_account_by_id ( & from ) . nonce , 1 ) ;
assert_eq! ( state . get_account_by_id ( & to ) . nonce , 0 ) ;
2025-08-13 01:33:11 -03:00
}
#[ test ]
fn transition_from_authenticated_transfer_program_invocation_insuficient_balance ( ) {
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
let initial_data = [ ( account_id , 100 ) ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) ;
2025-11-24 17:09:30 +03:00
let from = account_id ;
2025-08-13 01:33:11 -03:00
let from_key = key ;
2025-11-24 17:09:30 +03:00
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
2025-08-13 01:33:11 -03:00
let balance_to_move = 101 ;
2025-11-24 17:09:30 +03:00
assert! ( state . get_account_by_id ( & from ) . balance < balance_to_move ) ;
2025-08-13 01:33:11 -03:00
2025-08-13 14:15:05 +03:00
let tx = transfer_transaction ( from , from_key , 0 , to , balance_to_move ) ;
2025-08-13 01:33:11 -03:00
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::ProgramExecutionFailed ( _ ) ) ) ) ;
2025-11-24 17:09:30 +03:00
assert_eq! ( state . get_account_by_id ( & from ) . balance , 100 ) ;
assert_eq! ( state . get_account_by_id ( & to ) . balance , 0 ) ;
assert_eq! ( state . get_account_by_id ( & from ) . nonce , 0 ) ;
assert_eq! ( state . get_account_by_id ( & to ) . nonce , 0 ) ;
2025-08-13 01:33:11 -03:00
}
#[ test ]
fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination ( ) {
let key1 = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
let key2 = PrivateKey ::try_new ( [ 2 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id1 = AccountId ::from ( & PublicKey ::new_from_private_key ( & key1 ) ) ;
let account_id2 = AccountId ::from ( & PublicKey ::new_from_private_key ( & key2 ) ) ;
let initial_data = [ ( account_id1 , 100 ) , ( account_id2 , 200 ) ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) ;
2025-11-24 17:09:30 +03:00
let from = account_id2 ;
2025-08-13 01:33:11 -03:00
let from_key = key2 ;
2025-11-24 17:09:30 +03:00
let to = account_id1 ;
assert_ne! ( state . get_account_by_id ( & to ) , Account ::default ( ) ) ;
2025-08-13 01:33:11 -03:00
let balance_to_move = 8 ;
2025-08-13 14:15:05 +03:00
let tx = transfer_transaction ( from , from_key , 0 , to , balance_to_move ) ;
2025-08-13 01:33:11 -03:00
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
assert_eq! ( state . get_account_by_id ( & from ) . balance , 192 ) ;
assert_eq! ( state . get_account_by_id ( & to ) . balance , 108 ) ;
assert_eq! ( state . get_account_by_id ( & from ) . nonce , 1 ) ;
assert_eq! ( state . get_account_by_id ( & to ) . nonce , 0 ) ;
2025-08-13 01:33:11 -03:00
}
#[ test ]
2025-10-30 10:52:31 -03:00
fn transition_from_sequence_of_authenticated_transfer_program_invocations ( ) {
2025-08-13 01:33:11 -03:00
let key1 = PrivateKey ::try_new ( [ 8 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id1 = AccountId ::from ( & PublicKey ::new_from_private_key ( & key1 ) ) ;
2025-08-13 01:33:11 -03:00
let key2 = PrivateKey ::try_new ( [ 2 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id2 = AccountId ::from ( & PublicKey ::new_from_private_key ( & key2 ) ) ;
let initial_data = [ ( account_id1 , 100 ) ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) ;
2025-11-24 17:09:30 +03:00
let account_id3 = AccountId ::new ( [ 3 ; 32 ] ) ;
2025-08-13 01:33:11 -03:00
let balance_to_move = 5 ;
2025-11-24 17:09:30 +03:00
let tx = transfer_transaction ( account_id1 , key1 , 0 , account_id2 , balance_to_move ) ;
2025-08-13 01:33:11 -03:00
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
let balance_to_move = 3 ;
2025-11-24 17:09:30 +03:00
let tx = transfer_transaction ( account_id2 , key2 , 0 , account_id3 , balance_to_move ) ;
2025-08-13 01:33:11 -03:00
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
assert_eq! ( state . get_account_by_id ( & account_id1 ) . balance , 95 ) ;
assert_eq! ( state . get_account_by_id ( & account_id2 ) . balance , 2 ) ;
assert_eq! ( state . get_account_by_id ( & account_id3 ) . balance , 3 ) ;
assert_eq! ( state . get_account_by_id ( & account_id1 ) . nonce , 1 ) ;
assert_eq! ( state . get_account_by_id ( & account_id2 ) . nonce , 1 ) ;
assert_eq! ( state . get_account_by_id ( & account_id3 ) . nonce , 0 ) ;
2025-08-13 01:33:11 -03:00
}
2025-10-16 16:24:18 -03:00
impl V02State {
2025-11-24 17:09:30 +03:00
pub fn force_insert_account ( & mut self , account_id : AccountId , account : Account ) {
self . public_state . insert ( account_id , account ) ;
2025-08-13 01:55:56 -03:00
}
2025-08-13 01:33:11 -03:00
/// Include test programs in the builtin programs map
pub fn with_test_programs ( mut self ) -> Self {
self . insert_program ( Program ::nonce_changer_program ( ) ) ;
self . insert_program ( Program ::extra_output_program ( ) ) ;
self . insert_program ( Program ::missing_output_program ( ) ) ;
self . insert_program ( Program ::program_owner_changer ( ) ) ;
self . insert_program ( Program ::simple_balance_transfer ( ) ) ;
self . insert_program ( Program ::data_changer ( ) ) ;
self . insert_program ( Program ::minter ( ) ) ;
self . insert_program ( Program ::burner ( ) ) ;
2025-10-29 15:34:11 -03:00
self . insert_program ( Program ::chain_caller ( ) ) ;
2025-11-20 21:02:18 -05:00
self . insert_program ( Program ::amm ( ) ) ;
2025-12-03 17:36:53 -03:00
self . insert_program ( Program ::claimer ( ) ) ;
2025-08-13 01:33:11 -03:00
self
}
pub fn with_non_default_accounts_but_default_program_owners ( mut self ) -> Self {
let account_with_default_values_except_balance = Account {
balance : 100 ,
.. Account ::default ( )
} ;
let account_with_default_values_except_nonce = Account {
nonce : 37 ,
.. Account ::default ( )
} ;
let account_with_default_values_except_data = Account {
2025-12-05 02:17:09 +03:00
data : vec ! [ 0xca , 0xfe ] . try_into ( ) . unwrap ( ) ,
2025-08-13 01:33:11 -03:00
.. Account ::default ( )
} ;
self . force_insert_account (
2025-11-24 17:09:30 +03:00
AccountId ::new ( [ 255 ; 32 ] ) ,
2025-08-13 01:33:11 -03:00
account_with_default_values_except_balance ,
) ;
self . force_insert_account (
2025-11-24 17:09:30 +03:00
AccountId ::new ( [ 254 ; 32 ] ) ,
2025-08-13 01:33:11 -03:00
account_with_default_values_except_nonce ,
) ;
self . force_insert_account (
2025-11-24 17:09:30 +03:00
AccountId ::new ( [ 253 ; 32 ] ) ,
2025-08-13 01:33:11 -03:00
account_with_default_values_except_data ,
) ;
self
}
pub fn with_account_owned_by_burner_program ( mut self ) -> Self {
let account = Account {
program_owner : Program ::burner ( ) . id ( ) ,
balance : 100 ,
.. Default ::default ( )
} ;
2025-11-24 17:09:30 +03:00
self . force_insert_account ( AccountId ::new ( [ 252 ; 32 ] ) , account ) ;
2025-08-13 01:33:11 -03:00
self
}
2025-08-22 10:34:09 -03:00
2025-08-22 12:29:45 -03:00
pub fn with_private_account ( mut self , keys : & TestPrivateKeys , account : & Account ) -> Self {
2025-08-27 16:24:20 -03:00
let commitment = Commitment ::new ( & keys . npk ( ) , account ) ;
2025-08-22 10:34:09 -03:00
self . private_state . 0. extend ( & [ commitment ] ) ;
2025-08-22 12:29:45 -03:00
self
2025-08-22 10:34:09 -03:00
}
2025-08-13 01:33:11 -03:00
}
#[ test ]
fn test_program_should_fail_if_modifies_nonces ( ) {
2025-11-24 17:09:30 +03:00
let initial_data = [ ( AccountId ::new ( [ 1 ; 32 ] ) , 100 ) ] ;
2025-09-18 15:59:17 +03:00
let mut state =
2025-10-16 16:24:18 -03:00
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let account_ids = vec! [ AccountId ::new ( [ 1 ; 32 ] ) ] ;
2025-08-13 01:33:11 -03:00
let program_id = Program ::nonce_changer_program ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , account_ids , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_output_accounts_exceed_inputs ( ) {
2025-11-24 17:09:30 +03:00
let initial_data = [ ( AccountId ::new ( [ 1 ; 32 ] ) , 100 ) ] ;
2025-09-18 15:59:17 +03:00
let mut state =
2025-10-16 16:24:18 -03:00
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let account_ids = vec! [ AccountId ::new ( [ 1 ; 32 ] ) ] ;
2025-08-13 01:33:11 -03:00
let program_id = Program ::extra_output_program ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , account_ids , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_with_missing_output_accounts ( ) {
2025-11-24 17:09:30 +03:00
let initial_data = [ ( AccountId ::new ( [ 1 ; 32 ] ) , 100 ) ] ;
2025-09-18 15:59:17 +03:00
let mut state =
2025-10-16 16:24:18 -03:00
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let account_ids = vec! [ AccountId ::new ( [ 1 ; 32 ] ) , AccountId ::new ( [ 2 ; 32 ] ) ] ;
2025-08-13 01:33:11 -03:00
let program_id = Program ::missing_output_program ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , account_ids , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner ( ) {
2025-11-24 17:09:30 +03:00
let initial_data = [ ( AccountId ::new ( [ 1 ; 32 ] ) , 0 ) ] ;
2025-09-18 15:59:17 +03:00
let mut state =
2025-10-16 16:24:18 -03:00
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 1 ; 32 ] ) ;
let account = state . get_account_by_id ( & account_id ) ;
2025-11-26 00:27:20 +03:00
// Assert the target account only differs from the default account in the program owner
// field
2025-08-13 01:33:11 -03:00
assert_ne! ( account . program_owner , Account ::default ( ) . program_owner ) ;
assert_eq! ( account . balance , Account ::default ( ) . balance ) ;
assert_eq! ( account . nonce , Account ::default ( ) . nonce ) ;
assert_eq! ( account . data , Account ::default ( ) . data ) ;
let program_id = Program ::program_owner_changer ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , vec! [ account_id ] , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_balance ( ) {
let initial_data = [ ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] )
2025-08-13 01:33:11 -03:00
. with_test_programs ( )
. with_non_default_accounts_but_default_program_owners ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 255 ; 32 ] ) ;
let account = state . get_account_by_id ( & account_id ) ;
2025-08-13 01:33:11 -03:00
// Assert the target account only differs from the default account in balance field
assert_eq! ( account . program_owner , Account ::default ( ) . program_owner ) ;
assert_ne! ( account . balance , Account ::default ( ) . balance ) ;
assert_eq! ( account . nonce , Account ::default ( ) . nonce ) ;
assert_eq! ( account . data , Account ::default ( ) . data ) ;
let program_id = Program ::program_owner_changer ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , vec! [ account_id ] , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonce ( ) {
let initial_data = [ ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] )
2025-08-13 01:33:11 -03:00
. with_test_programs ( )
. with_non_default_accounts_but_default_program_owners ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 254 ; 32 ] ) ;
let account = state . get_account_by_id ( & account_id ) ;
2025-08-13 01:33:11 -03:00
// Assert the target account only differs from the default account in nonce field
assert_eq! ( account . program_owner , Account ::default ( ) . program_owner ) ;
assert_eq! ( account . balance , Account ::default ( ) . balance ) ;
assert_ne! ( account . nonce , Account ::default ( ) . nonce ) ;
assert_eq! ( account . data , Account ::default ( ) . data ) ;
let program_id = Program ::program_owner_changer ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , vec! [ account_id ] , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data ( ) {
let initial_data = [ ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] )
2025-08-13 01:33:11 -03:00
. with_test_programs ( )
. with_non_default_accounts_but_default_program_owners ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 253 ; 32 ] ) ;
let account = state . get_account_by_id ( & account_id ) ;
2025-08-13 01:33:11 -03:00
// Assert the target account only differs from the default account in data field
assert_eq! ( account . program_owner , Account ::default ( ) . program_owner ) ;
assert_eq! ( account . balance , Account ::default ( ) . balance ) ;
assert_eq! ( account . nonce , Account ::default ( ) . nonce ) ;
assert_ne! ( account . data , Account ::default ( ) . data ) ;
let program_id = Program ::program_owner_changer ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , vec! [ account_id ] , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_transfers_balance_from_non_owned_account ( ) {
2025-11-24 17:09:30 +03:00
let initial_data = [ ( AccountId ::new ( [ 1 ; 32 ] ) , 100 ) ] ;
2025-09-18 15:59:17 +03:00
let mut state =
2025-10-16 16:24:18 -03:00
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let sender_account_id = AccountId ::new ( [ 1 ; 32 ] ) ;
let receiver_account_id = AccountId ::new ( [ 2 ; 32 ] ) ;
2025-08-13 01:33:11 -03:00
let balance_to_move : u128 = 1 ;
let program_id = Program ::simple_balance_transfer ( ) . id ( ) ;
assert_ne! (
2025-11-24 17:09:30 +03:00
state . get_account_by_id ( & sender_account_id ) . program_owner ,
2025-08-13 01:33:11 -03:00
program_id
) ;
let message = public_transaction ::Message ::try_new (
program_id ,
2025-11-24 17:09:30 +03:00
vec! [ sender_account_id , receiver_account_id ] ,
2025-08-13 01:33:11 -03:00
vec! [ ] ,
balance_to_move ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_modifies_data_of_non_owned_account ( ) {
let initial_data = [ ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] )
2025-09-12 17:13:37 -03:00
. with_test_programs ( )
. with_non_default_accounts_but_default_program_owners ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 255 ; 32 ] ) ;
2025-08-13 01:33:11 -03:00
let program_id = Program ::data_changer ( ) . id ( ) ;
2025-11-24 17:09:30 +03:00
assert_ne! ( state . get_account_by_id ( & account_id ) , Account ::default ( ) ) ;
2025-08-13 01:33:11 -03:00
assert_ne! (
2025-11-24 17:09:30 +03:00
state . get_account_by_id ( & account_id ) . program_owner ,
2025-08-13 01:33:11 -03:00
program_id
) ;
let message =
2025-12-05 17:16:41 +03:00
public_transaction ::Message ::try_new ( program_id , vec! [ account_id ] , vec! [ ] , vec! [ 0 ] )
. unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting ( ) {
let initial_data = [ ] ;
2025-09-18 15:59:17 +03:00
let mut state =
2025-10-16 16:24:18 -03:00
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 1 ; 32 ] ) ;
2025-08-13 01:33:11 -03:00
let program_id = Program ::minter ( ) . id ( ) ;
let message =
2025-11-24 17:09:30 +03:00
public_transaction ::Message ::try_new ( program_id , vec! [ account_id ] , vec! [ ] , ( ) ) . unwrap ( ) ;
2025-08-13 01:33:11 -03:00
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
#[ test ]
fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning ( ) {
let initial_data = [ ] ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & initial_data , & [ ] )
2025-08-13 01:33:11 -03:00
. with_test_programs ( )
. with_account_owned_by_burner_program ( ) ;
let program_id = Program ::burner ( ) . id ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::new ( [ 252 ; 32 ] ) ;
2025-08-13 01:33:11 -03:00
assert_eq! (
2025-11-24 17:09:30 +03:00
state . get_account_by_id ( & account_id ) . program_owner ,
2025-08-13 01:33:11 -03:00
program_id
) ;
let balance_to_burn : u128 = 1 ;
2025-11-24 17:09:30 +03:00
assert! ( state . get_account_by_id ( & account_id ) . balance > balance_to_burn ) ;
2025-08-13 01:33:11 -03:00
let message = public_transaction ::Message ::try_new (
program_id ,
2025-11-24 17:09:30 +03:00
vec! [ account_id ] ,
2025-08-13 01:33:11 -03:00
vec! [ ] ,
balance_to_burn ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
}
2025-08-21 14:32:57 -03:00
2025-08-22 13:42:37 -03:00
pub struct TestPublicKeys {
pub signing_key : PrivateKey ,
2025-08-22 12:29:45 -03:00
}
impl TestPublicKeys {
2025-11-24 17:09:30 +03:00
pub fn account_id ( & self ) -> AccountId {
AccountId ::from ( & PublicKey ::new_from_private_key ( & self . signing_key ) )
2025-08-22 12:29:45 -03:00
}
}
fn test_public_account_keys_1 ( ) -> TestPublicKeys {
TestPublicKeys {
signing_key : PrivateKey ::try_new ( [ 37 ; 32 ] ) . unwrap ( ) ,
}
}
2025-08-22 13:42:37 -03:00
pub struct TestPrivateKeys {
pub nsk : NullifierSecretKey ,
2025-09-15 14:04:49 +03:00
pub isk : Scalar ,
2025-08-22 12:29:45 -03:00
}
impl TestPrivateKeys {
2025-08-22 13:42:37 -03:00
pub fn npk ( & self ) -> NullifierPublicKey {
2025-08-22 12:29:45 -03:00
NullifierPublicKey ::from ( & self . nsk )
}
2025-08-22 14:59:57 -03:00
pub fn ivk ( & self ) -> IncomingViewingPublicKey {
IncomingViewingPublicKey ::from_scalar ( self . isk )
}
2025-08-22 12:29:45 -03:00
}
2025-08-22 13:42:37 -03:00
pub fn test_private_account_keys_1 ( ) -> TestPrivateKeys {
2025-08-22 12:29:45 -03:00
TestPrivateKeys {
nsk : [ 13 ; 32 ] ,
2025-08-22 14:59:57 -03:00
isk : [ 31 ; 32 ] ,
2025-08-22 12:29:45 -03:00
}
}
2025-08-22 13:42:37 -03:00
pub fn test_private_account_keys_2 ( ) -> TestPrivateKeys {
2025-08-22 12:29:45 -03:00
TestPrivateKeys {
nsk : [ 38 ; 32 ] ,
2025-08-22 14:59:57 -03:00
isk : [ 83 ; 32 ] ,
2025-08-22 12:29:45 -03:00
}
}
2025-08-22 10:34:09 -03:00
fn shielded_balance_transfer_for_tests (
2025-08-22 12:29:45 -03:00
sender_keys : & TestPublicKeys ,
recipient_keys : & TestPrivateKeys ,
2025-08-22 10:34:09 -03:00
balance_to_move : u128 ,
2025-10-16 16:24:18 -03:00
state : & V02State ,
2025-08-22 10:34:09 -03:00
) -> PrivacyPreservingTransaction {
2025-09-11 16:37:28 -03:00
let sender = AccountWithMetadata ::new (
2025-11-24 17:09:30 +03:00
state . get_account_by_id ( & sender_keys . account_id ( ) ) ,
2025-09-11 16:37:28 -03:00
true ,
2025-11-24 17:09:30 +03:00
sender_keys . account_id ( ) ,
2025-09-11 16:37:28 -03:00
) ;
2025-08-25 14:51:46 -03:00
2025-08-22 10:34:09 -03:00
let sender_nonce = sender . account . nonce ;
2025-08-21 15:52:35 -03:00
2025-09-11 16:37:28 -03:00
let recipient = AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-08-21 14:32:57 -03:00
2025-08-25 14:51:46 -03:00
let esk = [ 3 ; 32 ] ;
2025-08-26 14:53:02 -03:00
let shared_secret = SharedSecretKey ::new ( & esk , & recipient_keys . ivk ( ) ) ;
2025-08-25 14:51:46 -03:00
let epk = EphemeralPublicKey ::from_scalar ( esk ) ;
2025-08-22 10:34:09 -03:00
let ( output , proof ) = circuit ::execute_and_prove (
2025-08-21 14:32:57 -03:00
& [ sender , recipient ] ,
& Program ::serialize_instruction ( balance_to_move ) . unwrap ( ) ,
& [ 0 , 2 ] ,
& [ 0xdeadbeef ] ,
2025-08-25 14:51:46 -03:00
& [ ( recipient_keys . npk ( ) , shared_secret ) ] ,
2025-08-21 14:32:57 -03:00
& [ ] ,
2025-11-20 19:25:56 -03:00
& Program ::authenticated_transfer_program ( ) . into ( ) ,
2025-08-21 14:32:57 -03:00
)
. unwrap ( ) ;
2025-08-25 14:51:46 -03:00
let message = Message ::try_from_circuit_output (
2025-11-24 17:09:30 +03:00
vec! [ sender_keys . account_id ( ) ] ,
2025-08-22 10:34:09 -03:00
vec! [ sender_nonce ] ,
2025-09-01 18:12:13 -03:00
vec! [ ( recipient_keys . npk ( ) , recipient_keys . ivk ( ) , epk ) ] ,
2025-08-25 14:51:46 -03:00
output ,
2025-08-26 14:53:02 -03:00
)
. unwrap ( ) ;
2025-08-21 14:32:57 -03:00
2025-08-22 12:29:45 -03:00
let witness_set = WitnessSet ::for_message ( & message , proof , & [ & sender_keys . signing_key ] ) ;
2025-08-22 10:34:09 -03:00
PrivacyPreservingTransaction ::new ( message , witness_set )
}
fn private_balance_transfer_for_tests (
2025-08-22 12:29:45 -03:00
sender_keys : & TestPrivateKeys ,
2025-08-22 10:34:09 -03:00
sender_private_account : & Account ,
2025-08-22 12:29:45 -03:00
recipient_keys : & TestPrivateKeys ,
2025-08-22 10:34:09 -03:00
balance_to_move : u128 ,
new_nonces : [ Nonce ; 2 ] ,
2025-10-16 16:24:18 -03:00
state : & V02State ,
2025-08-22 10:34:09 -03:00
) -> PrivacyPreservingTransaction {
let program = Program ::authenticated_transfer_program ( ) ;
2025-08-27 16:24:20 -03:00
let sender_commitment = Commitment ::new ( & sender_keys . npk ( ) , sender_private_account ) ;
2025-09-11 16:37:28 -03:00
let sender_pre =
AccountWithMetadata ::new ( sender_private_account . clone ( ) , true , & sender_keys . npk ( ) ) ;
let recipient_pre =
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-08-21 14:32:57 -03:00
2025-08-25 14:51:46 -03:00
let esk_1 = [ 3 ; 32 ] ;
2025-08-26 14:53:02 -03:00
let shared_secret_1 = SharedSecretKey ::new ( & esk_1 , & sender_keys . ivk ( ) ) ;
2025-08-25 14:51:46 -03:00
let epk_1 = EphemeralPublicKey ::from_scalar ( esk_1 ) ;
let esk_2 = [ 3 ; 32 ] ;
2025-08-26 14:53:02 -03:00
let shared_secret_2 = SharedSecretKey ::new ( & esk_2 , & recipient_keys . ivk ( ) ) ;
2025-08-25 14:51:46 -03:00
let epk_2 = EphemeralPublicKey ::from_scalar ( esk_2 ) ;
2025-08-22 10:34:09 -03:00
let ( output , proof ) = circuit ::execute_and_prove (
& [ sender_pre , recipient_pre ] ,
& Program ::serialize_instruction ( balance_to_move ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& new_nonces ,
& [
2025-08-25 14:51:46 -03:00
( sender_keys . npk ( ) , shared_secret_1 ) ,
( recipient_keys . npk ( ) , shared_secret_2 ) ,
2025-08-22 10:34:09 -03:00
] ,
& [ (
2025-08-22 12:29:45 -03:00
sender_keys . nsk ,
2025-08-27 16:24:20 -03:00
state . get_proof_for_commitment ( & sender_commitment ) . unwrap ( ) ,
2025-08-22 10:34:09 -03:00
) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-08-22 10:34:09 -03:00
)
. unwrap ( ) ;
2025-09-01 18:12:13 -03:00
let message = Message ::try_from_circuit_output (
vec! [ ] ,
vec! [ ] ,
vec! [
( sender_keys . npk ( ) , sender_keys . ivk ( ) , epk_1 ) ,
( recipient_keys . npk ( ) , recipient_keys . ivk ( ) , epk_2 ) ,
] ,
output ,
)
. unwrap ( ) ;
2025-08-22 10:34:09 -03:00
let witness_set = WitnessSet ::for_message ( & message , proof , & [ ] ) ;
PrivacyPreservingTransaction ::new ( message , witness_set )
}
2025-08-22 11:03:10 -03:00
fn deshielded_balance_transfer_for_tests (
2025-08-22 12:29:45 -03:00
sender_keys : & TestPrivateKeys ,
2025-08-22 11:03:10 -03:00
sender_private_account : & Account ,
2025-11-24 17:09:30 +03:00
recipient_account_id : & AccountId ,
2025-08-22 11:03:10 -03:00
balance_to_move : u128 ,
new_nonce : Nonce ,
2025-10-16 16:24:18 -03:00
state : & V02State ,
2025-08-22 11:03:10 -03:00
) -> PrivacyPreservingTransaction {
let program = Program ::authenticated_transfer_program ( ) ;
2025-08-27 16:24:20 -03:00
let sender_commitment = Commitment ::new ( & sender_keys . npk ( ) , sender_private_account ) ;
2025-09-11 16:37:28 -03:00
let sender_pre =
AccountWithMetadata ::new ( sender_private_account . clone ( ) , true , & sender_keys . npk ( ) ) ;
let recipient_pre = AccountWithMetadata ::new (
2025-11-24 17:09:30 +03:00
state . get_account_by_id ( recipient_account_id ) ,
2025-09-11 16:37:28 -03:00
false ,
2025-11-24 17:09:30 +03:00
* recipient_account_id ,
2025-09-11 16:37:28 -03:00
) ;
2025-08-22 11:03:10 -03:00
2025-08-25 14:51:46 -03:00
let esk = [ 3 ; 32 ] ;
2025-08-26 14:53:02 -03:00
let shared_secret = SharedSecretKey ::new ( & esk , & sender_keys . ivk ( ) ) ;
2025-08-25 14:51:46 -03:00
let epk = EphemeralPublicKey ::from_scalar ( esk ) ;
2025-08-22 11:03:10 -03:00
let ( output , proof ) = circuit ::execute_and_prove (
& [ sender_pre , recipient_pre ] ,
& Program ::serialize_instruction ( balance_to_move ) . unwrap ( ) ,
& [ 1 , 0 ] ,
& [ new_nonce ] ,
2025-08-25 14:51:46 -03:00
& [ ( sender_keys . npk ( ) , shared_secret ) ] ,
2025-08-22 11:03:10 -03:00
& [ (
2025-08-22 12:29:45 -03:00
sender_keys . nsk ,
2025-08-27 16:24:20 -03:00
state . get_proof_for_commitment ( & sender_commitment ) . unwrap ( ) ,
2025-08-22 11:03:10 -03:00
) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-08-22 11:03:10 -03:00
)
. unwrap ( ) ;
2025-09-01 18:12:13 -03:00
let message = Message ::try_from_circuit_output (
2025-11-24 17:09:30 +03:00
vec! [ * recipient_account_id ] ,
2025-09-01 18:12:13 -03:00
vec! [ ] ,
vec! [ ( sender_keys . npk ( ) , sender_keys . ivk ( ) , epk ) ] ,
output ,
)
. unwrap ( ) ;
2025-08-22 11:03:10 -03:00
let witness_set = WitnessSet ::for_message ( & message , proof , & [ ] ) ;
PrivacyPreservingTransaction ::new ( message , witness_set )
}
2025-08-22 10:34:09 -03:00
#[ test ]
fn test_transition_from_privacy_preserving_transaction_shielded ( ) {
2025-08-22 12:29:45 -03:00
let sender_keys = test_public_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_1 ( ) ;
2025-11-24 17:09:30 +03:00
let mut state =
V02State ::new_with_genesis_accounts ( & [ ( sender_keys . account_id ( ) , 200 ) ] , & [ ] ) ;
2025-08-22 12:29:45 -03:00
let balance_to_move = 37 ;
2025-08-22 10:34:09 -03:00
let tx = shielded_balance_transfer_for_tests (
2025-08-22 12:29:45 -03:00
& sender_keys ,
& recipient_keys ,
balance_to_move ,
2025-08-22 10:34:09 -03:00
& state ,
) ;
2025-09-03 15:20:40 -03:00
let expected_sender_post = {
2025-11-24 17:09:30 +03:00
let mut this = state . get_account_by_id ( & sender_keys . account_id ( ) ) ;
2025-09-03 15:20:40 -03:00
this . balance - = balance_to_move ;
this . nonce + = 1 ;
this
} ;
2025-08-22 10:34:09 -03:00
let [ expected_new_commitment ] = tx . message ( ) . new_commitments . clone ( ) . try_into ( ) . unwrap ( ) ;
assert! ( ! state . private_state . 0. contains ( & expected_new_commitment ) ) ;
2025-08-21 14:32:57 -03:00
state
. transition_from_privacy_preserving_transaction ( & tx )
. unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let sender_post = state . get_account_by_id ( & sender_keys . account_id ( ) ) ;
2025-09-03 15:20:40 -03:00
assert_eq! ( sender_post , expected_sender_post ) ;
2025-08-22 10:34:09 -03:00
assert! ( state . private_state . 0. contains ( & expected_new_commitment ) ) ;
2025-08-21 14:32:57 -03:00
assert_eq! (
2025-11-24 17:09:30 +03:00
state . get_account_by_id ( & sender_keys . account_id ( ) ) . balance ,
2025-08-22 12:29:45 -03:00
200 - balance_to_move
2025-08-21 14:32:57 -03:00
) ;
}
2025-08-22 10:34:09 -03:00
#[ test ]
fn test_transition_from_privacy_preserving_transaction_private ( ) {
2025-08-22 12:29:45 -03:00
let sender_keys = test_private_account_keys_1 ( ) ;
let sender_private_account = Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
balance : 100 ,
nonce : 0xdeadbeef ,
2025-12-05 02:17:09 +03:00
data : Data ::default ( ) ,
2025-08-22 12:29:45 -03:00
} ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] )
2025-08-22 12:29:45 -03:00
. with_private_account ( & sender_keys , & sender_private_account ) ;
2025-08-22 10:34:09 -03:00
let balance_to_move = 37 ;
let tx = private_balance_transfer_for_tests (
2025-08-22 12:29:45 -03:00
& sender_keys ,
2025-08-22 10:34:09 -03:00
& sender_private_account ,
2025-08-22 12:29:45 -03:00
& recipient_keys ,
2025-08-22 10:34:09 -03:00
balance_to_move ,
2025-08-22 12:29:45 -03:00
[ 0xcafecafe , 0xfecafeca ] ,
2025-08-22 10:34:09 -03:00
& state ,
) ;
let expected_new_commitment_1 = Commitment ::new (
2025-08-22 12:29:45 -03:00
& sender_keys . npk ( ) ,
2025-08-22 10:34:09 -03:00
& Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
2025-08-22 12:29:45 -03:00
nonce : 0xcafecafe ,
2025-08-22 10:34:09 -03:00
balance : sender_private_account . balance - balance_to_move ,
2025-12-05 02:17:09 +03:00
data : Data ::default ( ) ,
2025-08-22 10:34:09 -03:00
} ,
) ;
2025-08-22 12:29:45 -03:00
let sender_pre_commitment = Commitment ::new ( & sender_keys . npk ( ) , & sender_private_account ) ;
2025-10-03 20:44:29 -03:00
let expected_new_nullifier =
Nullifier ::for_account_update ( & sender_pre_commitment , & sender_keys . nsk ) ;
2025-08-22 10:34:09 -03:00
let expected_new_commitment_2 = Commitment ::new (
2025-08-22 12:29:45 -03:00
& recipient_keys . npk ( ) ,
2025-08-22 10:34:09 -03:00
& Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
2025-08-22 12:29:45 -03:00
nonce : 0xfecafeca ,
2025-08-22 10:34:09 -03:00
balance : balance_to_move ,
.. Account ::default ( )
} ,
) ;
let previous_public_state = state . public_state . clone ( ) ;
assert! ( state . private_state . 0. contains ( & sender_pre_commitment ) ) ;
assert! ( ! state . private_state . 0. contains ( & expected_new_commitment_1 ) ) ;
assert! ( ! state . private_state . 0. contains ( & expected_new_commitment_2 ) ) ;
assert! ( ! state . private_state . 1. contains ( & expected_new_nullifier ) ) ;
2025-08-22 11:03:10 -03:00
2025-08-22 10:34:09 -03:00
state
. transition_from_privacy_preserving_transaction ( & tx )
. unwrap ( ) ;
assert_eq! ( state . public_state , previous_public_state ) ;
assert! ( state . private_state . 0. contains ( & sender_pre_commitment ) ) ;
assert! ( state . private_state . 0. contains ( & expected_new_commitment_1 ) ) ;
assert! ( state . private_state . 0. contains ( & expected_new_commitment_2 ) ) ;
assert! ( state . private_state . 1. contains ( & expected_new_nullifier ) ) ;
}
2025-08-22 11:03:10 -03:00
#[ test ]
fn test_transition_from_privacy_preserving_transaction_deshielded ( ) {
2025-08-22 12:29:45 -03:00
let sender_keys = test_private_account_keys_1 ( ) ;
let sender_private_account = Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
balance : 100 ,
nonce : 0xdeadbeef ,
2025-12-05 02:17:09 +03:00
data : Data ::default ( ) ,
2025-08-22 12:29:45 -03:00
} ;
let recipient_keys = test_public_account_keys_1 ( ) ;
2025-08-22 11:03:10 -03:00
let recipient_initial_balance = 400 ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts (
2025-11-24 17:09:30 +03:00
& [ ( recipient_keys . account_id ( ) , recipient_initial_balance ) ] ,
2025-09-18 15:59:17 +03:00
& [ ] ,
)
2025-08-22 12:29:45 -03:00
. with_private_account ( & sender_keys , & sender_private_account ) ;
2025-08-22 11:03:10 -03:00
let balance_to_move = 37 ;
2025-09-03 15:20:40 -03:00
let expected_recipient_post = {
2025-11-24 17:09:30 +03:00
let mut this = state . get_account_by_id ( & recipient_keys . account_id ( ) ) ;
2025-09-03 15:20:40 -03:00
this . balance + = balance_to_move ;
this
} ;
2025-08-22 11:03:10 -03:00
let tx = deshielded_balance_transfer_for_tests (
2025-08-22 12:29:45 -03:00
& sender_keys ,
2025-08-22 11:03:10 -03:00
& sender_private_account ,
2025-11-24 17:09:30 +03:00
& recipient_keys . account_id ( ) ,
2025-08-22 11:03:10 -03:00
balance_to_move ,
2025-08-22 12:29:45 -03:00
0xcafecafe ,
2025-08-22 11:03:10 -03:00
& state ,
) ;
let expected_new_commitment = Commitment ::new (
2025-08-22 12:29:45 -03:00
& sender_keys . npk ( ) ,
2025-08-22 11:03:10 -03:00
& Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
2025-08-22 12:29:45 -03:00
nonce : 0xcafecafe ,
2025-08-22 11:03:10 -03:00
balance : sender_private_account . balance - balance_to_move ,
2025-12-05 02:17:09 +03:00
data : Data ::default ( ) ,
2025-08-22 11:03:10 -03:00
} ,
) ;
2025-08-22 12:29:45 -03:00
let sender_pre_commitment = Commitment ::new ( & sender_keys . npk ( ) , & sender_private_account ) ;
2025-10-03 20:44:29 -03:00
let expected_new_nullifier =
Nullifier ::for_account_update ( & sender_pre_commitment , & sender_keys . nsk ) ;
2025-08-22 11:03:10 -03:00
assert! ( state . private_state . 0. contains ( & sender_pre_commitment ) ) ;
assert! ( ! state . private_state . 0. contains ( & expected_new_commitment ) ) ;
assert! ( ! state . private_state . 1. contains ( & expected_new_nullifier ) ) ;
state
. transition_from_privacy_preserving_transaction ( & tx )
. unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let recipient_post = state . get_account_by_id ( & recipient_keys . account_id ( ) ) ;
2025-09-03 15:20:40 -03:00
assert_eq! ( recipient_post , expected_recipient_post ) ;
2025-08-22 11:03:10 -03:00
assert! ( state . private_state . 0. contains ( & sender_pre_commitment ) ) ;
assert! ( state . private_state . 0. contains ( & expected_new_commitment ) ) ;
assert! ( state . private_state . 1. contains ( & expected_new_nullifier ) ) ;
assert_eq! (
2025-08-22 12:29:45 -03:00
state
2025-11-24 17:09:30 +03:00
. get_account_by_id ( & recipient_keys . account_id ( ) )
2025-08-22 12:29:45 -03:00
. balance ,
2025-08-22 11:03:10 -03:00
recipient_initial_balance + balance_to_move
) ;
}
2025-09-02 12:38:31 -03:00
#[ test ]
fn test_burner_program_should_fail_in_privacy_preserving_circuit ( ) {
2025-09-02 14:09:50 -03:00
let program = Program ::burner ( ) ;
2025-09-18 17:09:02 -03:00
let public_account = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
2025-09-02 12:38:31 -03:00
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
2025-09-02 12:38:31 -03:00
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_minter_program_should_fail_in_privacy_preserving_circuit ( ) {
let program = Program ::minter ( ) ;
2025-09-18 17:09:02 -03:00
let public_account = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
2025-09-02 12:38:31 -03:00
let result = execute_and_prove (
2025-09-02 14:09:50 -03:00
& [ public_account ] ,
2025-09-02 12:38:31 -03:00
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
2025-09-02 14:09:50 -03:00
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_nonce_changer_program_should_fail_in_privacy_preserving_circuit ( ) {
let program = Program ::nonce_changer_program ( ) ;
2025-09-18 17:09:02 -03:00
let public_account = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account ] ,
& Program ::serialize_instruction ( ( ) ) . unwrap ( ) ,
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_data_changer_program_should_fail_for_non_owned_account_in_privacy_preserving_circuit ( ) {
let program = Program ::data_changer ( ) ;
2025-09-18 17:09:02 -03:00
let public_account = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account ] ,
2025-12-05 17:16:41 +03:00
& Program ::serialize_instruction ( vec! [ 0 ] ) . unwrap ( ) ,
2025-09-02 14:09:50 -03:00
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
2025-12-05 17:16:41 +03:00
#[ test ]
fn test_data_changer_program_should_fail_for_too_large_data_in_privacy_preserving_circuit ( ) {
let program = Program ::data_changer ( ) ;
let public_account = AccountWithMetadata ::new (
Account {
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
let large_data : Vec < u8 > = vec! [ 0 ; nssa_core ::account ::data ::DATA_MAX_LENGTH_IN_BYTES + 1 ] ;
let result = execute_and_prove (
& [ public_account ] ,
& Program ::serialize_instruction ( large_data ) . unwrap ( ) ,
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-12-10 14:50:00 -03:00
& program . to_owned ( ) . into ( ) ,
2025-12-05 17:16:41 +03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::ProgramProveFailed ( _ ) ) ) ) ;
}
2025-09-02 14:09:50 -03:00
#[ test ]
fn test_extra_output_program_should_fail_in_privacy_preserving_circuit ( ) {
let program = Program ::extra_output_program ( ) ;
2025-09-18 17:09:02 -03:00
let public_account = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account ] ,
& Program ::serialize_instruction ( ( ) ) . unwrap ( ) ,
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_missing_output_program_should_fail_in_privacy_preserving_circuit ( ) {
let program = Program ::missing_output_program ( ) ;
2025-09-18 17:09:02 -03:00
let public_account_1 = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
let public_account_2 = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 1 ; 32 ] ) ,
) ;
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account_1 , public_account_2 ] ,
& Program ::serialize_instruction ( ( ) ) . unwrap ( ) ,
& [ 0 , 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_program_owner_changer_should_fail_in_privacy_preserving_circuit ( ) {
let program = Program ::program_owner_changer ( ) ;
2025-09-18 17:09:02 -03:00
let public_account = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account ] ,
& Program ::serialize_instruction ( ( ) ) . unwrap ( ) ,
& [ 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:09:50 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_transfer_from_non_owned_account_should_fail_in_privacy_preserving_circuit ( ) {
let program = Program ::simple_balance_transfer ( ) ;
2025-09-18 17:09:02 -03:00
let public_account_1 = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
let public_account_2 = AccountWithMetadata ::new (
Account {
2025-09-02 14:09:50 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 1 ; 32 ] ) ,
) ;
2025-09-02 14:09:50 -03:00
let result = execute_and_prove (
& [ public_account_1 , public_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 0 , 0 ] ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 12:38:31 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
2025-09-02 14:50:16 -03:00
#[ test ]
fn test_circuit_fails_if_visibility_masks_have_incorrect_lenght ( ) {
let program = Program ::simple_balance_transfer ( ) ;
2025-09-18 17:09:02 -03:00
let public_account_1 = AccountWithMetadata ::new (
Account {
2025-09-02 14:50:16 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
let public_account_2 = AccountWithMetadata ::new (
Account {
2025-09-02 14:50:16 -03:00
program_owner : program . id ( ) ,
balance : 0 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 1 ; 32 ] ) ,
) ;
2025-09-02 14:50:16 -03:00
// Setting only one visibility mask for a circuit execution with two pre_state accounts.
let visibility_mask = [ 0 ] ;
let result = execute_and_prove (
& [ public_account_1 , public_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& visibility_mask ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-02 14:50:16 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
2025-09-03 16:25:02 -03:00
#[ test ]
fn test_circuit_fails_if_insufficient_nonces_are_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
2025-10-03 18:31:56 -03:00
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-09-03 16:25:02 -03:00
// Setting only one nonce for an execution with two private accounts.
let private_account_nonces = [ 0xdeadbeef1 ] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& private_account_nonces ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_fails_if_insufficient_keys_are_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
AccountWithMetadata ::new ( Account ::default ( ) , false , AccountId ::new ( [ 1 ; 32 ] ) ) ;
2025-09-03 16:25:02 -03:00
// Setting only one key for an execution with two private accounts.
let private_account_keys = [ (
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& private_account_keys ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_fails_if_insufficient_auth_keys_are_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
2025-10-03 18:31:56 -03:00
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-09-03 16:25:02 -03:00
// Setting no auth key for an execution with one non default private accounts.
let private_account_auth = [ ] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& private_account_auth ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_fails_if_invalid_auth_keys_are_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
2025-10-03 18:31:56 -03:00
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-09-03 16:25:02 -03:00
let private_account_keys = [
// First private account is the sender
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
// Second private account is the recipient
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ;
let private_account_auth = [
// Setting the recipient key to authorize the sender.
// This should be set to the sender private account in
// a normal circumstance. The recipient can't authorize this.
( recipient_keys . nsk , ( 0 , vec! [ ] ) ) ,
] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& private_account_keys ,
& private_account_auth ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_if_new_private_account_with_non_default_balance_is_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
// Non default balance
balance : 1 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
false ,
2025-10-03 18:31:56 -03:00
& recipient_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
2025-09-03 16:25:02 -03:00
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_if_new_private_account_with_non_default_program_owner_is_provided ( )
{
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
// Non default program_owner
program_owner : [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
false ,
2025-10-03 18:31:56 -03:00
& recipient_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
2025-09-03 16:25:02 -03:00
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_if_new_private_account_with_non_default_data_is_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
// Non default data
2025-12-05 02:17:09 +03:00
data : b " hola mundo " . to_vec ( ) . try_into ( ) . unwrap ( ) ,
2025-09-03 16:25:02 -03:00
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
false ,
2025-10-03 18:31:56 -03:00
& recipient_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
2025-09-03 16:25:02 -03:00
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_if_new_private_account_with_non_default_nonce_is_provided ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
// Non default nonce
nonce : 0xdeadbeef ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
false ,
2025-10-03 18:31:56 -03:00
& recipient_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
2025-09-03 16:25:02 -03:00
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_if_new_private_account_is_provided_with_default_values_but_marked_as_authorized ( )
{
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 = AccountWithMetadata ::new (
Account ::default ( ) ,
2025-09-03 16:25:02 -03:00
// This should be set to false in normal circumstances
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& recipient_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
2025-09-03 16:25:02 -03:00
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_with_invalid_visibility_mask_value ( ) {
let program = Program ::simple_balance_transfer ( ) ;
2025-09-18 17:09:02 -03:00
let public_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:25:02 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
AccountId ::new ( [ 0 ; 32 ] ) ,
) ;
let public_account_2 =
AccountWithMetadata ::new ( Account ::default ( ) , false , AccountId ::new ( [ 1 ; 32 ] ) ) ;
2025-09-03 16:25:02 -03:00
let visibility_mask = [ 0 , 3 ] ;
let result = execute_and_prove (
& [ public_account_1 , public_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& visibility_mask ,
& [ ] ,
& [ ] ,
& [ ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:25:02 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
2025-09-03 16:44:55 -03:00
#[ test ]
fn test_circuit_should_fail_with_too_many_nonces ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:44:55 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
2025-10-03 18:31:56 -03:00
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-09-03 16:44:55 -03:00
// Setting three new private account nonces for a circuit execution with only two private
// accounts.
let private_account_nonces = [ 0xdeadbeef1 , 0xdeadbeef2 , 0xdeadbeef3 ] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& private_account_nonces ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:44:55 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_with_too_many_private_account_keys ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:44:55 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
2025-10-03 18:31:56 -03:00
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-09-03 16:44:55 -03:00
// Setting three private account keys for a circuit execution with only two private
// accounts.
let private_account_keys = [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 57 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& [ 1 , 2 ] ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& private_account_keys ,
& [ ( sender_keys . nsk , ( 0 , vec! [ ] ) ) ] ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:44:55 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
#[ test ]
fn test_circuit_should_fail_with_too_many_private_account_auth_keys ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-09-18 17:09:02 -03:00
let private_account_1 = AccountWithMetadata ::new (
Account {
2025-09-03 16:44:55 -03:00
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
2025-09-18 17:09:02 -03:00
true ,
2025-10-03 18:31:56 -03:00
& sender_keys . npk ( ) ,
2025-09-18 17:09:02 -03:00
) ;
let private_account_2 =
2025-10-03 18:31:56 -03:00
AccountWithMetadata ::new ( Account ::default ( ) , false , & recipient_keys . npk ( ) ) ;
2025-09-03 16:44:55 -03:00
// Setting two private account keys for a circuit execution with only one non default
// private account (visibility mask equal to 1 means that auth keys are expected).
let visibility_mask = [ 1 , 2 ] ;
let private_account_auth = [
( sender_keys . nsk , ( 0 , vec! [ ] ) ) ,
( recipient_keys . nsk , ( 1 , vec! [ ] ) ) ,
] ;
let result = execute_and_prove (
& [ private_account_1 , private_account_2 ] ,
& Program ::serialize_instruction ( 10 u128 ) . unwrap ( ) ,
& visibility_mask ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
(
sender_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ,
) ,
(
recipient_keys . npk ( ) ,
SharedSecretKey ::new ( & [ 56 ; 32 ] , & recipient_keys . ivk ( ) ) ,
) ,
] ,
& private_account_auth ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-09-03 16:44:55 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
2025-10-03 20:44:29 -03:00
#[ test ]
fn test_private_accounts_can_only_be_initialized_once ( ) {
let sender_keys = test_private_account_keys_1 ( ) ;
let sender_private_account = Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
balance : 100 ,
nonce : 0xdeadbeef ,
2025-12-05 02:17:09 +03:00
data : Data ::default ( ) ,
2025-10-03 20:44:29 -03:00
} ;
let recipient_keys = test_private_account_keys_2 ( ) ;
2025-10-16 16:24:18 -03:00
let mut state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] )
2025-10-03 20:44:29 -03:00
. with_private_account ( & sender_keys , & sender_private_account ) ;
let balance_to_move = 37 ;
let tx = private_balance_transfer_for_tests (
& sender_keys ,
& sender_private_account ,
& recipient_keys ,
balance_to_move ,
[ 0xcafecafe , 0xfecafeca ] ,
& state ,
) ;
state
. transition_from_privacy_preserving_transaction ( & tx )
. unwrap ( ) ;
let sender_private_account = Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
balance : 100 - balance_to_move ,
nonce : 0xcafecafe ,
2025-12-05 02:17:09 +03:00
data : Data ::default ( ) ,
2025-10-03 20:44:29 -03:00
} ;
let tx = private_balance_transfer_for_tests (
& sender_keys ,
& sender_private_account ,
& recipient_keys ,
balance_to_move ,
[ 0x1234 , 0x5678 ] ,
& state ,
) ;
let result = state . transition_from_privacy_preserving_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidInput ( _ ) ) ) ) ;
let NssaError ::InvalidInput ( error_message ) = result . err ( ) . unwrap ( ) else {
panic! ( " Incorrect message error " ) ;
} ;
let expected_error_message = " Nullifier already seen " . to_string ( ) ;
assert_eq! ( error_message , expected_error_message ) ;
}
2025-10-07 12:56:57 -03:00
2025-10-03 18:31:56 -03:00
#[ test ]
fn test_circuit_should_fail_if_there_are_repeated_ids ( ) {
let program = Program ::simple_balance_transfer ( ) ;
let sender_keys = test_private_account_keys_1 ( ) ;
let private_account_1 = AccountWithMetadata ::new (
Account {
program_owner : program . id ( ) ,
balance : 100 ,
.. Account ::default ( )
} ,
true ,
& sender_keys . npk ( ) ,
) ;
let visibility_mask = [ 1 , 1 ] ;
let private_account_auth = [
( sender_keys . nsk , ( 1 , vec! [ ] ) ) ,
( sender_keys . nsk , ( 1 , vec! [ ] ) ) ,
] ;
let shared_secret = SharedSecretKey ::new ( & [ 55 ; 32 ] , & sender_keys . ivk ( ) ) ;
let result = execute_and_prove (
& [ private_account_1 . clone ( ) , private_account_1 ] ,
& Program ::serialize_instruction ( 100 u128 ) . unwrap ( ) ,
& visibility_mask ,
& [ 0xdeadbeef1 , 0xdeadbeef2 ] ,
& [
2025-12-16 14:05:34 +02:00
( sender_keys . npk ( ) , shared_secret ) ,
2025-10-03 18:31:56 -03:00
( sender_keys . npk ( ) , shared_secret ) ,
] ,
& private_account_auth ,
2025-11-20 19:25:56 -03:00
& program . into ( ) ,
2025-10-03 18:31:56 -03:00
) ;
assert! ( matches! ( result , Err ( NssaError ::CircuitProvingError ( _ ) ) ) ) ;
}
2025-10-29 15:34:11 -03:00
2025-10-30 10:52:31 -03:00
#[ test ]
fn test_claiming_mechanism ( ) {
let program = Program ::authenticated_transfer_program ( ) ;
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let account_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
2025-10-30 10:52:31 -03:00
let initial_balance = 100 ;
2025-11-24 17:09:30 +03:00
let initial_data = [ ( account_id , initial_balance ) ] ;
2025-10-30 10:52:31 -03:00
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
2025-11-24 17:09:30 +03:00
let from = account_id ;
2025-10-30 10:52:31 -03:00
let from_key = key ;
2025-11-24 17:09:30 +03:00
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
2025-10-30 10:52:31 -03:00
let amount : u128 = 37 ;
// Check the recipient is an uninitialized account
2025-11-24 17:09:30 +03:00
assert_eq! ( state . get_account_by_id ( & to ) , Account ::default ( ) ) ;
2025-10-30 10:52:31 -03:00
let expected_recipient_post = Account {
program_owner : program . id ( ) ,
balance : amount ,
.. Account ::default ( )
} ;
let message =
public_transaction ::Message ::try_new ( program . id ( ) , vec! [ from , to ] , vec! [ 0 ] , amount )
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ & from_key ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let recipient_post = state . get_account_by_id ( & to ) ;
2025-10-30 10:52:31 -03:00
assert_eq! ( recipient_post , expected_recipient_post ) ;
}
2025-10-29 15:34:11 -03:00
#[ test ]
2025-11-20 01:40:05 -03:00
fn test_public_chained_call ( ) {
2025-10-29 15:34:11 -03:00
let program = Program ::chain_caller ( ) ;
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
2025-11-26 16:53:21 -03:00
let from = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
2025-11-27 13:49:56 -03:00
let initial_balance = 1000 ;
2025-11-26 16:53:21 -03:00
let initial_data = [ ( from , initial_balance ) , ( to , 0 ) ] ;
2025-10-29 15:34:11 -03:00
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
let from_key = key ;
2025-11-27 13:49:56 -03:00
let amount : u128 = 37 ;
let instruction : ( u128 , ProgramId , u32 , Option < PdaSeed > ) = (
amount ,
Program ::authenticated_transfer_program ( ) . id ( ) ,
2 ,
None ,
) ;
2025-10-29 15:34:11 -03:00
2025-10-30 10:52:31 -03:00
let expected_to_post = Account {
2025-11-17 15:43:01 -03:00
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
2025-11-12 19:08:46 -03:00
balance : amount * 2 , // The `chain_caller` chains the program twice
2025-10-30 10:52:31 -03:00
.. Account ::default ( )
} ;
2025-10-29 15:34:11 -03:00
let message = public_transaction ::Message ::try_new (
program . id ( ) ,
2025-11-26 16:53:21 -03:00
vec! [ to , from ] , // The chain_caller program permutes the account order in the chain
2025-11-26 20:13:23 -03:00
// call
2025-10-29 15:34:11 -03:00
vec! [ 0 ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ & from_key ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-11-24 17:09:30 +03:00
let from_post = state . get_account_by_id ( & from ) ;
let to_post = state . get_account_by_id ( & to ) ;
2025-11-12 19:08:46 -03:00
// The `chain_caller` program calls the program twice
assert_eq! ( from_post . balance , initial_balance - 2 * amount ) ;
2025-10-30 10:52:31 -03:00
assert_eq! ( to_post , expected_to_post ) ;
2025-10-29 15:34:11 -03:00
}
2025-11-12 19:55:02 -03:00
#[ test ]
fn test_execution_fails_if_chained_calls_exceeds_depth ( ) {
let program = Program ::chain_caller ( ) ;
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
2025-11-26 16:53:21 -03:00
let from = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
2025-11-12 19:55:02 -03:00
let initial_balance = 100 ;
2025-11-26 16:53:21 -03:00
let initial_data = [ ( from , initial_balance ) , ( to , 0 ) ] ;
2025-11-12 19:55:02 -03:00
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
let from_key = key ;
let amount : u128 = 0 ;
2025-11-27 13:49:56 -03:00
let instruction : ( u128 , ProgramId , u32 , Option < PdaSeed > ) = (
2025-11-12 19:55:02 -03:00
amount ,
Program ::authenticated_transfer_program ( ) . id ( ) ,
MAX_NUMBER_CHAINED_CALLS as u32 + 1 ,
2025-11-27 13:49:56 -03:00
None ,
2025-11-12 19:55:02 -03:00
) ;
let message = public_transaction ::Message ::try_new (
program . id ( ) ,
2025-11-26 16:53:21 -03:00
vec! [ to , from ] , // The chain_caller program permutes the account order in the chain
2025-11-26 20:13:23 -03:00
// call
2025-11-12 19:55:02 -03:00
vec! [ 0 ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ & from_key ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! (
result ,
Err ( NssaError ::MaxChainedCallsDepthExceeded )
) ) ;
}
2025-11-20 21:02:18 -05:00
2025-12-15 10:40:46 +02:00
// TODO: repeated code needs to be cleaned up
// from token.rs (also repeated in amm.rs)
2025-11-20 21:02:18 -05:00
const TOKEN_DEFINITION_DATA_SIZE : usize = 23 ;
2025-12-15 10:40:46 +02:00
#[ allow(unused) ]
2025-11-20 21:02:18 -05:00
const TOKEN_HOLDING_TYPE : u8 = 1 ;
const TOKEN_HOLDING_DATA_SIZE : usize = 49 ;
struct TokenDefinition {
2025-11-21 19:17:50 -05:00
account_type : u8 ,
name : [ u8 ; 6 ] ,
total_supply : u128 ,
}
2025-11-20 21:02:18 -05:00
2025-11-21 19:17:50 -05:00
struct TokenHolding {
account_type : u8 ,
definition_id : AccountId ,
balance : u128 ,
2025-11-20 21:02:18 -05:00
}
2025-11-21 19:17:50 -05:00
impl TokenDefinition {
2025-12-15 18:55:38 -05:00
fn into_data ( self ) -> Data {
2025-11-21 19:17:50 -05:00
let mut bytes = [ 0 ; TOKEN_DEFINITION_DATA_SIZE ] ;
bytes [ 0 ] = self . account_type ;
bytes [ 1 .. 7 ] . copy_from_slice ( & self . name ) ;
bytes [ 7 .. ] . copy_from_slice ( & self . total_supply . to_le_bytes ( ) ) ;
2025-12-15 18:55:38 -05:00
bytes
. to_vec ( )
. try_into ( )
. expect ( " 23 bytes should fit into Data " )
2025-11-20 21:02:18 -05:00
}
}
2025-11-21 19:17:50 -05:00
impl TokenHolding {
fn into_data ( self ) -> Data {
let mut bytes = [ 0 ; TOKEN_HOLDING_DATA_SIZE ] ;
bytes [ 0 ] = self . account_type ;
bytes [ 1 .. 33 ] . copy_from_slice ( & self . definition_id . to_bytes ( ) ) ;
bytes [ 33 .. ] . copy_from_slice ( & self . balance . to_le_bytes ( ) ) ;
2025-12-15 18:55:38 -05:00
bytes
. to_vec ( )
. try_into ( )
. expect ( " 33 bytes should fit into Data " )
2025-11-20 21:02:18 -05:00
}
}
2025-12-15 10:40:46 +02:00
// TODO repeated code should ultimately be removed;
2025-12-09 14:42:58 -05:00
fn compute_pool_pda (
amm_program_id : ProgramId ,
definition_token_a_id : AccountId ,
definition_token_b_id : AccountId ,
) -> AccountId {
AccountId ::from ( (
& amm_program_id ,
& compute_pool_pda_seed ( definition_token_a_id , definition_token_b_id ) ,
) )
}
fn compute_pool_pda_seed (
definition_token_a_id : AccountId ,
definition_token_b_id : AccountId ,
) -> PdaSeed {
use risc0_zkvm ::sha ::{ Impl , Sha256 } ;
let mut i : usize = 0 ;
let ( token_1 , token_2 ) = loop {
if definition_token_a_id . value ( ) [ i ] > definition_token_b_id . value ( ) [ i ] {
2025-12-16 14:05:34 +02:00
let token_1 = definition_token_a_id ;
let token_2 = definition_token_b_id ;
2025-12-09 14:42:58 -05:00
break ( token_1 , token_2 ) ;
} else if definition_token_a_id . value ( ) [ i ] < definition_token_b_id . value ( ) [ i ] {
2025-12-16 14:05:34 +02:00
let token_1 = definition_token_b_id ;
let token_2 = definition_token_a_id ;
2025-12-09 14:42:58 -05:00
break ( token_1 , token_2 ) ;
}
2025-11-25 23:06:47 -05:00
2025-12-09 14:42:58 -05:00
if i = = 32 {
panic! ( " Definitions match " ) ;
} else {
i + = 1 ;
}
} ;
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
let mut bytes = [ 0 ; 64 ] ;
bytes [ 0 .. 32 ] . copy_from_slice ( & token_1 . to_bytes ( ) ) ;
bytes [ 32 .. ] . copy_from_slice ( & token_2 . to_bytes ( ) ) ;
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
PdaSeed ::new (
Impl ::hash_bytes ( & bytes )
. as_bytes ( )
. try_into ( )
. expect ( " Hash output must be exactly 32 bytes long " ) ,
)
}
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
fn compute_vault_pda (
amm_program_id : ProgramId ,
pool_id : AccountId ,
definition_token_id : AccountId ,
) -> AccountId {
AccountId ::from ( (
& amm_program_id ,
& compute_vault_pda_seed ( pool_id , definition_token_id ) ,
) )
}
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
fn compute_vault_pda_seed ( pool_id : AccountId , definition_token_id : AccountId ) -> PdaSeed {
use risc0_zkvm ::sha ::{ Impl , Sha256 } ;
2025-11-21 19:17:50 -05:00
2025-12-09 14:42:58 -05:00
let mut bytes = [ 0 ; 64 ] ;
bytes [ 0 .. 32 ] . copy_from_slice ( & pool_id . to_bytes ( ) ) ;
bytes [ 32 .. ] . copy_from_slice ( & definition_token_id . to_bytes ( ) ) ;
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
PdaSeed ::new (
Impl ::hash_bytes ( & bytes )
. as_bytes ( )
. try_into ( )
. expect ( " Hash output must be exactly 32 bytes long " ) ,
)
}
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
fn compute_liquidity_token_pda ( amm_program_id : ProgramId , pool_id : AccountId ) -> AccountId {
AccountId ::from ( ( & amm_program_id , & compute_liquidity_token_pda_seed ( pool_id ) ) )
}
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
fn compute_liquidity_token_pda_seed ( pool_id : AccountId ) -> PdaSeed {
use risc0_zkvm ::sha ::{ Impl , Sha256 } ;
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
let mut bytes = [ 0 ; 64 ] ;
bytes [ 0 .. 32 ] . copy_from_slice ( & pool_id . to_bytes ( ) ) ;
bytes [ 32 .. ] . copy_from_slice ( & [ 0 ; 32 ] ) ;
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
PdaSeed ::new (
Impl ::hash_bytes ( & bytes )
. as_bytes ( )
. try_into ( )
. expect ( " Hash output must be exactly 32 bytes long " ) ,
)
}
const POOL_DEFINITION_DATA_SIZE : usize = 225 ;
2025-12-08 22:05:51 -05:00
2025-12-16 09:27:34 +02:00
#[ derive(Default) ]
2025-12-09 14:42:58 -05:00
struct PoolDefinition {
definition_token_a_id : AccountId ,
definition_token_b_id : AccountId ,
2025-12-16 09:27:34 +02:00
vault_a_id : AccountId ,
vault_b_id : AccountId ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : AccountId ,
liquidity_pool_supply : u128 ,
reserve_a : u128 ,
reserve_b : u128 ,
fees : u128 ,
active : bool ,
}
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
impl PoolDefinition {
2025-12-16 09:27:34 +02:00
fn into_data ( self ) -> Data {
2025-12-09 14:42:58 -05:00
let mut bytes = [ 0 ; POOL_DEFINITION_DATA_SIZE ] ;
bytes [ 0 .. 32 ] . copy_from_slice ( & self . definition_token_a_id . to_bytes ( ) ) ;
bytes [ 32 .. 64 ] . copy_from_slice ( & self . definition_token_b_id . to_bytes ( ) ) ;
2025-12-16 09:27:34 +02:00
bytes [ 64 .. 96 ] . copy_from_slice ( & self . vault_a_id . to_bytes ( ) ) ;
bytes [ 96 .. 128 ] . copy_from_slice ( & self . vault_b_id . to_bytes ( ) ) ;
2025-12-09 14:42:58 -05:00
bytes [ 128 .. 160 ] . copy_from_slice ( & self . liquidity_pool_id . to_bytes ( ) ) ;
bytes [ 160 .. 176 ] . copy_from_slice ( & self . liquidity_pool_supply . to_le_bytes ( ) ) ;
bytes [ 176 .. 192 ] . copy_from_slice ( & self . reserve_a . to_le_bytes ( ) ) ;
bytes [ 192 .. 208 ] . copy_from_slice ( & self . reserve_b . to_le_bytes ( ) ) ;
bytes [ 208 .. 224 ] . copy_from_slice ( & self . fees . to_le_bytes ( ) ) ;
bytes [ 224 ] = self . active as u8 ;
2025-12-16 09:27:34 +02:00
bytes
. to_vec ( )
. try_into ( )
. expect ( " 225 bytes should fit into Data " )
}
2025-12-16 14:05:34 +02:00
#[ allow(unused) ]
2025-12-16 09:27:34 +02:00
fn parse ( data : & [ u8 ] ) -> Option < Self > {
if data . len ( ) ! = POOL_DEFINITION_DATA_SIZE {
None
} else {
let definition_token_a_id = AccountId ::new ( data [ 0 .. 32 ] . try_into ( ) . expect ( " Parse data: The AMM program must be provided a valid AccountId for Token A definition " ) ) ;
let definition_token_b_id = AccountId ::new ( data [ 32 .. 64 ] . try_into ( ) . expect ( " Parse data: The AMM program must be provided a valid AccountId for Vault B definition " ) ) ;
let vault_a_id = AccountId ::new ( data [ 64 .. 96 ] . try_into ( ) . expect (
" Parse data: The AMM program must be provided a valid AccountId for Vault A " ,
) ) ;
let vault_b_id = AccountId ::new ( data [ 96 .. 128 ] . try_into ( ) . expect (
" Parse data: The AMM program must be provided a valid AccountId for Vault B " ,
) ) ;
let liquidity_pool_id = AccountId ::new ( data [ 128 .. 160 ] . try_into ( ) . expect ( " Parse data: The AMM program must be provided a valid AccountId for Token liquidity pool definition " ) ) ;
let liquidity_pool_supply = u128 ::from_le_bytes ( data [ 160 .. 176 ] . try_into ( ) . expect (
" Parse data: The AMM program must be provided a valid u128 for liquidity cap " ,
) ) ;
let reserve_a = u128 ::from_le_bytes ( data [ 176 .. 192 ] . try_into ( ) . expect ( " Parse data: The AMM program must be provided a valid u128 for reserve A balance " ) ) ;
let reserve_b = u128 ::from_le_bytes ( data [ 192 .. 208 ] . try_into ( ) . expect ( " Parse data: The AMM program must be provided a valid u128 for reserve B balance " ) ) ;
let fees =
u128 ::from_le_bytes ( data [ 208 .. 224 ] . try_into ( ) . expect (
" Parse data: The AMM program must be provided a valid u128 for fees " ,
) ) ;
let active = match data [ 224 ] {
0 = > false ,
1 = > true ,
_ = > panic! (
" Parse data: The AMM program must be provided a valid bool for active "
) ,
} ;
Some ( Self {
definition_token_a_id ,
definition_token_b_id ,
vault_a_id ,
vault_b_id ,
liquidity_pool_id ,
liquidity_pool_supply ,
reserve_a ,
reserve_b ,
fees ,
active ,
} )
}
2025-12-09 14:42:58 -05:00
}
2025-12-06 14:52:18 -05:00
}
2025-11-26 21:44:57 -05:00
2025-12-06 14:52:18 -05:00
enum AccountsEnum {
2025-12-07 20:34:26 -05:00
UserTokenAHolding ,
UserTokenBHolding ,
UserTokenLPHolding ,
PoolDefinitionInit ,
TokenADefinitionAcc ,
TokenBDefinitionAcc ,
TokenLPDefinitionAcc ,
VaultAInit ,
VaultBInit ,
VaultASwap1 ,
VaultBSwap1 ,
UserTokenAHoldingSwap1 ,
UserTokenBHoldingSwap1 ,
PoolDefinitionSwap1 ,
VaultASwap2 ,
VaultBSwap2 ,
UserTokenAHoldingSwap2 ,
UserTokenBHoldingSwap2 ,
PoolDefinitionSwap2 ,
VaultAAdd ,
VaultBAdd ,
UserTokenAHoldingAdd ,
2025-12-09 14:42:58 -05:00
UserTokenBHoldingAdd ,
UserTokenLPHoldingAdd ,
2025-12-07 20:34:26 -05:00
PoolDefinitionAdd ,
TokenLPDefinitionAdd ,
VaultARemove ,
VaultBRemove ,
UserTokenAHoldingRemove ,
2025-12-09 14:42:58 -05:00
UserTokenBHoldingRemove ,
UserTokenLPHoldingRemove ,
2025-12-07 20:34:26 -05:00
PoolDefinitionRemove ,
TokenLPDefinitionRemove ,
2025-12-08 22:05:51 -05:00
VaultAInitInactive ,
VaultBInitInactive ,
TokenLPDefinitionInitInactive ,
PoolDefinitionInactive ,
2025-12-09 14:42:58 -05:00
UserTokenAHoldingNewInit ,
UserTokenBHoldingNewInit ,
UserTokenLPHoldingNewInit ,
TokenLPDefinitionNewInit ,
PoolDefinitionNewInit ,
UserTokenLPHoldingInitZero ,
2025-12-06 14:52:18 -05:00
}
enum BalancesEnum {
2025-12-07 20:34:26 -05:00
UserTokenAHoldingInit ,
UserTokenBHoldingInit ,
UserTokenLPHoldingInit ,
VaultABalanceInit ,
VaultBBalanceInit ,
PoolLPSupplyInit ,
TokenASupply ,
TokenBSupply ,
TokenLPSupply ,
RemoveLP ,
RemoveMinAmountA ,
RemoveMinAmountB ,
AddMinAmountLP ,
AddMaxAmountA ,
AddMaxAmountB ,
SwapAmountIn ,
SwapMinAmountOUt ,
VaultABalanceSwap1 ,
VaultBBalanceSwap1 ,
UserTokenAHoldingSwap1 ,
UserTokenBHoldingSwap1 ,
VaultABalanceSwap2 ,
VaultBBalanceSwap2 ,
UserTokenAHoldingSwap2 ,
UserTokenBHoldingSwap2 ,
VaultABalanceAdd ,
VaultBBalanceAdd ,
UserTokenAHoldingAdd ,
UserTokenBHoldingAdd ,
UserTokenLPHoldingAdd ,
TokenLPSupplyAdd ,
VaultABalanceRemove ,
VaultBBalanceRemove ,
UserTokenAHoldingRemove ,
UserTokenBHoldingRemove ,
UserTokenLPHoldingRemove ,
TokenLPSupplyRemove ,
2025-12-09 14:42:58 -05:00
UserTokenAHoldingNewDef ,
UserTokenBHoldingNewDef ,
2025-12-06 14:52:18 -05:00
}
2025-12-16 14:05:34 +02:00
#[ allow(clippy::enum_variant_names) ]
2025-12-06 14:52:18 -05:00
enum IdEnum {
2025-12-07 20:34:26 -05:00
PoolDefinitionId ,
TokenLPDefinitionId ,
TokenADefinitionId ,
TokenBDefinitionId ,
UserTokenAId ,
UserTokenBId ,
UserTokenLPId ,
VaultAId ,
VaultBId ,
2025-12-06 14:52:18 -05:00
}
2025-12-16 14:05:34 +02:00
#[ allow(clippy::enum_variant_names) ]
2025-12-06 14:52:18 -05:00
enum PrivateKeysEnum {
2025-12-07 20:34:26 -05:00
UserTokenAKey ,
UserTokenBKey ,
UserTokenLPKey ,
2025-12-06 14:52:18 -05:00
}
fn helper_balances_constructor ( selection : BalancesEnum ) -> u128 {
match selection {
2025-12-07 20:34:26 -05:00
BalancesEnum ::UserTokenAHoldingInit = > 10_000 ,
BalancesEnum ::UserTokenBHoldingInit = > 10_000 ,
BalancesEnum ::UserTokenLPHoldingInit = > 2_000 ,
BalancesEnum ::VaultABalanceInit = > 5_000 ,
BalancesEnum ::VaultBBalanceInit = > 2_500 ,
BalancesEnum ::PoolLPSupplyInit = > 5_000 ,
BalancesEnum ::TokenASupply = > 100_000 ,
BalancesEnum ::TokenBSupply = > 100_000 ,
BalancesEnum ::TokenLPSupply = > 5_000 ,
BalancesEnum ::RemoveLP = > 1_000 ,
BalancesEnum ::RemoveMinAmountA = > 500 ,
BalancesEnum ::RemoveMinAmountB = > 500 ,
BalancesEnum ::AddMinAmountLP = > 1_000 ,
BalancesEnum ::AddMaxAmountA = > 2_000 ,
BalancesEnum ::AddMaxAmountB = > 1_000 ,
BalancesEnum ::SwapAmountIn = > 1_000 ,
BalancesEnum ::SwapMinAmountOUt = > 200 ,
BalancesEnum ::VaultABalanceSwap1 = > 3_572 ,
BalancesEnum ::VaultBBalanceSwap1 = > 3_500 ,
BalancesEnum ::UserTokenAHoldingSwap1 = > 11_428 ,
BalancesEnum ::UserTokenBHoldingSwap1 = > 9_000 ,
BalancesEnum ::VaultABalanceSwap2 = > 6_000 ,
BalancesEnum ::VaultBBalanceSwap2 = > 2_084 ,
BalancesEnum ::UserTokenAHoldingSwap2 = > 9_000 ,
BalancesEnum ::UserTokenBHoldingSwap2 = > 10_416 ,
BalancesEnum ::VaultABalanceAdd = > 7_000 ,
BalancesEnum ::VaultBBalanceAdd = > 3_500 ,
BalancesEnum ::UserTokenAHoldingAdd = > 8_000 ,
BalancesEnum ::UserTokenBHoldingAdd = > 9_000 ,
BalancesEnum ::UserTokenLPHoldingAdd = > 4_000 ,
BalancesEnum ::TokenLPSupplyAdd = > 7_000 ,
BalancesEnum ::VaultABalanceRemove = > 4_000 ,
BalancesEnum ::VaultBBalanceRemove = > 2_000 ,
BalancesEnum ::UserTokenAHoldingRemove = > 11_000 ,
BalancesEnum ::UserTokenBHoldingRemove = > 10_500 ,
BalancesEnum ::UserTokenLPHoldingRemove = > 1_000 ,
BalancesEnum ::TokenLPSupplyRemove = > 4_000 ,
2025-12-09 14:42:58 -05:00
BalancesEnum ::UserTokenAHoldingNewDef = > 5_000 ,
BalancesEnum ::UserTokenBHoldingNewDef = > 7_500 ,
2025-12-06 14:52:18 -05:00
}
}
2025-11-24 19:44:08 -05:00
2025-12-06 14:52:18 -05:00
fn helper_private_keys_constructor ( selection : PrivateKeysEnum ) -> PrivateKey {
match selection {
2025-12-09 14:42:58 -05:00
PrivateKeysEnum ::UserTokenAKey = > {
PrivateKey ::try_new ( [ 31 ; 32 ] ) . expect ( " Keys constructor expects valid private key " )
}
PrivateKeysEnum ::UserTokenBKey = > {
PrivateKey ::try_new ( [ 32 ; 32 ] ) . expect ( " Keys constructor expects valid private key " )
}
PrivateKeysEnum ::UserTokenLPKey = > {
PrivateKey ::try_new ( [ 33 ; 32 ] ) . expect ( " Keys constructor expects valid private key " )
}
2025-12-06 14:52:18 -05:00
}
2025-11-26 21:44:57 -05:00
}
2025-12-06 14:52:18 -05:00
fn helper_id_constructor ( selection : IdEnum ) -> AccountId {
match selection {
2025-12-08 22:05:51 -05:00
IdEnum ::PoolDefinitionId = > compute_pool_pda (
2025-12-09 14:42:58 -05:00
Program ::amm ( ) . id ( ) ,
helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
) ,
2025-12-08 22:05:51 -05:00
IdEnum ::VaultAId = > compute_vault_pda (
2025-12-09 14:42:58 -05:00
Program ::amm ( ) . id ( ) ,
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
) ,
2025-12-08 22:05:51 -05:00
IdEnum ::VaultBId = > compute_vault_pda (
2025-12-09 14:42:58 -05:00
Program ::amm ( ) . id ( ) ,
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
) ,
2025-12-08 22:05:51 -05:00
IdEnum ::TokenLPDefinitionId = > compute_liquidity_token_pda (
2025-12-09 14:42:58 -05:00
Program ::amm ( ) . id ( ) ,
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
) ,
IdEnum ::TokenADefinitionId = > AccountId ::new ( [ 3 ; 32 ] ) ,
IdEnum ::TokenBDefinitionId = > AccountId ::new ( [ 4 ; 32 ] ) ,
IdEnum ::UserTokenAId = > AccountId ::from ( & PublicKey ::new_from_private_key (
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenAKey ) ,
) ) ,
IdEnum ::UserTokenBId = > AccountId ::from ( & PublicKey ::new_from_private_key (
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenBKey ) ,
) ) ,
IdEnum ::UserTokenLPId = > AccountId ::from ( & PublicKey ::new_from_private_key (
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenLPKey ) ,
) ) ,
2025-12-06 14:52:18 -05:00
}
}
2025-11-21 19:17:50 -05:00
2025-12-06 14:52:18 -05:00
fn helper_account_constructor ( selection : AccountsEnum ) -> Account {
match selection {
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenAHolding = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingInit ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenBHolding = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenBHoldingInit ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::PoolDefinitionInit = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : helper_balances_constructor (
BalancesEnum ::PoolLPSupplyInit ,
2025-12-06 14:52:18 -05:00
) ,
2025-12-09 14:42:58 -05:00
reserve_a : helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) ,
reserve_b : helper_balances_constructor ( BalancesEnum ::VaultBBalanceInit ) ,
fees : 0 u128 ,
active : true ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
AccountsEnum ::TokenADefinitionAcc = > Account {
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : helper_balances_constructor ( BalancesEnum ::TokenASupply ) ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::TokenBDefinitionAcc = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : helper_balances_constructor ( BalancesEnum ::TokenBSupply ) ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::TokenLPDefinitionAcc = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : helper_balances_constructor ( BalancesEnum ::TokenLPSupply ) ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultAInit = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultBInit = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultBBalanceInit ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenLPHolding = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenLPHoldingInit ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultASwap1 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultABalanceSwap1 ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultBSwap1 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultBBalanceSwap1 ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::PoolDefinitionSwap1 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : helper_balances_constructor (
BalancesEnum ::PoolLPSupplyInit ,
) ,
reserve_a : helper_balances_constructor ( BalancesEnum ::VaultABalanceSwap1 ) ,
reserve_b : helper_balances_constructor ( BalancesEnum ::VaultBBalanceSwap1 ) ,
fees : 0 u128 ,
active : true ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenAHoldingSwap1 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingSwap1 ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenBHoldingSwap1 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenBHoldingSwap1 ) ,
} ) ,
nonce : 1 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultASwap2 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultABalanceSwap2 ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultBSwap2 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultBBalanceSwap2 ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::PoolDefinitionSwap2 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : helper_balances_constructor (
BalancesEnum ::PoolLPSupplyInit ,
) ,
reserve_a : helper_balances_constructor ( BalancesEnum ::VaultABalanceSwap2 ) ,
reserve_b : helper_balances_constructor ( BalancesEnum ::VaultBBalanceSwap2 ) ,
fees : 0 u128 ,
active : true ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenAHoldingSwap2 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingSwap2 ) ,
} ) ,
nonce : 1 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenBHoldingSwap2 = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenBHoldingSwap2 ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultAAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultABalanceAdd ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultBAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultBBalanceAdd ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::PoolDefinitionAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : helper_balances_constructor (
BalancesEnum ::TokenLPSupplyAdd ,
) ,
reserve_a : helper_balances_constructor ( BalancesEnum ::VaultABalanceAdd ) ,
reserve_b : helper_balances_constructor ( BalancesEnum ::VaultBBalanceAdd ) ,
fees : 0 u128 ,
active : true ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenAHoldingAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingAdd ) ,
} ) ,
nonce : 1 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenBHoldingAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenBHoldingAdd ) ,
} ) ,
nonce : 1 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenLPHoldingAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenLPHoldingAdd ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::TokenLPDefinitionAdd = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : helper_balances_constructor ( BalancesEnum ::TokenLPSupplyAdd ) ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultARemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultABalanceRemove ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::VaultBRemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::VaultBBalanceRemove ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::PoolDefinitionRemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : helper_balances_constructor (
BalancesEnum ::TokenLPSupplyRemove ,
) ,
reserve_a : helper_balances_constructor ( BalancesEnum ::VaultABalanceRemove ) ,
reserve_b : helper_balances_constructor ( BalancesEnum ::VaultBBalanceRemove ) ,
fees : 0 u128 ,
active : true ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenAHoldingRemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingRemove ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenBHoldingRemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenBHoldingRemove ) ,
} ) ,
nonce : 0 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::UserTokenLPHoldingRemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenLPHoldingRemove ) ,
} ) ,
nonce : 1 ,
} ,
2025-12-07 20:34:26 -05:00
AccountsEnum ::TokenLPDefinitionRemove = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : helper_balances_constructor ( BalancesEnum ::TokenLPSupplyRemove ) ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-08 22:05:51 -05:00
AccountsEnum ::TokenLPDefinitionInitInactive = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : 0 ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
2025-12-08 22:05:51 -05:00
AccountsEnum ::VaultAInitInactive = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : 0 ,
} ) ,
nonce : 0 ,
} ,
2025-12-08 22:05:51 -05:00
AccountsEnum ::VaultBInitInactive = > Account {
2025-12-09 14:42:58 -05:00
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : 0 ,
} ) ,
nonce : 0 ,
} ,
AccountsEnum ::PoolDefinitionInactive = > Account {
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : 0 ,
reserve_a : 0 ,
reserve_b : 0 ,
fees : 0 u128 ,
active : false ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
AccountsEnum ::UserTokenAHoldingNewInit = > Account {
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingNewDef ) ,
} ) ,
nonce : 1 ,
} ,
AccountsEnum ::UserTokenBHoldingNewInit = > Account {
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenBHoldingNewDef ) ,
} ) ,
nonce : 1 ,
} ,
AccountsEnum ::UserTokenLPHoldingNewInit = > Account {
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
balance : helper_balances_constructor ( BalancesEnum ::UserTokenAHoldingNewDef ) ,
} ) ,
nonce : 0 ,
} ,
AccountsEnum ::TokenLPDefinitionNewInit = > Account {
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenDefinition ::into_data ( TokenDefinition {
account_type : 0 u8 ,
name : [ 1 u8 ; 6 ] ,
total_supply : helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
AccountsEnum ::PoolDefinitionNewInit = > Account {
program_owner : Program ::amm ( ) . id ( ) ,
balance : 0 u128 ,
data : PoolDefinition ::into_data ( PoolDefinition {
definition_token_a_id : helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
definition_token_b_id : helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-15 18:55:38 -05:00
vault_a_id : helper_id_constructor ( IdEnum ::VaultAId ) ,
vault_b_id : helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
liquidity_pool_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
liquidity_pool_supply : helper_balances_constructor (
BalancesEnum ::UserTokenAHoldingNewDef ,
) ,
reserve_a : helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) ,
reserve_b : helper_balances_constructor ( BalancesEnum ::VaultBBalanceInit ) ,
fees : 0 u128 ,
active : true ,
2025-12-16 14:05:34 +02:00
} ) ,
2025-12-09 14:42:58 -05:00
nonce : 0 ,
} ,
AccountsEnum ::UserTokenLPHoldingInitZero = > Account {
program_owner : Program ::token ( ) . id ( ) ,
balance : 0 u128 ,
data : TokenHolding ::into_data ( TokenHolding {
account_type : 1 u8 ,
definition_id : helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
balance : 0 ,
} ) ,
nonce : 0 ,
} ,
2025-12-06 14:52:18 -05:00
}
}
2025-11-21 19:17:50 -05:00
2025-12-06 14:52:18 -05:00
fn amm_state_constructor ( ) -> V02State {
let initial_data = [ ] ;
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::PoolDefinitionInit ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::TokenADefinitionAcc ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::TokenBDefinitionAcc ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::TokenLPDefinitionAcc ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::UserTokenAHolding ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::UserTokenBHolding ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::UserTokenLPHolding ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::VaultAId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::VaultAInit ) ,
2025-12-06 14:52:18 -05:00
) ;
state . force_insert_account (
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::VaultBInit ) ,
2025-12-06 14:52:18 -05:00
) ;
2025-11-25 23:06:47 -05:00
2025-12-06 14:52:18 -05:00
state
2025-11-26 21:44:57 -05:00
}
2025-11-25 23:06:47 -05:00
2025-12-08 22:05:51 -05:00
fn amm_state_constructor_for_new_def ( ) -> V02State {
let initial_data = [ ] ;
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::TokenADefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::TokenADefinitionAcc ) ,
2025-12-08 22:05:51 -05:00
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::TokenBDefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::TokenBDefinitionAcc ) ,
2025-12-08 22:05:51 -05:00
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::UserTokenAHolding ) ,
2025-12-08 22:05:51 -05:00
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::UserTokenBHolding ) ,
2025-12-08 22:05:51 -05:00
) ;
state
}
2025-11-26 21:44:57 -05:00
#[ test ]
fn test_simple_amm_remove ( ) {
2025-12-06 14:52:18 -05:00
let mut state = amm_state_constructor ( ) ;
2025-11-25 23:06:47 -05:00
2025-11-26 21:44:57 -05:00
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
instruction . push ( 3 ) ;
2025-12-09 14:42:58 -05:00
instruction
. extend_from_slice ( & helper_balances_constructor ( BalancesEnum ::RemoveLP ) . to_le_bytes ( ) ) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::RemoveMinAmountA ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::RemoveMinAmountB ) . to_le_bytes ( ) ,
) ;
2025-11-25 23:06:47 -05:00
let message = public_transaction ::Message ::try_new (
2025-11-26 21:44:57 -05:00
Program ::amm ( ) . id ( ) ,
vec! [
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
2025-11-26 21:44:57 -05:00
] ,
2025-12-08 22:05:51 -05:00
vec! [ 0 ] ,
2025-11-25 23:06:47 -05:00
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
2025-12-09 14:42:58 -05:00
& [ & helper_private_keys_constructor (
PrivateKeysEnum ::UserTokenLPKey ,
) ] ,
2025-11-25 23:06:47 -05:00
) ;
2025-11-26 21:44:57 -05:00
2025-11-21 19:17:50 -05:00
let tx = PublicTransaction ::new ( message , witness_set ) ;
2025-11-25 23:06:47 -05:00
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-12-07 20:34:26 -05:00
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
2025-12-09 14:42:58 -05:00
let token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ) ;
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
let user_token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenLPId ) ) ;
2025-12-07 20:34:26 -05:00
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionRemove ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultARemove ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBRemove ) ;
let expected_token_lp = helper_account_constructor ( AccountsEnum ::TokenLPDefinitionRemove ) ;
2025-12-09 14:42:58 -05:00
let expected_user_token_a =
helper_account_constructor ( AccountsEnum ::UserTokenAHoldingRemove ) ;
let expected_user_token_b =
helper_account_constructor ( AccountsEnum ::UserTokenBHoldingRemove ) ;
let expected_user_token_lp =
helper_account_constructor ( AccountsEnum ::UserTokenLPHoldingRemove ) ;
2025-12-07 20:34:26 -05:00
assert! ( pool_post = = expected_pool ) ;
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
assert! ( token_lp_post = = expected_token_lp ) ;
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
assert! ( user_token_lp_post = = expected_user_token_lp ) ;
2025-11-26 21:44:57 -05:00
}
2025-12-08 22:05:51 -05:00
#[ test ]
2025-12-09 14:42:58 -05:00
fn test_simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp ( ) {
2025-12-08 22:05:51 -05:00
let mut state = amm_state_constructor_for_new_def ( ) ;
2025-12-09 14:42:58 -05:00
// Uninitialized in constructor
2025-12-08 22:05:51 -05:00
state . force_insert_account (
helper_id_constructor ( IdEnum ::VaultAId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::VaultAInitInactive ) ,
2025-12-08 22:05:51 -05:00
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::VaultBId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::VaultBInitInactive ) ,
2025-12-08 22:05:51 -05:00
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::PoolDefinitionInactive ) ,
2025-12-08 22:05:51 -05:00
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
2025-12-09 14:42:58 -05:00
helper_account_constructor ( AccountsEnum ::TokenLPDefinitionInitInactive ) ,
2025-12-08 22:05:51 -05:00
) ;
2025-12-09 14:42:58 -05:00
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
instruction . push ( 0 ) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::VaultBBalanceInit ) . to_le_bytes ( ) ,
) ;
let amm_program_u8 : [ u8 ; 32 ] = bytemuck ::cast ( Program ::amm ( ) . id ( ) ) ;
instruction . extend_from_slice ( & amm_program_u8 ) ;
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
let message = public_transaction ::Message ::try_new (
Program ::amm ( ) . id ( ) ,
vec! [
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
] ,
vec! [ 0 , 0 ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
& [
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenAKey ) ,
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenBKey ) ,
] ,
) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
let token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ) ;
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
let user_token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenLPId ) ) ;
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionNewInit ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultAInit ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBInit ) ;
let expected_token_lp = helper_account_constructor ( AccountsEnum ::TokenLPDefinitionNewInit ) ;
let expected_user_token_a =
helper_account_constructor ( AccountsEnum ::UserTokenAHoldingNewInit ) ;
let expected_user_token_b =
helper_account_constructor ( AccountsEnum ::UserTokenBHoldingNewInit ) ;
let expected_user_token_lp =
helper_account_constructor ( AccountsEnum ::UserTokenLPHoldingNewInit ) ;
assert! ( pool_post = = expected_pool ) ;
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
assert! ( token_lp_post = = expected_token_lp ) ;
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
assert! ( user_token_lp_post = = expected_user_token_lp ) ;
}
#[ test ]
fn test_simple_amm_new_definition_inactive_initialized_pool_init_user_lp ( ) {
let mut state = amm_state_constructor_for_new_def ( ) ;
// Uninitialized in constructor
state . force_insert_account (
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_account_constructor ( AccountsEnum ::VaultAInitInactive ) ,
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_account_constructor ( AccountsEnum ::VaultBInitInactive ) ,
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_account_constructor ( AccountsEnum ::PoolDefinitionInactive ) ,
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
helper_account_constructor ( AccountsEnum ::TokenLPDefinitionInitInactive ) ,
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
helper_account_constructor ( AccountsEnum ::UserTokenLPHoldingInitZero ) ,
) ;
2025-12-08 22:05:51 -05:00
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
instruction . push ( 0 ) ;
2025-12-09 14:42:58 -05:00
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::VaultBBalanceInit ) . to_le_bytes ( ) ,
) ;
2025-12-08 22:05:51 -05:00
let amm_program_u8 : [ u8 ; 32 ] = bytemuck ::cast ( Program ::amm ( ) . id ( ) ) ;
instruction . extend_from_slice ( & amm_program_u8 ) ;
let message = public_transaction ::Message ::try_new (
Program ::amm ( ) . id ( ) ,
vec! [
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
] ,
vec! [ 0 , 0 ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
& [
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenAKey ) ,
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenBKey ) ,
] ,
) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-12-09 14:42:58 -05:00
2025-12-08 22:05:51 -05:00
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
2025-12-09 14:42:58 -05:00
let token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ) ;
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
let user_token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenLPId ) ) ;
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionNewInit ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultAInit ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBInit ) ;
let expected_token_lp = helper_account_constructor ( AccountsEnum ::TokenLPDefinitionNewInit ) ;
let expected_user_token_a =
helper_account_constructor ( AccountsEnum ::UserTokenAHoldingNewInit ) ;
let expected_user_token_b =
helper_account_constructor ( AccountsEnum ::UserTokenBHoldingNewInit ) ;
let expected_user_token_lp =
helper_account_constructor ( AccountsEnum ::UserTokenLPHoldingNewInit ) ;
2025-12-08 22:05:51 -05:00
assert! ( pool_post = = expected_pool ) ;
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
assert! ( token_lp_post = = expected_token_lp ) ;
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
2025-12-09 14:42:58 -05:00
assert! ( user_token_lp_post = = expected_user_token_lp ) ;
2025-12-08 22:05:51 -05:00
}
2025-12-09 14:42:58 -05:00
#[ test ]
fn test_simple_amm_new_definition_uninitialized_pool ( ) {
let mut state = amm_state_constructor_for_new_def ( ) ;
// Uninitialized in constructor
state . force_insert_account (
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_account_constructor ( AccountsEnum ::VaultAInitInactive ) ,
) ;
state . force_insert_account (
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_account_constructor ( AccountsEnum ::VaultBInitInactive ) ,
) ;
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
instruction . push ( 0 ) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::VaultABalanceInit ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::VaultBBalanceInit ) . to_le_bytes ( ) ,
) ;
let amm_program_u8 : [ u8 ; 32 ] = bytemuck ::cast ( Program ::amm ( ) . id ( ) ) ;
instruction . extend_from_slice ( & amm_program_u8 ) ;
let message = public_transaction ::Message ::try_new (
Program ::amm ( ) . id ( ) ,
vec! [
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
] ,
vec! [ 0 , 0 ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
& [
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenAKey ) ,
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenBKey ) ,
] ,
) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
let token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ) ;
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
let user_token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenLPId ) ) ;
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionNewInit ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultAInit ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBInit ) ;
let expected_token_lp = helper_account_constructor ( AccountsEnum ::TokenLPDefinitionNewInit ) ;
let expected_user_token_a =
helper_account_constructor ( AccountsEnum ::UserTokenAHoldingNewInit ) ;
let expected_user_token_b =
helper_account_constructor ( AccountsEnum ::UserTokenBHoldingNewInit ) ;
let expected_user_token_lp =
helper_account_constructor ( AccountsEnum ::UserTokenLPHoldingNewInit ) ;
assert! ( pool_post = = expected_pool ) ;
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
assert! ( token_lp_post = = expected_token_lp ) ;
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
assert! ( user_token_lp_post = = expected_user_token_lp ) ;
}
2025-12-08 22:05:51 -05:00
2025-11-26 21:44:57 -05:00
#[ test ]
fn test_simple_amm_add ( ) {
2025-12-06 14:52:18 -05:00
let mut state = amm_state_constructor ( ) ;
2025-11-26 21:44:57 -05:00
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
instruction . push ( 2 ) ;
2025-12-09 14:42:58 -05:00
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::AddMinAmountLP ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::AddMaxAmountA ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::AddMaxAmountB ) . to_le_bytes ( ) ,
) ;
2025-11-21 19:17:50 -05:00
2025-11-25 23:06:47 -05:00
let message = public_transaction ::Message ::try_new (
2025-11-26 21:44:57 -05:00
Program ::amm ( ) . id ( ) ,
vec! [
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
helper_id_constructor ( IdEnum ::UserTokenLPId ) ,
2025-11-26 21:44:57 -05:00
] ,
2025-12-09 14:42:58 -05:00
vec! [ 0 , 0 ] ,
2025-11-25 23:06:47 -05:00
instruction ,
)
. unwrap ( ) ;
2025-11-21 19:17:50 -05:00
2025-11-25 23:06:47 -05:00
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
2025-11-26 21:44:57 -05:00
& [
2025-12-07 20:34:26 -05:00
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenAKey ) ,
& helper_private_keys_constructor ( PrivateKeysEnum ::UserTokenBKey ) ,
2025-11-26 21:44:57 -05:00
] ,
2025-11-25 23:06:47 -05:00
) ;
2025-11-26 21:44:57 -05:00
2025-11-25 23:06:47 -05:00
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-12-07 20:34:26 -05:00
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
2025-12-09 14:42:58 -05:00
let token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::TokenLPDefinitionId ) ) ;
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
let user_token_lp_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenLPId ) ) ;
2025-12-07 20:34:26 -05:00
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionAdd ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultAAdd ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBAdd ) ;
let expected_token_lp = helper_account_constructor ( AccountsEnum ::TokenLPDefinitionAdd ) ;
let expected_user_token_a = helper_account_constructor ( AccountsEnum ::UserTokenAHoldingAdd ) ;
let expected_user_token_b = helper_account_constructor ( AccountsEnum ::UserTokenBHoldingAdd ) ;
2025-12-09 14:42:58 -05:00
let expected_user_token_lp =
helper_account_constructor ( AccountsEnum ::UserTokenLPHoldingAdd ) ;
2025-11-26 21:44:57 -05:00
2025-12-06 14:52:18 -05:00
assert! ( pool_post = = expected_pool ) ;
2025-11-26 21:44:57 -05:00
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
2025-12-06 14:52:18 -05:00
assert! ( token_lp_post = = expected_token_lp ) ;
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
assert! ( user_token_lp_post = = expected_user_token_lp ) ;
2025-11-26 21:44:57 -05:00
}
2025-12-06 14:52:18 -05:00
2025-11-26 21:44:57 -05:00
#[ test ]
fn test_simple_amm_swap_1 ( ) {
2025-12-06 14:52:18 -05:00
let mut state = amm_state_constructor ( ) ;
2025-11-25 23:06:47 -05:00
2025-11-26 21:44:57 -05:00
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
instruction . push ( 1 ) ;
2025-12-09 14:42:58 -05:00
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::SwapAmountIn ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::SwapMinAmountOUt ) . to_le_bytes ( ) ,
) ;
instruction
. extend_from_slice ( & helper_id_constructor ( IdEnum ::TokenBDefinitionId ) . to_bytes ( ) ) ;
2025-11-25 23:06:47 -05:00
let message = public_transaction ::Message ::try_new (
Program ::amm ( ) . id ( ) ,
vec! [
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
2025-11-25 23:06:47 -05:00
] ,
2025-12-08 22:05:51 -05:00
vec! [ 0 ] ,
2025-11-25 23:06:47 -05:00
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
2025-12-09 14:42:58 -05:00
& [ & helper_private_keys_constructor (
PrivateKeysEnum ::UserTokenBKey ,
) ] ,
2025-11-25 23:06:47 -05:00
) ;
2025-11-26 21:44:57 -05:00
2025-11-25 23:06:47 -05:00
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-12-09 14:42:58 -05:00
2025-12-07 20:34:26 -05:00
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
2025-12-09 14:42:58 -05:00
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
2025-11-25 23:06:47 -05:00
2025-12-07 20:34:26 -05:00
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionSwap1 ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultASwap1 ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBSwap1 ) ;
2025-12-09 14:42:58 -05:00
let expected_user_token_a =
helper_account_constructor ( AccountsEnum ::UserTokenAHoldingSwap1 ) ;
let expected_user_token_b =
helper_account_constructor ( AccountsEnum ::UserTokenBHoldingSwap1 ) ;
2025-11-25 23:06:47 -05:00
2025-12-06 14:52:18 -05:00
assert! ( pool_post = = expected_pool ) ;
2025-11-26 21:44:57 -05:00
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
2025-12-06 14:52:18 -05:00
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
2025-11-26 21:44:57 -05:00
}
2025-12-06 14:52:18 -05:00
2025-11-26 21:44:57 -05:00
#[ test ]
fn test_simple_amm_swap_2 ( ) {
2025-12-06 14:52:18 -05:00
let mut state = amm_state_constructor ( ) ;
2025-11-25 23:06:47 -05:00
let mut instruction : Vec < u8 > = Vec ::new ( ) ;
2025-11-26 21:44:57 -05:00
instruction . push ( 1 ) ;
2025-12-09 14:42:58 -05:00
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::SwapAmountIn ) . to_le_bytes ( ) ,
) ;
instruction . extend_from_slice (
& helper_balances_constructor ( BalancesEnum ::SwapMinAmountOUt ) . to_le_bytes ( ) ,
) ;
instruction
. extend_from_slice ( & helper_id_constructor ( IdEnum ::TokenADefinitionId ) . to_bytes ( ) ) ;
2025-11-26 21:44:57 -05:00
2025-11-25 23:06:47 -05:00
let message = public_transaction ::Message ::try_new (
Program ::amm ( ) . id ( ) ,
vec! [
2025-12-07 20:34:26 -05:00
helper_id_constructor ( IdEnum ::PoolDefinitionId ) ,
helper_id_constructor ( IdEnum ::VaultAId ) ,
helper_id_constructor ( IdEnum ::VaultBId ) ,
helper_id_constructor ( IdEnum ::UserTokenAId ) ,
helper_id_constructor ( IdEnum ::UserTokenBId ) ,
2025-11-26 21:44:57 -05:00
] ,
2025-12-08 22:05:51 -05:00
vec! [ 0 ] ,
2025-11-25 23:06:47 -05:00
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message (
& message ,
2025-12-09 14:42:58 -05:00
& [ & helper_private_keys_constructor (
PrivateKeysEnum ::UserTokenAKey ,
) ] ,
2025-11-25 23:06:47 -05:00
) ;
2025-11-26 21:44:57 -05:00
2025-11-25 23:06:47 -05:00
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
2025-12-09 14:42:58 -05:00
2025-12-07 20:34:26 -05:00
let pool_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::PoolDefinitionId ) ) ;
let vault_a_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultAId ) ) ;
let vault_b_post = state . get_account_by_id ( & helper_id_constructor ( IdEnum ::VaultBId ) ) ;
2025-12-09 14:42:58 -05:00
let user_token_a_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenAId ) ) ;
let user_token_b_post =
state . get_account_by_id ( & helper_id_constructor ( IdEnum ::UserTokenBId ) ) ;
2025-11-25 23:06:47 -05:00
2025-12-07 20:34:26 -05:00
let expected_pool = helper_account_constructor ( AccountsEnum ::PoolDefinitionSwap2 ) ;
let expected_vault_a = helper_account_constructor ( AccountsEnum ::VaultASwap2 ) ;
let expected_vault_b = helper_account_constructor ( AccountsEnum ::VaultBSwap2 ) ;
2025-12-09 14:42:58 -05:00
let expected_user_token_a =
helper_account_constructor ( AccountsEnum ::UserTokenAHoldingSwap2 ) ;
let expected_user_token_b =
helper_account_constructor ( AccountsEnum ::UserTokenBHoldingSwap2 ) ;
2025-11-26 21:44:57 -05:00
2025-12-06 14:52:18 -05:00
assert! ( pool_post = = expected_pool ) ;
2025-11-26 21:44:57 -05:00
assert! ( vault_a_post = = expected_vault_a ) ;
assert! ( vault_b_post = = expected_vault_b ) ;
2025-12-06 14:52:18 -05:00
assert! ( user_token_a_post = = expected_user_token_a ) ;
assert! ( user_token_b_post = = expected_user_token_b ) ;
2025-11-26 21:44:57 -05:00
}
2025-12-06 14:52:18 -05:00
2025-11-27 13:49:56 -03:00
#[ test ]
fn test_execution_that_requires_authentication_of_a_program_derived_account_id_succeeds ( ) {
let chain_caller = Program ::chain_caller ( ) ;
let pda_seed = PdaSeed ::new ( [ 37 ; 32 ] ) ;
let from = AccountId ::from ( ( & chain_caller . id ( ) , & pda_seed ) ) ;
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
let initial_balance = 1000 ;
let initial_data = [ ( from , initial_balance ) , ( to , 0 ) ] ;
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
let amount : u128 = 58 ;
let instruction : ( u128 , ProgramId , u32 , Option < PdaSeed > ) = (
amount ,
Program ::authenticated_transfer_program ( ) . id ( ) ,
1 ,
Some ( pda_seed ) ,
) ;
let expected_to_post = Account {
program_owner : Program ::authenticated_transfer_program ( ) . id ( ) ,
balance : amount , // The `chain_caller` chains the program twice
.. Account ::default ( )
} ;
let message = public_transaction ::Message ::try_new (
chain_caller . id ( ) ,
vec! [ to , from ] , // The chain_caller program permutes the account order in the chain
// call
vec! [ ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
let from_post = state . get_account_by_id ( & from ) ;
let to_post = state . get_account_by_id ( & to ) ;
2025-12-05 10:00:07 -03:00
assert_eq! ( from_post . balance , initial_balance - amount ) ;
assert_eq! ( to_post , expected_to_post ) ;
}
2025-12-03 17:06:09 -03:00
#[ test ]
fn test_claiming_mechanism_within_chain_call ( ) {
// This test calls the authenticated transfer program through the chain_caller program.
// The transfer is made from an initialized sender to an uninitialized recipient. And
// it is expected that the recipient account is claimed by the authenticated transfer
// program and not the chained_caller program.
let chain_caller = Program ::chain_caller ( ) ;
let auth_transfer = Program ::authenticated_transfer_program ( ) ;
let key = PrivateKey ::try_new ( [ 1 ; 32 ] ) . unwrap ( ) ;
let account_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & key ) ) ;
let initial_balance = 100 ;
let initial_data = [ ( account_id , initial_balance ) ] ;
let mut state =
V02State ::new_with_genesis_accounts ( & initial_data , & [ ] ) . with_test_programs ( ) ;
let from = account_id ;
let from_key = key ;
let to = AccountId ::new ( [ 2 ; 32 ] ) ;
let amount : u128 = 37 ;
// Check the recipient is an uninitialized account
assert_eq! ( state . get_account_by_id ( & to ) , Account ::default ( ) ) ;
let expected_to_post = Account {
// The expected program owner is the authenticated transfer program
program_owner : auth_transfer . id ( ) ,
balance : amount ,
.. Account ::default ( )
} ;
// The transaction executes the chain_caller program, which internally calls the
// authenticated_transfer program
2025-12-05 10:00:07 -03:00
let instruction : ( u128 , ProgramId , u32 , Option < PdaSeed > ) = (
amount ,
Program ::authenticated_transfer_program ( ) . id ( ) ,
1 ,
None ,
) ;
2025-12-03 17:06:09 -03:00
let message = public_transaction ::Message ::try_new (
chain_caller . id ( ) ,
vec! [ to , from ] , // The chain_caller program permutes the account order in the chain
// call
vec! [ 0 ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ & from_key ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
let from_post = state . get_account_by_id ( & from ) ;
let to_post = state . get_account_by_id ( & to ) ;
2025-11-27 13:49:56 -03:00
assert_eq! ( from_post . balance , initial_balance - amount ) ;
assert_eq! ( to_post , expected_to_post ) ;
}
2025-11-28 11:10:00 -03:00
2025-11-20 01:40:05 -03:00
#[ test ]
fn test_private_chained_call ( ) {
2025-11-22 17:48:29 -03:00
// Arrange
2025-11-20 19:25:56 -03:00
let chain_caller = Program ::chain_caller ( ) ;
let auth_transfers = Program ::authenticated_transfer_program ( ) ;
2025-11-20 01:40:05 -03:00
let from_keys = test_private_account_keys_1 ( ) ;
2025-11-20 19:25:56 -03:00
let to_keys = test_private_account_keys_2 ( ) ;
2025-11-20 01:40:05 -03:00
let initial_balance = 100 ;
let from_account = AccountWithMetadata ::new (
Account {
2025-11-20 19:25:56 -03:00
program_owner : auth_transfers . id ( ) ,
2025-11-20 01:40:05 -03:00
balance : initial_balance ,
.. Account ::default ( )
} ,
true ,
& from_keys . npk ( ) ,
) ;
2025-11-20 19:25:56 -03:00
let to_account = AccountWithMetadata ::new (
Account {
program_owner : auth_transfers . id ( ) ,
.. Account ::default ( )
} ,
true ,
& to_keys . npk ( ) ,
) ;
2025-11-22 17:48:29 -03:00
2025-11-20 01:40:05 -03:00
let from_commitment = Commitment ::new ( & from_keys . npk ( ) , & from_account . account ) ;
2025-11-20 19:25:56 -03:00
let to_commitment = Commitment ::new ( & to_keys . npk ( ) , & to_account . account ) ;
2025-11-22 17:48:29 -03:00
let mut state = V02State ::new_with_genesis_accounts (
2025-11-20 19:25:56 -03:00
& [ ] ,
& [ from_commitment . clone ( ) , to_commitment . clone ( ) ] ,
)
. with_test_programs ( ) ;
2025-11-20 01:40:05 -03:00
let amount : u128 = 37 ;
2025-12-09 22:27:38 -03:00
let instruction : ( u128 , ProgramId , u32 , Option < PdaSeed > ) = (
amount ,
Program ::authenticated_transfer_program ( ) . id ( ) ,
1 ,
None ,
) ;
2025-11-20 01:40:05 -03:00
let from_esk = [ 3 ; 32 ] ;
let from_ss = SharedSecretKey ::new ( & from_esk , & from_keys . ivk ( ) ) ;
2025-11-22 17:48:29 -03:00
let from_epk = EphemeralPublicKey ::from_scalar ( from_esk ) ;
2025-11-20 01:40:05 -03:00
2025-11-20 19:25:56 -03:00
let to_esk = [ 3 ; 32 ] ;
2025-11-20 01:40:05 -03:00
let to_ss = SharedSecretKey ::new ( & to_esk , & to_keys . ivk ( ) ) ;
2025-11-22 17:48:29 -03:00
let to_epk = EphemeralPublicKey ::from_scalar ( to_esk ) ;
2025-11-25 15:03:17 -03:00
2025-11-20 19:25:56 -03:00
let mut dependencies = HashMap ::new ( ) ;
2025-11-20 01:40:05 -03:00
2025-11-20 19:25:56 -03:00
dependencies . insert ( auth_transfers . id ( ) , auth_transfers ) ;
let program_with_deps = ProgramWithDependencies ::new ( chain_caller , dependencies ) ;
2025-11-22 17:48:29 -03:00
let from_new_nonce = 0xdeadbeef1 ;
2025-12-09 22:27:38 -03:00
let to_new_nonce = 0xdeadbeef2 ;
2025-11-22 17:48:29 -03:00
let from_expected_post = Account {
balance : initial_balance - amount ,
nonce : from_new_nonce ,
.. from_account . account . clone ( )
} ;
let from_expected_commitment = Commitment ::new ( & from_keys . npk ( ) , & from_expected_post ) ;
let to_expected_post = Account {
balance : amount ,
nonce : to_new_nonce ,
.. to_account . account . clone ( )
} ;
let to_expected_commitment = Commitment ::new ( & to_keys . npk ( ) , & to_expected_post ) ;
// Act
let ( output , proof ) = execute_and_prove (
2025-11-20 19:25:56 -03:00
& [ to_account , from_account ] ,
2025-11-20 01:40:05 -03:00
& Program ::serialize_instruction ( instruction ) . unwrap ( ) ,
2025-11-20 19:25:56 -03:00
& [ 1 , 1 ] ,
2025-12-09 22:27:38 -03:00
& [ from_new_nonce , to_new_nonce ] ,
& [ ( from_keys . npk ( ) , to_ss ) , ( to_keys . npk ( ) , from_ss ) ] ,
2025-11-20 19:25:56 -03:00
& [
(
from_keys . nsk ,
state . get_proof_for_commitment ( & from_commitment ) . unwrap ( ) ,
) ,
2025-12-09 22:27:38 -03:00
(
to_keys . nsk ,
state . get_proof_for_commitment ( & to_commitment ) . unwrap ( ) ,
) ,
2025-11-20 19:25:56 -03:00
] ,
& program_with_deps ,
2025-11-20 01:40:05 -03:00
)
. unwrap ( ) ;
2025-11-20 19:25:56 -03:00
2025-11-22 17:48:29 -03:00
let message = Message ::try_from_circuit_output (
vec! [ ] ,
vec! [ ] ,
vec! [
( to_keys . npk ( ) , to_keys . ivk ( ) , to_epk ) ,
( from_keys . npk ( ) , from_keys . ivk ( ) , from_epk ) ,
] ,
output ,
)
. unwrap ( ) ;
let witness_set = WitnessSet ::for_message ( & message , proof , & [ ] ) ;
let transaction = PrivacyPreservingTransaction ::new ( message , witness_set ) ;
state
. transition_from_privacy_preserving_transaction ( & transaction )
. unwrap ( ) ;
// Assert
assert! (
state
. get_proof_for_commitment ( & from_expected_commitment )
. is_some ( )
) ;
assert! (
state
. get_proof_for_commitment ( & to_expected_commitment )
. is_some ( )
) ;
}
2025-12-09 22:27:38 -03:00
2025-11-28 11:10:00 -03:00
#[ test ]
fn test_pda_mechanism_with_pinata_token_program ( ) {
let pinata_token = Program ::pinata_token ( ) ;
let token = Program ::token ( ) ;
let pinata_definition_id = AccountId ::new ( [ 1 ; 32 ] ) ;
let pinata_token_definition_id = AccountId ::new ( [ 2 ; 32 ] ) ;
// Total supply of pinata token will be in an account under a PDA.
let pinata_token_holding_id = AccountId ::from ( ( & pinata_token . id ( ) , & PdaSeed ::new ( [ 0 ; 32 ] ) ) ) ;
let winner_token_holding_id = AccountId ::new ( [ 3 ; 32 ] ) ;
let mut expected_winner_account_data = [ 0 ; 49 ] ;
expected_winner_account_data [ 0 ] = 1 ;
expected_winner_account_data [ 1 .. 33 ] . copy_from_slice ( pinata_token_definition_id . value ( ) ) ;
expected_winner_account_data [ 33 .. ] . copy_from_slice ( & 150 u128 . to_le_bytes ( ) ) ;
let expected_winner_token_holding_post = Account {
program_owner : token . id ( ) ,
2025-12-05 02:17:09 +03:00
data : expected_winner_account_data . to_vec ( ) . try_into ( ) . unwrap ( ) ,
2025-11-28 11:10:00 -03:00
.. Account ::default ( )
} ;
let mut state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] ) ;
state . add_pinata_token_program ( pinata_definition_id ) ;
// Execution of the token program to create new token for the pinata token
// definition and supply accounts
let total_supply : u128 = 10_000_000 ;
// instruction: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
let mut instruction : [ u8 ; 23 ] = [ 0 ; 23 ] ;
instruction [ 1 .. 17 ] . copy_from_slice ( & total_supply . to_le_bytes ( ) ) ;
instruction [ 17 .. ] . copy_from_slice ( b " PINATA " ) ;
let message = public_transaction ::Message ::try_new (
token . id ( ) ,
vec! [ pinata_token_definition_id , pinata_token_holding_id ] ,
vec! [ ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
// Execution of the token program transfer just to initialize the winner token account
let mut instruction : [ u8 ; 23 ] = [ 0 ; 23 ] ;
instruction [ 0 ] = 2 ;
let message = public_transaction ::Message ::try_new (
token . id ( ) ,
vec! [ pinata_token_definition_id , winner_token_holding_id ] ,
vec! [ ] ,
instruction ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
// Submit a solution to the pinata program to claim the prize
let solution : u128 = 989106 ;
let message = public_transaction ::Message ::try_new (
pinata_token . id ( ) ,
vec! [
pinata_definition_id ,
pinata_token_holding_id ,
winner_token_holding_id ,
] ,
vec! [ ] ,
solution ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
state . transition_from_public_transaction ( & tx ) . unwrap ( ) ;
let winner_token_holding_post = state . get_account_by_id ( & winner_token_holding_id ) ;
2025-11-28 13:55:19 -03:00
assert_eq! (
winner_token_holding_post ,
expected_winner_token_holding_post
) ;
2025-11-28 11:10:00 -03:00
}
2025-12-05 10:00:07 -03:00
2025-12-03 17:36:53 -03:00
#[ test ]
fn test_claiming_mechanism_cannot_claim_initialied_accounts ( ) {
let claimer = Program ::claimer ( ) ;
let mut state = V02State ::new_with_genesis_accounts ( & [ ] , & [ ] ) . with_test_programs ( ) ;
let account_id = AccountId ::new ( [ 2 ; 32 ] ) ;
// Insert an account with non-default program owner
state . force_insert_account (
account_id ,
Account {
program_owner : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ,
.. Account ::default ( )
} ,
) ;
let message =
public_transaction ::Message ::try_new ( claimer . id ( ) , vec! [ account_id ] , vec! [ ] , ( ) )
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let result = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( result , Err ( NssaError ::InvalidProgramBehavior ) ) )
}
2025-11-28 18:41:12 -05:00
/// This test ensures that even if a malicious program tries to perform overflow of balances
/// it will not be able to break the balance validation.
#[ test ]
fn test_malicious_program_cannot_break_balance_validation ( ) {
let sender_key = PrivateKey ::try_new ( [ 37 ; 32 ] ) . unwrap ( ) ;
let sender_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & sender_key ) ) ;
let sender_init_balance : u128 = 10 ;
let recipient_key = PrivateKey ::try_new ( [ 42 ; 32 ] ) . unwrap ( ) ;
let recipient_id = AccountId ::from ( & PublicKey ::new_from_private_key ( & recipient_key ) ) ;
let recipient_init_balance : u128 = 10 ;
let mut state = V02State ::new_with_genesis_accounts (
& [
( sender_id , sender_init_balance ) ,
( recipient_id , recipient_init_balance ) ,
] ,
& [ ] ,
) ;
state . insert_program ( Program ::modified_transfer_program ( ) ) ;
let balance_to_move : u128 = 4 ;
let sender =
AccountWithMetadata ::new ( state . get_account_by_id ( & sender_id . clone ( ) ) , true , sender_id ) ;
let sender_nonce = sender . account . nonce ;
let _recipient =
AccountWithMetadata ::new ( state . get_account_by_id ( & recipient_id ) , false , sender_id ) ;
let message = public_transaction ::Message ::try_new (
Program ::modified_transfer_program ( ) . id ( ) ,
vec! [ sender_id , recipient_id ] ,
vec! [ sender_nonce ] ,
balance_to_move ,
)
. unwrap ( ) ;
let witness_set = public_transaction ::WitnessSet ::for_message ( & message , & [ & sender_key ] ) ;
let tx = PublicTransaction ::new ( message , witness_set ) ;
let res = state . transition_from_public_transaction ( & tx ) ;
assert! ( matches! ( res , Err ( NssaError ::InvalidProgramBehavior ) ) ) ;
let sender_post = state . get_account_by_id ( & sender_id ) ;
let recipient_post = state . get_account_by_id ( & recipient_id ) ;
let expected_sender_post = {
let mut this = state . get_account_by_id ( & sender_id ) ;
this . balance = sender_init_balance ;
this . nonce = 0 ;
this
} ;
let expected_recipient_post = {
let mut this = state . get_account_by_id ( & sender_id ) ;
this . balance = recipient_init_balance ;
this . nonce = 0 ;
this
} ;
assert! ( expected_sender_post = = sender_post ) ;
assert! ( expected_recipient_post = = recipient_post ) ;
}
2025-08-13 01:33:11 -03:00
}