Skip to content

Commit

Permalink
Compound v2.3 Pre-Release
Browse files Browse the repository at this point in the history
**Note: This is a pre-release version and is subject to change**

* Feature: Add support for multi-collateral DAI as a new token
* Feature: Allow upgrades for cTokens which have upgradable underlying tokens
* Improvement: Allow liquidation of a borrow collateralized in the same kind of token
* Improvement: Add support for Erc-20 tokens which have a fee on transfers
  • Loading branch information
hayesgm committed Nov 23, 2019
1 parent 681833a commit bcf0bc7
Show file tree
Hide file tree
Showing 161 changed files with 36,237 additions and 11,663 deletions.
25 changes: 6 additions & 19 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
steps:
- run:
|
sudo wget https://github.com/ethereum/solidity/releases/download/v0.5.8/solc-static-linux -O /usr/local/bin/solc
sudo wget https://github.com/ethereum/solidity/releases/download/v0.5.12/solc-static-linux -O /usr/local/bin/solc
sudo chmod +x /usr/local/bin/solc
- checkout
- restore_cache:
Expand Down Expand Up @@ -43,7 +43,7 @@ jobs:
- attach_workspace:
at: ~/repo
- run: mkdir ~/junit
- run: TSC_ARGS="" MOCHA_FILE=~/junit/test-results.xml script/test
- run: MOCHA_FILE=~/junit/test-results.xml script/test
- store_test_results:
path: ~/junit
- store_artifacts:
Expand All @@ -61,24 +61,11 @@ jobs:
keys:
- v2-dependencies-{{ checksum "package.json" }}
- v2-dependencies-
- restore_cache:
keys:
- v2-scenario/dependencies-{{ checksum "scenario/package.json" }}
- v2-scenario/dependencies-
- run: yarn install
- run: cd scenario && yarn install
- run:
name: Ganache
command: script/ganache-coverage
background: true
- save_cache:
paths:
- node_modules
key: v2-dependencies-{{ checksum "package.json" }}
- save_cache:
paths:
- scenario/node_modules
key: v2-scenario-dependencies-{{ checksum "scenario/package.json" }}
- attach_workspace:
at: ~/repo
- run:
Expand Down Expand Up @@ -110,12 +97,12 @@ jobs:
keys:
- v2-scenario/dependencies-{{ checksum "scenario/package.json" }}
- v2-scenario/dependencies-
- run:
|
sudo wget https://github.com/ethereum/solidity/releases/download/v0.5.12/solc-static-linux -O /usr/local/bin/solc
sudo chmod +x /usr/local/bin/solc
- run: yarn install
- run: cd scenario && yarn install
- run:
name: Ganache
command: script/ganache-coverage
background: true
- save_cache:
paths:
- node_modules
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ networks/coverage.json
networks/coverage-abi.json
networks/development.json
networks/development-abi.json
networks/coverage-contracts/*
networks/test-contracts/*
networks/*-contracts.json
networks/*-history
networks/*-settings.json
Expand Down
26 changes: 22 additions & 4 deletions .solcover.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
const {execSync} = require('child_process');
async function moveCoverage(config) {
execSync('mv ./.coverage_artifacts/contracts ./networks/coverage-contracts');
}

async function moveCoverageBack() {
execSync('mv ./networks/coverage-contracts ./.coverage_artifacts/contracts');
}

module.exports = {
port: 8555,
norpc: true,
testCommand: process.env['TEST_COMMAND'] || 'NETWORK=coverage script/test',
skipFiles: ['FormalMoneyMarket.sol', 'test_contracts'].concat(
providerOpts:
{ // See example coverage settings at https://github.com/sc-forks/solidity-coverage
gas: 0xfffffff,
gasPrice: 0x01
},
mocha: {
enableTimeouts: false,
grep: /@gas|@no-cov/,
invert: true
},
onCompileComplete: moveCoverage,
onTestsComplete: moveCoverageBack,
skipFiles: ['test'].concat(
process.env['SKIP_UNITROLLER'] ? ['Unitroller.sol'] : []),
deepSkip: true
};
9 changes: 6 additions & 3 deletions .soliumrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
"error",
"double"
],
"indentation": [
"indentation": "off",
"max-len": [
"error",
4
]
200
],
"security/no-inline-assembly": "off",
"security/no-low-level-calls": "off"
}
}
115 changes: 58 additions & 57 deletions contracts/CErc20.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.5.8;
pragma solidity ^0.5.12;

import "./CToken.sol";

Expand All @@ -7,15 +7,9 @@ import "./CToken.sol";
* @notice CTokens which wrap an EIP-20 underlying
* @author Compound
*/
contract CErc20 is CToken {

/**
* @notice Underlying asset for this CToken
*/
address public underlying;

contract CErc20 is CToken, CErc20Interface {
/**
* @notice Construct a new money market
* @notice Initialize the new money market
* @param underlying_ The address of the underlying asset
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
Expand All @@ -24,18 +18,19 @@ contract CErc20 is CToken {
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
*/
constructor(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_) public
CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, admin_) {
// Set underlying
function initialize(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_) public {
// CToken initialize does the bulk of the work
super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);

// Set underlying and sanity check it
underlying = underlying_;
EIP20Interface(underlying).totalSupply(); // Sanity check the underlying
EIP20Interface(underlying).totalSupply();
}

/*** User Interface ***/
Expand All @@ -47,7 +42,8 @@ contract CErc20 is CToken {
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(uint mintAmount) external returns (uint) {
return mintInternal(mintAmount);
(uint err,) = mintInternal(mintAmount);
return err;
}

/**
Expand Down Expand Up @@ -85,7 +81,8 @@ contract CErc20 is CToken {
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrow(uint repayAmount) external returns (uint) {
return repayBorrowInternal(repayAmount);
(uint err,) = repayBorrowInternal(repayAmount);
return err;
}

/**
Expand All @@ -95,19 +92,30 @@ contract CErc20 is CToken {
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) {
return repayBorrowBehalfInternal(borrower, repayAmount);
(uint err,) = repayBorrowBehalfInternal(borrower, repayAmount);
return err;
}

/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @param repayAmount The amount of the underlying borrowed asset to repay
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function liquidateBorrow(address borrower, uint repayAmount, CToken cTokenCollateral) external returns (uint) {
return liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint) {
(uint err,) = liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
return err;
}

/**
* @notice The sender adds to reserves.
* @param addAmount The amount fo underlying token to add as reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReserves(uint addAmount) external returns (uint) {
return _addReservesInternal(addAmount);
}

/*** Safe Token ***/
Expand Down Expand Up @@ -141,76 +149,69 @@ contract CErc20 is CToken {
}

/**
* @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and returns an explanatory
* error code rather than reverting. If caller has not called `checkTransferIn`, this may revert due to
* insufficient balance or insufficient allowance. If caller has called `checkTransferIn` prior to this call,
* and it returned Error.NO_ERROR, this should not revert in normal conditions.
* @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` reverts in that case.
* If caller has not called `checkTransferIn`, this may revert due to insufficient balance or insufficient
* allowance. If caller has called `checkTransferIn` prior to this call, and it returned Error.NO_ERROR,
* this should not revert in normal conditions. This function returns the actual amount received,
* with may be less than `amount` if there is a fee attached with the transfer.
*
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
function doTransferIn(address from, uint amount) internal returns (Error) {
function doTransferIn(address from, uint amount) internal returns (uint) {
EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
bool result;

uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));
token.transferFrom(from, address(this), amount);

// solium-disable-next-line security/no-inline-assembly
bool success;
assembly {
switch returndatasize()
case 0 { // This is a non-standard ERC-20
result := not(0) // set result to true
case 0 { // This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 { // This is a complaint ERC-20
case 32 { // This is a compliant ERC-20
returndatacopy(0, 0, 32)
result := mload(0) // Set `result = returndata` of external call
success := mload(0) // Set `success = returndata` of external call
}
default { // This is an excessively non-compliant ERC-20, revert.
default { // This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_IN_FAILED");

if (!result) {
return Error.TOKEN_TRANSFER_IN_FAILED;
}

return Error.NO_ERROR;
// Calculate the amount that was *actually* transferred
uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));
require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW");
return balanceAfter - balanceBefore; // underflow already checked above, just subtract
}

/**
* @dev Similar to EIP20 transfer, except it handles a False result from `transfer` and returns an explanatory
* @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory
* error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
* insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
* it is >= amount, this should not revert in normal conditions.
*
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
function doTransferOut(address payable to, uint amount) internal returns (Error) {
function doTransferOut(address payable to, uint amount) internal {
EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
bool result;

token.transfer(to, amount);

// solium-disable-next-line security/no-inline-assembly
bool success;
assembly {
switch returndatasize()
case 0 { // This is a non-standard ERC-20
result := not(0) // set result to true
success := not(0) // set success to true
}
case 32 { // This is a complaint ERC-20
returndatacopy(0, 0, 32)
result := mload(0) // Set `result = returndata` of external call
success := mload(0) // Set `success = returndata` of external call
}
default { // This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}

if (!result) {
return Error.TOKEN_TRANSFER_OUT_FAILED;
}

return Error.NO_ERROR;
require(success, "TOKEN_TRANSFER_OUT_FAILED");
}
}
43 changes: 43 additions & 0 deletions contracts/CErc20Delegate.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity ^0.5.12;

import "./CErc20.sol";

/**
* @title Compound's CErc20Delegate Contract
* @notice CTokens which wrap an EIP-20 underlying and are delegated to
* @author Compound
*/
contract CErc20Delegate is CErc20, CDelegateInterface {
/**
* @notice Construct an empty delegate
*/
constructor() public {}

/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) public {
// Shh -- currently unused
data;

// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}

require(msg.sender == admin, "only the admin may call _becomeImplementation");
}

/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() public {
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}

require(msg.sender == admin, "only the admin may call _resignImplementation");
}
}
Loading

0 comments on commit bcf0bc7

Please sign in to comment.