PletherDOV
Inherits: ERC20, ReentrancyGuard, Ownable2Step
Title: PletherDOV
Automated Covered Call Vault for Plether synthetic assets.
Natively holds splDXY to prevent weekly AMM slippage. Implements on-chain Dutch Auctions.
Note: security-contact: contact@plether.com
Constants
MARGIN_ENGINE
IMarginEngine public immutable MARGIN_ENGINE
STAKED_TOKEN
IERC4626 public immutable STAKED_TOKEN
USDC
IERC20 public immutable USDC
IS_BULL
bool public immutable IS_BULL
State Variables
currentState
State public currentState = State.UNLOCKED
currentEpochId
uint256 public currentEpochId = 0
zapKeeper
address public zapKeeper
epochs
mapping(uint256 => Epoch) public epochs
pendingUsdcDeposits
uint256 public pendingUsdcDeposits
userUsdcDeposits
mapping(address => uint256) public userUsdcDeposits
userDepositEpoch
mapping(address => uint256) public userDepositEpoch
epochDeposits
mapping(uint256 => EpochDeposits) public epochDeposits
_preZapSplDXYBalance
uint256 internal _preZapSplDXYBalance
_preZapDepositUsdc
uint256 internal _preZapDepositUsdc
_preZapPremiumUsdc
uint256 internal _preZapPremiumUsdc
_zapSnapshotTaken
bool internal _zapSnapshotTaken
Functions
constructor
constructor(
string memory _name,
string memory _symbol,
address _marginEngine,
address _stakedToken,
address _usdc,
bool _isBull
) ERC20(_name, _symbol) Ownable(msg.sender);
initializeShares
Mints initial shares to the owner for seed capital already held by the vault.
Must be called before the first epoch if the vault holds pre-seeded splDXY.
function initializeShares() external onlyOwner;
deposit
Queue USDC to be deposited into the DOV at the start of the next epoch.
Auto-claims shares from any previous epoch deposit before recording the new one.
function deposit(
uint256 amount
) external nonReentrant;
withdrawDeposit
Withdraw queued USDC that has not yet been processed into an epoch.
function withdrawDeposit(
uint256 amount
) external nonReentrant;
claimShares
Claims DOV shares earned from a previous epoch’s processed deposit.
function claimShares() external nonReentrant;
withdraw
Redeems vault shares for proportional splDXY (and any premium USDC).
Only callable during UNLOCKED. Auto-claims pending deposit shares first.
function withdraw(
uint256 shares
) external nonReentrant;
setZapKeeper
function setZapKeeper(
address _keeper
) external onlyOwner;
releaseUsdcForZap
Releases all USDC held by this DOV to the caller (zapKeeper only).
Snapshots pre-zap state for share calculation in startEpochAuction.
function releaseUsdcForZap() external returns (uint256 amount);
startEpochAuction
Step 1: Rolls the vault into a new epoch, mints options, starts Dutch Auction.
If deposits are pending, releaseUsdcForZap must have been called first to snapshot pre-zap state. Deposit shares are minted proportionally based on the zap conversion.
function startEpochAuction(
uint256 strike,
uint256 expiry,
uint256 maxPremium,
uint256 minPremium,
uint256 duration
) external nonReentrant;
getCurrentOptionPrice
Calculates the current linearly decaying price per option.
function getCurrentOptionPrice() public view returns (uint256);
fillAuction
Step 2: Market Makers call this to buy the entire batch of options.
Premium calculation: optionsMinted (18 decimals) * currentPremium (6 decimals) / 1e18 = totalPremiumUsdc (6 decimals). Relies on OptionToken.decimals() == 18.
function fillAuction() external nonReentrant;
cancelAuction
Cancels an expired auction that received no fill, returning the vault to UNLOCKED.
Also allows immediate cancellation when the Splitter has liquidated.
function cancelAuction() external nonReentrant;
exerciseUnsoldOptions
Exercises unsold option tokens held by the DOV after a cancelled auction.
Skips exercise for OTM options so keeper batch transactions don’t revert.
function exerciseUnsoldOptions(
uint256 epochId
) external nonReentrant;
reclaimCollateral
Reclaims collateral from an unsold series after it has been settled.
function reclaimCollateral(
uint256 epochId
) external nonReentrant;
settleEpoch
Step 3: At expiration, settles the series and unlocks remaining collateral.
function settleEpoch(
uint80[] calldata roundHints
) external nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
roundHints | uint80[] | Chainlink round IDs for oracle lookup (one per feed component). Ignored if the series is already settled. |
emergencyWithdraw
Recovers stranded funds after Splitter liquidation (protocol end-of-life).
Only callable by owner when the Splitter has permanently settled.
function emergencyWithdraw(
IERC20 token
) external onlyOwner;
pendingSharesOf
Returns the number of shares a user can claim from a processed deposit.
function pendingSharesOf(
address user
) external view returns (uint256);
totalVaultAssets
Returns the vault’s total assets excluding pending deposits.
function totalVaultAssets() external view returns (uint256 splDXYShares, uint256 usdcBalance);
_claimShares
Claims DOV shares for a user whose deposit was processed in a previous epoch.
function _claimShares(
address user
) internal;
_calculatePendingShares
function _calculatePendingShares(
address user
) private view returns (uint256);
_mintDepositShares
Computes and mints aggregate shares for all depositors whose USDC was zapped. Uses the pre-zap snapshot from releaseUsdcForZap to attribute splDXY proportionally between existing shareholders (premium) and new depositors (deposit USDC).
function _mintDepositShares() internal;
Events
DepositQueued
event DepositQueued(address indexed user, uint256 amount);
DepositWithdrawn
event DepositWithdrawn(address indexed user, uint256 amount);
EpochRolled
event EpochRolled(uint256 indexed epochId, uint256 seriesId, uint256 optionsMinted);
AuctionFilled
event AuctionFilled(uint256 indexed epochId, address indexed buyer, uint256 premiumPaid);
AuctionCancelled
event AuctionCancelled(uint256 indexed epochId);
EpochSettled
event EpochSettled(uint256 indexed epochId, uint256 collateralReturned);
EmergencyWithdraw
event EmergencyWithdraw(address indexed token, uint256 amount);
ZapKeeperSet
event ZapKeeperSet(address indexed keeper);
SharesInitialized
event SharesInitialized(address indexed owner, uint256 shares);
DepositSharesMinted
event DepositSharesMinted(uint256 indexed epochId, uint256 totalShares, uint256 totalDepositsUsdc);
SharesClaimed
event SharesClaimed(address indexed user, uint256 shares);
Withdrawn
event Withdrawn(address indexed user, uint256 shares, uint256 splDXYAmount, uint256 usdcAmount);
Errors
PletherDOV__WrongState
error PletherDOV__WrongState();
PletherDOV__ZeroAmount
error PletherDOV__ZeroAmount();
PletherDOV__AuctionEnded
error PletherDOV__AuctionEnded();
PletherDOV__AuctionNotExpired
error PletherDOV__AuctionNotExpired();
PletherDOV__SplitterNotSettled
error PletherDOV__SplitterNotSettled();
PletherDOV__InvalidParams
error PletherDOV__InvalidParams();
PletherDOV__InsufficientDeposit
error PletherDOV__InsufficientDeposit();
PletherDOV__DepositProcessed
error PletherDOV__DepositProcessed();
PletherDOV__Unauthorized
error PletherDOV__Unauthorized();
PletherDOV__AlreadyInitialized
error PletherDOV__AlreadyInitialized();
PletherDOV__NotInitialized
error PletherDOV__NotInitialized();
PletherDOV__DepositsNotZapped
error PletherDOV__DepositsNotZapped();
PletherDOV__NothingToClaim
error PletherDOV__NothingToClaim();
Structs
Epoch
struct Epoch {
uint256 seriesId;
uint256 optionsMinted;
uint256 auctionStartTime;
uint256 maxPremium; // Max USDC price per option (6 decimals)
uint256 minPremium; // Min USDC price per option (6 decimals)
uint256 auctionDuration;
address winningMaker;
}
EpochDeposits
struct EpochDeposits {
uint256 totalUsdc;
uint256 sharesMinted;
}
Enums
State
enum State {
UNLOCKED,
AUCTIONING,
LOCKED
}