Skip to content

fix(platform)!: charge a sponsored batch's fee increase to its signer (PV14) - #5398

Merged
QuantumExplorer merged 2 commits into
v5.0-devfrom
fix/sponsored-batch-fee-increase-paid-by-signer
Oct 13, 2026
Merged

QuantumExplorer merged 2 commits into
v5.0-devfrom
fix/sponsored-batch-fee-increase-paid-by-signer

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Basic explanation

What this does: Every state transition can carry a user_fee_increase: a percentage the sender adds to the processing fee to get picked sooner. When a contract owner pays the gas of a document action (gas sponsorship, protocol version 14), that extra percentage was billed to the contract owner, although the signer chose it. Now the contract owner pays the fee as if no increase was chosen, and the signer pays the extra amount themselves.

Value: A contract owner who sponsors gas pays a predictable fee per action, whatever the signer puts in the transition. A signer who wants priority still gets it and pays for it, as on an unsponsored transition.

Risks: Low. Consensus change at protocol version 14 only, which has not shipped to mainnet; the two methods edited are selected by no released version. A sponsored batch with user_fee_increase: 0 is judged and charged exactly as before. A signer with a nonzero increase who cannot pay it is now refused (unpaid) instead of having the contract owner pay it.

Issue being fixed or feature implemented

With gas sponsorship (gasFeesPaidBy: ContractOwner / PreferContractOwner), validate_fees_of_event v1 judged and execute_event v1 charged the contract owner the processing fee raised by the signer's user_fee_increase. The signer chose the increase, so the signer should pay it.

What was done?

Before, a sponsored creation with user_fee_increase: 100:

Contract owner pays Signer pays
Fee storage + 2 × processing 0

After:

Contract owner pays Signer pays
Fee storage + processing processing (the increase)
  • validate_fees_of_event v1 (settle_fees_of_event_v1): the sponsor is judged on the estimated gas less the increase. When the sponsor pays, the signer's balance has to cover the principal plus the increase (IdentityInsufficientBalanceError, 40210, unpaid otherwise), and a budgeted signing key has to cover the same (IdentityPublicKeyBudgetExceededError, 40218).
  • execute_event v1: when a sponsor pays, the increase is taken off the sponsor's fee and charged to the signer as a processing fee of its own (a second apply_balance_change_from_fee_to_identity). The reported actual fee is the sum of both, and the signer's key budget is charged the increase.
  • When the signer pays the gas (no sponsor, a PreferContractOwner fallback, or a failed batch) nothing changes.
  • Docs: protocol version 14 note 11 (in place), ResolvedGasSponsor, ExecutionEvent::Paid.gas_sponsor, the book's fee overview and tokenCost chapter.

In-place changes to shipped generations

None. execute_event 1 and validate_fees_of_event 1 are selected only by DRIVE_ABCI_METHOD_VERSIONS_V10 (protocol version 14, unreleased), so they are edited in place.

How Has This Been Tested?

New tests in packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/gas_sponsorship.rs:

  • the same sponsored creation on two identical chains, with user_fee_increase 0 and u16::MAX: the contract owner pays the same, the signer pays exactly processing × 65535 / 100, and the result reports both;
  • a signer without credits asking for an increase on a sponsored creation (ContractOwner and PreferContractOwner): refused in check tx and at execution, unpaid, the contract owner untouched;
  • a budgeted signing key is charged only the increase, and a budget below the increase refuses the batch unpaid.

cargo test -p drive-abci --lib -- gas_sponsorship key_limits action_fees token_cost_policy validate_fees_of_event execute_event

Breaking Changes

Consensus change at protocol version 14 (unreleased): a sponsored document batch with a nonzero user_fee_increase charges the increase to its signer.

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Fee Changes
    • From protocol version 14, gas sponsors pay the covered batch fee without the signer’s processing-fee increase. The signer pays that increase, which must fit within their available balance and any applicable signing-key budget.
    • If the signer cannot cover the required amount, the batch is refused without charging the sponsor and returns IdentityInsufficientBalanceError (40210).
    • Fee results reflect the amounts paid by both the sponsor and signer.

PR Hygiene · 57eb03c

  • Bots — coderabbitai ✓ · thepastaclaw not yet — /skip-bots proceeds without the ones not yet reported
  • Self-review — post /self-reviewed
  • Build running
  • Approvals — you own every area touched; none needed

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

… (PV14)

The signer of a document batch chooses its user_fee_increase. When the
contract owner pays the batch's gas, fee validation v1 judged and
execute_event v1 charged that owner the processing fee raised by it.

Now the sponsor is judged on and charged the fee without the increase,
and the signer pays the processing fee the increase adds, as a fee of
its own: its balance and a budgeted key's budget must cover the
principal plus the increase (refused unpaid otherwise, 40210 / 40218).
The reported actual fee is the sum of both charges. A batch with no
increase, or paid by its signer, is judged and charged as before.

Both generations are selected only by protocol version 14, which has
not shipped, so they are edited in place; v14 note 11 and the book
describe the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: dashpay/platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3c9500d3-e8fe-4a31-8ff7-45fea9b0f69c
📥 Commits

Reviewing files that changed from the base of the PR and between 83a98ba and 57eb03c.

📒 Files selected for processing (1)
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/gas_sponsorship.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

Protocol-version-14 gas sponsorship now excludes the signer-selected user fee increase from the sponsor’s fee. Validation checks the signer’s balance and signing-key budget. Execution charges the increase to the signer and reports the combined fee. Tests and documentation describe these rules.

Changes: Gas sponsorship fee allocation

Layer / File(s) Summary
Validate sponsor and signer fee coverage
book/src/contract-keywords/token-cost.md, book/src/fees/overview.md, packages/rs-platform-version/src/version/v14.rs, packages/rs-drive/src/state_transition_action/batch/mod.rs, packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v1/mod.rs
Validation excludes the user fee increase from the sponsor’s required gas. It checks the signer’s balance and signing-key budget for the required amounts. The documentation describes the payment rules and the unpaid insufficient-balance error.
Settle fees and report total
packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v1/mod.rs, packages/rs-drive-abci/src/execution/types/execution_event/mod.rs, packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/gas_sponsorship.rs
Execution separately charges the signer’s fee increase when a sponsor pays, then reports the actual fees paid by both parties. Tests cover fee allocation, insufficient signer balance, and signing-key budget limits.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant FeeValidation
  participant ContractOwner
  participant Signer
  participant FeeExecution
  FeeValidation->>ContractOwner: Assess gas excluding user fee increase
  FeeValidation->>Signer: Check balance and signing-key budget
  FeeValidation-->>FeeExecution: Approve sponsor payment when checks pass
  FeeExecution->>ContractOwner: Charge sponsored fee
  FeeExecution->>Signer: Charge user fee increase
  FeeExecution-->>Signer: Report combined actual fee
Loading

Suggested reviewers: shumkov

Merge Risk: ⚪ Minimal · up to 57eb0

This change adds tests for sponsored fee handling at protocol version 14. They check that the sponsor pays only the unincreased gas and that the signer pays the increase. No merge-blocking risk is identified.

Pre-merge checks · Passed 5
Passed Passed checks (5 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely identifies the main protocol version 14 change: charging a sponsored batch's fee increase to its signer.
Docstring Coverage Passed Docstring coverage is 94.44% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 18 functions across 6 files.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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 v5.0.0 milestone Oct 13, 2026
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai ✓ · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 13, 2026
@github-actions

github-actions Bot commented Oct 13, 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-10-13T07:43:34.388Z

@thepastaclaw

thepastaclaw commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 57eb03c) · triage: normal
█░░░░░░░░░░░░░░░░░░░ 6% · about 20 min left · running for 1 min
✅ triage → ⏳ Phase 1 (0/2 lanes) → ▫️ verify 1 → ▫️ gate → ▫️ Phase 2 → ▫️ verify 2 → ▫️ fresh Phase 2 → ▫️ fresh verify → ▫️ publish
Estimated from recent reviews of this tier · updated 07:46 UTC · live progress

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Phase 1 + Phase 2

Static verification at head 83a98ba found no blocking defects: sponsorship excludes the signer's fee increase in both validation and execution, and the changed implementations are confined to unreleased PV14. One targeted admission-boundary test would strengthen coverage of the new sponsor-selection rule. No local builds or tests were run; the supplied CI snapshot reports successful Rust workspace tests, with PR Hygiene pending.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The diff changes consensus fee allocation in settle_fees_of_event_v1 and execute_event_v1, but the surcharge split and associated balance and budget checks are contained rather than large or intricate enough to meet the critical tier.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 14% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/gas_sponsorship.rs`:
- [SUGGESTION] packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/gas_sponsorship.rs:1068-1073: Cover sponsor admission when only the unincreased fee fits
  The successful fee-split test fixes the sponsor balance at 0.1 Dash without establishing that it covers the estimated base gas but cannot cover the gas including the increase. Its payment assertions verify execution, but do not explicitly pin the changed admission boundary in `settle_fees_of_event_v1`, which now subtracts the increase before selecting the sponsor. Add a deterministic case that establishes the sponsor's balance is between those two estimated requirements and gives the signer enough credits for the increase. Exercise both `ContractOwner` and `PreferContractOwner`, asserting check-tx admission and sponsor payment at execution, so charging the increased estimate cannot regress into an unpaid refusal or a signer-pays fallback.

@github-actions

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 13, 2026
… fits

A contract owner whose balance holds exactly the gas estimated without
the signer's fee increase still sponsors a creation asking for a 100%
increase, under ContractOwner and PreferContractOwner: check tx admits
it, the owner pays the gas and the signer the increase. Before the fix
an insisting batch was refused with 40222 and a preferring one fell
back to the signer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai ✓ · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed labels Oct 13, 2026
@QuantumExplorer
QuantumExplorer merged commit ea8e4ee into v5.0-dev Oct 13, 2026
21 of 22 checks passed
@QuantumExplorer
QuantumExplorer deleted the fix/sponsored-batch-fee-increase-paid-by-signer branch October 13, 2026 07:48
@QuantumExplorer QuantumExplorer mentioned this pull request Oct 13, 2026
8 of 26 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-bots Waiting for the review bots to report on this head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants