Skip to content

Commit

Permalink
more color in readme, another unit test, and another fix
Browse files Browse the repository at this point in the history
  • Loading branch information
moodysalem committed Mar 18, 2024
1 parent ee7720a commit 69723be
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 16 deletions.
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,33 @@ Contracts in this repository are designed so that they may be used together _or_
- Users call `Token#approve(staker, stake_amount)`, then `Staker#stake(delegate)` to stake and delegate their tokens to other addresses
- Users call `Staker#withdraw(delegate, recipient, amount)` to remove part or all of their delegation
- The average delegation weight is computable over *any* historical period
- The contract has no owner, and cannot be updated nor configured.
- The contract has no owner, and cannot be updated nor configured

#### Governor

`Governor` enables stakers to vote on whether to make a _single_ call.

- A user's voting weight for a period is determined by their average delegation according to the staker over the `voting_weight_smoothing_duration`
- A delegate may create a proposal to make a `call` if their voting weight exceeds the threshold
- After the `voting_start_delay`, users may choose to vote yea or nay on the proposal for the `voting_period`. A user's vote weight is computed based on the start time of the proposal.
- If a proposal receives at least quorum in voting weight, the simple majority of total votes is yea, and the voting period is over, the proposal may be executed exactly once
- If the call fails, the transaction will revert, and the call may be re-executed
- Proposals can be canceled at any time by anyone if the voting weight of the proposer falls below the configurable threshold
- A user's **voting weight** for a period is determined by their average total delegation over the period `voting_weight_smoothing_duration`
- A delegate may create a proposal to make a `call` if their voting weight exceeds the proposal creation threshold
- After the `voting_start_delay`, users may choose to vote `yea` or `nay` on the created proposal for the duration of the `voting_period`
- A voter's voting weight is computed based on their average delegation over the period `voting_weight_smoothing_duration` from before the start time of the proposal
- If a proposal receives at least `quorum` in voting weight, and the simple majority of total votes is yea, and the voting period is over, the proposal may be executed exactly once
- If the call fails, the transaction will revert, and anyone may attempt to execute the proposal again
- Proposals can be canceled at any time by _anyone_ iff the voting weight of the proposer falls below the proposal creation threshold
- The proposer may also cancel the proposal at any time before the end of the voting period
- A canceled proposal may not be re-proposed. The call may be slightly modified and re-proposed
- Proposers may only have one active proposal at any time
- The only thing stored regarding a proposal is the call that it makes, along with the metadata
- The single call can be to `Timelock#queue(calls)`, which may execute multiple calls
- The contract has no owner, and cannot be updated nor re-configured.
- The contract has no owner, and cannot be updated nor re-configured

#### Timelock

`Timelock` allows a list of calls to be executed after a configurable delay by its owner

- Anyone can execute the calls after a period of time, once queued by the owner
- The contract has an owner, and may be upgraded or configured via a call to self
- Designed to be the principal agent in representation of the DAO, i.e. hold all assets
- The contract has an owner, and may be upgraded or configured via a call to self.

#### Factory

Expand Down
16 changes: 9 additions & 7 deletions src/governor.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,14 @@ pub mod Governor {
if latest_proposal_id.is_non_zero() {
let latest_proposal_timestamps = self.get_proposal(latest_proposal_id).timestamps;

assert(
latest_proposal_timestamps.created
+ config.voting_start_delay
+ config.voting_period < timestamp_current,
'PROPOSER_HAS_ACTIVE_PROPOSAL'
);
if (latest_proposal_timestamps.canceled.is_zero()) {
assert(
latest_proposal_timestamps.created
+ config.voting_start_delay
+ config.voting_period <= timestamp_current,
'PROPOSER_HAS_ACTIVE_PROPOSAL'
);
}
}

assert(
Expand Down Expand Up @@ -208,7 +210,7 @@ pub mod Governor {

assert(proposal.proposer.is_non_zero(), 'DOES_NOT_EXIST');
assert(proposal.timestamps.canceled.is_zero(), 'PROPOSAL_CANCELED');

let config = self.config.read();
let timestamp_current = get_block_timestamp();
let voting_start_time = (proposal.timestamps.created + config.voting_start_delay);
Expand Down
14 changes: 14 additions & 0 deletions src/governor_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,20 @@ fn test_proposer_cannot_cancel_and_re_propose() {
governor.propose(transfer_call(token, recipient(), amount: 100));
}

#[test]
fn test_proposer_can_cancel_and_propose_different() {
let (staker, token, governor, config) = setup();

token.approve(staker.contract_address, config.proposal_creation_threshold.into());
staker.stake(proposer());
advance_time(config.voting_weight_smoothing_duration);

set_contract_address(proposer());
let id = governor.propose(transfer_call(token, recipient(), amount: 100));
governor.cancel(id);
governor.propose(transfer_call(token, recipient(), amount: 101));
}

#[test]
#[should_panic(expected: ('ALREADY_PROPOSED', 'ENTRYPOINT_FAILED'))]
fn test_propose_already_exists_should_fail() {
Expand Down

0 comments on commit 69723be

Please sign in to comment.