Skip to main content

MonoCooler

Git Source

Inherits: IMonoCooler, Policy, PolicyAdmin

A borrow/lend market where users can deposit their gOHM as collateral and then borrow a stablecoin debt token up to a certain LTV

  • The debt token may change over time - eg DAI to USDS (or USDC), determined by the CoolerTreasuryBorrower
  • The collateral and debt amounts tracked on this contract are always reported in wad, ie 18 decimal places
  • gOHM collateral can be delegated to accounts for voting, via the DLGTE module
  • Positions can be liquidated if the LTV breaches the 'liquidation LTV' as determined by the LTV Oracle
  • Users may set an authorization for one other address to act on its behalf.

State Variables

_COLLATERAL_TOKEN

The collateral token, eg gOHM

ERC20 private immutable _COLLATERAL_TOKEN;

_OHM

The OHM token

ERC20 private immutable _OHM;

_STAKING

The OHM staking contract

IStaking private immutable _STAKING;

_MIN_DEBT_REQUIRED

The minimum debt a user needs to maintain

uint256 private immutable _MIN_DEBT_REQUIRED;

DOMAIN_SEPARATOR

Returns the domain separator used in the encoding of the signature for setAuthorizationWithSig(), as defined by {EIP712}.

bytes32 public immutable override DOMAIN_SEPARATOR;

MINTR

MINTRv1 public MINTR;

DLGTE

DLGTEv1 public DLGTE;

totalCollateral

The total amount of collateral posted across all accounts.

To 18 decimal places

uint128 public override totalCollateral;

totalDebt

The total amount of debt which has been borrowed across all users as of the latest checkpoint

To 18 decimal places

uint128 public override totalDebt;

interestAccumulatorRay

The accumulator index used to track the compounding of debt, starting at 1e27 at genesis

To RAY (1e27) precision

uint256 public override interestAccumulatorRay;

interestRateWad

The flat interest rate (APR).

Interest (approximately) continuously compounds at this rate.

uint96 public override interestRateWad;

ltvOracle

The oracle serving both the Max Origination LTV and the Liquidation LTV

ICoolerLtvOracle public override ltvOracle;

liquidationsPaused

Liquidations may be paused in order for users to recover/repay debt after emergency actions or interest rate changes

bool public override liquidationsPaused;

borrowsPaused

Borrows may be paused for emergency actions or deprecating the facility

bool public override borrowsPaused;

interestAccumulatorUpdatedAt

The last time the global debt accumulator was updated

uint40 public override interestAccumulatorUpdatedAt;

treasuryBorrower

The policy which borrows/repays from Treasury on behalf of Cooler

ICoolerTreasuryBorrower public override treasuryBorrower;

allAccountState

A per account store, tracking collateral/debt as of their latest checkpoint.

mapping(address => AccountState) private allAccountState;

authorizations

Whether authorized is authorized to act on authorizer's behalf for all user actions up until the authorizationDeadline unix timestamp.

Anyone is authorized to modify their own positions, regardless of this variable.

mapping(address => mapping(address => uint96)) public override authorizations;

authorizationNonces

The authorizer's current nonce. Used to prevent replay attacks with EIP-712 signatures.

mapping(address => uint256) public override authorizationNonces;

_RAY

Extra precision scalar

uint256 private constant _RAY = 1e27;

_DOMAIN_TYPEHASH

The EIP-712 typeHash for EIP712Domain.

bytes32 private constant _DOMAIN_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");

_AUTHORIZATION_TYPEHASH

The EIP-712 typeHash for Authorization.

bytes32 private constant _AUTHORIZATION_TYPEHASH = keccak256(
"Authorization(address account,address authorized,uint96 authorizationDeadline,uint256 nonce,uint256 signatureDeadline)"
);

_EXPECTED_DECIMALS

expected decimals for the _COLLATERAL_TOKEN and treasuryBorrower

uint8 private constant _EXPECTED_DECIMALS = 18;

MAX_INTEREST_RATE

Cannot set an interest rate higher than 10%

uint96 private constant MAX_INTEREST_RATE = 0.1e18;

Functions

constructor

constructor(
address ohm_,
address gohm_,
address staking_,
address kernel_,
address ltvOracle_,
uint96 interestRateWad_,
uint256 minDebtRequired_
) 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 requests);

Returns

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

setAuthorization

Sets the authorization for authorized to manage msg.sender's positions until authorizationDeadline

Authorization can be revoked by setting the authorizationDeadline into the past

function setAuthorization(address authorized, uint96 authorizationDeadline) external override;

Parameters

NameTypeDescription
authorizedaddressThe authorized address.
authorizationDeadlineuint96The unix timestamp that they the authorization is valid until.

setAuthorizationWithSig

Sets the authorization for authorization.authorized to manage authorization.authorizer's positions until authorization.authorizationDeadline.

Warning: Reverts if the signature has already been submitted.

function setAuthorizationWithSig(Authorization memory authorization, Signature calldata signature) external override;

Parameters

NameTypeDescription
authorizationAuthorizationThe Authorization struct.
signatureSignatureThe signature.

isSenderAuthorized

Returns whether the sender is authorized to manage onBehalf's positions.

function isSenderAuthorized(address sender, address onBehalfOf) public view override returns (bool);

_requireSenderAuthorized

function _requireSenderAuthorized(address sender, address onBehalfOf) internal view;

addCollateral

Deposit gOHM as collateral

function addCollateral(
uint128 collateralAmount,
address onBehalfOf,
IDLGTEv1.DelegationRequest[] calldata delegationRequests
) external override;

Parameters

NameTypeDescription
collateralAmountuint128The amount to deposit to 18 decimal places - MUST be greater than zero
onBehalfOfaddressA caller can add collateral on behalf of themselves or another address. - MUST NOT be address(0)
delegationRequestsIDLGTEv1.DelegationRequest[]The set of delegations to apply after adding collateral. - MAY be empty, meaning no delegations are applied. - MUST ONLY be requests to add delegations, and that total MUST BE less than the collateralAmount argument - If onBehalfOf does not equal the caller, the caller must be authorized via setAuthorization() or setAuthorizationWithSig()

withdrawCollateral

Withdraw gOHM collateral.

  • Account LTV MUST be less than or equal to maxOriginationLtv after the withdraw is applied
  • At least collateralAmount collateral MUST be undelegated for this account. Use the delegationRequests to rescind enough as part of this request.
function withdrawCollateral(
uint128 collateralAmount,
address onBehalfOf,
address recipient,
IDLGTEv1.DelegationRequest[] calldata delegationRequests
) external override returns (uint128 collateralWithdrawn);

Parameters

NameTypeDescription
collateralAmountuint128The amount of collateral to remove to 18 decimal places - MUST be greater than zero - If set to type(uint128).max then withdraw the max amount up to maxOriginationLtv
onBehalfOfaddressA caller can withdraw collateral on behalf of themselves or another address if authorized via setAuthorization() or setAuthorizationWithSig()
recipientaddressSend the gOHM collateral to a specified recipient address. - MUST NOT be address(0)
delegationRequestsIDLGTEv1.DelegationRequest[]The set of delegations to apply before removing collateral. - MAY be empty, meaning no delegations are applied. - MUST ONLY be requests to undelegate, and that total undelegated MUST BE less than the collateralAmount argument

borrow

Borrow debtToken

  • Account LTV MUST be less than or equal to maxOriginationLtv after the borrow is applied
  • Total debt for this account MUST be greater than or equal to the minDebtRequired after the borrow is applied
function borrow(uint128 borrowAmount, address onBehalfOf, address recipient)
external
override
returns (uint128 amountBorrowed);

Parameters

NameTypeDescription
borrowAmountuint128
onBehalfOfaddressA caller can borrow on behalf of themselves or another address if authorized via setAuthorization() or setAuthorizationWithSig()
recipientaddressSend the borrowed token to a specified recipient address. - MUST NOT be address(0)

Returns

NameTypeDescription
amountBorroweduint128amountBorrowedInWad The amount actually borrowed.

repay

Repay a portion, or all of the debt

  • MUST NOT be called for an account which has no debt
  • If the entire debt isn't paid off, then the total debt for this account MUST be greater than or equal to the minDebtRequired after the borrow is applied
function repay(uint128 repayAmount, address onBehalfOf) external override returns (uint128 amountRepaid);

Parameters

NameTypeDescription
repayAmountuint128
onBehalfOfaddressA caller can repay the debt on behalf of themselves or another address

Returns

NameTypeDescription
amountRepaiduint128amountRepaidInWad The amount actually repaid.

applyDelegations

Apply a set of delegation requests on behalf of a given user.

function applyDelegations(IDLGTEv1.DelegationRequest[] calldata delegationRequests, address onBehalfOf)
external
override
returns (uint256 totalDelegated, uint256 totalUndelegated, uint256 undelegatedBalance);

Parameters

NameTypeDescription
delegationRequestsIDLGTEv1.DelegationRequest[]The set of delegations to apply. - MAY be empty, meaning no delegations are applied. - Total collateral delegated as part of these requests MUST BE less than the account collateral. - MUST NOT apply delegations that results in more collateral being undelegated than the account has collateral for. - It applies across total gOHM balances for a given account across all calling policies So this may (un)delegate the account's gOHM set by another policy
onBehalfOfaddressA caller can apply delegations on behalf of themselves or another address if authorized via setAuthorization() or setAuthorizationWithSig()

applyUnhealthyDelegations

If an account becomes unhealthy and has many delegations such that liquidation can't be performed in one transaction, then delegations can be rescinded over multiple transactions in order to get this account into a state where it can then be liquidated.

function applyUnhealthyDelegations(address account, uint256 autoRescindMaxNumDelegates)
external
override
returns (uint256 totalUndelegated, uint256 undelegatedBalance);

batchLiquidate

Liquidate one or more accounts which have exceeded the liquidationLtv The gOHM collateral is seized (unstaked to OHM and burned), and the accounts debt is wiped.

  • If one of the provided accounts in the batch hasn't exceeded the max LTV then it is skipped.
  • Delegations are auto-rescinded if required. Ordering of this is not guaranteed.*
function batchLiquidate(address[] calldata accounts)
external
override
returns (uint128 totalCollateralClaimed, uint128 totalDebtWiped, uint128 totalLiquidationIncentive);

setLtvOracle

Set the oracle which serves the max Origination LTV and the Liquidation LTV

function setLtvOracle(address newOracle) external override onlyAdminRole;

setTreasuryBorrower

Set the policy which borrows/repays from Treasury on behalf of Cooler

function setTreasuryBorrower(address newTreasuryBorrower) external override;

setLiquidationsPaused

Liquidation may be paused in order for users to recover/repay debt after emergency actions

Can only be called by emergency or admin roles

function setLiquidationsPaused(bool isPaused) external override onlyEmergencyOrAdminRole;

setBorrowPaused

Pause any new borrows of debtToken

Can only be called by emergency or admin roles

function setBorrowPaused(bool isPaused) external override onlyEmergencyOrAdminRole;

setInterestRateWad

Update the interest rate (APR), specified in Wad (18 decimals)

  • Cannot be set higher than 10% APR
  • Interest (approximately) continuously compounds at this rate.*
function setInterestRateWad(uint96 newInterestRate) external override onlyAdminRole;

setMaxDelegateAddresses

Allow an account to have more or less than the DEFAULT_MAX_DELEGATE_ADDRESSES number of delegates.

function setMaxDelegateAddresses(address account, uint32 maxDelegateAddresses) external override onlyAdminRole;

checkpointDebt

Update and checkpoint the total debt up until now

May be useful in case there are no new user actions for some time.

function checkpointDebt() external override returns (uint128, uint256);

collateralToken

The collateral token supplied by users/accounts, eg gOHM

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

ohm

Unwrapped gOHM

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

debtToken

The debt token which can be borrowed, eg DAI or USDS

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

staking

staking contract to unstake (and burn) OHM from liquidations

function staking() external view override returns (IStaking);

minDebtRequired

The minimum debt a user needs to maintain

It costs gas to liquidate users, so we don't want dust amounts. To 18 decimal places

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

loanToValues

The current Max Origination LTV and Liquidation LTV from the ltvOracle()

Both to 18 decimal places

function loanToValues() external view override returns (uint96 maxOriginationLtv, uint96 liquidationLtv);

debtDeltaForMaxOriginationLtv

Calculate the difference in debt required in order to be at or just under the maxOriginationLTV if collateralDelta was added/removed from the current position. A positive debtDeltaInWad means the account can borrow that amount after adding that collateralDelta collateral A negative debtDeltaInWad means it needs to repay that amount in order to withdraw that collateralDelta collateral

debtDeltaInWad is always to 18 decimal places

function debtDeltaForMaxOriginationLtv(address account, int128 collateralDelta)
external
view
override
returns (int128 debtDelta);

accountPosition

An view of an accounts current and up to date position as of this block

function accountPosition(address account) external view override returns (AccountPosition memory position);

Parameters

NameTypeDescription
accountaddressThe account to get a position for

computeLiquidity

Compute the liquidity status for a set of accounts.

This can be used to verify if accounts can be liquidated or not.

function computeLiquidity(address[] calldata accounts)
external
view
override
returns (LiquidationStatus[] memory status);

Parameters

NameTypeDescription
accountsaddress[]The accounts to get the status for.

accountDelegationsList

Paginated view of an account's delegations

Can call sequentially increasing the startIndex each time by the number of items returned in the previous call, until number of items returned is less than maxItems

function accountDelegationsList(address account, uint256 startIndex, uint256 maxItems)
external
view
override
returns (IDLGTEv1.AccountDelegation[] memory delegations);

accountState

A view of the last checkpoint of account data (not as of this block)

function accountState(address account) external view override returns (AccountState memory);

accountCollateral

An account's current collateral

to 18 decimal places

function accountCollateral(address account) external view override returns (uint128);

accountDebt

An account's current debt as of this block

function accountDebt(address account) external view override returns (uint128);

globalState

A view of the derived/internal cache data.

function globalState() external view override returns (uint128, uint256);

_globalStateRW

Setup and refresh the global state Update storage if and only if the timestamp has changed since last updated.

function _globalStateRW() private returns (GlobalStateCache memory gStateCache);

_globalStateRO

Setup the GlobalStateCache for a given token read only -- storage isn't updated.

function _globalStateRO() private view returns (GlobalStateCache memory gStateCache);

_initGlobalStateCache

Initialize the global state cache from storage to this block, for a given token.

function _initGlobalStateCache(GlobalStateCache memory gStateCache) private view returns (bool dirty);

_reduceTotalDebt

Reduce the total debt in storage by a repayment amount. NB: The sum of all users debt may be slightly more than the recorded total debt because users debt is rounded up for dust. The total debt is floored at 0.

function _reduceTotalDebt(GlobalStateCache memory gStateCache, uint128 repayAmount) private;

_maxDebt

Calculate the maximum amount which can be borrowed up to the maxOriginationLtv, given a collateral amount

function _maxDebt(uint128 collateral, uint256 maxOriginationLtv) private pure returns (uint128);

_minCollateral

Calculate the maximum collateral amount which can be withdrawn up to the maxOriginationLtv, given a current debt amount

function _minCollateral(uint128 debt, uint256 maxOriginationLtv) private pure returns (uint128);

_validateOriginationLtv

Ensure the LTV isn't higher than the maxOriginationLtv

function _validateOriginationLtv(uint128 ltv, uint256 maxOriginationLtv) private pure;

_calculateCurrentLtv

Calculate the current LTV based on the latest debt

function _calculateCurrentLtv(uint128 currentDebt, uint128 collateral) private pure returns (uint128);

_computeLiquidity

Generate the LiquidationStatus struct with current details for this account.

function _computeLiquidity(AccountState memory aStateCache, GlobalStateCache memory gStateCache)
private
pure
returns (LiquidationStatus memory status);

_currentAccountDebt

Calculate the latest debt for a given account & token. Derived from the prior debt checkpoint, and the interest accumulator.

function _currentAccountDebt(
uint128 accountDebtCheckpoint_,
uint256 accountInterestAccumulatorRay_,
uint256 globalInterestAccumulatorRay_
) private pure returns (uint128 result);

_requireAmountNonZero

function _requireAmountNonZero(uint256 amount_) internal pure;

_requireAddressNonZero

function _requireAddressNonZero(address addr_) internal pure;

Structs

GlobalStateCache

struct GlobalStateCache {
uint128 totalDebt;
uint256 interestAccumulatorRay;
uint96 liquidationLtv;
uint96 maxOriginationLtv;
}