Skip to content

feat(platform)!: document action fees paid to the contract owner and moderators, with a fee claim state transition - #4851

Merged
QuantumExplorer merged 14 commits into
v4.2-devfrom
claude/state-transition-fees-moderator-d1cd46
Sep 20, 2026
Merged

QuantumExplorer merged 14 commits into
v4.2-devfrom
claude/state-transition-fees-moderator-d1cd46

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 20, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Follow-up to #4830 (contract moderation). A contract can now pay its owner and its moderation team: a document type may charge a fixed fee in credits for an action on one of its documents, on top of the gas, and the collected fees are paid out by a new state transition. Protocol version 14, tables amended in place like #4830.

"post": {
  "type": "object",
  "actionFees": {
    "pricing": "feeMultiplier",
    "create": { "moderators": 100000000, "owner": 10000000 }
  }
}

Creating a post costs an extra 0.001 Dash for the moderation team and 0.0001 Dash for the contract owner.

What was done?

Declaration (rs-dpp). The actionFees keyword in the v3 document meta-schema, beside tokenCost, prices the same six actions (create, replace, delete, transfer, update_price, purchase), each with an owner and a moderators part. pricing is feeMultiplier (the default: the declared amounts are scaled by the fee multiplier of the epoch) or fixed. Parsed by try_from_schema generation 3 into DocumentTypeV2.action_fees.

  • The amounts never change. Nobody signs the fee on a transition, so what the contract showed when it was published is what its users agreed to: document type validate_update v1 refuses adding, changing or removing the actionFees of an existing document type. A document type added by an update may declare its own, which is how a live contract gets fees.
  • A moderators part needs a contract that declares moderation (DocumentActionFeesWithoutModerationError, 10902), checked in contract create and update basic_structure v2.
  • ContractModerators::team(): the identities that share the moderators pot are the ones the contract appoints, the owner among them only when appointed, and the owner alone when nobody is appointed.

The pots (rs-drive). [PreFundedSpecializedBalances, 64, contract id] is the owner pot and [PreFundedSpecializedBalances, 192, contract id] the moderators pot, both sum items. They are deliberately not under the contract: calculate_total_credits_balance sums a fixed set of root sum trees, DataContractDocuments is a normal tree, and credits parked there would fail every block with CorruptedCreditsNotBalanced. The two sum trees are created at genesis (state structure 4) and by transition_to_version_14 through the same helper. The epoch each pot was last claimed in is a plain item of the contract's other tree (keys 32 and 96). All of it is described in structure.rs and grovedb-structure.json; the recorded Merk shapes show the voting balances still on top of the prefunded layer and the banlist still on top of the contract's other tree.

  • A chain that reached protocol version 14 on a build from before the pots never ran the upgrade step that creates their trees. The first fee a pot receives checks, with a billed read, that its tree is there and creates it in the same batch when it is not. A pot that holds credits proves its tree, so no later fee pays for the check.
  • The prefunded balances layer now holds three trees instead of one, so the estimation of a voting balance write gets a protocol version 14 generation (estimated_cost_for_prefunded_specialized_balance_update: 1) that describes it that way; the shipped v0 is untouched.

Charging (rs-drive-abci). Whoever pays the gas pays the action fee: the signer, or the contract owner when they sponsor the gas (#4826). That is only settled in fee validation, so the fee travels on ExecutionEvent::Paid.action_fees and one function, action_fee_operations(payer, fees), builds the removal from the payer and the additions to the pots where the payer is chosen. validate_fees_of_event v1 and execute_event v1 (both protocol version 14 only) ask one question through one function, gas_sponsor_pays, on one estimate, so they always name the same payer.

  • The contract owner never pays into their own owner pot. A sponsor is the contract owner, so a sponsored action pays into the moderators pot only.
  • The fee is no part of the FeeResult: the fee pools and the proposers see what they saw before. What leaves the payer is summed from what reaches the pots, so the two cannot drift.
  • The fee is a price the contract set and moves as a purchase price does: with the batch's operations, before the gas is metered and debited.
  • Fee arithmetic is held at the maximum number of credits instead of overflowing. The epoch multiplier has no upper bound, and a fee nobody can pay is refused for an insufficient balance, a consensus error, where an overflow would have failed every transition on the action with an internal one.
  • The fee counts against the budget of a budgeted signing key when its identity pays it.
  • Token transitions are not charged.

ContractFeeClaim (state transition type 25). Names a contract and a pot (owner or moderators) and pays the pot out: the owner pot whole to the contract owner, who alone may claim it; the moderators pot in equal shares to the team, any member of which may claim it. What the split leaves over stays in the pot, so no member is favoured by identity id order. Each pot is paid out at most once per epoch and the two are independent. A refused claim is paid for by a nonce bump and leaves the pot alone. Errors 41111 (already claimed this epoch), 41112 (nothing to claim), 41113 (not a recipient of the pot). The execution proof shows the pot, its last claim epoch and the balance of every recipient (VerifiedContractFeeClaim).

Clients. ClaimContractFees in the Rust SDK, the ContractFeeClaim class and proof result in wasm-dpp2, the new errors in the legacy wasm-dpp. The proof of a claim is verified against the contract, which names who the pot pays, and the team can change by a contract update, so the SDK fetches the contract again before a claim rather than trust a copy the context provider holds; that registration is one helper shared with the moderation transition. Book: fees/overview.md, data-model/contract-moderation.md, error-handling/error-codes.md.

Three things the tests caught that are worth a reviewer's eye

  1. A transition that fails in state validation must owe nothing. State validation replaces a failed transition with a nonce bump after the transformer ran. Fees resolved at transform time were charged to a creation that then failed on its token balance (40700). The batch action now keeps only the epoch multiplier it read, and resolved_action_fees() reads the fees off the final transitions when the execution event is built.
  2. The first block of an epoch has no fee multiplier item yet. State transitions execute before the end of the block, where the epoch is initialized. fetch_action_fee_multiplier_with_fee falls back to the fee schedule's multiplier, which is what the epoch is about to be initialized with. Without it every fee-bearing transition of the first block of each epoch would have been an internal error.
  3. A stray actionFees key in an old contract, and why it needs no special case. The frozen v0 document meta-schema (protocol versions 1 to 11) does not forbid unknown top-level keys, and stored contracts are parsed by generation 3 from protocol version 14, so a contract from that era could in principle carry a key of this name that nobody validated. An earlier revision of this PR read such a declaration as none on the stored path. That is gone: like every doctype-level keyword of generation 3, actionFees is read wherever it appears and its shape is enforced on the validating and the stored path alike, which is what indexOnly, immutable and the aggregate keywords do and what feat(sdk): show and lock immutable document properties in the mobile example apps #4820 pins. A census of every contract create and update on mainnet and testnet (2026-09-20), decoded from the raw bytes, found no contract admitted under meta-schema v0 carrying the key (mainnet: 54 contract versions before protocol version 12, zero hits; testnet: 3347, zero hits), and that set is closed, since every create and update since is validated by a meta-schema that refuses unknown doctype-level keys. So every declaration a node reads from state was validated. The gate test still pins the precondition: protocol versions 1 to 11 admit and ignore the key, 12 and 13 refuse it, 14 reads it.

Not in this pull request

  • A DAPI query for the pots (getContractFeePots) with its rs-sdk Fetch, wasm-sdk and js-evo-sdk surfaces, and a wasm-sdk / js-evo-sdk method for the claim. The Drive side is ready for it (fetch_contract_fee_pot, prove_contract_fee_pots, verify_contract_fee_pots).
  • The shared test that pins the stored-path rule for every generation 3 keyword at once. It is not on this branch's base yet; actionFees joins its list of malformed keywords at the merge.
  • Reading the epoch multiplier once per block instead of once per fee-bearing batch. It needs block-scoped state in the batch transformer; today it is one small billed read.
  • A strategy test over several epochs. The once-per-epoch rule is tested by processing claims in different epochs.
  • Swift and Kotlin.

How Has This Been Tested?

Targeted suites, all green locally:

  • rs-dpp: keyword parsing, both pricings, malformed declarations refused on the validating and the stored path, a moderators fee parsing on both paths (the contract is what refuses it), the protocol version gate (ignored at 1 to 11, refused at 12 and 13, read from 14), the update rule, team(), amounts held at the maximum credits, the frozen error discriminants, the transition's bytes, JSON and value round trips.
  • rs-drive: pot add, deduct and fetch, a chain whose pot trees are missing, the last claim epochs, proof round trips, the pots counted by calculate_total_credits_balance, estimation against applied cost, the multiplier read including the first block of an epoch, action_fee_operations, and the structure conformance tests against a real GroveDB.
  • rs-drive-abci:
    • charging: the signer pays gas plus fee and the credits in all trees drop by the gas alone; each of the six actions charges its own, distinct fee; feeMultiplier against fixed with an epoch multiplier of 1500, through check tx as well; the first block of an epoch through a block; the owner's own document; a paying sponsor with an unfunded user; an insisted sponsor that covers the gas but not the fee (40222, unpaid); a preferred sponsor that falls back to the signer; a signer who cannot afford the fee; a transition that fails pays no fee; a budgeted key;
    • contracts: 10902 on contract create and on a contract update; a live contract gaining fees through a document type an update adds, a stranger filling both pots and the team being paid from them;
    • the claim: both pots, the team with and without the owner, outsiders, the once-per-epoch rule of each pot and their independence, an empty pot, an unmoderated contract, an unknown contract, check tx refusing with the same codes, the execution proof, a proof of a claim that never executed, and protocol version 13;
    • the upgrade to 14 creating the pot trees byte-identical to a chain born at 14.
  • Broader regression passes around the change, run before the last merge of v4.2-dev: 2,245 rs-dpp tests (document_type, state_transition, consensus), 1,333 rs-drive tests (prefunded, votes, fee_pots, state_transition_action, structure) and 620 rs-drive-abci tests (document batches, contract create and update, moderation, the claim, fee validation and execution, masternode votes and voting, the protocol upgrade), all passing. After that merge the suites around everything it touched were run again and pass. The full suites and the strategy tests are left to CI.
  • cargo clippy --all-targets -- -D warnings on dpp, drive, drive-abci, platform-version (with --all-features), dash-sdk, wasm-dpp, wasm-dpp2 and wasm-sdk; cargo check -p drive --no-default-features --features verify; cargo check --workspace --all-targets.
  • Not run: the new wasm-dpp2 TypeScript spec (ContractFeeClaimTransition.spec.ts), which needs a wasm build. It mirrors the type 24 spec.

Breaking Changes

Consensus-breaking, gated at protocol version 14: a new document type keyword, a new state transition type (25), new GroveDB structure under PreFundedSpecializedBalances and the contract's other tree, new consensus errors (10902, 41111 to 41113), a new generation of the voting balance cost estimation, and document batches on a fee-bearing document type move credits into the pots. Nothing changes for a contract that declares no actionFees.

One point is consensus-relevant only in theory: a stored contract with a malformed actionFees refuses to load, as it does for every other generation 3 keyword, instead of reading as a contract without fees. The census above shows no such contract exists on mainnet or testnet, and none can be created.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

🤖 Generated with Claude Code

QuantumExplorer and others added 10 commits September 20, 2026 13:52
The `actionFees` keyword (v3 document meta-schema, protocol version 14) sets a
fixed fee in credits per document action, split between the contract's owner pot
and its moderators pot, priced as written or scaled by the epoch fee multiplier.
The fees are fixed when the document type is published. Adds the moderation team
helper and the consensus errors of the fee claim.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two sum trees under the prefunded specialized balances hold what every contract's
document action fees have collected: the owner pot and the moderators pot. They
sit under a root sum tree so the credits stay inside the sum every block is
checked against. The epoch each pot was last claimed in is an item of the
contract's other tree. Versioned add, deduct, fetch, marker and prove methods,
the verifier, cost estimation, the drive operation and the structure
description; created at genesis (structure v4).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The base document action carries the fee its document type declares for the
action and how it is priced. The batch action carries the fees once priced, and
action_fee_operations turns them into operations for whoever pays: one removal
from the payer, one addition per fee pot, the owner part dropped when the payer
is the contract owner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A document transition on a document type that declares an action fee moves the
fee from the gas payer's balance into the contract's owner and moderators pots,
with the batch's own operations. The signer pays, or the contract owner when they
sponsor the gas; fee validation and execution settle the payer with one formula
on one estimate. The owner never pays into their own owner pot, a transition that
became a nonce bump owes nothing, and the fee is no part of the fee result, so
the fee pools see what they saw. A fee priced by the fee multiplier follows the
multiplier of the epoch, read once per batch and billed. A moderators fee needs
declared moderation (10902). The pot trees are created by the upgrade to
protocol version 14 as at genesis.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ContractFeeClaim (type 25, protocol version 14) pays out one of the two fee pots
a contract's document action fees collect in. The owner pot goes to the contract
owner, who alone may claim it; the moderators pot is split equally between the
moderation team, any member of which may claim it, and what the split leaves
over stays in the pot. Each pot is paid out at most once per epoch, on its own
clock. A refused claim is paid for by a nonce bump and leaves the pot alone. The
execution proof shows the pot, its last claim epoch and the balance of everyone
it paid.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sm-dpp

Boxing keeps the batched transition enum under clippy's large-variant threshold:
most actions declare no fee. The legacy wasm-dpp matches gain the new consensus
errors and refuse the new transition like the other wasm-dpp2-only ones.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…laim

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ClaimContractFees sends a ContractFeeClaim and resolves with the proved pot and
balances. The proof is verified against the contract, which names who the pot
pays, so the contract is registered with the context provider before anything
is signed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…in the protocol version 14 changelog

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The ContractFeeClaim class, its arms in the state transition wrapper and the
VerifiedContractFeeClaim proof result. The credits left in the pot are a number
in JSON while that is exact in JavaScript and a decimal string past it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 186 files, which is 86 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Repository: dashpay/platform/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 288690a9-31d1-4c1f-9ab5-b74fd8c2e836

📥 Commits

Reviewing files that changed from the base of the PR and between 72b58f6 and 6dbd6cb.

📒 Files selected for processing (186)
  • book/src/data-model/contract-moderation.md
  • book/src/error-handling/error-codes.md
  • book/src/fees/overview.md
  • packages/rs-dpp/schema/meta_schemas/document/v3/document-meta.json
  • packages/rs-dpp/src/data_contract/config/moderation/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/accessors/v2/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/action_fees/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/action_fees/v0/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v3/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/methods/validate_update/v1/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/v2/accessors.rs
  • packages/rs-dpp/src/data_contract/document_type/v2/mod.rs
  • packages/rs-dpp/src/errors/consensus/basic/basic_error.rs
  • packages/rs-dpp/src/errors/consensus/basic/contract_moderation/document_action_fees_without_moderation_error.rs
  • packages/rs-dpp/src/errors/consensus/basic/contract_moderation/mod.rs
  • packages/rs-dpp/src/errors/consensus/codes.rs
  • packages/rs-dpp/src/errors/consensus/state/contract_moderation/contract_fee_claim_not_allowed_error.rs
  • packages/rs-dpp/src/errors/consensus/state/contract_moderation/contract_fees_already_claimed_this_epoch_error.rs
  • packages/rs-dpp/src/errors/consensus/state/contract_moderation/contract_fees_nothing_to_claim_error.rs
  • packages/rs-dpp/src/errors/consensus/state/contract_moderation/mod.rs
  • packages/rs-dpp/src/errors/consensus/state/state_error.rs
  • packages/rs-dpp/src/state_transition/mod.rs
  • packages/rs-dpp/src/state_transition/proof_result.rs
  • packages/rs-dpp/src/state_transition/state_transition_types.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/accessors/mod.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/accessors/v0/mod.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/fields.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/identity_signed.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/methods/mod.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/methods/v0/mod.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/mod.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/state_transition_estimated_fee_validation.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/state_transition_like.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/v0/identity_signed.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/v0/mod.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/v0/state_transition_like.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/v0/types.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/v0/v0_methods.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/v0/version.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/contract_fee_claim_transition/version.rs
  • packages/rs-dpp/src/state_transition/state_transitions/contract/mod.rs
  • packages/rs-dpp/src/state_transition/traits/state_transition_like.rs
  • packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v1/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v1/mod.rs
  • packages/rs-drive-abci/src/execution/types/execution_event/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/advanced_structure_v1/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v2/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v2/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/action_fees.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/gas_sponsorship.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/basic_structure/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/basic_structure/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/identity_contract_nonce/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/identity_contract_nonce/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/state/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/state/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_fee_claim/tests.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_user_moderation/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/contract_user_moderation/tests.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/v2/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/v2/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs
  • packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs
  • packages/rs-drive/grovedb-structure.json
  • packages/rs-drive/src/drive/contract/fee_pots/add_to_contract_fee_pot/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/add_to_contract_fee_pot/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/deduct_from_contract_fee_pot/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/deduct_from_contract_fee_pot/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/estimated_costs/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/estimated_costs/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/fetch_action_fee_multiplier/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/fetch_action_fee_multiplier/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/fetch_contract_fee_pot/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/fetch_contract_fee_pot/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/insert_contract_fee_pot_trees/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/insert_contract_fee_pot_trees/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/prove_contract_fee_pots/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/prove_contract_fee_pots/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/queries.rs
  • packages/rs-drive/src/drive/contract/fee_pots/set_contract_last_fee_claim_epoch/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/set_contract_last_fee_claim_epoch/v0/mod.rs
  • packages/rs-drive/src/drive/contract/fee_pots/tests.rs
  • packages/rs-drive/src/drive/contract/fee_pots/types.rs
  • packages/rs-drive/src/drive/contract/mod.rs
  • packages/rs-drive/src/drive/contract/paths.rs
  • packages/rs-drive/src/drive/contract/structure.rs
  • packages/rs-drive/src/drive/document/index_uniqueness/mod.rs
  • packages/rs-drive/src/drive/initialization/v4/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/estimation_costs/for_prefunded_specialized_balance_update/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/estimation_costs/for_prefunded_specialized_balance_update/v1/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/structure.rs
  • packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs
  • packages/rs-drive/src/state_transition_action/action_convert_to_operations/contract/contract_fee_claim_transition.rs
  • packages/rs-drive/src/state_transition_action/action_convert_to_operations/contract/mod.rs
  • packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_index_only_delete_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/batch/mod.rs
  • packages/rs-drive/src/state_transition_action/batch/tests.rs
  • packages/rs-drive/src/state_transition_action/batch/v0/mod.rs
  • packages/rs-drive/src/state_transition_action/contract/contract_fee_claim/mod.rs
  • packages/rs-drive/src/state_transition_action/contract/contract_fee_claim/transformer.rs
  • packages/rs-drive/src/state_transition_action/contract/contract_fee_claim/v0/mod.rs
  • packages/rs-drive/src/state_transition_action/contract/contract_fee_claim/v0/transformer.rs
  • packages/rs-drive/src/state_transition_action/contract/mod.rs
  • packages/rs-drive/src/state_transition_action/mod.rs
  • packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs
  • packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs
  • packages/rs-drive/src/structure/tests.rs
  • packages/rs-drive/src/util/batch/drive_op_batch/contract_fee_pot.rs
  • packages/rs-drive/src/util/batch/drive_op_batch/mod.rs
  • packages/rs-drive/src/util/batch/mod.rs
  • packages/rs-drive/src/verify/contract_moderation/mod.rs
  • packages/rs-drive/src/verify/contract_moderation/verify_contract_fee_pots/mod.rs
  • packages/rs-drive/src/verify/contract_moderation/verify_contract_fee_pots/v0/mod.rs
  • packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v3.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v10.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v9.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v3.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v3.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v4.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v9.rs
  • packages/rs-platform-version/src/version/feature_initial_protocol_versions.rs
  • packages/rs-platform-version/src/version/v14.rs
  • packages/rs-sdk/src/platform/transition.rs
  • packages/rs-sdk/src/platform/transition/contract_fee_claim.rs
  • packages/rs-sdk/src/platform/transition/contract_user_moderation.rs
  • packages/wasm-dpp/src/errors/consensus/consensus_error.rs
  • packages/wasm-dpp/src/state_transition/state_transition_factory.rs
  • packages/wasm-dpp2/src/data_contract/mod.rs
  • packages/wasm-dpp2/src/data_contract/transitions/fee_claim.rs
  • packages/wasm-dpp2/src/data_contract/transitions/mod.rs
  • packages/wasm-dpp2/src/lib.rs
  • packages/wasm-dpp2/src/state_transitions/base/state_transition.rs
  • packages/wasm-dpp2/src/state_transitions/proof_result/convert.rs
  • packages/wasm-dpp2/src/state_transitions/proof_result/data_contract.rs
  • packages/wasm-dpp2/tests/unit/ContractFeeClaimTransition.spec.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added this to the v4.2.0 milestone Sep 20, 2026
@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

🌳 GroveDB structure

This pull request changes the described GroveDB structure. Open it in the structure viewer: new nodes glow, removed ones stay as ghosts, and the tour walks through each change.

Added (6 nodes)

  • prefunded_balances.owner_fee_pots
  • prefunded_balances.moderators_fee_pots
  • contracts.contract.other.last_owner_fee_claim_epoch
  • contracts.contract.other.last_moderators_fee_claim_epoch

Changed (2 nodes)

  • prefunded_balances
  • contracts.contract.other

Compared 72b58f6073 with 6dbd6cb230. Updated at 2026-09-20T11:06:10.477Z

@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

📖 Book Preview built successfully.

Download the preview from the workflow artifacts.
To view locally: download the artifact, unzip, and open index.html.

Updated at 2026-09-20T11:06:23.499Z

@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

PR Hygiene

State: waiting-bots · commit 6dbd6cb230659e7448a2b8fe6de4bd4aca7e7ae1

  • coderabbitai has not reported for the current head
  • thepastaclaw has not reported for the current head

Self-review is an author attestation that you have read the diff:
/self-reviewed — covers everything pushed so far; post it again after a new push.

This check passes when the policy is satisfied; the repository decides whether merging requires it.

@thepastaclaw

thepastaclaw commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator

🕓 Queued for automated review — 3rd in line, estimated start in ~55 min (commit 6dbd6cb)
Estimated review time once started: ~55 min (two-phase automated review; median of recent runs).

  • Request priority review — click to move this review to the front of the queue.

@codecov

codecov Bot commented Sep 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.74532% with 434 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.18%. Comparing base (72b58f6) to head (6dbd6cb).
⚠️ Report is 2 commits behind head on v4.2-dev.

Files with missing lines Patch % Lines
...ract_moderation/verify_contract_fee_pots/v0/mod.rs 53.73% 31 Missing ⚠️
...events_on_first_block_of_protocol_change/v0/mod.rs 61.19% 26 Missing ⚠️
...state_transition_was_executed_with_proof/v0/mod.rs 66.66% 26 Missing ⚠️
...ansition_action/contract/contract_fee_claim/mod.rs 14.28% 24 Missing ⚠️
...ct/document_type/methods/validate_update/v1/mod.rs 79.62% 22 Missing ⚠️
.../rs-drive/src/state_transition_action/batch/mod.rs 82.45% 20 Missing ⚠️
...sition/state_transitions/contract_fee_claim/mod.rs 76.25% 19 Missing ⚠️
...sition_processing/validate_fees_of_event/v1/mod.rs 63.41% 15 Missing ⚠️
...s-drive/src/prove/prove_state_transition/v0/mod.rs 57.57% 14 Missing ⚠️
...tate_transition_processing/execute_event/v1/mod.rs 60.60% 13 Missing ⚠️
... and 52 more
Additional details and impacted files
@@             Coverage Diff              @@
##           v4.2-dev    #4851      +/-   ##
============================================
- Coverage     84.70%   84.18%   -0.53%     
============================================
  Files          3063     3100      +37     
  Lines        411520   417212    +5692     
============================================
+ Hits         348587   351226    +2639     
- Misses        62933    65986    +3053     
Components Coverage Δ
dpp 85.29% <90.59%> (-0.72%) ⬇️
drive 83.30% <81.70%> (-0.69%) ⬇️
drive-abci 85.85% <77.95%> (-0.26%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.97% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 31.85% <ø> (+0.62%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

QuantumExplorer and others added 4 commits September 20, 2026 15:56
- The first fee a pot receives creates the pot's tree when it is missing, so a
  chain that reached protocol version 14 before the pots existed can use them.
- Fee arithmetic is held at the maximum credits instead of overflowing: a fee
  nobody can pay is an insufficient balance, not an internal error.
- A stored contract whose action fees charge the moderators without declared
  moderation cannot have been validated and is read as declaring none, so no
  credits collect in a pot that has no team.
- The voting balance estimation gets a protocol version 14 generation that
  describes the prefunded balances layer as the three trees it now holds.
- The SDK fetches the contract again before a claim: the team can change, and a
  stale copy would refuse a claim that executed. The registration is shared with
  the moderation transition.
- What leaves the payer is summed from what reaches the pots.
- Tests: every action charges its own fee, check tx with the fee multiplier
  pricing, the first block of an epoch through a block, a live contract gaining
  fees through a new document type, and 10902 on a contract update. The claim
  tests share the moderation tests' actor and assertions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ate-transition-fees-moderator-d1cd46

# Conflicts:
#	book/src/data-model/contract-moderation.md
#	book/src/error-handling/error-codes.md
#	packages/rs-dpp/src/errors/consensus/basic/basic_error.rs
#	packages/rs-dpp/src/errors/consensus/codes.rs
#	packages/rs-drive/grovedb-structure.json
#	packages/rs-drive/src/structure/tests.rs
#	packages/wasm-dpp/src/errors/consensus/consensus_error.rs
#	packages/wasm-dpp2/src/state_transitions/proof_result/data_contract.rs
Every doctype-level keyword of generation 3 is read wherever it appears and its
shape is enforced on the validating and the stored path alike. actionFees now
follows that rule like indexOnly, immutable and the aggregate keywords: a
malformed declaration is an error on both paths, and the arm that read a
moderators fee without moderation as no declaration is gone, since creation
refuses that state (10902) and moderation is never turned off.

The leniency guarded against a stray key in a contract admitted under the open
v0 meta-schema. A census of every contract create and update on mainnet and
testnet (2026-09-20) found none, and every create and update since protocol
version 12 is validated by a meta-schema that refuses unknown doctype-level
keys, so every declaration a node reads from state was validated. The leniency
was also the wrong tool: it could only soften the malformed case, never the
well-formed one, and full_validation false is also what check tx and client
parsing pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The sum of a claim's payouts and an addition to a fee pot reported a failed
checked_add as corrupted code execution and as a critically corrupted state.
Both are overflows, and Drive's fee arithmetic has an error for that.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@QuantumExplorer

Copy link
Copy Markdown
Member Author

Reviewed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants