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/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/aggregator.cairo b/src/aggregator.cairo index 3e4cbe8..429d5a5 100644 --- a/src/aggregator.cairo +++ b/src/aggregator.cairo @@ -1,66 +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, + } + + #[derive(Drop, starknet::Event)] + pub struct CountIncreased { + pub new_count: u32, + pub caller: ContractAddress, + } + + #[derive(Drop, starknet::Event)] + pub struct CounterCountIncreased { + pub new_counter: u32, + pub caller: ContractAddress, + } + + #[derive(Drop, starknet::Event)] + pub struct CountDecreasedByOne { + pub new_count: u32, + pub caller: ContractAddress, + } + + #[derive(Drop, starknet::Event)] + pub struct SwitchStatus { + 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); + 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); + 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(), 'not active'); - ICounterDispatcher { contract_address: self.counter.read() }.increase_count(amount) + assert(killswitch.get_status(), 'Oops! Switch is off'); + ICounterDispatcher { contract_address: self.counter.read() }.increase_count(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); + 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(), }; @@ -68,10 +131,42 @@ mod Agggregator { if !killswitch.get_status() { killswitch.switch() } + + 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/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/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 8b3993c..713255b 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,61 +1,8 @@ -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); -} - -// 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}"); -} +pub mod ownable; -// 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 9d6708a..0000000 --- a/tests/test_contract.cairo +++ /dev/null @@ -1,49 +0,0 @@ -use starknet::ContractAddress; - -use snforge_std::{declare, ContractClassTrait, DeclareResultTrait}; - -use cohort_4::counter::{ICounterDispatcher, ICounterDispatcherTrait, ICounterSafeDispatcher, ICounterSafeDispatcherTrait}; - -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 -} - -#[test] -fn test_increase_count() { - let contract_address = deploy_contract(); - - let dispatcher = ICounterDispatcher { contract_address }; - - let balance_before = dispatcher.get_count(); - assert(balance_before == 0, 'Invalid balance'); - - dispatcher.increase_count(42); - - let balance_after = 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 balance_before = dispatcher.get_count(); - assert(balance_before == 0 , 'Invalid balance'); - - let safe_dispatcher = ICounterSafeDispatcher { 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)); - } - }; - - -} 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); +}