diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6453b02d6..8598ab4f3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,7 +30,7 @@ jobs: FOUNDRY_VERSION=$(grep 'snforge_std = ' Scarb.toml | sed 's/snforge_std = "\(.*\)"/\1/') echo "FOUNDRY_VERSION=$FOUNDRY_VERSION" >> "$GITHUB_ENV" - - uses: foundry-rs/setup-snfoundry@v4 + - uses: foundry-rs/setup-snfoundry@v5.0.0 with: starknet-foundry-version: ${{ env.FOUNDRY_VERSION }} @@ -48,7 +48,7 @@ jobs: run: scarb fmt --check --workspace - name: Run tests - run: snforge test --workspace --features fuzzing --fuzzer-runs 500 + run: snforge test --workspace --features fuzzing --fuzzer-runs 200 - name: Run tests and generate coverage report run: snforge test --workspace --coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c13f24f..9c5809914 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `MAXIMUM_DEFAULT_ADMIN_TRANSFER_DELAY` constant exposed in the component ImmutableConfig. - `maximum_default_admin_transfer_delay` getter to the `IAccessControlDefaultAdminRules` interface. +### Changed (Breaking) + +- `GovernorComponent` proposal state resolution at snapshot timepoint changed from Active to Pending (#1606) + ## 3.0.0-alpha.3 (2025-10-9) ### Added diff --git a/packages/governance/src/governor/governor.cairo b/packages/governance/src/governor/governor.cairo index 3fbbda05d..d167070be 100644 --- a/packages/governance/src/governor/governor.cairo +++ b/packages/governance/src/governor/governor.cairo @@ -894,13 +894,12 @@ pub mod GovernorComponent { assert(snapshot.is_non_zero(), Errors::NONEXISTENT_PROPOSAL); let current_timepoint = self.clock(); - if current_timepoint < snapshot { + if snapshot >= current_timepoint { return ProposalState::Pending; } let deadline = self._proposal_deadline(proposal_id); - - if current_timepoint <= deadline { + if deadline >= current_timepoint { return ProposalState::Active; } else if !self.quorum_reached(proposal_id) || !self.vote_succeeded(proposal_id) { return ProposalState::Defeated; diff --git a/packages/governance/src/tests/governor/block_number/test_governor.cairo b/packages/governance/src/tests/governor/block_number/test_governor.cairo index f26c7875c..d339b7e01 100644 --- a/packages/governance/src/tests/governor/block_number/test_governor.cairo +++ b/packages/governance/src/tests/governor/block_number/test_governor.cairo @@ -144,6 +144,19 @@ fn test_state_pending() { setup_pending_proposal(ref state, true); } +#[test] +fn test_state_pending_at_snapshot() { + let mut state = COMPONENT_STATE(); + deploy_votes_token(); + initialize_votes_component(VOTES_TOKEN); + let (id, proposal) = setup_pending_proposal(ref state, true); + + let snapshot = proposal.vote_start; + start_cheat_block_number_global(snapshot); + let current_state = get_state(@state, id, true); + assert_eq!(current_state, ProposalState::Pending); +} + fn test_state_active_external_version(external_state_version: bool) { let mut state = COMPONENT_STATE(); deploy_votes_token(); @@ -581,8 +594,8 @@ fn test_execute() { // 2. Cast vote - // Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_number_global(current_time); // Cast vote @@ -634,8 +647,8 @@ fn test_execute_panics() { // 2. Cast vote - // Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_number_global(current_time); // Cast vote @@ -1230,8 +1243,8 @@ fn prepare_governor_and_signature( start_cheat_block_number_global(current_time); let proposal_id = governor.propose(calls, description.clone()); - // 2. Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // 2. Fast forward the voting start + current_time = resolve_voting_start(current_time); start_cheat_block_number_global(current_time); // 3. Generate a key pair and set up an account @@ -1332,8 +1345,8 @@ fn prepare_governor_and_signature_with_reason_and_params( start_cheat_block_number_global(current_time); let proposal_id = governor.propose(calls, description.clone()); - // 2. Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // 2. Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_number_global(current_time); // 3. Generate a key pair and set up an account @@ -2034,7 +2047,7 @@ fn test__cast_vote_pending() { } #[test] -#[should_panic(expected: 'Votes: future Lookup')] +#[should_panic(expected: 'Unexpected proposal state')] fn test__cast_vote_at_vote_start() { let mut state = COMPONENT_STATE(); deploy_votes_token(); @@ -2094,7 +2107,7 @@ fn test__cast_vote_active_with_params() { } #[test] -#[should_panic(expected: 'Votes: future Lookup')] +#[should_panic(expected: 'Unexpected proposal state')] fn test__cast_vote_zero_delay() { start_cheat_block_number_global(BLOCK_NUMBER - 1); let voter = test_address(); @@ -2209,3 +2222,9 @@ fn delegate_votes_to(delegatee: ContractAddress) { let votes_dispatcher = IVotesDispatcher { contract_address: VOTES_TOKEN }; votes_dispatcher.delegate(delegatee); } + +fn resolve_voting_start(propose_timepoint: u64) -> u64 { + let voting_delay = GovernorMock::VOTING_DELAY; + let snapshot_timepoint = propose_timepoint + voting_delay; + snapshot_timepoint + 1 +} diff --git a/packages/governance/src/tests/governor/block_number/test_governor_core_execution.cairo b/packages/governance/src/tests/governor/block_number/test_governor_core_execution.cairo index c4df4cf90..adff683a3 100644 --- a/packages/governance/src/tests/governor/block_number/test_governor_core_execution.cairo +++ b/packages/governance/src/tests/governor/block_number/test_governor_core_execution.cairo @@ -62,6 +62,19 @@ fn test_state_pending() { assert_eq!(state, ProposalState::Pending); } +#[test] +fn test_state_pending_at_snapshot() { + let mut component_state = COMPONENT_STATE(); + deploy_votes_token(); + initialize_votes_component(VOTES_TOKEN); + let (id, proposal) = setup_pending_proposal(ref component_state, false); + + let snapshot = proposal.vote_start; + start_cheat_block_number_global(snapshot); + let state = GovernorExecution::state(@component_state, id); + assert_eq!(state, ProposalState::Pending); +} + #[test] fn test_state_active() { let mut component_state = COMPONENT_STATE(); diff --git a/packages/governance/src/tests/governor/timestamp/test_governor.cairo b/packages/governance/src/tests/governor/timestamp/test_governor.cairo index 75fcb60cd..114080764 100644 --- a/packages/governance/src/tests/governor/timestamp/test_governor.cairo +++ b/packages/governance/src/tests/governor/timestamp/test_governor.cairo @@ -144,6 +144,19 @@ fn test_state_pending() { setup_pending_proposal(ref state, true); } +#[test] +fn test_state_pending_at_snapshot() { + let mut state = COMPONENT_STATE(); + deploy_votes_token(); + initialize_votes_component(VOTES_TOKEN); + let (id, proposal) = setup_pending_proposal(ref state, true); + + let snapshot = proposal.vote_start; + start_cheat_block_timestamp_global(snapshot); + let current_state = get_state(@state, id, true); + assert_eq!(current_state, ProposalState::Pending); +} + fn test_state_active_external_version(external_state_version: bool) { let mut state = COMPONENT_STATE(); deploy_votes_token(); @@ -581,8 +594,8 @@ fn test_execute() { // 2. Cast vote - // Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // Cast vote @@ -634,8 +647,8 @@ fn test_execute_panics() { // 2. Cast vote - // Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // Cast vote @@ -934,7 +947,7 @@ fn test_cast_vote_pending() { } #[test] -#[should_panic(expected: 'Votes: future Lookup')] +#[should_panic(expected: 'Unexpected proposal state')] fn test__cast_vote_at_vote_start() { let mut state = COMPONENT_STATE(); deploy_votes_token(); @@ -968,7 +981,7 @@ fn test_cast_vote_active() { } #[test] -#[should_panic(expected: 'Votes: future Lookup')] +#[should_panic(expected: 'Unexpected proposal state')] fn test__cast_vote_zero_delay() { start_cheat_block_timestamp_global(TIMESTAMP - 1); let voter = test_address(); @@ -1286,8 +1299,8 @@ fn prepare_governor_and_signature( start_cheat_block_timestamp_global(current_time); let proposal_id = governor.propose(calls, description.clone()); - // 2. Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // 2. Fast forward the voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // 3. Generate a key pair and set up an account @@ -1388,8 +1401,8 @@ fn prepare_governor_and_signature_with_reason_and_params( start_cheat_block_timestamp_global(current_time); let proposal_id = governor.propose(calls, description.clone()); - // 2. Fast forward the vote delay - current_time += GovernorMock::VOTING_DELAY; + // 2. Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // 3. Generate a key pair and set up an account @@ -2209,3 +2222,9 @@ fn delegate_votes_to(delegatee: ContractAddress) { let votes_dispatcher = IVotesDispatcher { contract_address: VOTES_TOKEN }; votes_dispatcher.delegate(delegatee); } + +fn resolve_voting_start(propose_timepoint: u64) -> u64 { + let voting_delay = GovernorMock::VOTING_DELAY; + let snapshot_timepoint = propose_timepoint + voting_delay; + snapshot_timepoint + 1 +} diff --git a/packages/governance/src/tests/governor/timestamp/test_governor_core_execution.cairo b/packages/governance/src/tests/governor/timestamp/test_governor_core_execution.cairo index 0e02b3b74..013c872ce 100644 --- a/packages/governance/src/tests/governor/timestamp/test_governor_core_execution.cairo +++ b/packages/governance/src/tests/governor/timestamp/test_governor_core_execution.cairo @@ -62,6 +62,19 @@ fn test_state_pending() { assert_eq!(state, ProposalState::Pending); } +#[test] +fn test_state_pending_at_snapshot() { + let mut component_state = COMPONENT_STATE(); + deploy_votes_token(); + initialize_votes_component(VOTES_TOKEN); + let (id, proposal) = setup_pending_proposal(ref component_state, false); + + let snapshot = proposal.vote_start; + start_cheat_block_timestamp_global(snapshot); + let state = GovernorExecution::state(@component_state, id); + assert_eq!(state, ProposalState::Pending); +} + #[test] fn test_state_active() { let mut component_state = COMPONENT_STATE(); diff --git a/packages/governance/src/tests/governor/timestamp/test_governor_timelock_execution.cairo b/packages/governance/src/tests/governor/timestamp/test_governor_timelock_execution.cairo index 2da5cb596..5c14f7f82 100644 --- a/packages/governance/src/tests/governor/timestamp/test_governor_timelock_execution.cairo +++ b/packages/governance/src/tests/governor/timestamp/test_governor_timelock_execution.cairo @@ -381,8 +381,8 @@ fn test_execute_operations() { // 3. Cast vote - // Fast forward the vote delay - current_time += GovernorTimelockedMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // Cast vote @@ -458,8 +458,8 @@ fn test_queue_operations() { // 3. Cast vote - // Fast forward the vote delay - current_time += GovernorTimelockedMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // Cast vote @@ -535,8 +535,8 @@ fn test_cancel_operations_queued() { // 3. Cast vote - // Fast forward the vote delay - current_time += GovernorTimelockedMock::VOTING_DELAY; + // Fast forward to voting start + current_time = resolve_voting_start(current_time); start_cheat_block_timestamp_global(current_time); // Cast vote @@ -691,6 +691,12 @@ fn initialize_votes_component(votes_token: ContractAddress) { mock_state.governor_votes.initializer(votes_token); } +fn resolve_voting_start(propose_timepoint: u64) -> u64 { + let voting_delay = GovernorTimelockedMock::VOTING_DELAY; + let snapshot_timepoint = propose_timepoint + voting_delay; + snapshot_timepoint + 1 +} + // // Setup proposals //