Skip to content

feat: add PendlePTSlisBNBVaultAdapter for slisBNB unstake#70

Draft
Debugger022 wants to merge 3 commits into
developfrom
feat/VPD-1508
Draft

feat: add PendlePTSlisBNBVaultAdapter for slisBNB unstake#70
Debugger022 wants to merge 3 commits into
developfrom
feat/VPD-1508

Conversation

@Debugger022

@Debugger022 Debugger022 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Description

Adds PendlePTSlisBNBVaultAdapter, a slisBNB-specialized adapter that inherits the universal PendlePTVaultAdapter — the base adapter is untouched (no re-audit, minimal diff).

Problem

A user exiting a matured PT position via redeemAtMaturity receives slisBNB (the SY redeem token) and is left holding a liquid-staking token. To get native BNB 1:1 they must separately run Lista's async unstake (requestWithdraw → wait unbond ~7d → claimWithdraw).

Solution

  • requestWithdraw(pendleMarket, vTokenAmount, minSlisBnbOut) — one-tx withdraw → redeem → unstake. Redeems vTokens → PT 1:1 to slisBNB (to the adapter) → enqueues a Lista withdrawal request. Modifiers whenNotPaused nonReentrant onlyRegisteredMarket atOrAfterMaturity. Records uuid → msg.sender so funds return to the right user.
  • claimUnstaked(uuid) — permissionless finalizer; nonReentrant only (intentionally not pausable so funds are never trapped). Resolves the live Lista index fresh (Lista compacts via swap-pop), follows CEI (clears state before the external call), and forwards native BNB to the recorded owner.
  • Views: getUserUuids, getUnstakeRequest (exposes startTime/claimableAt for off-chain countdowns).

Design

  • slisBNB token, Lista StakeManager, and unbond period are child immutables (single-asset → no per-market unstake config). Works for any registered market whose PT redeems 1:1 to slisBNB (multiple maturities allowed).
  • Child storage appended after parent layout; own __gap for upgrade safety. Initializer inherited from parent.

Files

  • contracts/pendle-pt-fixed-rate-vault/PendlePTSlisBNBVaultAdapter.sol (new)
  • contracts/pendle-pt-fixed-rate-vault/interfaces/IPendlePTSlisBNBVaultAdapter.sol (new)
  • contracts/pendle-pt-fixed-rate-vault/interfaces/IListaStakeManager.sol (Lista interface)

Verification

  • npx hardhat compile — passes.
  • slither . — only informational findings, all consistent with the base adapter's established patterns (intentional balance-delta unused-return; reentrancy-benign guarded by nonReentrant; UPPER_CASE immutables). claimUnstaked flagged nothing — CEI + nonReentrant + sendValue-last hold.

Tests (fork + mock-Lista full request→claim cycle) to follow in a separate change.

Status

Done

  • Contract: PendlePTSlisBNBVaultAdapter (requestWithdraw + claimUnstaked + views)
  • Interface: IPendlePTSlisBNBVaultAdapter
  • npx hardhat compile passes
  • slither . reviewed — only informational findings

Remaining

  • Tests (fork + mock-Lista full request→claim cycle)
  • Deploy script
  • Documentation update

Extends PendlePTVaultAdapter with a one-tx withdraw->redeem->Lista
unstake entrypoint (requestWithdraw) and a permissionless claimUnstaked
that forwards native BNB to the original owner. slisBNB, Lista
StakeManager, and unbond period are child immutables; uuid->owner is
tracked so funds return to the right user. Base adapter untouched.
- Gate claims on Lista's bot-advanced nextConfirmedRequestUUID, the
  real on-chain condition, instead of the elapsed unbond period. Add
  isClaimable() and correct the interface docs, which described a
  time-based gate that does not exist.
- Handle requests the Lista bot claims on the adapter's behalf via
  claimWithdrawFor: the uuid leaves the adapter's request array and
  the BNB is pre-delivered, so claimUnstaked now forwards the amount
  snapshotted at request time rather than reverting and stranding
  funds. The snapshot avoids overpaying as slisBNB appreciates.
- Record each request in a struct keyed by uuid so views read in O(1)
  without scanning Lista's live array.
- Fix the storage gap (49 to 48 slots) to keep the child's reserved
- Exercise the requestWithdraw/claimUnstaked lifecycle against the
  real deployed Lista StakeManager and Pendle router on a BSC fork,
  so the adapter's on-chain assumptions are validated, not mocked.
- Cover the orphan path where Lista's bot claims via claimWithdrawFor:
  the request-time BNB snapshot is forwarded to the owner exactly,
  never recomputed (which would overpay as slisBNB appreciates).
- Run at a post-maturity block and reproduce the market registration
  and bot confirmation through getter-verified storage writes, since
  those states are unreachable on a fork by normal calls.
@github-actions

Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Health
contracts 100% 100%
contracts.DeviationSentinel 100% 100%
contracts.DeviationSentinel.Oracles 96% 93%
contracts.EmergencyBrake 0% 0%
contracts.Executor 0% 0%
contracts.Interfaces 100% 100%
contracts.LeverageManager 94% 80%
contracts.Libraries 29% 33%
contracts.PositionSwapper 0% 0%
contracts.RelativePositionManager 91% 64%
contracts.SwapHelper 100% 100%
contracts.SwapRouter 79% 55%
contracts.pendle-pt-fixed-rate-vault 0% 0%
contracts.pendle-pt-fixed-rate-vault.interfaces 100% 100%
contracts.pendle-pt-fixed-rate-vault.test 0% 0%
Summary 59% (942 / 1606) 47% (467 / 1004)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant