From 9da684b7c6cc87106ca3f04589a967cd5d5c1609 Mon Sep 17 00:00:00 2001 From: jonesmarvin8 <83104039+jonesmarvin8@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:44:08 -0500 Subject: [PATCH] fixed some deterministic issues --- nssa/program_methods/guest/src/bin/amm.rs | 48 +- nssa/src/state.rs | 559 ++++++++++------------ 2 files changed, 289 insertions(+), 318 deletions(-) diff --git a/nssa/program_methods/guest/src/bin/amm.rs b/nssa/program_methods/guest/src/bin/amm.rs index 389671b..4bbbd13 100644 --- a/nssa/program_methods/guest/src/bin/amm.rs +++ b/nssa/program_methods/guest/src/bin/amm.rs @@ -50,7 +50,9 @@ struct PoolDefinition{ impl PoolDefinition { fn into_data(self) -> Vec { - let u8_token_program_id : [u8;32] = bytemuck::cast(self.token_program_id); + //let u8_token_program_id : [u8;32] = bytemuck::cast(self.token_program_id); + //TODO: fix to include token Program + let mut bytes = [0; POOL_DEFINITION_DATA_SIZE]; bytes[0..32].copy_from_slice(&self.definition_token_a_id.to_bytes()); @@ -61,7 +63,7 @@ impl PoolDefinition { bytes[160..176].copy_from_slice(&self.liquidity_pool_cap.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..].copy_from_slice(&u8_token_program_id); + //bytes[208..].copy_from_slice(&u8_token_program_id); bytes.into() } @@ -131,6 +133,12 @@ impl TokenHolding { } } +/* + //TODO-useful +fn convert_u8_vec_to_u32_vec() { + +} +*/ fn new_definition( pre_states: &[AccountWithMetadata], @@ -157,9 +165,12 @@ fn new_definition( let user_b = &pre_states[5]; let user_lp = &pre_states[6]; + /* + //TODO: fix? if pool.account == Account::default() || !pool.is_authorized { panic!("Pool account is uninitiated or not authorized"); } + */ // TODO: temporary band-aid to prevent vault's from being // owned by the amm program. @@ -204,16 +215,27 @@ fn new_definition( let mut chained_call = Vec::new(); + /* let mut instruction_data = [0; 23]; - instruction_data[0] = 1; - + instruction_data[0] = 1; instruction_data[1..17].copy_from_slice(&amount_a.to_le_bytes()); +*/ + /* +let mut token_program_id: [u32;8] = [0]; + token_program_id[0] = u32::from_le_bytes(instruction[0..8].try_into().unwrap()); + token_program_id[1] = u32::from_le_bytes(instruction[8..16].try_into().unwrap()); + token_program_id[2] = u32::from_le_bytes(instruction[16..24].try_into().unwrap()); + + */ + + let instruction_data = to_vec(&amount_a).unwrap(); let call_token_a = ChainedCall{ program_id: token_program, - instruction_data: bytemuck::cast_slice(&instruction_data).to_vec(), + instruction_data: instruction_data,//bytemuck::cast_slice(&instruction_data).to_vec(), pre_states: vec![user_a.clone(), vault_a.clone()] }; + /* instruction_data[1..17].copy_from_slice(&amount_b.to_le_bytes()); let call_token_b = ChainedCall{ program_id: token_program, @@ -231,7 +253,7 @@ fn new_definition( chained_call.push(call_token_lp); chained_call.push(call_token_b); chained_call.push(call_token_a); - + */ let post_states = vec![pool_post.clone(), pre_states[1].account.clone(), @@ -256,10 +278,16 @@ fn main() { 0 => { let balance_a: u128 = u128::from_le_bytes(instruction[1..17].try_into().unwrap()); let balance_b: u128 = u128::from_le_bytes(instruction[17..33].try_into().unwrap()); - - - let token_program_id : &[u32] = bytemuck::cast_slice(&instruction[33..65]); - let token_program_id : [u32;8] = token_program_id.try_into().unwrap(); + + let mut token_program_id: [u32;8] = [0;8]; + token_program_id[0] = u32::from_le_bytes(instruction[33..37].try_into().unwrap()); + token_program_id[1] = u32::from_le_bytes(instruction[37..41].try_into().unwrap()); + token_program_id[2] = u32::from_le_bytes(instruction[41..45].try_into().unwrap()); + token_program_id[3] = u32::from_le_bytes(instruction[45..49].try_into().unwrap()); + token_program_id[4] = u32::from_le_bytes(instruction[49..53].try_into().unwrap()); + token_program_id[5] = u32::from_le_bytes(instruction[53..57].try_into().unwrap()); + token_program_id[6] = u32::from_le_bytes(instruction[57..61].try_into().unwrap()); + token_program_id[7] = u32::from_le_bytes(instruction[61..65].try_into().unwrap()); let (post_states, chained_call) = new_definition(&pre_states, &[balance_a, balance_b], diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 156e452..59127c0 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -2232,264 +2232,11 @@ pub mod tests { token_id: ProgramId, } - #[test] - fn test_simple_amm_initialized() { - let token_program_id = program_methods::TOKEN_ID; - let program = Program::amm(); - - //initialize AMM accounts - let mut token_a_definition_data = TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [1u8; 6], - total_supply: 1000u128, - }); - - let mut token_b_definition_data = TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [2u8; 6], - total_supply: 1000u128, - }); - - let mut pool_lp_definition_data = TokenDefinition::into_data(TokenDefinition { - account_type: TOKEN_DEFINITION_TYPE, - name: [2u8; 6], - total_supply: u128::MAX, - }); - - let amm_key = PrivateKey::try_new([1; 32]).unwrap(); - let vault_a_key = PrivateKey::try_new([2; 32]).unwrap(); - let vault_b_key = PrivateKey::try_new([3; 32]).unwrap(); - let user_a_key = PrivateKey::try_new([4; 32]).unwrap(); - let user_b_key = PrivateKey::try_new([5; 32]).unwrap(); - let user_lp_key = PrivateKey::try_new([6; 32]).unwrap(); - let pool_lp_key = PrivateKey::try_new([7; 32]).unwrap(); - - let mut definition_a_account = Account::default(); - let mut definition_b_account = Account::default(); - let mut pool_lp_account = Account::default(); - - let definition_a_address = Address::new([1u8; 32]); - let definition_b_address = Address::new([2u8; 32]); - let definition_lp_address = Address::new([3u8; 32]); - let vault_a_address = Address::from(&PublicKey::new_from_private_key(&vault_a_key)); - let vault_b_address = Address::from(&PublicKey::new_from_private_key(&vault_b_key)); - let user_a_address = Address::from(&PublicKey::new_from_private_key(&user_a_key)); - let user_b_address = Address::from(&PublicKey::new_from_private_key(&user_b_key)); - let user_lp_address = Address::from(&PublicKey::new_from_private_key(&pool_lp_key)); - let pool_lp_address = Address::from(&PublicKey::new_from_private_key(&user_lp_key)); - let amm_pool_address = Address::from(&PublicKey::new_from_private_key(&amm_key)); - - definition_a_account.data = token_a_definition_data; - definition_b_account.data = token_b_definition_data; - pool_lp_account.data = pool_lp_definition_data; - - let mut vault_a_account = Account::default(); - let mut vault_b_account = Account::default(); - let mut user_a_account = Account::default(); - let mut user_b_account = Account::default(); - let mut pool_lp_account = Account::default(); - let mut user_lp_account = Account::default(); - - let user_a_init_balance: u128 = 300; - let user_b_init_balance: u128 = 400; - - vault_a_account.program_owner = program_methods::TOKEN_ID; - vault_b_account.program_owner = program_methods::TOKEN_ID; - user_a_account.program_owner = program_methods::TOKEN_ID; - user_b_account.program_owner = program_methods::TOKEN_ID; - pool_lp_account.program_owner = program_methods::TOKEN_ID; - user_lp_account.program_owner = program_methods::TOKEN_ID; - - user_lp_account.data = TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: definition_lp_address.clone(), - balance: 0u128, - }); - - vault_a_account.data = TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: definition_a_address.clone(), - balance: 0u128, - }); - - vault_b_account.data = TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: definition_b_address.clone(), - balance: 0u128, - }); - - user_a_account.data = TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: definition_a_address.clone(), - balance: user_a_init_balance, - }); - - user_b_account.data = TokenHolding::into_data(TokenHolding { - account_type: TOKEN_HOLDING_TYPE, - definition_id: definition_b_address.clone(), //TODO - balance: user_b_init_balance, - }); - - user_a_account.balance = user_a_init_balance; - user_b_account.balance = user_b_init_balance; - - let amm_pool = AccountWithMetadata::default(); - let mut user_a_meta = AccountWithMetadata::default(); - let mut user_b_meta = AccountWithMetadata::default(); - let mut vault_a_meta = AccountWithMetadata::default(); - let mut vault_b_meta = AccountWithMetadata::default(); - let mut pool_lp_meta = AccountWithMetadata::default(); - let mut user_lp_meta = AccountWithMetadata::default(); - - user_a_meta.account = user_a_account.clone(); - user_a_meta.account_id = user_a_address; - - user_b_meta.account = user_b_account.clone(); - user_a_meta.account_id = user_b_address; - - vault_a_meta.account = vault_a_account.clone(); - vault_a_meta.account_id = vault_a_address; - - vault_b_meta.account = vault_b_account.clone(); - vault_b_meta.account_id = vault_b_address; - - pool_lp_meta.account = pool_lp_account.clone(); - pool_lp_meta.account_id = pool_lp_address; - - user_lp_meta.account = user_lp_account.clone(); - user_lp_meta.account_id = user_lp_address; - - let key = PrivateKey::try_new([1; 32]).unwrap(); - let from_address = Address::from(&PublicKey::new_from_private_key(&key)); - let to_address = Address::new([2; 32]); - let initial_balance = 100; - let initial_data = [(from_address, initial_balance), (to_address, 0)]; - let mut state = - V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - - state.force_insert_account(user_a_address, user_a_account.clone()); - state.force_insert_account(user_b_address, user_b_account.clone()); - state.force_insert_account(vault_a_address, vault_a_account.clone()); - state.force_insert_account(vault_b_address, vault_b_account.clone()); - state.force_insert_account(pool_lp_address, pool_lp_account.clone()); - state.force_insert_account(user_lp_address, user_lp_account.clone()); - - //TODO: return here - let amount_a: u128 = 20; - let amount_b: u128 = 20; - - //TODO: delete - let u8_token_program_id: [u8; 32] = bytemuck::cast(token_program_id); - /* - let instruction = NewAMMInstructions { - option: 0x00, - balance_a: amount_a, - balance_b: amount_b, - token_id: token_program_id, - };*/ - - let mut instruction: [u8;65] = [0;65]; - instruction[0] = 0x00; - instruction[1..17].copy_from_slice(&amount_a.to_le_bytes()); - instruction[17..33].copy_from_slice(&amount_b.to_le_bytes()); - instruction[33..65].copy_from_slice(&u8_token_program_id); - - - //let instruction_data = Program::serialize_instruction(instruction).unwrap(); - /* - TODO: delete - bytes[176..192].copy_from_slice(&self.reserve_a.to_le_bytes()); - bytes[192..208].copy_from_slice(&self.reserve_b.to_le_bytes()); - */ - - //expected post states - let mut user_a_post = user_a_account.clone(); - user_a_post.balance -= amount_a; - - let mut user_b_post = user_b_account.clone(); - user_b_post.balance -= amount_b; - - let mut user_lp_post = user_lp_account.clone(); - user_lp_post.balance += amount_a; - - let mut vault_a_post = vault_a_account.clone(); - vault_a_post.balance += amount_a; - - let mut vault_b_post = vault_b_account.clone(); - vault_b_post.balance += amount_b; - - let instruction= NewAMMInstructions { - option: 0u8, - balance_a: amount_a, - balance_b: amount_b, - token_id: token_program_id, - }; - - let message = public_transaction::Message::try_new( - program.id(), - vec![amm_pool_address, vault_a_address, vault_b_address, pool_lp_address, user_a_address, user_b_address, user_lp_address], - vec![0], - instruction, - ) - .unwrap(); - - let witness_set = public_transaction::WitnessSet::for_message( - &message, - &[ - &amm_key, - &vault_a_key, - &vault_b_key, - &pool_lp_key, - &user_a_key, - &user_b_key, - &user_lp_key, - ], - ); - let tx = PublicTransaction::new(message, witness_set); - - - - let result = state.transition_from_public_transaction(&tx); - - - - assert!(state.get_account_by_address(&user_a_address).balance == user_a_init_balance); - assert!(state.get_account_by_address(&vault_a_address).balance == 0);//amount_a); - /* assert!(matches!( - result, - Err(NssaError::MaxChainedCallsDepthExceeded) - ));*/ - - - /* - - 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(()) - } - - */ - } - #[test] fn test_simple_amm_initialized_attempt2() { //let token_program_id = program_methods::TOKEN_ID; let program_amm = Program::amm(); - let program_token = Program::token(); - - /* - let amm_key = PrivateKey::try_new([1; 32]).unwrap(); - let vault_a_key = PrivateKey::try_new([2; 32]).unwrap(); - let vault_b_key = PrivateKey::try_new([3; 32]).unwrap(); - let user_a_key = PrivateKey::try_new([4; 32]).unwrap(); - let user_b_key = PrivateKey::try_new([5; 32]).unwrap(); - let user_lp_key = PrivateKey::try_new([6; 32]).unwrap(); - let pool_lp_key = PrivateKey::try_new([7; 32]).unwrap(); - */ + let program_token = Program::token().id(); let initial_data = []; let mut state = @@ -2502,16 +2249,49 @@ pub mod tests { let token_a_definition_address = Address::from(&PublicKey::new_from_private_key(&token_a_definition_key)); let token_a_supply: u128 = 30000; + let token_b_holding_key = PrivateKey::try_new([3;32]).unwrap(); + let token_b_definition_key = PrivateKey::try_new([4;32]).unwrap(); + let token_b_holding_address = Address::from(&PublicKey::new_from_private_key(&token_b_holding_key)); + let token_b_definition_address = Address::from(&PublicKey::new_from_private_key(&token_b_definition_key)); + let token_b_supply: u128 = 50000; + let token_lp_holding_key = PrivateKey::try_new([5;32]).unwrap(); + let token_lp_definition_key = PrivateKey::try_new([6;32]).unwrap(); + let token_lp_holding_address = Address::from(&PublicKey::new_from_private_key(&token_lp_holding_key)); + let token_lp_definition_address = Address::from(&PublicKey::new_from_private_key(&token_lp_definition_key)); + let token_lp_supply: u128 = 300000; + + let user_a_holding_key = PrivateKey::try_new([7;32]).unwrap(); + let user_a_holding_address = Address::from(&PublicKey::new_from_private_key(&user_a_holding_key)); + let user_a_amount: u128 = 10000; + + let user_b_holding_key = PrivateKey::try_new([8;32]).unwrap(); + let user_b_holding_address = Address::from(&PublicKey::new_from_private_key(&user_b_holding_key)); + let user_b_amount: u128 = 10000; + + + + let vault_a_key = PrivateKey::try_new([9;32]).unwrap(); + let vault_a_address = Address::from(&PublicKey::new_from_private_key(&vault_a_key)); + + let vault_b_key = PrivateKey::try_new([10;32]).unwrap(); + let vault_b_address = Address::from(&PublicKey::new_from_private_key(&vault_b_key)); + + let user_lp_holding_key = PrivateKey::try_new([11;32]).unwrap(); + let user_lp_holding_address = Address::from(&PublicKey::new_from_private_key(&user_lp_holding_key)); + + let pool_lp_holding_key = PrivateKey::try_new([12;32]).unwrap(); + let pool_lp_holding_address = Address::from(&PublicKey::new_from_private_key(&pool_lp_holding_key)); + + let pool_key = PrivateKey::try_new([13;32]).unwrap(); + let pool_address = Address::from(&PublicKey::new_from_private_key(&pool_key)); + + //initialize Tokens: Token A, Token B and Took LP let mut instruction: [u8;23] = [0;23]; instruction[1..17].copy_from_slice(&token_a_supply.to_le_bytes()); instruction[18] = 0x01; //name is not default. instruction[19] = 0x02; - //TODO delete - //let instruction_data = Program::serialize_instruction(instruction).unwrap(); - - //initialize Token Accounts let message = public_transaction::Message::try_new( Program::token().id(), vec![token_a_definition_address, token_a_holding_address], @@ -2525,14 +2305,222 @@ pub mod tests { &[], ); let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx).unwrap(); - assert!(state.get_account_by_address(&token_a_definition_address).balance == 0); - assert!(state.get_account_by_address(&token_a_holding_address).balance == token_a_supply); - assert!(state.get_account_by_address(&token_a_holding_address).program_owner == program_token.id()); + instruction[1..17].copy_from_slice(&token_b_supply.to_le_bytes()); + instruction[18] = 0x03; //name is not default. + instruction[19] = 0x02; -/* + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_b_definition_address, token_b_holding_address], + 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(); + + instruction[1..17].copy_from_slice(&token_lp_supply.to_le_bytes()); + instruction[18] = 0x03; //name is not default. + instruction[19] = 0x04; + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_lp_definition_address, token_lp_holding_address], + 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(); + + + // Initialize User accounts for Token A and B + let mut instruction: [u8;23] = [0;23]; + instruction[0] = 1; //transfer + instruction[1..17].copy_from_slice(&user_a_amount.to_le_bytes()); + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_a_holding_address, user_a_holding_address], + vec![0], + instruction, + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[&token_a_holding_key], + ); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + instruction[0] = 1; //transfer + instruction[1..17].copy_from_slice(&user_b_amount.to_le_bytes()); + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_b_holding_address, user_b_holding_address], + vec![0], + instruction, + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[&token_b_holding_key], + ); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + + //TODO: initialize vaults - ideally, we won't need to do this. + let temp_amt = 1u128; + let mut instruction: [u8;23] = [0;23]; + instruction[0] = 1; //transfer + instruction[1..17].copy_from_slice(&temp_amt.to_le_bytes()); + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_a_holding_address, vault_a_address], + vec![1], + instruction, + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[&token_a_holding_key], + ); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + instruction[0] = 1; //transfer + instruction[1..17].copy_from_slice(&temp_amt.to_le_bytes()); + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_b_holding_address, vault_b_address], + vec![1], + instruction, + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[&token_b_holding_key], + ); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + //need LP accounts for both AMM and user + instruction[0] = 1; //transfer + instruction[1..17].copy_from_slice(&temp_amt.to_le_bytes()); + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_lp_holding_address, user_lp_holding_address], + vec![0], + instruction, + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[&token_lp_holding_key], + ); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + instruction[0] = 1; //transfer + instruction[1..17].copy_from_slice(&temp_amt.to_le_bytes()); + + let message = public_transaction::Message::try_new( + Program::token().id(), + vec![token_lp_holding_address, pool_lp_holding_address], + vec![1], + instruction, + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[&token_lp_holding_key], + ); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + //Set up instruction to initialize AMM for (Token-A, Token-B) + let init_balance_a: u128 = 1000; + let init_balance_b: u128 = 1000; + let token_program_u8: [u8;32] = bytemuck::cast(program_token); + + + let mut instruction: Vec = Vec::new(); + instruction.push(0); + instruction.extend_from_slice(&init_balance_a.to_le_bytes()); + instruction.extend_from_slice(&init_balance_b.to_le_bytes()); + instruction.extend_from_slice(&token_program_u8); + + assert!(token_program_u8.len() == 32); + + + let mut instruction: Vec = Vec::new(); + instruction.push(0); + instruction.extend_from_slice(&init_balance_a.to_le_bytes()); + instruction.extend_from_slice(&init_balance_b.to_le_bytes()); + instruction.extend_from_slice(&token_program_u8); + + assert!(token_program_u8.len() == 32); + + + let message = public_transaction::Message::try_new( + Program::amm().id(), + vec![ + pool_address, + vault_a_address, + vault_b_address, + pool_lp_holding_address, + user_a_holding_address, + user_b_holding_address, + user_lp_holding_address + ], + vec![0,0,0,0], + instruction, //TODO: bah + ) + .unwrap(); + + let witness_set = public_transaction::WitnessSet::for_message( + &message, + &[ + &pool_key, + &pool_lp_holding_key, + &user_a_holding_key, + &user_b_holding_key, + ], + ); + + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx).unwrap(); + + + + + + + + /* assert_eq!(state.get_account_by_address(&to), Account::default()); @@ -2564,48 +2552,3 @@ pub mod tests { } - -/* - - #[test] - fn test_chained_call_succeeds() { - let program = Program::chain_caller(); - let key = PrivateKey::try_new([1; 32]).unwrap(); - let from_address = Address::from(&PublicKey::new_from_private_key(&key)); - let to_address = Address::new([2; 32]); - let initial_balance = 100; - let initial_data = [(from_address, initial_balance), (to_address, 0)]; - let mut state = - V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let from_key = key; - let amount: u128 = 0; - let instruction: (u128, ProgramId, u32) = - (amount, Program::authenticated_transfer_program().id(), 2); - - let expected_to_post = Account { - program_owner: Program::authenticated_transfer_program().id(), - balance: amount * 2, // The `chain_caller` chains the program twice - ..Account::default() - }; - - let message = public_transaction::Message::try_new( - program.id(), - vec![to_address, from_address], //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_address(&from_address); - let to_post = state.get_account_by_address(&to_address); - // The `chain_caller` program calls the program twice - assert_eq!(from_post.balance, initial_balance - 2 * amount); - assert_eq!(to_post, expected_to_post); - } - - -*/ \ No newline at end of file