You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A data contract can declare that its moderation team is chosen by masternodes and evonodes instead of by the contract owner. Teams apply by publishing a charter, masternodes elect one, and the seated team moderates the contract's content under the limits of its charter, paid from the contract's moderators fee pot. A seated team can only be replaced by a challenge vote.
All design questions are answered (rounds 1 to 8, 2026-09-19 to 2026-09-21; the round comments below hold the history). This body is the consolidated design. Nothing is built. Target: protocol version 14 on v4.2-dev, version tables edited in place.
Document action fees (fixed credits per action, immutable) into an owner pot and a moderators pot, ContractFeeClaim (type 25), equal split between team(), once per pot per epoch, last claim record, getContractFeePots
D8. Election parameters are frozen once set. Seconds as u32, bounds in SystemLimits: join window and vote window 1 day to 4 weeks, default 1 week each; challenge cool-down x 2 weeks to 3 years.
D25. The contract declares which document types it moderates (the moderated set). The charter never chooses types; it says how they are moderated.
D47. The moderated set may include types not flagged canBeDeletedByModerators. Deletes reach only the flagged types, within each type's window. Bans and suspensions are not limited by the flag.
D62, D64; D63 dropped (2026-09-22, round 9). The contract declares, per moderated document type, the abilities a charter may claim on it (non-empty). There are no charter fee maximums: a type's own actionFees.moderators amount is the most a team may charge on its actions, and a charter charges a share of it, so the signer's fee agreement to the declared amounts never mismatches a seated charter. Owner pot amounts stay contract-fixed and immutable.
D6, D17, D18. Interim mode until the first team is seated: the owner moderates, an appointed set moderates (the merged kinds, no power group), or the moderated types are not yet usable. "Not yet usable" blocks only the moderated types; if no team ever comes those types are dead forever. Accepted. A fourth interim, noModeration (2026-09-22, round 9): nobody moderates and nobody claims the pot until a team is seated, but the moderated types stay usable meanwhile.
D19, D26. Interim bans, suspensions and removals survive the first seating. Interim moderators may claim the pot until seating; at the first seating the pot is not settled, it carries over to the elected team.
D20, D27. The contract says whether the owner is protected from moderation in elected mode, default not protected. The leader and the current members are always protected (41102).
2. Charter and team
D15, D57, D59, D60. Charters are documents of a new system data contract. An application is a charter document create on a contested unique index keyed by the target contract id, reusing the DPNS contest machinery with the windows and the fee read from the target contract. The seated team (leader, members with powers, active charter id) lives under the moderated contract for a cheap read; the system contract holds only charters. Charter documents are immutable; an amendment is a new charter document plus a vote that swaps the active charter id.
D1 (amended), D58. Consensus enforces abilities, per-ability powers, the fee amounts and the split from the charter, and the document types from the contract. The "what we moderate" text is informational, capped at 4096 bytes.
D50. The charter lists its reason codes (1 = hate speech, 2 = doxing, ...). Every moderation action's code must be one the seated charter lists.
D2, D9, D28, D29, D30, D31. A team is a group with power. The applicant pays, is the contender, and becomes the leader. The initial member list with powers is part of the application and is seated as-is. The leader is a member with a power of their own, assigns powers freely, cap 16. The charter sets a required power per ability. A membership change that leaves any ability unreachable is refused.
D10, D11, D33. One team per contract. The leader cannot change. A challenge is the only remedy for a lost-keys or rogue leader.
D4. No terms, no resignation.
3. Abilities
D48. Silence is the merged suspension, as-is.
D49. Warn is an on-chain record with no consensus effect and no expiry. In scope.
D51. Ban and suspension scope stays contract-wide. The moderated set limits deletes and the interim block only.
4. Fees and the split
D45, D65. The charter sets the moderators per-action amounts within the contract's maximum; $actionFeeAgreement protects users. New amounts apply immediately at the block a seating or amendment passes; the agreement's tolerance absorbs small rises, larger ones fail at recheck and the user re-signs. Needs validate_action_fees_unchanged lifted for the moderators part and the RecheckTx gap closed. Teams compete on price.
D34, D38. The claim split is written in the charter, three percentages summing to 100, free within 0 to 100: a leader share, a share split equally between the other members, and a share split by each member's moderation action count. Example 10 / 40 / 50.
D35, D36, D37. Only charter-allowed actions count, reversals excluded, farming accepted (the leader removes a farmer). Every signer of a threshold action gets a count. Counters reset at every settle; with no actions in the period the action share is split equally.
D32, D13. Adding and removing a member both force a settle of the moderators pot first, ignoring the once-per-epoch limit. At a seat change between elected teams the pot is settled to the outgoing team first.
5. Initial election
D21, D22, D23, D43, D52, D53. New VotePoll variants on the MasternodeVote machinery. Contender poll without Lock. The applicant with the most votes wins, plurality, no minimum; with zero votes the first applicant wins. "First" is block time, then block height, then document id. A single applicant wins when the join window closes, with no vote window.
D24, D54, D55, D16. Applying costs 0.5 Dash, prefunding the masternode votes, the remainder released as processing fees at clean-up. The amounts are new fields of VoteResolutionFundFees in rs-platform-version, shared by application, challenge and amendment polls. No extra spam limit.
D56. DPNS is untouched: first-wins applies only to the new poll kinds.
6. Challenges and amendments
D40, D41, D42. A challenge runs in two stages. The first challenger opens it and pays; the contract's join window admits more challengers, each paying the same fee; nobody joins after it closes. Stage 1, "replace the incumbent?", runs for the vote window and passes when yes power exceeds two thirds of yes plus no (abstain excluded) and yes plus no is at least 400 (evonode 4, masternode 1). Stage 2, "which challenger?", is a contender poll with plurality and first-wins, skipped with a single challenger. The winner is seated immediately. The challengers' fees pool into one prefunded balance for both stages; nothing is refunded on failure.
D39, D46, D61. Challenges are allowed at most once every x, counted from the last seat change. A failed challenge starts no cool-down; instead the fee doubles for each challenge opened within 3 months of the previous challenge's close (relative to the previous fee, reset to base after 3 months, system constant, saturating). Amendments have their own clock of the same length, reset by a passed amendment, so an amendment never shields a team from a challenge.
D44. The leader prefunds an amendment vote. An amendment may run while a challenge is open. Per-ability powers are amendable only by vote.
D12. Bans and suspensions persist across a handover.
7. Scope
D5. Protocol version 14, v4.2-dev, tables edited in place.
D14. Appeals are a different PR; the design must not block them.
Clients: consensus, DAPI queries, proof verifier, rs-sdk and wasm/JS in the stack; Swift and Kotlin later.
Findings in the code that shape the work
The shipped contested-document tie-break awards the LATEST contender (check_for_ended_vote_polls v0, max_by(created_at, ...)). DPNS keeps it (D56); the new polls use min_by.
The contested document fund is 0.1 Dash at PV14 (VOTE_RESOLUTION_FUND_FEES_VERSION2), the single vote cost 0.0001 Dash, and a vote is refused once the prefunded balance is empty. 0.5 Dash (D54) covers 5,000 votes.
clean_up_after_contested_resources_vote_polls_end v1 already releases the remainder of a prefunded balance as processing credits.
VotePoll has a single variant. YesNoAbstainVoteChoice already exists in rs-dpp.
The merged claim pays equal shares to team() once per pot per epoch and leaves the remainder. D32 and D13 are forced claims that run before the membership or seat change; D34 replaces the equal split.
The merged moderation gate is actor-level and contract-wide, which D51 keeps. Per-type scope is needed only for deletes (already per type) and the interim block.
The contract's "other" tree [64, contract_id, 2] already holds keys 16, 32, 64, 96, 128, 192, and tests pin which key tops it. The seated team, the action counters and the two cool-down clocks need a home there or their own.
ContractModerationReason.code is stored unchecked today; D50 makes the seated charter's code list the check.
PR stack
Precursor: generalise vote polls. New VotePoll variants (contender poll without Lock, yes/no poll with supermajority and minimum power), first-wins tie-break for the new kinds, the 0.5 Dash fund fields, windows and fee sourced from a target contract.
Charter system data contract, plus the contract-side declaration: elected ContractModerators variant with its frozen parameters, moderated set, ability envelope, per-action maximums, interim mode, owner flag.
Application, initial election, seating. Seated-team state under the contract, per-ability powers, per-type delete gate, charter-priced moderators amounts with the fee-immutability check lifted and the RecheckTx gap closed.
Membership by the leader with forced settles, the three-part split, action counters, reason-code check.
Challenges (two stages, escalating fee, cool-down clock) and amendments (own clock, active charter swap).
Warn.
DAPI queries, proof verifier, rs-sdk, wasm/JS. Mobile later. Appeals separate.
Summary
A data contract can declare that its moderation team is chosen by masternodes and evonodes instead of by the contract owner. Teams apply by publishing a charter, masternodes elect one, and the seated team moderates the contract's content under the limits of its charter, paid from the contract's moderators fee pot. A seated team can only be replaced by a challenge vote.
All design questions are answered (rounds 1 to 8, 2026-09-19 to 2026-09-21; the round comments below hold the history). This body is the consolidated design. Nothing is built. Target: protocol version 14 on
v4.2-dev, version tables edited in place.It builds on what already merged:
ContractModerators::{ContractOwner, AppointedModerators}, banlist + suspensions,ContractUserModerationstate transition (type 24), actor-level gate in the batch transformerContractModerationReason { code: Option<u16>, text <= 1024 bytes }, the code is never checked todaycanBeDeletedByModerators, permanent removal record, storage refund forfeitedcanBeDeletedByModeratorsFor: a window after a document's last modification for moderator deletesContractFeeClaim(type 25), equal split betweenteam(), once per pot per epoch, last claim record,getContractFeePots$actionFeeAgreement: a document transition states the action fee it agrees to pay, with an increase toleranceDecisions
1. Contract-side declaration (frozen at creation)
ContractModeratorsvariant, exclusive with the two merged ones. Declarable only at contract creation; once elected, never out. (feat(platform)!: contract moderation with a banlist and a suspension list #4830 already refuses enabling moderation on update.)u32, bounds inSystemLimits: join window and vote window 1 day to 4 weeks, default 1 week each; challenge cool-downx2 weeks to 3 years.canBeDeletedByModerators. Deletes reach only the flagged types, within each type's window. Bans and suspensions are not limited by the flag.actionFees.moderatorsamount is the most a team may charge on its actions, and a charter charges a share of it, so the signer's fee agreement to the declared amounts never mismatches a seated charter. Owner pot amounts stay contract-fixed and immutable.noModeration(2026-09-22, round 9): nobody moderates and nobody claims the pot until a team is seated, but the moderated types stay usable meanwhile.2. Charter and team
codemust be one the seated charter lists.3. Abilities
4. Fees and the split
$actionFeeAgreementprotects users. New amounts apply immediately at the block a seating or amendment passes; the agreement's tolerance absorbs small rises, larger ones fail at recheck and the user re-signs. Needsvalidate_action_fees_unchangedlifted for the moderators part and the RecheckTx gap closed. Teams compete on price.5. Initial election
VotePollvariants on theMasternodeVotemachinery. Contender poll without Lock. The applicant with the most votes wins, plurality, no minimum; with zero votes the first applicant wins. "First" is block time, then block height, then document id. A single applicant wins when the join window closes, with no vote window.VoteResolutionFundFeesinrs-platform-version, shared by application, challenge and amendment polls. No extra spam limit.6. Challenges and amendments
x, counted from the last seat change. A failed challenge starts no cool-down; instead the fee doubles for each challenge opened within 3 months of the previous challenge's close (relative to the previous fee, reset to base after 3 months, system constant, saturating). Amendments have their own clock of the same length, reset by a passed amendment, so an amendment never shields a team from a challenge.7. Scope
v4.2-dev, tables edited in place.Findings in the code that shape the work
check_for_ended_vote_pollsv0,max_by(created_at, ...)). DPNS keeps it (D56); the new polls usemin_by.VOTE_RESOLUTION_FUND_FEES_VERSION2), the single vote cost 0.0001 Dash, and a vote is refused once the prefunded balance is empty. 0.5 Dash (D54) covers 5,000 votes.clean_up_after_contested_resources_vote_polls_endv1 already releases the remainder of a prefunded balance as processing credits.VotePollhas a single variant.YesNoAbstainVoteChoicealready exists in rs-dpp.team()once per pot per epoch and leaves the remainder. D32 and D13 are forced claims that run before the membership or seat change; D34 replaces the equal split.[64, contract_id, 2]already holds keys 16, 32, 64, 96, 128, 192, and tests pin which key tops it. The seated team, the action counters and the two cool-down clocks need a home there or their own.ContractModerationReason.codeis stored unchecked today; D50 makes the seated charter's code list the check.PR stack
VotePollvariants (contender poll without Lock, yes/no poll with supermajority and minimum power), first-wins tie-break for the new kinds, the 0.5 Dash fund fields, windows and fee sourced from a target contract.ContractModeratorsvariant with its frozen parameters, moderated set, ability envelope, per-action maximums, interim mode, owner flag.