diff --git a/apps/contracts/audit_registry/src/lib.rs b/apps/contracts/audit_registry/src/lib.rs index 68e5520..2532be2 100644 --- a/apps/contracts/audit_registry/src/lib.rs +++ b/apps/contracts/audit_registry/src/lib.rs @@ -451,4 +451,23 @@ mod tests { soroban_sdk::String::from_str(&env, "1.0.0") ); } + + // ── event emission tests (#330) ────────────────────────────────────────── + + #[test] + fn test_anchor_emits_event() { + let (env, api_signer, client) = setup(); + let h = hash(&env); + client.anchor(&api_signer, &h).unwrap(); + let events = env.events().all(); + let anchor_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("anchor"), &env)] + }); + assert!(anchor_event.is_some(), "anchor event not emitted"); + // data = (reading_hash, ledger_sequence, timestamp) + let (_, _, data) = anchor_event.unwrap(); + let (emitted_hash, _ledger, _ts): (BytesN<32>, u32, u64) = + soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(emitted_hash, h); + } } diff --git a/apps/contracts/community_governance/src/lib.rs b/apps/contracts/community_governance/src/lib.rs index 02ea4a6..920ff10 100644 --- a/apps/contracts/community_governance/src/lib.rs +++ b/apps/contracts/community_governance/src/lib.rs @@ -1081,4 +1081,98 @@ mod tests { client.finalize(&id); assert_eq!(client.get_proposal(&id).unwrap().status, ProposalStatus::Expired); } + + // ── event emission tests (#330) ────────────────────────────────────────── + + #[test] + fn test_propose_emits_event() { + let (env, _admin, client) = setup(); + let proposer = Address::generate(&env); + client.propose( + &proposer, + &String::from_str(&env, "Title"), + &String::from_str(&env, "Desc"), + ); + let events = env.events().all(); + let propose_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("propose"), &env)] + }); + assert!(propose_event.is_some(), "propose event not emitted"); + let (_, _, data) = propose_event.unwrap(); + let proposal_id: u32 = soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(proposal_id, 1_u32); + } + + #[test] + fn test_vote_emits_event() { + let (env, _admin, client) = setup(); + let proposer = Address::generate(&env); + let voter = Address::generate(&env); + let id = client.propose( + &proposer, + &String::from_str(&env, "T"), + &String::from_str(&env, "D"), + ); + client.vote(&voter, &id, &true); + let events = env.events().all(); + let vote_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("vote"), &env)] + }); + assert!(vote_event.is_some(), "vote event not emitted"); + let (_, _, data) = vote_event.unwrap(); + let (pid, _voter_addr, approve): (u32, Address, bool) = + soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(pid, id); + assert!(approve); + } + + #[test] + fn test_finalize_emits_event() { + let (env, _admin, client) = setup(); + let proposer = Address::generate(&env); + let id = client.propose( + &proposer, + &String::from_str(&env, "T"), + &String::from_str(&env, "D"), + ); + client.vote(&Address::generate(&env), &id, &true); + client.vote(&Address::generate(&env), &id, &true); + env.ledger().with_mut(|l| l.sequence_number += 101); + client.finalize(&id); + let events = env.events().all(); + let final_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("final"), &env)] + }); + assert!(final_event.is_some(), "finalize event not emitted"); + let (_, _, data) = final_event.unwrap(); + let (pid, status): (u32, ProposalStatus) = soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(pid, id); + assert_eq!(status, ProposalStatus::Passed); + } + + #[test] + fn test_execute_emits_event() { + let (env, _admin, client) = setup(); + let proposer = Address::generate(&env); + let id = client.propose( + &proposer, + &String::from_str(&env, "T"), + &String::from_str(&env, "D"), + ); + client.vote(&Address::generate(&env), &id, &true); + client.vote(&Address::generate(&env), &id, &true); + env.ledger().with_mut(|l| l.sequence_number += 101); + client.finalize(&id); + env.ledger() + .with_mut(|l| l.sequence_number += EXECUTE_TIMELOCK_LEDGERS); + client.execute(&id); + let events = env.events().all(); + let exec_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("exec"), &env)] + }); + assert!(exec_event.is_some(), "execute event not emitted"); + let (_, _, data) = exec_event.unwrap(); + let pid: u32 = soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(pid, id); + } } diff --git a/apps/contracts/energy_token/src/lib.rs b/apps/contracts/energy_token/src/lib.rs index acf029f..b088b94 100644 --- a/apps/contracts/energy_token/src/lib.rs +++ b/apps/contracts/energy_token/src/lib.rs @@ -1013,4 +1013,73 @@ mod tests { client.mint(&user, &1_i128); assert_eq!(client.balance(&user), 1_i128); } + + // ── event emission tests (#330) ────────────────────────────────────────── + + #[test] + fn test_mint_emits_event() { + let (env, client) = setup(); + let user = Address::generate(&env); + client.mint(&user, &500_i128); + let events = env.events().all(); + // Find the mint event: topic = ("mint",), data = (to, amount) + let mint_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("mint"), &env)] + }); + assert!(mint_event.is_some(), "mint event not emitted"); + let (_, _, data) = mint_event.unwrap(); + let (to, amount): (Address, i128) = soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(to, user); + assert_eq!(amount, 500_i128); + } + + #[test] + fn test_transfer_emits_event() { + let (env, client) = setup(); + let a = Address::generate(&env); + let b = Address::generate(&env); + client.mint(&a, &1000_i128); + env.events().all(); // clear + client.transfer(&a, &b, &300_i128); + let events = env.events().all(); + let transfer_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("transfer"), &env)] + }); + assert!(transfer_event.is_some(), "transfer event not emitted"); + let (_, _, data) = transfer_event.unwrap(); + let (from, to, amount): (Address, Address, i128) = soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(from, a); + assert_eq!(to, b); + assert_eq!(amount, 300_i128); + } + + #[test] + fn test_retire_emits_event() { + let (env, client) = setup(); + let user = Address::generate(&env); + client.mint(&user, &1000_i128); + client.retire(&user, &String::from_str(&env, "REC compliance")); + let events = env.events().all(); + let retire_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("retire"), &env)] + }); + assert!(retire_event.is_some(), "retire event not emitted"); + } + + #[test] + fn test_burn_emits_event() { + let (env, client) = setup(); + let user = Address::generate(&env); + client.mint(&user, &1000_i128); + client.burn(&user, &200_i128); + let events = env.events().all(); + let burn_event = events.iter().find(|(_, topics, _)| { + topics == &soroban_sdk::vec![&env, soroban_sdk::IntoVal::::into_val(&symbol_short!("burn"), &env)] + }); + assert!(burn_event.is_some(), "burn event not emitted"); + let (_, _, data) = burn_event.unwrap(); + let (from, amount): (Address, i128) = soroban_sdk::FromVal::from_val(&env, &data); + assert_eq!(from, user); + assert_eq!(amount, 200_i128); + } }