MinterAmm

Polygon Contract Address

View on Polygonscan

Source Code

MinterAmm.sol

Overview

The MinterAmm is an Automated Market Maker or "AMM" designed specifically for trading options for ERC20 tokens. It exposes functions for buying and selling bToken as well as selling wToken. Each MinterAmm trades one of the two types of option Series: Puts or Calls. All option premiums will be in units of the AMM's collateral token, which for a Call AMM will be equal to the underlying token (e.g. a WBTC Call AMM's collateral token is WBTC), and for a Put AMM be equal to USDC (e.g. a WBTC Put AMM's collateral token is USDC). It uses the collateral token added by liquidity providers to mint bTokens and wTokens, keeping the wTokens for itself and selling the bTokens to traders. The AMM exposes functions for providing and withdrawing liquidity in the AMM pool. It is often useful to know the total value of all the option tokens and collateral token that comprise a pool, and there is a function for that as well.

Option Token Pricing

When a trader goes to buy or sell option tokens via the MinterAmm, the quoted premium includes consists of the component from the onchain Black-Scholes approximation formula, as well as a price impact component. It is not possible to guarantee an exact option token price, because the price depends on the reserves of bToken and wToken held by the AMM, and those reserves might change if another transaction which affects the reserve amounts gets mined before the original trader's transaction gets mined. This is also true for when an LP withdraws their liquidity from the AMM and sets sellTokens = true, which will sell the wTokens owed to trader back to AMM in return for collateral token. This is why all of these functions take some slippage function argument, either collateralMinimum when selling option tokens, or collateralMaximum when buying option tokens.

However, it's still useful for the trader to know what the expected price will be, and if there are no changes in the reserves in between when the trader broadcasts the transaction and when the trader's transaction gets mined, this will indeed be the price of the trade. The AMM exposes functions for calculating the expected price when selling bTokens, buying 'bTokens', and selling wTokens.

For more details on the pricing formulas used throughout the AMM, see the protocol math section

Functions

Modifiers

minTradeSize

modifier minTradeSize(uint256 tradeSize) {
require(
tradeSize >= MINIMUM_TRADE_SIZE,
"Buy/Sell amount below min size"
);
_;
}

Prevents low-valued trades from occurring. Due to numeric rounding issues with Solidity, if a user passes a low-valued argument in bTokenBuy, bTokenSell, or wTokenSell unexpected behavior can occur. So to preclude this from happening we gate these function calls with the minTradeSize modifier

onlyOwner

modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}

Certain functions can only be called by the SIREN protocol owner multisig address. The functions updateImplementation and transferOwnership exist so that the owners can update the contracts in the event of a critical vulnerability that puts user's funds at risk.

View/Pure Functions

lpToken

function lpToken(
) public view returns (ISimpleToken)

Returns the address of the ERC20 contract used for this MinterAmm's LP Token.

underlyingToken

function underlyingToken(
) public view returns (IERC20)

Returns the address of the ERC20 token whose price determines the (glossary.md#moneyness) of the Series this AMM trades. For example, both WBTC Call option series and WBTC Put option series share WBTC as their underlying token, because the price of WBTC determines whether the Series is in or out of the money. If this AMM trades Calls then this will be the same token as the collateralToken.

priceToken

function priceToken(
) public view returns (IERC20)

Returns the address of the ERC20 token used to denominate the strike price of the Series this AMM trades. This will almost always be USDC, but in the future could be different when SIREN denominates prices in something other than USDC. If this AMM trades Puts then this will be the same token as the collateralToken

collateralToken

function collateralToken(
) public view returns (IERC20)

Returns the address of the ERC20 token this AMM uses for collateral. This is the token used to denominate all option prices (a.k.a. premiums) in the MinterAmm, as well as the liquidity provided by LPs

If this is a Call Series then the collateral token will be equal to the underlyingToken, because a Call gives the holder the right to buy the underlying. And if this is a Put Series then the collateral token will be equal to the priceToken, because a Put gives the holder the right to sell the underlying.

seriesController

function seriesController(
) public view returns (ISeriesController)

Returns the SeriesController associated with this MinterAmm. The MinterAmm uses the SeriesController to interact with the Series it trades.

erc1155Controller

function erc1155Controller(
) public view returns (IERC1155)

Returns the ERC1155Controller associated with this MinterAmm. The MinterAmm uses the ERC1155Controller to interact with the the option tokens of the Series it trades.

tradeFeeBasisPoints

function tradeFeeBasisPoints(
) public view returns (uint16)

The fee, denominated in bips (i.e. hundredths of a percent), that the MinterAmm takes when it executes a trade.

volatilityFactor

function volatilityFactor(
) public view returns (uint256)

The volatility coefficient to use in the Black-Scholes approximation formula. This value is calculated offchain to save gas, and updated by the contract [owner]((glossary.md#owner)). It is equal to the implied volatility multiplied by 0.4, multiplied by the square root of the number of seconds in a year (i.e. implied_volatility * 0.4 * Math.sqrt(365 * 24 * 60 * 60))

MINIMUM_TRADE_SIZE

function MINIMUM_TRADE_SIZE(
) public view returns (uint256)

Equal to 1000. This is the minimum trade sized used in the minTradeSize modifier.

getTotalPoolValue

function getTotalPoolValue(bool includeUnclaimed)
public
view
returns (uint256)

Returns the total value of all the tokens held by the pool, denominated in units of collateral token. The AMM's value stems from several different tokens: The option tokens it holds, as well as the [collateral token] is has received from LP's and from collecting option premiums.

The argument includeUnclaimed exists only as a way to save on gas when calculating total pool value on chain; if the caller knows all option tokens have been claimed (which will be true if claimAllExpiredTokens has just been called), it can pass false for includeUnclaimed and skip calculating their value.

Parameters

Name

Type

Description

includeUnclaimed

bool

true if the value of expired of unclaimed wToken should be included in the total pool calculation, and false if it should not be included

getAllSeries

function getAllSeries() external view returns (uint64[] memory)

Returns the array of seriesIds for the Series this AMM trades.

getSeries

function getSeries(uint64 seriesId)
external
view
returns (ISeriesController.Series memory)

Returns the Series struct with the given seriesId traded by this AMM.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

getVirtualReserves

function getVirtualReserves(uint64 seriesId)
public
view
returns (uint256, uint256)

Returns the balances of bToken and wToken available to the AMM for the given seriesId. The AMM uses these balances as inputs into its bonding curve equation to compute the premiums for buying and selling option tokens.

We use the word "virtual" because the balances returned by this function include not only the raw balances of bToken and wToken held by the AMM, but additionally those option tokens that could be minted using the AMM's collateral token. The amounts returned will likely be slightly less than the full bToken and wToken amounts owned by the AMM, because the amounts returned must satisfy the ratio of the wToken and bToken prices computed by the onchain Black-Scholes approximation formula. See the documentation section on protocol math for the motivation behind calculating virtual reserve balances in this manner.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

Return Values

Name

Type

Description

bTokenVirtualBalance

uint256

The amount of bToken available on the AMM

wTokenVirtualBalance

uint256

The amount of wToken available on the AMM

getPriceForSeries

function getPriceForSeries(uint64 seriesId)
external
view
returns (uint256)

Returns the price of the underlyingToken of the given seriesId denominated in the priceToken. The returned values always use 8 decimal places. For example, if the Series' underlying == WBTC and price == USDC, then this function will return 4500000000000 ($45_000 in human readable units).

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

calcPrice

function calcPrice(
uint256 timeUntilExpiry,
uint256 strike,
uint256 currentPrice,
uint256 volatility,
bool isPutOption
) public pure returns (uint256)

Returns the price of a Series' bToken as a percentage of collateral locked by 1 option token, multiplied by a scaling factor of 1e18. For instance, if the price of 1 bToken is 0.1 * 1e18, and the bToken's Series has a strike price of $35,000, then the price of 1 bToken in units of USDC is $3,500.

The scaling factor exists as a workaround to Solidity's lack of floating point numerics. If we did not use the scaling factor, then any division of the price variable would round down to 0. So a price of 0.5 * 1e18 and be thought treated logically as simply 0.5.

calcPrice uses a Black-Scholes approximation formula for pricing bTokens. See the section protocol math for more details on the approximation formula.

The price of a Series' wToken is always 1e18 - price_of_btoken, so in the above scenario, the price of the wToken would be $35,000 - $3,500 = $31,500.

Parameters

Name

Type

Description

timeUntilExpiry

uint256

The number of seconds until the Series' expiration date

strike

uint256

The strike price of the Series'. See The Series struct parameters section for more details on the strike price

currentPrice

uint256

The spot price of the Series' underlying token, denominated in units of price token with 8 decimals

volatility

uint256

The AMM's volatility factor

isPutOption

uint256

true if the Series is for a Put option, and false if it's for a Call option

bTokenGetCollateralIn

function bTokenGetCollateralIn(uint64 seriesId, uint256 bTokenAmount)
public
view
returns (uint256)

Returns the premium for purchasing from the AMM bTokenAmount of bTokens on the given seriesId in units of collateral token. The premium has two components: the price returned by the Black-Scholes approximation formula, and the added cost of price impact.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

bTokenAmount

uint256

The amount of bToken the caller wants to receive in return for paying the premium

bTokenGetCollateralOut

function bTokenGetCollateralOut(uint64 seriesId, uint256 bTokenAmount)
public
view
returns (uint256)

Returns the premium for selling to the AMM bTokenAmount of bTokens on the given seriesId in units of collateral token. The premium has two components: the price returned by the Black-Scholes approximation formula, and the price impact.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

bTokenAmount

uint256

The amount of bToken the caller wants to sell to the AMM

wTokenGetCollateralOut

function wTokenGetCollateralOut(uint64 seriesId, uint256 wTokenAmount)
public
view
returns (uint256)

Returns the premium for selling to the AMM wTokenAmount of wTokens on the given seriesId in units of collateral token. The premium has two components: the price returned by the Black-Scholes approximation formula, and the price impact.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

wTokenAmount

uint256

The amount of wToken the caller wants to sell to the AMM

getCollateralValueOfAllExpiredOptionTokens

function getCollateralValueOfAllExpiredOptionTokens()
public
view
returns (uint256)

Returns the amount of collateral token the AMM would receive by redeeming all expired bTokens and wTokens held by the AMM. This function is useful for offchain clients to calculate the total collateral token available to the AMM. The offchain clients can use this to calculate the collateral owed to LPs when The LPs withdraw their LP Token

getOptionTokensSaleValue

function getOptionTokensSaleValue(uint256 lpTokenAmount)
external
view
returns (uint256)

Returns the expected amount of collateral token an LP will receive for selling the bTokens and wTokens held by the AMM on the LP's behalf. This function is useful for offchain clients to calculate value of the option tokens owed to the holder of lpTokenAmount of LP Token.

For example, if lpTokenAmount is equal to 10% of the total supply of LP Token, then the return value of MinterAmm.getOptionTokensSaleValue will be equal to the premiums for selling 10% of the bTokens and wTokens held by the AMM. See MinterAmm.bTokenGetCollateralOut and MinterAmm.wTokenGetCollateralOut for how to calculate the premiums when selling bTokens and wTokens.

Parameters

Name

Type

Description

lpTokenAmount

uint256

The amount of LP token that the caller will burn in return for collateral

Mutating Functions

provideCapital

function provideCapital(uint256 collateralAmount, uint256 lpTokenMinimum)
external

Transfers the caller's collateral token to the AMM so it can be used for minting options, and in return sends LP Token the caller can use to later withdraw their share of the AMM's total value.

The amount of LP Token the caller receives depends on the AMM's total value, which itself depends on the AMM's reserves of option tokens and collateral token. The reserve amounts may change when the caller's transaction finally gets included in the blockchain, so this function takes an lpTokenMinimum argument to specify the minimum acceptable amount of LP Token the caller will receive, and any lower than this will cause the function call to revert.

LPs profit when the fees they acquire from selling options is greater than their losses from the options they sell going deeper in the money.

Parameters

Name

Type

Description

collateralAmount

uint256

The amount of collateral token to transfer to the AMM

lpTokenMinimum

uint256

The minimum amount of LP Token the caller is willing to receive for providing collateraAmount of collateral token

withdrawCapital

function withdrawCapital(
uint256 lpTokenAmount,
bool sellTokens,
uint256 collateralMinimum
) public

The caller burns lpTokenAmount of their LP Token and in exchange receives their pro-rata share of the AMM's tokens. For example, if lpTokenAmount is equal to 10% of the total supply of LP Tokens, then the caller will receive 10% of the AMM's collateral token as well as 10% of each of the option tokens the AMM holds. If sellTokens is set to true, then the caller will receive only collateral token, because all of LP's option tokens will be sold to the AMM in exchange for collateral token. However, because of price impact the value of the collateral token the LP receives may be less than 10% of the AMM's total value.

The amount of collateral token the caller receives depends on the AMM's total value, which itself depends on the AMM's reserves of option tokens and collateral token. The reserve amounts may change when the caller's transaction finally gets included in the blockchain, so this function takes a collateralMinimum argument to specify the minimum acceptable amount of collateral token the caller will receive, and any lower than this will cause the function call to revert.

Parameters

Name

Type

Description

lpTokenAmount

uint256

The amount of LP Token to burn

sellTokens

bool

true if the caller wishes to sell their option tokens to the AMM and only receive collateral token, and false if they wish to receive less collateral token but receive their pro-rata share of the AMM's option tokens which they can sell at a later time

collateralMinimum

uint256

The minimum amount of collateral token the caller wishes to receive for burning their LP Token

claimAllExpiredTokens

function claimAllExpiredTokens() public

Redeems all the option tokens held by the AMM that have recently expired. See MinterAmm.claimExpiredTokens

claimExpiredTokens

function claimExpiredTokens(uint64 seriesId) public

Redeems the given Series' expired bTokens and wTokens held by the AMM. If the Series is out of the money then all bTokens will be worthless, and the wTokens will be claimed for the collateral value locked when minting them. If the Series is in the money then both the bTokens and wTokens will have some non-zero value.

The AMM redeems all expired option tokens every time an LP provides or withdraws liquidity, so the AMM is constantly converting expired option tokens back into collateral it can use to mint further options

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

bTokenBuy

function bTokenBuy(
uint64 seriesId,
uint256 bTokenAmount,
uint256 collateralMaximum
) external minTradeSize(bTokenAmount) returns (uint256)

Purchases bTokenAmount of bToken from the AMM, but will revert if the premium calculated by the AMM exceeds collateralMaximum. The return value is the premium (in units of collateral token) the caller pays. Prior to calling this function, the caller must approve the AMM for the collateralMaximum amount. See MinterAmm.bTokenGetCollateralIn for how the AMM calculates the premium.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

bTokenAmount

uint256

The amount of bToken the caller wishes to purchase

collateralMaximum

uint256

The maximum amount of collateral the caller wishes to pay for the bToken. The actual premium can exceed this value due to slippage

bTokenSell

function bTokenSell(
uint64 seriesId,
uint256 bTokenAmount,
uint256 collateralMinimum
) external minTradeSize(bTokenAmount) returns (uint256)

Sells bTokenAmount of bToken to the AMM, but will revert if the premium calculated by the AMM goes below collateralMinimum. The return value is the premium (in units of collateral token) the caller receives. Prior to calling this function, the caller must approve the AMM for the bTokenAmount. See MinterAmm.bTokenGetCollateralOut for how the AMM calculates the premium.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

bTokenAmount

uint256

The amount of bToken the caller wishes to purchase

collateralMinimum

uint256

The minimum amount of collateral the caller wishes to receive for selling their bToken, The actual premium can go below this value due to slippage

wTokenSell

function wTokenSell(
uint64 seriesId,
uint256 wTokenAmount,
uint256 collateralMinimum
) external minTradeSize(wTokenAmount) returns (uint256)

Sells wTokenAmount of wToken to the AMM, but will revert if the premium calculated by the AMM goes below collateralMinimum. The return value is the premium (in units of collateral token) the caller receives. Prior to calling this function, the caller must approve the AMM for the wTokenAmount. See MinterAmm.wTokenGetCollateralOut for how the AMM calculates the premium.

Parameters

Name

Type

Description

seriesId

uint64

The ID of the Series

wTokenAmount

uint256

The amount of wToken the caller wishes to purchase

collateralMinimum

uint256

The minimum amount of collateral the caller wishes to receive for selling their wToken, The actual premium can go below this value due to slippage

setVolatilityFactor

function setVolatilityFactor(uint256 _volatilityFactor) public onlyOwner

Sets a new volatility factor for this AMM to use when pricing option premiums. See MinterAmm.calcPrice for how it is used.

Parameters

Name

Type

Description

_volatilityFactor

uint256

The new volatility factor, equal to 0.4 * implied_vol * sqrt(num_seconds_in_year)

updateImplementation

function updateImplementation(
address _newImplementation
) external onlyOwner

Updates this MinterAmm's logic contract. The SIREN protocol's contracts use the EIP-1822 standard for implementing upgradeable contracts. This allows us to update vulnerable contracts and keep users' option tokens safe. When the SIREN protocol has reached a certain level of stability, we can remove these safety guards and ensure no one on the Siren team can swap out the smart contract functionality.

Parameters

Name

Type

Description

_newImplementation

address

The address of the new logic contract to use for the MinterAmm's function implementations

transferOwnership

function transferOwnership(address newOwner) external onlyOwner

Removes ownership from the current owner and assigns ownership to the newOwner address. See the onlyOwner modifier for the permissions granted to the protocol admin.

Parameters

Name

Type

Description

newOwner

address

The address of the new admin for this contract