diff --git a/contracts/src/constants/funds.cairo b/contracts/src/constants/funds.cairo index 48e175a..2555e8f 100644 --- a/contracts/src/constants/funds.cairo +++ b/contracts/src/constants/funds.cairo @@ -1,3 +1,3 @@ pub mod state_constants; pub mod fund_constants; -pub mod starknet_constants; \ No newline at end of file +pub mod starknet_constants; diff --git a/contracts/src/constants/funds/starknet_constants.cairo b/contracts/src/constants/funds/starknet_constants.cairo index 3a1fde6..78b1275 100644 --- a/contracts/src/constants/funds/starknet_constants.cairo +++ b/contracts/src/constants/funds/starknet_constants.cairo @@ -4,5 +4,6 @@ use starknet::ContractAddress; // STARKNET CONSTANTS // ************************************************************************* pub mod StarknetConstants { - pub const STRK_TOKEN_ADDRESS: felt252 = 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d; -} \ No newline at end of file + pub const STRK_TOKEN_ADDRESS: felt252 = + 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d; +} diff --git a/contracts/src/constants/funds/state_constants.cairo b/contracts/src/constants/funds/state_constants.cairo index 0da1356..0c04d65 100644 --- a/contracts/src/constants/funds/state_constants.cairo +++ b/contracts/src/constants/funds/state_constants.cairo @@ -6,4 +6,5 @@ pub mod FundStates { pub const RECOLLECTING_VOTES: u8 = 1; pub const RECOLLECTING_DONATIONS: u8 = 2; pub const CLOSED: u8 = 3; + pub const WITHDRAW: u8 = 4; } diff --git a/contracts/src/fund.cairo b/contracts/src/fund.cairo index 9ac9023..e241f47 100644 --- a/contracts/src/fund.cairo +++ b/contracts/src/fund.cairo @@ -14,9 +14,10 @@ pub trait IFund { fn getGoal(self: @TContractState) -> u256; fn receiveDonation(ref self: TContractState, strks: u256); fn getCurrentGoalState(self: @TContractState) -> u256; - fn setIsActive(ref self: TContractState, state: u8); - fn getIsActive(self: @TContractState) -> u8; + fn setState(ref self: TContractState, state: u8); + fn getState(self: @TContractState) -> u8; fn getVoter(self: @TContractState) -> u32; + fn withdraw(ref self: TContractState); } #[starknet::contract] @@ -26,9 +27,12 @@ mod Fund { // ************************************************************************* use starknet::ContractAddress; use starknet::get_caller_address; + use starknet::contract_address_const; + use starknet::get_contract_address; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use gostarkme::constants::{funds::{state_constants::FundStates},}; use gostarkme::constants::{funds::{fund_constants::FundConstants},}; + use gostarkme::constants::{funds::{starknet_constants::StarknetConstants},}; // ************************************************************************* @@ -127,15 +131,33 @@ mod Fund { fn getCurrentGoalState(self: @ContractState) -> u256 { return self.current_goal_state.read(); } - // TODO: Validate to change method to change setState and getState - fn setIsActive(ref self: ContractState, state: u8) { + fn setState(ref self: ContractState, state: u8) { self.state.write(state); } - fn getIsActive(self: @ContractState) -> u8 { + fn getState(self: @ContractState) -> u8 { return self.state.read(); } fn getVoter(self: @ContractState) -> u32 { return self.voters.read(get_caller_address()); } + fn withdraw(ref self: ContractState) { + // Verifications + let caller = get_caller_address(); + assert!(self.owner.read() == caller, "You are not the owner"); + assert(self.state.read() == FundStates::CLOSED, 'Fund not close goal yet.'); + assert(self.getCurrentGoalState() > 0, 'Fund hasnt reached its goal yet'); + // Withdraw + let starknet_contract_address = contract_address_const::< + StarknetConstants::STRK_TOKEN_ADDRESS + >(); + let starknet_dispatcher = IERC20Dispatcher { + contract_address: starknet_contract_address + }; + let balance = starknet_dispatcher.balance_of(get_contract_address()); + //TODO: Calculate balance to deposit in owner address and in fund manager address (95% and 5%), also transfer the amount to fund manager address. + starknet_dispatcher.transfer(self.getOwner(), balance); + assert(self.getCurrentGoalState() != 0, 'Fund hasnt reached its goal yet'); + self.setState(4); + } } } diff --git a/contracts/src/fundManager.cairo b/contracts/src/fundManager.cairo index d999904..22786ed 100755 --- a/contracts/src/fundManager.cairo +++ b/contracts/src/fundManager.cairo @@ -42,7 +42,7 @@ mod FundManager { fn constructor(ref self: ContractState, fund_class_hash: felt252) { self.owner.write(get_caller_address()); self.fund_class_hash.write(fund_class_hash.try_into().unwrap()); - self.current_id.write(0); + self.current_id.write(1); } // *************************************************************************************** @@ -60,8 +60,8 @@ mod FundManager { self.fund_class_hash.read(), 12345, call_data.span(), false ) .unwrap(); - self.current_id.write(self.current_id.read() + 1); self.funds.write(self.current_id.read(), address_0); + self.current_id.write(self.current_id.read() + 1); } fn getCurrentId(self: @ContractState) -> u128 { return self.current_id.read(); @@ -76,4 +76,4 @@ mod FundManager { return self.fund_class_hash.read(); } } -} \ No newline at end of file +} diff --git a/contracts/tests/test_fund.cairo b/contracts/tests/test_fund.cairo index 2b7c292..e8ff290 100644 --- a/contracts/tests/test_fund.cairo +++ b/contracts/tests/test_fund.cairo @@ -52,7 +52,7 @@ fn test_constructor() { let up_votes = dispatcher.getUpVotes(); let goal = dispatcher.getGoal(); let current_goal_state = dispatcher.getCurrentGoalState(); - let state = dispatcher.getIsActive(); + let state = dispatcher.getState(); assert(id == ID(), 'Invalid id'); assert(owner == OWNER(), 'Invalid owner'); assert(name == NAME(), 'Invalid name'); @@ -131,7 +131,7 @@ fn test_receive_donation_successful() { let contract_address = _setup_(); let dispatcher = IFundDispatcher { contract_address }; // Put state as recollecting dons - dispatcher.setIsActive(2); + dispatcher.setState(2); // Put 10 strks as goal, only owner start_cheat_caller_address_global(OWNER()); dispatcher.setGoal(10); @@ -141,7 +141,7 @@ fn test_receive_donation_successful() { assert(current_goal_state == 5, 'Receive donation not working'); // Donate 5 strks, the goal is done dispatcher.receiveDonation(5); - let state = dispatcher.getIsActive(); + let state = dispatcher.getState(); assert(state == 3, 'State should be close'); } @@ -151,7 +151,7 @@ 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); + dispatcher.setState(1); // Donate dispatcher.receiveDonation(5); } diff --git a/contracts/tests/test_fund_manager.cairo b/contracts/tests/test_fund_manager.cairo index 4bb4569..a9a862b 100755 --- a/contracts/tests/test_fund_manager.cairo +++ b/contracts/tests/test_fund_manager.cairo @@ -49,7 +49,7 @@ fn _setup_() -> (ContractAddress, ClassHash) { let mut fund_manager_calldata: Array = array![]; fund_manager_calldata.append_serde(fund_class_hash); let (contract_address, _) = fund_manager.deploy(@fund_manager_calldata).unwrap(); - + return (contract_address, fund_class_hash,); } @@ -69,15 +69,13 @@ fn test_constructor() { } #[test] -fn test_new_fund(){ +fn test_new_fund() { start_cheat_caller_address_global(OWNER()); let (contract_address, fund_class_hash) = _setup_(); let fund_manager_contract = IFundManagerDispatcher { contract_address }; fund_manager_contract.newFund(NAME(), GOAL()); - let expected_fund_class_hash = get_class_hash( - fund_manager_contract.getFund(1) - ); + let expected_fund_class_hash = get_class_hash(fund_manager_contract.getFund(1)); let current_id = fund_manager_contract.getCurrentId(); assert(expected_fund_class_hash == fund_class_hash, 'Invalid fund address'); - assert(current_id == 1, 'Invalid current ID'); -} \ No newline at end of file + assert(current_id == 2 , 'Invalid current ID'); +}