feat(intent_settlement): proportional slashing (#193), bid window (#191), dispute flow (#188), multi-bond-token (#187) - #314
Open
iam-mercy wants to merge 1 commit into
Conversation
…low, multi-bond-token Implements four High-priority settlement-hardening issues in one change set. They share the IntentState enum, slash_solver, fill_intent and the solver bond model, so they are delivered together. stellar-vortex-protocol#193 — Dynamic, proportional bond slashing slash_solver no longer takes a flat 10% of the bond. compute_slash_amount returns min(unfilled_output, bond) / 10, capped at 10% of the bond (never more punitive than the old baseline) and floored at 1 stroop (keeps issue stellar-vortex-protocol#32's non-zero-slash guarantee). Integer-only, cannot panic, caps at 100% of bond when the intent dwarfs it. SECURITY.md "Known Limitations" updated. stellar-vortex-protocol#191 — Competitive bid window Dedicated DataKey::BidWindowEnabled replaces the placeholder that reused DstAllowlistEnabled (a real storage-key collision — set_dst_allowlist_enabled could silently toggle bidding). New entrypoints: bid_intent (strictly-higher quotes only; ties keep the incumbent) and settle_bids (permissionless — promotes the winner to Accepted with a fresh fill window, or re-opens the intent as Open when no usable bid exists, mirroring expire_intent's materialisation pattern). set_bid_window_enabled / is_bid_window_enabled / get_best_bid round it out. stellar-vortex-protocol#188 — Dispute-resolution state machine (Filling -> Disputed -> Resolved) Per docs/dispute-resolution-design.md. begin_fill escrows a completing fill in the contract and opens DISPUTE_WINDOW; dispute_fill lets the user contest; resolve_dispute (arbiter-only, set_arbiter / get_arbiter, defaults to admin) rules Upheld (proportional slash, full escrow to user, no fee) or Dismissed (fee taken, no slash); release_fill is the permissionless clean-release and arbiter-timeout path. Escrow is always custodied by the contract, never the solver. New states Filling/Disputed/Resolved and enum DisputeResolution; every new error path has a uniquely-discriminated Error variant. stellar-vortex-protocol#187 — Multi-bond-token support with per-token accounting Per docs/60-multi-bond-token-design.md, implemented additively: DataKey::SolverBond(solver, token) holds per-token balances; SolverRecord keeps bond_amount as the default-token mirror (pre-stellar-vortex-protocol#187 readers and the bond-conservation proptest keep working) and gains bond_tokens: Vec<Address>. register_solver / withdraw_bond / accept_intent keep their signatures and gain *_with_token / *_token siblings. add_allowed_bond_token / set_bond_token_min / get_solver_bond(s) manage and expose it. slash_solver now slashes — and pays out — in intent.bond_token. deregister_solver refunds every token. Cap of MAX_BOND_TOKENS (8) per solver. Also de-duplicates fill_intent, whose output/fee transfer block had been written three times by a bad merge; it now transfers once, after state is committed (CEI). Tests: 25 new cases in test.rs covering all four features (proportional-slash disproportion scenarios + floor; no-bid/single-bid/multi-bid + allowlist collision regression; dispute happy/upheld/dismissed/timeout + escrow custody; multi-token register/slash/withdraw/deregister/cap/legacy). proptest_bond.rs's AcceptAndSlash step now asserts the proportional formula. Docs: README lifecycle diagram + function list, SECURITY.md, CHANGELOG.md [Unreleased] (storage-layout change noted), and both design docs' status. NOTE: main (c5da0fd) does not compile — a prior bad merge dropped ~15 DataKey variants, ~7 Error variants and ~12 constants, and left duplicate Error discriminants. This change adds zero new compile errors (still 67, all pre-existing) but CI stays red until main is repaired separately. closes stellar-vortex-protocol#193 closes stellar-vortex-protocol#191 closes stellar-vortex-protocol#188 closes stellar-vortex-protocol#187
|
@iam-mercy Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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
Implements four High-priority settlement-hardening issues in one change set.
They all touch the
IntentStateenum,slash_solver,fill_intentand thesolver bond model, so splitting them would mean four heavily-conflicting stacked
PRs; they're delivered together instead.
Filling → Disputed → Resolved)closes #193
closes #191
closes #188
closes #187
main(c5da0fd) failscargo checkwith 67 errors — a prior bad mergedropped ~15
DataKeyvariants, ~7Errorvariants and ~12 constants, leftduplicate
Errordiscriminants, and triplicated thefill_intenttransferblock. This is pre-existing and identical on
origin/mainandstellar-vortex-protocol/main.This PR adds zero new compile errors (still exactly 67, all pre-existing and
all outside the code added here), but CI will stay red until
mainisrepaired separately. Because the crate can't build, the new tests could not be
executed and the wasm/proptest/clippy jobs cannot pass from this base. Every
addition here was written to be internally consistent and to match house style;
it needs a green
mainto be fully verified.#193 — Proportional slashing
slash_solverno longer takes a flat 10 % of the bond. New helpercompute_slash_amount(bond, unfilled_amount):50 000. A minimally-bonded solver failing a huge intent is still capped at
10 % of bond (and at 100 % of bond via
exposure ≤ bond).SECURITY.md"Known Limitations" updated;solver_slashedevent unchanged.#191 — Competitive bid window
is_bid_window_enablednow reads a dedicatedDataKey::BidWindowEnabledinstead of borrowingDstAllowlistEnabled"as aplaceholder".
set_dst_allowlist_enabledandset_bid_window_enabledare nowfully independent (regression test included).
bid_intent(solver, intent_id, quoted_dst_amount)— reusesis_solver_eligible; records the bid only if strictly higher; tie-break:the first solver to a given amount keeps the lead.
settle_bids(intent_id)— permissionless. Winner →Acceptedwith a freshFILL_WINDOWandaccept_intent's bookkeeping (active_intents,OpenIntents). No usable bid (nobody bid, or the leader's bond droppedbelow the floor since bidding) → re-opened as
Openwith a freshINTENT_EXPIRY, matchingexpire_intent's permissionless-materialisationpattern rather than getting stuck in
Bidding.get_best_bidview added.#188 — Dispute-resolution state machine
Per
docs/dispute-resolution-design.md. New statesFilling,Disputed,Resolved; new enumDisputeResolution { Upheld, Dismissed }; newIntentRecordfieldsdispute_deadline,dispute_raised_at,resolution.begin_fillDISPUTE_WINDOW(1 h)dispute_fillFilling → Disputedwithin the windowresolve_disputeset_arbiter, defaults to admin)Upheld→ full escrow to user + proportional slash;Dismissed→ escrow − fee to user, no slashrelease_fillFilling+ window elapsed → clean release (fee taken);Disputed+ARBITER_WINDOW(24 h) elapsed → full escrow to user, no slash,resolution == Nonemarks the timeoutEscrowed tokens are held by the contract, never the solver; all state is
committed before any transfer (CEI). Every new error path has a
uniquely-discriminated
Errorvariant (30–39).#187 — Multi-bond-token support
Per
docs/60-multi-bond-token-design.md, implemented additively (the designdoc's "remove
bond_amount" schema would break every existing test and thebond-conservation proptest with no way to verify the refactor against a
non-compiling base):
DataKey::SolverBond(solver, token)holds per-token balances.SolverRecord.bond_amountis kept as the default-token mirror so pre-[High] Implement multi-bond-token support with per-token accounting #187readers keep working;
SolverRecord.bond_tokens: Vec<Address>enumerates therest (cap
MAX_BOND_TOKENS = 8).register_solver/withdraw_bond/accept_intentkeep their signatures(pinned to the default token) and gain
register_solver_with_token/withdraw_bond_token/accept_intent_with_bondsiblings ("Option A" fromthe design doc §7.2).
add_allowed_bond_token/remove_allowed_bond_token/set_bond_token_min/get_bond_token_min/get_solver_bond/get_solver_bonds.IntentRecord.bond_tokenrecords which token backs each accepted intent;slash_solverslashes and pays out in that token.deregister_solverrefunds every token the solver holds.
DataKey::MinBond(token), falling back toProtocolConfig.min_bondfor the default token andMIN_BONDotherwise.BondTokenNotAllowed = 40,TooManyBondTokens = 41(discriminantsdiffer from the design doc's §6 to avoid colliding with existing variants).
CHANGELOG.md[Unreleased]notes the storage-layout change and itsupgrade behaviour.
Also
fill_intent's output/fee transfer block had been written three times by abad merge (paying the user 3× and the fee 2×). De-duplicated to a single
transfer after all state is committed.
Tests
25 new cases in
test.rs:floor of 1.
Open, single-bid settlement,strictly-higher replacement,
set_dst_allowlist_enabledno longer touchesbid-window state.
release_fill), disputed→upheld (full refund + slash),disputed→dismissed (refund − fee, no slash), arbiter timeout, escrow custody.
refunds all, unapproved-token rejection, withdraw-below-minimum, token cap,
legacy single-token path unchanged.
proptest_bond.rs'sAcceptAndSlashstep now asserts the exact proportionalformula instead of the flat 10 %.