Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update error handling #207

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5a8c41d
Upgrade Contracts to 0.8.6
arjun-io Jul 22, 2021
bbd14c9
Remove CToken SafeMath, use Custom Errors
arjun-io Aug 29, 2021
46ee4cd
EnterExitMarkets.scen fixes
arjun-io Aug 29, 2021
c6dc5b2
Borrow.scen fixes
arjun-io Aug 29, 2021
1d71611
Update CI and Dockerfile Solidity version
arjun-io Aug 29, 2021
018f227
Increase memory available for CI
arjun-io Aug 30, 2021
8265286
gasCosts
arjun-io Aug 31, 2021
6313621
Remove *LocalVar structs
arjun-io Aug 31, 2021
b7c1361
clean up proposalID
arjun-io Sep 4, 2021
55daa66
pull in punitive accounting
kbrizzle Sep 12, 2021
c945f35
comments
arjun-io Sep 14, 2021
14c0f7c
audit remediations
arjun-io Oct 11, 2021
4a54ec5
further remediations
arjun-io Oct 26, 2021
42e6d56
Merge remote-tracking branch 'upstream/master' into rfp12-ctoken-cleanup
arjun-io Dec 1, 2021
01948c6
compilation fixes after master merge
arjun-io Dec 1, 2021
3a50927
Partial Fix: L03 - Gas inefficiencies
arjun-io Mar 11, 2022
fa51595
Partial Fix: L05 - Missing or erroneous docstrings and comments
arjun-io Mar 11, 2022
8ad1367
Partial Fix: L08 - Unreachable code
arjun-io Mar 11, 2022
56efb6b
var type
arjun-io Mar 11, 2022
bc6cca4
remove unused accrue interest custom errors
arjun-io Mar 16, 2022
8d79b11
Partial Fix: N13 - Typos
arjun-io Mar 11, 2022
442519e
Fix L07: Outdated Solidity versions
arjun-io Mar 23, 2022
30c5c1b
Merge pull request #5 from equilibria-xyz/l07
arjun-io Mar 26, 2022
4e5f455
Merge pull request #4 from equilibria-xyz/n13
arjun-io Mar 26, 2022
1687c56
Merge pull request #3 from equilibria-xyz/l08
arjun-io Mar 26, 2022
57385cb
Merge pull request #2 from equilibria-xyz/l05
arjun-io Mar 26, 2022
079d62f
Merge pull request #1 from equilibria-xyz/l03
arjun-io Mar 26, 2022
769d3b8
refactor: update remaining codebase to modern error handling.
ZrowGz May 26, 2022
1023f6e
undo removal of noerror returns, separated out to distinct branch.
ZrowGz May 26, 2022
85ad180
refactor: ctoken.sol errors updated
ZrowGz May 26, 2022
dbf4d8b
refactor: comptrollerG7 error handling completed - still needs math work
ZrowGz Jun 14, 2022
c6c2eed
refactor: BaseJumpRateModelV2 error updated
ZrowGz Jun 14, 2022
a50bc64
refactor: cerc20 errors updated. needs returns removed on correct branch
ZrowGz Jun 14, 2022
90d0439
refactor: cerc20 delegate, delegator, and cether - modern error handling
ZrowGz Jun 14, 2022
fc6cf90
refactor: migrated interfaces to directory and update imports, update…
ZrowGz Jun 14, 2022
eaacb3b
refactor: timelock error handling updated
ZrowGz Jun 14, 2022
1503e91
refactor: reorganized interfaces, updated errors in governors, unitro…
ZrowGz Jun 14, 2022
85177f3
refactor: cleanup of internal noerror and single file interfaces
ZrowGz Jun 15, 2022
b6640ed
refactor: clean up remaining few NO_ERRORs & clean up formatting
ZrowGz Jun 15, 2022
39c92fc
refactor: update governoralpha requires and corrected other errors
ZrowGz Jun 15, 2022
2604706
refactor: corrected some errors and started making some changes to te…
ZrowGz Jun 20, 2022
6f84023
Create GovernorBravoDelegateG2.sol
ZrowGz Jun 23, 2022
7504b6a
add missing file
ZrowGz Jun 23, 2022
c9b39b7
Merge branch 'zrowgz/update-error-handling' into update-error-handling
ZrowGz Jun 23, 2022
588c10a
cleaned up merge conflicts
ZrowGz Jun 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 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.16/solc-static-linux -O /usr/local/bin/solc
sudo wget https://github.com/ethereum/solidity/releases/download/v0.8.10/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:
- run:
shell: /bin/bash -eox pipefail -O globstar
name: yarn test
command: JEST_JUNIT_OUTPUT_DIR=~/junit JEST_JUNIT_OUTPUT_NAME=test-results.xml yarn test $(circleci tests glob 'tests/**/**Test.js' | circleci tests split --split-by=timings)
command: NODE_OPTIONS="--max-old-space-size=12228" JEST_JUNIT_OUTPUT_DIR=~/junit JEST_JUNIT_OUTPUT_NAME=test-results.xml yarn test $(circleci tests glob 'tests/**/**Test.js' | circleci tests split --split-by=timings)
- save_cache:
paths:
- .build
Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
steps:
- run:
|
sudo wget https://github.com/ethereum/solidity/releases/download/v0.5.16/solc-static-linux -O /usr/local/bin/solc
sudo wget https://github.com/ethereum/solidity/releases/download/v0.8.10/solc-static-linux -O /usr/local/bin/solc
sudo chmod +x /usr/local/bin/solc
- checkout
- restore_cache:
Expand Down Expand Up @@ -112,7 +112,7 @@ jobs:
shell: /bin/bash -eox pipefail -O globstar
name: yarn test
no_output_timeout: 30m
command: JEST_JUNIT_OUTPUT_DIR=~/junit JEST_JUNIT_OUTPUT_NAME=test-results.xml script/coverage $(circleci tests glob 'tests/**/**Test.js' | circleci tests split --split-by=timings) -- --maxWorkers=4
command: NODE_OPTIONS="--max-old-space-size=12228" JEST_JUNIT_OUTPUT_DIR=~/junit JEST_JUNIT_OUTPUT_NAME=test-results.xml script/coverage $(circleci tests glob 'tests/**/**Test.js' | circleci tests split --split-by=timings) -- --maxWorkers=4
- save_cache:
paths:
- .build
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ scenario/build/webpack.js
scenario/.tscache
script/certora
tests/scenarios/
tests/Scenarios/
junit.xml
.build
.last_confs
.saddle_history
node_modules_tmp
node_modules_tmp
.idea
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM mhart/alpine-node:13.8.0

RUN apk update && apk add --no-cache --virtual build-dependencies git python g++ make
RUN wget https://github.com/ethereum/solidity/releases/download/v0.5.16/solc-static-linux -O /bin/solc && chmod +x /bin/solc
RUN wget https://github.com/ethereum/solidity/releases/download/v0.8.10/solc-static-linux -O /bin/solc && chmod +x /bin/solc

RUN mkdir -p /compound-protocol
WORKDIR /compound-protocol
Expand Down
69 changes: 41 additions & 28 deletions contracts/BaseJumpRateModelV2.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
pragma solidity ^0.5.16;
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;

import "./SafeMath.sol";
import "./interfaces/InterestRateModel.sol";

/**
* @title Logic for Compound's JumpRateModel Contract V2.
* @author Compound (modified by Dharma Labs, refactored by Arr00)
* @notice Version 2 modifies Version 1 by enabling updateable parameters.
*/
contract BaseJumpRateModelV2 {
using SafeMath for uint;
abstract contract BaseJumpRateModelV2 is InterestRateModel {

error AddressUnauthorized();

event NewInterestParams(uint baseRatePerBlock, uint multiplierPerBlock, uint jumpMultiplierPerBlock, uint kink);

uint256 private constant BASE = 1e18;

/**
* @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly
*/
Expand Down Expand Up @@ -44,27 +48,36 @@ contract BaseJumpRateModelV2 {

/**
* @notice Construct an interest rate model
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
* @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly)
*/
constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_, address owner_) internal {
constructor(
uint baseRatePerYear,
uint multiplierPerYear,
uint jumpMultiplierPerYear,
uint kink_,
address owner_
) {
owner = owner_;

updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);
}

/**
* @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock)
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
*/
function updateJumpRateModel(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) external {
require(msg.sender == owner, "only the owner may call this function.");
function updateJumpRateModel(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) virtual external {
// require(msg.sender == owner, "only the owner may call this function.");
if (msg.sender != owner) {
revert AddressUnauthorized();
}

updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);
}
Expand All @@ -74,33 +87,33 @@ contract BaseJumpRateModelV2 {
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market (currently unused)
* @return The utilization rate as a mantissa between [0, 1e18]
* @return The utilization rate as a mantissa between [0, BASE]
*/
function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) {
// Utilization rate is 0 when there are no borrows
if (borrows == 0) {
return 0;
}

return borrows.mul(1e18).div(cash.add(borrows).sub(reserves));
return borrows * BASE / (cash + borrows - reserves);
}

/**
* @notice Calculates the current borrow rate per block, with the error code expected by the market
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @return The borrow rate percentage per block as a mantissa (scaled by 1e18)
* @return The borrow rate percentage per block as a mantissa (scaled by BASE)
*/
function getBorrowRateInternal(uint cash, uint borrows, uint reserves) internal view returns (uint) {
uint util = utilizationRate(cash, borrows, reserves);

if (util <= kink) {
return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);
return ((util * multiplierPerBlock) / BASE) + baseRatePerBlock;
} else {
uint normalRate = kink.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);
uint excessUtil = util.sub(kink);
return excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add(normalRate);
uint normalRate = ((kink * multiplierPerBlock) / BASE) + baseRatePerBlock;
uint excessUtil = util - kink;
return ((excessUtil * jumpMultiplierPerBlock) / BASE) + normalRate;
}
}

Expand All @@ -110,26 +123,26 @@ contract BaseJumpRateModelV2 {
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @param reserveFactorMantissa The current reserve factor for the market
* @return The supply rate percentage per block as a mantissa (scaled by 1e18)
* @return The supply rate percentage per block as a mantissa (scaled by BASE)
*/
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint) {
uint oneMinusReserveFactor = uint(1e18).sub(reserveFactorMantissa);
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) virtual override public view returns (uint) {
uint oneMinusReserveFactor = BASE - reserveFactorMantissa;
uint borrowRate = getBorrowRateInternal(cash, borrows, reserves);
uint rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);
return utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18);
uint rateToPool = borrowRate * oneMinusReserveFactor / BASE;
return utilizationRate(cash, borrows, reserves) * rateToPool / BASE;
}

/**
* @notice Internal function to update the parameters of the interest rate model
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
*/
function updateJumpRateModelInternal(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) internal {
baseRatePerBlock = baseRatePerYear.div(blocksPerYear);
multiplierPerBlock = (multiplierPerYear.mul(1e18)).div(blocksPerYear.mul(kink_));
jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear);
baseRatePerBlock = baseRatePerYear / blocksPerYear;
multiplierPerBlock = (multiplierPerYear * BASE) / (blocksPerYear * kink_);
jumpMultiplierPerBlock = jumpMultiplierPerYear / blocksPerYear;
kink = kink_;

emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);
Expand Down
90 changes: 45 additions & 45 deletions contracts/CDaiDelegate.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
pragma solidity ^0.5.16;
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;

import "./CErc20Delegate.sol";
import "./interfaces/IMaker.sol";

/**
* @title Compound's CDai Contract
* @notice CToken which wraps Multi-Collateral DAI
* @author Compound
*/
contract CDaiDelegate is CErc20Delegate {

// error AddressUnauthorized();
// error MustUseDai();
// error MathError();

/**
* @notice DAI adapter address
*/
Expand All @@ -27,8 +34,11 @@ contract CDaiDelegate is CErc20Delegate {
* @notice Delegate interface to become the implementation
* @param data The encoded arguments for becoming
*/
function _becomeImplementation(bytes memory data) public {
require(msg.sender == admin, "only the admin may initialize the implementation");
function _becomeImplementation(bytes memory data) override public {
// require(msg.sender == admin, "only the admin may initialize the implementation");
if (msg.sender != admin) {
revert AddressUnauthorized();
}

(address daiJoinAddress_, address potAddress_) = abi.decode(data, (address, address));
return _becomeImplementation(daiJoinAddress_, potAddress_);
Expand All @@ -45,15 +55,18 @@ contract CDaiDelegate is CErc20Delegate {
PotLike pot = PotLike(potAddress_);
GemLike dai = daiJoin.dai();
VatLike vat = daiJoin.vat();
require(address(dai) == underlying, "DAI must be the same as underlying");
// require(address(dai) == underlying, "DAI must be the same as underlying");
if (address(dai) != underlying) {
revert MustUseDai();
}

// Remember the relevant addresses
daiJoinAddress = daiJoinAddress_;
potAddress = potAddress_;
vatAddress = address(vat);

// Approve moving our DAI into the vat through daiJoin
dai.approve(daiJoinAddress, uint(-1));
dai.approve(daiJoinAddress, type(uint).max);

// Approve the pot to transfer our funds within the vat
vat.hope(potAddress);
Expand All @@ -69,8 +82,11 @@ contract CDaiDelegate is CErc20Delegate {
/**
* @notice Delegate interface to resign the implementation
*/
function _resignImplementation() public {
require(msg.sender == admin, "only the admin may abandon the implementation");
function _resignImplementation() override public {
// require(msg.sender == admin, "only the admin may abandon the implementation");
if (msg.sender != admin) {
revert AddressUnauthorized();
}

// Transfer all cash out of the DSR - note that this relies on self-transfer
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
Expand Down Expand Up @@ -98,7 +114,7 @@ contract CDaiDelegate is CErc20Delegate {
* @dev This calculates interest accrued from the last checkpointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueInterest() public returns (uint) {
function accrueInterest() override public returns (uint) {
// Accumulate DSR interest
PotLike(potAddress).drip();

Expand All @@ -113,7 +129,7 @@ contract CDaiDelegate is CErc20Delegate {
* @dev This excludes the value of the current message, if any
* @return The quantity of underlying tokens owned by this contract
*/
function getCashPrior() internal view returns (uint) {
function getCashPrior() override internal view returns (uint) {
PotLike pot = PotLike(potAddress);
uint pie = pot.pie(address(this));
return mul(pot.chi(), pie) / RAY;
Expand All @@ -125,13 +141,17 @@ contract CDaiDelegate is CErc20Delegate {
* @param amount Amount of underlying to transfer
* @return The actual amount that is transferred
*/
function doTransferIn(address from, uint amount) internal returns (uint) {
function doTransferIn(address from, uint amount) override internal returns (uint) {
// Read from storage once
address underlying_ = underlying;
// Perform the EIP-20 transfer in
EIP20Interface token = EIP20Interface(underlying);
require(token.transferFrom(from, address(this), amount), "unexpected EIP-20 transfer in return");
EIP20Interface token = EIP20Interface(underlying_);

// require(token.transferFrom(from, address(this), amount), "unexpected EIP-20 transfer in return");
token.transferFrom(from, address(this), amount);

DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
GemLike dai = GemLike(underlying);
GemLike dai = GemLike(underlying_);
PotLike pot = PotLike(potAddress);
VatLike vat = VatLike(vatAddress);

Expand All @@ -154,7 +174,7 @@ contract CDaiDelegate is CErc20Delegate {
* @param to Address to transfer funds to
* @param amount Amount of underlying to transfer
*/
function doTransferOut(address payable to, uint amount) internal {
function doTransferOut(address payable to, uint amount) override internal {
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
PotLike pot = PotLike(potAddress);

Expand All @@ -171,38 +191,18 @@ contract CDaiDelegate is CErc20Delegate {
uint256 constant RAY = 10 ** 27;

function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "add-overflow");
// require((z = x + y) >= x, "add-overflow");
z = x + y;
if (z >= x) {
revert MathError();
}
}

function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "mul-overflow");
// require(y == 0 || (z = x * y) / y == x, "mul-overflow");
z = x * y;
if (y != 0 && z / y != x) {
revert MathError();
}
}
}

/*** Maker Interfaces ***/

interface PotLike {
function chi() external view returns (uint);
function pie(address) external view returns (uint);
function drip() external returns (uint);
function join(uint) external;
function exit(uint) external;
}

interface GemLike {
function approve(address, uint) external;
function balanceOf(address) external view returns (uint);
function transferFrom(address, address, uint) external returns (bool);
}

interface VatLike {
function dai(address) external view returns (uint);
function hope(address) external;
}

interface DaiJoinLike {
function vat() external returns (VatLike);
function dai() external returns (GemLike);
function join(address, uint) external payable;
function exit(address, uint) external;
}
}
Loading