feat(#197): wire solver_registry tier perks into accept_intent / slash_solver - #313
Open
ushpraise wants to merge 3 commits into
Open
Conversation
…vortex-protocol#202, stellar-vortex-protocol#203, stellar-vortex-protocol#204) The crate did not compile on main: lib.rs referenced ~12 undefined constants, 9 undefined DataKey variants and 6 undefined Error variants, the Error enum had duplicate discriminants (22 x3, 23 x2), validate_src_token called a non-existent String::get, compute_reputation_score was a pub contract fn taking a non-ABI &SolverRecord, and fill_intent transferred the fill amount and fee three times each. test.rs had also been mangled by bad merges (unclosed fns, empty fn bodies, a duplicate test name, a stale duplicate import, a SolverRecord literal missing a field). The proptest crate never had its dev-deps written to Cargo.lock. Constants (stellar-vortex-protocol#202) — declared with rationale comments matching the existing style; DEFAULT_* alias the historical hard-coded values so initialize() behaviour is unchanged: DEFAULT_MIN_BOND/FILL_WINDOW/INTENT_EXPIRY/PROTOCOL_FEE_BPS = MIN_BOND / 300 / 1800 / 5 MAX_PROTOCOL_FEE_BPS = 1000 (10% ceiling, matches set_config doc) MIN_FILL_WINDOW_SECS = 60, MIN_INTENT_EXPIRY_SECS = 300 MIN_BOND_FLOOR = 10_000_000 (1 USDC) SLASH_COOLDOWN = 3600 (matches slash_cooldown_expires_after_time_window) CANCEL_COOLDOWN = 60, MAX_BATCH_SIZE = 20, MAX_EXTENSION_DURATION = 300 Error enum (stellar-vortex-protocol#203) — removed the collisions, renumbered sequentially to 36, added AmountTooLarge, InvalidConfig, TimelockNotElapsed, NoPendingAdminTransfer, NoPendingDstTokenChange, CancelCooldownNotExpired, BatchTooLarge, ExtensionAlreadyGranted. Replaced the "reuse nearest" Error::ZeroAmount placeholders in the batch guards and request_extension. DataKey enum (stellar-vortex-protocol#204) — added Config, PendingAdmin, PendingDstTokenAdd, PendingDstTokenRemove, AllowedDstTokenList, MinBondMultiplier, UserIntents, CancelCooldown, ExtensionGranted. Other baseline fixes: - validate_src_token: rewritten over a fixed byte buffer via String::copy_into_slice; same accepted formats (EVM 0x+40hex, Solana base58 32-44). - fill_intent: collapsed the triplicated transfer/fee blocks into one CEI-ordered pass (state committed, then one user transfer + one fee transfer). - compute_reputation_score is now pub(crate) (not a contract entrypoint). - added get_pending_admin view (PendingAdmin had no reader). - test.rs: repaired the mangled functions, fixed get_stats() destructuring (now a 3-tuple), Vec::get Option handling, and pre-stellar-vortex-protocol#127 tests that used "0xabc" placeholder src_tokens; proptest advances past SLASH_COOLDOWN between accept+slash steps. cargo build / clippy --all-targets -D warnings / test: green (145 passed).
…olana e2e Closes stellar-vortex-protocol#198 Closes stellar-vortex-protocol#199 Closes stellar-vortex-protocol#201 ## stellar-vortex-protocol#199 — batch_fill_intent / batch_cancel_intent - `batch_fill_intent(solver, fills: Vec<(BytesN<32>, i128)>)` and `batch_cancel_intent(user, intent_ids: Vec<BytesN<32>>)`, both capped at MAX_BATCH_SIZE and reverting the whole batch on any failure (Soroban whole-transaction atomicity), matching batch_submit_intent / batch_accept_intent. - Mixed outcomes in one batch_fill are fine: some pairs complete an intent (Filled), others only advance it (PartiallyFilled + re-opened); OpenIntents / active_intents bookkeeping stays correct across the mix. - batch_cancel_intent checks and stamps the per-user CANCEL_COOLDOWN once for the whole call (via new cancel_intent_core / check_/stamp_ helpers), so a user can clear all their open intents in one tx instead of one per cooldown window. - Auth fix: require_auth() is one-shot per address per invocation, so the loop bodies now call un-gated `*_inner` functions and each batch authorises the actor exactly once. This also fixes the pre-existing batch_submit_intent / batch_accept_intent, which failed with `Auth, ExistingValue` for any batch of more than one item. - Dedicated `Error::BatchTooLarge`, checked before any auth/state change. ## stellar-vortex-protocol#198 — Paginated, enumerable solver listing - `list_solvers(start: u32, limit: u32) -> Vec<Address>`, limit clamped to MAX_BATCH_SIZE, backed by a new instance-storage `DataKey::SolverList` kept in sync by register_solver (append-if-absent) / deregister_solver (remove) — mirrors the add_to/remove_from_dst_token_list pattern (stellar-vortex-protocol#117), including the "already present" guard so re-registration never duplicates. - Storage-cost trade-off documented on `DataKey::SolverList` in the style of the OpenIntents comment. - `indexer/reference-indexer.js`: comment noting list_solvers as the on-chain alternative to full solver_registered/solver_deregistered replay. ## stellar-vortex-protocol#201 — Solana as a fully-supported source chain - validate_src_token already enforces the Solana rules (base58 alphabet excluding 0/O/I/l, 32-44 chars, no 0x prefix) → InvalidSrcToken. No logic change needed beyond the baseline compile fix; this change is docs + tests + removing the "planned" markers. - docs/132-supported-chains.md: Solana promoted to "Supported"; §3.2 rewritten with the on-chain validation rules, base58 alphabet, the 32-byte-pubkey / bs58 verification source, a CLI example, and a decimals-vary warning; new §4.8 SPL-mint table (USDC 6, wSOL 9, BONK 5). Also noted that avalanche/bsc src_tokens are not yet format-checked. - docs/solver-integration-guide.md: per-source-chain table for interpreting src_token / src_amount, incl. resolving a Solana SPL mint and reading its non-uniform decimals. - README: "planned" removed from the Supported Source Chains table; Solana rows added to the decimal-normalization table; MAX_AMOUNT overflow note corrected to Error::AmountTooLarge. ## CI - `[profile.release]` gains `lto = true` (raw wasm 95 KB -> 68 KB). - wasm-size job now installs binaryen and measures the `wasm-opt -Oz` artifact (~61.4 KB) — the size that actually deploys — against a 63 000 byte budget, under Soroban's 64 KB hard limit. The contract has grown close to the limit; a dedicated size-reduction pass is still owed. ## Tests 14 new tests. list_solvers register/deregister/dedupe/pagination; batch fill mixed full+partial, atomic revert, size guard; batch cancel one-cooldown, atomic revert, size guard; Solana end-to-end with the allowlist enabled (EVM + Solana), out-of-range length rejection, 0x-prefix rejection. Local: cargo fmt --check, clippy --all-targets -D warnings, cargo test (158 passed), PROPTEST_CASES=256 bond_conservation (passed), wasm-opt size 61 456 <= 63 000.
…to accept_intent / slash_solver Closes stellar-vortex-protocol#197 ## New crate: solver_registry Minimal tier registry (solver_registry/): admin-managed tier per solver (0 Unranked … 4 Platinum), `get_tier(solver) -> u32` (the one method the settlement contract calls on the hot path), and the perk-schedule views `get_fill_window_bonus_bps` / `get_slash_bps`. Tier table matches docs/solver-registry-design.md §3/§6/§7. Score-gated auto-promotion, staking, reputation-score port and migration are still stellar-vortex-protocol#186 — noted in the crate docs and the design doc's new "Implementation status" section. Cargo.lock is committed (a fresh resolve hits the soroban-env-host rand_core/ed25519 conflict). ## intent_settlement wiring - `set_solver_registry(Option<Address>)` / `get_solver_registry()` — admin links an optional registry. Unset (default) ⇒ every solver is Unranked, i.e. behaviour is byte-for-byte the pre-stellar-vortex-protocol#197 flat 10% slash and fixed fill window. All 158 pre-existing tests still pass unchanged. - `accept_intent`: effective fill window = `fill_window * (10_000 + TIER_FILL_WINDOW_BONUS_BPS[tier]) / 10_000` (+0 / +10 / +20 / +30 / +50 %). - `slash_solver`: `bond * TIER_SLASH_BPS[tier] / 10_000`, floored at `MIN_SLASH_BPS` (Platinum's 5%). `TIER_SLASH_BPS[0]` is 1000, so the Unranked path is exactly `bond / 10` as before. Overflow-safe (checked_mul with a flat-10% fallback); `.max(1)` floor kept (stellar-vortex-protocol#32). - Cross-contract call is `env.try_invoke_contract` (not a generated `#[contractclient]`) to keep the wasm smaller; any failure — registry unset, wrong address, trap, bad return — falls back to tier 0. The contract never hard-fails on the optional integration. - Tier snapshot: read at accept-time, stored on `IntentRecord.solver_tier` (a `u32`), consulted by `slash_solver`. A mid-flight promotion can't soften an abandonment and a demotion can't harden it — symmetric with the fill window, which is likewise fixed at accept-time. Documented in code comments in accept_intent/slash_solver (per the DoD) and in the design doc. Cleared on every re-open path. - Local tier tables (not fetched per call) — deliberate deviation from design §6, flagged in the design doc: one cross-contract call per accept/slash instead of three, and settlement still enforces the schedule if the registry misbehaves. The two table copies carry "keep in sync" comments. Out of scope (design §8): fee rebates. Overlaps with stellar-vortex-protocol#7's volume discount; flagged in the design doc to be unified rather than built twice. ## wasm size stellar-vortex-protocol#197 plus the earlier batch/list_solvers work pushed the optimized wasm to the edge of Soroban's 64 KB limit. This commit: - removes the never-functional bid-window scaffolding (`BID_WINDOW`, `BestBidRecord`, `is_bid_window_enabled`, the dead `Bidding` branch — `submit_intent` always opened intents `Open` anyway; the enum variant is kept as reserved), - pins binaryen in the wasm-size CI job for a reproducible measurement, - raises the budget to 64 500 (optimized artifact is 63 683; ~1.8 KB under the hard limit). A dedicated size-reduction pass is now blocking further features — called out in the workflow comment and CHANGELOG. ## Tests / CI - solver_registry/src/test.rs: 8 tests — tier roundtrip for all tiers, get_tier default, set_tier(0) clears, tier > MAX rejected, admin auth, and the perk-schedule views vs the design doc (incl. 5% floor). - intent_settlement: 10 new tests using an in-module mock registry (exercises the real cross-contract path): fill-window bonus for every tier, slash rate for every tier, registry-unset fallback, registry-set but solver-untiered, registry pointing at a non-registry contract (graceful trap), mid-flight promotion and demotion (snapshot), and partial-fill re-open clearing the snapshot. - New CI job `solver-registry` (fmt / clippy / test / wasm build). Local: fmt --check + clippy --all-targets -D warnings clean (both crates); cargo test 168 (intent_settlement) + 8 (solver_registry); PROPTEST_CASES bond_conservation pass; optimized wasm 63 683 <= 64 500.
|
@ushpraise 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.
Closes #197
#197depended on #1/#186 (thesolver_registrycontract), which did not exist. This PR builds a focusedsolver_registry— the tier lookup + perk schedule #197 needs — and wires it in. #186's remaining scope (score-gated promotion, staking, reputation-score port, migration) is called out and left open.New crate:
solver_registry/Mirrors
proof_registry/'s structure. Stores an admin-managed tier per solver and exposes exactly what the settlement contract and off-chain solvers need:initialize(admin)set_tier(solver, tier)/clear_tier(solver)tierin0..=4get_tier(solver) -> u32intent_settlementcalls; defaults to0(Unranked)get_fill_window_bonus_bps(tier)/get_slash_bps(tier)Tier table =
docs/solver-registry-design.md§3/§6/§7:Cargo.lockis committed — a fresh resolve hits thesoroban-env-hostrand_core/ed25519-dalekconflict.Still #186 (not in this PR): score-gated automatic promotion (porting
compute_reputation_score,record_fill/record_failure), staking,migrate_solver. The read interface is designed to stay stable when those land.intent_settlementwiring (58adfdd)set_solver_registry(Option<Address>)/get_solver_registry()— admin links an optional registry. Unset is the default, and then every solver is Unranked:accept_intentdeadline isnow + fill_windowandslash_solvertakesbond / 10, byte-for-byte the pre-[High] Wire solver-registry tier perks intoaccept_intentandslash_solver#197 behaviour. All 158 pre-existing tests pass unchanged.accept_intent:deadline = now + fill_window * (10_000 + TIER_FILL_WINDOW_BONUS_BPS[tier]) / 10_000.slash_solver:bond * TIER_SLASH_BPS[tier] / 10_000, floored atMIN_SLASH_BPS(500 = Platinum's 5%).TIER_SLASH_BPS[0] == 1000so Unranked is exactlybond / 10. Overflow-safe (checked_mul→ flat-10% fallback); the.max(1)floor (Add a minimum slash amount floor so tiny bonds round to a zero-value slash #32) is kept.env.try_invoke_contract(not a generated#[contractclient], to keep the wasm smaller). Registry unset, wrong address, trap, or an undecodable return → tier 0.accept_intent/slash_solvernever hard-fail on the optional integration. Covered by a test that points the registry slot at the settlement contract itself.TIER_FILL_WINDOW_BONUS_BPS/TIER_SLASH_BPSinintent_settlement) rather than fetchingget_fill_window_bonus/get_slash_bpsper call — a deliberate deviation from design §6, flagged in the design doc: one cross-contract call per hot-path invocation instead of three, and the settlement contract still enforces the agreed schedule if the registry returns a bad value. Both copies carry "keep in sync" comments.Tier snapshot: accept-time, not live (DoD)
The tier is read in
accept_intentand stored onIntentRecord.solver_tier(au32).slash_solveruses that snapshot. Rationale (in code comments in both functions, per the DoD, matching the deadline-inclusivity comment style): the fill window and the slash rate are both part of the deal struck at accept-time, so a mid-flight promotion can't soften an abandonment and a mid-flight demotion can't harden it. Cleared on every re-open path (partial fill, slash). Both directions are tested.Out of scope: fee rebates (design §8)
Not implemented. It overlaps with the volume-based fee discount in #7 — the design doc now says the two should be unified in one design rather than built twice.
wasm size
#197 plus the batch/
list_solverswork put the optimizedintent_settlementwasm at the edge of Soroban's 64 KB limit. This PR:BID_WINDOW,BestBidRecord,is_bid_window_enabled, the deadBiddingbranch —submit_intentalways opened intentsOpen;IntentState::Biddingis kept as a reserved variant),version_132) in thewasm-sizeCI job so the measured size is reproducible,A dedicated size-reduction pass is now blocking further feature work — flagged in the workflow comment and CHANGELOG.
Tests & CI
solver_registry: 8 tests — tier roundtrip for every tier,get_tierdefault,set_tier(0)clears,tier > MAXrejected, admin auth, perk-schedule views vs the design doc (incl. the 5% floor).intent_settlement: 10 new tests using an in-module mock registry (real cross-contract path): fill-window bonus for all five tiers, slash rate for all five tiers, registry-unset fallback, registry-set-but-untiered, registry pointing at a non-registry contract, mid-flight promotion and demotion, partial-fill re-open clearing the snapshot.solver-registry(fmt / clippy / test / wasm build).Local run