From 107eb9b10ba3180df05c313104f0c6d29efcec6b Mon Sep 17 00:00:00 2001 From: enyinnaya1234 Date: Thu, 8 May 2025 18:04:11 +0100 Subject: [PATCH 1/4] test: validate aggregator logic --- .tool-versions | 2 + src/aggregator.cairo | 2 +- tests/test_contract.cairo | 139 +++++++++++++++++++++++++++++++++----- 3 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..9f71edc --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +scarb 2.11.4 +starknet-foundry 0.40.0 diff --git a/src/aggregator.cairo b/src/aggregator.cairo index 3e4cbe8..12d8229 100644 --- a/src/aggregator.cairo +++ b/src/aggregator.cairo @@ -50,7 +50,7 @@ mod Agggregator { let killswitch: IKillSwitchDispatcher = IKillSwitchDispatcher { contract_address: self.killswitch.read(), }; - assert(killswitch.get_status(), 'not active'); + assert(killswitch.get_status(), 'should be active'); ICounterDispatcher { contract_address: self.counter.read() }.increase_count(amount) } diff --git a/tests/test_contract.cairo b/tests/test_contract.cairo index 9d6708a..20d224e 100644 --- a/tests/test_contract.cairo +++ b/tests/test_contract.cairo @@ -1,42 +1,62 @@ -use starknet::ContractAddress; - use snforge_std::{declare, ContractClassTrait, DeclareResultTrait}; use cohort_4::counter::{ICounterDispatcher, ICounterDispatcherTrait, ICounterSafeDispatcher, ICounterSafeDispatcherTrait}; +use cohort_4::aggregator::{IAggregatorDispatcher, IAggregatorDispatcherTrait}; +use cohort_4::killswitch::{IKillSwitchDispatcher, IKillSwitchDispatcherTrait}; + -fn deploy_contract() -> ContractAddress { - let countract_name: ByteArray = "Counter"; - let contract = declare(countract_name).unwrap().contract_class(); - let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - contract_address +fn deploy_contract() -> (ICounterDispatcher, IKillSwitchDispatcher, IAggregatorDispatcher) { + //counter deployment + let counter_countract_name: ByteArray = "Counter"; + let contract = declare(counter_countract_name).unwrap().contract_class(); + let (counter_contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); + let counter_dispatcher = ICounterDispatcher{ + contract_address: counter_contract_address + }; + + //killswitch deployment + let killswitch_contract_name: ByteArray = "KillSwitch"; + let killswitch_contract = declare(killswitch_contract_name).unwrap().contract_class(); + let (killswitch_contract_address, _) = killswitch_contract.deploy(@ArrayTrait::new()).unwrap(); + let killswitch_dispatcher = IKillSwitchDispatcher{ + contract_address: killswitch_contract_address + }; + + //aggregator deployment + let aggregator = declare("Agggregator").unwrap().contract_class(); + let (aggregator_contract_address, _) = aggregator.deploy(@array![counter_contract_address.into(), killswitch_contract_address.into()]).unwrap(); + + let aggregator_dispatcher = IAggregatorDispatcher{ + contract_address: aggregator_contract_address + }; + + (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) } #[test] fn test_increase_count() { - let contract_address = deploy_contract(); + let (counter_dispatcher, _, _) = deploy_contract(); - let dispatcher = ICounterDispatcher { contract_address }; + - let balance_before = dispatcher.get_count(); + let balance_before = counter_dispatcher.get_count(); assert(balance_before == 0, 'Invalid balance'); - dispatcher.increase_count(42); + counter_dispatcher.increase_count(42); - let balance_after = dispatcher.get_count(); + let balance_after = counter_dispatcher.get_count(); assert(balance_after == 42, 'Invalid balance'); } #[test] #[feature("safe_dispatcher")] fn test_cannot_increase_balance_with_zero_value() { - let contract_address = deploy_contract(); - - let dispatcher = ICounterDispatcher { contract_address }; + let (counter_dispatcher, _, _) = deploy_contract(); - let balance_before = dispatcher.get_count(); + let balance_before = counter_dispatcher.get_count(); assert(balance_before == 0 , 'Invalid balance'); - let safe_dispatcher = ICounterSafeDispatcher { contract_address }; + let safe_dispatcher = ICounterSafeDispatcher { contract_address: counter_dispatcher.contract_address }; match safe_dispatcher.increase_count(0) { Result::Ok(_) => core::panic_with_felt252('Should have panicked'), @@ -47,3 +67,88 @@ fn test_cannot_increase_balance_with_zero_value() { } + +#[test] +fn test_increase_count_aggregator() { + let (_, _, aggregator_dispatcher)= deploy_contract(); + + let balance_before = aggregator_dispatcher.get_count(); + assert(balance_before == 0, 'Invalid balance'); + + aggregator_dispatcher.increase_count(42); + + let balance_after = aggregator_dispatcher.get_count(); + assert(balance_after == 42, 'Invalid balance'); +} + +#[test] +fn test_increase_counter_count_aggregator() { + let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); + + let count_1 = counter_dispatcher.get_count(); + assert(count_1 == 0, 'invalid count 1'); + + let status_before = killswitch_dispatcher.get_status(); + assert(!status_before, 'incorrect status'); + + aggregator_dispatcher.activate_switch(); + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'failed to activate'); + + aggregator_dispatcher.increase_counter_count(42); + + let count_2 = counter_dispatcher.get_count(); + assert(count_2 == 42, 'invalid count 2'); +} + +#[test] +fn test_decrease_count_by_one_aggregator() { + let (_, _, aggregator_dispatcher) = deploy_contract(); + + let count_after = aggregator_dispatcher.get_count(); + assert(count_after == 0, 'invalid count'); + + aggregator_dispatcher.increase_count(20); + aggregator_dispatcher.decrease_count_by_one(); + + let count_after = aggregator_dispatcher.get_count(); + assert(count_after == 19, 'incorrect count'); + +} + +#[test] +fn test_increase_activate_switch() { + let (_, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); + + let status = killswitch_dispatcher.get_status(); + assert(!status, 'failed'); + + aggregator_dispatcher.activate_switch(); + + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'invalid status'); + +} + +#[test] +#[should_panic(expect: 'Amount cannot be 0')] +fn test_increase_count_by_zero(){ + let (_, _, aggregator_dispatcher) = deploy_contract(); + + let count_after = aggregator_dispatcher.get_count(); + assert(count_after == 0, 'incorrect count'); + + aggregator_dispatcher.increase_count(0); +} + +#[test] +#[should_panic(expect: 'should be active')] +fn test_increase_counter_count_error() { + let (_, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); + + let status_before = killswitch_dispatcher.get_status(); + assert(status_before, 'invalid status'); + + aggregator_dispatcher.increase_counter_count(42); + +} \ No newline at end of file From f8963aeac2a3b6138af62f639728b2af85103250 Mon Sep 17 00:00:00 2001 From: enyinnaya1234 Date: Thu, 8 May 2025 18:07:23 +0100 Subject: [PATCH 2/4] chore: run scarb fmt --- src/IHello.cairo | 2 +- src/INumber.cairo | 2 +- src/counter.cairo | 2 +- src/hello.cairo | 6 ++-- src/lib.cairo | 9 +++--- tests/test_contract.cairo | 61 +++++++++++++++++++-------------------- 6 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/IHello.cairo b/src/IHello.cairo index 0d1c511..df6f372 100644 --- a/src/IHello.cairo +++ b/src/IHello.cairo @@ -8,4 +8,4 @@ pub trait IHelloStarknet { fn get_balance(self: @TContractState) -> felt252; fn add_and_subtract(ref self: TContractState, amount: felt252); -} \ No newline at end of file +} diff --git a/src/INumber.cairo b/src/INumber.cairo index eb4014b..5a4f700 100644 --- a/src/INumber.cairo +++ b/src/INumber.cairo @@ -5,4 +5,4 @@ pub trait INumber { fn set_number(ref self: TContractState, amount: u8); /// Returns the current number fn get_number(self: @TContractState) -> u8; -} \ No newline at end of file +} diff --git a/src/counter.cairo b/src/counter.cairo index 190c073..ced698b 100644 --- a/src/counter.cairo +++ b/src/counter.cairo @@ -37,7 +37,7 @@ mod Counter { } fn get_count(self: @ContractState) -> u32 { - self.count.read() + self.count.read() } } } diff --git a/src/hello.cairo b/src/hello.cairo index fd7d3e2..13c95fd 100644 --- a/src/hello.cairo +++ b/src/hello.cairo @@ -39,8 +39,8 @@ mod HelloStarknet { } fn add_and_subtract(ref self: ContractState, amount: felt252) { - self._add(amount); - self._subtract(amount); + self._add(amount); + self._subtract(amount); } } @@ -52,4 +52,4 @@ mod HelloStarknet { number } } -} \ No newline at end of file +} diff --git a/src/lib.cairo b/src/lib.cairo index 8b3993c..7df1810 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,22 +1,21 @@ -pub mod hello; pub mod IHello; pub mod INumber; +pub mod aggregator; pub mod counter; +pub mod hello; pub mod killswitch; -pub mod aggregator; - fn main() { // Function calls (Uncomment to execute them) // say_name("Sylvia Nnoruka!"); // intro_to_felt(); - + let num_1 = 5; let num_2 = 10; let sum = sum_num(num_1, num_2); println!("The sum of {} and {} is = {}", num_1, num_2, sum); - + // check_u16(6553); // Uncomment if needed is_greater_than_50(3); } diff --git a/tests/test_contract.cairo b/tests/test_contract.cairo index 20d224e..71b3178 100644 --- a/tests/test_contract.cairo +++ b/tests/test_contract.cairo @@ -1,8 +1,10 @@ -use snforge_std::{declare, ContractClassTrait, DeclareResultTrait}; - -use cohort_4::counter::{ICounterDispatcher, ICounterDispatcherTrait, ICounterSafeDispatcher, ICounterSafeDispatcherTrait}; use cohort_4::aggregator::{IAggregatorDispatcher, IAggregatorDispatcherTrait}; +use cohort_4::counter::{ + ICounterDispatcher, ICounterDispatcherTrait, ICounterSafeDispatcher, + ICounterSafeDispatcherTrait, +}; use cohort_4::killswitch::{IKillSwitchDispatcher, IKillSwitchDispatcherTrait}; +use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; fn deploy_contract() -> (ICounterDispatcher, IKillSwitchDispatcher, IAggregatorDispatcher) { @@ -10,24 +12,24 @@ fn deploy_contract() -> (ICounterDispatcher, IKillSwitchDispatcher, IAggregatorD let counter_countract_name: ByteArray = "Counter"; let contract = declare(counter_countract_name).unwrap().contract_class(); let (counter_contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - let counter_dispatcher = ICounterDispatcher{ - contract_address: counter_contract_address - }; - - //killswitch deployment + let counter_dispatcher = ICounterDispatcher { contract_address: counter_contract_address }; + + //killswitch deployment let killswitch_contract_name: ByteArray = "KillSwitch"; let killswitch_contract = declare(killswitch_contract_name).unwrap().contract_class(); let (killswitch_contract_address, _) = killswitch_contract.deploy(@ArrayTrait::new()).unwrap(); - let killswitch_dispatcher = IKillSwitchDispatcher{ - contract_address: killswitch_contract_address + let killswitch_dispatcher = IKillSwitchDispatcher { + contract_address: killswitch_contract_address, }; //aggregator deployment let aggregator = declare("Agggregator").unwrap().contract_class(); - let (aggregator_contract_address, _) = aggregator.deploy(@array![counter_contract_address.into(), killswitch_contract_address.into()]).unwrap(); + let (aggregator_contract_address, _) = aggregator + .deploy(@array![counter_contract_address.into(), killswitch_contract_address.into()]) + .unwrap(); - let aggregator_dispatcher = IAggregatorDispatcher{ - contract_address: aggregator_contract_address + let aggregator_dispatcher = IAggregatorDispatcher { + contract_address: aggregator_contract_address, }; (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) @@ -35,9 +37,7 @@ fn deploy_contract() -> (ICounterDispatcher, IKillSwitchDispatcher, IAggregatorD #[test] fn test_increase_count() { - let (counter_dispatcher, _, _) = deploy_contract(); - - + let (counter_dispatcher, _, _) = deploy_contract(); let balance_before = counter_dispatcher.get_count(); assert(balance_before == 0, 'Invalid balance'); @@ -51,26 +51,26 @@ fn test_increase_count() { #[test] #[feature("safe_dispatcher")] fn test_cannot_increase_balance_with_zero_value() { - let (counter_dispatcher, _, _) = deploy_contract(); + let (counter_dispatcher, _, _) = deploy_contract(); let balance_before = counter_dispatcher.get_count(); - assert(balance_before == 0 , 'Invalid balance'); + assert(balance_before == 0, 'Invalid balance'); - let safe_dispatcher = ICounterSafeDispatcher { contract_address: counter_dispatcher.contract_address }; + let safe_dispatcher = ICounterSafeDispatcher { + contract_address: counter_dispatcher.contract_address, + }; match safe_dispatcher.increase_count(0) { Result::Ok(_) => core::panic_with_felt252('Should have panicked'), Result::Err(panic_data) => { assert(*panic_data.at(0) == 'Amount cannot be 0', *panic_data.at(0)); - } + }, }; - - } #[test] fn test_increase_count_aggregator() { - let (_, _, aggregator_dispatcher)= deploy_contract(); + let (_, _, aggregator_dispatcher) = deploy_contract(); let balance_before = aggregator_dispatcher.get_count(); assert(balance_before == 0, 'Invalid balance'); @@ -83,7 +83,7 @@ fn test_increase_count_aggregator() { #[test] fn test_increase_counter_count_aggregator() { - let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); + let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); let count_1 = counter_dispatcher.get_count(); assert(count_1 == 0, 'invalid count 1'); @@ -103,7 +103,7 @@ fn test_increase_counter_count_aggregator() { #[test] fn test_decrease_count_by_one_aggregator() { - let (_, _, aggregator_dispatcher) = deploy_contract(); + let (_, _, aggregator_dispatcher) = deploy_contract(); let count_after = aggregator_dispatcher.get_count(); assert(count_after == 0, 'invalid count'); @@ -113,7 +113,6 @@ fn test_decrease_count_by_one_aggregator() { let count_after = aggregator_dispatcher.get_count(); assert(count_after == 19, 'incorrect count'); - } #[test] @@ -124,16 +123,15 @@ fn test_increase_activate_switch() { assert(!status, 'failed'); aggregator_dispatcher.activate_switch(); - + let status_after = killswitch_dispatcher.get_status(); assert(status_after, 'invalid status'); - } #[test] #[should_panic(expect: 'Amount cannot be 0')] -fn test_increase_count_by_zero(){ - let (_, _, aggregator_dispatcher) = deploy_contract(); +fn test_increase_count_by_zero() { + let (_, _, aggregator_dispatcher) = deploy_contract(); let count_after = aggregator_dispatcher.get_count(); assert(count_after == 0, 'incorrect count'); @@ -150,5 +148,4 @@ fn test_increase_counter_count_error() { assert(status_before, 'invalid status'); aggregator_dispatcher.increase_counter_count(42); - -} \ No newline at end of file +} From cbe8b8fb52bd28273a6778eef1331e8362239555 Mon Sep 17 00:00:00 2001 From: dinahmaccodes Date: Fri, 9 May 2025 07:56:28 +0100 Subject: [PATCH 3/4] feat: add constructor assertions & event emissions --- src/aggregator.cairo | 45 ++++++++++++++++++++++++++++++++++++++- tests/test_contract.cairo | 17 ++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/aggregator.cairo b/src/aggregator.cairo index 12d8229..2d4d589 100644 --- a/src/aggregator.cairo +++ b/src/aggregator.cairo @@ -20,6 +20,7 @@ mod Agggregator { use cohort_4::counter::{ICounterDispatcher, ICounterDispatcherTrait}; use cohort_4::killswitch::{IKillSwitchDispatcher, IKillSwitchDispatcherTrait}; use starknet::ContractAddress; + use core::num::traits::Zero; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; @@ -30,10 +31,48 @@ mod Agggregator { killswitch: ContractAddress, } + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + CountIncreased: CountIncreased, + CounterCountIncreased: CounterCountIncreased, + CountDecreasedByOne: CountDecreasedByOne, + SwitchStatus: SwitchStatus, + } + + #[derive(Drop, Serde, starknet::Event)] + pub struct CountIncreased { + amount: u32, + } + + #[derive(Drop, Serde, starknet::Event)] + pub struct CounterCountIncreased { + amount: u32, + } + + #[derive(Drop, Serde, starknet::Event)] + pub struct CountDecreasedByOne { + pub previous_count: u32, + } + + #[derive(Drop, Serde, starknet::Event)] + pub struct SwitchStatus { + pub get_status: bool, + } + #[constructor] fn constructor(ref self: ContractState, counter: ContractAddress, killswitch: ContractAddress) { self.counter.write(counter); self.killswitch.write(killswitch); + //Assert address is not 0 + assert(!self.counter.read().is_zero(), 'Counter address cannot be 0'); + assert(!self.killswitch.read().is_zero(), 'KillSwitch address cannot be 0'); + //Assert count is not kill_switch + assert( + self.counter.read() != self.killswitch.read(), + 'Odd! Counter is KillSwitch' + ); } @@ -44,6 +83,7 @@ mod Agggregator { let counter = ICounterDispatcher { contract_address: self.counter.read() }; let counter_count = counter.get_count(); self.count.write(counter_count + amount); + self.emit(CountIncreased { amount }); } fn increase_counter_count(ref self: ContractState, amount: u32) { @@ -51,13 +91,15 @@ mod Agggregator { contract_address: self.killswitch.read(), }; assert(killswitch.get_status(), 'should be active'); - ICounterDispatcher { contract_address: self.counter.read() }.increase_count(amount) + ICounterDispatcher { contract_address: self.counter.read() }.increase_count(amount); + self.emit(CounterCountIncreased { amount }); } fn decrease_count_by_one(ref self: ContractState) { let current_count = self.get_count(); assert!(current_count != 0, "Amount cannot be 0"); self.count.write(current_count - 1); + self.emit(CountDecreasedByOne { previous_count: current_count }); } fn activate_switch(ref self: ContractState) { @@ -68,6 +110,7 @@ mod Agggregator { if !killswitch.get_status() { killswitch.switch() } + self.emit(SwitchStatus { get_status: true }); } fn get_count(self: @ContractState) -> u32 { diff --git a/tests/test_contract.cairo b/tests/test_contract.cairo index 71b3178..e9ffb8a 100644 --- a/tests/test_contract.cairo +++ b/tests/test_contract.cairo @@ -115,6 +115,7 @@ fn test_decrease_count_by_one_aggregator() { assert(count_after == 19, 'incorrect count'); } + #[test] fn test_increase_activate_switch() { let (_, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); @@ -130,7 +131,7 @@ fn test_increase_activate_switch() { #[test] #[should_panic(expect: 'Amount cannot be 0')] -fn test_increase_count_by_zero() { +fn test_increase_count_by_zero_aggregator() { let (_, _, aggregator_dispatcher) = deploy_contract(); let count_after = aggregator_dispatcher.get_count(); @@ -149,3 +150,17 @@ fn test_increase_counter_count_error() { aggregator_dispatcher.increase_counter_count(42); } + +#[test] +#[should_panic(expect: "Amount cannot be 0")] +fn test_decrease_zero_count_by_one_aggregator() { + let (_, _, aggregator_dispatcher) = deploy_contract(); + + let count_after = aggregator_dispatcher.get_count(); + assert(count_after == 0, 'invalid count'); + + aggregator_dispatcher.decrease_count_by_one(); + + let count_after = aggregator_dispatcher.get_count(); + assert(count_after == 19, 'incorrect count'); +} From 8afa8c93a5cc873e4f671eb38463eda5c3c0ded9 Mon Sep 17 00:00:00 2001 From: dinahmaccodes Date: Mon, 12 May 2025 11:12:23 +0100 Subject: [PATCH 4/4] feat: improve contracts and expand test cases --- src/aggregator.cairo | 142 ++++++++++----- src/killswitch.cairo | 1 - src/lib.cairo | 54 +----- src/ownable.cairo | 43 +++++ tests/lib.cairo | 92 ++++++++++ tests/test_aggregator.cairo | 349 ++++++++++++++++++++++++++++++++++++ tests/test_contract.cairo | 166 ----------------- tests/test_counter.cairo | 86 +++++++++ tests/test_killswitch.cairo | 22 +++ tests/test_ownable.cairo | 50 ++++++ 10 files changed, 740 insertions(+), 265 deletions(-) create mode 100644 src/ownable.cairo create mode 100644 tests/lib.cairo create mode 100644 tests/test_aggregator.cairo delete mode 100644 tests/test_contract.cairo create mode 100644 tests/test_counter.cairo create mode 100644 tests/test_killswitch.cairo create mode 100644 tests/test_ownable.cairo diff --git a/src/aggregator.cairo b/src/aggregator.cairo index 2d4d589..429d5a5 100644 --- a/src/aggregator.cairo +++ b/src/aggregator.cairo @@ -1,108 +1,129 @@ #[starknet::interface] pub trait IAggregator { - /// Increase contract count. + // Increase contract count. fn increase_count(ref self: TContractState, amount: u32); - /// Increase contract count. - /// + // Increase counter count fn increase_counter_count(ref self: TContractState, amount: u32); - - /// Retrieve contract count. + // Retrieve contract count. fn decrease_count_by_one(ref self: TContractState); - /// Retrieve contract count. + // Retrieve contract count. fn get_count(self: @TContractState) -> u32; - + // Activate the switch fn activate_switch(ref self: TContractState); } /// Simple contract for managing count. #[starknet::contract] -mod Agggregator { +pub mod Aggregator { use cohort_4::counter::{ICounterDispatcher, ICounterDispatcherTrait}; use cohort_4::killswitch::{IKillSwitchDispatcher, IKillSwitchDispatcherTrait}; - use starknet::ContractAddress; + use cohort_4::ownable::{IOwnableDispatcher, IOwnableDispatcherTrait}; use core::num::traits::Zero; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - + use starknet::{ContractAddress, get_caller_address}; + use crate::events::*; + use super::*; #[storage] struct Storage { count: u32, counter: ContractAddress, killswitch: ContractAddress, + ownable: ContractAddress, } - - #[event] #[derive(Drop, starknet::Event)] - pub enum Event { - CountIncreased: CountIncreased, - CounterCountIncreased: CounterCountIncreased, - CountDecreasedByOne: CountDecreasedByOne, - SwitchStatus: SwitchStatus, - } - - #[derive(Drop, Serde, starknet::Event)] pub struct CountIncreased { - amount: u32, + pub new_count: u32, + pub caller: ContractAddress, } - #[derive(Drop, Serde, starknet::Event)] + #[derive(Drop, starknet::Event)] pub struct CounterCountIncreased { - amount: u32, + pub new_counter: u32, + pub caller: ContractAddress, } - #[derive(Drop, Serde, starknet::Event)] + #[derive(Drop, starknet::Event)] pub struct CountDecreasedByOne { - pub previous_count: u32, + pub new_count: u32, + pub caller: ContractAddress, } - #[derive(Drop, Serde, starknet::Event)] + #[derive(Drop, starknet::Event)] pub struct SwitchStatus { - pub get_status: bool, + pub status: bool, + pub caller: ContractAddress, + } + + + #[event] + #[derive(Drop, starknet::Event)] + pub enum Event { + CountIncreased: CountIncreased, + CounterCountIncreased: CounterCountIncreased, + CountDecreasedByOne: CountDecreasedByOne, + SwitchStatus: SwitchStatus, } #[constructor] - fn constructor(ref self: ContractState, counter: ContractAddress, killswitch: ContractAddress) { + fn constructor( + ref self: ContractState, + counter: ContractAddress, + killswitch: ContractAddress, + ownable: ContractAddress, + ) { + //Validate the addresses to be sure + self.validate_contract_addresses(counter, killswitch, ownable); + self.counter.write(counter); self.killswitch.write(killswitch); - //Assert address is not 0 - assert(!self.counter.read().is_zero(), 'Counter address cannot be 0'); - assert(!self.killswitch.read().is_zero(), 'KillSwitch address cannot be 0'); - //Assert count is not kill_switch - assert( - self.counter.read() != self.killswitch.read(), - 'Odd! Counter is KillSwitch' - ); + self.ownable.write(ownable); } - #[abi(embed_v0)] impl AggregatorImpl of super::IAggregator { fn increase_count(ref self: ContractState, amount: u32) { + // Check ownership with internal function + self.assert_only_owner(); assert(amount > 0, 'Amount cannot be 0'); + let counter = ICounterDispatcher { contract_address: self.counter.read() }; let counter_count = counter.get_count(); - self.count.write(counter_count + amount); - self.emit(CountIncreased { amount }); + let new_count = counter_count + amount; + self.count.write(new_count); + + self.emit(CountIncreased { new_count: amount, caller: get_caller_address() }); } fn increase_counter_count(ref self: ContractState, amount: u32) { + // Check ownership with internal function + + self.assert_only_owner(); + let killswitch: IKillSwitchDispatcher = IKillSwitchDispatcher { contract_address: self.killswitch.read(), }; - assert(killswitch.get_status(), 'should be active'); + assert(killswitch.get_status(), 'Oops! Switch is off'); ICounterDispatcher { contract_address: self.counter.read() }.increase_count(amount); - self.emit(CounterCountIncreased { amount }); + self.emit(CounterCountIncreased { new_counter: amount, caller: get_caller_address() }); } fn decrease_count_by_one(ref self: ContractState) { + // Check ownership with internal function + self.assert_only_owner(); + let current_count = self.get_count(); - assert!(current_count != 0, "Amount cannot be 0"); - self.count.write(current_count - 1); - self.emit(CountDecreasedByOne { previous_count: current_count }); + assert(current_count != 0, 'Count cannot be 0'); + let new_count1 = current_count - 1; + self.count.write(new_count1); + + self.emit(CountDecreasedByOne { new_count: new_count1, caller: get_caller_address() }); } fn activate_switch(ref self: ContractState) { + self.assert_only_owner(); + let killswitch: IKillSwitchDispatcher = IKillSwitchDispatcher { contract_address: self.killswitch.read(), }; @@ -110,11 +131,42 @@ mod Agggregator { if !killswitch.get_status() { killswitch.switch() } - self.emit(SwitchStatus { get_status: true }); + + self.emit(SwitchStatus { status: true, caller: get_caller_address() }); } fn get_count(self: @ContractState) -> u32 { + self.assert_only_owner(); self.count.read() } } + + #[generate_trait] + impl OwnerHelpers of OwnersHelpersTrait { + //check owner is caller + fn assert_only_owner(self: @ContractState) { + let caller = get_caller_address(); + // Dispatcher to interact with contract + let ownable = IOwnableDispatcher { contract_address: self.ownable.read() }; + let owner = ownable.get_owner(); + assert(caller == owner, 'Caller is not owner'); + } + + fn validate_contract_addresses( + self: @ContractState, + counter: ContractAddress, + killswitch: ContractAddress, + ownable: ContractAddress, + ) { + //check that none is address zero + assert(counter.is_non_zero(), 'Counter address cannot be 0'); + assert(killswitch.is_non_zero(), 'KillSwitch address cannot be 0'); + assert(ownable.is_non_zero(), 'Ownable address cannot be 0'); + + //check there is no duplicate + assert(counter != killswitch, 'counter cant be killswitch'); + assert(counter != ownable, 'counter cant be ownable'); + assert(killswitch != ownable, 'killswitch cant be ownable'); + } + } } diff --git a/src/killswitch.cairo b/src/killswitch.cairo index 6437088..e207930 100644 --- a/src/killswitch.cairo +++ b/src/killswitch.cairo @@ -23,7 +23,6 @@ mod KillSwitch { #[abi(embed_v0)] impl KillSwitchImpl of super::IKillSwitch { fn switch(ref self: ContractState) { - // assert(amount != 0, 'Amount cannot be 0'); self.status.write(!self.status.read()); } diff --git a/src/lib.cairo b/src/lib.cairo index 7df1810..713255b 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -4,57 +4,5 @@ pub mod aggregator; pub mod counter; pub mod hello; pub mod killswitch; +pub mod ownable; - -fn main() { - // Function calls (Uncomment to execute them) - // say_name("Sylvia Nnoruka!"); - // intro_to_felt(); - - let num_1 = 5; - let num_2 = 10; - let sum = sum_num(num_1, num_2); - println!("The sum of {} and {} is = {}", num_1, num_2, sum); - - // check_u16(6553); // Uncomment if needed - is_greater_than_50(3); -} - -// DATA TYPES IN CAIRO -// - felts: felt252 (Field elements) -// - ByteArray: Represents a sequence of bytes -// - Integers: -// - Signed: i8, i16, i32, i64, i128, i256 -// - Unsigned: u8, u16, u32, u64, u128, u256 -// - Boolean: bool - -// Function to demonstrate ByteArray usage -fn say_name(x: ByteArray) { - println!("{}", x); -} - -// Function to demonstrate felt252 usage -fn intro_to_felt() { - let x = 40000; - println!("{}", x); -} - -// Function to sum two u8 integers -fn sum_num(x: u8, y: u8) -> u8 { - return x + y; -} - -// Function to print a u16 integer -fn check_u16(x: u16) { - println!("{x}"); -} - -// Function to check if a u32 integer is greater than 50 -fn is_greater_than_50(x: u32) -> bool { - if x > 50 { - println!("true"); - return true; - } - println!("false"); - return false; -} diff --git a/src/ownable.cairo b/src/ownable.cairo new file mode 100644 index 0000000..de92197 --- /dev/null +++ b/src/ownable.cairo @@ -0,0 +1,43 @@ +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IOwnable { + fn set_owner(ref self: TContractState, owner: ContractAddress); + fn get_owner(self: @TContractState) -> ContractAddress; +} + +#[starknet::contract] +mod Ownable { + use core::num::traits::Zero; + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use starknet::{ContractAddress, get_caller_address}; + + + #[storage] + struct Storage { + owner: ContractAddress, + } + + + #[constructor] + fn constructor(ref self: ContractState, initial_owner: ContractAddress) { + assert(initial_owner.is_non_zero(), 'Owner cannot be zero address'); + self.owner.write(initial_owner); + } + + #[abi(embed_v0)] + impl OwnableImpl of super::IOwnable { + fn set_owner(ref self: ContractState, owner: ContractAddress) { + let caller = get_caller_address(); + let current_owner = self.owner.read(); + assert(current_owner == caller, 'Nope! only owner can call this'); + assert(owner.is_non_zero(), 'New owner cant be zero address'); + //Set the owner + self.owner.write(owner); + } + + fn get_owner(self: @ContractState) -> ContractAddress { + self.owner.read() + } + } +} diff --git a/tests/lib.cairo b/tests/lib.cairo new file mode 100644 index 0000000..57354bd --- /dev/null +++ b/tests/lib.cairo @@ -0,0 +1,92 @@ +use cohort_4::aggregator::Aggregator::{ + CountDecreasedByOne, CountIncreased, CounterCountIncreased, Event, SwitchStatus, +}; +use cohort_4::aggregator::{IAggregatorDispatcher, IAggregatorDispatcherTrait,}; +use cohort_4::counter::{ + ICounterDispatcher, ICounterDispatcherTrait, ICounterSafeDispatcher, + ICounterSafeDispatcherTrait, +}; +use cohort_4::killswitch::{IKillSwitchDispatcher, IKillSwitchDispatcherTrait}; +use cohort_4::ownable::{IOwnableDispatcher, IOwnableDispatcherTrait}; +use core::traits::TryInto; +use core::num::traits::Zero; +use snforge_std::{ + ContractClassTrait, DeclareResultTrait, EventSpyAssertionsTrait, declare, spy_events, + start_cheat_caller_address, stop_cheat_caller_address, +}; +use starknet::ContractAddress; +pub mod test_aggregator; +pub mod test_counter; +pub mod test_killswitch; +pub mod test_ownable; + +fn deploy_contract() -> ( + ICounterDispatcher, IKillSwitchDispatcher, IAggregatorDispatcher, IOwnableDispatcher, +) { + //counter deployment + let counter_countract_name: ByteArray = "Counter"; + let contract = declare(counter_countract_name) + .expect('counter contract is not working') + .contract_class(); + let (counter_contract_address, _) = contract + .deploy(@ArrayTrait::new()) + .expect('counter address issue'); + let counter_dispatcher = ICounterDispatcher { contract_address: counter_contract_address }; + + //killswitch deployment + let killswitch_contract_name: ByteArray = "KillSwitch"; + let killswitch_contract = declare(killswitch_contract_name) + .expect('killswitch contract not working') + .contract_class(); + let (killswitch_contract_address, _) = killswitch_contract + .deploy(@ArrayTrait::new()) + .expect('killswitch address issue'); + let killswitch_dispatcher = IKillSwitchDispatcher { + contract_address: killswitch_contract_address, + }; + + //ownable deployment + let ownable_contract_name: ByteArray = "Ownable"; + let ownable_contract = declare(ownable_contract_name) + .expect('ownable contract not working') + .contract_class(); + let (ownable_contract_address, _) = ownable_contract + .deploy(@array![OWNER().into()]) + .expect('ownable address issue'); + let ownable = IOwnableDispatcher { contract_address: ownable_contract_address }; + + //aggregator deployment + let aggregator = declare("Aggregator").expect('aggregator contract error').contract_class(); + let (aggregator_contract_address, _) = aggregator + .deploy( + @array![ + counter_contract_address.into(), + killswitch_contract_address.into(), + ownable_contract_address.into(), + ], + ) + .expect('aggregator address issue'); + + let aggregator_dispatcher = IAggregatorDispatcher { + contract_address: aggregator_contract_address, + }; + + (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher, ownable) +} + +//Test accounts +fn OWNER() -> ContractAddress { + 'OWNER'.try_into().unwrap() +} + +fn NON_OWNER() -> ContractAddress { + 'NON_OWNER'.try_into().unwrap() +} + +fn NEW_OWNER() -> ContractAddress { + 'NEW_OWNER'.try_into().unwrap() +} + +fn zero_address() -> ContractAddress { + Zero::zero() +} diff --git a/tests/test_aggregator.cairo b/tests/test_aggregator.cairo new file mode 100644 index 0000000..a32b4bf --- /dev/null +++ b/tests/test_aggregator.cairo @@ -0,0 +1,349 @@ + +use super::*; + + + +#[test] +fn test_initial_count_balance_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + //check balance to ensure it is zero + let count_before = aggregator_dispatcher.get_count(); + assert(count_before == 0, 'wrong intial count'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); +} + + +#[test] +fn test_increase_count_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + let balance_1 = aggregator_dispatcher.get_count(); + assert(balance_1 == 0, 'wrong starting balance'); + //increase count + aggregator_dispatcher.increase_count(42); + + let balance_after = aggregator_dispatcher.get_count(); + //check balance to be sure increase occured + assert(balance_after == 42, 'wrong new balance'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); +} + +#[test] +fn test_increase_counter_count_aggregator() { + let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + let count_1 = aggregator_dispatcher.get_count(); + assert(count_1 == 0, 'invalid count 1'); + + //check if killswitch is off + let status_before = killswitch_dispatcher.get_status(); + assert(!status_before, 'incorrect killswitch status'); + //turn on the switch + aggregator_dispatcher.activate_switch(); + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'failed to activate'); + //increase the counter count + aggregator_dispatcher.increase_counter_count(42); + + //check if the count increased + let count_2 = counter_dispatcher.get_count(); + assert(count_2 == 42, 'invalid count_2'); +} + + +#[test] +fn test_decrease_count_by_one_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + let count_before = aggregator_dispatcher.get_count(); + assert(count_before == 0, 'intial count is not zero'); + + aggregator_dispatcher.increase_count(58); + aggregator_dispatcher.decrease_count_by_one(); + + let count_after = aggregator_dispatcher.get_count(); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + assert(count_after == 57, 'count is incorrect'); +} + +#[test] +fn test_activate_switch_aggregator() { + let (_, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + // check kill status_ + let status = killswitch_dispatcher.get_status(); + assert(!status, 'switch status failed'); + + // Start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + // Activate the switch + aggregator_dispatcher.activate_switch(); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + //check status once more + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'switch status not active'); +} + + +#[test] +#[should_panic(expect: 'Caller is not owner')] +fn test_should_panic_initial_count_balance_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + //start prank as non-owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, NON_OWNER()); + //check balance to ensure it is zero + let count_before = aggregator_dispatcher.get_count(); + assert(count_before == 0, 'wrong intial count'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); +} + +#[test] +#[should_panic(expect: 'Amount cannot be 0')] +fn test_increase_count_aggregator_by_zero() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + //start prank as non-owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + + let count_before = aggregator_dispatcher.get_count(); + assert(count_before == 0, 'wrong intial count'); + aggregator_dispatcher.increase_count(0); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); +} + +#[test] +#[should_panic(expect: 'Caller is not owner')] +fn test_should_panic_increase_count_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + //start prank as non-owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, NON_OWNER()); + let balance_1 = aggregator_dispatcher.get_count(); + assert(balance_1 == 0, 'wrong starting balance'); + //increase count + aggregator_dispatcher.increase_count(42); + + let balance_after = aggregator_dispatcher.get_count(); + //check balance to be sure increase occured + assert(balance_after == 42, 'wrong new balance'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); +} + + +#[test] +#[should_panic(expect: 'Caller is not owner')] +fn test_should_panic_increase_counter_count_aggregator() { + let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, NON_OWNER()); + let count_1 = aggregator_dispatcher.get_count(); + assert(count_1 == 0, 'invalid count 1'); + + //check if killswitch is off + let status_before = killswitch_dispatcher.get_status(); + assert(!status_before, 'incorrect killswitch status'); + //turn on the switch + aggregator_dispatcher.activate_switch(); + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'failed to activate'); + //increase the counter count + aggregator_dispatcher.increase_counter_count(42); + + //check if the count increased + let count_2 = counter_dispatcher.get_count(); + assert(count_2 == 42, 'invalid count_2'); +} + + +#[test] +#[should_panic(expect: 'Caller is not owner')] +fn test_should_panic_decrease_count_by_one_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + + start_cheat_caller_address(aggregator_dispatcher.contract_address, NON_OWNER()); + let count_before = aggregator_dispatcher.get_count(); + assert(count_before == 0, 'intial count is not zero'); + + aggregator_dispatcher.increase_count(58); + aggregator_dispatcher.decrease_count_by_one(); + + let count_after = aggregator_dispatcher.get_count(); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + assert(count_after == 57, 'count is incorrect'); +} + +#[test] +#[should_panic(expect: 'Caller is not owner')] +fn test_should_panic_activate_switch_aggregator() { + let (_, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + // check kill status_ + let status = killswitch_dispatcher.get_status(); + assert(!status, 'switch status failed'); + + // Start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, NON_OWNER()); + // Activate the switch + aggregator_dispatcher.activate_switch(); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + //check status once more + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'switch status not active'); +} + +// Tests to check for events! + +#[test] +fn test_should_emit_increase_count_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + + let mut spy = spy_events(); + + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + + let balance_1 = aggregator_dispatcher.get_count(); + assert(balance_1 == 0, 'wrong starting balance'); + + //increase count + aggregator_dispatcher.increase_count(42); + + let balance_after = aggregator_dispatcher.get_count(); + //check balance to be sure increase occured + assert(balance_after == 42, 'wrong new balance'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + + let expected_event = Event::CountIncreased( + CountIncreased { new_count: balance_after, caller: OWNER() }, + ); + + // Assert the event was emitted + spy.assert_emitted(@array![(aggregator_dispatcher.contract_address, expected_event)]); +} + +#[test] +fn test_should_emit_increase_counter_count_aggregator() { + let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + + let mut spy = spy_events(); + + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + let count_1 = aggregator_dispatcher.get_count(); + assert(count_1 == 0, 'invalid count 1'); + + //check if killswitch is off + let status_before = killswitch_dispatcher.get_status(); + assert(!status_before, 'incorrect killswitch status'); + //turn on the switch + aggregator_dispatcher.activate_switch(); + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'failed to activate'); + //increase the counter count + aggregator_dispatcher.increase_counter_count(42); + + //check if the count increased + let count_2 = counter_dispatcher.get_count(); + assert(count_2 == 42, 'invalid count_2'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + + let expected_event = Event::CounterCountIncreased( + CounterCountIncreased { new_counter: count_2, caller: OWNER() }, + ); + + //Check if the event was emmitted + spy.assert_emitted(@array![(aggregator_dispatcher.contract_address, expected_event)]); +} + +#[test] +fn test_should_emit_decrease_count_by_one_aggregator() { + let (_, _, aggregator_dispatcher, _) = deploy_contract(); + + let mut spy = spy_events(); + //start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + let count_before = aggregator_dispatcher.get_count(); + assert(count_before == 0, 'intial count is not zero'); + //increase count to have value > 0 to decrease from + aggregator_dispatcher.increase_count(58); + aggregator_dispatcher.decrease_count_by_one(); + //check new count value + let count_after = aggregator_dispatcher.get_count(); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + //assert that you have the right count value + assert(count_after == 57, 'count is incorrect'); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + + let expected_event = Event::CountDecreasedByOne( + CountDecreasedByOne { new_count: count_after, caller: OWNER() }, + ); + //check that event was emitted + spy.assert_emitted(@array![(aggregator_dispatcher.contract_address, expected_event)]); +} + +#[test] +fn test_should_emit_activate_switch_aggregator() { + let (_, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + + let mut spy = spy_events(); + + // check kill status + let status = killswitch_dispatcher.get_status(); + assert(!status, 'switch status failed'); + + // Start prank as owner + start_cheat_caller_address(aggregator_dispatcher.contract_address, OWNER()); + // Activate the switch + aggregator_dispatcher.activate_switch(); + stop_cheat_caller_address(aggregator_dispatcher.contract_address); + //check status once more + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'switch status not active'); + + let expected_event = Event::SwitchStatus(SwitchStatus { status: status_after, caller: OWNER()}); + + //check that event was emitted + spy.assert_emitted(@array![(aggregator_dispatcher.contract_address, expected_event)]); + +} + + +// #[test] +// #[feature("safe_dispatcher")] +// fn test_fail_for_non_owner_increase_counter_count() { +// let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher, _) = deploy_contract(); + +// //start prank as non-owner +// start_cheat_caller_address(aggregator_dispatcher.contract_address, NON_OWNER()); +// let count_1 = aggregator_dispatcher.get_count(); +// assert(count_1 == 0, 'invalid count 1'); + +// //check if killswitch is off +// let status_before = killswitch_dispatcher.get_status(); +// assert(!status_before, 'incorrect killswitch status'); +// //turn on the switch +// aggregator_dispatcher.activate_switch(); +// let status_after = killswitch_dispatcher.get_status(); +// assert(status_after, 'failed to activate'); +// //increase the counter count +// aggregator_dispatcher.increase_counter_count(42); + +// //check if the count increased +// let count_2 = counter_dispatcher.get_count(); +// assert(count_2 == 42, 'invalid count_2'); + +// let safe_dispatcher = IAggregatorSafeDispatcher { +// contract_address: NON_OWNER(), +// }; + +// match safe_dispatcher.increase_counter_count(2) { +// Result::Ok(_) => core::panic_with_felt252('Should have panicked'), +// Result::Err(panic_data) => { +// assert(*panic_data.at(0) == 'Caller is not owner', *panic_data.at(0)); +// }, +// }; + +// } diff --git a/tests/test_contract.cairo b/tests/test_contract.cairo deleted file mode 100644 index e9ffb8a..0000000 --- a/tests/test_contract.cairo +++ /dev/null @@ -1,166 +0,0 @@ -use cohort_4::aggregator::{IAggregatorDispatcher, IAggregatorDispatcherTrait}; -use cohort_4::counter::{ - ICounterDispatcher, ICounterDispatcherTrait, ICounterSafeDispatcher, - ICounterSafeDispatcherTrait, -}; -use cohort_4::killswitch::{IKillSwitchDispatcher, IKillSwitchDispatcherTrait}; -use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; - - -fn deploy_contract() -> (ICounterDispatcher, IKillSwitchDispatcher, IAggregatorDispatcher) { - //counter deployment - let counter_countract_name: ByteArray = "Counter"; - let contract = declare(counter_countract_name).unwrap().contract_class(); - let (counter_contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap(); - let counter_dispatcher = ICounterDispatcher { contract_address: counter_contract_address }; - - //killswitch deployment - let killswitch_contract_name: ByteArray = "KillSwitch"; - let killswitch_contract = declare(killswitch_contract_name).unwrap().contract_class(); - let (killswitch_contract_address, _) = killswitch_contract.deploy(@ArrayTrait::new()).unwrap(); - let killswitch_dispatcher = IKillSwitchDispatcher { - contract_address: killswitch_contract_address, - }; - - //aggregator deployment - let aggregator = declare("Agggregator").unwrap().contract_class(); - let (aggregator_contract_address, _) = aggregator - .deploy(@array![counter_contract_address.into(), killswitch_contract_address.into()]) - .unwrap(); - - let aggregator_dispatcher = IAggregatorDispatcher { - contract_address: aggregator_contract_address, - }; - - (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) -} - -#[test] -fn test_increase_count() { - let (counter_dispatcher, _, _) = deploy_contract(); - - let balance_before = counter_dispatcher.get_count(); - assert(balance_before == 0, 'Invalid balance'); - - counter_dispatcher.increase_count(42); - - let balance_after = counter_dispatcher.get_count(); - assert(balance_after == 42, 'Invalid balance'); -} - -#[test] -#[feature("safe_dispatcher")] -fn test_cannot_increase_balance_with_zero_value() { - let (counter_dispatcher, _, _) = deploy_contract(); - - let balance_before = counter_dispatcher.get_count(); - assert(balance_before == 0, 'Invalid balance'); - - let safe_dispatcher = ICounterSafeDispatcher { - contract_address: counter_dispatcher.contract_address, - }; - - match safe_dispatcher.increase_count(0) { - Result::Ok(_) => core::panic_with_felt252('Should have panicked'), - Result::Err(panic_data) => { - assert(*panic_data.at(0) == 'Amount cannot be 0', *panic_data.at(0)); - }, - }; -} - -#[test] -fn test_increase_count_aggregator() { - let (_, _, aggregator_dispatcher) = deploy_contract(); - - let balance_before = aggregator_dispatcher.get_count(); - assert(balance_before == 0, 'Invalid balance'); - - aggregator_dispatcher.increase_count(42); - - let balance_after = aggregator_dispatcher.get_count(); - assert(balance_after == 42, 'Invalid balance'); -} - -#[test] -fn test_increase_counter_count_aggregator() { - let (counter_dispatcher, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); - - let count_1 = counter_dispatcher.get_count(); - assert(count_1 == 0, 'invalid count 1'); - - let status_before = killswitch_dispatcher.get_status(); - assert(!status_before, 'incorrect status'); - - aggregator_dispatcher.activate_switch(); - let status_after = killswitch_dispatcher.get_status(); - assert(status_after, 'failed to activate'); - - aggregator_dispatcher.increase_counter_count(42); - - let count_2 = counter_dispatcher.get_count(); - assert(count_2 == 42, 'invalid count 2'); -} - -#[test] -fn test_decrease_count_by_one_aggregator() { - let (_, _, aggregator_dispatcher) = deploy_contract(); - - let count_after = aggregator_dispatcher.get_count(); - assert(count_after == 0, 'invalid count'); - - aggregator_dispatcher.increase_count(20); - aggregator_dispatcher.decrease_count_by_one(); - - let count_after = aggregator_dispatcher.get_count(); - assert(count_after == 19, 'incorrect count'); -} - - -#[test] -fn test_increase_activate_switch() { - let (_, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); - - let status = killswitch_dispatcher.get_status(); - assert(!status, 'failed'); - - aggregator_dispatcher.activate_switch(); - - let status_after = killswitch_dispatcher.get_status(); - assert(status_after, 'invalid status'); -} - -#[test] -#[should_panic(expect: 'Amount cannot be 0')] -fn test_increase_count_by_zero_aggregator() { - let (_, _, aggregator_dispatcher) = deploy_contract(); - - let count_after = aggregator_dispatcher.get_count(); - assert(count_after == 0, 'incorrect count'); - - aggregator_dispatcher.increase_count(0); -} - -#[test] -#[should_panic(expect: 'should be active')] -fn test_increase_counter_count_error() { - let (_, killswitch_dispatcher, aggregator_dispatcher) = deploy_contract(); - - let status_before = killswitch_dispatcher.get_status(); - assert(status_before, 'invalid status'); - - aggregator_dispatcher.increase_counter_count(42); -} - -#[test] -#[should_panic(expect: "Amount cannot be 0")] -fn test_decrease_zero_count_by_one_aggregator() { - let (_, _, aggregator_dispatcher) = deploy_contract(); - - let count_after = aggregator_dispatcher.get_count(); - assert(count_after == 0, 'invalid count'); - - aggregator_dispatcher.decrease_count_by_one(); - - let count_after = aggregator_dispatcher.get_count(); - assert(count_after == 19, 'incorrect count'); -} diff --git a/tests/test_counter.cairo b/tests/test_counter.cairo new file mode 100644 index 0000000..fd1dc86 --- /dev/null +++ b/tests/test_counter.cairo @@ -0,0 +1,86 @@ +use super::*; + +#[test] +fn test_initial_count_balance() { + let (counter_dispatcher, _, _, _) = deploy_contract(); + let count = counter_dispatcher.get_count(); + assert(count == 0, 'Wrong intial count value'); +} + + +#[test] +fn test_increase_count() { + let (counter_dispatcher, _, _, _) = deploy_contract(); + + let balance_before = counter_dispatcher.get_count(); + assert(balance_before == 0, 'Invalid balance'); + + counter_dispatcher.increase_count(42); + + let balance_after = counter_dispatcher.get_count(); + assert(balance_after == 42, 'Invalid balance'); +} + + +#[test] +#[feature("safe_dispatcher")] +fn test_cannot_increase_balance_with_zero_value() { + let (counter_dispatcher, _, _, _) = deploy_contract(); + + let balance_before = counter_dispatcher.get_count(); + assert(balance_before == 0, 'Invalid balance'); + + let safe_dispatcher = ICounterSafeDispatcher { + contract_address: counter_dispatcher.contract_address, + }; + + match safe_dispatcher.increase_count(0) { + Result::Ok(_) => core::panic_with_felt252('Should have panicked'), + Result::Err(panic_data) => { + assert(*panic_data.at(0) == 'Amount cannot be 0', *panic_data.at(0)); + }, + }; +} + +#[test] +fn test_decrease_count_by_one() { + let (counter_dispatcher, _, _, _) = deploy_contract(); + + //Check initial balance + let balance_before = counter_dispatcher.get_count(); + assert(balance_before == 0, 'Wrong initial value'); + + //increase count then decrease count + counter_dispatcher.increase_count(20); + counter_dispatcher.decrease_count_by_one(); + let balance_after = counter_dispatcher.get_count(); + assert(balance_after == 19, 'Wrong new balance'); + +} + +#[test] +#[feature("safe_dispatcher")] +fn test_cannot_decrease_balance_with_zero_value() { + let (counter_dispatcher, _, _, _) = deploy_contract(); + + //check intial balance + let balance_before = counter_dispatcher.get_count(); + assert(balance_before == 0, 'Wrong intial value'); + + let safe_dispatcher = ICounterSafeDispatcher { + contract_address: counter_dispatcher.contract_address, + + }; + match safe_dispatcher.decrease_count_by_one() { + Result::Ok(_) => core::panic_with_felt252('Should have panicked'), + Result::Err(panic_data) => { + assert(*panic_data.at(0) == 'Amount cannot be 0', *panic_data.at(0)); + + }, + }; + +} + + + + diff --git a/tests/test_killswitch.cairo b/tests/test_killswitch.cairo new file mode 100644 index 0000000..3e1ccec --- /dev/null +++ b/tests/test_killswitch.cairo @@ -0,0 +1,22 @@ +use super::*; + +#[test] +fn test_use_switch() { + let (_, killswitch_dispatcher, _, _) = deploy_contract(); + // check kill status_ + let status = killswitch_dispatcher.get_status(); + assert(!status, 'switch status failed'); + + killswitch_dispatcher.switch(); + let status_after = killswitch_dispatcher.get_status(); + assert(status_after, 'nothing changed'); + +} + +#[test] +fn test_get_switch_status() { + let (_, killswitch_dispatcher, _, _) = deploy_contract(); + //check kill switch status + let status = killswitch_dispatcher.get_status(); + assert(!status, 'switch status failed'); +} \ No newline at end of file diff --git a/tests/test_ownable.cairo b/tests/test_ownable.cairo new file mode 100644 index 0000000..fc2e586 --- /dev/null +++ b/tests/test_ownable.cairo @@ -0,0 +1,50 @@ + +use super::*; + + + +#[test] +fn test_check_ownable() { + let (_, _, _, ownable) = deploy_contract(); + + start_cheat_caller_address(ownable.contract_address, OWNER()); + assert(ownable.get_owner() == OWNER(), 'Oops! not the owner'); +} + + +#[test] +fn test_check_ownable_set_new_owner() { + let (_, _, _, ownable) = deploy_contract(); + + start_cheat_caller_address(ownable.contract_address, OWNER()); + assert(ownable.get_owner() == OWNER(), 'Oops! not the owner'); + // stop_cheat_caller_address(ownable.contract_address); + + // start_cheat_caller_address(ownable.contract_address, OWNER()); + ownable.set_owner(NEW_OWNER()); + assert(ownable.get_owner() == NEW_OWNER(), 'Oops! not the new owner'); + stop_cheat_caller_address(ownable.contract_address); +} + +//CHECK THIS TEST WELL +#[test] +#[should_panic(expect: 'Nope! only owner can call this')] +fn test_ownable_should_panic_with_non_owner() { + let (_, _, _, ownable) = deploy_contract(); + + //start prank as non-owner + start_cheat_caller_address(ownable.contract_address, NON_OWNER()); + assert(ownable.get_owner() == NON_OWNER(), 'Oops! not the new owner'); + stop_cheat_caller_address(ownable.contract_address); +} +#[test] +#[should_panic(expect: 'New owner cant be zero address')] +fn test_ownable_should_panic_with_new_owner_zero_address() { + let (_, _, _, ownable) = deploy_contract(); + + + start_cheat_caller_address(ownable.contract_address, OWNER()); + ownable.set_owner(zero_address()); + assert(ownable.get_owner() == zero_address(), 'Oops! not the new owner'); + stop_cheat_caller_address(ownable.contract_address); +}