Esgtroller
The Esgtroller is the risk management layer of the Eco DeFi 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 eToken, the Esgtroller is asked to approve or deny the transaction.
The Esgtroller maps user balances to prices (via the Price Oracle) to risk weights (called Collateral Factors) to make its determinations. Users explicitly list which assets they would like to be included in their risk scoring, by calling Enter Markets and Exit Market.

Architecture

The Esgtroller is implemented as an upgradeable proxy. The Unitroller proxies all logic to the Esgtroller implementation, but storage values are set on the Unitroller. To call Esgtroller functions, use the Esgtroller ABI on the Unitroller address.

Enter Markets

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

Esgtroller

  • msg.sender: The account which shall enter the given markets.
  • eTokens: The addresses of the eToken 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.
Esgtroller
Solidity
Web3 1.0
function enterMarkets(address[] calldata eTokens) returns (uint[] memory)
​
  • msg.sender: The account which shall enter the given markets.
  • eTokens: The addresses of the eToken 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.
Ecoptroller troll = Ecoptroller(0xABCD...);
​
EToken[] memory eTokens = new EToken[](2);
​
eTokens[0] = CErc20(0x3FDA...);
​
eTokens[1] = EBNB(0x3FDB...);
​
uint[] memory errors = troll.enterMarkets(eTokens);
​
const troll = Ecoptroller.at(0xABCD...);
​
const eTokens = [CErc20.at(0x3FDA...), EBNB.at(0x3FDB...)];
​
const errors = await troll.methods.enterMarkets(eTokens).send({from: ...});
​

Exit Market

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

Esgtroller

function exitMarket(address eToken) returns (uint)
  • msg.sender: The account which shall exit the given market.
  • eTokens: The addresses of the eToken market to exit.
  • RETURN: 0 on success, otherwise an Error code.
Solidity
Web3 1.0
Esgtroller troll = Esgtroller(0xABCD...);
​
uint error = troll.exitMarket(EToken(0x3FDA...));
​
const troll = Esgtroller.at(0xABCD...);
​
const errors = await troll.methods.exitMarket(EBNB.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 calculations.

Esgtroller

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
Web3 1.0
Esgtroller troll = Esgtroller(0xABCD...);
​
address[] memory markets = troll.getAssetsIn(0xMyAccount);
​
const troll = Esgtroller.at(0xABCD...);
​
const markets = await troll.methods.getAssetsIn(eTokens).call();
​

Collateral Factor

An eToken's collateral factor can range from 0-90%, and represents the proportionate increase in liquidity (borrow limit) that an account receives by minting eToken.
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 can be increased (or decreased) through Eco DeFi Governance, as market conditions change.

Esgtroller

function markets(address eTokenAddress) view returns (bool, uint, bool)
  • eTokenAddress: The address of the eToken to check if listed and get the collateral factor for.
  • RETURN: Tuple of values (isListed, collateralFactorMantissa, isEsged); isListed represents whether the Esgtroller recognizes this eToken; collateralFactorMantissa, scaled by 1e18, is multiplied by a supply balance to determine how much value can be borrowed. The isEsged boolean indicates whether or not suppliers and borrowers are distributed Eco tokens.
Solidity
Web3 1.0
Esgtroller troll = Esgtroller(0xABCD...);
​
(bool isListed, uint collateralFactorMantissa, bool isEsged) = troll.markets(0x3FDA...);
const troll = Esgtroller.at(0xABCD...);
​
const result = await troll.methods.markets(0x3FDA...).call();
​
const {0: isListed, 1: collateralFactorMantissa, 2: isEsged} = 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 withdraw or borrow assets until Account Liquidity is positive again.
For each market the user has entered into, their supplied balance is multiplied by the market 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 collateral factor times each USD withdrawn.
Because the Eco DeFi Protocol exclusively uses unsigned integers, Account Liquidity returns either a surplus or shortfall.

Esgtroller

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. A non-zero liquidity value indicates the account has available 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
Web3 1.0
Esgtroller troll = Esgtroller(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");
​
const troll = Esgtroller.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 outstanding borrowing.

Esgtroller

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
Web3 1.0
Esgtroller troll = Esgtroller(0xABCD...);
​
uint closeFactor = troll.closeFactorMantissa();
​
const troll = Esgtroller.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. For example, if the liquidation incentive is 1.1, liquidators receive an extra 15% of the borrowers collateral for every unit they close.

Esgtroller

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
Web3 1.0
Esgtroller troll = Esgtroller(0xABCD...);
​
uint closeFactor = troll.liquidationIncentiveMantissa();
​
const troll = Esgtroller.at(0xABCD...);
​
const closeFactor = await troll.methods.liquidationIncentiveMantissa().call();
​

Key Events

Event
Description
MarketEntered(EToken eToken, address account)
Emitted upon a successful Enter Market.
MarketExited(EToken eToken, address account)
Emitted upon a successful Exit Market.

Error Codes

Name
Description
NO_ERROR
Not a failure.
UNAUTHORIZED
The sender is not authorized to perform this action.
ECOTROLLER_MISMATCH
Liquidation cannot be performed in markets with different Esgtroller.
INSUFFICIENT_SHORTFALL
The account does not have sufficient shortfall to perform this action.
INSUFFICIENT_LIQUIDITY
The account does not have sufficient liquidity to perform this action.
INVALID_CLOSE_FACTOR
The close factor is not valid.
INVALID_COLLATERAL_FACTOR
The collateral factor is not valid.
INVALID_LIQUIDATION_INCENTIVE
The liquidation incentive is invalid.
MARKET_NOT_ENTERED
The market has not been entered by the account.
MARKET_NOT_LISTED
The market is not currently listed by the comptroller.
MARKET_ALREADY_LISTED
An admin tried to list the same market more than once.
MATH_ERROR
A math calculation error occurred.
NONZERO_BORROW_BALANCE
The action cannot be performed since the account carries a borrow balance.
PRICE_ERROR
The Esgtroller could not obtain a required price of an asset.
REJECTION
The Esgtroller rejects the action requested by the market.
SNAPSHOT_ERROR
The Esgtroller could not get the account borrows and exchange rate from the market.
TOO_MANY_ASSETS
Attempted to enter more markets than are currently supported.
TOO_MUCH_REPAY
Attempted to repay more than is allowed by the protocol.

Failure Info

Name
ACCEPT_ADMIN_PENDING_ADMIN_CHECK
ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK
EXIT_MARKET_BALANCE_OWED
EXIT_MARKET_REJECTION
SET_CLOSE_FACTOR_OWNER_CHECK
SET_CLOSE_FACTOR_VALIDATION
SET_COLLATERAL_FACTOR_OWNER_CHECK
SET_COLLATERAL_FACTOR_NO_EXISTS
SET_COLLATERAL_FACTOR_VALIDATION
SET_COLLATERAL_FACTOR_WITHOUT_PRICE
SET_IMPLEMENTATION_OWNER_CHECK
SET_LIQUIDATION_INCENTIVE_OWNER_CHECK
SET_LIQUIDATION_INCENTIVE_VALIDATION
SET_MAX_ASSETS_OWNER_CHECK
SET_PENDING_ADMIN_OWNER_CHECK
SET_PENDING_IMPLEMENTATION_OWNER_CHECK
SET_PRICE_ORACLE_OWNER_CHECK
SUPPORT_MARKET_EXISTS
SUPPORT_MARKET_OWNER_CHECK

ESG Distribution Speeds

ESG Speed

The "ESG Speed" unique to each market is an unsigned integer that specifies the amount of ESG that is distributed, per block, to suppliers and borrowers in each market. This number can be changed for individual markets by calling the_setEsgSpeed method through a successful Eco DeFi Governance proposal.
The following is the formula for calculating the rate that ESG is distributed to each supported market.
utility = eTokenTotalBorrows * assetPrice
​
utilityFraction = utility / sumOfAllECOedMarketUtilities
​
marketEsgSpeed = EsgRate * utilityFraction

ESG Distributed Per Block (All Markets)

The Esgtroller contract EsgRate is an unsigned integer that indicates the rate at which the protocol distributes ESG to markets suppliers or borrowers, every BSC block. The value is the amount of ESG (in wei), per block, allocated for the markets. Note that not every market has ESG distributed to its participants (see Market Metadata).
The EsgRate indicates how much ESG goes to the suppliers or borrowers, so doubling this number shows how much ESG goes to all suppliers and borrowers combined. The code examples implement reading the amount of ESG distributed, per Ethereum block, to all markets.
Esgtroller
uint public EsgRate;
Solidity
Web3 1.2.6
Esgtroller troll = Esgtroller(0xABCD...);
​
// ESG issued per block to suppliers OR borrowers * (1 * 10 ^ 18)
uint EsgRate = troll.EsgRate();
​
// Approximate ESG issued per day to suppliers OR borrowers * (1 * 10 ^ 18)
uint EsgRatePerDay = EsgRate * 4 * 60 * 24;
​
​
// Approximate ESG issued per day to suppliers AND borrowers * (1 * 10 ^ 18)
uint EsgRatePerDayTotal = EsgRatePerDay * 2;
const Esgtroller = new web3.eth.Contract(EsgtrollerAbi, EsgtrollerAddress);
​
let EsgRate = await Esgtroller.methods.EsgRate().call();
EcopRate = EsgRate / 1e18;
​
// ECOP issued to suppliers OR borrowers
const EsgRatePerDay = EsgRate * 4 * 60 * 24;
​
// ECOP issued to suppliers AND borrowers
const EsgRatePerDayTotal = EsgRatePerDay * 2;

ESG Distributed Per Block (Single Market)

The Esgtroller contract has a mapping called EsgSpeeds. It maps eToken addresses to an integer of each market ESG distribution per BSC block. The integer indicates the rate at which the protocol distributes ESG to markets suppliers or borrowers. The value is the amount of ESG (in wei), per block, allocated for the market. Note that not every market has ESG distributed to its participants (see Market Metadata).
The speed indicates how much ESG goes to the suppliers or the borrowers, so doubling this number shows how much ESG goes to market suppliers and borrowers combined. The code examples implement reading the amount of ESG distributed, per BSC block, to a single market.
Esgtroller
mapping(address => uint) public EsgSpeeds;
Solidity
Web3 1.2.6
Esgtroller troll = Esgtroller(0x123...);
​
address eToken = 0xabc...;
​
// ESG issued per block to suppliers OR borrowers * (1 * 10 ^ 18)
uint EsgSpeed = troll.EsgSpeeds(eToken);
​
// Approximate ESG issued per day to suppliers OR borrowers * (1 * 10 ^ 18)
uint EsgSpeedPerDay = EsgSpeed * 4 * 60 * 24;
​
// Approximate ESG issued per day to suppliers AND borrowers * (1 * 10 ^ 18)
uint EsgSpeedPerDayTotal = EsgSpeedPerDay * 2;
​
const eTokenAddress = '0xabc...';
​
const Esgtroller = new web3.eth.Contract(EsgtrollerAbi, EsgtrollerAddress);
​
let EsgSpeed = await Esgtroller.methods.EsgSpeeds(eTokenAddress).call();
EsgSpeed = EsgSpeed / 1e18;
​
// ESG issued to suppliers OR borrowers
const EsgSpeedPerDay = EsgSpeed * 4 * 60 * 24;
​
// ESG issued to suppliers AND borrowers
const EsgSpeedPerDayTotal = EsgSpeedPerDay

Claim Eco

Every Eco DeFi user accrues ESG for each block they are supplying to or borrowing from the protocol. Users may call the Esgtroller's claimEsg method at any time to transfer ESG accrued to their address.

Esgtroller

// Claim all the ESG accrued by holder in all markets
function claimEsg(address holder) public
​
// Claim all the ESG accrued by holder in specific markets
function claimEsg(address holder, EToken[] memory eTokens) public
​
// Claim all the ESG accrued by specific holders in specific markets for their supplies and/or borrows
function claimEsg(address[] memory holders, EToken[] memory eTokens, bool borrowers, bool suppliers) public
Solidity
Web3 1.2.6
Esgtroller troll = Esgtroller(0xABCD...);
​
troll.claimEsg(0x1234...);
​
const Esgtroller = new web3.eth.Contract(EsgtrollerAbi, EsgtrollerAddress);
​
await Esgtroller.methods.claimEsg("0x1234...").send({ from: sender })

Market Metadata

The Esgtroller contract has an array called getAllMarkets that contains the addresses of each eToken contract. Each address in the getAllMarketsarray can be used to fetch a metadata struct in the Esgtroller markets constant. See the Esgtroller Storage contract for the Market struct definition.

Esgtroller

EToken[] public getAllMarkets;
Solidity
Web3 1.2.6
Esgtroller troll = Esgtroller(0xABCD...);
​
EToken eTokens[] = troll.getAllMarkets();
​
const Esgtroller = new web3.eth.Contract(EsgtrollerAbi, EsgtrollerAddress);
​
const eTokens = await Esgtroller.methods.getAllMarkets().call();
​
const eToken = eTokens[0]; // address of a eToken
Copy link
Outline
Architecture
Enter Markets
Exit Market
Get Assets In
Collateral Factor
Get Account Liquidity
Close Factor
Liquidation Incentive
Key Events
Error Codes
Failure Info
ESG Distribution Speeds
Claim Eco
Market Metadata