Skip to main content

ConvertibleDepositAuctioneer

Git Source

Inherits: IConvertibleDepositAuctioneer, Policy, PolicyEnabler, ReentrancyGuard

Title: Convertible Deposit Auctioneer

forge-lint: disable-start(mixed-case-function, screaming-snake-case-const)

Implementation of the {IConvertibleDepositAuctioneer} interface for a specific deposit token and 1 or more deposit periods

This contract implements an auction for convertible deposit tokens. It runs these auctions according to the following principles:

  • Auctions are of infinite duration
  • Auctions are of infinite capacity
  • Users place bids by supplying an amount of the configured bid token
  • The payout token is a receipt token (managed by {DepositManager}), which can be converted to OHM at the price that was set at the time of the bid
  • During periods of greater demand, the conversion price will increase
  • During periods of lower demand, the conversion price will decrease
  • The auction has a minimum price, below which the conversion price will not decrease
  • The auction has a target amount of convertible OHM to sell per day
  • When the target is reached, the amount of OHM required to increase the conversion price will decrease, resulting in more rapid price increases (assuming there is demand)
  • The auction parameters are able to be updated in order to tweak the auction's behaviour

State Variables

ROLE_EMISSION_MANAGER

The role that can perform periodic actions, such as updating the auction parameters

bytes32 public constant ROLE_EMISSION_MANAGER = "cd_emissionmanager"

_ohmScale

Scale of the OHM token

uint256 internal constant _ohmScale = 1e9

ONE_HUNDRED_PERCENT

uint24 public constant ONE_HUNDRED_PERCENT = 100e2

WAD

Fixed point scale (WAD)

uint256 internal constant WAD = 1e18

TICK_SIZE_BASE_MIN

Minimum and maximum allowed tick size base (in WAD)

uint256 internal constant TICK_SIZE_BASE_MIN = 1e18

TICK_SIZE_BASE_MAX

uint256 internal constant TICK_SIZE_BASE_MAX = 10e18

MAX_RPOW_EXP

Maximum safe exponent for rpow to prevent overflow

uint256 internal constant MAX_RPOW_EXP = 41

SECONDS_IN_DAY

Seconds in one day

uint256 internal constant SECONDS_IN_DAY = 1 days

_ENABLE_PARAMS_LENGTH

The length of the enable parameters

uint256 internal constant _ENABLE_PARAMS_LENGTH = 192

_TICK_SIZE_MINIMUM

The minimum tick size

uint256 internal constant _TICK_SIZE_MINIMUM = 1

_depositPeriodsEnabled

Whether the deposit period is enabled

mapping(uint8 depositPeriod => bool isDepositPeriodEnabled) internal _depositPeriodsEnabled

_DEPOSIT_ASSET

The deposit asset

IERC20 internal immutable _DEPOSIT_ASSET

_depositPeriods

Array of enabled deposit periods

EnumerableSet.UintSet internal _depositPeriods

_depositPeriodPreviousTicks

Previous tick for each deposit period

Use getCurrentTick() to recalculate and access the latest data

mapping(uint8 depositPeriod => Tick previousTick) internal _depositPeriodPreviousTicks

CD_FACILITY

Address of the Convertible Deposit Facility

ConvertibleDepositFacility public immutable CD_FACILITY

_auctionParameters

Auction parameters

These values should only be set through the setAuctionParameters() function

AuctionParameters internal _auctionParameters

_currentTickSize

The current tick size

uint256 internal _currentTickSize

_dayState

Auction state for the day

Day internal _dayState

_tickStep

The tick step

See getTickStep() for more information

uint24 internal _tickStep

_minimumBid

The minimum bid amount

The minimum bid amount is the minimum amount of deposit asset that can be bid See getMinimumBid() for more information

uint256 internal _minimumBid

_tickSizeBase

The base used for exponential tick size reduction (by 1/(base^multiplier)) when the day target is crossed (WAD, 1e18 = 1.0)

uint256 internal _tickSizeBase

_auctionResultsNextIndex

The index of the next auction result

uint8 internal _auctionResultsNextIndex

_auctionTrackingPeriod

The number of days that auction results are tracked for

uint8 internal _auctionTrackingPeriod

_auctionResults

The auction results, where a positive number indicates an over-subscription for the day.

The length of this array is equal to the auction tracking period

int256[] internal _auctionResults

_pendingDepositPeriodChanges

Queue of pending deposit period enable/disable changes

PendingDepositPeriodChange[] internal _pendingDepositPeriodChanges

Functions

constructor

constructor(address kernel_, address cdFacility_, address depositAsset_) Policy(Kernel(kernel_));

configureDependencies

Define module dependencies for this policy.

function configureDependencies() external override returns (Keycode[] memory dependencies);

Returns

NameTypeDescription
dependenciesKeycode[]- Keycode array of module dependencies.

requestPermissions

Function called by kernel to set module function permissions.

function requestPermissions() external view override returns (Permissions[] memory permissions);

Returns

NameTypeDescription
permissionsPermissions[]requests - Array of keycodes and function selectors for requested permissions.

VERSION

function VERSION() external pure returns (uint8 major, uint8 minor);

bid

Submit a bid for convertible deposit tokens

This function performs the following:

  • Updates the current tick based on the current state
  • Determines the amount of OHM that can be purchased for the deposit amount, and the updated tick capacity and price
  • Updates the day state, if necessary
  • Creates a convertible deposit position using the deposit amount, the average conversion price and the deposit period This function reverts if:
  • The contract is not active
  • The auction is disabled
  • The bid amount is below the minimum bid
  • Deposits are not enabled for the asset/period/operator
  • The depositor has not approved the DepositManager to spend the deposit asset
  • The depositor has an insufficient balance of the deposit asset
  • The calculated amount of OHM out is 0
  • The calculated amount of OHM out is < minOhmOut_
function bid(
uint8 depositPeriod_,
uint256 depositAmount_,
uint256 minOhmOut_,
bool wrapPosition_,
bool wrapReceipt_
)
external
override
nonReentrant
onlyEnabled
onlyDepositPeriodEnabled(depositPeriod_)
returns (uint256, uint256, uint256, uint256);

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period
depositAmount_uint256Amount of deposit asset to deposit
minOhmOut_uint256The minimum amount of OHM tokens that the deposit should convert to, in order to succeed. This acts as slippage protection.
wrapPosition_boolWhether to wrap the position as an ERC721
wrapReceipt_boolWhether to wrap the receipt as an ERC20

Returns

NameTypeDescription
<none>uint256ohmOut Amount of OHM tokens that the deposit can be converted to
<none>uint256positionId The ID of the position created by the DEPOS module to represent the convertible deposit terms
<none>uint256receiptTokenId The ID of the receipt token created by the DepositManager to represent the deposit
<none>uint256actualAmount The actual amount of deposit assets that were deposited (receipt tokens minted)

_bid

Internal function to submit an auction bid on the given deposit asset and period

This function expects the calling function to have already validated the contract state and deposit asset and period

function _bid(BidParams memory params) internal returns (uint256, uint256, uint256, uint256);

_previewBid

Internal function to preview the quantity of OHM tokens that can be purchased for a given deposit amount

This function performs the following:

  • Cycles through ticks until the deposit is fully converted
  • If the current tick has enough capacity, it will be used
  • If the current tick does not have enough capacity, the remaining capacity will be used. The current tick will then shift to the next tick, resulting in the capacity being filled to the tick size, and the price being multiplied by the tick step. Notes:
  • This function assumes that the auction is active (i.e. the target is non-zero) and the tick size is non-zero
  • The function returns the updated tick capacity and price after the bid
  • If the capacity of a tick is depleted (but does not cross into the next tick), the current tick will be shifted to the next one. This ensures that getCurrentTick() will not return a tick that has been depleted.
function _previewBid(uint256 deposit_, Tick memory tick_) internal view returns (BidOutput memory output);

Parameters

NameTypeDescription
deposit_uint256The amount of deposit to be bid
tick_Tick

Returns

NameTypeDescription
outputBidOutputThe output of the bid

previewBid

Get the amount of OHM tokens that could be converted for a bid

function previewBid(uint8 depositPeriod_, uint256 bidAmount_)
external
view
override
onlyEnabled
onlyDepositPeriodEnabled(depositPeriod_)
returns (uint256 ohmOut);

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period
bidAmount_uint256

Returns

NameTypeDescription
ohmOutuint256Amount of OHM tokens that the deposit could be converted to

_getConvertedDeposit

Internal function to preview the quantity of OHM tokens that can be purchased for a given deposit amount

This function does not take into account the capacity of the current tick

function _getConvertedDeposit(uint256 deposit_, uint256 price_) internal pure returns (uint256 convertibleAmount);

Parameters

NameTypeDescription
deposit_uint256The amount of deposit to be converted
price_uint256The price of the deposit in OHM

Returns

NameTypeDescription
convertibleAmountuint256The quantity of OHM tokens that can be purchased

_getNewTickPrice

Internal function to preview the new price of the current tick after applying the tick step

This function does not take into account the capacity of the current tick

function _getNewTickPrice(uint256 currentPrice_, uint256 tickStep_) internal pure returns (uint256 newPrice);

Parameters

NameTypeDescription
currentPrice_uint256The current price of the tick in terms of the bid token
tickStep_uint256The step size of the tick

Returns

NameTypeDescription
newPriceuint256The new price of the tick

_getNewTickSize

Internal function to calculate the new tick size based on the amount of OHM that has been converted in the current day

This implements exponential tick size reduction (by 1/(base^multiplier)) for each multiple of the day target that is reached If the new tick size is 0 or a calculation would result in an overflow, the tick size is set to the minimum

function _getNewTickSize(uint256 ohmOut_, AuctionParameters memory auctionParams_)
internal
view
returns (uint256 newTickSize);

Parameters

NameTypeDescription
ohmOut_uint256The amount of OHM that has been converted in the current day
auctionParams_AuctionParameters

Returns

NameTypeDescription
newTickSizeuint256The new tick size

_getOhmUntilNextThreshold

Internal function to calculate the amount of OHM remaining until the next day target threshold is reached

function _getOhmUntilNextThreshold(uint256 currentConvertible_, uint256 target_)
internal
pure
returns (uint256 ohmUntilThreshold);

Parameters

NameTypeDescription
currentConvertible_uint256The current cumulative amount of OHM that has been converted
target_uint256The day target

Returns

NameTypeDescription
ohmUntilThresholduint256The amount of OHM remaining until the next threshold

_getCurrentTick

function _getCurrentTick(uint8 depositPeriod_) internal view returns (Tick memory tick);

getCurrentTick

Calculate the current tick of the auction

This function calculates the tick at the current time. It uses the following approach:

  • Calculate the added capacity based on the time passed since the last bid, and add it to the current capacity to get the new capacity
  • Until the new capacity is <= to the standard tick size, reduce the capacity by the standard tick size and reduce the price by the tick step
  • If the calculated price is ever lower than the minimum price, the new price is set to the minimum price and the capacity is set to the standard tick size Notes:
  • If the target is 0, the price will not decay and the capacity will not change. It will only decay when a target is set again to a non-zero value. This function reverts if:
  • The deposit asset and period are not enabled
function getCurrentTick(uint8 depositPeriod_)
external
view
onlyDepositPeriodEnabled(depositPeriod_)
returns (Tick memory tick);

Returns

NameTypeDescription
tickTickTick info

getPreviousTick

Get the previous tick of the auction

This function returns the previous tick for the deposit period If the deposit period is not configured, all values will be 0

function getPreviousTick(uint8 depositPeriod_) public view override returns (Tick memory tick);

Returns

NameTypeDescription
tickTickTick info

getCurrentTickSize

Get the current tick size

function getCurrentTickSize() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256tickSize The current tick size

getAuctionParameters

Get the current auction parameters

function getAuctionParameters() external view override returns (AuctionParameters memory);

Returns

NameTypeDescription
<none>AuctionParametersauctionParameters Auction parameters

isAuctionActive

Check if the auction is currently active

The auction is considered active when target > 0

function isAuctionActive() external view override returns (bool);

Returns

NameTypeDescription
<none>boolisActive True if the auction is active, false if disabled

getDayState

Get the auction state for the current day

function getDayState() external view override returns (Day memory);

Returns

NameTypeDescription
<none>Dayday Day info

getTickStep

The multiplier applied to the conversion price at every tick, in terms of ONE_HUNDRED_PERCENT

This is stored as a percentage, where 100e2 = 100% (no increase)

function getTickStep() external view override returns (uint24);

Returns

NameTypeDescription
<none>uint24tickStep The tick step, in terms of ONE_HUNDRED_PERCENT

getMinimumBid

Get the minimum bid amount

function getMinimumBid() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256minimumBid The minimum bid amount required

getAuctionTrackingPeriod

Get the number of days that auction results are tracked for

function getAuctionTrackingPeriod() external view override returns (uint8);

Returns

NameTypeDescription
<none>uint8daysTracked The number of days that auction results are tracked for

getAuctionResultsNextIndex

Get the index of the next auction result

function getAuctionResultsNextIndex() external view override returns (uint8);

Returns

NameTypeDescription
<none>uint8index The index where the next auction result will be stored

getAuctionResults

Get the auction results for the tracking period

function getAuctionResults() external view override returns (int256[] memory);

Returns

NameTypeDescription
<none>int256[]results The auction results, where a positive number indicates an over-subscription for the day.

_validateNoDuplicatePendingChange

Validates that the requested action would not result in the same effective state, preventing redundant queue operations

function _validateNoDuplicatePendingChange(uint8 depositPeriod_, bool enable_) internal view;

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period to check
enable_boolWhether the requested operation is to enable (true) or disable (false)

_getEffectiveDepositPeriodState

Gets the effective state of a deposit period considering pending changes

function _getEffectiveDepositPeriodState(uint8 depositPeriod_) internal view returns (bool effectiveState);

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period to check

Returns

NameTypeDescription
effectiveStateboolThe effective enabled state (current state + pending changes)

_processPendingDepositPeriodChanges

Processes all pending deposit period changes

function _processPendingDepositPeriodChanges(uint256 tickSize_, uint256 minPrice_) internal;

Parameters

NameTypeDescription
tickSize_uint256The tick size to initialize new periods with
minPrice_uint256The minimum price to initialize new periods with

_enableDepositPeriod

Internal function to actually enable a deposit period

function _enableDepositPeriod(uint8 depositPeriod_, uint256 tickSize_, uint256 minPrice_) internal;

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period to enable
tickSize_uint256The tick size to initialize with
minPrice_uint256The minimum price to initialize with

_disableDepositPeriod

Internal function to actually disable a deposit period

function _disableDepositPeriod(uint8 depositPeriod_) internal;

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period to disable

getDepositAsset

Get the deposit asset

function getDepositAsset() external view override returns (IERC20);

Returns

NameTypeDescription
<none>IERC20asset The deposit asset

getDepositPeriods

Get the deposit periods for the deposit asset that are enabled

function getDepositPeriods() external view override returns (uint8[] memory);

Returns

NameTypeDescription
<none>uint8[]periods The deposit periods

isDepositPeriodEnabled

Returns whether a deposit period is enabled

function isDepositPeriodEnabled(uint8 depositPeriod_)
public
view
override
returns (bool isEnabled, bool isPendingEnabled);

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period

Returns

NameTypeDescription
isEnabledboolCurrent state
isPendingEnabledboolDesired state after applying all queued changes (equals isEnabled if no changes are queued)

_onlyDepositPeriodEnabled

function _onlyDepositPeriodEnabled(uint8 depositPeriod_) internal view;

onlyDepositPeriodEnabled

Modifier to check if a deposit period is enabled

modifier onlyDepositPeriodEnabled(uint8 depositPeriod_) ;

enableDepositPeriod

Enables a deposit period

Notes:

  • Enabling a deposit period will queue the change to be processed at the next setAuctionParameters call
  • Can be called while the contract is disabled (changes will be processed when contract is enabled)
  • The deposit period will reset the minimum price and tick size to the standard values when actually enabled This function will revert if:
  • The caller is not a manager or admin
  • The deposit period is 0
  • The effective state would result in enabling an already enabled period
function enableDepositPeriod(uint8 depositPeriod_) external override onlyManagerOrAdminRole;

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period

disableDepositPeriod

Disables a deposit period

Notes:

  • Disabling a deposit period will queue the change to be processed at the next setAuctionParameters call
  • Can be called while the contract is disabled (changes will be processed when contract is enabled) This function will revert if:
  • The caller is not a manager or admin
  • The deposit period is 0
  • The effective state would result in disabling an already disabled period
function disableDepositPeriod(uint8 depositPeriod_) external override onlyManagerOrAdminRole;

Parameters

NameTypeDescription
depositPeriod_uint8The deposit period

getDepositPeriodsCount

Get the number of deposit periods that are enabled

function getDepositPeriodsCount() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256count The number of deposit periods

getPendingDepositPeriodChanges

Gets the list of pending deposit period changes, from first to last

function getPendingDepositPeriodChanges() external view returns (PendingDepositPeriodChange[] memory);

_setAuctionParameters

function _setAuctionParameters(uint256 target_, uint256 tickSize_, uint256 minPrice_) internal;

_storeAuctionResults

function _storeAuctionResults(uint256 previousTarget_) internal;

_setNewTickParameters

Sets tick parameters for all enabled deposit periods

function _setNewTickParameters(
uint256 tickSize_,
uint256 minPrice_,
bool enforceCapacity_,
bool enforceMinPrice_,
bool setLastUpdate_
) internal;

Parameters

NameTypeDescription
tickSize_uint256If the new tick size is less than a tick's capacity (or enforceCapacity_ is true), the tick capacity will be set to this
minPrice_uint256If the new minimum price is greater than a tick's price (or enforceMinPrice_ is true), the tick price will be set to this
enforceCapacity_boolIf true, will set the capacity of each enabled deposit period to the value of tickSize_
enforceMinPrice_boolIf true, will set the price of each enabled deposit period to the value of minPrice_
setLastUpdate_boolIf true, will set the tick's last update to the current timestamp

_updateCurrentTicks

Takes a snapshot of the current tick values for enabled deposit periods

function _updateCurrentTicks(uint8 excludedDepositPeriod_) internal;

Parameters

NameTypeDescription
excludedDepositPeriod_uint8The deposit period that should be excluded from updates. Provide 0 to not exclude (since 0 is an invalid deposit period).

setAuctionParameters

Update the auction parameters

This function assumes that the the caller is only calling once per period (day), as the contract does not track epochs or timestamps. This function performs the following:

  • Performs validation of the inputs
  • Captures the current tick state for all enabled deposit periods
  • Stores the auction results for the previous period
  • Sets the auction parameters
  • Sets the tick parameters for all enabled deposit periods
  • Processes any pending deposit period changes This function reverts if:
  • The caller does not have the ROLE_EMISSION_MANAGER role
  • The new tick size is 0
  • The new min price is 0
function setAuctionParameters(uint256 target_, uint256 tickSize_, uint256 minPrice_)
external
override
onlyRole(ROLE_EMISSION_MANAGER);

Parameters

NameTypeDescription
target_uint256new target sale per day
tickSize_uint256new size per tick
minPrice_uint256new minimum tick price

setTickStep

Sets the multiplier applied to the conversion price at every tick, in terms of ONE_HUNDRED_PERCENT

This function will revert if:

  • The caller does not have the ROLE_ADMIN role
  • The new tick step is < 100e2
function setTickStep(uint24 newStep_) public override onlyManagerOrAdminRole;

Parameters

NameTypeDescription
newStep_uint24The new tick step

getTickSizeBase

Get the exponent base used for determining the tick size when the day target is crossed

function getTickSizeBase() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256baseWad The tick size base

setTickSizeBase

Set the exponent base used for determining the tick size when the day target is crossed

This function will revert if:

  • The caller does not have the ROLE_ADMIN or ROLE_MANAGER role
  • The new tick size base is not within the bounds (1e18 ≤ base ≤ 10e18)
function setTickSizeBase(uint256 newBase_) public override onlyManagerOrAdminRole;

Parameters

NameTypeDescription
newBase_uint256The new tick size base

setAuctionTrackingPeriod

Set the number of days that auction results are tracked for

Notes:

  • Calling this function will erase the previous auction results, which in turn may affect the bond markets created to sell under-sold OHM capacity This function will revert if:
  • The caller does not have the ROLE_ADMIN role
  • The new auction tracking period is 0
function setAuctionTrackingPeriod(uint8 days_) public override onlyManagerOrAdminRole;

Parameters

NameTypeDescription
days_uint8The new auction tracking period

setMinimumBid

Set the minimum bid amount

This function will revert if:

  • The caller does not have the ROLE_ADMIN or ROLE_MANAGER role
function setMinimumBid(uint256 minimumBid_) external override onlyManagerOrAdminRole;

Parameters

NameTypeDescription
minimumBid_uint256The new minimum bid amount

_enable

Implementation-specific enable function

This function will revert if:

  • The enable data is not the correct length
  • The enable data is not an encoded EnableParams struct
  • The auction parameters are invalid
  • The tick step is invalid
  • The auction tracking period is invalid This function performs the following:
  • Sets the auction parameters
  • Sets the tick step
  • Sets the auction tracking period
  • Ensures all existing ticks have the current parameters
  • Processes any pending deposit period changes with the new parameters (including any that were pending prior to disabling)
  • Resets the day state
  • Resets the auction results
function _enable(bytes calldata enableData_) internal override;

Parameters

NameTypeDescription
enableData_bytesCustom data that can be used by the implementation. The format of this data is left to the discretion of the implementation.

Structs

BidOutput

struct BidOutput {
uint256 tickCapacity;
uint256 tickPrice;
uint256 tickSize;
uint256 depositIn;
uint256 ohmOut;
}

BidParams

struct BidParams {
uint8 depositPeriod;
uint256 depositAmount;
uint256 minOhmOut;
bool wrapPosition;
bool wrapReceipt;
}

PendingDepositPeriodChange

struct PendingDepositPeriodChange {
uint8 depositPeriod;
bool enable;
}