Skip to content

refactor: stable slippage default#446

Draft
Seranged wants to merge 1 commit into
developmentfrom
fix/stable-slippage-default
Draft

refactor: stable slippage default#446
Seranged wants to merge 1 commit into
developmentfrom
fix/stable-slippage-default

Conversation

@Seranged

@Seranged Seranged commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Stable-to-stable swap contexts use the 0.05% default slippage in the settings modal and transaction slippage state.
  • Slippage remains available from global user settings and per-flow slippage modals; high custom overrides apply within the pair-default bucket where they were set.
  • Overrides at or below the active default remain usable across contexts; stale, future-dated, invalid, or pair-default mismatched high overrides fall back to the active default.
  • Existing swap-slippage* storage keys hydrate into the explicit override shape for compatibility and are cleared after migration/reset so old values do not resurrect.
  • Embedded borrow/pay-with and position supply/withdraw swap flows pass their selected swap token pair into the slippage context.
  • The active custom slippage chip uses the active-chip text color for both Custom and the value.

Slippage Product Behavior

Swap slippage defaults follow the selected swap token pair:

  • Stable-to-stable pairs (for example, USDC -> RLUSD) default to 0.05%.
  • Other pairs (for example, wstETH -> WETH) default to 0.3%.

The slippage control is globally accessible from user settings and is also available inside swap flows. Custom slippage is stored as a user override with the pair-default bucket where it was set:

  • A high custom value such as 3% applies within the same default bucket where the user set it.
  • A 3% override set from global settings or a normal 0.3% pair applies to normal 0.3% pairs, but does not carry into stable-to-stable 0.05% pairs.
  • A 3% override set from a stable-to-stable 0.05% flow applies to stable-to-stable pairs, but does not carry into normal 0.3% pairs.
  • High custom overrides reset to the active pair default after 24 hours.
  • Lower-than-default overrides such as 0.01% can carry across pair types and do not expire just because 24 hours passed.

Existing persisted swap-slippage* values hydrate into the current override model. Values with a stored stable 0.05% bucket remain custom on stable pairs, while values without a stored bucket hydrate as normal 0.3% overrides and fall back to the stable 0.05% default on stable pairs.

Changes

  • Adds swap-slippage-override as the source of truth for persisted custom slippage.
  • Uses explicit JSON serialization for the nullable override object.
  • Computes effective slippage from the active swap pair default plus the stored override, without writing default/effective values back as custom overrides.
  • Clears migrated legacy keys when the override is persisted, reset, expired, invalid, or pair-default mismatched.
  • Keeps context-mismatched stable overrides from being cleared before the swap context is available.
  • Keeps lower-than-default overrides active even after 24h, while high overrides expire after 24h within their pair-default context.
  • Expands useSlippage coverage for stable/non-stable pairs, override context changes, existing storage hydration, stale/future timestamps, invalid overrides, and clearing custom values equal to the active default.

Test plan

  • npm run test:run -- tests/composables/useSlippage.test.ts tests/utils/swap-slippage-validation.test.ts (28 passing tests)
  • npm run lint
  • npm run typecheck
  • git diff --check
  • Local Nuxt slippage settings smoke on 127.0.0.1:3082 with deterministic injected swap contexts:
    • stable context defaults to 0.05%
    • non-stable context defaults to 0.3%
    • stable context keeps a stable-context 3% override and shows resets to 0.05% default after 24h
    • non-stable context keeps a generic-context 3% override and shows resets to 0.3% default after 24h
    • stable context rejects a generic-context 3% override
    • non-stable context rejects a stable-context 3% override
    • stable and non-stable contexts keep stale 0.01% lower-than-default overrides
    • stale and future-dated stable-context 3% overrides fall back to 0.05%
    • existing stable-context swap-slippage* keys hydrate to Custom 3%
    • existing generic-context swap-slippage* keys fall back to stable 0.05%
    • migrated legacy overrides are written to swap-slippage-override as JSON
    • active Custom 3% chip renders matching dark text for label and value

Summary by CodeRabbit

  • Bug Fixes

    • Fixed slippage override expiry so expired custom settings are cleared and displayed state stays accurate.
  • New Features

    • Slippage now only applies when relevant tabs/forms are active, preventing unintended overrides.
    • Dynamic default slippage selection adapts for stablecoin vs non-stablecoin swaps.
  • Refactor

    • Centralized slippage logic for more consistent behavior and a minor visual tweak to the “Custom” slippage chip.
  • Tests

    • Added tests covering default selection and override expiry behavior.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Extract slippage predicates into exported helpers, refactor useSlippage to consume them with an optional enabled gate and improved override expiry cleanup, update SlippageSettings to use a computed isSlippageAboveDefault, add tests, and gate/parametrize useSlippage in borrow/multiply/collateral forms.

Changes

Slippage logic extraction and component integration

Layer / File(s) Summary
Extract slippage helper functions
composables/useSlippage.ts
New exported helpers isUsdStablecoin, isStablecoinSwapContext, getDefaultSlippageForContext, and isSlippageOverrideActive centralize stablecoin classification, default selection, and override expiry rules.
Refactor useSlippage to use helpers
composables/useSlippage.ts
UseSlippageOptions adds optional enabled predicate; composable now computes defaultSlippage, isOverrideActive, and effectiveSlippage via helpers, adds a runtime guard for enabled, and clears stale setAt/setAtPersisted when overrides expire.
Update SlippageSettings component
components/entities/swap/SlippageSettings.vue
Added isSlippageAboveDefault computed property, replaced direct constant comparison in template with it, and adjusted custom-chip styling for the displayed custom slippage value.
Gate and parametrize useSlippage at call sites
composables/borrow/useBorrowForm.ts, composables/borrow/useMultiplyForm.ts, composables/position/useCollateralForm.ts
Enable useSlippage only when the relevant form tab is active and derive fromSymbol/toSymbol conditionally based on whether a swap is required and the form mode.
Test slippage helper functions
tests/composables/useSlippage.test.ts
Vitest suite validates USD stablecoin classification, default slippage selection by context, and isSlippageOverrideActive behavior across expired/non-expired timestamps and stable/non-stable contexts.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • euler-xyz/euler-lite#304: Overlaps on SlippageSettings.vue and slippage-above-default UI logic tied to useSlippage default behavior.
  • euler-xyz/euler-lite#320: Touches SlippageSettings.vue styling and chip classes related to custom slippage display.

Suggested reviewers

  • kasperpawlowski
  • dglowinski

Poem

🐰 I hopped through helpers, clean and keen,
Extracted rules where slippage had been,
Forms now ask only when tabs are right,
Tests keep timestamps from lingering in night,
A little hop for UI, everything bright. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title 'refactor: stable slippage default' directly describes the primary focus of the changeset—extracting and refactoring slippage logic to use pair-context-aware defaults instead of a single global default.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/stable-slippage-default

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

@railway-app

railway-app Bot commented May 14, 2026

Copy link
Copy Markdown

🚅 Deployed to the euler-lite-pr-446 environment in euler-lite

Service Status Web Updated (UTC)
production-master-branch ✅ Success (View Logs) Web May 18, 2026 at 4:28 pm

@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 14, 2026 18:04 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from 6e3d000 to b35f8da Compare May 14, 2026 18:17
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 14, 2026 18:17 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from b35f8da to 57fe4ad Compare May 14, 2026 18:30
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 14, 2026 18:30 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from 57fe4ad to f834784 Compare May 14, 2026 18:36
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 14, 2026 18:36 Destroyed
@Seranged Seranged marked this pull request as ready for review May 15, 2026 08:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
tests/composables/useSlippage.test.ts (2)

21-29: ⚡ Quick win

Assert numeric defaults explicitly in this suite.

These expectations reuse DEFAULT_STABLECOIN_SLIPPAGE/DEFAULT_SLIPPAGE, so a constant regression can still pass here. Add at least one direct numeric assertion (e.g., 0.05 / 0.3) to pin product intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/composables/useSlippage.test.ts` around lines 21 - 29, The test
currently only asserts against the constants DEFAULT_STABLECOIN_SLIPPAGE and
DEFAULT_SLIPPAGE which could hide regressions; update the cases in the it('uses
0.05% as the default for stablecoin swap pairs', ...) block (the const cases
array) to include at least one explicit numeric expectation alongside the
constants—e.g., replace or add an entry that expects 0.05 for stablecoin pairs
and one that expects 0.3 for non-stablecoin pairs (referencing
DEFAULT_STABLECOIN_SLIPPAGE and DEFAULT_SLIPPAGE for clarity), and update the
assertion that iterates over cases to check the numeric literal as well as the
constant.

36-50: ⚡ Quick win

Add an exact-expiry boundary test.

The suite checks +1ms past expiry, but not the exact setAt + SLIPPAGE_EXPIRY_MS boundary. Add one assertion to lock in intended > vs >= behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/composables/useSlippage.test.ts` around lines 36 - 50, Add an
exact-expiry boundary assertion for isSlippageOverrideActive: after computing
setAt and expiredNow in the test (using SLIPPAGE_EXPIRY_MS), call
isSlippageOverrideActive(DEFAULT_SLIPPAGE, setAt, setAt + SLIPPAGE_EXPIRY_MS,
DEFAULT_STABLECOIN_SLIPPAGE) and assert the expected boundary behavior (i.e.,
that the override is still active at exactly setAt + SLIPPAGE_EXPIRY_MS if your
logic treats expiry as strictly greater than the window, or assert false if your
logic treats it as >=); place this single assertion alongside the existing
expiredNow check so the test documents the exact >= vs > behavior for
SLIPPAGE_EXPIRY_MS and the isSlippageOverrideActive function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/composables/useSlippage.test.ts`:
- Around line 21-29: The test currently only asserts against the constants
DEFAULT_STABLECOIN_SLIPPAGE and DEFAULT_SLIPPAGE which could hide regressions;
update the cases in the it('uses 0.05% as the default for stablecoin swap
pairs', ...) block (the const cases array) to include at least one explicit
numeric expectation alongside the constants—e.g., replace or add an entry that
expects 0.05 for stablecoin pairs and one that expects 0.3 for non-stablecoin
pairs (referencing DEFAULT_STABLECOIN_SLIPPAGE and DEFAULT_SLIPPAGE for
clarity), and update the assertion that iterates over cases to check the numeric
literal as well as the constant.
- Around line 36-50: Add an exact-expiry boundary assertion for
isSlippageOverrideActive: after computing setAt and expiredNow in the test
(using SLIPPAGE_EXPIRY_MS), call isSlippageOverrideActive(DEFAULT_SLIPPAGE,
setAt, setAt + SLIPPAGE_EXPIRY_MS, DEFAULT_STABLECOIN_SLIPPAGE) and assert the
expected boundary behavior (i.e., that the override is still active at exactly
setAt + SLIPPAGE_EXPIRY_MS if your logic treats expiry as strictly greater than
the window, or assert false if your logic treats it as >=); place this single
assertion alongside the existing expiredNow check so the test documents the
exact >= vs > behavior for SLIPPAGE_EXPIRY_MS and the isSlippageOverrideActive
function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: euler-xyz/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 67add0dd-255b-4be1-913b-45ef4bf1db26

📥 Commits

Reviewing files that changed from the base of the PR and between 7fcc092 and f834784.

📒 Files selected for processing (3)
  • components/entities/swap/SlippageSettings.vue
  • composables/useSlippage.ts
  • tests/composables/useSlippage.test.ts

@Seranged Seranged force-pushed the fix/stable-slippage-default branch from f834784 to 69bcf04 Compare May 18, 2026 11:16
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 18, 2026 11:16 Destroyed
@Seranged Seranged marked this pull request as draft May 18, 2026 11:18
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from 69bcf04 to b9f3e6f Compare May 18, 2026 11:45
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 18, 2026 11:45 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from b9f3e6f to bf2bff0 Compare May 18, 2026 11:54
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 18, 2026 11:56 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from bf2bff0 to af8a974 Compare May 18, 2026 13:15
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 18, 2026 13:15 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from af8a974 to 4ddd8e4 Compare May 18, 2026 13:27
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 18, 2026 13:27 Destroyed
@Seranged Seranged force-pushed the fix/stable-slippage-default branch from 4ddd8e4 to aa3d699 Compare May 18, 2026 15:45
@railway-app railway-app Bot temporarily deployed to euler-lite / euler-lite-pr-446 May 18, 2026 15:45 Destroyed
@Seranged Seranged changed the title fix: stable slippage default refactor: stable slippage default May 18, 2026
Make slippage override expiry use the active pair default so stale generic overrides do not mask the stablecoin 0.05% default. Align the settings copy with the same pair-aware default and cover stable/non-stable pair cases.
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.

1 participant