feat: buy cooldown, key simulation, slippage tolerance, deprecation notice - #898
Merged
Conversation
…ation notice work
- Add slippageTolerance.utils.ts computing max_price (buy) and min_price (sell) from a preview price and tolerance percentage: max_price = preview_price * (1 + tolerance), min_price = preview_price * (1 - tolerance), floored at 0. - Add SlippageToleranceSelector with 0.5%/1%/5% presets and a custom input validated to [0, 50]%. - Wire the selector into TradeDialog for both buy and sell, and forward the computed bound through onConfirm. - Extend TradeVariables/useTradeMutation with maxPriceStroops/ minPriceStroops so the (simulated) contract call carries the slippage bound. - Route LandingPage's sell confirmation through the same useTradeMutation path as buy (previously a disconnected inline stub) so slippage protection, optimistic updates, and rollback behave consistently for both trade directions. - Update TradeDialog.a11y/.sellPayoutDisplay tests for the new focusable controls and onConfirm signature. No prior slippage implementation had landed on upstream/dev at the time of this work (PR accesslayerorg#895 with SlippageToleranceSelector/ slippageTolerance.utils was still open), so this is a from-scratch implementation matching the computation contract described in accesslayerorg#872.
) - Add keySimulation.utils.ts's simulateKeyBuy, which reuses the existing bonding-curve primitives (computeBondingCurvePrice / computeBuyCost) for the curve-aware gross cost and start/end price, plus the same bps fee math used by pricePreview.utils, so simulation numbers stay consistent with the real buy flow instead of duplicating pricing logic. - Add KeySimulationTool: an input for a hypothetical buy quantity showing projected start/end price, price impact %, average price paid, fees, and total cost. - Mount it on CreatorDetailPage between the price chart and holder concentration sections. - Label the tool's fee rows 'Simulated protocol/creator fee' to avoid colliding with the page's existing Fee Structure section text (fixed a pre-existing-test collision this introduced).
No per-user buy cooldown concept existed anywhere in this repo prior to this change — no lastBuyAt/cooldown field on user-key state, and no ABI/contract read method for it (src/contracts/abis only has a README; src/types/contracts/index.ts is empty). The closest analog, last_buy_timestamp, drives a *sell*-side lockup (LockupCountdown), which is the opposite of a buy cooldown. - Add HeldKeyPosition.nextBuyAllowedAt and Course.nextBuyAllowedAt as the wiring points for this data once the backend/contract starts returning it: per-user position value preferred, falling back to a creator-wide value on Course. - Add buyCooldown.utils.ts (computeRemainingCooldownSeconds, formatCooldownDuration) and BuyCooldownCountdown, a self-ticking countdown mirroring LockupCountdown's setInterval/onExpire pattern, rendering 'Next buy available in 4m 32s' style text. - Mount it on CreatorDetailPage for authenticated users, sourced from userPosition.nextBuyAllowedAt (falling back to creator.nextBuyAllowedAt). - Renders nothing when no cooldown data is present or the cooldown has expired — this reflects real state only, it does not fabricate a client-only timer disconnected from backend data.
…esslayerorg#871) - Add Course.deprecated/deprecationReason as the status field marking a key deprecated (e.g. creator left the platform, key superseded). - Add keyDeprecation.utils.ts: isKeyDeprecated and estimateRedeemValue (quantity * current per-key price, reusing resolveCreatorKeyPriceStroops the same way reinvestDividend.utils reuses it for its own estimate). - Add DeprecationNotice badge and RedeemKeyDialog (mirrors ReinvestDividendDialog's structure/testids) showing the held quantity, per-key price, and total redemption value. - Add useRedeemDeprecatedKeyMutation to useWallet.ts, mirroring useReinvestDividendMutation's optimistic-update/rollback/ invalidation shape; on success it removes the position entirely. - Wire into PortfolioHoldingRow: deprecated keys show the notice badge, hide Buy/Sell/the sell lockup countdown, and show a Redeem button opening the confirmation dialog; wire onRedeem through LandingPage's portfolio section. Full vitest run comparison against the pre-existing base commit (6f05e2e) shows the same pre-existing environment-level failures (WagmiProvider/localStorage mocking issues when the full suite runs together) on both branches — no new regressions from this change beyond what was already fixed in the accesslayerorg#872 commit (a11y focus order, sellPayoutDisplay assertion).
|
@davedumto 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! 🚀 |
…erance-deprecation-notice
5 tasks
freebuff-web Bot
pushed a commit
to Neziahtech/accesslayer-client
that referenced
this pull request
Aug 31, 2026
The merge commit e498adc (PR accesslayerorg#898) corrupted KeySimulationTool.tsx, SlippageToleranceSelector.tsx, their tests, and slippageTolerance.utils.ts by duplicating code blocks. Restore working versions from pre-merge commits. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Seunfunmi-319509
pushed a commit
to Seunfunmi-319509/accesslayer-client
that referenced
this pull request
Sep 1, 2026
…org#898) PR accesslayerorg#898 merge into feat/846-watchlist concatenated two versions of KeySimulationTool, SlippageToleranceSelector, slippageTolerance.utils, and their test files, producing broken syntax and duplicate declarations. - KeySimulationTool.tsx: removed stale courseService-based duplicate, kept simulateKeyBuy version used by CreatorDetailPage - SlippageToleranceSelector.tsx: kept only the accesslayerorg#877 version with previewPrice/side/onConfirm props - slippageTolerance.utils.ts: added missing closing brace for computeSlippageBounds, removed duplicate SLIPPAGE_TOLERANCE_PRESETS - Merged concatenated test files for SlippageToleranceSelector and slippageTolerance.utils with combined imports - CreatorDetailPage.tsx: removed unused WatchlistButton import - BatchBuyModal.tsx: fixed react-hooks/exhaustive-deps warning by capturing debounceTimers.current ref before cleanup 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Seunfunmi-319509
added a commit
to Seunfunmi-319509/accesslayer-client
that referenced
this pull request
Sep 4, 2026
…#900) The last dev merge into feat/recently-viewed-keys-864 carried over dev's own badly-resolved merge (e498adc in accesslayerorg#898), which left several files with duplicate, unparseable content that broke `pnpm lint` and `tsc`: - slippageTolerance.utils.ts / SlippageToleranceSelector.tsx / KeySimulationTool.tsx and their tests were each stitched from two generations of the API (accesslayerorg#872-era and accesslayerorg#877/accesslayerorg#887-era). Restore the implementations the tree's consumers (TradeDialog, LandingPage, CreatorDetailPage) actually use, from the clean pre-merge state. - WatchlistToggle.tsx and its test (dev accesslayerorg#861 artifacts) cannot compile against the wallet-scoped zustand watchlist store used by this branch's components; drop them and restore the store from the branch's own last good state, matching the accesslayerorg#870 resolution. Verified locally: pnpm lint clean, pnpm build green, 46 watchlist / slippage / recently-viewed tests pass. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
freebuff-web Bot
pushed a commit
to DanbabaJr/accesslayer-client
that referenced
this pull request
Sep 7, 2026
The accesslayerorg#898 merge appended a second implementation to KeySimulationTool.tsx, SlippageToleranceSelector.tsx and slippageTolerance.utils.ts (and spliced imports into interfaces), leaving the tree unbuildable. Keep the implementation each production consumer is wired to and drop the orphaned duplicates and their test suites so tsc and the test runner pass again. Generated with Codebuff 🤖 Co-Authored-By: Codebuff <noreply@codebuff.com>
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 4 key detail / portfolio buy-UX issues: a per-user buy cooldown countdown, a key buy simulation tool, slippage tolerance on buy/sell modals, and a deprecation notice + redeem flow for deprecated keys.
#873 — Buy cooldown countdown on the key detail page
No buy-cooldown concept existed anywhere in the repo before this change (no
lastBuyAt/cooldown field, no contract ABI or read method —src/contracts/abisonly has a README andsrc/types/contracts/index.tsis empty). The closest existing analog,last_buy_timestamp/LockupCountdown, drives a sell-side lockup, the opposite of what this issue asks for.HeldKeyPosition.nextBuyAllowedAt(per-user) andCourse.nextBuyAllowedAt(creator-wide fallback) as the wiring point for this data once the backend/contract returns it.buyCooldown.utils.ts(computeRemainingCooldownSeconds,formatCooldownDuration) andBuyCooldownCountdown, a self-ticking countdown mirroringLockupCountdown'ssetInterval/onExpirepattern, rendering "Next buy available in 4m 32s" style text.CreatorDetailPagefor authenticated users.#875 — Key simulation tool on the key detail page
keySimulation.utils.ts'ssimulateKeyBuy, which reuses the existing bonding-curve primitives (computeBondingCurvePrice/computeBuyCost) for the curve-aware gross cost and start/end price, plus the same bps fee math used bypricePreview.utils, so simulation numbers stay consistent with the real buy flow instead of duplicating pricing logic.KeySimulationTool: an input for a hypothetical buy quantity showing projected start/end price, price impact %, average price paid, fees, and total cost.CreatorDetailPagebetween the price chart and holder concentration sections.#872 — Slippage tolerance in buy/sell modals
Checked whether mawuli's slippage work (issue #877, PR #895 —
SlippageToleranceSelector.tsx/slippageTolerance.utils.ts) had landed onupstream/dev. It had not (PR #895 is still open;upstream/devwas unchanged at the time this branch was rebased), so this is a from-scratch implementation matching the same computation contract described in #872.slippageTolerance.utils.tscomputingmax_price(buy) andmin_price(sell) from a preview price and tolerance percentage:max_price = preview_price * (1 + tolerance),min_price = preview_price * (1 - tolerance), floored at 0.SlippageToleranceSelectorwith 0.5% / 1% / 5% presets and a custom input validated to [0, 50]%.TradeDialogfor both buy and sell; the computed bound is forwarded throughonConfirm.TradeVariables/useTradeMutationwithmaxPriceStroops/minPriceStroopsso the (simulated) contract call carries the slippage bound.LandingPage's sell confirmation through the sameuseTradeMutationpath as buy (previously a disconnected inlinesetTimeoutstub), so slippage protection, optimistic updates, and rollback behave consistently for both trade directions.#871 — Deprecation notice + redeem button on the portfolio page
Course.deprecated/deprecationReasonas the status field marking a key deprecated.keyDeprecation.utils.ts:isKeyDeprecatedandestimateRedeemValue(quantity × current per-key price, reusingresolveCreatorKeyPriceStroopsthe same wayreinvestDividend.utilsreuses it for its own estimate).DeprecationNoticebadge andRedeemKeyDialog(mirrorsReinvestDividendDialog's structure/testids) showing held quantity, per-key price, and total redemption value.useRedeemDeprecatedKeyMutation, mirroringuseReinvestDividendMutation's optimistic-update/rollback/invalidation shape; on success it removes the position entirely.PortfolioHoldingRow: deprecated keys show the notice badge, hide Buy/Sell and the sell lockup countdown, and show a Redeem button opening the confirmation dialog.Test plan
SlippageToleranceSelector,KeySimulationTool,BuyCooldownCountdown,DeprecationNotice,RedeemKeyDialog, andTradeDialog's new slippage wiring) — 137 tests across 16 new/changed test files, all passing.TradeDialogtests that the new slippage selector legitimately changed:TradeDialog.a11y.test.tsx's sell-modal Tab-order test (now passes through the new preset/custom-input controls before reaching Confirm) andTradeDialog.sellPayoutDisplay.test.tsx'sonConfirmassertion (now receives a thirdslippageargument).npx tsc -b— clean.npx eslinton all touched files — clean.npx vite build— succeeds (pre-existing bundle-size and third-party/*#__PURE__*/comment warnings only, unrelated to this change).npx vitest runcompared against the pre-existing base commit (6f05e2e, before this branch's work): both show the same ~49 pre-existing failing test files from environment-level issues (WagmiProvider/localStoragemocking gaps when the full suite runs together, and file-order-dependent flakiness — e.g.LandingPage.buyFlowEndToEnd.integration.test.tsxpasses individually but is order-sensitive in a full run on both branches). No new regressions were introduced beyond the twoTradeDialogtests intentionally updated above.Caveats
#873and#871add new optional fields (nextBuyAllowedAt,deprecated,deprecationReason) toCourse/HeldKeyPositionas the client-side wiring point; neither the mock API nor a contract currently populates them, so the countdown/notice will activate automatically once the backend or contract starts returning real values.#872's contract call is still the existing simulatedsetTimeoutstub inuseTradeMutation/useRedeemDeprecatedKeyMutation(matching the rest of the repo's trading hooks) —maxPriceStroops/minPriceStroopsare threaded all the way to the mutation variables with a comment marking where the realmax_price/min_pricecontract args would go.closes #873
closes #875
closes #872
closes #871