Description
contracts/governance/src/settlement.rs implements the cross-contract two-phase prepare_settlement → commit_settlement (with abort_settlement fallback) protocol that execute_proposal relies on for treasury disbursements, but a full-text search confirms zero references to disbursement, settlement, or token_factory anywhere in contracts/governance/src/governance_test.rs, governance_property_test.rs, or governance_bounds_test.rs. Neither the happy path (successful commit) nor the abort path (commit fails, abort_settlement is invoked and FinalizationError::DisbursementFailed is returned) has any unit test coverage, despite this being one of the contract's most structurally complex code paths.
Requirements and Context
- Must not modify
settlement::execute_disbursement's cross-contract call sequence (prepare_settlement → commit_settlement → conditional abort_settlement); this is test-only work.
- Since
settlement.rs's own module doc explains governance and token-factory pin different soroban-sdk major versions and therefore cannot share a generated client, the test double must be a minimal in-crate mock contract registered via env.register_contract, not a real token-factory dependency.
- New tests must be deterministic and not depend on any external
.wasm artifact (unlike the fuzz target in token-factory/fuzz, which does depend on a pre-built governance.wasm).
Suggested Execution
Branch: test/governance-settlement-coverage
Implement Changes
- Add a small mock contract (in a new
contracts/governance/src/settlement_test.rs, gated #[cfg(test)]) exposing prepare_settlement, commit_settlement, and abort_settlement entry points with controllable success/failure behavior, matching the symbol names settlement.rs invokes via Env::invoke_contract/try_invoke_contract.
- Register the mock via
env.register_contract in place of a real token-factory address, call set_token_factory with its ID, create and pass a proposal carrying a Disbursement, then call execute_proposal and assert ProposalStatus::Executed is set only after a successful mocked commit.
- Add a second test where the mock's
commit_settlement is configured to fail, and assert execute_proposal returns FinalizationError::DisbursementFailed, the mock's abort_settlement was invoked, and the proposal's status remains Passed (not Executed).
- Declare the new module with
#[cfg(test)] mod settlement_test; in contracts/governance/src/lib.rs.
Test and Commit
Run cargo test --lib (and cargo test for proptest/fuzz targets where relevant) in the appropriate contracts/<governance|token-factory> directory, confirming the new coverage passes and cargo build --target wasm32v1-none --release --lib still succeeds.
Example Commit Message
test(contract): cover settlement's prepare/commit/abort protocol with a mock token-factory
Closes #<issue>
Guidelines
- Branch from
main, open a PR back to main
- All new code must have corresponding tests
- Run
cargo fmt --check, cargo clippy, and cargo test --lib before pushing
- Follow existing naming conventions and file structure
- PR description must reference this issue number (e.g.,
Closes #<issue>)
- Keep commits atomic and use conventional commit format
Description
contracts/governance/src/settlement.rsimplements the cross-contract two-phaseprepare_settlement→commit_settlement(withabort_settlementfallback) protocol thatexecute_proposalrelies on for treasury disbursements, but a full-text search confirms zero references todisbursement,settlement, ortoken_factoryanywhere incontracts/governance/src/governance_test.rs,governance_property_test.rs, orgovernance_bounds_test.rs. Neither the happy path (successful commit) nor the abort path (commit fails,abort_settlementis invoked andFinalizationError::DisbursementFailedis returned) has any unit test coverage, despite this being one of the contract's most structurally complex code paths.Requirements and Context
settlement::execute_disbursement's cross-contract call sequence (prepare_settlement→commit_settlement→ conditionalabort_settlement); this is test-only work.settlement.rs's own module doc explains governance and token-factory pin different soroban-sdk major versions and therefore cannot share a generated client, the test double must be a minimal in-crate mock contract registered viaenv.register_contract, not a realtoken-factorydependency..wasmartifact (unlike the fuzz target intoken-factory/fuzz, which does depend on a pre-builtgovernance.wasm).Suggested Execution
Branch:
test/governance-settlement-coverageImplement Changes
contracts/governance/src/settlement_test.rs, gated#[cfg(test)]) exposingprepare_settlement,commit_settlement, andabort_settlemententry points with controllable success/failure behavior, matching the symbol namessettlement.rsinvokes viaEnv::invoke_contract/try_invoke_contract.env.register_contractin place of a real token-factory address, callset_token_factorywith its ID, create and pass a proposal carrying aDisbursement, then callexecute_proposaland assertProposalStatus::Executedis set only after a successful mocked commit.commit_settlementis configured to fail, and assertexecute_proposalreturnsFinalizationError::DisbursementFailed, the mock'sabort_settlementwas invoked, and the proposal's status remainsPassed(notExecuted).#[cfg(test)] mod settlement_test;incontracts/governance/src/lib.rs.Test and Commit
Run
cargo test --lib(andcargo testfor proptest/fuzz targets where relevant) in the appropriatecontracts/<governance|token-factory>directory, confirming the new coverage passes andcargo build --target wasm32v1-none --release --libstill succeeds.Example Commit Message
Guidelines
main, open a PR back tomaincargo fmt --check,cargo clippy, andcargo test --libbefore pushingCloses #<issue>)