# Comptroller

### Introduction

The Comptroller is the risk management layer of the Paribus Protocol; it determines how much collateral a user is required to maintain, and whether (and by how much) a user can be liquidated. Each time a user interacts with a pToken, the Comptroller is asked to approve or deny the transaction.

The Comptroller maps user balances to prices (via the Price Oracle) to risk weights (called [Collateral Factors](#collateral-factor)) to make its determinations. Users explicitly list which assets they would like included in their risk scoring, by calling [Enter Markets](#enter-markets) and [Exit Market](#exit-market).

### Architecture

The Comptroller is made out of two parts, `ComptrollerPart1` as well as `ComptrollerPart2`. This is due to block size limitations. The Comptroller is implemented as upgradeable proxy. The Unitroller proxies all logic to the Comptroller implementation, but storage values are set on the Unitroller. To call Comptroller functions, use the Comptroller ABI on the Unitroller address.

### Enter Markets

Enter into a list of markets - it is not an error to enter the same market more than once. In order to supply collateral or borrow in a market, it must be entered first.

**Comptroller**

```solidity
function enterMarkets(address[] calldata pTokens) returns (uint[] memory)
```

* `msg.sender`: The account which shall enter the given markets.
* `pTokens`: The addresses of the pToken markets to enter.
* `RETURN`: For each market, returns an error code indicating whether or not it was entered. Each is 0 on success, otherwise an Error code.

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
pToken[] memory pTokens = new pToken[](2);
pTokens[0] = PErc20(0x3FDA...);
pTokens[1] = PEther(0x3FDB...);
uint[] memory errors = troll.enterMarkets(pTokens);
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const pTokens = [PErc20.at(0x3FDA...), PEther.at(0x3FDB...)];
const errors = await troll.methods.enterMarkets(pTokens).send({from: ...});
```

### Exit Market

Exit a market - it is not an error to exit a market which is not currently entered. Exited markets will not count towards account liquidity calculations.

**Comptroller**

```solidity
function exitMarket(address pToken) returns (uint)
```

* `msg.sender`: The account which shall exit the given market.
* `pTokens`: The addresses of the pToken market to exit.
* `RETURN`: 0 on success, otherwise an [Error code](#error-codes).

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
uint error = troll.exitMarket(pToken(0x3FDA...));
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const errors = await troll.methods.exitMarket(PEther.at(0x3FDB...)).send({from: ...});
```

### Get Assets In

Get the list of markets an account is currently entered into. In order to supply collateral or borrow in a market, it must be entered first. Entered markets count towards [account liquidity](#get-account-liquidity) calculations.

**Comptroller**

```solidity
function getAssetsIn(address account) view returns (address[] memory)

```

* `account`: The account whose list of entered markets shall be queried.
* `RETURN`: The address of each market which is currently entered into.

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
address[] memory markets = troll.getAssetsIn(0xMyAccount);
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const markets = await troll.methods.getAssetsIn(pTokens).call();
```

### Collateral Factor

A pToken's collateral factor can range from 0-90%, and represents the proportionate increase in liquidity (borrow limit) that an account receives by minting the pToken. Generally, large or liquid assets have high collateral factors, while small or illiquid assets have low collateral factors. If an asset has a 0% collateral factor, it can't be used as collateral (or seized in liquidation), though it can still be borrowed.

Collateral factors will be increased (or decreased) in the future through Paribus Governance.

**Comptroller**

```solidity
function markets(address pTokenAddress) view returns (bool, uint, bool)
```

* `pTokenAddress`: The address of the pToken to check if listed and get the collateral factor for.
* `RETURN`: Tuple of values (isListed, collateralFactorMantissa, isComped); isListed represents whether the comptroller recognizes this pToken; collateralFactorMantissa, scaled by 1e18, is multiplied by a supply balance to determine how much value can be borrowed. The isComped boolean indicates whether or not suppliers and borrowers are distributed COMP tokens.

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
(bool isListed, uint collateralFactorMantissa, bool isComped) = troll.markets(0x3FDA...);
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const result = await troll.methods.markets(0x3FDA...).call();
const {0: isListed, 1: collateralFactorMantissa, 2: isComped} = result;
```

### Get Account Liquidity

Account Liquidity represents the USD value borrowable by a user, before it reaches liquidation. Users with a shortfall (negative liquidity) are subject to liquidation, and can’t withdraw or borrow assets until Account Liquidity is positive again.

For each market the user has [entered](#enter-markets) into, their supplied balance is multiplied by the market’s [collateral factor](#collateral-factor), and summed; borrow balances are then subtracted, to equal Account Liquidity. Borrowing an asset reduces Account Liquidity for each USD borrowed; withdrawing an asset reduces Account Liquidity by the asset’s collateral factor times each USD withdrawn.

Because the Paribus Protocol exclusively uses unsigned integers, Account Liquidity returns either a surplus or shortfall.

**Comptroller**

```solidity
function getAccountLiquidity(address account) view returns (uint, uint, uint)
```

* `account`: The account whose liquidity shall be calculated.
* `RETURN`: Tuple of values (error, liquidity, shortfall). The error shall be 0 on success, otherwise an [error code](#error-codes). A non-zero liquidity value indicates the account has available [account liquidity](#get-account-liquidity). A non-zero shortfall value indicates the account is currently below his/her collateral requirement and is subject to liquidation. At most one of liquidity or shortfall shall be non-zero.

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
(uint error, uint liquidity, uint shortfall) = troll.getAccountLiquidity(msg.caller);
require(error == 0, "join the Discord");
require(shortfall == 0, "account underwater");
require(liquidity > 0, "account has excess collateral");
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const result = await troll.methods.getAccountLiquidity(0xBorrower).call();
const {0: error, 1: liquidity, 2: shortfall} = result;
```

### Close Factor

The percent, ranging from 0% to 100%, of a liquidatable account's borrow that can be repaid in a single liquidate transaction. If a user has multiple borrowed assets, the closeFactor applies to any single borrowed asset, not the aggregated value of a user’s outstanding borrowing.

**Comptroller**

```solidity
function closeFactorMantissa() view returns (uint)
```

* `RETURN`: The closeFactor, scaled by 1e18, is multiplied by an outstanding borrow balance to determine how much could be closed.

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
uint closeFactor = troll.closeFactorMantissa();
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const closeFactor = await troll.methods.closeFactorMantissa().call();
```

### Liquidation Incentive

The additional collateral given to liquidators as an incentive to perform liquidation of underwater accounts. A portion of this is given to the collateral pToken reserves as determined by the seize share. The seize share is assumed to be 0 if the pToken does not have a `protocolSeizeShareMantissa` constant. For example, if the liquidation incentive is 1.08, and the collateral's seize share is 1.028, liquidators receive an extra 5.2% of the borrower's collateral for every unit they close, and the remaining 2.8% is added to the pToken's reserves.

**Comptroller**

```solidity
function liquidationIncentiveMantissa() view returns (uint)
```

* `RETURN`: The liquidationIncentive, scaled by 1e18, is multiplied by the closed borrow amount from the liquidator to determine how much collateral can be seized.

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
uint closeFactor = troll.liquidationIncentiveMantissa();
```

**Web3 1.0**

```js
const troll = Comptroller.at(0xABCD...);
const closeFactor = await troll.methods.liquidationIncentiveMantissa().call();
```

### Key Events

| Event                                           | Description                                               |
| ----------------------------------------------- | --------------------------------------------------------- |
| `MarketEntered(pToken pToken, address account)` | Emitted upon a successful [Enter Market](#enter-markets). |
| `MarketExited(pToken pToken, address account)`  | Emitted upon a successful [Exit Market](#exit-market).    |

{: .key-events-table }

### Error Codes

| Code | Name                            | Description                                                                          |
| ---- | ------------------------------- | ------------------------------------------------------------------------------------ |
| 0    | `NO_ERROR`                      | Not a failure.                                                                       |
| 1    | `UNAUTHORIZED`                  | The sender is not authorized to perform this action.                                 |
| 2    | `COMPTROLLER_MISMATCH`          | Liquidation cannot be performed in markets with different comptrollers.              |
| 3    | `INSUFFICIENT_SHORTFALL`        | The account does not have sufficient shortfall to perform this action.               |
| 4    | `INSUFFICIENT_LIQUIDITY`        | The account does not have sufficient liquidity to perform this action.               |
| 5    | `INVALID_CLOSE_FACTOR`          | The close factor is not valid.                                                       |
| 6    | `INVALID_COLLATERAL_FACTOR`     | The collateral factor is not valid.                                                  |
| 7    | `INVALID_LIQUIDATION_INCENTIVE` | The liquidation incentive is invalid.                                                |
| 8    | `MARKET_NOT_ENTERED`            | The market has not been entered by the account.                                      |
| 9    | `MARKET_NOT_LISTED`             | The market is not currently listed by the comptroller.                               |
| 10   | `MARKET_ALREADY_LISTED`         | An admin tried to list the same market more than once.                               |
| 11   | `MATH_ERROR`                    | A math calculation error occurred.                                                   |
| 12   | `NONZERO_BORROW_BALANCE`        | The action cannot be performed since the account carries a borrow balance.           |
| 13   | `PRICE_ERROR`                   | The comptroller could not obtain a required price of an asset.                       |
| 14   | `REJECTION`                     | The comptroller rejects the action requested by the market.                          |
| 15   | `SNAPSHOT_ERROR`                | The comptroller could not get the account borrows and exchange rate from the market. |
| 16   | `TOO_MANY_ASSETS`               | Attempted to enter more markets than are currently supported.                        |
| 17   | `TOO_MUCH_REPAY`                | Attempted to repay more than is allowed by the protocol.                             |

### Failure Info

| Code | Name                                          |
| ---- | --------------------------------------------- |
| 0    | `ACCEPT_ADMIN_PENDING_ADMIN_CHECK`            |
| 1    | `ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK` |
| 2    | `EXIT_MARKET_BALANCE_OWED`                    |
| 3    | `EXIT_MARKET_REJECTION`                       |
| 4    | `SET_CLOSE_FACTOR_OWNER_CHECK`                |
| 5    | `SET_CLOSE_FACTOR_VALIDATION`                 |
| 6    | `SET_COLLATERAL_FACTOR_OWNER_CHECK`           |
| 7    | `SET_COLLATERAL_FACTOR_NO_EXISTS`             |
| 8    | `SET_COLLATERAL_FACTOR_VALIDATION`            |
| 9    | `SET_COLLATERAL_FACTOR_WITHOUT_PRICE`         |
| 10   | `SET_IMPLEMENTATION_OWNER_CHECK`              |
| 11   | `SET_LIQUIDATION_INCENTIVE_OWNER_CHECK`       |
| 12   | `SET_LIQUIDATION_INCENTIVE_VALIDATION`        |
| 13   | `SET_MAX_ASSETS_OWNER_CHECK`                  |
| 14   | `SET_PENDING_ADMIN_OWNER_CHECK`               |
| 15   | `SET_PENDING_IMPLEMENTATION_OWNER_CHECK`      |
| 16   | `SET_PRICE_ORACLE_OWNER_CHECK`                |
| 17   | `SUPPORT_MARKET_EXISTS`                       |
| 18   | `SUPPORT_MARKET_OWNER_CHECK`                  |
| 19   | `SET_PAUSE_GUARDIAN_OWNER_CHECK`              |

### PBX Distribution Speeds

#### PBX Distributed Per Block (Single Borrow Market)

The Comptroller contract has a mapping called `PBXBorrowSpeeds`. It maps pToken addresses to an integer of each market’s PBX distribution per Ethereum block. The integer indicates the rate at which the protocol distributes PBX to markets’ borrowers. The value is the amount of PBX (in wei), per block, allocated for the market. Note that not every market has PBX distributed to its participants (see Market Metadata). The speed indicates how much PBX goes to the borrowers. The code examples implement reading the amount of PBX distributed, per Ethereum block, to a single borrow market.

**Comptroller**

```solidity
mapping(address => uint) public PBXBorrowSpeeds;
```

**Solidity**

```solidity
Comptroller troll = Comptroller(0x123...);
address pToken = 0xabc...;
// PBX issued per block to borrowers * (1 * 10 ^ 18)
uint pbxBorrowSpeed = troll.PBXBorrowSpeeds(pToken);
// Approximate PBX issued per day to borrowers * (1 * 10 ^ 18)
uint pbxBorrowSpeedPerDay = pbxBorrowSpeed * 4 * 60 * 24;
```

**Web3 1.2.6**

```js
const pTokenAddress = '0xabc...';
const comptroller = new web3.eth.Contract(comptrollerAbi, comptrollerAddress);
let pbxBorrowSpeed = await comptroller.methods
  .PBXBorrowSpeeds(pTokenAddress)
  .call();
pbxBorrowSpeed = pbxBorrowSpeed / 1e18;
// PBX issued to borrowers
const pbxBorrowSpeedPerDay = pbxBorrowSpeed * 4 * 60 * 24;
```

#### PBX Distributed Per Block (Single Supply Market)

The Comptroller contract has a mapping called `PBXSupplySpeeds`. It maps pToken addresses to an integer of each market’s PBX distribution per Ethereum block. The integer indicates the rate at which the protocol distributes PBX to markets’ suppliers. The value is the amount of PBX (in wei), per block, allocated for the market. Note that not every market has PBX distributed to its participants (see Market Metadata). The speed indicates how much PBX goes to the suppliers. The code examples implement reading the amount of PBX distributed, per Ethereum block, to a single supplier market.

**Comptroller**

```solidity
mapping(address => uint) public PBXSupplySpeeds;
```

**Solidity**

```solidity
Comptroller troll = Comptroller(0x123...);
address pToken = 0xabc...;
// PBX issued per block to suppliers * (1 * 10 ^ 18)
uint pbxSupplySpeed = troll.PBXSupplySpeeds(pToken);
// Approximate PBX issued per day to suppliers * (1 * 10 ^ 18)
uint pbxSupplySpeedPerDay = pbxSupplySpeed * 4 * 60 * 24;
```

**Web3 1.2.6**

```js
const pTokenAddress = '0xabc...';
const comptroller = new web3.eth.Contract(comptrollerAbi, comptrollerAddress);
let pbxSupplySpeed = await comptroller.methods
  .PBXSupplySpeeds(pTokenAddress)
  .call();
pbxSupplySpeed = pbxSupplySpeed / 1e18;
// PBX issued to suppliers
const pbxSupplySpeedPerDay = pbxSupplySpeed * 4 * 60 * 24;
```

### Claim PBX

Every Paribus user accrues PBX for each block they are supplying to or borrowing from the protocol. Users may call the Comptroller's `claimPBX` method at any time to transfer PBX accrued to their address.

**Comptroller**

```solidity
// Claim all the PBX accrued by holder in all markets
function claimPBXReward(address holder) external;
// Claim all the PBX accrued by holder in specific markets
function claimPBXSingle(address holder, PToken[] memory pTokens) public;
// Claim all the PBX accrued by specific holders in specific markets for their supplies and/or borrows
function claimPBX(address[] memory holders, PToken[] memory pTokens, bool borrowers, bool suppliers) public;
```

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
troll.claimPBX(0x1234...);
```

**Web3 1.2.6**

```js
const comptroller = new web3.eth.Contract(comptrollerAbi, comptrollerAddress);
await comptroller.methods.claimPBX('0x1234...').send({ from: sender });
```

### Market Metadata

The Comptroller contract has an array called `getAllMarkets` that contains the addresses of each pToken contract. Each address in the `getAllMarkets` array can be used to fetch a metadata struct in the Comptroller’s markets constant. See the [ComptrollerPart1 contract](https://github.com/Paribus/paribus-protocol-contracts/blob/mainnet-mvp/contracts/Comptroller/ComptrollerPart1.sol) for the Market struct definition.

**Comptroller**

```solidity
pToken[] public getAllMarkets;
```

**Solidity**

```solidity
Comptroller troll = Comptroller(0xABCD...);
pToken pTokens[] = troll.getAllMarkets();
```

**Web3 1.2.6**

```js
const comptroller = new web3.eth.Contract(comptrollerAbi, comptrollerAddress);
const pTokens = await comptroller.methods.getAllMarkets().call();
const pToken = pTokens[0]; // address of a pToken
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.paribus.io/for-developers/comptroller.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
