Skip to content

Commit

Permalink
tests/: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bun919tw committed Oct 7, 2021
1 parent 572496d commit 1b80ad0
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 17 deletions.
172 changes: 166 additions & 6 deletions tests/Contracts/CErc20Harness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import "../../contracts/CErc20Delegate.sol";
import "../../contracts/Legacy/CSLPDelegate.sol";
import "../../contracts/Legacy/CCTokenDelegate.sol";
import "../../contracts/CCollateralCapErc20Delegate.sol";
import "../../contracts/CCollateralCapErc20CheckRepayDelegate.sol";
import "../../contracts/Legacy/CCollateralCapErc20Delegator.sol";
import "../../contracts/CWrappedNativeDelegate.sol";
import "../../contracts/CWrappedNativeDelegator.sol";
import "./ComptrollerScenario.sol";

contract CErc20Harness is CErc20Immutable {
uint256 blockNumber = 100000;
uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

Expand Down Expand Up @@ -376,7 +377,7 @@ contract CErc20DelegateHarness is CErc20Delegate {
event Log(string x, address y);
event Log(string x, uint256 y);

uint256 blockNumber = 100000;
uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

Expand Down Expand Up @@ -531,6 +532,165 @@ contract CErc20DelegateHarness is CErc20Delegate {
}
}

contract CCollaterlaCapErc20CheckRepayDelegateHarness is CCollateralCapErc20CheckRepayDelegate {
event Log(string x, address y);
event Log(string x, uint256 y);

uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

mapping(address => bool) public failTransferToAddresses;

function exchangeRateStoredInternal() internal view returns (uint256) {
if (harnessExchangeRateStored) {
return harnessExchangeRate;
}
return super.exchangeRateStoredInternal();
}

function doTransferOut(
address payable to,
uint256 amount,
bool isNative
) internal {
require(failTransferToAddresses[to] == false, "TOKEN_TRANSFER_OUT_FAILED");
return super.doTransferOut(to, amount, isNative);
}

function getBlockNumber() internal view returns (uint256) {
return blockNumber;
}

function getBorrowRateMaxMantissa() public pure returns (uint256) {
return borrowRateMaxMantissa;
}

function harnessSetBlockNumber(uint256 newBlockNumber) public {
blockNumber = newBlockNumber;
}

function harnessFastForward(uint256 blocks) public {
blockNumber += blocks;
}

function harnessSetBalance(address account, uint256 amount) external {
accountTokens[account] = amount;
}

function harnessSetAccrualBlockNumber(uint256 _accrualblockNumber) public {
accrualBlockNumber = _accrualblockNumber;
}

function harnessSetTotalSupply(uint256 totalSupply_) public {
totalSupply = totalSupply_;
}

function harnessSetTotalBorrows(uint256 totalBorrows_) public {
totalBorrows = totalBorrows_;
}

function harnessIncrementTotalBorrows(uint256 addtlBorrow_) public {
totalBorrows = totalBorrows + addtlBorrow_;
}

function harnessSetTotalReserves(uint256 totalReserves_) public {
totalReserves = totalReserves_;
}

function harnessExchangeRateDetails(
uint256 totalSupply_,
uint256 totalBorrows_,
uint256 totalReserves_
) public {
totalSupply = totalSupply_;
totalBorrows = totalBorrows_;
totalReserves = totalReserves_;
}

function harnessSetExchangeRate(uint256 exchangeRate) public {
harnessExchangeRate = exchangeRate;
harnessExchangeRateStored = true;
}

function harnessSetFailTransferToAddress(address _to, bool _fail) public {
failTransferToAddresses[_to] = _fail;
}

function harnessMintFresh(address account, uint256 mintAmount) public returns (uint256) {
(uint256 err, ) = super.mintFresh(account, mintAmount, false);
return err;
}

function harnessRedeemFresh(
address payable account,
uint256 cTokenAmount,
uint256 underlyingAmount
) public returns (uint256) {
return super.redeemFresh(account, cTokenAmount, underlyingAmount, false);
}

function harnessAccountBorrows(address account) public view returns (uint256 principal, uint256 interestIndex) {
BorrowSnapshot memory snapshot = accountBorrows[account];
return (snapshot.principal, snapshot.interestIndex);
}

function harnessSetAccountBorrows(
address account,
uint256 principal,
uint256 interestIndex
) public {
accountBorrows[account] = BorrowSnapshot({principal: principal, interestIndex: interestIndex});
}

function harnessSetBorrowIndex(uint256 borrowIndex_) public {
borrowIndex = borrowIndex_;
}

function harnessBorrowFresh(address payable account, uint256 borrowAmount) public returns (uint256) {
return borrowFresh(account, borrowAmount, false);
}

function harnessRepayBorrowFresh(
address payer,
address account,
uint256 repayAmount
) public returns (uint256) {
(uint256 err, ) = repayBorrowFresh(payer, account, repayAmount, false, false);
return err;
}

function harnessLiquidateBorrowFresh(
address liquidator,
address borrower,
uint256 repayAmount,
CToken cTokenCollateral
) public returns (uint256) {
(uint256 err, ) = liquidateBorrowFresh(liquidator, borrower, repayAmount, cTokenCollateral, false);
return err;
}

function harnessReduceReservesFresh(uint256 amount) public returns (uint256) {
return _reduceReservesFresh(amount);
}

function harnessSetReserveFactorFresh(uint256 newReserveFactorMantissa) public returns (uint256) {
return _setReserveFactorFresh(newReserveFactorMantissa);
}

function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) public returns (uint256) {
return _setInterestRateModelFresh(newInterestRateModel);
}

function harnessSetInterestRateModel(address newInterestRateModelAddress) public {
interestRateModel = InterestRateModel(newInterestRateModelAddress);
}

function harnessCallBorrowAllowed(uint256 amount) public returns (uint256) {
return comptroller.borrowAllowed(address(this), msg.sender, amount);
}
}

contract CErc20DelegateScenario is CErc20Delegate {
constructor() public {}

Expand Down Expand Up @@ -563,7 +723,7 @@ contract CErc20DelegateScenarioExtra is CErc20DelegateScenario {
}

contract CSLPDelegateHarness is CSLPDelegate {
uint256 blockNumber = 100000;
uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

Expand Down Expand Up @@ -721,7 +881,7 @@ contract CSLPDelegateScenario is CSLPDelegate {
}

contract CCTokenDelegateHarness is CCTokenDelegate {
uint256 blockNumber = 100000;
uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

Expand Down Expand Up @@ -886,7 +1046,7 @@ contract CCollateralCapErc20DelegateHarness is CCollateralCapErc20Delegate {
event Log(string x, address y);
event Log(string x, uint256 y);

uint256 blockNumber = 100000;
uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

Expand Down Expand Up @@ -1078,7 +1238,7 @@ contract CWrappedNativeDelegateHarness is CWrappedNativeDelegate {
event Log(string x, address y);
event Log(string x, uint256 y);

uint256 blockNumber = 100000;
uint256 public blockNumber = 100000;
uint256 harnessExchangeRate;
bool harnessExchangeRateStored;

Expand Down
74 changes: 70 additions & 4 deletions tests/Contracts/EvilToken.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
pragma solidity ^0.5.16;

import "./ERC20.sol";
import "./FaucetToken.sol";
import "../../contracts/Legacy/CEther.sol";
import "../../contracts/CCollateralCapErc20.sol";
import "../../contracts/Legacy/CTokenDeprecated.sol";
import "../../contracts/CToken.sol";
import "../../contracts/CErc20.sol";
import "../../contracts/ComptrollerInterface.sol";

/**
* @title The Compound Evil Test Token
Expand Down Expand Up @@ -73,7 +77,7 @@ contract EvilAccount is RecipientInterface {
borrowAmount = _borrowAmount;
}

function attack() external payable {
function attackBorrow() external payable {
// Mint crEth.
CEther(crEth).mint.value(msg.value)();
ComptrollerInterface comptroller = CEther(crEth).comptroller();
Expand All @@ -84,7 +88,7 @@ contract EvilAccount is RecipientInterface {
comptroller.enterMarkets(markets);

// Borrow EvilTransferToken.
require(CCollateralCapErc20(crEvilToken).borrow(borrowAmount) == 0, "first borrow failed");
require(CErc20(crEvilToken).borrow(borrowAmount) == 0, "first borrow failed");
}

function tokensReceived() external {
Expand All @@ -95,7 +99,55 @@ contract EvilAccount is RecipientInterface {
function() external payable {}
}

contract EvilAccount2 is RecipientInterface {
address private crWeth;
address private crEvilToken;
address private borrower;
uint256 private repayAmount;

constructor(
address _crWeth,
address _crEvilToken,
address _borrower,
uint256 _repayAmount
) public {
crWeth = _crWeth;
crEvilToken = _crEvilToken;
borrower = _borrower;
repayAmount = _repayAmount;
}

function attackLiquidate() external {
// Make sure the evil account has enough balance to repay.
address evilToken = CErc20(crEvilToken).underlying();
require(ERC20Base(evilToken).balanceOf(address(this)) > repayAmount, "insufficient balance");

// Approve for repayment.
require(ERC20Base(evilToken).approve(crEvilToken, repayAmount) == true, "failed to approve");

// Liquidate EvilTransferToken.
require(
CErc20(crEvilToken).liquidateBorrow(borrower, repayAmount, CToken(crWeth)) == 0,
"first liquidate failed"
);
}

function tokensReceived() external {
// Make sure the evil account has enough balance to repay.
address weth = CErc20(crWeth).underlying();
require(ERC20Base(weth).balanceOf(address(this)) > repayAmount, "insufficient balance");

// Approve for repayment.
require(ERC20Base(weth).approve(crWeth, repayAmount) == true, "failed to approve");

// Liquidate ETH.
CErc20(crWeth).liquidateBorrow(borrower, repayAmount, CToken(crWeth));
}
}

contract EvilTransferToken is FaucetToken {
bool private attackSwitchOn;

constructor(
uint256 _initialAmount,
string memory _tokenName,
Expand All @@ -108,7 +160,9 @@ contract EvilTransferToken is FaucetToken {
balanceOf[dst] = balanceOf[dst].add(amount);
emit Transfer(msg.sender, dst, amount);

RecipientInterface(dst).tokensReceived();
if (attackSwitchOn) {
RecipientInterface(dst).tokensReceived();
}
return true;
}

Expand All @@ -121,6 +175,18 @@ contract EvilTransferToken is FaucetToken {
balanceOf[dst] = balanceOf[dst].add(amount);
allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);
emit Transfer(src, dst, amount);

if (attackSwitchOn) {
RecipientInterface(src).tokensReceived();
}
return true;
}

function turnSwitchOn() external {
attackSwitchOn = true;
}

function turnSwitchOff() external {
attackSwitchOn = false;
}
}
Loading

0 comments on commit 1b80ad0

Please sign in to comment.