Skip to content

Conversation

Septimus4
Copy link
Contributor

@Septimus4 Septimus4 commented Sep 16, 2025

Strengthens the governance contract by addressing unsafe patterns, clarifying rules, and adding protective checks. It improves security, maintainability, and auditability.

I focused only on code inside contracts/tansu/src
For Point 7 specifically, my understanding:
Total votes used as denominator included abstentions. That means abstaining acted like a silent “no.”
Example: with 10 voters, 4 yes, 0 no, 6 abstain → 40% yes → proposal fails.

Doc description (before my update): majority was described as ratio of yes over (yes + no), meaning abstentions are ignored. Same case → 4 yes, 0 no → 100% yes → proposal passes.

The intent is stricter governance (requirement that a majority of all eligible voters must approve), then code was correct and docs needed updating. If the intent is looser governance (only count explicit yes/no votes), then docs were correct and code needed changing. @tupui, I went with the code a source of truth and updated the doc, I can do the other way around.

  1. Maintainer authorization on execute
    Added explicit checks so only designated maintainers can trigger contract upgrades.
    Why: Prevents unauthorized execution that could bypass governance decisions.

  2. Voting deadline enforcement
    Enforced timestamp comparison against env.ledger().timestamp().
    Why: Eliminates ambiguity about late votes and ensures proposals close predictably.

  3. Anonymous vote and seed validation
    Enforced strict equality between votes and seeds arrays, with explicit errors.
    Why: Protects against index errors, malformed submissions, and tally corruption.

  4. Removal of unsafe unwrap()
    Replaced all reachable unwrap() calls with guarded branches and error returns.
    Why: Prevents contract panics that could be exploited for denial of service.

  5. Logical operator corrections
    Replaced bitwise | and & with logical || and &&.
    Why: Ensures correct boolean evaluation and short-circuiting, reducing logic errors.

  6. Governance threshold validation
    Rejected thresholds of 0 or greater than the number of maintainers.
    Why: Prevents governance lockups or trivial approvals that undermine the system.

  7. Majority formula clarification
    Documented and aligned behavior on how abstentions affect vote outcomes.
    Why: Removes ambiguity between documentation and implementation, ensuring predictable governance.

  8. Timestamp boundary tests
    Added explicit test for voting at exactly the deadline tick.
    Why: Clarifies off-by-one edge cases and prevents disputes around deadline interpretation.

  9. Pattern simplification in vote()
    Rewrote nested if let constructs into clear conditionals.
    Why: Improves readability, reduces audit complexity, and ensures stability across Rust versions.

  10. BLS commitment verification
    Added tests with known vectors and documented cryptographic assumptions (curve, RNG, serialization).
    Why: Ensures anonymity mechanisms are verifiable and built on explicit, auditable assumptions.

  11. Pagination and gas limits
    Introduced hard caps on page sizes and added gas-scaling tests.
    Why: Protects against resource exhaustion and DoS vectors.

Copy link

netlify bot commented Sep 16, 2025

Deploy Preview for staging-tansu ready!

Name Link
🔨 Latest commit 3b5d05a
🔍 Latest deploy log https://app.netlify.com/projects/staging-tansu/deploys/68d927648b09ae00084371b4
😎 Deploy Preview https://deploy-preview-239--staging-tansu.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 69
Accessibility: 90
Best Practices: 83
SEO: 92
PWA: 70
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

netlify bot commented Sep 16, 2025

Deploy Preview for tansu ready!

Name Link
🔨 Latest commit 3b5d05a
🔍 Latest deploy log https://app.netlify.com/projects/tansu/deploys/68d92764d66498000760ce2a
😎 Deploy Preview https://deploy-preview-239--tansu.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@tupui
Copy link
Owner

tupui commented Sep 16, 2025

Hi @Septimus4 thanks for doing that!

Can you rebase on #240 or have a look at it? I added a bunch of things.

@Septimus4
Copy link
Contributor Author

@tupui, rebased and I added a commit to improve the pause logic:
enforce pause checks on all admin state changes (only execute upgrades when unpaused),
updated constructor to save one storage read/write op,
include wasm_hash in the collateral update event for parity

@tupui
Copy link
Owner

tupui commented Sep 18, 2025

Thanks 🙏 I am at Meridian now, I will do my best to review quickly!

@tupui tupui added rust Rust stuff onlydust-wave Contribute to awesome OSS repos during OnlyDust's open source week labels Sep 18, 2025
Copy link
Owner

@tupui tupui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for doing this. I have some minor things to address but otherwise that's great.

The intent is stricter governance (requirement that a majority of all eligible voters must approve), then code was correct and docs needed updating. If the intent is looser governance (only count explicit yes/no votes), then docs were correct and code needed changing. @tupui, I went with the code a source of truth and updated the doc, I can do the other way around.

Correct, the code is the source of truth and we want this supermajority 👍 Abstaining is a vote in itself and can be an outcome. We have accept/reject/abstain as possible outcomes.

  1. Maintainer authorization on execute
    Added explicit checks so only designated maintainers can trigger contract upgrades.
    Why: Prevents unauthorized execution that could bypass governance decisions.

This is not needed because we this way the DAO can be decentralised in its operation. This is also why I added a collateral system so that anyone can open a proposal. Such mode of operation is classic in other DAO. Anyone can trigger the execution after the tally phase is done. The caveat in our case is with anonymous voting. Only a maintainer can have the private key, hence only that maintainer will be able to execute the proposal. I think this is ok and we can add some wording in the UI for that.

  1. Voting deadline enforcement
    Enforced timestamp comparison against env.ledger().timestamp().
    Why: Eliminates ambiguity about late votes and ensures proposals close predictably.

Good catch! That was a real bug there.

  1. Anonymous vote and seed validation
    Enforced strict equality between votes and seeds arrays, with explicit errors.
    Why: Protects against index errors, malformed submissions, and tally corruption.

Good input validation 👍

  1. BLS commitment verification
    Added tests with known vectors and documented cryptographic assumptions (curve, RNG, serialization).
    Why: Ensures anonymity mechanisms are verifiable and built on explicit, auditable assumptions.

Not sure if really needed. We can assume the SDK is doing the right thing and only need to test our handling of it.

  1. Pagination and gas limits
    Introduced hard caps on page sizes and added gas-scaling tests.
    Why: Protects against resource exhaustion and DoS vectors.

Good catch, I had missed one place indeed 👍

Comment on lines 432 to 434
if voter_max_weight == 0 {
panic_with_error!(&env, &errors::ContractErrors::UnknownMember);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not sure about that. But I guess if you do not register, voting anyway does nothing because your vote basically count for nothing at all and yes we get some DoS then.

Comment on lines 470 to 494
maintainer.require_auth();
// Verify the maintainer is authorized for this project
crate::auth_maintainers(&env, &maintainer, &project_key);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cf comment. I would revert.

};

// Validate tallies and seeds have expected length (3: approve, reject, abstain)
if tallies_.len() != 3 || seeds_.len() != 3 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok but now we check these too many times. Here then in the proof etc. We just need to check once.

if !(tallies.is_some() && seeds.is_some()) {
panic_with_error!(&env, &errors::ContractErrors::TallySeedError);
}
let tallies_ = tallies.unwrap();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some unwrap_or_else or else would be more succinct no?

Comment on lines 779 to 830
voted_abstain: u128,
_voted_abstain: u128,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change? I would not do that.

Comment on lines 164 to 165
// Proposing an upgrade mutates state; require not paused.
Self::require_not_paused(env.clone());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even more important here. Admins would even pause the contract to do a migration to prevent anything bad from happening.

Comment on lines 216 to 217
// Approving an upgrade mutates state; require not paused.
Self::require_not_paused(env.clone());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same no

Comment on lines 278 to 279
// Executing an upgrade should respect pause state.
Self::require_not_paused(env.clone());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same no

To cast a vote on a proposal, users must:

- Be registered as a member using `add_member`
- Have one or more badges assigned for the project (see [Membership & Badges](./membership.mdx))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People can have no badges, they just get weight as 1. Maybe I should revisit the values. I will think about that for some follow ups.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These belong to the existing test files I think.

@tupui tupui moved this to Todo in SCF Journey - Tansu Sep 24, 2025
@tupui tupui moved this from Todo to In progress in SCF Journey - Tansu Sep 24, 2025
@tupui
Copy link
Owner

tupui commented Sep 24, 2025

FYI I am also going to push a small update to add a collateral on the votes themselves. All that should really prevent DoS issues.

@tupui
Copy link
Owner

tupui commented Sep 25, 2025

I have merged my changes on main for the collateral on votes.

@Septimus4
Copy link
Contributor Author

I have merged my changes on main for the collateral on votes.

Okay I will rebase and check

@Copilot Copilot AI review requested due to automatic review settings September 28, 2025 12:13
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR strengthens the Tansu smart contract governance system by addressing security vulnerabilities, improving error handling, and clarifying governance rules. It focuses on production readiness and auditability enhancements.

Key Changes:

  • Replaced unsafe unwrap() calls with proper error handling
  • Added strict validation for voting deadlines, thresholds, and anonymous voting parameters
  • Clarified supermajority governance model where abstentions count toward the denominator

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
website/docs/developers/governance.mdx Documents supermajority governance rules and voting requirements
contracts/tansu/src/tests/test_security.rs Adds comprehensive security tests for edge cases and malformed inputs
contracts/tansu/src/tests/mod.rs Includes new security test module
contracts/tansu/src/contract_tansu.rs Improves constructor safety, adds threshold validation, and strengthens upgrade controls
contracts/tansu/src/contract_membership.rs Simplifies nested pattern matching for better readability
contracts/tansu/src/contract_dao.rs Enhances vote validation, deadline enforcement, and removes unsafe operations

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@Septimus4
Copy link
Contributor Author

With all the rebase I had issues, I will open it updated and cleaned soon

@Septimus4 Septimus4 mentioned this pull request Sep 28, 2025
@tupui
Copy link
Owner

tupui commented Sep 28, 2025

Ok no worries 👍 thanks for following up.

My objective is to attempt mainnet this week. I sort of prepared the rest on Netlify, Cloudflare and the registrar. Only need to deploy the contract basically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
onlydust-wave Contribute to awesome OSS repos during OnlyDust's open source week rust Rust stuff
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants