Contract Reference
Complete API reference for every ETH Strategy smart contract — function signatures, parameters, return values, access control, and revert conditions.
This is the canonical API reference for ETH Strategy smart contracts. Every public and external function is documented with a consistent template:
Signature → Parameters → Returns → Access Control → Reverts → Why It Exists
For integration patterns, production warnings, and working code examples, see the Integration Guide. For deployed addresses, see Contracts.
esETH
Non-rebasing ERC-20 wrapper around multiple liquid staking tokens (wstETH, rETH, cbETH, weETH, aWETH), pegged 1:1 with ETH. The denomination layer for the entire treasury.
Status: Deploying soon. Address will be published on the Contracts page before permissionless launch.
mint(address lst, uint256 amount, address recipient) → uint256 esEthAmount
mint(address lst, uint256 amount, address recipient) → uint256 esEthAmountDeposit a supported LST and receive esETH at a 1:1 ratio with the ETH value of the deposit.
lst
address
Address of the LST to deposit (wstETH, rETH, cbETH, weETH, or aWETH)
amount
uint256
Amount of the LST to deposit
recipient
address
Address to receive the minted esETH
esEthAmount
uint256
Amount of esETH minted
Caller
Any (permissionless)
Requires
Caller must have approved esETH contract to spend amount of lst
—
lst is not a supported token
—
amount is zero
ERC-20 revert
Caller has insufficient lst balance or allowance
Why: Primary entry point for adding collateral to the protocol. Wrapping multiple LSTs into a single non-rebasing token pegged 1:1 with ETH simplifies treasury accounting and enables a unified denomination layer across all protocol operations.
mint(address recipient) → uint256 esEthAmount
mint(address recipient) → uint256 esEthAmountDeposit raw ETH and receive esETH. The sent ETH is staked via the most favorable LST route.
recipient
address
Address to receive the minted esETH
esEthAmount
uint256
Amount of esETH minted
Caller
Any (permissionless)
Requires
msg.value > 0
—
msg.value is zero
Why: Convenience overload so users don't need to manually acquire an LST before minting. The contract routes ETH to the most favorable LST automatically.
redeem(address lst, uint256 esEthAmount, address recipient) → uint256 lstAmount
redeem(address lst, uint256 esEthAmount, address recipient) → uint256 lstAmountRedeem esETH for a supported LST held by the contract.
lst
address
Address of the desired LST to receive
esEthAmount
uint256
Amount of esETH to burn
recipient
address
Address to receive the LST
lstAmount
uint256
Amount of the LST returned
Caller
Any (permissionless)
Requires
Caller must hold esEthAmount of esETH
—
lst is not a supported token
—
Contract does not hold enough of the requested LST
—
Caller has insufficient esETH balance
Why: Allows exit from the esETH wrapper back to individual LSTs. Exchange rate is the LST's native rate, not a market price. Redemption depends on contract holdings — if the treasury has rebalanced, a specific LST may have insufficient balance.
ethPerEsEth() → uint256
ethPerEsEth() → uint256Returns the ETH value of 1 esETH (in wei, 18 decimals). Always returns 1e18 (1:1 peg).
Caller
Any (view)
Why: The canonical pricing function for esETH. This always returns 1e18 because esETH is pegged 1:1 with ETH — yield from underlying LSTs is harvested separately and does not accrete to the exchange rate. Use this for collateral valuation, lending markets, and portfolio display — never use AMM spot price for fair value.
previewMint(address lst, uint256 lstAmount) → uint256 esEthAmount
previewMint(address lst, uint256 lstAmount) → uint256 esEthAmountPreview: returns the esETH amount that would be minted for a given LST deposit.
lst
address
Address of the LST
lstAmount
uint256
Amount of the LST
esEthAmount
uint256
Equivalent esETH that would be minted
Caller
Any (view)
Why: Allows UIs and smart contracts to display expected output before executing a mint. Essential for slippage protection and user-facing previews.
previewRedeem(address lst, uint256 esEthAmount) → uint256 lstAmount
previewRedeem(address lst, uint256 esEthAmount) → uint256 lstAmountPreview: returns the LST amount that would be returned for a given esETH redemption.
lst
address
Address of the LST
esEthAmount
uint256
Amount of esETH to redeem
lstAmount
uint256
Equivalent LST that would be returned
Caller
Any (view)
Why: Pre-flight check for redemptions. Critical because redemption depends on contract holdings — previewRedeem() reveals whether the requested LST has sufficient balance before executing.
Standard ERC-20 + ERC-2612
esETH implements the full ERC-20 interface with ERC-2612 permit support.
balanceOf(address) → uint256
Token balance (non-rebasing — never changes except on transfer/mint/burn)
transfer(address to, uint256 amount) → bool
Standard transfer
approve(address spender, uint256 amount) → bool
Standard approval
transferFrom(address from, address to, uint256 amount) → bool
Standard delegated transfer
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
Gasless approval via off-chain signature
totalSupply() → uint256
Total esETH in circulation
allowance(address owner, address spender) → uint256
Current spending allowance
Name
esETH
Symbol
esETH
Decimals
18
Rebasing
No
Ownership
Ownable2Step (protocol multisig)
STRAT
ERC-20 equity token with ERC-2612 permit. Does not rebase. Only minted through convertible note conversion.
Name
ETH Strategy
Symbol
STRAT
Decimals
18
Standard
ERC-20 with ERC-2612 permit
Compiler
Solidity v0.8.20, 999,999 optimization runs, Paris EVM
Inherits
MintableBurnableToken → ERC20Permit → Ownable2Step
Ownership
Ownable2Step (protocol multisig)
mint(address to, uint256 amount)
mint(address to, uint256 amount)Mint new STRAT tokens.
to
address
Recipient of the minted tokens
amount
uint256
Amount to mint
Caller
Authorized minter contracts only (ConvertibleNote)
—
Caller is not an authorized minter
—
to is the zero address
Why: STRAT has no inflation schedule and no emission mechanism. New STRAT only enters circulation when a note holder exercises conversion rights. This restricted minting is the fundamental supply guarantee — STRAT supply only grows when someone converts debt to equity.
burn(uint256 amount)
burn(uint256 amount)Burn STRAT tokens from the caller's balance.
amount
uint256
Amount to burn
Caller
Any holder (burns from msg.sender)
—
Caller has insufficient balance
Why: Public burn function — any holder can destroy their own STRAT. Also used by authorized contracts for protocol operations.
burnFrom(address from, uint256 amount)
burnFrom(address from, uint256 amount)Burn STRAT tokens from another address using an allowance.
from
address
Address to burn from
amount
uint256
Amount to burn
Caller
Any address with sufficient allowance from from
—
Caller has insufficient allowance
—
from has insufficient balance
Why: Allowance-based burn — used by TreasuryLend to burn STRAT collateral at loan origination. On successful repayment, equivalent STRAT is re-minted. This burn-at-origination model eliminates the need for collateral escrow.
manageMinter(address minter, bool authorized)
manageMinter(address minter, bool authorized)Add or remove an authorized minter address.
minter
address
Address to authorize or revoke
authorized
bool
true to authorize, false to revoke
Caller
Owner only (protocol multisig via Ownable2Step)
Why: Governance control over which contracts can create new STRAT. In practice, only the ConvertibleNote contract is an authorized minter. This is checked before every mint operation.
Standard ERC-20 + ERC-2612
balanceOf(address) → uint256
Token balance
transfer(address to, uint256 amount) → bool
Standard transfer
approve(address spender, uint256 amount) → bool
Standard approval
transferFrom(address from, address to, uint256 amount) → bool
Standard delegated transfer
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
Gasless approval via off-chain signature
totalSupply() → uint256
Total STRAT supply — increases only through note conversion
allowance(address owner, address spender) → uint256
Current spending allowance
nonces(address owner) → uint256
Permit nonce tracking
CDT (Convertible Debt Token)
Fungible ERC-20 representing protocol debt. Each CDT = ~$1 of debt. totalSupply() = total protocol debt.
Status: Deploying soon. Address will be published on the Contracts page before permissionless launch.
Name
ETH Strategy Debt
Symbol
CDT
Decimals
18
Standard
ERC-20 with ERC-2612 permit
Ownership
Ownable2Step (protocol multisig)
Minting
Restricted to authorized minter contracts (ConvertibleNote, TreasuryLend)
mint(address to, uint256 amount)
mint(address to, uint256 amount)Mint new CDT tokens.
to
address
Recipient of the minted CDT
amount
uint256
Amount to mint (1 CDT per ~$1 of notional)
Caller
Authorized minter contracts only (ConvertibleNote, TreasuryLend)
—
Caller is not an authorized minter
Why: CDT is minted during convertible note bonding (new debt) and when treasury lending borrowers repay (restoring previously burned CDT). Restricted minting ensures protocol debt cannot be inflated arbitrarily.
burn(address from, uint256 amount)
burn(address from, uint256 amount)Burn CDT tokens.
from
address
Address to burn from
amount
uint256
Amount to burn
Caller
Authorized contracts (ConvertibleNote burns on conversion/redemption, TreasuryLend burns collateral)
—
Caller is not authorized
—
from has insufficient balance
Why: CDT is destroyed through three paths: conversion (before expiry), redemption (after expiry), and treasury lending collateral deposit. Each burn reduces total protocol debt.
manageMinter(address minter, bool authorized)
manageMinter(address minter, bool authorized)Add or remove an authorized minter address.
minter
address
Address to authorize or revoke
authorized
bool
true to authorize, false to revoke
Caller
Owner only (protocol multisig via Ownable2Step)
Why: Governance control over which contracts can create or destroy CDT. In practice, ConvertibleNote and TreasuryLend are the only authorized minters.
Standard ERC-20 + ERC-2612
balanceOf(address) → uint256
CDT balance (does not accrue interest)
transfer(address to, uint256 amount) → bool
Standard transfer
approve(address spender, uint256 amount) → bool
Standard approval
transferFrom(address from, address to, uint256 amount) → bool
Standard delegated transfer
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
Gasless approval — enables single-tx conversion and redemption
totalSupply() → uint256
Total protocol debt in USD terms
allowance(address owner, address spender) → uint256
Current spending allowance
EthStrategyConvertibleNote
Bonding, note issuance, conversion, and redemption. Issues CDT + NFT pairs on bonding; settles them on conversion or redemption.
Status: Deploying soon. Address will be published on the Contracts page before permissionless launch.
bond(address recipient, uint256 minConversionAmountStrat, uint256 minConversionAmountEth, uint256 deadline) → uint256 tokenId
bond(address recipient, uint256 minConversionAmountStrat, uint256 minConversionAmountEth, uint256 deadline) → uint256 tokenIdPurchase a USD-denominated convertible note by sending ETH. Receives CDT + NFT option.
recipient
address
Address to receive CDT and NFT
minConversionAmountStrat
uint256
Minimum STRAT entitlement (slippage protection)
minConversionAmountEth
uint256
Minimum esETH entitlement (slippage protection)
deadline
uint256
Transaction deadline (block.timestamp must be ≤ deadline)
tokenId
uint256
The minted NFT token ID
Caller
Any (permissionless, payable)
Requires
msg.value > 0
NoEthSent
msg.value is zero
ZeroAddress
recipient is address(0)
TransactionStale
block.timestamp > deadline
InsufficientOutput
Conversion entitlements fall below specified minimums
InvalidTimelockOrExpiry
Computed timelock/expiry values are invalid
Why: The protocol's primary growth mechanism. Notes are USD-denominated — the buyer sends ETH, which is priced in USD via an ETH/USD oracle and acquired for the treasury. The buyer receives composable debt (CDT, 1 per ~$1 USD notional) and conversion rights (NFT) — a structure borrowed from TradFi convertible bonds, decomposed into DeFi primitives. Zero-interest debt is possible because the conversion option itself is the buyer's compensation.
convertToStrat(uint256 tokenId, uint256 cdtAmount)
convertToStrat(uint256 tokenId, uint256 cdtAmount)Convert note to STRAT before expiry. Burns CDT, mints STRAT.
tokenId
uint256
NFT token ID
cdtAmount
uint256
Amount of CDT to burn (partial exercise supported)
Caller
ownerOf(tokenId) only — NFT approvals are NOT accepted
Requires
CDT approved or permitted to the contract
TimelockActive
Timelock hasn't passed (~6.9 days after bonding)
OptionExpired
Past expiry (~4.2 years) — use redeem() instead
NotOwnerOrApproved
Caller is not the NFT owner
InvalidExerciseAmount
cdtAmount is 0 or exceeds remaining amountOwedCdt
Why: The equity conversion path. The holder exchanges debt for newly minted STRAT, betting on appreciation. Pro-rata esETH backing moves from encumbered to unencumbered holdings, freeing capital for protocol operations — creating a positive flywheel between conversion activity and available lending capital.
convertToEth(uint256 tokenId, uint256 cdtAmount)
convertToEth(uint256 tokenId, uint256 cdtAmount)Convert note to esETH before expiry. Burns CDT, transfers esETH from treasury.
tokenId
uint256
NFT token ID
cdtAmount
uint256
Amount of CDT to burn (partial exercise supported)
Caller
ownerOf(tokenId) only
Requires
CDT approved or permitted to the contract
TimelockActive
Timelock hasn't passed
OptionExpired
Past expiry
NotOwnerOrApproved
Caller is not the NFT owner
InvalidExerciseAmount
cdtAmount is 0 or exceeds remaining amountOwedCdt
Why: The risk-off conversion path. The holder exits into ETH-denominated value without selling STRAT on the open market. esETH moves from encumbered → unencumbered → holder's address.
redeem(uint256 tokenId, uint256 minEthOut)
redeem(uint256 tokenId, uint256 minEthOut)Redeem CDT for USD notional value in esETH after expiry.
tokenId
uint256
NFT token ID
minEthOut
uint256
Minimum esETH to receive (slippage protection against oracle movement)
Caller
ownerOf(tokenId) only
TimelockActive
Timelock hasn't passed
OptionUnexpired
Note hasn't expired yet — use conversion instead
NotOwnerOrApproved
Caller is not the NFT owner
InsufficientOutput
esETH output is below minEthOut
Why: The maturity settlement. After ~4.2 years, conversion rights expire and the holder redeems at USD face value. Single-shot: settles the entire remaining position, burns both CDT and NFT. Pro-rata if the protocol is underwater — all CDT holders treated pari passu.
convertToStratWithPermit(uint256 tokenId, uint256 cdtAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
convertToStratWithPermit(uint256 tokenId, uint256 cdtAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)Combine CDT approval and STRAT conversion in one transaction via ERC-2612 permit.
tokenId
uint256
NFT token ID
cdtAmount
uint256
Amount of CDT to burn
deadline
uint256
Permit signature deadline
v, r, s
uint8, bytes32, bytes32
ERC-2612 permit signature
Caller
ownerOf(tokenId) only
Why: Gas optimization — saves one transaction by combining CDT approval with conversion. Same mechanics as convertToStrat() with an inline permit.
convertToEthWithPermit(uint256 tokenId, uint256 cdtAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
convertToEthWithPermit(uint256 tokenId, uint256 cdtAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)Combine CDT approval and esETH conversion in one transaction.
Same parameters and access control as convertToStratWithPermit. Mechanics match convertToEth().
redeemWithPermit(uint256 tokenId, uint256 minEthOut, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
redeemWithPermit(uint256 tokenId, uint256 minEthOut, uint256 deadline, uint8 v, bytes32 r, bytes32 s)Combine CDT approval and post-expiry redemption in one transaction.
Same access control as redeem(). Adds permit parameters for gasless CDT approval.
conversionEntitlements(uint256 ethAmount) → (uint256 stratAmount, uint256 ethEntitlement, uint256 settlementUsd)
conversionEntitlements(uint256 ethAmount) → (uint256 stratAmount, uint256 ethEntitlement, uint256 settlementUsd)Preview conversion entitlements for a given ETH amount without executing.
ethAmount
uint256
Amount of ETH (in wei) to preview
stratAmount
uint256
STRAT conversion entitlement
ethEntitlement
uint256
esETH conversion entitlement
settlementUsd
uint256
USD notional (CDT amount)
Caller
Any (view)
Why: Essential pre-flight check. Shows exact note terms (in USD) before sending ETH. If the protocol is underwater, ethEntitlement will be zero — this function makes that transparent upfront.
notes(uint256 tokenId) → Note
notes(uint256 tokenId) → NoteReturns the full state of a convertible note.
conversionEntitlementStrat
uint256
STRAT claimable via conversion
conversionEntitlementEth
uint256
esETH claimable via conversion
settlementEntitlementUsd
uint256
USD notional for post-expiry redemption
amountOwedCdt
uint256
CDT required for full exercise (decrements on partial exercise)
expiry
uint256
Timestamp after which conversion closes
timelock
uint256
Timestamp before which conversion is blocked
Caller
Any (view)
Why: On-chain transparency for note positions. UIs, dashboards, and integrators query this to display note details, calculate remaining value, and determine which actions are available.
releaseEncumbrance(uint256 tokenId)
releaseEncumbrance(uint256 tokenId)Move an expired note's backing esETH from encumbered to unencumbered holdings.
tokenId
uint256
NFT token ID (must be expired)
Caller
Owner only (protocol multisig)
EncumbranceAlreadyReleased
Encumbrance was already released for this note
—
Note has not expired
Why: Administrative function to free protocol liquidity. After a note expires, its backing esETH remains encumbered until released. This allows the protocol to reclaim capital from expired but unredeemed notes without affecting the holder's redemption rights.
StakedStrat (sSTRAT-v2)
On-chain STRAT staking with 7-day anti-frontrunning reward streaming. Accepts STRAT deposits, streams esETH rewards.
Status: Deploying soon. Address will be published on the Contracts page before permissionless launch.
Receipt Token
sSTRAT-v2 (ERC-20 with transfers disabled)
Reward Token
esETH
Stream Duration
7 days
Reentrancy
All state-changing functions guarded by nonReentrant
Ownership
Ownable2Step (protocol multisig)
stake(uint256 amount)
stake(uint256 amount)Stake STRAT tokens. Receives sSTRAT-v2 1:1.
amount
uint256
Amount of STRAT to stake
Caller
Any (permissionless)
Requires
Caller must have approved StakedStrat to spend amount of STRAT
ZeroAmount
amount is 0
ERC-20 revert
Insufficient STRAT balance or allowance
Why: Entry point for earning protocol revenue. Staking locks STRAT in the contract and issues a non-transferable receipt. Automatically calls syncRewards() before staking to ensure accurate reward accounting.
unstake(uint256 amount)
unstake(uint256 amount)Unstake STRAT tokens. Burns sSTRAT-v2 proportionally.
amount
uint256
Amount of STRAT to unstake
Caller
Any (must have staked position)
ZeroAmount
amount is 0
InsufficientStake
amount exceeds staked balance
Why: No lock period — unstaking is always available. Automatically claims all pending esETH rewards before reducing the stake, so nothing is forfeited. The 7-day streaming design makes frontrunning uneconomical without requiring lockups.
claim()
claim()Claim accrued esETH rewards without changing staked position.
Caller
Any (must have staked position)
Why: Allows stakers to collect earned yield without modifying their position. Returns silently if no rewards are pending.
syncRewards()
syncRewards()Detect new esETH in the contract and start/extend the reward stream.
Caller
Any (permissionless)
Why: The mechanism that enables anti-frontrunning. When esETH arrives at the contract, syncRewards() detects the new balance and begins a 7-day linear stream. New rewards blend with any active stream using a value-weighted average duration. Called automatically by stake(), unstake(), claim(), and migrateStake() — but anyone can call it directly.
migrateStake(address to, uint256 amount)
migrateStake(address to, uint256 amount)Move staked position to a new address without unstaking.
to
address
Destination address
amount
uint256
Amount to migrate (0 = full balance)
Caller
Any (must have staked position)
—
to is zero address, caller, or the contract itself
InsufficientStake
amount exceeds staked balance
Why: Wallet rotation without leaving the reward stream. Pays out the recipient's pending rewards during migration to prevent accounting corruption. Migrated rewards are proportional to the migrated stake amount.
getPendingRewards(address account) → uint256
getPendingRewards(address account) → uint256View pending (claimable) esETH rewards for an account.
account
address
Address to check
—
uint256
Pending esETH rewards in wei
Caller
Any (view)
Why: Dashboard and UI function. May undercount if new rewards arrived but syncRewards() hasn't been called — for accurate readings, call syncRewards() first in a static call.
StratETHTreasuryLend
Fixed-rate, fixed-term esETH lending against STRAT + CDT collateral. Positions represented as ERC-721 NFTs.
Status: Roadmap — Q2 2026. Will be audited and deployed separately from the core protocol launch.
Position Token
ERC-721 (transferable)
Collateral
STRAT + CDT (burned at origination)
Borrow Asset
esETH
Rate Model
Fixed rate, snapshotted at origination
Liquidation
Time-based only (after expiry) — no price-based liquidation
Reentrancy
All state-changing functions guarded by nonReentrant
Ownership
Ownable2Step (protocol multisig)
borrow(uint256 maxStratIn, uint256 maxCdtIn, uint256 minBorrowAmount, uint256 deadline) → uint256 tokenId
borrow(uint256 maxStratIn, uint256 maxCdtIn, uint256 minBorrowAmount, uint256 deadline) → uint256 tokenIdOpen a loan position. Burn STRAT + CDT collateral, receive esETH.
maxStratIn
uint256
Maximum STRAT to deposit as collateral
maxCdtIn
uint256
Maximum CDT to deposit as collateral
minBorrowAmount
uint256
Minimum esETH to receive (slippage protection)
deadline
uint256
Transaction deadline
tokenId
uint256
The minted position NFT
Caller
Any (permissionless)
Requires
Caller must hold sufficient STRAT and CDT, both approved to the contract
ZeroAmount
Either collateral input is zero
InsufficientOutput
Computed borrow amount < minBorrowAmount
TransactionStale
block.timestamp > deadline
Why: Allows STRAT holders to access ETH liquidity without selling, at a fixed rate with no liquidation risk during the term. The interest paid by borrowers flows to STRAT stakers, creating real yield from real demand. Serves as a natural escape valve — any STRAT holder can borrow against NAV-backed value.
repay(uint256 tokenId)
repay(uint256 tokenId)Repay a loan before expiry. Returns principal + accrued interest, re-mints STRAT + CDT collateral.
tokenId
uint256
Position NFT token ID
Caller
ownerOf(tokenId) only
Requires
Caller must hold sufficient esETH for principal + accrued interest
LoanExpired
block.timestamp >= expiry — only liquidation remains
NotOwnerOrApproved
Caller is not the position NFT owner
Why: Early repayment is cheaper — interest accrues linearly, so repaying at the halfway point costs half the maximum interest. Accrued interest flows to stakers; unused interest reserve returns to unencumbered holdings. STRAT and CDT collateral is re-minted to the borrower.
roll(uint256 tokenId, uint256 additionalStrat, uint256 additionalCdt, uint256 minBorrowAmount, uint256 deadline)
roll(uint256 tokenId, uint256 additionalStrat, uint256 additionalCdt, uint256 minBorrowAmount, uint256 deadline)Roll an existing position: settle accrued interest, adjust collateral, recompute terms, reset term.
tokenId
uint256
Position NFT token ID
additionalStrat
uint256
Additional STRAT to add (0 to keep same or reduce)
additionalCdt
uint256
Additional CDT to add (0 to keep same or reduce)
minBorrowAmount
uint256
Minimum esETH to receive after rolling
deadline
uint256
Transaction deadline
Caller
ownerOf(tokenId) only
LoanExpired
Position has already expired
TransactionStale
block.timestamp > deadline
InsufficientOutput
New borrow amount < minBorrowAmount
Why: Avoids the gas and friction of close-then-reopen. Settles accrued interest, adjusts collateral, recomputes terms at current governance parameters (which may have changed), and resets the term clock — all in one transaction, preserving the same NFT.
liquidate(uint256 tokenId)
liquidate(uint256 tokenId)Liquidate an expired position. Permissionless — anyone can call after expiry.
tokenId
uint256
Position NFT token ID
Caller
Any (permissionless, after expiry only)
—
block.timestamp < expiry (loan not yet expired)
Why: Time-based liquidation — no price oracles, no flash-loan manipulation, no cascading liquidations. On liquidation: full-term interest goes to stakers, delinquent fee goes to unencumbered holdings (increasing ethPerStrat), collateral is forfeited, position NFT is burned. The liquidator receives nothing — liquidation is a public good.
previewBorrow(uint256 maxStratIn, uint256 maxCdtIn) → (uint256 stratIn, uint256 cdtIn, uint256 ethBacking, uint256 borrowAmount, uint256 maxTermInterest, uint256 delinquentFee)
previewBorrow(uint256 maxStratIn, uint256 maxCdtIn) → (uint256 stratIn, uint256 cdtIn, uint256 ethBacking, uint256 borrowAmount, uint256 maxTermInterest, uint256 delinquentFee)Preview loan terms without executing.
maxStratIn
uint256
Maximum STRAT collateral
maxCdtIn
uint256
Maximum CDT collateral
stratIn
uint256
Actual STRAT that would be consumed
cdtIn
uint256
Actual CDT that would be consumed
ethBacking
uint256
Total ETH backing of the deposited STRAT
borrowAmount
uint256
esETH loan amount
maxTermInterest
uint256
Maximum interest over the full term
delinquentFee
uint256
Fee reserved for default penalty
Caller
Any (view)
Why: Pre-flight check showing exact loan terms. The invariant always holds: borrowAmount + maxTermInterest + delinquentFee = ethBacking. Essential for UIs to display terms before the user commits collateral.
ESPN (EthStrategyPerpetualNote)
ERC-4626 tokenized vault. Deposit USDS, receive ESPN shares.
Name
ETH Strategy Perpetual Note
Symbol
ESPN
Standard
ERC-4626
Deposit Asset
USDS
Deposit Cap
Governance-configurable
Withdrawals
May be disabled by governance; check maxWithdraw()
Compiler
Solidity v0.8.20, 999,999 optimization runs, Shanghai EVM
Inherits
ERC4626, Ownable2Step, ReentrancyGuard
Ownership
Ownable2Step (protocol multisig)
Standard ERC-4626 Interface
ESPN follows the standard ERC-4626 Tokenized Vault specification. If your protocol already supports ERC-4626, no custom integration is needed.
deposit(uint256 assets, address receiver) → uint256 shares
Deposit USDS, receive ESPN shares
mint(uint256 shares, address receiver) → uint256 assets
Mint exact ESPN shares by depositing USDS
withdraw(uint256 assets, address receiver, address owner) → uint256 shares
Withdraw USDS by specifying asset amount
redeem(uint256 shares, address receiver, address owner) → uint256 assets
Redeem ESPN shares for USDS
convertToShares(uint256 assets) → uint256
Preview: USDS → ESPN conversion
convertToAssets(uint256 shares) → uint256
Preview: ESPN → USDS conversion
previewDeposit(uint256 assets) → uint256
Preview shares for a given deposit
previewMint(uint256 shares) → uint256
Preview assets needed to mint shares
previewWithdraw(uint256 assets) → uint256
Preview shares burned for a withdrawal
previewRedeem(uint256 shares) → uint256
Preview assets received for a redemption
totalAssets() → uint256
Total USDS managed by the vault
asset() → address
Underlying asset (USDS)
maxDeposit(address) → uint256
Maximum depositable (reflects cap)
maxMint(address) → uint256
Maximum mintable shares
maxWithdraw(address owner) → uint256
Maximum withdrawable (0 when withdrawals disabled)
maxRedeem(address owner) → uint256
Maximum redeemable shares
Owner Functions
setManager(address _manager)
Owner
Set the manager address authorized to deploy deposited assets
setDepositCap(uint256 _depositCap)
Owner
Update the maximum total deposits
setWithdrawalsDisabled(bool _disabled)
Owner
Toggle direct withdrawals on/off
increaseAssetsPerShare(uint256 assets)
Manager
Increase the vault's assets-per-share for yield distribution
Query Functions
manager() → address
Current manager address
depositCap() → uint256
Current deposit cap
withdrawalsDisabled() → bool
Whether direct withdrawals are disabled
Withdrawals may be disabled. Check maxWithdraw(owner) before presenting a withdraw button. When direct withdrawals are disabled, users exit via the ESPN/USDS LP on secondary markets or the redemption queue.
STRAT Option (StratOption)
ERC-721 representing call options over STRAT. Used for convertible note conversion rights and presale allocations.
Name
STRAT Option
Symbol
oSTRAT
Standard
ERC-721
Compiler
Solidity v0.8.20, 999,999 optimization runs, Paris EVM
Ownership
Ownable2Step (protocol multisig)
Each NFT encodes conversion entitlements, timelock, and expiry. The NFT is the "key" that — when combined with CDT — unlocks conversion to STRAT or esETH. Standard ERC-721 transfers and approvals apply, but settlement authorization requires ownerOf(tokenId) — approvals are not accepted for conversion/redemption.
Per-Token Query Functions
strikeAmount(uint256 tokenId) → uint256
CDT required to exercise (18 decimals)
The "cost" of exercising the option
notionalUnderlyingAmount(uint256 tokenId) → uint256
STRAT received on exercise (18 decimals)
The equity conversion entitlement
notionalUSDAmount(uint256 tokenId) → uint256
USD notional value of the note at purchase (18 decimals)
Settlement value for post-expiry redemption
expiry(uint256 tokenId) → uint256
Expiration timestamp
After this, conversion closes and redemption opens
timelock(uint256 tokenId) → uint256
Earliest exercise timestamp
Before this, no conversion or redemption
Management Functions
mint(address to, uint256 strikeAmount, uint256 notionalUnderlyingAmount, uint256 notionalUSDAmount, uint256 expiry, uint256 timelock)
Authorized minters
Mint a new option NFT with specified terms
burn(uint256 tokenId)
Token owner
Burn an option NFT
manageMinter(address who, bool canMint)
Owner
Authorize/revoke minter addresses
managerRenderer(address renderer)
Owner
Set the tokenURI renderer contract
Access Control Summary
All ETH Strategy contracts use OpenZeppelin's Ownable2Step for ownership transfers — a two-step process (propose → accept) that prevents accidental transfers to wrong addresses.
esETH
Protocol multisig
—
STRAT
Protocol multisig
Minter management (manageMinter)
CDT
Protocol multisig
Minter management (manageMinter)
EthStrategyConvertibleNote
Protocol multisig
—
StakedStrat
Protocol multisig
—
StratETHTreasuryLend
Protocol multisig
Rate setter, fee setter (can be delegated to automated keepers)
ESPN
Protocol multisig
—
Immutability Guarantees
ETH Strategy contracts are deployed without proxy-upgrade patterns. Deployed code is immutable.
PCF/GCF (bonding price factors)
Existing note entitlements
Supported LST whitelist for esETH
Existing note timelock/expiry
Deposit caps
Existing loan terms
Reward distribution addresses
CDT supply accounting
Borrow rate, loan duration (TreasuryLend)
Contract logic (no upgrades)
Rate setter / fee setter delegation
Conversion/redemption mechanics
Last updated