Pye Finance (via Hypotenuse Labs)
Principal / yield tokenization for ETH staking
Split an ETH staking position into independently tradable Principal (PT) and Yield (YT) tokens — Pendle-style — on top of StakeWise v3.
pye.fi ↗Stack
- Solidity 0.8.22
- Foundry
- ERC-20 (PT / YT)
- ERC-6093
- ERC-1967 Beacon proxy
- ERC-4626 (pattern)
- ERC-7540 (pattern)
- StakeWise v3
- WadRayMath
- Ethereum
Context
A staking position bundles two things: your principal and the yield it earns. Pye separates them into two tradable tokens. Depositing ETH stakes it in StakeWise v3 validators and mints a Principal Token (a 1:1 claim on your capital) and a Yield Token (a claim on the rewards earned until a maturity date).
What it does — the product
Principal holders keep capital liquidity (sell or borrow against PT without giving up the position); yield holders trade or hedge future staking returns (buy YT to go long yield, sell it to lock a rate). YT issued scales with time-to-maturity — one year ≈ 100% of principal in YT. At maturity, each tranche redeems against the yield actually generated.
Standards — the ERCs we used
Read straight from the contracts — what is implemented vs. what is followed as a design pattern:
- ERC-20implemented
Principal (PT) and Yield (YT) are two independent ERC-20 tranche tokens; mint/burn is restricted to their bond, and PT supports an optional transfer-lock before maturity.
- ERC-6093implemented
The token base uses the standardized ERC-20 custom errors (draft-IERC6093 / IERC20Errors) instead of revert strings.
- ERC-1967 · Beacon proxyimplemented
Every bond is a BeaconProxy, so all per-(vault, maturity) bonds share one upgradeable implementation behind a single beacon.
- ERC-4626pattern
Share↔asset accounting follows the tokenized-vault standard — convertToAssets, totalAssets, pricePerShare, previewShares — so a bond values PT/YT against the underlying staked ETH.
- ERC-7540pattern
Redemption is an async request→claim flow (requestUnstake → wait → unstake → redeem), the ERC-7540 shape that models StakeWise’s multi-day (~8 day) exit queue.
Architecture
A PyeRouter is the entry point and bond registry: it whitelists StakeWise validator vaults and mints a separate Bond per (validatorVault, maturity) pair via a BeaconProxy, keyed by keccak256(vault, maturity). Each bond stakes the ETH, mints the PT/YT pair, and manages the exit queue and redemptions.
Money flow — deposit
A deposit picks a validator vault and a maturity; the router creates the bond if it doesn’t exist yet, stakes the ETH into StakeWise, and mints the matching PT and YT to the depositor.
Money flow — maturity & redeem
Because StakeWise settles withdrawals through a multi-day exit queue, redemption is a two-step async flow: request the unstake (which enters the queue), wait for the ETH to settle, then redeem — PT pays out the principal and YT pays out the yield actually generated.
Contracts
- PyeRouterV1 — entry point + bond registry; whitelists validator vaults, mints bonds via
BeaconProxy, and exposesdeposit,requestUnstake,unstake,redeemwith configurablemintFee/redemptionFee(bps). - Bond — per (vault, maturity); stakes into StakeWise, mints/burns PT & YT, and runs the share/asset accounting and exit-queue handling.
- PT & YT — the two ERC-20 tranches (bond-gated mint/burn; PT with an optional transfer-lock).
- StakeWise v3 adapter — registers each bond as an access-managed entry on private validator vaults, stakes ETH, and routes the exit queue back to redemptions; fixed-point math via
WadRayMath.
My contribution
Designed and delivered the proof-of-concept end to end — the router, the BeaconProxy bond factory, the PT/YT token tranches, the ERC-4626/7540-style vault accounting and async exit-queue handling, the StakeWise v3 adapter, and the fee mechanics. Built on EVM before the team pivoted to SVM.