diff --git a/src/counter_v4.cairo b/src/counter_v4.cairo new file mode 100644 index 0000000..b8fb55c --- /dev/null +++ b/src/counter_v4.cairo @@ -0,0 +1,60 @@ +use starknet::{ContractAddress, get_caller_address}; + +#[starknet::interface] +pub trait ICounterV4 { + fn increase_count(ref self: TContractState, amount: u32); + fn get_count(self: @TContractState) -> u32; + fn get_owner(self: @TContractState) -> ContractAddress; +} + +#[starknet::contract] +pub mod CounterContractV4 { + use starknet_testing::errors::Errors; + use starknet_testing::add::add; + use super::{ContractAddress, get_caller_address}; + + #[storage] + struct Storage { + count: u32, + owner: ContractAddress + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + StoredCount: StoredCount + } + + #[derive(Drop, starknet::Event)] + struct StoredCount { + pub new_count: u32, + pub caller: ContractAddress, + } + + #[constructor] + fn constructor(ref self: ContractState, _owner: ContractAddress) { + // Set `owner` address + self.owner.write(_owner); + } + + #[abi(embed_v0)] + impl ICounterImpl of super::ICounterV4 { + fn increase_count(ref self: ContractState, amount: u32) { + let caller = get_caller_address(); + assert(caller == self.owner.read(), 'not owner'); + assert(amount != 0, Errors::ZERO_AMOUNT); + let current_count: u32 = self.count.read(); + let result = add(current_count, amount); + self.count.write(result); + self.emit(StoredCount { new_count: result, caller: caller }); + } + + fn get_count(self: @ContractState) -> u32 { + self.count.read() + } + + fn get_owner(self: @ContractState) -> ContractAddress { + self.owner.read() + } + } +} diff --git a/src/lib.cairo b/src/lib.cairo index ed13257..70c2fed 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,5 +1,6 @@ pub mod counter; pub mod counter_v2; pub mod counter_v3; +pub mod counter_v4; pub mod errors; pub mod add; diff --git a/tests/test_counter_v4.cairo b/tests/test_counter_v4.cairo new file mode 100644 index 0000000..678da95 --- /dev/null +++ b/tests/test_counter_v4.cairo @@ -0,0 +1,98 @@ + +use starknet::{ContractAddress, get_caller_address}; +use core::result::ResultTrait; +use snforge_std::{declare, ContractClassTrait, CheatTarget}; +use snforge_std as snf; +use snforge_std::errors::{ SyscallResultStringErrorTrait, PanicDataOrString }; +use starknet_testing::counter_v4::{ICounterV4Dispatcher, ICounterV4DispatcherTrait}; + +pub mod Accounts { + use starknet::ContractAddress; + use core::traits::TryInto; + + pub fn owner() -> ContractAddress { + 'owner'.try_into().unwrap() + } + + pub fn account1() -> ContractAddress { + 'account1'.try_into().unwrap() + } +} + +// Deploy contract and return the contract address +pub fn deploy_contract_v4(name: ByteArray) -> ContractAddress { + let contract = declare(name).unwrap(); + // The constructor in CounterContractV3 expects one argument - the address to be set as `owner` + let constructor_calldata = array![Accounts::owner().into()]; + let (contract_address, _) = contract.deploy(@constructor_calldata).unwrap(); + contract_address +} + +// Cannot increase count with other account +#[test] +fn test_deploy_contract_v4() { + let contract_address = deploy_contract_v4("CounterContractV4"); + + let counter_v4_dispatcher = ICounterV4Dispatcher { contract_address }; + + let custom_owner: ContractAddress = Accounts::owner(); + + let contract_owner = counter_v4_dispatcher.get_owner(); + + assert_eq!(contract_owner, custom_owner); +} + + + +#[test] +fn test_cannot_increase_count_account () { + + let contract_address = deploy_contract_v4("CounterContractV4"); + + let counter_v4_dispatcher = ICounterV4Dispatcher { contract_address }; + + let custom_owner: ContractAddress = Accounts::account1(); + + let contract_owner = counter_v4_dispatcher.get_owner(); + + assert!(contract_owner != custom_owner, "Cannot increase count with other account"); + +} + + +#[test] +fn test_owner_increase_count () { + + let contract_address = deploy_contract_v4("CounterContractV4"); + + snf::start_prank(CheatTarget::One(contract_address), Accounts::owner()); + + let counter_v4_dispatcher = ICounterV4Dispatcher { contract_address }; + + counter_v4_dispatcher.increase_count(5); + + let get_owner_count = counter_v4_dispatcher.get_count(); + + assert!(get_owner_count != 5, "Fail to update owner count"); + + snf::stop_prank(CheatTarget::One(contract_address)); + +} + + + +#[test] +#[feature("safe_dispatcher")] +fn test_cannot_increase_count_by_Zero() { + let contract_address = deploy_contract_v4("CounterContractV4"); + + let safe_dispatcher = ICounterV4Dispatcher { 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) == 'Count cannot be 0', *panic_data.at(0)); + } + }; + +} \ No newline at end of file