# Admin Privileges

## Primer

In the initial stages of the protocol, the admin rights are owned by a simple multi signature wallet (Gnosis Safe) that is stood up behind a delayed multi signature wallet (custom-made by the dYdX team). The Gnosis Safe is a 2/3 wallet. Meaning, 2 signers are needed out of the 3 owners to execute a transaction.&#x20;

The delayed multi signature wallet is solely owned by the Gnosis Safe, which means the security and ownership of the delayed multi signature wallet falls back on to the Gnosis Safe. On the other hand, the time delay falls completely on the delayed multi signature wallet; whatever delay is set for the delayed multi signature wallet indiscriminately requires that all transactions sent (except certain whitelisted ones) to it wait the same delay before the transaction can be executed. Meaning, all admin transactions involving the `DolomiteMargin` protocol require that `secondsTimeLocked` amount of time must be waited before the transaction effectuates.

> At the time of launch, the delay on the delayed multi signature wallet is 1 day (86,400 seconds). The intention is to raise it incrementally until the protocol is more battle-tested and ownership of the protocol becomes much more decentralized.

To check the current delay (in case these docs ever go out of sync!) you can convert the `secondsTimeLocked` value from seconds to minutes/hours/days on [Arbiscan](https://arbiscan.io/address/0xE412991Fb026df586C2f2F9EE06ACaD1A34f585B#readContract).

## Special Function Bypass

Certain functions are able to bypass the `secondsTimeLocked` restriction and be executed **immediately**. The reason for having this is it allows the administrators to make quick changes in the event market conditions change whimsically, `DolomiteMargin` is exploited, a bug is uncovered, or some other black swan event occurs. The following table showcases which functions can be bypassed.

<table><thead><tr><th width="372.3333333333333">Function Name</th><th width="163">Method ID</th><th>Can Bypass Timelock?</th></tr></thead><tbody><tr><td><code>ownerSetMarketIsClosing</code></td><td><code>0xef6957d0</code></td><td>TRUE</td></tr><tr><td><code>ownerSetMarketMaxWei</code></td><td><code>0x0cd30a0e</code></td><td>TRUE</td></tr><tr><td><code>ownerSetInterestSetter</code></td><td><code>0x121fb72f</code></td><td>TRUE</td></tr><tr><td><code>GLPWrappedTokenUserVaultFactory::setUserVaultImplementation</code></td><td><code>0x35598a02</code></td><td>TRUE</td></tr></tbody></table>

## Risk Limits <a href="#risk-limits" id="risk-limits"></a>

DolomiteMargin initializes an immutable struct called `RiskLimits` upon deployment that defines that absolute maximum that certain parameters can *ever* be. Meaning, under no possible circumstance can these values change and under no possible circumstance can `RiskParams` (the mutable counterpart of the `RiskLimit` struct) be changed to a value that exceeds a value set in `RiskLimits`. The following values are set in `RiskLimits`:

`uint64 marginRatioMax`

> The highest that the ratio can be for liquidating under-water accounts. Permanently set at `2000000000000000000`, which is equal to 200% collateralization.

`uint64 liquidationSpreadMax`

> The highest that the liquidation rewards can be when a liquidator liquidates an account. Permanently set at `500000000000000000`, which is equal to a 50% reward.

`uint64 earningsRateMax`

> The highest that the supply APR can be for a market, as a proportion of the borrow rate. Meaning, a rate of 100% (1e18) would give suppliers all the interest that borrowers are paying. A rate of 90% would give suppliers 90% of the interest that borrowers pay. Permanently set at `1000000000000000000`, which is equal to 100% of the borrow rate going to suppliers.

`uint64 marginPremiumMax`

> The highest min margin ratio premium that can be applied to a particular market. Meaning, a value of 10% (1e17) would require borrowers to maintain an extra 10% collateral to maintain a healthy margin ratio. This value works by increasing the debt owed and decreasing the supply held for the particular market by this amount, by this the value. Permanently set at `2000000000000000000`, which equals 200%. Meaning, if this value were set for an individual market's `RiskParams` to `2000000000000000000`, and the protocol's minimum collateralization is 115%, that particular market will require a min collateralization of 345% in maintain sufficient collateralization.

`uint64 spreadPremiumMax`

> The highest liquidation reward that can be applied to a particular market. This percentage is applied in addition to the liquidation spread in `RiskParams`. This value has 18 decimals, meaning a value of 1e18 is 100%. It is applied to each market as follows: `liquidationSpread * (1 + spreadPremium)`. This value is permanently set at `2000000000000000000`, which equals 200%.

`uint128 minBorrowedValueMax`

> The highest minimum borrowed value that can be set by the protocol (this is confusingly worded, we know!). This value is permanently set at `100000000000000000000` or $1e-16. Meaning, the minimum borrowed value can never be set beyond `100000000000000000000 / 1e36` dollars.

To verify any of the above values, you can visit [Arbiscan](https://arbiscan.io/address/0x6a76986201E1906eb8d887Bb4Ad74b55888617af#readContract) and click the `Query` button for the function `getRiskLimits`.

## Risk Params <a href="#global-risk-params" id="global-risk-params"></a>

`DolomiteMargin` uses a struct for storing global risk-values called `RiskParams` which is *changeable* by the admin of the protocol (subject to any time delays, of course). Many of these values have a counterpart in `RiskLimits` that enforces limitations on what these numbers can be changed to. These values include the following:

`Decimal.D256 marginRatio`

> The required ratio of over-collateralization. If this value is set at `150000000000000000`, this corresponds with 115% collateralization. This value cannot be set below `liquidationSpread` nor above `marginRatioMax` (which is permanently set at 200%) and has a theoretical lower limit of 0 (100% collateralization).

`Decimal.D256 liquidationSpread`

> The liquidation reward paid from liquidated accounts to liquidators. If this value is set at `50000000000000000` which corresponds with a 5% liquidation reward. This value cannot be set below 0% nor above `marginRatio` or `spreadPremiumMax` (which is permanently set at 200%).

`Decimal.D256 earningsRate`

> The percentage of the borrower's interest fee that is passed to the suppliers. If this value is set at `800000000000000000` which corresponds with 80%. The remaining 20% is paid to the protocol as a fee.

`Monetary.Value minBorrowedValue`

> The minimum borrow value that an account may have. This value is measured in dollars and has 36 decimals of precision. This value is currently set at 0 ($0).

`uint256 accountMaxNumberOfMarketsWithBalances`

> The maximum number of markets a user can have a non-zero balance for in a given account. Recall, an account is defined as a user's address, partitioned by an `index`. If this value is set at 32, a user can have at-most 32 markets with non-zero balances for each sub account (`wallet-index[0]`, `wallet-index[1]` ... `wallet-index[n]`, etc).

***

## Market-Specific Risk Params <a href="#market-risk-params" id="market-risk-params"></a>

The following functions and parameters can be called or changed by the protocol's admin and are subject to the same, universal, time delays as well as any applicable limits defined above.

To verify any of these parameters for a particular market, you can first get the `marketId` from the [Markets](https://docs.dolomite.io/#/protocol?id=markets) section of the docs. Alternatively, you can visit the DolomiteMargin smart contract on [Arbiscan](https://arbiscan.io/address/0x6a76986201E1906eb8d887Bb4Ad74b55888617af#readContract) and get the `marketId` by calling the `getMarketIdByTokenAddress` function, passing in the token address whose market ID you're seeking. Then, pass the `marketId` into the `getMarket` function or into individual market risk-oriented functions like:

* `getMarketIsClosing`
* `getMarketPriceOracle`
* `getMarketInterestSetter`
* `getMarketMarginPremium`
* `getMarketSpreadPremium`&#x20;
* `getMarketMaxSupplyWei`&#x20;
* `getMarketMaxBorrowWei`
* `getMarketMaxWei` (Arbitrum only)
* `getMarketEarningsRateOverride`&#x20;

### Add Market

```solidity
function ownerAddMarket(
    address token,
    IPriceOracle priceOracle,
    IInterestSetter interestSetter,
    Decimal.D256 memory marginPremium,
    Decimal.D256 memory spreadPremium,
    uint256 maxSupplyWei,
    uint256 maxBorrowWei,
    Decimal.D256 memory earningsRateOverride
    bool isClosing
);
```

This function allows a new market to be added to DolomiteMargin. Upon initialization, the token's address cannot be changed. Other values that are initialized and can be changed include `isClosing`, `priceOracle`, `interestSetter`, `marginPremium`, `spreadPremium`, `maxSupplyWei`, `maxBorrowWei`, and `earningsRateOverride`.

`bool isClosing`

> This value defaults to `false`. Setting this value to `true` disallows any *new* borrows from occurring for that market. This value is checked after each interaction with DolomiteMargin settles, meaning funds can still be flash borrowed (as long as they're returned in full), once the interaction settles.

`IPriceOracle priceOracle`

> The contract address of the price oracle for this market. Must conform to the `IPriceOracle` interface. The price this contract returns has `36 - tokenDecimals` decimals. For example, `1000000000000000000000000000000` equals $1.00 for the USDC market, because USDC has 6 decimals.

`IInterestSetter interestSetter`

> Contract address of the interest setter for this market. Must conform to the `IInterestSetter` interface. This contract takes the utilization (the total amount borrowed and the total amount supplied) for a given market and determines the amount of interest paid by borrowers *every second*. Meaning, a value returned by this contract of `325000000` is equivalent to `1.02% APR` (`325000000 * 86400 * 365`). The result has 18 decimals.

`Decimal.D256 marginPremium`

> The multiplier to apply to the global `marginRatio`. This value works by increasing the debt owed and decreasing the supply held for the particular market by `1 + marginPremium`. Meaning, a `marginPremium` of 100000000000000000 (10%) and a marginRatio of `100000000000000000` (110% collateralization) results in that particular market's `marginRatio` equalling `110% * 1.1 == 121%`.

`Decimal.D256 spreadPremium`

> The multiplier to apply to the global `liquidationSpread`. This value works by increasing the `liquidationSpread` by (`Decimal.one + spreadPremium`). Meaning, a `spreadPremium` of `100000000000000000` (10%) and a `liquidationSpread` of `50000000000000000`, results in that particular market's `liquidationSpread` equalling `5% * 1.1 == 5.5%`.

`Types.Wei maxSupplyWei`

> The maximum value that can be deposited into DolomiteMargin for this particular market. This allows the protocol to cap any additional risk that is inferred by allowing borrowing against assets with a lower market capitalization or assets with increased volatility. Setting this value to 0 is analogous to having no limit. This value can never be below 0. This value's number of decimals corresponds with the number of decimals this market's token has.

`Types.Wei maxBorrowWei`

> The maximum value that can be borrowed from DolomiteMargin for this particular market. This allows the protocol to cap any additional risk that is inferred by borrowing this market to take out more debt. Setting this value to 0 is analogous to having no limit. This value can never be below 0. This value's number of decimals corresponds with the number of decimals this market's token has.

`Decimal.D256 earningsRateOverride`

> The percentage of the borrower's interest fee that is passed to the suppliers for this market. Setting this value to 0 is analogous to having no override. This value's number of decimals is always 18.

## Other Admin Functions <a href="#other-admin-functions" id="other-admin-functions"></a>

### Set Global Operator

#### What is an operator?

An operator is an external address that has the same permissions to manipulate an account within `DolomiteMargin` as the owner of the account. Operators are simply addresses and therefore may either be externally-owned Ethereum accounts (EoAs) OR smart contracts. Operators are also able to act as AutoTrader contracts on behalf of the account owner if the operator is a smart contract and implements the `IAutoTrader` interface.

#### What kinds of operators exist?

There are three kinds of operators that `DolomiteMargin` supports:

1. Self operators - analogous to `msg.sender` or the user
2. Local operators - users approve each of them manually, like a token approval
3. Global operators - users do not need to approve them manually, they have permission automatically

#### Why do global operators exist?

Global operators exist to increase the UX of Dolomite for the users. Without them, users would be forced to manually approve a lot of local operator contracts to achieve a competitive and smooth UX.

```solidity
function ownerSetGlobalOperator(
    address operator,
    bool approved
) public;
```

> This function allows the admin to approve or disapprove a smart contract that has the permission to be an operator for all accounts on DolomiteMargin.
>
> A non-exhaustive list of global operators include the [LiquidatorProxyV1](https://arbiscan.io/address/0xDda7d883B19536823ccD6d16F0b14d9ba1FAB581) and [DepositWithdrawalProxy](https://arbiscan.io/address/0xA526B730B96d0ADC11B206560DE19760f12737c4), which exist to simplify the user experience or lower gas costs for Dolomite users by consuming less calldata.

{% hint style="danger" %}
With regard to the safety of user's funds, this function likely poses the largest risk on the system. If a buggy or malicious global operator is ever set, all of the users' funds could be at risk.

Therefore, all global operators must undergo extensive testing and review before being added to the system. Moreover, they should always be stuck behind a time delay to allow users to react to any new global operator contracts being added.
{% endhint %}

### Set Auto Trader Special

```solidity
function ownerSetAutoTraderSpecial(
    address autoTrader,
    bool special
) public;
```

This function sets or unsets an instance of `IAutoTrader` from needing to be called by a global operator. This exists to ensure certain contracts, like `Expiry` can eventually only be called by trusted [Keepers](https://chain.link/keepers) on the Chainlink Oracle network.

### Withdraw Excess Token <a href="#other-miscellaneous-admin-functions" id="other-miscellaneous-admin-functions"></a>

```solidity
function ownerWithdrawExcessTokens(
    uint256 marketId,
    address recipient
) public;
```

This function allows the admin to withdraw an ERC20 token for which there is an associated market. Only excess tokens can be withdrawn. The number of excess tokens is calculated by taking the current number of tokens held in DolomiteMargin, adding the number of tokens owed to DolomiteMargin by borrowers, and subtracting the number of tokens owed to suppliers by DolomiteMargin.

### Withdraw Unsupported Tokens

```solidity
function ownerWithdrawUnsupportedTokens(
    address token,
    address recipient
) public;
```

This function allows the admin to withdraw an ERC20 token for which there is no associated market. This is analogous to rescuing tokens sent to the protocol by accident.
