Repository navigation
feat(documents): agree to document action fees before broadcasting - #1122
Claudius-Maginificent wants to merge 14 commits into
Conversation
On protocol 14 a document type can charge an action fee. A fee quote holds the declared owner and moderator parts at the fee multiplier the user saw and the most it can become; its agreement tolerates a 20% multiplier rise for a multiplier-priced fee. The backend never agrees on the user's behalf: an action whose agreement is missing or names another fee is refused before signing. A refusal for a risen multiplier refreshes the multiplier from a proved epoch, so trying again quotes the current fee; if that refresh fails the user is told the fee could not be updated. A protocol 13 guard checks that a fee agreement is refused locally there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
Map a missing or mismatched fee agreement, a changed contract fee and a multiplier risen past the tolerance to dedicated TaskError variants, plus one for a multiplier that could not be refreshed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
… action The estimated-fee panel shows the contract fee split between owner and moderators. Sending asks for confirmation naming the fee, the ceiling and the tolerance (or that the fee is fixed); confirming sends the action built when the dialog opened. An optional token cost can be skipped, the gas then being paid in credits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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. Comment |
|
🕓 Review not started yet because this PR is a draft.
Commit 5f34e34. Normal review starts when eligible; priority review starts as soon as a slot is available. |
The optional token cost (the "Pay the token cost" option, DOC-011) moves to its own branch, so every document action builds its token payment as before and this branch only adds the contract action fee agreement. The network's refusals of a missing or changed fee agreement now show the same text as the app's own check, which tells the user to reload the contract first, since either way the local copy may be out of date. The fee estimation imports sit in the file's top import block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
…ment action fee branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
Loading a contract that is already stored keeps the stored copy, so the fee agreement refusals and DOC-010 now tell the user to remove the contract on the Contracts screen and load it again, an action the app offers, instead of an unnamed reload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
Conflicts: platform_info.rs doc comment (kept base wording); protocol_13_transitions.rs deleted upstream, deletion kept. This PR's test there (a_fee_agreement_is_refused_on_protocol_13) exercised the SDK's protocol-13 encoding guard, not DET logic, so it is dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
|
Next steps: the updated #1117 head is merged into this branch locally and verified (fmt, clippy, area tests); it will be pushed right after #1117. Once #1117 merges, this PR gets retargeted to 🤖 Co-authored by Claudius the Magnificent AI Agent |
…tion-fees Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
…t-action-fees Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q
…fees Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WunYYhY7P2FJqHVgkHiXtT
…fees Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WunYYhY7P2FJqHVgkHiXtT
TL;DR: On networks running protocol 14, a contract can charge a fee for document actions. The app shows that fee, asks the user to agree to it, and sends exactly the action that was confirmed. When the network's fee multiplier rises past the agreed tolerance, the app updates the fee from a proved epoch, so the next try shows the new amount.
Stacked atop #1117.
User story
As a user acting on a document whose contract charges a fee, I want to see that fee and agree to it before anything is sent, so that I am never charged more than I accepted (DOC-010).
Scenario
Base flow
deletecharges an action fee priced by the fee multiplier.Actual
The app did not show contract action fees and sent no agreement to them, so the network refused every action of a contract that charges one.
Expected
Detailed discussion
src/model/fee_estimation.rs):document_action_fee_quotebuilds aDocumentActionFeeQuotefrom the document type's declaredactionFees. The quote holds the owner and moderator parts at the multiplier the user saw, the total, and the most it can become (max_total).ACTION_FEE_MULTIPLIER_INCREASE_TOLERANCE_PERCENT(20%).src/model/fee_estimation.rs,src/backend_task/document.rs):checked_action_fee_agreementrefuses an action whose agreement is missing, or names a fee other than the one the document type declares, before anything is signed (TaskError::ActionFeeAgreement).src/ui/contracts_documents/document_action_screen.rs): the action is built when the confirmation opens and stored with it (PendingActionFeeConfirmation), so confirming sends that exact action.DocumentActionFeeMultiplierNotToleratedrefusal triggers a proved epoch refresh through chore(deps)!: update Platform to v5.1-dev 063589bf and follow the network's protocol version #1114'srefresh_current_epoch.DocumentActionFeeMultiplierNotRefreshed), rather than that it was.src/backend_task/error.rs):DocumentActionFeeNotAgreedandDocumentActionFeeChanged(the network's refusals) show the same text as the app's ownActionFeeAgreementError::NotConfirmedandOutdated. Either way the app's copy of the contract may be out of date, and loading a contract that is already stored keeps the stored copy, so each tells the user to remove the contract on the Contracts screen and load it again.DocumentActionFeeMultiplierRosenames the known and current multipliers.DocumentActionFeeMultiplierNotRefreshedcovers a multiplier that could not be refreshed.feat/document-optional-token-cost.Testing
model::fee_estimation: quoting fixed and multiplier-priced fees (a_fixed_fee_is_charged_as_declared,a_multiplier_priced_fee_scales_and_names_the_tolerance, and others); refusing a missing or mismatched agreement (a_charged_fee_without_an_agreement_is_refused,an_agreement_to_another_fee_is_outdated).ui::contracts_documents::document_action_screen::tests:confirming_a_contract_fee_sends_the_action_it_was_shown_for;every_action_maps_to_its_document_transition.backend_task::document:a_fee_refusal_stands_once_the_epoch_is_refreshedanda_failed_epoch_refresh_says_the_fee_was_not_updated.backend_task::error: the refusal mappings inprotocol_v14_consensus_errors_map_to_their_variants, andfee_agreement_refusals_read_the_same_locally_and_from_the_network.cargo clippy --all-features --lib --tests -- -D warningsandcargo fmt --allpass.🤖 Co-authored by Claudius the Magnificent AI Agent
🤖 Generated with Claude Code
https://claude.ai/code/session_012ujJpB9DBhvtbjhYB3aG9Q