Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add get_proposal_status #527

Merged
merged 6 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion starknet/src/execution_strategies/eth_relayer.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod EthRelayerExecutionStrategy {
use serde::Serde;
use starknet::{info, syscalls, EthAddress};
use sx::interfaces::IExecutionStrategy;
use sx::types::Proposal;
use sx::types::{Proposal, ProposalStatus};

#[storage]
struct Storage {}
Expand Down Expand Up @@ -53,5 +53,16 @@ mod EthRelayerExecutionStrategy {
fn get_strategy_type(self: @ContractState) -> felt252 {
'EthRelayer'
}

fn get_proposal_status(
self: @ContractState,
proposal: Proposal,
votes_for: u256,
votes_against: u256,
votes_abstain: u256,
) -> ProposalStatus {
panic_with_felt252('unimplemented');
ProposalStatus::Cancelled(())
}
}
}
230 changes: 229 additions & 1 deletion starknet/src/execution_strategies/simple_quorum.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mod SimpleQuorumExecutionStrategy {
proposal: @Proposal,
votes_for: u256,
votes_against: u256,
votes_abstain: u256
votes_abstain: u256,
) -> ProposalStatus {
let accepted = _quorum_reached(self._quorum.read(), votes_for, votes_against, votes_abstain)
& _supported(votes_for, votes_against);
Expand Down Expand Up @@ -67,3 +67,231 @@ mod SimpleQuorumExecutionStrategy {
votes_for > votes_against
}
}

#[cfg(test)]
mod tests {
use super::SimpleQuorumExecutionStrategy;
use super::SimpleQuorumExecutionStrategy::{get_proposal_status, initializer};
use sx::types::{Proposal, proposal::ProposalDefault, FinalizationStatus, ProposalStatus};

#[test]
#[available_gas(10000000)]
fn cancelled() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();

let mut proposal = ProposalDefault::default();
proposal.finalization_status = FinalizationStatus::Cancelled(());
let votes_for = 0;
let votes_against = 0;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Cancelled(()), 'failed cancelled');
}

#[test]
#[available_gas(10000000)]
fn executed() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();

let mut proposal = ProposalDefault::default();
proposal.finalization_status = FinalizationStatus::Executed(());
let votes_for = 0;
let votes_against = 0;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Executed(()), 'failed executed');
}

#[test]
#[available_gas(10000000)]
fn voting_delay() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();

let mut proposal = ProposalDefault::default();
proposal.start_timestamp = 42424242;
let votes_for = 0;
let votes_against = 0;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::VotingDelay(()), 'failed voting_delay');
}

#[test]
#[available_gas(10000000)]
fn voting_period() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();

let mut proposal = ProposalDefault::default();
proposal.min_end_timestamp = 42424242;
let votes_for = 0;
let votes_against = 0;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::VotingPeriod(()), 'failed min_end_timestamp');
}

#[test]
#[available_gas(10000000)]
fn shortcut_accepted() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 2;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
proposal.max_end_timestamp = 10;
let votes_for = quorum;
let votes_against = 0;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::VotingPeriodAccepted(()), 'failed shortcut_accepted');
}

#[test]
#[available_gas(10000000)]
fn shortcut_only_abstains() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 2;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
proposal.max_end_timestamp = 10;
let votes_for = 0;
let votes_against = 0;
let votes_abstain = quorum;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::VotingPeriod(()), 'failed shortcut_only_abstains');
}

#[test]
#[available_gas(10000000)]
fn shortcut_only_againsts() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 2;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
proposal.max_end_timestamp = 10;
let votes_for = 0;
let votes_against = quorum;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::VotingPeriod(()), 'failed shortcut_only_againsts');
}

#[test]
#[available_gas(10000000)]
fn shortcut_balanced() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 2;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
proposal.max_end_timestamp = 10;
let votes_for = quorum;
let votes_against = quorum;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::VotingPeriod(()), 'failed shortcut_balanced');
}

#[test]
#[available_gas(10000000)]
fn balanced() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 2;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
let votes_for = quorum;
let votes_against = quorum;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Rejected(()), 'failed balanced');
}

#[test]
#[available_gas(10000000)]
fn accepted() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 2;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
let votes_for = quorum;
let votes_against = quorum - 1;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Accepted(()), 'failed accepted');
}

#[test]
#[available_gas(10000000)]
fn accepted_with_abstains() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 5;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
let votes_for = 2;
let votes_against = 1;
let votes_abstain = 10;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Accepted(()), 'failed accepted abstains');
}

#[test]
#[available_gas(10000000)]
fn rejected_only_againsts() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 0;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
let votes_for = 0;
let votes_against = 1;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Rejected(()), 'failed rejected');
}

#[test]
#[available_gas(10000000)]
fn quorum_not_reached() {
let mut state = SimpleQuorumExecutionStrategy::unsafe_new_contract_state();
let quorum = 3;
initializer(ref state, quorum);

let mut proposal = ProposalDefault::default();
let votes_for = 2;
let votes_against = 0;
let votes_abstain = 0;
let result = get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
assert(result == ProposalStatus::Rejected(()), 'failed quorum_not_reached');
}
}
23 changes: 17 additions & 6 deletions starknet/src/execution_strategies/vanilla.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,8 @@ mod VanillaExecutionStrategy {
votes_abstain: u256,
payload: Array<felt252>
) {
let mut state: SimpleQuorumExecutionStrategy::ContractState =
SimpleQuorumExecutionStrategy::unsafe_new_contract_state();

let proposal_status = SimpleQuorumExecutionStrategy::get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
let proposal_status = self
.get_proposal_status(proposal, votes_for, votes_against, votes_abstain,);
assert(
(proposal_status == ProposalStatus::Accepted(()))
| (proposal_status == ProposalStatus::VotingPeriodAccepted(())),
Expand All @@ -43,6 +39,21 @@ mod VanillaExecutionStrategy {
self._num_executed.write(self._num_executed.read() + 1);
}

fn get_proposal_status(
self: @ContractState,
proposal: Proposal,
votes_for: u256,
votes_against: u256,
votes_abstain: u256,
) -> ProposalStatus {
let mut state: SimpleQuorumExecutionStrategy::ContractState =
SimpleQuorumExecutionStrategy::unsafe_new_contract_state();

SimpleQuorumExecutionStrategy::get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain,
)
}

fn get_strategy_type(self: @ContractState) -> felt252 {
'SimpleQuorumVanilla'
}
Expand Down
10 changes: 9 additions & 1 deletion starknet/src/interfaces/i_execution_strategy.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use sx::types::Proposal;
use sx::types::{Proposal, ProposalStatus};

#[starknet::interface]
trait IExecutionStrategy<TContractState> {
Expand All @@ -11,5 +11,13 @@ trait IExecutionStrategy<TContractState> {
payload: Array<felt252>
);

fn get_proposal_status(
self: @TContractState,
proposal: Proposal,
votes_for: u256,
votes_against: u256,
votes_abstain: u256,
) -> ProposalStatus;

fn get_strategy_type(self: @TContractState) -> felt252;
}
24 changes: 18 additions & 6 deletions starknet/src/space/space.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use starknet::{ClassHash, ContractAddress};
use sx::types::{UserAddress, Strategy, Proposal, IndexedStrategy, Choice, UpdateSettingsCalldata};
use sx::types::{
UserAddress, Strategy, Proposal, IndexedStrategy, Choice, UpdateSettingsCalldata, ProposalStatus
};

#[starknet::interface]
trait ISpace<TContractState> {
Expand All @@ -19,8 +21,7 @@ trait ISpace<TContractState> {
// #[view]
// fn vote_registry(proposal_id: u256, voter: ContractAddress) -> bool;
fn proposals(self: @TContractState, proposal_id: u256) -> Proposal;
// #[view]
// fn get_proposal_status(proposal_id: u256) -> u8;
fn get_proposal_status(self: @TContractState, proposal_id: u256) -> ProposalStatus;

// Owner Actions
fn update_settings(ref self: TContractState, input: UpdateSettingsCalldata);
Expand Down Expand Up @@ -85,8 +86,8 @@ mod Space {
},
types::{
UserAddress, Choice, FinalizationStatus, Strategy, IndexedStrategy, Proposal,
PackedProposal, IndexedStrategyTrait, IndexedStrategyImpl, UpdateSettingsCalldata,
NoUpdateTrait, NoUpdateString,
ProposalStatus, PackedProposal, IndexedStrategyTrait, IndexedStrategyImpl,
UpdateSettingsCalldata, NoUpdateTrait, NoUpdateString,
},
utils::{
reinitializable::{Reinitializable}, ReinitializableImpl, bits::BitSetter,
Expand All @@ -98,7 +99,6 @@ mod Space {
external::ownable::Ownable
};


#[storage]
struct Storage {
_min_voting_duration: u32,
Expand Down Expand Up @@ -582,6 +582,18 @@ mod Space {
self._proposals.read(proposal_id)
}

fn get_proposal_status(self: @ContractState, proposal_id: u256) -> ProposalStatus {
let proposal = self._proposals.read(proposal_id);
assert_proposal_exists(@proposal);

let votes_for = self._vote_power.read((proposal_id, Choice::For(())));
let votes_against = self._vote_power.read((proposal_id, Choice::Against(())));
let votes_abstain = self._vote_power.read((proposal_id, Choice::Abstain(())));

IExecutionStrategyDispatcher { contract_address: proposal.execution_strategy }
.get_proposal_status(proposal, votes_for, votes_against, votes_abstain)
}

fn update_settings(ref self: ContractState, input: UpdateSettingsCalldata) {
//TODO: temporary component syntax
let state = Ownable::unsafe_new_contract_state();
Expand Down
Loading
Loading