Skip to main content

API Reference

Auto-generated from the NatSpec in foundry/contracts/. Edit the Solidity source and run yarn docs:gen from the repo root to refresh this page.

Core Contracts

Option

Inherits: ERC20, Ownable, ReentrancyGuardTransient, Initializable

Title: Option — long-side ERC20

Author: Greek.fi

One half of a Greek option pair. Holding this token grants the right (not obligation) to buy the collateral at the strike price — a standard call — or, for puts, the right to sell. Its paired Collateral contract holds the short side of the same option. Three behaviour modes are fixed at creation (driven by Factory):

ModeoracleisEuroPre-expiryPost-expiry
American non-settled0falseexercise— (token is dust)
American settledsetfalseexerciseclaim ITM residual
Europeansettrueno exerciseclaim ITM residual
The mode is read from the paired Collateral (isEuro, oracle).
Auto-mint / auto-redeem

Addresses that have opted in via factory.enableAutoMintRedeem(true) get two transfer-time conveniences:

  • Auto-mint — if the sender tries to transfer more Option than they hold, the contract pulls enough collateral from the sender and mints the deficit.
  • Auto-redeem — if the receiver already holds the matching Collateral ("short") token, incoming Option is immediately redeemed pair-wise, returning collateral. Both behaviours are opt-in per-account and make it possible to treat Option and its underlying collateral as interchangeable for power users (e.g. vaults).

Deployed once as a template; the factory produces per-option instances via EIP-1167 minimal proxy clones. init() is used instead of a constructor. Example (opening and exercising a call):

// 1. Deploy an option via the factory
address opt = factory.createOption(
CreateParams({
collateral: WETH,
consideration: USDC,
expirationDate: uint40(block.timestamp + 30 days),
strike: uint96(3000e18), // 3000 USDC / WETH, 18-dec fixed point
isPut: false,
isEuro: false,
oracleSource: address(0), // American non-settled
twapWindow: 0
})
);
// 2. Mint 1 WETH worth of options (collateral-side approval on the factory)
factory.approve(WETH, 1e18);
Option(opt).mint(1e18);
// 3. If spot moves above strike, exercise before expiry
factory.approve(USDC, 3000e6); // USDC is 6-dec
Option(opt).exercise(1e18); // pays USDC, receives WETH

State Variables

coll

Paired short-side ERC20 that holds the collateral and handles settlement math.

Collateral public coll

Functions

notLocked

Blocks mutations while the paired collateral is locked by the owner.

modifier notLocked() ;
notExpired

Blocks calls that require the option to still be live.

modifier notExpired() ;
validAmount

Rejects zero-amount mutations to keep accounting clean and events meaningful.

modifier validAmount(uint256 amount) ;
sufficientBalance

Ensures account holds at least amount Option tokens.

modifier sufficientBalance(address account, uint256 amount) ;
constructor

Template constructor. Never called for user-facing instances; each clone goes through init instead. Disables initializers on the template to prevent takeover.

constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) Ownable(msg.sender);

Parameters

NameTypeDescription
name_stringPlaceholder name (overridden by the computed name() view).
symbol_stringPlaceholder symbol (overridden by the computed symbol() view).
init

Initialises a freshly-cloned Option. Called exactly once by the factory.

function init(address coll_, address owner_) public initializer;

Parameters

NameTypeDescription
coll_addressAddress of the paired Collateral contract — immutable for this option.
owner_addressAdmin of this option (receives Ownable rights; typically the user who called factory.createOption).
factory

Address of the Factory that created this option. Read from the paired Collateral.

function factory() public view returns (address);
collateral

Underlying collateral token (e.g. WETH for a WETH/USDC call).

function collateral() public view returns (address);
consideration

Consideration / quote token (e.g. USDC for a WETH/USDC call).

function consideration() public view returns (address);
expirationDate

Unix timestamp at which the option expires. After this, exercise reverts and post-expiry paths (claim, coll.redeem) become active.

function expirationDate() public view returns (uint256);
strike

Strike price in 18-decimal fixed point, encoded as "consideration per collateral".

For puts, this stores the inverse of the human-readable strike (see name for display).

function strike() public view returns (uint256);
isPut

true if this is a put option; false for calls.

function isPut() public view returns (bool);
isEuro

true if the option is European-style (no pre-expiry exercise, oracle required).

function isEuro() public view returns (bool);
oracle

Oracle contract used for post-expiry settlement. address(0) in American non-settled mode.

function oracle() public view returns (address);
isSettled

true once the oracle price has been latched (first settle post-expiry).

function isSettled() public view returns (bool);
settlementPrice

Oracle settlement price (18-decimal fixed point). 0 until settle runs.

function settlementPrice() public view returns (uint256);
decimals

Option token shares the collateral's decimals so 1 option token ↔ 1 collateral unit.

function decimals() public view override returns (uint8);
name

Human-readable token name in the form OPT[E]-<coll>-<cons>-<strike>-<YYYY-MM-DD>.

For puts the displayed strike is inverted back (1e36 / strike) to the human form. The OPTE- prefix flags European options.

function name() public view override returns (string memory);
symbol

Same as name. Matching name/symbol keeps wallets and explorers in sync.

function symbol() public view override returns (string memory);
mint

Mint amount option tokens to the caller, collateralised 1:1 with the underlying.

Requires factory.allowance(collateral, msg.sender) >= amount (factory acts as the single collateral transfer point). Reverts if the option is expired or locked.

function mint(uint256 amount) public notLocked;

Parameters

NameTypeDescription
amountuint256Collateral-denominated amount to mint (≤ type(uint160).max). Example: solidity IERC20(WETH).approve(address(factory), 1e18); factory.approve(WETH, 1e18); option.mint(1e18); // caller receives 1e18 Option + 1e18 Collateral tokens
mint

Mint amount option tokens to account. Collateral is pulled from account.

The factory enforces approvedOperator(account, msg.sender) / allowance rules — minting "for" a third party still requires their approval.

function mint(address account, uint256 amount) public notLocked nonReentrant;

Parameters

NameTypeDescription
accountaddressRecipient of both Option and Collateral tokens.
amountuint256Collateral-denominated mint amount.
mint_

Internal mint path shared by mint and auto-mint-on-transfer.

function mint_(address account, uint256 amount) internal notExpired validAmount(amount);
_settledTransfer

Core transfer hook implementing auto-mint (sender) and auto-redeem (receiver). Both are gated on each party's autoMintRedeem opt-in held on the factory.

function _settledTransfer(address from, address to, uint256 amount) internal;
transfer

Overridden to run the auto-mint / auto-redeem hook. Reverts post-expiry — the long token stops circulating once settlement begins.

function transfer(address to, uint256 amount) public override notExpired notLocked nonReentrant returns (bool);
transferFrom

Skips _spendAllowance when msg.sender is a factory-approved operator for from (ERC-1155 style blanket approval across every option in the protocol).

function transferFrom(address from, address to, uint256 amount)
public
override
notExpired
notLocked
nonReentrant
returns (bool);
exercise

Exercise amount options as the caller: pay consideration, receive collateral.

American-only. European options revert with EuropeanExerciseDisabled. Requires the caller to hold at least amount option tokens AND have factory.allowance(consideration, caller) >= toNeededConsideration(amount).

function exercise(uint256 amount) public notLocked;

Parameters

NameTypeDescription
amountuint256Collateral units to receive. Consideration paid = ceil(amount * strike). Example: solidity WETH/USDC call, strike 3000. Exercise 1e18 (1 WETH): factory.approve(USDC, 3000e6); option.exercise(1e18);
exercise

Exercise amount options on behalf of account; caller pays consideration, account receives collateral, caller's option balance is burned.

function exercise(address account, uint256 amount) public notExpired notLocked nonReentrant validAmount(amount);

Parameters

NameTypeDescription
accountaddressAddress receiving the collateral payout.
amountuint256Collateral units to exercise.
redeem

Burn matched Option + Collateral pairs to recover the underlying collateral.

Pre-expiry only. Caller must hold both sides in equal amount. Useful for closing a position you hold both sides of (e.g. a market maker winding down inventory).

function redeem(uint256 amount) public notLocked nonReentrant;

Parameters

NameTypeDescription
amountuint256Collateral-denominated amount to redeem from each side. Example: solidity Holding 1e18 Option + 1e18 Collateral from a prior mint: option.redeem(1e18); // burns both, returns 1e18 WETH
redeem_

Internal pair-redeem. Burns Option side here, delegates Collateral-side burn + payout to the paired Collateral contract.

function redeem_(address account, uint256 amount) internal notExpired sufficientBalance(account, amount);
settle

Latch the oracle settlement price. Callable by anyone post-expiry. Idempotent.

Required before claim can pay out. Forwarded to the paired collateral; implementation-specific hint (e.g. a Chainlink roundId) is passed through.

function settle(bytes calldata hint) external notLocked;

Parameters

NameTypeDescription
hintbytesOracle-specific settlement hint; empty bytes for UniV3Oracle.
claim

Post-expiry ITM claim. Burns amount options, pays the (S-K)/S residual in collateral.

Only makes sense for settled (American-settled or European) modes. Calls settle("") internally, so a separate settle step isn't strictly required. Payout is floor-rounded; OTM options claim zero (the tokens still burn).

function claim(uint256 amount)
external
notLocked
nonReentrant
validAmount(amount)
sufficientBalance(msg.sender, amount);

Parameters

NameTypeDescription
amountuint256Option tokens to burn. Example: solidity European WETH/USDC call, strike 3000, settled at S=3500: payout per option = (3500 - 3000) / 3500 ≈ 0.1429 WETH option.claim(1e18);
claimFor

Claim on behalf of holder. Anyone can call; payout still goes to holder. Enables gas-sponsored or keeper-driven settlement sweeps. No-op for zero balance.

function claimFor(address holder) external notLocked nonReentrant;

Parameters

NameTypeDescription
holderaddressThe option holder whose full balance should be claimed.
balancesOf

All four balances that matter for this option in one call.

function balancesOf(address account) public view returns (Balances memory);

Parameters

NameTypeDescription
accountaddressAddress to query.

Returns

NameTypeDescription
<none>BalancesA Balances struct: collateral token, consideration token, long option, short coll.
details

Full option descriptor — addresses, token metadata, strike, expiry, flags. Convenient one-shot read for frontends.

function details() public view returns (OptionInfo memory);
lock

Emergency pause — blocks all state-changing paths on this option and its pair.

Only callable by the option's owner (the account that called createOption).

function lock() public onlyOwner;
unlock

Resume a previously locked option.

function unlock() public onlyOwner;
renounceOwnership

Ownership renouncement is permanently disabled — an unowned option has no recovery path.

function renounceOwnership() public pure override;

Events

Mint

Emitted when new options are minted against fresh collateral.

event Mint(address longOption, address holder, uint256 amount);

Parameters

NameTypeDescription
longOptionaddressThe Option contract (always address(this)).
holderaddressThe account credited with the new tokens.
amountuint256Collateral-denominated amount (same decimals as the collateral token).
Exercise

Emitted when an option is exercised (American modes only).

event Exercise(address longOption, address holder, uint256 amount);

Parameters

NameTypeDescription
longOptionaddressThe Option contract (always address(this)).
holderaddressThe account receiving collateral.
amountuint256Collateral units received (consideration paid is toNeededConsideration(amount)).
Settled

Emitted once when the oracle-settled spot price is latched on first settle.

event Settled(uint256 price);

Parameters

NameTypeDescription
priceuint25618-decimal fixed-point settlement price (consideration per collateral).
Claimed

Emitted on each post-expiry ITM claim.

event Claimed(address indexed holder, uint256 optionBurned, uint256 collateralOut);

Parameters

NameTypeDescription
holderaddressOption holder whose tokens were burned.
optionBurneduint256Option token amount burned.
collateralOutuint256Collateral units paid out (the (S-K)/S ITM residual).
ContractLocked

Emitted when the owner pauses the contract.

event ContractLocked();
ContractUnlocked

Emitted when the owner unpauses the contract.

event ContractUnlocked();

Errors

ContractExpired

Thrown when a call that requires a live option is made after expiration.

error ContractExpired();
ContractNotExpired

Thrown when a post-expiry-only call (e.g. claim) is made before expiration.

error ContractNotExpired();
InsufficientBalance

Thrown when an account does not hold enough Option tokens for the operation.

error InsufficientBalance();
InvalidValue

Thrown when amount == 0 or a similar non-zero invariant fails.

error InvalidValue();
InvalidAddress

Thrown when a zero address is supplied where a contract is required.

error InvalidAddress();
LockedContract

Thrown when the option (or its paired collateral) has been locked by the owner.

error LockedContract();
EuropeanExerciseDisabled

Thrown when exercise is called on a European option.

error EuropeanExerciseDisabled();
NoOracle

Thrown when claim / settle is called on an option that has no oracle.

error NoOracle();

Collateral

Inherits: ERC20, Ownable, ReentrancyGuardTransient, Initializable

Title: Collateral — short-side ERC20

Author: Greek.fi

The short side of a Greek option pair. Holding this token means you have sold the option: you received the premium (off-chain) and now bear the obligation of the exercise / settlement payoff. It holds all collateral for the pair and receives the consideration paid on exercise. Three settlement modes are chosen at creation and reflected in (oracle, isEuro):

ModeoracleisEuroPre-expiry pathPost-expiry paths
American non-settled0falsepair redeem +pro-rata redeem over (coll, cons)
exercise+ redeemConsideration
American settledsetfalsepair redeem +oracle-settled redeem;
exerciseoption-holder claim via Option.sol
Europeansettruepair redeem onlyoracle-settled redeem;
(no exercise)option-holder claim via Option.sol
(oracle == 0 && isEuro) is rejected at the factory — European options always need a price.
Post-expiry in settled modes

On first settle call after expiration, the oracle price S is latched. If the option finishes ITM (S > K) we reserve a portion of the collateral — optionReserveRemaining — for option holders to claim the (S-K)/S residual. Remaining collateral plus any consideration earned during pre-expiry exercise is paid pro-rata to short-side holders via redeem / sweep.

Rounding
  • Collections from users (exercise): round UP (toNeededConsideration).
  • Payouts to users (redeem, claim): round DOWN (floor). Dust stays in the contract, guaranteeing the key invariant available_collateral >= outstanding_option_supply at every state transition.

Deployed once as a template; per-option instances are EIP-1167 minimal proxy clones. init() is used instead of a constructor. Owner of each clone is its paired Option contract — only Option can drive mint / exercise / pair-redeem.

Constants

STRIKE_DECIMALS

Decimal basis of the strike — fixed at 18 and independent of token decimals.

uint8 public constant STRIKE_DECIMALS = 18

State Variables

strike

Strike price, 18-decimal fixed point, "consideration per collateral".

For puts this is the inverted human strike (see Option name() for display).

uint256 public strike
settlementPrice

Oracle spot price latched on first post-expiry settle. 0 until settled.

18-decimal fixed point; same encoding as strike.

uint256 public settlementPrice
optionReserveRemaining

Collateral reserved for option-holder ITM claims. Decremented on each _claimForOption.

Initialised to O * (S-K) / S the first time settle runs post-expiry (zero if OTM).

uint256 public optionReserveRemaining
collateral

Underlying collateral token (e.g. WETH). All collateral sits here.

IERC20 public collateral
consideration

Consideration / quote token (e.g. USDC). Accrues here from exercise payments.

IERC20 public consideration
_factory

Factory handle used to pull tokens through its centralised allowance registry.

IFactoryTransfer public _factory
oracle

Settlement oracle. address(0) in American non-settled mode.

IPriceOracle public oracle
expirationDate

Unix timestamp at which the option expires.

uint40 public expirationDate
isPut

true if put, false if call.

bool public isPut
isEuro

true if European-style (no pre-expiry exercise).

bool public isEuro
locked

Owner-controlled emergency pause flag.

bool public locked
consDecimals

Cached consideration.decimals() used in conversion math.

uint8 public consDecimals
collDecimals

Cached collateral.decimals() used in conversion math.

uint8 public collDecimals
reserveInitialized

true once the first post-expiry settle has initialised optionReserveRemaining.

bool public reserveInitialized

Functions

expired

Blocks calls that must wait until expiration (e.g. post-expiry redeem).

modifier expired() ;
notExpired

Blocks calls that must happen while the option is still live (e.g. mint, exercise).

modifier notExpired() ;
validAmount

Rejects zero-amount mutations.

modifier validAmount(uint256 amount) ;
validAddress

Rejects the zero address where a real contract is required.

modifier validAddress(address addr) ;
sufficientBalance

Ensures account holds at least amount of this Collateral token.

modifier sufficientBalance(address account, uint256 amount) ;
notLocked

Blocks mutations while the owner has paused the option.

modifier notLocked() ;
sufficientCollateral

Ensures the contract itself holds at least amount of collateral.

modifier sufficientCollateral(uint256 amount) ;
sufficientConsideration

Ensures account holds at least toConsideration(amount) of consideration.

modifier sufficientConsideration(address account, uint256 amount) ;
constructor

Template constructor. Never called for user-facing instances; each clone goes through init instead. Disables initializers on the template.

constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) Ownable(msg.sender);
init

Initialises a freshly-cloned Collateral. Called exactly once by the factory.

function init(
address collateral_,
address consideration_,
uint40 expirationDate_,
uint256 strike_,
bool isPut_,
bool isEuro_,
address oracle_,
address option_,
address factory_
) public initializer;

Parameters

NameTypeDescription
collateral_addressUnderlying collateral token.
consideration_addressQuote / consideration token.
expirationDate_uint40Unix timestamp at which the option expires; must be in the future.
strike_uint256Strike price in 18-decimal fixed point (consideration per collateral).
isPut_boolTrue if put, false if call.
isEuro_boolTrue if European-style (exercise disabled, oracle required).
oracle_addressSettlement oracle; address(0) only valid in American non-settled mode.
option_addressPaired Option contract — becomes this Collateral's owner.
factory_addressFactory used as the centralised allowance / transfer authority.
mint

Mint amount Collateral tokens to account, pulling the matching amount of underlying collateral through the factory's allowance registry.

Only callable by the paired Option contract (the owner). amount is capped at uint160.max because the factory's transfer path uses Permit2-compatible typing. Fee-on-transfer tokens are detected and rejected (balance-diff check).

function mint(address account, uint256 amount)
public
onlyOwner
notExpired
notLocked
nonReentrant
validAmount(amount)
validAddress(account);

Parameters

NameTypeDescription
accountaddressRecipient of the newly-minted Collateral tokens.
amountuint256Collateral-denominated amount (same decimals as the collateral token).
_redeemPair

Burn matched Option + Collateral pair, return collateral. Only callable by Option.

Falls back to a consideration payout if the contract is under-collateralized at the collateral layer (defense-in-depth — this should not happen with the current invariants).

function _redeemPair(address account, uint256 amount) public notExpired notLocked onlyOwner nonReentrant;

Parameters

NameTypeDescription
accountaddressRecipient of the collateral.
amountuint256Amount of Collateral tokens to burn.
_redeemPairInternal

Waterfall used by both _redeemPair and exercise-path fallback.

function _redeemPairInternal(address account, uint256 amount)
internal
sufficientBalance(account, amount)
validAmount(amount);
exercise

Exercise path invoked by Option. caller pays consideration; account receives collateral.

Only callable by the paired Option. Consideration amount is computed with toNeededConsideration (ceiling-rounded — favours the protocol on collection).

function exercise(address account, uint256 amount, address caller)
public
notExpired
notLocked
onlyOwner
nonReentrant
sufficientCollateral(amount)
validAmount(amount);

Parameters

NameTypeDescription
accountaddressThe collateral recipient (option holder being exercised in favour of).
amountuint256Collateral units to deliver; consideration collected is ceil(amount * strike).
calleraddressThe account paying consideration (msg.sender at the Option layer).
redeem

Redeem the caller's full Collateral balance post-expiry. In non-settled mode: pro-rata over (collateral, consideration). In settled mode: pro-rata over (collateral - reserve, consideration). Example:

Post-expiry short-side exit (non-settled):
coll.redeem(); // burns all caller's CLL-*, returns collateral + any consideration collected
function redeem() public notLocked;
redeem

Redeem amount of the caller's Collateral tokens post-expiry.

function redeem(uint256 amount) public notLocked;

Parameters

NameTypeDescription
amountuint256Collateral tokens to burn.
redeem

Redeem amount for account post-expiry. Routes to settled or pro-rata path based on whether an oracle is configured.

Callable by anyone — used by keepers to sweep short-side holders.

function redeem(address account, uint256 amount) public expired notLocked nonReentrant;

Parameters

NameTypeDescription
accountaddressThe Collateral holder whose position is redeemed.
amountuint256Amount of Collateral tokens to burn.
_redeemProRata

Pro-rata payout used in American non-settled mode. Pays amount first in collateral up to the available balance, then tops up with consideration at the strike rate.

function _redeemProRata(address account, uint256 amount)
internal
sufficientBalance(account, amount)
validAmount(amount);
_redeemSettled

Settled-mode payout. Distributes (collBalance - reserve, consBalance) pro-rata; the reserve stays behind for option-holder claims.

function _redeemSettled(address account, uint256 amount)
internal
sufficientBalance(account, amount)
validAmount(amount);
redeemConsideration

Convert amount Collateral tokens straight into consideration at the strike rate. Only meaningful in American modes (Europeans never hold consideration — no exercise).

Useful for a short-side holder who wants their payout settled in quote currency rather than a mix of collateral and consideration.

function redeemConsideration(uint256 amount) public notLocked nonReentrant;

Parameters

NameTypeDescription
amountuint256Collateral tokens to burn. Example: solidity WETH/USDC call, strike 3000. Caller holds 1e18 CLL-WETH-USDC-3000-* and wants USDC: coll.redeemConsideration(1e18); // burns coll, returns 3000e6 USDC (6-dec)
_redeemConsideration

Shared body for direct redeemConsideration calls and the pair-redeem fallback.

function _redeemConsideration(address account, uint256 collAmount)
internal
sufficientBalance(account, collAmount)
sufficientConsideration(address(this), collAmount)
validAmount(collAmount);
settle

Latch the oracle settlement price and initialise the option-holder reserve. Callable by anyone post-expiry. Idempotent — subsequent calls are no-ops.

function settle(bytes calldata hint) public notLocked;

Parameters

NameTypeDescription
hintbytesOracle-specific settlement hint (e.g. abi.encode(roundId) for Chainlink; empty bytes for Uniswap v3 TWAP oracles).
_settle

Internal settle — see settle.

function _settle(bytes memory hint) internal;
_claimForOption

Pay an option-holder's ITM residual. Only callable by the paired Option.

Payout formula: amount * (S - K) / S, floor-rounded, capped at the remaining reserve. Zero if OTM (S ≤ K).

function _claimForOption(address holder, uint256 amount) external onlyOwner returns (uint256 payout);

Parameters

NameTypeDescription
holderaddressRecipient of the collateral payout.
amountuint256Option tokens being burned on the long side.

Returns

NameTypeDescription
payoutuint256Collateral units actually sent.
sweep

Redeem holder's full Collateral balance post-expiry. No-op for zero-balance accounts. Useful for gas-sponsored cleanup.

function sweep(address holder) public expired notLocked nonReentrant;

Parameters

NameTypeDescription
holderaddressThe short-side holder to sweep.
sweep

Batch form of sweep — walks the array and redeems each holder's full balance.

Settlement is latched once up front (in settled mode) so the oracle only runs once.

function sweep(address[] calldata holders) public expired notLocked nonReentrant;

Parameters

NameTypeDescription
holdersaddress[]Array of short-side holders to sweep.
lock

Emergency pause. Blocks all user-facing mutations on this contract and its Option.

Only callable by the owner (the paired Option, which gates its own lock() on Ownable).

function lock() public onlyOwner;
unlock

Resume after a lock.

function unlock() public onlyOwner;
toConsideration

Convert a collateral amount to the consideration it is worth at the strike rate, normalised for both tokens' decimals. Floor-rounded — used for payouts.

Formula: amount * strike * 10^consDec / (10^18 * 10^collDec).

function toConsideration(uint256 amount) public view returns (uint256);

Parameters

NameTypeDescription
amountuint256Collateral-denominated amount (same decimals as the collateral token).

Returns

NameTypeDescription
<none>uint256Consideration amount in the consideration token's native decimals.
toNeededConsideration

Same as toConsideration but ceiling-rounded — used when collecting consideration so the protocol never accepts a short payment.

function toNeededConsideration(uint256 amount) public view returns (uint256);

Parameters

NameTypeDescription
amountuint256Collateral-denominated amount.

Returns

NameTypeDescription
<none>uint256Ceiling-rounded consideration required.
toCollateral

Inverse of toConsideration — how much collateral a given consideration amount is worth at the strike rate.

function toCollateral(uint256 consAmount) public view returns (uint256);

Parameters

NameTypeDescription
consAmountuint256Consideration-denominated amount.

Returns

NameTypeDescription
<none>uint256Collateral-denominated amount (floor-rounded).
name

Human-readable token name, mirroring Option but with a CLL[E]- prefix. Puts display the inverted strike back in human form (1e36 / strike).

function name() public view override returns (string memory);
symbol

Same as name. Keeping them aligned avoids wallet/explorer drift.

function symbol() public view override returns (string memory);
decimals

Decimals match the underlying collateral so 1 Collateral unit ↔ 1 collateral unit.

function decimals() public view override returns (uint8);
collateralData

Metadata bundle for the collateral token (convenience read).

function collateralData() public view returns (TokenData memory);
considerationData

Metadata bundle for the consideration token (convenience read).

function considerationData() public view returns (TokenData memory);
option

Paired Option contract (also this Collateral's owner).

function option() public view returns (address);
factory

Factory that created this option.

function factory() public view returns (address);

Events

Redeemed

Emitted on every path that returns collateral or consideration to a user.

event Redeemed(address option, address token, address holder, uint256 amount);

Parameters

NameTypeDescription
optionaddressThe paired Option contract (also this contract's owner).
tokenaddressThe token actually transferred out (collateral or consideration).
holderaddressRecipient of the payout.
amountuint256Token units sent.
Settled

Emitted once when the oracle price is latched.

event Settled(uint256 price);

Parameters

NameTypeDescription
priceuint25618-decimal settlement price (consideration per collateral).

Errors

ContractNotExpired

Thrown when a pre-expiry-only path (mint, exercise, pair-redeem) runs after expiration.

error ContractNotExpired();
ContractExpired

Thrown when a post-expiry-only path (redeem, sweep, claim) runs before expiration.

error ContractExpired();
InsufficientBalance

Thrown when an account does not hold enough Collateral tokens for the operation.

error InsufficientBalance();
InvalidValue

Thrown on amount == 0 (or any derived zero-amount the invariant requires to be positive).

error InvalidValue();
InvalidAddress

Thrown when a zero address is supplied where a real token/contract is required.

error InvalidAddress();
LockedContract

Thrown when the option has been paused by its owner.

error LockedContract();
FeeOnTransferNotSupported

Thrown if the transferred amount doesn't match what arrived — fee-on-transfer tokens are rejected.

error FeeOnTransferNotSupported();
InsufficientCollateral

Thrown when this contract does not hold enough collateral for an exercise payout.

error InsufficientCollateral();
InsufficientConsideration

Thrown when the exerciser's consideration balance (or the contract's) is short.

error InsufficientConsideration();
ArithmeticOverflow

Thrown when casting amount to uint160 would overflow the Permit2 cap.

error ArithmeticOverflow();
NoOracle

Thrown when a settled-mode path is invoked on an option with no oracle.

error NoOracle();
NotSettled

Thrown when a read relies on a settlement price that hasn't been latched yet.

error NotSettled();
SettledOnly

Thrown when a settled-only path is invoked in non-settled mode.

error SettledOnly();
NonSettledOnly

Thrown when a non-settled-only path is invoked in settled mode.

error NonSettledOnly();
EuropeanExerciseDisabled

Thrown when exercise is called on a European option.

error EuropeanExerciseDisabled();

Factory

Inherits: Ownable, ReentrancyGuardTransient

Title: Factory — deployer, allowance hub, operator registry

Author: Greek.fi

The only on-chain contract users need to interact with to create options. Once deployed, every Option + Collateral pair runs off pre-compiled template clones, so creation is cheap and the factory is never an upgradeable rug vector (the templates are immutable). The factory also plays three lasting roles post-creation:

  1. Single allowance point. Users approve(collateralToken, amount) on the factory once, and any Option / Collateral pair created by this factory can pull from that allowance via transferFrom. No need to approve every new option individually.
  2. Operator registry. approveOperator gives an address blanket authority to move any Option produced by this factory on your behalf — the ERC-1155-style "setApprovalForAll" pattern. Used by trading venues and aggregators.
  3. Auto-mint / auto-redeem opt-in. enableAutoMintRedeem flips a per-account flag that Option consults on transfer to auto-mint deficits and auto-redeem matched Option+Collateral on the receiving side.
Token blocklist

The factory owner can blockToken / unblockToken to prevent options from being created against known-problematic tokens (fee-on-transfer, rebasing, exploited). It never affects already-created options — only new creations.

Oracle sources

createOption(params) auto-detects the oracle source in params.oracleSource:

  • Pre-deployed IPriceOracle whose expiration() matches → reused in place.
  • Uniswap v3 pool (detected via token0()) → a fresh UniV3Oracle is deployed inline, bound to (collateral, consideration, expiration, twapWindow).
  • Anything else → reverts with UnsupportedOracleSource. A Chainlink branch is planned.

Example (create + approve + mint):

// Create a 30-day WETH/USDC 3000 call, European, settled by a v3 TWAP on a WETH/USDC pool.
address opt = factory.createOption(
CreateParams({
collateral: WETH,
consideration: USDC,
expirationDate: uint40(block.timestamp + 30 days),
strike: uint96(3000e18),
isPut: false,
isEuro: true,
oracleSource: UNIV3_WETH_USDC_POOL,
twapWindow: 1800 // 30-min TWAP
})
);
// Single approval feeds every option this factory creates.
IERC20(WETH).approve(address(factory), type(uint256).max);
factory.approve(WETH, type(uint256).max);
Option(opt).mint(1e18);

Constants

COLL_CLONE

Template Collateral contract; per-option instances are EIP-1167 clones of this.

address public immutable COLL_CLONE
OPTION_CLONE

Template Option contract; per-option instances are EIP-1167 clones of this.

address public immutable OPTION_CLONE

State Variables

colls

Registered Collateral clones — transferFrom is only callable by these.

mapping(address => bool) private colls
options

true if the address is a Option clone this factory created.

mapping(address => bool) public options
blocklist

Tokens rejected for new option creation. Does not affect already-created options.

mapping(address => bool) public blocklist
_allowances

Per-token allowance table: _allowances[token][owner] -> amount.

mapping(address => mapping(address => uint256)) private _allowances
_approvedOperators

Operator approval table: _approvedOperators[owner][operator] -> bool.

mapping(address => mapping(address => bool)) private _approvedOperators
autoMintRedeem

Per-account opt-in for auto-mint on transfer and auto-redeem on receive in Option.

mapping(address => bool) public autoMintRedeem

Functions

constructor

Bind the factory to its immutable templates.

constructor(address collClone_, address optionClone_) Ownable(msg.sender);

Parameters

NameTypeDescription
collClone_addressDeployed Collateral template.
optionClone_addressDeployed Option template.
createOption

Deploy a new Option + Collateral pair.

Clones the templates, classifies / deploys an oracle if needed, and initialises both sides. Emits OptionCreated. The caller becomes the Option's admin owner.

function createOption(CreateParams memory p) public nonReentrant returns (address);

Parameters

NameTypeDescription
pCreateParamsSee CreateParams: - collateral, consideration: ERC20 addresses; must differ and not be blocklisted. - expirationDate: unix timestamp; must be in the future. - strike: 18-decimal fixed point (consideration per collateral, inverted for puts). - isPut, isEuro: option flavour flags. isEuro requires an oracle. - oracleSource: pre-deployed IPriceOracle, a Uniswap v3 pool, or address(0). - twapWindow: seconds of TWAP when oracleSource is a v3 pool (ignored otherwise).

Returns

NameTypeDescription
<none>addressThe new Option address.
createOptions

Batch form of createOption. Same ordering in → same ordering out.

function createOptions(CreateParams[] memory params) external returns (address[] memory result);

Parameters

NameTypeDescription
paramsCreateParams[]Array of CreateParams.

Returns

NameTypeDescription
resultaddress[]Array of newly-created Option addresses, aligned with params.
createOption

Backward-compatibility overload for the American non-settled case (no oracle, American).

function createOption(
address collateral_,
address consideration_,
uint40 expirationDate_,
uint96 strike_,
bool isPut_
) external returns (address);

Parameters

NameTypeDescription
collateral_addressCollateral token.
consideration_addressConsideration token.
expirationDate_uint40Expiration timestamp.
strike_uint9618-decimal strike.
isPut_boolPut/call flag.

Returns

NameTypeDescription
<none>addressNew Option address.
_deployOracle

Classify p.oracleSource and return a concrete oracle address. Detection order:

  1. Object already quacks like an IPriceOracle and its expiration() matches — reuse.
  2. Object quacks like a Uniswap v3 pool (token0() succeeds) — wrap in a fresh UniV3Oracle.
  3. Otherwise — revert. A Chainlink aggregator branch is reserved for a later change.
function _deployOracle(CreateParams memory p) internal returns (address);
transferFrom

Pull amount of token from from to to. Only callable by Collateral clones that this factory has created.

Decrements _allowances[token][from] (unless it is type(uint256).max). This is the mechanism by which a single user approval on the factory flows to every option pair it creates, rather than requiring approvals on each Collateral clone.

function transferFrom(address from, address to, uint160 amount, address token)
external
nonReentrant
returns (bool);

Parameters

NameTypeDescription
fromaddressToken owner.
toaddressRecipient (typically the calling Collateral contract).
amountuint160Token amount to transfer (≤ uint160.max, matching Permit2 semantics).
tokenaddressToken to move.

Returns

NameTypeDescription
<none>boolsuccess Always true on success; reverts otherwise.
allowance

Factory-level allowance lookup: how much of token can the factory pull from owner_?

function allowance(address token, address owner_) public view returns (uint256);

Parameters

NameTypeDescription
tokenaddressToken.
owner_addressToken owner.

Returns

NameTypeDescription
<none>uint256Current allowance.
approve

Set the caller's factory-level allowance for token to amount.

This is the shared approval consumed by every Option + Collateral pair created by this factory. Does not replace the ERC20-level token.approve(factory, ...) the user must also grant so the factory can call safeTransferFrom on the token.

function approve(address token, uint256 amount) public;

Parameters

NameTypeDescription
tokenaddressERC20 to be approved.
amountuint256Allowance to grant (use type(uint256).max for infinite).
approveOperator

Grant or revoke operator blanket authority to move any of the caller's Option tokens across every option this factory has created (ERC-1155-style setApprovalForAll).

Used by trading venues to avoid per-option approvals. Operators also skip the per-transfer _spendAllowance step on Option.transferFrom.

function approveOperator(address operator, bool approved) external;

Parameters

NameTypeDescription
operatoraddressAddress being approved/revoked (must differ from msg.sender).
approvedbooltrue to grant, false to revoke.
approvedOperator

Is operator an approved operator for owner_?

function approvedOperator(address owner_, address operator) external view returns (bool);
enableAutoMintRedeem

Opt in to Option's auto-mint-on-send and auto-redeem-on-receive transfer behaviour.

Scoped to msg.sender. See Option for the full semantics — in short, enabling lets the caller treat Option and its backing collateral as interchangeable. Example:

factory.enableAutoMintRedeem(true);
Now: `option.transfer(bob, 1e18)` will auto-mint if the sender is short Option but long collateral.
function enableAutoMintRedeem(bool enabled) external;
blockToken

Block token from being used as collateral or consideration for new options.

Owner-only. Does not retroactively affect existing options — use Option.lock for that.

function blockToken(address token) external onlyOwner nonReentrant;
unblockToken

Reverse of blockToken.

function unblockToken(address token) external onlyOwner nonReentrant;
isBlocked

Is token on the blocklist?

function isBlocked(address token) external view returns (bool);

Events

OptionCreated

Emitted for every newly-created option.

event OptionCreated(
address indexed collateral,
address indexed consideration,
uint40 expirationDate,
uint96 strike,
bool isPut,
bool isEuro,
address oracle,
address indexed option,
address coll
);
TokenBlocked

Emitted on blockToken / unblockToken.

event TokenBlocked(address token, bool blocked);
OperatorApproval

Emitted on approveOperator.

event OperatorApproval(address indexed owner, address indexed operator, bool approved);
AutoMintRedeemUpdated

Emitted on enableAutoMintRedeem.

event AutoMintRedeemUpdated(address indexed account, bool enabled);
Approval

Emitted on approve (factory-level allowance set by token owner).

event Approval(address indexed token, address indexed owner, uint256 amount);

Errors

BlocklistedToken

Thrown when createOption is called against a blocklisted collateral or consideration token.

error BlocklistedToken();
InvalidAddress

Thrown when a zero address is supplied where a real contract is required.

error InvalidAddress();
InvalidTokens

Thrown when collateral == consideration (no real option pair).

error InvalidTokens();
InsufficientAllowance

Thrown when transferFrom is called with allowance < amount.

error InsufficientAllowance();
EuropeanRequiresOracle

Thrown when isEuro == true but no oracle source was provided.

error EuropeanRequiresOracle();
UnsupportedOracleSource

Thrown when createOption cannot classify oracleSource (neither an IPriceOracle nor a v3 pool).

error UnsupportedOracleSource();

YieldVault

Inherits: ERC4626, ERC165, Ownable, ReentrancyGuardTransient, Pausable, IERC7540Redeem, IERC7540Operator, IERC1271

Title: YieldVault — operator-managed option-writing vault

Author: Greek.fi

ERC4626 vault that accepts collateral (e.g. WETH), writes options against it, and earns yield from the premiums collected on each trade. Depositors share in that yield pro-rata via vault shares.

Architecture
  • ERC-4626 for the share accounting.
  • ERC-7540 async redeems — vault collateral may be locked inside live options, so withdrawals go through requestRedeem → owner fulfillRedeem → redeem. The synchronous withdraw / previewRedeem paths are intentionally disabled.
  • ERC-1271 contract signatures — the vault can act as a Bebop taker; authorised operators sign RFQ quotes on its behalf.
  • Operator registrysetOperator delegates the vault's trading powers (execute, burn, redeemExpired, removeOption, signing). The vault owner is always authorised.
  • Auto-mint — with setupFactoryApproval + enableAutoMintRedeem, selling an option inside a Bebop swapSingle automatically mints it against vault collateral.
Flow
  1. Users deposit(asset, shares) — receive vault shares.
  2. Operator routes RFQ trades through execute — Bebop settlement pulls options from the vault, auto-minting against idle collateral.
  3. After expiry, operator calls redeemExpired to recover leftover collateral + any consideration earned. burn is used to close matched pairs pre-expiry.
  4. Users who want out call requestRedeem. Once the operator has idle collateral, they call fulfillRedeem to snapshot the asset value. The user then claims via redeem.

Deployments are per-collateral (one vault for WETH, another for USDC, etc.).

State Variables

factory

Factory used when configuring auto-mint approvals.

IFactory public factory
activeOptions

Options this vault has written / is tracking. Drives totalCommitted accounting.

address[] public activeOptions
_pendingRedeemShares

Controller → shares awaiting fulfillment.

mapping(address => uint256) private _pendingRedeemShares
_claimableRedeemShares

Controller → shares that have been fulfilled and can now be claimed.

mapping(address => uint256) private _claimableRedeemShares
_claimableRedeemAssets

Controller → asset amount earmarked at fulfillment (price snapshot).

mapping(address => uint256) private _claimableRedeemAssets
_totalClaimableShares

Sum of all _claimableRedeemShares across controllers — subtracted from totalSupply in the share math so claimable shares don't dilute active depositors.

uint256 private _totalClaimableShares
_totalClaimableAssets

Sum of all _claimableRedeemAssets — subtracted from balance in totalAssets.

uint256 private _totalClaimableAssets
_operators

_operators[controller][operator] -> bool.

mapping(address => mapping(address => bool)) private _operators

Functions

onlyOperatorOrOwner

Permits owner + operators approved by the owner.

modifier onlyOperatorOrOwner() ;
constructor

Deploy a vault for a single collateral asset.

constructor(IERC20 collateral_, string memory name_, string memory symbol_, address factory_)
ERC4626(collateral_)
ERC20(name_, symbol_)
Ownable(msg.sender);

Parameters

NameTypeDescription
collateral_IERC20Underlying ERC20 (e.g. WETH).
name_stringVault share token name.
symbol_stringVault share token symbol.
factory_addressFactory used for auto-mint approvals (non-zero).
_decimalsOffset

Virtual-share offset prevents first-depositor inflation attacks (OZ ERC-4626 convention).

function _decimalsOffset() internal pure override returns (uint8);
totalAssets

Assets actively backing shares: idle balance + collateral committed to live options, minus amounts earmarked for fulfilled (but not yet claimed) redeems.

function totalAssets() public view override returns (uint256);
_activeSupply

Active share supply — excludes shares already locked in the vault as claimable redeems, so fulfilled-but-unclaimed redeems don't inflate the price per share.

function _activeSupply() internal view returns (uint256);
_convertToShares

Internal conversion function (from assets to shares) with support for rounding direction.

function _convertToShares(uint256 assets, Math.Rounding rounding) internal view override returns (uint256);
_convertToAssets

Internal conversion function (from shares to assets) with support for rounding direction.

function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view override returns (uint256);
maxDeposit

Deposits are disabled while paused.

function maxDeposit(address) public view override returns (uint256);
maxMint

Mints are disabled while paused.

function maxMint(address) public view override returns (uint256);
maxWithdraw

Synchronous withdraw is disabled in favour of the ERC-7540 flow.

Returns 0 so interfaces don't offer it as an option.

function maxWithdraw(address) public pure override returns (uint256);
maxRedeem

Shares that controller has had fulfilled and can now claim via redeem.

function maxRedeem(address controller) public view override returns (uint256);
previewRedeem

Preview for synchronous redeems is not defined — use the async flow.

function previewRedeem(uint256) public pure override returns (uint256);
previewWithdraw

Preview for synchronous withdraws is not defined — use the async flow.

function previewWithdraw(uint256) public pure override returns (uint256);
withdraw

Synchronous withdraw is disabled.

function withdraw(uint256, address, address) public pure override returns (uint256);
requestRedeem

Step 1/3 of the async redeem: lock shares in the vault until an operator fulfils.

Shares move from owner into address(this). Caller can be owner directly or an operator approved via setOperator. Returns 0 (synchronous request id not used).

function requestRedeem(uint256 shares, address controller, address owner)
external
override
nonReentrant
returns (uint256);

Parameters

NameTypeDescription
sharesuint256Number of shares to redeem
controlleraddressAddress that will control the claim
owneraddressAddress whose shares are locked

Returns

NameTypeDescription
<none>uint256requestId The request identifier
fulfillRedeem

Step 2/3: owner fulfils a pending request, snapshotting its asset value at the current share price. Requires idle collateral ≥ quoted assets.

function fulfillRedeem(address controller) public onlyOwner nonReentrant;

Parameters

NameTypeDescription
controlleraddressController whose pending request is being fulfilled.
fulfillRedeems

Batch fulfillRedeem — useful when rebalancing the vault periodically.

function fulfillRedeems(address[] calldata controllers) external onlyOwner;

Parameters

NameTypeDescription
controllersaddress[]Controllers whose requests should be fulfilled.
redeem

Step 3/3: claim the fulfilled redeem. Burns shares, transfers assets to receiver.

Caller can be controller directly or an operator approved by controller. assets are computed pro-rata in case the controller is partially claiming a larger fulfilled bucket.

function redeem(uint256 shares, address receiver, address controller)
public
override
nonReentrant
returns (uint256 assets);

Parameters

NameTypeDescription
sharesuint256Shares to claim (≤ maxRedeem(controller)).
receiveraddressAddress receiving the underlying collateral.
controlleraddressController whose claimable bucket is being drawn from.

Returns

NameTypeDescription
assetsuint256Underlying collateral paid out.
pendingRedeemRequest

Returns pending (not yet fulfilled) shares for a controller

function pendingRedeemRequest(uint256, address controller) external view override returns (uint256);
claimableRedeemRequest

Returns claimable (fulfilled, ready to claim) shares for a controller

function claimableRedeemRequest(uint256, address controller) external view override returns (uint256);
setOperator

Authorize or revoke an operator for the caller

Self-approval is rejected; returns true on success.

function setOperator(address operator, bool approved) external override returns (bool);
isOperator

Check if an address is an authorized operator for a controller

function isOperator(address controller, address operator) external view override returns (bool);
execute

Execute an arbitrary call from the vault. Used to route RFQ trades (e.g. calling BebopSettlement.swapSingle with the vault as taker).

Owner or owner-approved operator only. Bubbles up the callee's revert reason.

function execute(address target, bytes calldata data) external onlyOperatorOrOwner returns (bytes memory);

Parameters

NameTypeDescription
targetaddressThe contract to call.
databytesRaw calldata.

Returns

NameTypeDescription
<none>bytesresult Raw return data. Example: solidity vault.execute(BEBOP_SETTLEMENT, abi.encodeCall(IBebop.swapSingle, (order, sig)));
burn

Pre-expiry: burn matched Option + Collateral tokens held by the vault to recover the underlying collateral (calls Option.redeem).

function burn(address option, uint256 amount) external onlyOperatorOrOwner nonReentrant;

Parameters

NameTypeDescription
optionaddressOption contract whose Option + Collateral are paired in the vault.
amountuint256Collateral-denominated pair amount to redeem.
redeemExpired

Post-expiry: redeem all Collateral tokens this vault holds for option, pulling leftover collateral + any consideration earned during exercise.

function redeemExpired(address option) external onlyOperatorOrOwner;

Parameters

NameTypeDescription
optionaddressOption contract whose short side is held by the vault.
removeOption

Untrack an option (does not affect token balances).

Swap-and-pop — ordering is not preserved. Called automatically by cleanupOptions once the option has expired and the vault's short-side balance is zero.

function removeOption(address option) external onlyOperatorOrOwner;
isValidSignature

Let contracts (e.g. Bebop settlement) verify the vault's signature. Accepts any ECDSA signature produced by the owner or an owner-approved operator.

function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4);

Parameters

NameTypeDescription
hashbytes32Message hash being verified.
signaturebytes65-byte ECDSA signature.

Returns

NameTypeDescription
<none>bytes4magicValue 0x1626ba7e on success, 0xffffffff otherwise (EIP-1271 convention).
supportsInterface

See IERC165-supportsInterface.

function supportsInterface(bytes4 interfaceId) public view override returns (bool);
setupFactoryApproval

One-time setup: grant the factory infinite allowance over the vault's collateral AND record the same allowance in the factory's own allowance registry.

Required before auto-mint can pull collateral inside a settlement call.

function setupFactoryApproval() external onlyOwner;
enableAutoMintRedeem

Opt the vault into Option's auto-mint-on-transfer / auto-redeem-on-receive hooks.

function enableAutoMintRedeem(bool enabled) external onlyOwner;

Parameters

NameTypeDescription
enabledbooltrue to opt in, false to opt out.
approveToken

Approve spender to pull amount of token from the vault.

Used to configure Permit2 / Bebop balance manager approvals for settlement flows.

function approveToken(address token, address spender, uint256 amount) external onlyOwner;

Parameters

NameTypeDescription
tokenaddressERC20 to approve.
spenderaddressAddress being approved.
amountuint256Allowance (use type(uint256).max for infinite).
addOption

Start tracking option in activeOptions and optionally approve a settlement contract to pull the vault's Option tokens.

function addOption(address option, address spender) external onlyOwner;

Parameters

NameTypeDescription
optionaddressOption contract to activate.
spenderaddressSettlement contract receiving an infinite Option-token approval, or address(0) to skip approvals (the option is just tracked).
cleanupOptions

Untrack options whose short-side balance is zero and which are past expiry.

Publicly callable — anyone can pay the gas to compact the active set. Keeps totalCommitted cheap over time.

function cleanupOptions() external;
pause

Pause deposits and mints. Existing deposits continue to earn and can still redeem.

function pause() external onlyOwner;
unpause

Reverse of pause.

function unpause() external onlyOwner;
totalCommitted

Sum of the vault's Collateral-token balances across every tracked option — i.e. collateral currently locked backing live short positions.

function totalCommitted() public view returns (uint256 total);
committed

Collateral committed to a single option (Collateral-token balance for that option).

function committed(address option) public view returns (uint256);
idleCollateral

Collateral sitting in the vault that is free to use (idle balance minus earmarked redeems).

function idleCollateral() external view returns (uint256);
utilizationBps

Share of total assets currently committed to live options, in basis points.

function utilizationBps() external view returns (uint256);

Returns

NameTypeDescription
<none>uint2560 when the vault is empty, otherwise totalCommitted / totalAssets * 1e4.
getVaultStats

One-shot snapshot for frontends.

function getVaultStats()
external
view
returns (uint256 totalAssets_, uint256 totalShares_, uint256 idle_, uint256 committed_, uint256 utilizationBps_);

Returns

NameTypeDescription
totalAssets_uint256Total asset value (totalAssets).
totalShares_uint256Active share supply (excludes claimable redeems).
idle_uint256Idle asset balance (excludes earmarked redeems).
committed_uint256Assets committed to live options.
utilizationBps_uint256committed_ / totalAssets_ * 1e4.
_activateOption

Idempotently append option to activeOptions.

function _activateOption(address option) internal;

Events

OptionAdded

Emitted when an option is added to the active set via addOption.

event OptionAdded(address indexed option);
OptionRemoved

Emitted when an option is removed from the active set via removeOption or cleanupOptions.

event OptionRemoved(address indexed option);
OptionsBurned

Emitted when the vault pair-redeems held Option + Collateral tokens via burn.

event OptionsBurned(address indexed option, uint256 amount);

Errors

InvalidAddress

Thrown when a required address is zero.

error InvalidAddress();
ZeroAmount

Thrown when a mutation is called with amount == 0.

error ZeroAmount();
Unauthorized

Thrown when the caller is neither owner nor an approved operator.

error Unauthorized();
InsufficientIdle

Thrown when idle collateral is insufficient to fulfill a redeem request.

error InsufficientIdle();
InsufficientClaimable

Thrown when a user tries to claim more shares than they have fulfilled.

error InsufficientClaimable();
WithdrawDisabled

Thrown when synchronous withdraw is called — use the async redeem flow.

error WithdrawDisabled();
AsyncOnly

Thrown when a preview function requiring a sync path is called in async-only mode.

error AsyncOnly();

OptionUtils

Title: OptionUtils

Author: Greek.fi

Pure-function library used by Option and Collateral to render human-readable token names ("OPT-WETH-USDC-3000-2025-12-26") without blowing up the clone deployment cost.

Contains no state. All functions are internal pure. Three concerns:

  • uint2str — decimal → ASCII conversion.
  • strike2str — 18-decimal fixed point → human string, with sensible rounding and scientific notation for very small values (e.g. inverted put strikes).
  • epoch2str — unix timestamp → YYYY-MM-DD (UTC). The helpers live here (not inline in Option / Collateral) so every option-pair clone shares a single deployed copy of the rendering logic.

Functions

uint2str

Convert a uint to its base-10 ASCII representation.

function uint2str(uint256 _i) internal pure returns (string memory str);

Parameters

NameTypeDescription
_iuint256The number to convert.

Returns

NameTypeDescription
strstringThe decimal string (e.g. 42 → "42"; 0 → "0").
strike2str

Render an 18-decimal fixed-point strike as a compact, human-readable string.

Rules applied, in order:

  1. No fractional part → print the integer.
  2. Whole number with ≥4 leading fractional zeros → drop the noise (e.g. floating-point artifacts from 1e36 / strike on puts) and print only the integer.
  3. Whole == 0 and >8 leading zeros → scientific notation ("1e-9").
  4. Otherwise → decimal string, rounded to 4 significant fractional digits and trimmed of trailing zeros. Overflow on rounding (e.g. 0.99995 → 1) is handled.
function strike2str(uint256 _i) internal pure returns (string memory str);

Parameters

NameTypeDescription
_iuint256Strike price in 18-decimal fixed-point.

Returns

NameTypeDescription
strstringHuman-readable strike (e.g. "3000", "0.0005", "1e-9").
epoch2str

Convert a unix timestamp to a YYYY-MM-DD (UTC) string.

Uses the proleptic Gregorian calendar including leap-year rules (divisible by 4 except centuries, which must be divisible by 400). Independent of EVM time zone (block.timestamp is always UTC anyway).

function epoch2str(uint256 _i) internal pure returns (string memory str);

Parameters

NameTypeDescription
_iuint256Unix timestamp (seconds since 1970-01-01).

Returns

NameTypeDescription
strstringDate string (e.g. 1704067200 → "2024-01-01").
isLeapYear

Gregorian leap-year test.

function isLeapYear(uint256 year) internal pure returns (bool);

Parameters

NameTypeDescription
yearuint256Four-digit year.

Returns

NameTypeDescription
<none>booltrue if year is a leap year.

Oracles

IPriceOracle

Title: IPriceOracle — settlement oracle interface

Author: Greek.fi

Uniform interface exposed by every settlement oracle used by Collateral. Wraps Chainlink aggregators, Uniswap v3 TWAPs, or any other source and exposes a single latched price in the protocol's strike encoding (18-decimal fixed point, consideration-per-collateral).

Oracles are write-once: the first post-expiry settle latches price() forever, making settlement deterministic even if the underlying source changes afterward. Idempotent — re-settling is a safe no-op.

Functions

expiration

Settlement target — must equal the paired option's expiration timestamp.

function expiration() external view returns (uint256);
isSettled

true iff settle has been called successfully and price is now available.

function isSettled() external view returns (bool);
settle

Latch the settlement price. Callable at or after expiration by anyone. Idempotent.

hint is implementation-specific:

  • UniV3Oracle: ignored (empty bytes).
  • ChainlinkOracle (planned): abi.encode(uint80 roundId) — earliest round after expiry.
function settle(bytes calldata hint) external returns (uint256);

Parameters

NameTypeDescription
hintbytesImplementation-specific settlement hint.

Returns

NameTypeDescription
<none>uint256The latched settlement price, 18-decimal fixed point (consideration per collateral).
price

Read the latched settlement price. Reverts if settle has not yet run.

Same encoding as strike on Collateral: 18-decimal fixed point, "consideration per collateral".

function price() external view returns (uint256);

UniV3Oracle

Inherits: IPriceOracle

Title: UniV3Oracle — Uniswap v3 TWAP settlement oracle

Author: Greek.fi

IPriceOracle implementation that derives its settlement price from a Uniswap v3 pool's arithmetic-mean tick over a configurable window ending at the option's expiration.

One oracle instance per option: constructed with a pool, the ordered collateral / consideration pair, the expiration timestamp, and the TWAP window size. After expiry, any caller may run settle to latch the price forever.

Price semantics

settledPrice is 18-decimal fixed-point, "consideration per collateral" — the same encoding used by Collateral for strike. Conversion handles:

  1. sqrtPriceX96 → tick → ratio math on the pool's observe() output.
  2. Inversion when collateral sits at token1 (Uniswap orders lexicographically).
  3. Decimal normalisation via the tokens' on-chain decimals.
Manipulation resistance

A longer TWAP window (twapWindow_) is more expensive to poison but requires the pool to have recorded enough historical observations. If the pool's ring buffer has rolled over the earliest endpoint (typical when block.timestamp >> expiration + window), observe() itself reverts and the oracle cannot settle — callers must invoke settle within observationCardinality * avg_block_time of expiry.

Constants

POOL

The Uniswap v3 pool providing the TWAP observations.

IUniswapV3Pool public immutable POOL
COLLATERAL

Collateral token address (one of POOL.token0() / POOL.token1()).

address public immutable COLLATERAL
CONSIDERATION

Consideration token address (the other of POOL.token0() / POOL.token1()).

address public immutable CONSIDERATION
EXPIRATION_TS

Option expiration timestamp (settlement target).

uint256 public immutable EXPIRATION_TS
TWAP_WINDOW

TWAP window length in seconds.

uint32 public immutable TWAP_WINDOW
COLLATERAL_IS_TOKEN0

Pre-computed: true when collateral is pool.token0(), false when it's token1.

bool public immutable COLLATERAL_IS_TOKEN0
COLLATERAL_DECIMALS

Cached collateral.decimals().

uint8 public immutable COLLATERAL_DECIMALS
CONSIDERATION_DECIMALS

Cached consideration.decimals().

uint8 public immutable CONSIDERATION_DECIMALS

State Variables

settledPrice

Latched settlement price (18-decimal fixed point, consideration per collateral).

uint256 public settledPrice
settled

true once settle has latched settledPrice.

bool public settled

Functions

constructor
constructor(address pool_, address collateral_, address consideration_, uint256 expiration_, uint32 twapWindow_) ;

Parameters

NameTypeDescription
pool_addressUniswap v3 pool with (collateral, consideration) liquidity
collateral_addressCollateral token address (must be one of pool.token0/token1)
consideration_addressConsideration token address (the other pool token)
expiration_uint256Option expiration timestamp — TWAP ends here
twapWindow_uint32TWAP window in seconds (e.g., 60 for 1-min, 1800 for 30-min)
expiration

Settlement target — must equal the paired option's expiration timestamp.

function expiration() external view returns (uint256);
isSettled

true iff settle has been called successfully and price is now available.

function isSettled() external view returns (bool);
settle

Settles the oracle by reading a TWAP from pool.observe().

hint is ignored (Uniswap needs no external input). Observation window: [expiration - window, expiration]. Must be called before observations roll off the pool's ring buffer — in practice within observationCardinality * avg_block_time of expiration. Idempotent: no-op after first successful settle.

function settle(
bytes calldata /* hint */
)
external
returns (uint256);
price

Read the latched settlement price. Reverts if settle has not yet run.

Same encoding as strike on Collateral: 18-decimal fixed point, "consideration per collateral".

function price() external view returns (uint256);
_tickToPriceWad

Convert a Uniswap v3 tick to an 18-decimal "consideration per collateral" price. Uniswap gives sqrt(token1/token0) in Q64.96. We:

  1. Square to get the raw token1/token0 ratio (×1e18 for precision).
  2. Invert if collateral is token1.
  3. Normalize decimals: result *= 10^collDec / 10^consDec.
function _tickToPriceWad(int24 tick) internal view returns (uint256);

Events

Settled

Emitted once when the oracle latches its settlement price.

event Settled(uint256 price, int24 avgTick);

Parameters

NameTypeDescription
priceuint256Latched 18-decimal fixed-point price.
avgTickint24Arithmetic-mean tick over the TWAP window.

Errors

PoolTokenMismatch

Thrown in the constructor if (collateral, consideration) do not match the pool's pair.

error PoolTokenMismatch();
NotExpired

Thrown if settle is called before EXPIRATION_TS.

error NotExpired();
AlreadySettled

Reserved.

error AlreadySettled();
NotSettled

Thrown by price if called before settle succeeds.

error NotSettled();
WindowTooLong

Thrown if ago + twapWindow overflows uint32 (window can't be fetched safely).

error WindowTooLong();

Interfaces

IOption

Title: IOption — long-side option token interface

Author: Greek.fi

ERC20 with option-specific extensions: mint / exercise / redeem (pre-expiry), settle / claim (post-expiry, settled modes). Transfers use auto-mint / auto-redeem hooks when the sender / receiver has opted in on the factory.

Functions

coll

Paired short-side Collateral contract.

function coll() external view returns (address);
init

One-time initialisation (factory-only for clones).

function init(address coll_, address owner) external;
name

ERC20 name (rendered OPT[E]-coll-cons-strike-YYYY-MM-DD).

function name() external view returns (string memory);
symbol

ERC20 symbol (matches name).

function symbol() external view returns (string memory);
factory

Address of the Factory that created this option.

function factory() external view returns (address);
collateral

Underlying collateral token.

function collateral() external view returns (address);
consideration

Consideration / quote token.

function consideration() external view returns (address);
expirationDate

Unix expiration timestamp.

function expirationDate() external view returns (uint256);
strike

Strike price (18-decimal fixed point; inverted for puts).

function strike() external view returns (uint256);
isPut

true if this is a put.

function isPut() external view returns (bool);
isEuro

true if European-style (no pre-expiry exercise).

function isEuro() external view returns (bool);
oracle

Settlement oracle (address(0) in American non-settled mode).

function oracle() external view returns (address);
isSettled

true once the oracle price has been latched.

function isSettled() external view returns (bool);
settlementPrice

Latched oracle price (0 until settled).

function settlementPrice() external view returns (uint256);
balanceOf

ERC20 balance.

function balanceOf(address account) external view returns (uint256);
balancesOf

All four balances that matter for this option.

function balancesOf(address account) external view returns (Balances memory);
details

Full option descriptor.

function details() external view returns (OptionInfo memory);
mint

Mint amount options to the caller.

function mint(uint256 amount) external;
mint

Mint amount options to account.

function mint(address account, uint256 amount) external;
transferFrom

ERC20 transferFrom override — runs auto-mint + auto-redeem hooks; reverts post-expiry.

function transferFrom(address from, address to, uint256 amount) external returns (bool success);
transfer

ERC20 transfer override — runs auto-mint + auto-redeem hooks; reverts post-expiry.

function transfer(address to, uint256 amount) external returns (bool success);
exercise

Exercise amount options (American-only): pay consideration, receive collateral.

function exercise(uint256 amount) external;
exercise

Exercise amount options on behalf of account.

function exercise(address account, uint256 amount) external;
redeem

Burn matched Option + Collateral pair pre-expiry; return collateral.

function redeem(uint256 amount) external;
settle

Latch the oracle settlement price. Idempotent; callable post-expiry by anyone.

function settle(bytes calldata hint) external;
claim

Post-expiry ITM claim — burn amount options, receive the (S-K)/S residual.

function claim(uint256 amount) external;
claimFor

Claim on behalf of holder for their full balance.

function claimFor(address holder) external;
lock

Emergency pause (owner-only).

function lock() external;
unlock

Reverse of lock.

function unlock() external;

Events

Mint

Emitted on IOption.mint.

event Mint(address longOption, address holder, uint256 amount);
Exercise

Emitted on IOption.exercise (American only).

event Exercise(address longOption, address holder, uint256 amount);
Settled

Emitted once per option when the oracle settlement price is latched.

event Settled(uint256 price);
Claimed

Emitted on every post-expiry IOption.claim / IOption.claimFor payout.

event Claimed(address indexed holder, uint256 optionBurned, uint256 collateralOut);
ContractLocked

Emitted on IOption.lock.

event ContractLocked();
ContractUnlocked

Emitted on IOption.unlock.

event ContractUnlocked();

Errors

ContractExpired

Call that requires a live option was made after expiration.

error ContractExpired();
ContractNotExpired

Post-expiry-only call was made before expiration.

error ContractNotExpired();
InsufficientBalance

Account doesn't hold enough Option tokens for the operation.

error InsufficientBalance();
InvalidValue

Zero-amount mutation rejected.

error InvalidValue();
InvalidAddress

Zero address supplied where a contract is required.

error InvalidAddress();
LockedContract

Option has been paused by its owner.

error LockedContract();
NotEuropean

Reserved — kept for ABI compatibility.

error NotEuropean();
NoOracle

Call requiring an oracle was made on an option without one.

error NoOracle();
EuropeanExerciseDisabled

exercise was called on a European option.

error EuropeanExerciseDisabled();

ICollateral

Title: ICollateral — short-side token interface

Author: Greek.fi

ERC20 extension for the short-side position: holds underlying collateral, receives consideration on exercise, and handles post-expiry settlement + redemption math.

Functions

strike

Strike price (18-decimal fixed point, consideration per collateral; inverted for puts).

function strike() external view returns (uint256);
collateral

Underlying collateral token.

function collateral() external view returns (IERC20);
consideration

Consideration / quote token.

function consideration() external view returns (IERC20);
expirationDate

Unix expiration timestamp (uint40).

function expirationDate() external view returns (uint40);
isPut

true if this is a put.

function isPut() external view returns (bool);
isEuro

true if European-style (no pre-expiry exercise).

function isEuro() external view returns (bool);
locked

Owner-controlled emergency pause flag.

function locked() external view returns (bool);
consDecimals

Cached consideration.decimals().

function consDecimals() external view returns (uint8);
collDecimals

Cached collateral.decimals().

function collDecimals() external view returns (uint8);
STRIKE_DECIMALS

Decimal basis of the strike (always 18).

function STRIKE_DECIMALS() external view returns (uint8);
oracle

Settlement oracle (address(0) in American non-settled mode).

function oracle() external view returns (address);
settlementPrice

Latched oracle price (0 until first post-expiry settle).

function settlementPrice() external view returns (uint256);
reserveInitialized

true once the option-holder reserve has been initialised.

function reserveInitialized() external view returns (bool);
optionReserveRemaining

Collateral set aside for option-holder ITM claims; decremented on each claim.

function optionReserveRemaining() external view returns (uint256);
init

One-time initialisation (factory-only for clones).

function init(
address collateral_,
address consideration_,
uint40 expirationDate_,
uint256 strike_,
bool isPut_,
bool isEuro_,
address oracle_,
address option_,
address factory_
) external;
name

ERC20 name (rendered CLL[E]-coll-cons-strike-YYYY-MM-DD).

function name() external view returns (string memory);
symbol

ERC20 symbol (matches name).

function symbol() external view returns (string memory);
decimals

Matches collateral().decimals().

function decimals() external view returns (uint8);
collateralData

Metadata bundle for the collateral token.

function collateralData() external view returns (TokenData memory);
considerationData

Metadata bundle for the consideration token.

function considerationData() external view returns (TokenData memory);
option

Paired IOption contract (also the Ownable owner).

function option() external view returns (address);
factory

Factory that created this pair.

function factory() external view returns (address);
toConsideration

Floor-rounded conversion used for payouts.

function toConsideration(uint256 amount) external view returns (uint256);
toNeededConsideration

Ceiling-rounded conversion used when collecting consideration (exercise).

function toNeededConsideration(uint256 amount) external view returns (uint256);
toCollateral

Inverse of toConsideration — how much collateral a given consideration amount is worth.

function toCollateral(uint256 consAmount) external view returns (uint256);
mint

Mint (Option-only). Pulls collateral from account via the factory.

function mint(address account, uint256 amount) external;
redeem

Redeem amount of caller's Collateral post-expiry.

function redeem(uint256 amount) external;
redeem

Redeem amount of account's Collateral post-expiry (anyone may call — sweeps).

function redeem(address account, uint256 amount) external;
_redeemPair

Pair-redeem helper called by the paired IOption on pre-expiry close-out.

function _redeemPair(address account, uint256 amount) external;
redeemConsideration

Convert Collateral directly to consideration at the strike rate (American only).

function redeemConsideration(uint256 amount) external;
exercise

Exercise path invoked by IOption: caller pays consideration; account receives collateral.

function exercise(address account, uint256 amount, address caller) external;
settle

Latch the oracle settlement price. Idempotent; callable post-expiry.

function settle(bytes calldata hint) external;
_claimForOption

Option-holder ITM payout helper (Option-only).

function _claimForOption(address holder, uint256 amount) external returns (uint256);
sweep

Sweep a single holder's balance post-expiry.

function sweep(address holder) external;
sweep

Batch sweep.

function sweep(address[] calldata holders) external;
lock

Emergency pause (owner-only).

function lock() external;
unlock

Reverse of lock.

function unlock() external;

Events

Redeemed

Emitted whenever collateral or consideration is returned to a user.

event Redeemed(address option, address token, address holder, uint256 amount);
Settled

Emitted once per option when the oracle settlement price is latched.

event Settled(uint256 price);

Errors

ContractNotExpired

Pre-expiry-only path was called after expiration.

error ContractNotExpired();
ContractExpired

Post-expiry-only path was called before expiration.

error ContractExpired();
InsufficientBalance

Account lacks enough Collateral tokens for this operation.

error InsufficientBalance();
InvalidValue

Zero-amount (or derived-zero) mutation rejected.

error InvalidValue();
InvalidAddress

Zero address supplied where a contract is required.

error InvalidAddress();
LockedContract

Option has been paused by its owner.

error LockedContract();
FeeOnTransferNotSupported

Fee-on-transfer token detected (transfer debit ≠ transfer credit).

error FeeOnTransferNotSupported();
InsufficientCollateral

Contract holds less collateral than amount.

error InsufficientCollateral();
InsufficientConsideration

Caller holds less consideration than toConsideration(amount).

error InsufficientConsideration();
ArithmeticOverflow

Casting amount to uint160 would overflow the Permit2 cap.

error ArithmeticOverflow();
NoOracle

Call requiring an oracle was made on an option without one.

error NoOracle();
NotSettled

Read relies on a settlement price that hasn't been latched yet.

error NotSettled();
SettledOnly

Settled-only path invoked in non-settled mode.

error SettledOnly();
NonSettledOnly

Non-settled-only path invoked in settled mode.

error NonSettledOnly();

IFactory

Title: IFactory — option pair deployer + allowance hub

Author: Greek.fi

Deploys Option + Collateral pairs via EIP-1167 clones, serves as the single ERC20 approval point for every option pair it creates, and holds an operator + auto-mint-redeem registry.

Functions

COLL_CLONE

Collateral template clone.

function COLL_CLONE() external view returns (address);
OPTION_CLONE

Option template clone.

function OPTION_CLONE() external view returns (address);
blocklist

true if token is blocklisted for new option creation.

function blocklist(address token) external view returns (bool);
options

true if opt is an Option produced by this factory.

function options(address opt) external view returns (bool);
allowance

Factory-level allowance: how much of token the factory may pull from owner.

function allowance(address token, address owner) external view returns (uint256);
isBlocked

Alias for blocklist.

function isBlocked(address token) external view returns (bool);
autoMintRedeem

true if account has opted into Option's auto-mint / auto-redeem transfer hooks.

function autoMintRedeem(address account) external view returns (bool);
approvedOperator

true if operator has blanket authority over owner's Option tokens.

function approvedOperator(address owner, address operator) external view returns (bool);
createOption

Create a new Option + Collateral pair per the given parameters.

function createOption(CreateParams memory params) external returns (address);
createOption

Backward-compatibility overload for American non-settled options.

function createOption(address collateral, address consideration, uint40 expirationDate, uint96 strike, bool isPut)
external
returns (address);
createOptions

Batch form of createOption.

function createOptions(CreateParams[] memory params) external returns (address[] memory);
transferFrom

Pull tokens via the factory-level allowance. Only callable by Collateral clones.

function transferFrom(address from, address to, uint160 amount, address token) external returns (bool success);
approve

Set the caller's factory-level allowance for token.

function approve(address token, uint256 amount) external;
blockToken

Owner-only: block token from new option creation.

function blockToken(address token) external;
unblockToken

Owner-only: reverse of blockToken.

function unblockToken(address token) external;
enableAutoMintRedeem

Opt-in / opt-out of Option's auto-mint-on-transfer / auto-redeem-on-receive behaviour.

function enableAutoMintRedeem(bool enabled) external;
approveOperator

Grant / revoke blanket operator authority over the caller's options.

function approveOperator(address operator, bool approved) external;

Events

OptionCreated

Emitted for every newly-created option.

event OptionCreated(
address indexed collateral,
address indexed consideration,
uint40 expirationDate,
uint96 strike,
bool isPut,
bool isEuro,
address oracle,
address indexed option,
address coll
);
TokenBlocked

Emitted on blockToken / unblockToken.

event TokenBlocked(address token, bool blocked);
OperatorApproval

Emitted on approveOperator.

event OperatorApproval(address indexed owner, address indexed operator, bool approved);
AutoMintRedeemUpdated

Emitted on enableAutoMintRedeem.

event AutoMintRedeemUpdated(address indexed account, bool enabled);
Approval

Emitted on approve (factory-level allowance set).

event Approval(address indexed token, address indexed owner, uint256 amount);

Errors

BlocklistedToken

Attempted to create an option against a blocklisted collateral/consideration token.

error BlocklistedToken();
InvalidAddress

Zero address supplied where a contract is required.

error InvalidAddress();
InvalidTokens

Collateral and consideration were the same address.

error InvalidTokens();
InsufficientAllowance

transferFrom called with allowance < amount.

error InsufficientAllowance();
EuropeanRequiresOracle

isEuro requires an oracle source; none was provided.

error EuropeanRequiresOracle();
UnsupportedOracleSource

oracleSource couldn't be classified (neither a deployed oracle nor a v3 pool).

error UnsupportedOracleSource();