Skip to content

Commit

Permalink
add some unit tests and improve the code for the versioned configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
moodysalem committed May 13, 2024
1 parent 5e9bd4e commit 9de6d66
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 6 deletions.
17 changes: 11 additions & 6 deletions src/governor.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ pub trait IGovernor<TContractState> {
// Get the latest configuration for this governor contract.
fn get_config(self: @TContractState) -> Config;

// Get the latest configuration for this governor contract and its config version ID
fn get_config_with_version(self: @TContractState) -> (Config, u64);

// Get the configuration with the given version ID.
fn get_config_version(self: @TContractState, version: u64) -> Config;

Expand Down Expand Up @@ -213,7 +216,7 @@ pub mod Governor {
let id = get_proposal_id(get_contract_address(), nonce);

let proposer = get_caller_address();
let config = self.get_config();
let (config, config_version) = self.get_config_with_version();
let timestamp_current = get_block_timestamp();

let latest_proposal_id = self.latest_proposal_by_proposer.read(proposer);
Expand Down Expand Up @@ -241,7 +244,6 @@ pub mod Governor {
'THRESHOLD'
);

let config_version = self.latest_config_version.read();
self
.proposals
.write(
Expand Down Expand Up @@ -319,14 +321,13 @@ pub mod Governor {
}

fn cancel(ref self: ContractState, id: felt252) {
let mut proposal = self.proposals.read(id);
let (mut proposal, config) = self.get_proposal_with_config(id);

assert(proposal.proposer.is_non_zero(), 'DOES_NOT_EXIST');
assert(proposal.proposer == get_caller_address(), 'PROPOSER_ONLY');
assert(proposal.execution_state.canceled.is_zero(), 'ALREADY_CANCELED');

// This is prevented so that proposers cannot grief voters by creating proposals that they plan to cancel after the result is known
let config = self.config.read();
assert(
get_block_timestamp() < (proposal.execution_state.created
+ config.voting_start_delay),
Expand Down Expand Up @@ -398,8 +399,7 @@ pub mod Governor {
) -> Span<Span<felt252>> {
let calls_hash = hash_calls(@calls);

let config = self.config.read();
let mut proposal = self.proposals.read(id);
let (mut proposal, config) = self.get_proposal_with_config(id);

assert(proposal.calls_hash == calls_hash, 'CALLS_HASH_MISMATCH');
assert(proposal.proposer.is_non_zero(), 'DOES_NOT_EXIST');
Expand Down Expand Up @@ -452,6 +452,11 @@ pub mod Governor {
self.get_config_version(self.latest_config_version.read())
}

fn get_config_with_version(self: @ContractState) -> (Config, u64) {
let config_version = self.latest_config_version.read();
(self.get_config_version(config_version), config_version)
}

fn get_config_version(self: @ContractState, version: u64) -> Config {
if version.is_zero() {
self.config.read()
Expand Down
126 changes: 126 additions & 0 deletions src/governor_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -1006,3 +1006,129 @@ fn test_execute_invalid_call_id() {
id, array![transfer_call(token: token, recipient: recipient(), amount: 101)].span()
);
}

#[test]
#[should_panic(expected: ('SELF_CALL_ONLY', 'ENTRYPOINT_FAILED'))]
fn test_upgrade_fails_if_not_self_call() {
let (_staker, _token, governor, _config) = setup();
governor.upgrade(Governor::TEST_CLASS_HASH.try_into().unwrap());
}

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

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

let id = create_proposal_with_call(
governor,
token,
staker,
Call {
to: governor.contract_address,
selector: selector!("upgrade"),
calldata: array![Governor::TEST_CLASS_HASH].span()
}
);

advance_time(config.voting_start_delay);

set_contract_address(proposer());
governor.vote(id, true);

advance_time(config.voting_period + config.execution_delay);

governor
.execute(
id,
array![
Call {
to: governor.contract_address,
selector: selector!("upgrade"),
calldata: array![Governor::TEST_CLASS_HASH].span()
}
]
.span()
);
}

#[test]
#[should_panic(expected: ('SELF_CALL_ONLY', 'ENTRYPOINT_FAILED'))]
fn test_reconfigure_fails_if_not_self_call() {
let (_staker, _token, governor, _config) = setup();
governor
.reconfigure(
Config {
voting_start_delay: 1,
voting_period: 2,
voting_weight_smoothing_duration: 3,
quorum: 4,
proposal_creation_threshold: 5,
execution_delay: 6,
execution_window: 7
}
);
}


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

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

let mut args: Array<felt252> = array![];
let new_config = Config {
voting_start_delay: 1,
voting_period: 2,
voting_weight_smoothing_duration: 3,
quorum: 4,
proposal_creation_threshold: 5,
execution_delay: 6,
execution_window: 7
};
Serde::serialize(@new_config, ref args);

let id = create_proposal_with_call(
governor,
token,
staker,
Call {
to: governor.contract_address, selector: selector!("reconfigure"), calldata: args.span()
}
);

advance_time(config.voting_start_delay);

set_contract_address(proposer());
governor.vote(id, true);

advance_time(config.voting_period + config.execution_delay);

governor
.execute(
id,
array![
Call {
to: governor.contract_address,
selector: selector!("reconfigure"),
calldata: args.span()
}
]
.span()
);

pop_log::<Governor::Proposed>(governor.contract_address).unwrap();
pop_log::<Governor::Voted>(governor.contract_address).unwrap();
let reconfigured = pop_log::<Governor::Reconfigured>(governor.contract_address).unwrap();
assert_eq!(reconfigured.new_config, new_config);
assert_eq!(reconfigured.version, 1);
let executed = pop_log::<Governor::Executed>(governor.contract_address).unwrap();
assert_eq!(governor.get_config_with_version(), (new_config, 1));
assert_eq!(executed.id, id);
assert_eq!(executed.result_data, array![array![1_felt252].span()].span());
}

0 comments on commit 9de6d66

Please sign in to comment.