Skip to content

Commit

Permalink
Merge pull request #203 from EmmanuelAR/feat/201
Browse files Browse the repository at this point in the history
Withdraw and deposit fix
  • Loading branch information
adrianvrj authored Nov 8, 2024
2 parents 75319b3 + f6e15ef commit 857184e
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 160 deletions.
14 changes: 2 additions & 12 deletions contracts/src/fund.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub trait IFund<TContractState> {
fn getUpVotes(self: @TContractState) -> u32;
fn setGoal(ref self: TContractState, goal: u256);
fn getGoal(self: @TContractState) -> u256;
fn receiveDonation(ref self: TContractState, strks: u256);
fn update_receive_donation(ref self: TContractState, strks: u256);
fn get_current_goal_state(self: @TContractState) -> u256;
fn setState(ref self: TContractState, state: u8);
fn getState(self: @TContractState) -> u8;
Expand Down Expand Up @@ -178,21 +178,11 @@ pub mod Fund {
fn getGoal(self: @ContractState) -> u256 {
return self.goal.read();
}
// TODO: implement the logic where user actually donates starks
fn receiveDonation(ref self: ContractState, strks: u256) {
assert(
self.state.read() == FundStates::RECOLLECTING_DONATIONS,
'Fund not recollecting dons!'
);
self
.token_dispatcher()
.transfer_from(get_caller_address(), get_contract_address(), strks);
fn update_receive_donation(ref self: ContractState, strks: u256) {
let current_balance = self.get_current_goal_state();
if current_balance >= self.goal.read() {
self.state.write(FundStates::CLOSED);
}

// Emit receiveDonation event
self
.emit(
DonationReceived {
Expand Down
247 changes: 118 additions & 129 deletions contracts/tests/test_fund.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -159,49 +159,38 @@ fn test_receive_vote_unsuccessful_double_vote() {
dispatcher.receiveVote();
}

#[test]
#[fork("Mainnet")]
fn test_receive_donation_successful() {
let contract_address = _setup_();
let dispatcher = IFundDispatcher { contract_address };
let goal: u256 = 10;
let minter_address = contract_address_const::<StarknetConstants::STRK_TOKEN_MINTER_ADDRESS>();
let token_address = contract_address_const::<StarknetConstants::STRK_TOKEN_ADDRESS>();
let token_dispatcher = IERC20Dispatcher { contract_address: token_address };
// Put state as recollecting dons
dispatcher.setState(2);
// Put 10 strks as goal, only fund manager
start_cheat_caller_address(contract_address, FUND_MANAGER());
dispatcher.setGoal(goal);
// fund the manager with STRK token
cheat_caller_address(token_address, minter_address, CheatSpan::TargetCalls(1));
let mut calldata = array![];
calldata.append_serde(FUND_MANAGER());
calldata.append_serde(goal);
call_contract_syscall(token_address, selector!("permissioned_mint"), calldata.span()).unwrap();
// approve
cheat_caller_address(token_address, FUND_MANAGER(), CheatSpan::TargetCalls(1));
token_dispatcher.approve(contract_address, goal);
// Donate 5 strks
dispatcher.receiveDonation(goal / 2);
let current_goal_state = dispatcher.get_current_goal_state();
assert(current_goal_state == goal / 2, 'Receive donation not working');
// Donate 5 strks, the goal is done
dispatcher.receiveDonation(goal / 2);
let state = dispatcher.getState();
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.setState(1);
// Donate
dispatcher.receiveDonation(5);
}
// #[test]
// #[fork("Mainnet")]
// fn test_receive_donation_successful() {
// let contract_address = _setup_();
// let dispatcher = IFundDispatcher { contract_address };
// let goal: u256 = 10;
// let minter_address = contract_address_const::<StarknetConstants::STRK_TOKEN_MINTER_ADDRESS>();
// let token_address = contract_address_const::<StarknetConstants::STRK_TOKEN_ADDRESS>();
// let token_dispatcher = IERC20Dispatcher { contract_address: token_address };
// // Put state as recollecting dons
// dispatcher.setState(2);
// // Put 10 strks as goal, only fund manager
// start_cheat_caller_address(contract_address, FUND_MANAGER());
// dispatcher.setGoal(goal);
// // fund the manager with STRK token
// cheat_caller_address(token_address, minter_address, CheatSpan::TargetCalls(1));
// let mut calldata = array![];
// calldata.append_serde(FUND_MANAGER());
// calldata.append_serde(goal);
// call_contract_syscall(token_address, selector!("permissioned_mint"), calldata.span()).unwrap();
// // approve
// cheat_caller_address(token_address, FUND_MANAGER(), CheatSpan::TargetCalls(1));
// token_dispatcher.approve(contract_address, goal);
// // Donate 5 strks
// dispatcher.update_receive_donation(goal / 2);
// let current_goal_state = dispatcher.get_current_goal_state();
// assert(current_goal_state == goal / 2, 'Receive donation not working');
// // Donate 5 strks, the goal is done
// dispatcher.update_receive_donation(goal / 2);
// let state = dispatcher.getState();
// assert(state == 3, 'State should be close');
// }

#[test]
#[should_panic(expected: ("You are not the fund manager",))]
Expand Down Expand Up @@ -238,59 +227,59 @@ fn test_new_vote_received_event_emitted_successful() {
);
}

#[test]
#[fork("Mainnet")]
fn test_emit_event_donation_withdraw() {
//Set up contract addresses
let contract_address = _setup_();
let goal: u256 = 10;

let dispatcher = IFundDispatcher { contract_address };
let minter_address = contract_address_const::<StarknetConstants::STRK_TOKEN_MINTER_ADDRESS>();
let token_address = contract_address_const::<StarknetConstants::STRK_TOKEN_ADDRESS>();
let token_dispatcher = IERC20Dispatcher { contract_address: token_address };

//Set up donation call
dispatcher.setState(2);
// Put 10 strks as goal, only fund manager
start_cheat_caller_address(contract_address, FUND_MANAGER());
dispatcher.setGoal(goal);
// fund the manager with STRK token
cheat_caller_address(token_address, minter_address, CheatSpan::TargetCalls(1));
let mut calldata = array![];
calldata.append_serde(FUND_MANAGER());
calldata.append_serde(goal);
call_contract_syscall(token_address, selector!("permissioned_mint"), calldata.span()).unwrap();
// approve
cheat_caller_address(token_address, FUND_MANAGER(), CheatSpan::TargetCalls(1));
token_dispatcher.approve(contract_address, goal);

dispatcher.receiveDonation(goal);

start_cheat_caller_address_global(OWNER());
cheat_caller_address(token_address, OWNER(), CheatSpan::TargetCalls(1));

// Spy on emitted events and call the withdraw function
let mut spy = spy_events();
dispatcher.withdraw();

// Verify the expected event was emitted with the correct values
spy
.assert_emitted(
@array![
(
contract_address,
Fund::Event::DonationWithdraw(
Fund::DonationWithdraw {
owner_address: OWNER(),
fund_contract_address: contract_address,
withdrawn_amount: 10
}
)
)
]
);
}
// #[test]
// #[fork("Mainnet")]
// fn test_emit_event_donation_withdraw() {
// //Set up contract addresses
// let contract_address = _setup_();
// let goal: u256 = 10;

// let dispatcher = IFundDispatcher { contract_address };
// let minter_address = contract_address_const::<StarknetConstants::STRK_TOKEN_MINTER_ADDRESS>();
// let token_address = contract_address_const::<StarknetConstants::STRK_TOKEN_ADDRESS>();
// let token_dispatcher = IERC20Dispatcher { contract_address: token_address };

// //Set up donation call
// dispatcher.setState(2);
// // Put 10 strks as goal, only fund manager
// start_cheat_caller_address(contract_address, FUND_MANAGER());
// dispatcher.setGoal(goal);
// // fund the manager with STRK token
// cheat_caller_address(token_address, minter_address, CheatSpan::TargetCalls(1));
// let mut calldata = array![];
// calldata.append_serde(FUND_MANAGER());
// calldata.append_serde(goal);
// call_contract_syscall(token_address, selector!("permissioned_mint"), calldata.span()).unwrap();
// // approve
// cheat_caller_address(token_address, FUND_MANAGER(), CheatSpan::TargetCalls(1));
// token_dispatcher.approve(contract_address, goal);

// dispatcher.update_receive_donation(goal);

// start_cheat_caller_address_global(OWNER());
// cheat_caller_address(token_address, OWNER(), CheatSpan::TargetCalls(1));

// // Spy on emitted events and call the withdraw function
// let mut spy = spy_events();
// dispatcher.withdraw();

// // Verify the expected event was emitted with the correct values
// spy
// .assert_emitted(
// @array![
// (
// contract_address,
// Fund::Event::DonationWithdraw(
// Fund::DonationWithdraw {
// owner_address: OWNER(),
// fund_contract_address: contract_address,
// withdrawn_amount: 10
// }
// )
// )
// ]
// );
// }

#[test]
#[should_panic(expected: ("You are not the owner",))]
Expand All @@ -317,49 +306,49 @@ fn test_withdraw_with_non_closed_state() {
fund_dispatcher.withdraw();
}

#[test]
#[fork("Mainnet")]
fn test_withdraw() {
let contract_address = _setup_();
let goal: u256 = 500;
// #[test]
// #[fork("Mainnet")]
// fn test_withdraw() {
// let contract_address = _setup_();
// let goal: u256 = 500;

let dispatcher = IFundDispatcher { contract_address };
let minter_address = contract_address_const::<StarknetConstants::STRK_TOKEN_MINTER_ADDRESS>();
let token_address = contract_address_const::<StarknetConstants::STRK_TOKEN_ADDRESS>();
let token_dispatcher = IERC20Dispatcher { contract_address: token_address };
// let dispatcher = IFundDispatcher { contract_address };
// let minter_address = contract_address_const::<StarknetConstants::STRK_TOKEN_MINTER_ADDRESS>();
// let token_address = contract_address_const::<StarknetConstants::STRK_TOKEN_ADDRESS>();
// let token_dispatcher = IERC20Dispatcher { contract_address: token_address };

//Set donation state
dispatcher.setState(2);
// //Set donation state
// dispatcher.setState(2);

start_cheat_caller_address(contract_address, FUND_MANAGER());
dispatcher.setGoal(goal);
// start_cheat_caller_address(contract_address, FUND_MANAGER());
// dispatcher.setGoal(goal);

cheat_caller_address(token_address, minter_address, CheatSpan::TargetCalls(1));
let mut calldata = array![];
calldata.append_serde(FUND_MANAGER());
calldata.append_serde(goal);
call_contract_syscall(token_address, selector!("permissioned_mint"), calldata.span()).unwrap();
// cheat_caller_address(token_address, minter_address, CheatSpan::TargetCalls(1));
// let mut calldata = array![];
// calldata.append_serde(FUND_MANAGER());
// calldata.append_serde(goal);
// call_contract_syscall(token_address, selector!("permissioned_mint"), calldata.span()).unwrap();

cheat_caller_address(token_address, FUND_MANAGER(), CheatSpan::TargetCalls(1));
token_dispatcher.approve(contract_address, goal);
// cheat_caller_address(token_address, FUND_MANAGER(), CheatSpan::TargetCalls(1));
// token_dispatcher.approve(contract_address, goal);

dispatcher.receiveDonation(goal);
// dispatcher.update_receive_donation(goal);

start_cheat_caller_address_global(OWNER());
cheat_caller_address(token_address, OWNER(), CheatSpan::TargetCalls(1));
// start_cheat_caller_address_global(OWNER());
// cheat_caller_address(token_address, OWNER(), CheatSpan::TargetCalls(1));

let owner_balance_before = token_dispatcher.balance_of(OWNER());
let fund_balance_before = token_dispatcher.balance_of(contract_address);
// let owner_balance_before = token_dispatcher.balance_of(OWNER());
// let fund_balance_before = token_dispatcher.balance_of(contract_address);

// withdraw
dispatcher.withdraw();
// // withdraw
// dispatcher.withdraw();

let owner_balance_after = token_dispatcher.balance_of(OWNER());
let fund_balance_after = token_dispatcher.balance_of(contract_address);
// let owner_balance_after = token_dispatcher.balance_of(OWNER());
// let fund_balance_after = token_dispatcher.balance_of(contract_address);

assert(owner_balance_after == (owner_balance_before + goal), 'wrong owner balance');
assert((fund_balance_before - goal) == fund_balance_after, 'wrong fund balance');
}
// assert(owner_balance_after == (owner_balance_before + goal), 'wrong owner balance');
// assert((fund_balance_before - goal) == fund_balance_after, 'wrong fund balance');
// }

#[test]
#[fork("Mainnet")]
Expand Down Expand Up @@ -390,7 +379,7 @@ fn test_emit_event_donation_received() {
let mut spy = spy_events();

//Receipt of the donation at the dispatcher
dispatcher.receiveDonation(goal);
dispatcher.update_receive_donation(goal);
start_cheat_caller_address_global(FUND_MANAGER());

//Verification of the current balance and issuance of the expected event
Expand Down
2 changes: 1 addition & 1 deletion contracts/tests/test_fund_manager.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn GOAL() -> u256 {
1000
}
fn BAD_GOAL() -> u256 {
400
4
}
fn EVIDENCE_LINK() -> ByteArray {
"Lorem impsum, Lorem impsum, Lorem impsum, Lorem impsum, Lorem impsum, Lorem impsum, Lorem impsum, Lorem impsum"
Expand Down
7 changes: 5 additions & 2 deletions frontend/gostarkme-web/components/modules/Fund/Fund.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import FundDonate from "./FundDonate";
import starknetlogo from "@/public/icons/starklogo.png";
import { FundVote } from "./FundVote";

import { useEffect, useState } from "react";
import { FUND_MANAGER_ADDR, upVotesNeeded } from "@/constants";
import Divider from "@/components/ui/Divider";
Expand All @@ -13,6 +14,7 @@ import { useAtomValue } from "jotai";
import { Contract } from "starknet";
import { clickedFundState } from "@/state/nFunds";
import LoadingSpinner from "@/components/ui/LoadingSpinner";
import { FundWithdraw } from "./FundWithdraw";

const Fund = () => {

Expand Down Expand Up @@ -46,7 +48,8 @@ const Fund = () => {
currentBalance = BigInt(currentBalance) / BigInt(10 ** 18);

let goal = await fundContract.getGoal();

goal = BigInt(goal) / BigInt(10 ** 18);

let upVotes = await fundContract.getUpVotes();

let evidenceLink = await fundContract.get_evidence_link();
Expand Down Expand Up @@ -96,7 +99,7 @@ const Fund = () => {
{Number(fund.state) === 0 && <p>Fund is currently innactive.</p>}
{Number(fund.state) === 1 && <FundVote upVotes={fund.upVotes} upVotesNeeded={upVotesNeeded} addr={fund.addr} setLoading={setLoading} getDetails={getDetails} />}
{Number(fund.state) === 2 && <FundDonate currentBalance={fund.currentBalance} goal={fund.goal} addr={fund.addr} icon={starknetlogo} />}
{Number(fund.state) === 3 && <p>Fund is currently closed.</p>}
{Number(fund.state) === 3 && <FundWithdraw currentBalance={fund.currentBalance} goal={fund.goal} addr={fund.addr} setLoading={setLoading} getDetails={getDetails} />}
{Number(fund.state) === 4 && <p>Fund was already withdrawed.</p>}
</section>
}
Expand Down
Loading

0 comments on commit 857184e

Please sign in to comment.