feat: per-project governance overrides (min_voting_period, execute_delay)#155
Open
willemneal wants to merge 9 commits into
Open
feat: per-project governance overrides (min_voting_period, execute_delay)#155willemneal wants to merge 9 commits into
willemneal wants to merge 9 commits into
Conversation
👷 Deploy request for tansu pending review.Visit the deploys page to approve it
|
👷 Deploy request for staging-tansu pending review.Visit the deploys page to approve it
|
3d28f28 to
53aa944
Compare
tupui
reviewed
May 28, 2026
tupui
reviewed
May 28, 2026
| execute_delay: Option<u64>, | ||
| ) -> Bytes; | ||
|
|
||
| fn get_min_voting_period(env: Env, project_key: Bytes) -> u64; |
Member
There was a problem hiding this comment.
Do we really need these 2 in the public API? I don't have much simple accessor otherwise as you can see elsewhere. I tend to just inline storage calls.
| VoterWeight = 209, | ||
| VoteLimitExceeded = 210, | ||
| VoterConflicted = 211, | ||
| InvalidVotingPeriod = 212, |
Member
There was a problem hiding this comment.
There is a mapping file to update. I know that thing is not ideal. (The linter failure)
573bf75 to
17a2b91
Compare
This was referenced Jun 3, 2026
Member
|
@willemneal Ping in case you missed my review. Otherwise LGTM |
…ename Regenerated via `stellar contract bindings typescript`. Function bodies are unchanged at runtime — only the symbol name shifts from `Contract` to `ContractRef` for the typed-address-plus-wasm-hash wrapper used by `set_*_contract`. Formatting reflects current stellar-cli 26.0.0 output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Run prettier --write on dapp/packages/tansu sources/dist generated by stellar-cli's TS binding emitter, which doesn't match the project's prettier config out of the box. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`register()` accepts an optional `min_voting_period: Option<u64>` (seconds). When `Some(v)`, `v` must be in `1..=MAX_VOTING_PERIOD`; otherwise the global 24h default applies. The override is stored under a new `ProjectKey::MinVotingPeriod(project_key)` storage entry so existing projects' `Project` schema is unchanged. `create_proposal` now reads the per-project override (falling back to the default) when validating `voting_ends_at`. Added read accessor `get_min_voting_period(project_key) -> u64` returning the effective value. New `ContractErrors::InvalidVotingPeriod` (212) is raised at registration for out-of-range overrides. Includes: - Unit tests for default lookup, override storage, zero / above-max rejection. - End-to-end test: a 7-day project rejects a 2-day proposal and accepts an 8-day one. - Regenerated TypeScript bindings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-run prettier on dapp/packages/tansu after regenerating bindings against the new wasm spec (now includes `min_voting_period` / `get_min_voting_period`). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a second `execute_delay: Option<u64>` parameter to `register`, mirroring `min_voting_period`. When `Some(v)`, `v` must be in `1..=MAX_VOTING_PERIOD` (reuses `InvalidVotingPeriod`); stored under `ProjectKey::ExecuteDelay(project_key)`. `execute()` reads the per-project value, falling back to `types::TIMELOCK_DELAY`. The admin upgrade timelock in `propose_upgrade` is intentionally unchanged — different threat model. `get_execute_delay(project_key) -> u64` exposes the effective value. Together with `min_voting_period`, this lets a fast-flow testnet project drive a proposal end-to-end in <2 minutes instead of the ~25-hour mainnet floor. New tests: - `execute_delay_defaults_when_unset` / `_override_is_stored_and_read` / `_rejects_zero` in test_register.rs. - `execute_delay_override_applies_to_execute` in test_dao.rs: a 60-second override lets `execute()` succeed at voting_ends_at + 60s and panic at voting_ends_at + 59s — proving the 24-hour TIMELOCK_DELAY no longer gates the path. Regenerated TypeScript bindings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Accidentally included in the previous commit; this contract ID belongs in my fork's local state, not in the upstream PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ctFlow Rebasing onto upstream/main (which removed SorobanDomain via Consulting-Manao#157 and replaced it with a collateral deposit) makes the previously generated bindings stale. Regenerate them from the rebased contract: * drops the SorobanDomain client methods / error variants * keeps the collateral-based register() and the new governance params * adds InvalidVotingPeriod (212), now mapped in contractErrorMessages.ts `register()` gained `min_voting_period` / `execute_delay`, so thread them (optional) through `createProjectFlow` in FlowService.ts; otherwise the dapp no longer type-checks against the regenerated bindings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
17a2b91 to
05e12bf
Compare
This was referenced Jun 8, 2026
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 8, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fc1944d to
05e12bf
Compare
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
willemneal
added a commit
to willemneal/tansu
that referenced
this pull request
Jun 10, 2026
…ay accessors Per review on Consulting-Manao#155: the codebase inlines storage reads rather than exposing simple accessors. The DAO already reads the per-project overrides directly from storage (contract_dao.rs), and the dapp never queried these methods, so nothing relied on them. Remove them from VersioningTrait; the affected tests now read the stored value straight from storage via `as_contract`. Regenerate the bindings to drop the two methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tupui
approved these changes
Jun 30, 2026
tupui
left a comment
Member
There was a problem hiding this comment.
@willemneal what is the status here? Now it looks good to me and happy to get in. Just noting that the update config function does not let people adjust the timings. Which can be ok.
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.
Summary
Adds two optional per-project governance overrides at registration:
min_voting_period: Option<u64>— minimum seconds between proposal creation andvoting_ends_at. Defaults to the globalMIN_VOTING_PERIOD(24h).execute_delay: Option<u64>— seconds betweenvoting_ends_atand whenexecute()becomes callable. Defaults to the globalTIMELOCK_DELAY(24h).Together these let a project drive a proposal end-to-end in seconds instead of the ~25-hour mainnet floor. Use cases: testnet flows, internal-tool DAOs, fast-iteration governance experiments.
Stacked on #154 — diff shows the contract-rename commits from that PR too; once #154 merges, the diff here will narrow.
API changes
Some(v)in1..=MAX_VOTING_PERIOD(30 days). Out-of-range panics with newContractErrors::InvalidVotingPeriod = 212.Storage
Two new persistent
ProjectKeyentries:ProjectKey::MinVotingPeriod(Bytes) -> u64ProjectKey::ExecuteDelay(Bytes) -> u64Where the overrides take effect
create_proposalreadsMinVotingPeriod, falling back toMIN_VOTING_PERIOD, when computing the lower bound forvoting_ends_at.executereadsExecuteDelay, falling back totypes::TIMELOCK_DELAY, when gating proposal execution.propose_upgrade(contract_tansu.rs:199) still uses the hardcodedTIMELOCK_DELAY. Different threat model — admin compromise window — and not something a project's maintainers should be able to shorten.Test plan
cargo test --manifest-path contracts/tansu/Cargo.toml --release— 63 pass (54 existing + 9 new)min_voting_period_defaults_when_unsetmin_voting_period_override_is_stored_and_readmin_voting_period_rejects_zeromin_voting_period_rejects_above_maxmin_voting_period_override_applies_to_create_proposal(7-day project rejects 2-day proposal, accepts 8-day)execute_delay_defaults_when_unsetexecute_delay_override_is_stored_and_readexecute_delay_rejects_zeroexecute_delay_override_applies_to_execute(60-second override:execute()panics atvoting_ends_at + 59s, succeeds atvoting_ends_at + 60s— proving the 24-hourTIMELOCK_DELAYno longer gates the path)cargo clippy --all-targets --all-features -- -Dwarningscargo fmt --checkcargo build --target wasm32v1-none --releasestellar contract bindings typescript).get_execute_delayreturns 86400 on a fresh project (default ✓).Out of scope
update_config).🤖 Generated with Claude Code