diff --git a/README.md b/README.md index d13b071..6fdd6ba 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,11 @@ If you are interested in contributing to Go Stark Me, please follow these steps: 2. Comment on the issue you want to participate in, detailing how you plan to address it and how long you expect it to take. 3. Wait to be assigned to the issue. +Official Discord Channel: +- [Web3Wagers](https://discord.gg/sEpnC6JB2U) + You can also contact us on Telegram: - [@adrian_vrj](https://t.me/adrian_vrj) - [@EmmanuelDevCr](https://t.me/EmmanuelDevCr) + diff --git a/contracts/.snfoundry_cache/.prev_tests_failed b/contracts/.snfoundry_cache/.prev_tests_failed index e69de29..5d28940 100644 --- a/contracts/.snfoundry_cache/.prev_tests_failed +++ b/contracts/.snfoundry_cache/.prev_tests_failed @@ -0,0 +1 @@ +tests::test_fund::test_receive_vote_unsuccessful_wrong_state diff --git a/contracts/src/constants/funds.cairo b/contracts/src/constants/funds.cairo index 3c57400..a0adbf1 100644 --- a/contracts/src/constants/funds.cairo +++ b/contracts/src/constants/funds.cairo @@ -1 +1,2 @@ pub mod state_constants; +pub mod fund_constants; diff --git a/contracts/src/constants/funds/fund_constants.cairo b/contracts/src/constants/funds/fund_constants.cairo new file mode 100644 index 0000000..7de0d07 --- /dev/null +++ b/contracts/src/constants/funds/fund_constants.cairo @@ -0,0 +1,8 @@ +// ************************************************************************* +// FUND CONSTANTS +// ************************************************************************* +pub mod FundConstants { + pub const UP_VOTES_NEEDED: u32 = 100; + pub const INITIAL_UP_VOTES: u32 = 0; + pub const INITIAL_GOAL: u64 = 0; +} diff --git a/contracts/src/fund.cairo b/contracts/src/fund.cairo index 01a2e8f..dc33e04 100644 --- a/contracts/src/fund.cairo +++ b/contracts/src/fund.cairo @@ -1,7 +1,7 @@ use starknet::ContractAddress; #[starknet::interface] -trait IFund { +pub trait IFund { fn getId(self: @TContractState) -> u128; fn getOwner(self: @TContractState) -> ContractAddress; fn setName(ref self: TContractState, name: felt252); @@ -27,6 +27,8 @@ mod Fund { use starknet::ContractAddress; use starknet::get_caller_address; use gostarkme::constants::{funds::{state_constants::FundStates},}; + use gostarkme::constants::{funds::{fund_constants::FundConstants},}; + // ************************************************************************* // STORAGE @@ -60,9 +62,9 @@ mod Fund { self.owner.write(owner); self.name.write(name); self.reason.write(reason); - self.up_votes.write(1); + self.up_votes.write(FundConstants::INITIAL_UP_VOTES); self.goal.write(goal); - self.current_goal_state.write(0); + self.current_goal_state.write(FundConstants::INITIAL_GOAL); self.state.write(FundStates::RECOLLECTING_VOTES); } @@ -98,9 +100,9 @@ mod Fund { assert( self.state.read() == FundStates::RECOLLECTING_VOTES, 'Fund not recollecting votes!' ); - self.voters.write(get_caller_address(), self.up_votes.read()); self.up_votes.write(self.up_votes.read() + 1); - if self.up_votes.read() >= 1 { + self.voters.write(get_caller_address(), self.up_votes.read()); + if self.up_votes.read() >= FundConstants::UP_VOTES_NEEDED { self.state.write(FundStates::RECOLLECTING_DONATIONS); } } @@ -129,6 +131,7 @@ mod Fund { fn getCurrentGoalState(self: @ContractState) -> u64 { return self.current_goal_state.read(); } + // TODO: Validate to change method to change setState and getState fn setIsActive(ref self: ContractState, state: u8) { self.state.write(state); } diff --git a/contracts/tests/test_fund.cairo b/contracts/tests/test_fund.cairo new file mode 100644 index 0000000..c275ec9 --- /dev/null +++ b/contracts/tests/test_fund.cairo @@ -0,0 +1,157 @@ +// ************************************************************************* +// FUND TEST +// ************************************************************************* +use starknet::{ContractAddress, contract_address_const}; + +use snforge_std::{declare, ContractClassTrait, CheatTarget}; + +use openzeppelin::utils::serde::SerializedAppend; + +use gostarkme::fund::IFundDispatcher; +use gostarkme::fund::IFundDispatcherTrait; + +fn ID() -> u128 { + 1 +} +fn OWNER() -> ContractAddress { + contract_address_const::<'OWNER'>() +} +fn OTHER_USER() -> ContractAddress { + contract_address_const::<'USER'>() +} +fn NAME() -> felt252 { + 'NAME_FUND_TEST' +} +fn REASON() -> felt252 { + 'REASON_FUND_TEST' +} +fn GOAL() -> u64 { + 1000 +} +fn __setup__() -> ContractAddress { + let contract = declare("Fund"); + let mut calldata: Array = array![]; + calldata.append_serde(ID()); + calldata.append_serde(OWNER()); + calldata.append_serde(NAME()); + calldata.append_serde(REASON()); + calldata.append_serde(GOAL()); + contract.deploy(@calldata).unwrap() +} +// ************************************************************************* +// TEST +// ************************************************************************* +#[test] +fn test_constructor() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + let id = dispatcher.getId(); + let owner = dispatcher.getOwner(); + let name = dispatcher.getName(); + let reason = dispatcher.getReason(); + let up_votes = dispatcher.getUpVotes(); + let goal = dispatcher.getGoal(); + let current_goal_state = dispatcher.getCurrentGoalState(); + let state = dispatcher.getIsActive(); + assert(id == ID(), 'Invalid id'); + assert(owner == OWNER(), 'Invalid owner'); + assert(name == NAME(), 'Invalid name'); + assert(reason == REASON(), 'Invalid reason'); + assert(up_votes == 0, 'Invalid up votes'); + assert(goal == GOAL(), 'Invalid goal'); + assert(current_goal_state == 0, 'Invalid current goal state'); + assert(state == 1, 'Invalid state'); +} + +#[test] +fn test_set_name() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + let name = dispatcher.getName(); + assert(name == NAME(), 'Invalid name'); + snforge_std::start_prank(CheatTarget::One(contract_address), OWNER()); + dispatcher.setName('NEW_NAME'); + let new_name = dispatcher.getName(); + assert(new_name == 'NEW_NAME', 'Set name method not working') +} + +#[test] +fn test_set_reason() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + let reason = dispatcher.getReason(); + assert(reason == REASON(), 'Invalid reason'); + snforge_std::start_prank(CheatTarget::One(contract_address), OWNER()); + dispatcher.setReason('NEW_REASON'); + let new_reason = dispatcher.getReason(); + assert(new_reason == 'NEW_REASON', 'Set reason method not working') +} + +#[test] +fn test_set_goal() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + let goal = dispatcher.getGoal(); + assert(goal == GOAL(), 'Invalid goal'); + snforge_std::start_prank(CheatTarget::One(contract_address), OWNER()); + dispatcher.setGoal(123); + let new_goal = dispatcher.getGoal(); + assert(new_goal == 123, 'Set goal method not working') +} + +#[test] +fn test_receive_vote_successful() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + dispatcher.receiveVote(); + let me = dispatcher.getVoter(); + // Owner vote, fund have one vote + assert(me == 1, 'Owner is not in the voters'); + let votes = dispatcher.getUpVotes(); + assert(votes == 1, 'Vote unuseccessful'); +} + +#[test] +#[should_panic(expected: ('User already voted!',))] +fn test_receive_vote_unsuccessful_double_vote() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + dispatcher.receiveVote(); + let me = dispatcher.getVoter(); + // Owner vote, fund have one vote + assert(me == 1, 'Owner is not in the voters'); + let votes = dispatcher.getUpVotes(); + assert(votes == 1, 'Vote unuseccessful'); + // Owner vote, second time + dispatcher.receiveVote(); +} + +#[test] +fn test_receive_donation_successful() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + // Put state as recollecting dons + dispatcher.setIsActive(2); + // Put 10 strks as goal, only owner + snforge_std::start_prank(CheatTarget::One(contract_address), OWNER()); + dispatcher.setGoal(10); + // Donate 5 strks + dispatcher.receiveDonation(5); + let current_goal_state = dispatcher.getCurrentGoalState(); + assert(current_goal_state == 5, 'Receive donation not working'); + // Donate 5 strks, the goal is done + dispatcher.receiveDonation(5); + let state = dispatcher.getIsActive(); + assert(state == 3, 'State should be close'); +} + +#[test] +#[should_panic(expected: ('Fund not recollecting dons!',))] +fn test_receive_donation_unsuccessful_wrong_state() { + let contract_address = __setup__(); + let dispatcher = IFundDispatcher { contract_address }; + // Put a wrong state to receive donations + dispatcher.setIsActive(1); + // Donate + dispatcher.receiveDonation(5); +}