Skip to content

Commit

Permalink
Compound Protocol v2.2 Release Candidate
Browse files Browse the repository at this point in the history
Note: **this is a release candidate version and is not yet fully completed audited. This code is liable for change. For concerns about security, message [email protected]**

This patch modifies the Compound Protocol Comptroller for a Timelock administrator which will add a delay to allow the community to audit and respond to changes before they are made. Additionally, in the event of an in-the-wild concern, we add a pause gaurdian that has the ability to pause borrows, withdraws or liqudations if any funds appear to be put at risk. We also change the behavior to allow a user to enter a market simply by invoking the borrow function.

Finally, we make a variety of changes in response to the OpenZeppelin audits for minor code quality concerns.
  • Loading branch information
hayesgm committed Oct 12, 2019
1 parent 745238a commit 681833a
Show file tree
Hide file tree
Showing 85 changed files with 12,741 additions and 4,189 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ jobs:
lint:
docker:
- image: circleci/node:11
- image: trufflesuite/ganache-cli:v6.2.5
- image: trufflesuite/ganache-cli:v6.7.0
working_directory: ~/repo
steps:
- checkout
Expand Down
5 changes: 3 additions & 2 deletions contracts/CErc20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ contract CErc20 is CToken {
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint decimals_) public
CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) {
uint8 decimals_,
address payable admin_) public
CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, admin_) {
// Set underlying
underlying = underlying_;
EIP20Interface(underlying).totalSupply(); // Sanity check the underlying
Expand Down
5 changes: 3 additions & 2 deletions contracts/CEther.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ contract CEther is CToken {
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint decimals_) public
CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) {}
uint8 decimals_,
address payable admin_) public
CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, admin_) {}

/*** User Interface ***/

Expand Down
40 changes: 19 additions & 21 deletions contracts/CToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,18 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
/**
* @notice EIP-20 token decimals for this token
*/
uint public decimals;
uint8 public decimals;

/**
* @notice Maximum borrow rate that can ever be applied (.0005% / block)
*/
uint constant borrowRateMaxMantissa = 5e14;

uint internal constant borrowRateMaxMantissa = 0.0005e16;

/**
* @notice Maximum fraction of interest that can be set aside for reserves
*/
uint constant reserveFactorMaxMantissa = 1e18;
uint internal constant reserveFactorMaxMantissa = 1e18;

/**
* @notice Administrator for this contract
Expand Down Expand Up @@ -80,7 +81,7 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
uint public accrualBlockNumber;

/**
* @notice Accumulator of total earned interest since the opening of the market
* @notice Accumulator of the total earned interest rate since the opening of the market
*/
uint public borrowIndex;

Expand All @@ -102,12 +103,12 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
/**
* @notice Official record of token balances for each account
*/
mapping (address => uint256) accountTokens;
mapping (address => uint256) internal accountTokens;

/**
* @notice Approved token transfer amounts on behalf of others
*/
mapping (address => mapping (address => uint256)) transferAllowances;
mapping (address => mapping (address => uint256)) internal transferAllowances;

/**
* @notice Container for borrow balance information
Expand All @@ -122,7 +123,7 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
/**
* @notice Mapping of account addresses to outstanding borrow balances
*/
mapping(address => BorrowSnapshot) accountBorrows;
mapping(address => BorrowSnapshot) internal accountBorrows;


/*** Market Events ***/
Expand Down Expand Up @@ -199,20 +200,21 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
* @param name_ EIP-20 name of this token
* @param symbol_ EIP-20 symbol of this token
* @param decimals_ EIP-20 decimal precision of this token
* @param admin_ Administrator of this token
*/
constructor(ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint decimals_) internal {
// Set admin to msg.sender
admin = msg.sender;

uint8 decimals_,
address payable admin_) internal {
// Set initial exchange rate
initialExchangeRateMantissa = initialExchangeRateMantissa_;
require(initialExchangeRateMantissa > 0, "Initial exchange rate must be greater than zero.");

// Temporarily set msg.sender to admin to set comptroller and interest rate model
admin = msg.sender;
// Set the comptroller
uint err = _setComptroller(comptroller_);
require(err == uint(Error.NO_ERROR), "Setting comptroller failed");
Expand All @@ -228,6 +230,9 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
name = name_;
symbol = symbol_;
decimals = decimals_;

// Set the proper admin now that initialization is done
admin = admin_;
}

/**
Expand Down Expand Up @@ -295,7 +300,6 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
/* We emit a Transfer event */
emit Transfer(src, dst, tokens);

/* We call the defense hook (which checks for under-collateralization) */
comptroller.transferVerify(address(this), src, dst, tokens);

return uint(Error.NO_ERROR);
Expand Down Expand Up @@ -790,7 +794,7 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to redeem
* @param redeemAmount The amount of underlying to receive from redeeming cTokens
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) {
Expand All @@ -817,8 +821,8 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
* @notice User redeems cTokens in exchange for the underlying asset
* @dev Assumes interest has already been accrued up to the current block
* @param redeemer The address of the account which is redeeming the tokens
* @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be zero)
* @param redeemAmountIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be zero)
* @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
* @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
Expand Down Expand Up @@ -1302,8 +1306,6 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
* @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @param newPendingAdmin New pending admin.
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*
* TODO: Should we add a second arg to verify, like a checksum of `newAdmin` address?
*/
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {
// Check caller = admin
Expand Down Expand Up @@ -1402,7 +1404,6 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu

// Verify market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
// TODO: static_assert + no error code?
return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK);
}

Expand Down Expand Up @@ -1452,7 +1453,6 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu

// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
// TODO: static_assert + no error code?
return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK);
}

Expand All @@ -1462,7 +1462,6 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu
}

// Check reduceAmount ≤ reserves[n] (totalReserves)
// TODO: I'm following the spec literally here but I think we should we just use SafeMath instead and fail on an error (which would be underflow)
if (reduceAmount > totalReserves) {
return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);
}
Expand Down Expand Up @@ -1522,7 +1521,6 @@ contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGu

// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
// TODO: static_assert + no error code?
return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK);
}

Expand Down
Loading

0 comments on commit 681833a

Please sign in to comment.