fix: governance cancel_proposal veto, execute_proposal invocation, min_share_balance update, finalize proptest - #1286
Merged
Merged
Conversation
…n_share_balance update, finalize proptest - cancel_proposal (astera-hq#1118): once a proposal has passed quorum, only the admin may cancel it — the original proposer alone can no longer veto an approved proposal during the timelock window. Proposer cancellation is still allowed while Active. - execute_proposal (astera-hq#1119): removed dead TODO match arms that shadowed six real pool actions (fee tier, loyalty tiers, fallback price, rate bounds, exchange rate, collateral config), fixed drifted action field types, and passed action fields by reference to match the generated cross-contract client signatures. Also split GovernanceAction into per-target sub-enums (Pool/Invoice/OracleRegistry/Compliance) since the flat 54-variant enum exceeded soroban's 50-case union cap — the crate did not compile at all before this change. - min_share_balance (astera-hq#1121): added update_min_share_balance and update_min_share_balance_via_ac so the proposal-creation stake threshold can be changed after initialize. - finalize_proposal proptest (astera-hq#1122): added tests/finalize_proposal_proptest.rs covering the quorum/pass-threshold bps math end-to-end through the public API, in the style of share's existing fuzz tests. Also repairs the governance crate's test suite, which was stale against the current contract API and depended on independently broken sibling crates (pool, compliance); tests now use a small in-crate mock target contract instead. Collapses a duplicate ed25519-dalek resolution in Cargo.lock that otherwise broke `cargo test` for any crate using soroban-sdk testutils.
|
@Samuel1505 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…n_share_balance update, finalize proptest
Summary
Fixes four governance issues: #1118, #1119, #1121, #1122.
closes #1118
closes #1119
closes #1121
closes #1122
fix:
cancel_proposallets a single proposer veto an already-Passedproposal #1118 —cancel_proposallet a single proposer veto aPassedproposal.cancel_proposalnow only lets the original proposer cancel while aproposal is still
Active. Once a proposal has passed quorum, only theadmin may cancel it — a single voter can no longer unilaterally block an
approved change during the timelock window. Finalization is also applied
lazily before the authorization check, so a proposer can't dodge the new
rule by cancelling before anyone else has touched a proposal whose voting
period already ended (which would otherwise still read
Activeinstorage).
fix:
execute_proposalnever invokestarget_contract/function_name/calldata#1119 —execute_proposalnever invoked the target contract.execute_governance_action's dispatch match had six action variants(
SetPoolFeeTier,SetPoolLoyaltyTiers,SetPoolFallbackPrice,SetPoolRateBounds,SetPoolExchangeRate,SetPoolCollateralConfig)shadowed by earlier
TODO: Implement/return Ok(())arms for the samepatterns, so those actions silently no-opped instead of calling the target
contract. The crate also didn't compile:
GovernanceActionhad grown to54 variants against soroban's 50-case cap on a single
#[contracttype]union, two variant names exceeded the 32-character symbol limit, three
PoolAction-style fields had drifted from the real target signatures(
u32/i128mismatches, ani128standing in forCollateralConfig),and every cross-contract call in the dispatcher passed arguments by value
where the generated
#[contractclient]methods expect references.Fixed by: splitting
GovernanceActionintoPoolAction/InvoiceAction/
OracleRegistryAction/ComplianceActionsub-enums (each under the50-case cap) wrapped by a 4-variant
GovernanceAction; removing the deadTODO arms so the real implementations execute; correcting the drifted
field types; and passing every action field by reference to match the
generated client signatures.
execute_proposalnow performs a genuinecross-contract call for every action variant instead of only emitting an
event for an off-chain relayer.
feat: add a way to update
min_share_balanceafterinitialize#1121 — no way to updatemin_share_balanceafterinitialize.Added
update_min_share_balance(admin-gated) andupdate_min_share_balance_via_ac(multisig-gated, matching the existingupdate_config/update_config_via_acpattern), so the proposal-creationstake threshold can be raised or lowered post-deploy without redeploying
governance. Both reject non-positive values, preserving the fix:
create_proposalhas no proposal threshold or quorum-eligibility check #931 spamguard.
testing: no property-based tests for
finalize_proposal's quorum/pass-threshold math #1122 — no property-based coverage forfinalize_proposal's bps math.Added
tests/finalize_proposal_proptest.rs, in the style ofshare/tests/fuzz_tests.rs, covering the quorum/pass-threshold arithmeticend-to-end through the public contract API (
create_proposal→vote→execute_proposal) against an independent oracle of the same formula, plustwo targeted invariants: under-quorum proposals never execute, and adding
more YES votes never turns an
Executedoutcome intoRejected.Other changes bundled in
The governance crate did not compile on
main(54-variant union over the50-case cap, over-length symbols, drifted field types, missing
&on everycross-contract call argument — all pre-existing, unrelated to any single
issue above but blocking all of them) and its three test files were
completely stale against the current contract API (
initialize,create_proposal,vote, andexecute_proposalhad all changed shape).Both are fixed here since none of the four issues could otherwise be
verified. New tests use a small in-crate mock target contract
(
tests/common/mod.rs) instead of the real pool/invoice/oracle_registry/compliance contracts, because those are independently broken on
mainforunrelated reasons (missing storage keys, moved-value bugs, and — for
compliance's
*_via_governancemethods specifically — function names thatexceed Soroban's 32-character limit, meaning no valid contract can currently
implement them; this is a pre-existing defect worth a follow-up but is out
of scope here).
Cargo.lockchanges collapse a duplicateed25519-dalekresolution (2.2.0and 3.0.0 both present) down to a single version — the 3.0.0 edge doesn't
compile against the workspace's
rand/rand_chachaversions, whichpreviously made
cargo testfail to even build for any crate pulling insoroban-sdk'stestutils(confirmed this also blockedshare's existingtest suite, unrelated to governance).
Test plan
cargo build -p governancecargo test -p governance— 46 tests pass acrosslib,access_control_tests,governance_flow_tests, andfinalize_proposal_proptestcargo clippy -p governance --all-targets— no errors, onlypre-existing/cosmetic warnings