# # # # # # # # # # # # # # # # # # # # # #
# #
# |\_/| #
# | O O #
# | <> _ #
# | _/\------____ ((| |)) #
# | `--' | #
# ____|_ ___| |___.' #
# /_/_____/____/_______| #
# _ _ _ #
# | | | | | | #
# | |_| | ___ _ _ _ __ __| | #
# | _ | / _ \ | | | || '_ \ / _` | #
# | | | || (_) || |_| || | | || (_| | #
# \_| |_/ \___/ \__,_||_| |_| \__,_| #
# #
# # # # # # # # # # # # # # # # # # # # # #
Id | Title | Instances |
---|---|---|
[H-01] | Missing slippage checks | 4 |
Total: 4 instances over 1 issues.
Id | Title | Instances |
---|---|---|
[M-01] | Missing staleness checks for Chainlink oracle | 2 |
[M-02] | Chainlink oracle will return the wrong price if the aggregator hits minAnswer |
2 |
[M-03] | Return values of transfer /transferFrom not checked |
2 |
[M-04] | Some functions do not work correctly with fee-on-transfer tokens | 2 |
[M-05] | Some ERC20 can revert on a zero value transfer |
1 |
[M-06] | Non-compliant IERC20 tokens may revert with transfer |
2 |
[M-07] | Centralization issue caused by admin privileges | 26 |
Total: 37 instances over 7 issues.
Id | Title | Instances |
---|---|---|
[L-01] | Execution at deadlines should be allowed | 2 |
[L-02] | Possible reentrancy with callback on transfer tokens | 2 |
[L-03] | Use of ecrecover is susceptible to signature malleability |
2 |
[L-04] | Low level calls with Solidity before 0.8.14 result in an optimiser bug |
1 |
[L-05] | Missing checks in constructor/initialize | 9 |
[L-06] | Vulnerability to storage write removal | 1 |
[L-07] | Functions calling contracts with transfer hooks are missing reentrancy guards | 5 |
[L-08] | Usage of functions that are not part of the IERC20 interface |
4 |
[L-09] | Large transfers may not work with some ERC20 tokens |
4 |
[L-10] | Large approvals may not work with some ERC20 tokens |
1 |
[L-11] | approve can revert if the current approval is not zero |
1 |
[L-12] | Return values of approve not checked |
1 |
[L-13] | Pausing withdrawals is unfair to the users | 1 |
[L-14] | Unsafe downcast may overflow | 3 |
[L-15] | Some functions contain the same exact logic | 4 |
[L-16] | Possible division by 0 is not prevented | 2 |
[L-17] | Truncating block.timestamp can reduce the lifespan of a contract |
4 |
[L-18] | Draft imports should be avoided | 1 |
[L-19] | Missing limits when setting min/max amounts | 14 |
[L-20] | Use of transfer instead of safeTransfer |
8 |
[L-21] | Owner can renounce ownership while system is paused | 1 |
[L-22] | Missing contract-existence checks before low-level calls | 1 |
[L-23] | External calls in an unbounded loop can result in a DoS | 10 |
[L-24] | Solidity version 0.8.20 may not work on other chains due to PUSH0 |
43 |
[L-25] | Lack of two-step update for critical addresses | 5 |
[L-26] | Use of ownership with a single step rather than double | 7 |
[L-27] | Use of abi.encodePacked with dynamic types inside keccak256 |
1 |
[L-28] | Loss of precision on division | 27 |
[L-29] | Gas griefing/theft is possible on an unsafe external call | 1 |
[L-30] | onlyOwner functions not accessible if owner renounces ownership |
19 |
[L-31] | Using a vulnerable dependency from some libraries | 40 |
[L-32] | Missing checks for address(0) in constructor/initializers |
23 |
[L-33] | Missing checks for address(0) when updating state variables |
10 |
[L-34] | Use of floating pragma | 42 |
[L-35] | Array lacks use of the pop function |
1 |
Total: 301 instances over 35 issues.
Id | Title | Instances |
---|---|---|
[NC-01] | Missing events in sensitive functions | 6 |
[NC-02] | Unused named return |
19 |
[NC-03] | Unused error definition |
4 |
[NC-04] | Unused event definition |
1 |
[NC-05] | Unused modifier definition |
1 |
[NC-06] | OpenZeppelin libraries should be upgraded to a newer version | 40 |
[NC-07] | Unused/empty receive /fallback |
1 |
[NC-08] | Use at least Solidity version 0.8.19 to gain some gas boost |
45 |
[NC-09] | Hardcoded address should be avoided |
8 |
[NC-10] | Avoid hardcoded index accesses | 5 |
[NC-11] | Variable initialization with default value | 3 |
[NC-12] | Inconsistent usage of require /error |
2 |
[NC-13] | Unbounded loop may run out of gas | 14 |
[NC-14] | Public functions not called internally | 4 |
[NC-15] | Large multiples of ten should use scientific notation | 3 |
[NC-16] | Use of exponentiation instead of scientific notation | 2 |
[NC-17] | Use EIP-5627 to describe EIP-712 domains | 2 |
[NC-18] | Unused state variables | 2 |
[NC-19] | 2**<n> - 1 should be re-written as type(uint<n>).max |
5 |
[NC-20] | Use of non-named numeric constants | 40 |
[NC-21] | Some functions don't have any logic | 1 |
[NC-22] | Non-assembly method available | 1 |
[NC-23] | Some contract names don't follow the Solidity naming conventions | 1 |
[NC-24] | Some functions don't follow the Solidity naming conventions | 1 |
[NC-25] | Variable names don't follow the Solidity naming convention | 18 |
[NC-26] | Constant names should be UPPERCASE | 4 |
[NC-27] | Don't use uppercase for non constant /immutable variables |
2 |
[NC-28] | Use a single file for system wide constants | 10 |
[NC-29] | Use named mappings to improve code readability | 16 |
[NC-30] | Some events are never emitted | 1 |
[NC-31] | Event does not have proper indexed fields |
27 |
[NC-32] | Inconsistent method of specifying a floating pragma | 6 |
[NC-33] | experimental pragmas may be dangerous/deprecated |
2 |
[NC-34] | Old Solidity version | 43 |
[NC-35] | Zero as a function argument should have a descriptive meaning | 3 |
[NC-36] | Use of abi.encodePacked instead of bytes.concat |
3 |
[NC-37] | Use of constant variables instead of immutable |
5 |
[NC-38] | require /revert without any message |
3 |
[NC-39] | Consider activating via-ir for deploying |
1 |
[NC-40] | Imports should be organized more systematically | 14 |
[NC-41] | Event is missing msg.sender parameter |
5 |
[NC-42] | Parameter omission in events | 13 |
[NC-43] | Events may be emitted out of order due to reentrancy | 72 |
[NC-44] | Consider disabling renounceOwnership |
7 |
[NC-45] | Custom error without details |
75 |
[NC-46] | Constants in comparisons should appear on the left side | 53 |
[NC-47] | Consider using delete instead of assigning zero/false to clear values |
6 |
[NC-48] | Use a ternary statement instead of if /else when appropriate |
1 |
[NC-49] | Files not imported in any source code | 1 |
[NC-50] | Layout order does not comply with best practices | 7 |
[NC-51] | Function visibility order does not comply with best practices | 9 |
[NC-52] | Long functions should be refactored into multiple functions | 3 |
[NC-53] | Imports should use double quotes rather than single quotes | 127 |
[NC-54] | Strings should use double quotes rather than single quotes | 19 |
[NC-55] | Lines are too long | 19 |
[NC-56] | Avoid the use of sensitive terms | 63 |
[NC-57] | Misplaced SPDX identifier | 1 |
[NC-58] | Typos in comments | 54 |
[NC-59] | Contracts should have full test coverage | 1 |
[NC-60] | Large or complicated code bases should implement invariant tests | 1 |
[NC-61] | Inconsistent spacing in comments | 38 |
[NC-62] | State variables should include comments | 20 |
[NC-63] | Complicated functions should have explicit comments | 1 |
[NC-64] | Assembly code should have explicit comments | 1 |
[NC-65] | Missing NatSpec @param |
19 |
[NC-66] | Incomplete NatSpec @return |
13 |
Total: 998 instances over 66 issues.
Id | Title | Instances | Gas Saved |
---|---|---|---|
[GAS-01] | Use custom error s instead of require /assert |
7 | 203 |
[GAS-02] | Structs can be packed into fewer storage slots | 1 | 20,000 |
[GAS-03] | Structs can be modified to fit in fewer storage slots | 1 | 40,000 |
[GAS-04] | Multiple mapping s that share an ID can be combined into a single mapping of ID / struct |
2 | 40,084 |
[GAS-05] | Use of memory instead of storage for struct/array state variables |
4 | 8,400 |
[GAS-06] | State variables access within a loop | 5 | 1,325 |
[GAS-07] | State variables only set in the constructor should be declared immutable |
18 | 360,000 |
[GAS-08] | Cache state variables with stack variables | 25 | 6,700 |
[GAS-09] | Use of memory instead of calldata for immutable arguments |
8 | 2,882 |
[GAS-10] | Avoid updating storage when the value hasn't changed | 27 | 18,900 |
[GAS-11] | Use of emit inside a loop |
1 | 1,026 |
[GAS-12] | Shortcircuit rules can be be used to optimize some gas usage | 1 | 2,100 |
[GAS-13] | Cache multiple accesses of a mapping/array | 11 | 546 |
[GAS-14] | Using private for constants saves gas |
18 | 151,308 |
[GAS-15] | Using bool for storage incurs overhead |
2 | 34,200 |
[GAS-16] | Function calls should be cached instead of re-calling the function | 13 | - |
[GAS-17] | Functions that revert when called by normal users can be payable |
55 | 1,155 |
[GAS-18] | Array length is not cached |
10 | 30 |
[GAS-19] | Add unchecked blocks for subtractions where the operands cannot underflow |
2 | 170 |
[GAS-20] | Empty blocks should be removed or emit something | 1 | 4,006 |
[GAS-21] | Usage of uints /ints smaller than 32 bytes (256 bits) incurs overhead |
11 | 66 |
[GAS-22] | Using pre instead of post increments/decrements | 5 | 15 |
[GAS-23] | Avoid using _msgSender if not supporting EIP-2771 |
54 | 864 |
[GAS-24] | Low level call can be optimized with assembly |
1 | 248 |
[GAS-25] | Use assembly to emit an event |
82 | 3,116 |
[GAS-26] | >= /<= costs less gas than > /< |
69 | 207 |
[GAS-27] | internal/private functions only called once can be inlined to save gas |
22 | 440 |
[GAS-28] | abi.encode is more efficient than abi.encodePacked |
3 | 720 |
[GAS-29] | Avoid contract existence checks by using low level calls | 26 | 2,600 |
[GAS-30] | Unused named return variables without optimizer waste gas | 17 | 60 |
[GAS-31] | Using this.<fn>() wastes gas |
8 | 800 |
[GAS-32] | Function names can be optimized | 48 | 1,056 |
[GAS-33] | Avoid zero transfers calls | 6 | - |
[GAS-34] | Using delete instead of setting mapping/struct to 0 saves gas |
4 | 20 |
[GAS-35] | x += y is more expensive than x = x + y for state variables |
15 | 1,695 |
[GAS-36] | Bytes constants are more efficient than string constants | 2 | 756 |
[GAS-37] | Use a more recent version of Solidity | 43 | - |
[GAS-38] | Constructors can be marked payable |
21 | 441 |
[GAS-39] | Lack of unchecked in loops |
5 | 300 |
[GAS-40] | uint comparison with zero can be cheaper |
10 | 40 |
[GAS-41] | Use assembly to check for address(0) |
6 | 36 |
[GAS-42] | Use assembly to write hashes | 14 | 1,680 |
Total: 684 instances over 42 issues with an estimate of 708,195 gas saved.
The following functions lack slippage protection and they are exposed to front-running, which will lead to the user losing their funds as they get sandwiched.
There are 4 instances of this issue.
File: core/solidity/contracts/core/WUSDA.sol
59: function mint(uint256 _wusdaAmount) external override returns (uint256 _usdaAmount) {
60: _usdaAmount = _wUSDAToUSDA(_wusdaAmount, _usdaSupply());
61: _deposit(_msgSender(), _msgSender(), _usdaAmount, _wusdaAmount);
62: }
70: function mintFor(address _to, uint256 _wusdaAmount) external override returns (uint256 _usdaAmount) {
71: _usdaAmount = _wUSDAToUSDA(_wusdaAmount, _usdaSupply());
72: _deposit(_msgSender(), _to, _usdaAmount, _wusdaAmount);
73: }
119: function deposit(uint256 _usdaAmount) external override returns (uint256 _wusdaAmount) {
120: _wusdaAmount = _usdaToWUSDA(_usdaAmount, _usdaSupply());
121: _deposit(_msgSender(), _msgSender(), _usdaAmount, _wusdaAmount);
122: }
130: function depositFor(address _to, uint256 _usdaAmount) external override returns (uint256 _wusdaAmount) {
131: _wusdaAmount = _usdaToWUSDA(_usdaAmount, _usdaSupply());
132: _deposit(_msgSender(), _to, _usdaAmount, _wusdaAmount);
133: }
[59-62, 70-73, 119-122, 130-133]
Consider adding an additional parameter to indicate the minimum (or maximum) amount that should be transfered to the user, revert the transaction if this threshold is not met.
latestRoundData
may return stale data, and there aren't any checks to ensure that this doesn't happen.
This can be caused by any issues with Chainlink, such as oracle consensus problems or chain congestion, which may result in this contract relying on outdated data.
There are 2 instances of this issue.
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit missing negative price check
58: (,,, uint256 _updatedAt,) = _AGGREGATOR.latestRoundData();
[58]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
// @audit missing stale answer check
12: (, int256 _answer,,,) = _aggregator.latestRoundData();
[12]
Consider using the following checks:
(uint80 roundId, int256 answer, uint startedAt, uint updatedAt, uint80) = oracle.latestRoundData();
// negative price check
require(answer > 0, "Negative Oracle Price");
// stale answer check
require(updatedAt + TIME_THRESHOLD >= block.timestamp, "Stale pricefeed");
Chainlink aggregators have a built-in circuit breaker if the price of an asset goes outside of a predetermined price band.
The result is that if an asset experiences a huge drop in value (i.e. LUNA crash) the price of the oracle will continue to return the minPrice
instead of the actual price of the asset.
This would allow users to continue borrowing with the asset but at the wrong price. This is exactly what happened to Venus on BSC when LUNA crashed.
There are 2 instances of this issue.
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit missing min/max price check
58: (,,, uint256 _updatedAt,) = _AGGREGATOR.latestRoundData();
[58]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
// @audit missing min/max price check
12: (, int256 _answer,,,) = _aggregator.latestRoundData();
[12]
Consider using the following checks:
(uint80, int256 answer, uint, uint, uint80) = oracle.latestRoundData();
// minPrice check
require(answer > minPrice, "Min price exceeded");
// maxPrice check
require(answer < maxPrice, "Max price exceeded");
Not all IERC20
implementations revert when there's a failure while transfering. The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually making a payment.
There are 2 instances of this issue.
File: core/solidity/contracts/core/AMPHClaimer.sol
129: IERC20(_token).transfer(owner(), _amount);
[129]
File: core/solidity/contracts/core/Vault.sol
194: _rewardToken.transfer(_msgSender(), _earnedReward);
[194]
Some tokens take a transfer fee (e.g. STA
, PAXG
), some do not currently charge a fee but may do so in the future (e.g. USDT
, USDC
).
Should a fee-on-transfer token be added as an asset and deposited, it could be abused, as the accounting is wrong. In the current implementation the following function calls do not work well with fee-on-transfer tokens as the amount variable is the pre-fee amount, including the fee, whereas the final balance do not include the fee anymore.
There are 2 instances of this issue.
Expand findings
File: core/solidity/contracts/core/Vault.sol
// @audit missing checks on line 92
89: function depositERC20(address _token, uint256 _amount) external override onlyMinter {
90: if (CONTROLLER.tokenId(_token) == 0) revert Vault_TokenNotRegistered();
91: if (_amount == 0) revert Vault_AmountZero();
92: SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(_token), _msgSender(), address(this), _amount);
93: if (CONTROLLER.tokenCollateralType(_token) == IVaultController.CollateralType.CurveLPStakedOnConvex) {
94: uint256 _poolId = CONTROLLER.tokenPoolId(_token);
95: /// If it's type CurveLPStakedOnConvex then pool id can't be 0
96: IBooster _booster = CONTROLLER.BOOSTER();
97: if (isTokenStaked[_token]) {
98: /// In this case the user's balance is already staked so we only stake the newly deposited amount
99: _depositAndStakeOnConvex(_token, _booster, _amount, _poolId);
100: } else {
101: /// In this case the user's balance isn't staked so we stake the amount + his balance for the specific tokenv
102: isTokenStaked[_token] = true;
103: _depositAndStakeOnConvex(_token, _booster, balances[_token] + _amount, _poolId);
104: }
105: }
106: balances[_token] += _amount;
107: CONTROLLER.modifyTotalDeposited(vaultInfo.id, _amount, _token, true);
108: emit Deposit(_token, _amount);
109: }
[89-109]
File: core/solidity/contracts/core/WUSDA.sol
// @audit missing checks on line 215
214: function _deposit(address _from, address _to, uint256 _usdaAmount, uint256 _wusdaAmount) private {
215: IERC20(USDA).safeTransferFrom(_from, address(this), _usdaAmount);
216: _mint(_to, _wusdaAmount);
217:
218: emit Deposit(_from, _to, _usdaAmount, _wusdaAmount);
219: }
[214-219]
- Consider comparing before and after balance to get the actual transferred amount.
- Alternatively, disallow tokens with fee-on-transfer mechanics to be added as valid tokens.
Not all ERC20
implementations are totally compliant, and some (e.g LEND
) may fail while transfering a zero amount.
There is 1 instance of this issue.
File: core/solidity/contracts/core/AMPHClaimer.sol
129: IERC20(_token).transfer(owner(), _amount);
[129]
Some IERC20
do not implement the standard properly, but they are still accepted by most code that accepts ERC20
tokens.
For example, USDT transfer
functions on L1 do not return booleans: when casted to IERC20
, their function signatures do not match, and therefore the calls made will revert.
There are 2 instances of this issue.
File: core/solidity/contracts/core/AMPHClaimer.sol
129: IERC20(_token).transfer(owner(), _amount);
[129]
File: core/solidity/contracts/core/Vault.sol
194: _rewardToken.transfer(_msgSender(), _earnedReward);
[194]
Use the OpenZeppelin SafeERC20 safeTransfer
/safeTransferFrom
functions instead of transfer
/safeTransfer
.
The owner
role has a single point of failure and onlyOwner
can use critical functions, posing a centralization issue. There is always a chance for owner
keys to be stolen, and in such a case, the attacker can cause serious damage to the project due to important functions.
There are 26 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
119: function changeVaultController(address _newVaultController) external override onlyOwner {
128: function recoverDust(address _token, uint256 _amount) external override onlyOwner {
136: function changeCvxRewardFee(uint256 _newFee) external override onlyOwner {
144: function changeCrvRewardFee(uint256 _newFee) external override onlyOwner {
File: core/solidity/contracts/core/USDA.sol
63: function setPauser(address _pauser) external override onlyOwner {
161: function mint(uint256 _susdAmount) external override paysInterest onlyOwner {
182: function burn(uint256 _susdAmount) external override paysInterest onlyOwner {
212: function recoverDust(address _to) external onlyOwner {
278: function addVaultController(address _vaultController) external onlyOwner {
287: function removeVaultController(address _vaultController) external onlyOwner {
297: function removeVaultControllerFromList(address _vaultController) external onlyOwner {
[63, 161, 182, 212, 278, 287, 297]
File: core/solidity/contracts/core/VaultController.sol
305: function registerUSDA(address _usdaAddress) external override onlyOwner {
312: function registerCurveMaster(address _masterCurveAddress) external override onlyOwner {
319: function changeProtocolFee(uint192 _newProtocolFee) external override onlyOwner {
331: function registerErc20(
383: function updateRegisteredErc20(
416: function changeClaimerContract(IAMPHClaimer _newClaimerContract) external override onlyOwner {
425: function changeInitialBorrowingFee(uint192 _newBorrowingFee) external override onlyOwner {
435: function changeLiquidationFee(uint192 _newLiquidationFee) external override onlyOwner {
[305, 312, 319, 331, 383, 416, 425, 435]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
20: function mint(address _dst, uint256 _rawAmount) public onlyOwner {
[20]
File: core/solidity/contracts/periphery/CurveMaster.sol
31: function setVaultController(address _vaultMasterAddress) external override onlyOwner {
41: function setCurve(address _tokenAddress, address _curveAddress) external override onlyOwner {
52: function forceSetCurve(address _tokenAddress, address _curveAddress) external override onlyOwner {
File: core/solidity/contracts/utils/UFragments.sol
111: function setMonetaryPolicy(address _monetaryPolicy) external onlyOwner {
[111]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
57: function changeAnchoredView(address _anchoredViewUnderlying) external onlyOwner {
[57]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
65: function setStalePriceDelay(uint256 _stalePriceDelay) external onlyOwner {
[65]
The condition may be wrong in these cases, as when block.timestamp
is equal to the compared >
or <
variable these blocks will not be executed.
There are 2 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
560: return (whitelistAccountExpirations[_account] > block.timestamp);
[560]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
59: if (block.timestamp > _updatedAt + stalePriceDelay) _stale = true;
[59]
The following functions don't apply the CEI pattern. It's possible to reenter after the transfer if the token has some kind of callback functionality (e.g. ERC777/ERC1155).
There are 2 instances of this issue.
File: core/solidity/contracts/core/Vault.sol
// @audit state update on line 93
92: SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(_token), _msgSender(), address(this), _amount);
// @audit state update on line 286
285: SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_token), _to, _amount);
The built-in EVM precompile ecrecover
is susceptible to signature malleability, which could lead to replay attacks.
Consider using OpenZeppelin’s ECDSA library instead of the built-in function.
There are 2 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
517: address _signatory = ecrecover(_digest, _v, _r, _s);
[517]
File: core/solidity/contracts/utils/UFragments.sol
333: require(_owner == ecrecover(_digest, _v, _r, _s));
[333]
The project contracts in scope are using low level calls with solidity version before 0.8.14 which can result in an optimizer bug.
This bug causes the optimizer to consider some memory operations in inline assembly as being 'dead' and remove them.
Later operations that would read the values written by these improperly removed memory operations will instead observe the old version of memory.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
166: assembly {
[166]
There are some missing checks in these functions, and this could lead to unexpected scenarios. Consider always adding a sanity check for state variables.
There are 9 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
// @audit _cvxRewardFee, _crvRewardFee
53: constructor(
54: address _vaultController,
55: IERC20 _amph,
56: IERC20 _cvx,
57: IERC20 _crv,
58: uint256 _cvxRewardFee,
59: uint256 _crvRewardFee
[53-59]
File: core/solidity/contracts/core/Vault.sol
// @audit _id
66: constructor(uint96 _id, address _minter, address _controllerAddress, IERC20 _cvx, IERC20 _crv) {
[66]
File: core/solidity/contracts/core/VaultController.sol
// @audit _initialBorrowingFee, _liquidationFee
93: constructor(
94: IVaultController _oldVaultController,
95: address[] memory _tokenAddresses,
96: IAMPHClaimer _claimerContract,
97: IVaultDeployer _vaultDeployer,
98: uint192 _initialBorrowingFee,
99: address _booster,
100: uint192 _liquidationFee
[93-100]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
// @audit _initialSupply
9: constructor(
10: address _account,
11: uint256 _initialSupply
[9-11]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
// @audit _r0, _r1, _r2, _s1, _s2
33: constructor(int256 _r0, int256 _r1, int256 _r2, int256 _s1, int256 _s2) {
[33]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
// @audit _widthNumerator, _widthDenominator, _staleWidthNumerator, _staleWidthDenominator
36: constructor(
37: address _anchorAddress,
38: address _mainAddress,
39: uint256 _widthNumerator,
40: uint256 _widthDenominator,
41: uint256 _staleWidthNumerator,
42: uint256 _staleWidthDenominator
[36-42]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit _mul, _div, _stalePriceDelay
33: constructor(
34: address _underlying,
35: address _feedAddress,
36: uint256 _mul,
37: uint256 _div,
38: uint256 _stalePriceDelay
[33-38]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
// @audit _lookback
41: constructor(uint32 _lookback, address _poolAddress, bool _quoteTokenIsToken0) OracleRelay(OracleType.Uniswap) {
[41]
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
// @audit _lookback
19: constructor(
20: UniswapV3OracleRelay _ethOracle,
21: uint32 _lookback,
22: address _poolAddress,
23: bool _quoteTokenIsToken0
[19-23]
This bug was introduced in Solidity version 0.8.13, and it was fixed in version 0.8.17. This bug is significantly easier to trigger with optimized via-IR code generation, but can theoretically also occur in optimized legacy code generation.. More info can be read in this post.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
166: assembly {
[166]
Even if the function follows the best practice of check-effects-interaction, not using a reentrancy guard when there may be transfer hooks will open the users of this protocol up to read-only reentrancies with no way to protect against it, except by block-listing the whole protocol.
There are 5 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
129: IERC20(_token).transfer(owner(), _amount);
[129]
File: core/solidity/contracts/core/Vault.sol
92: SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(_token), _msgSender(), address(this), _amount);
129: SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_tokenAddress), _msgSender(), _amount);
194: _rewardToken.transfer(_msgSender(), _earnedReward);
285: SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_token), _to, _amount);
The name
, symbol
, and decimals
are not part of the IERC20
interface, and they may revert with some tokens if the don't also extend the IERC20Metadata
interface.
Even if these addresses are safe and known, consider refactoring the typing to IERC20Metadata
nonetheless to represent this fact.
There are 4 instances of this issue.
File: core/solidity/contracts/core/VaultController.sol
// @audit IERC20Metadata(_tokenAddress).decimals()
341: uint8 _tokenDecimals = IERC20Metadata(_tokenAddress).decimals();
[341]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
// @audit IERC20Metadata(cToken.underlying()).decimals()
25: uint256 _underlyingDecimals = cETH_ADDRESS == _cToken ? 18 : IERC20Metadata(cToken.underlying()).decimals();
[25]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
// @audit IERC20Metadata(BASE_TOKEN).decimals()
50: BASE_TOKEN_DECIMALS = IERC20Metadata(BASE_TOKEN).decimals();
// @audit IERC20Metadata(QUOTE_TOKEN).decimals()
51: QUOTE_TOKEN_DECIMALS = IERC20Metadata(QUOTE_TOKEN).decimals();
Some IERC20
implementations (e.g UNI
, COMP
) may fail if the valued transferred is larger than uint96
. Source
There are 4 instances of this issue.
File: core/solidity/contracts/core/AMPHClaimer.sol
129: IERC20(_token).transfer(owner(), _amount);
[129]
File: core/solidity/contracts/core/Vault.sol
129: SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_tokenAddress), _msgSender(), _amount);
194: _rewardToken.transfer(_msgSender(), _earnedReward);
285: SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_token), _to, _amount);
Not all IERC20
implementations are totally compliant, and some (e.g UNI
, COMP
) may fail if the valued passed is larger than uint96
. Source
There is 1 instance of this issue.
File: core/solidity/contracts/core/Vault.sol
321: IERC20(_token).approve(address(_booster), _amount);
[321]
Some tokens like USDT check for the current approval, and they revert if it's not zero. While Tether is known to do this, it applies to other tokens as well, which are trying to protect against this attack vector.
There is 1 instance of this issue.
File: core/solidity/contracts/core/Vault.sol
321: IERC20(_token).approve(address(_booster), _amount);
[321]
Consider always calling token.safeApprove(addr, 0)
before changing the approval, or better yet, use safeIncreaseAllowance
/safeDecreaseAllowance
.
Not all IERC20
implementations revert
when there's a failure in approve
. The function signature has a boolean return value and they indicate errors that way instead.
By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything.
There is 1 instance of this issue.
File: core/solidity/contracts/core/Vault.sol
321: IERC20(_token).approve(address(_booster), _amount);
[321]
Users should always have the possibility of accessing their own funds, but when these functions are paused, their funds will be locked until the contracts are unpaused.
There is 1 instance of this issue.
File: core/solidity/contracts/core/USDA.sol
147: function _withdraw(uint256 _susdAmount, address _target) internal paysInterest whenNotPaused {
[147]
When a type is downcast to a smaller type, the higher order bits are discarded, resulting in the application of a modulo operation to the original value.
If the downcasted value is large enough, this may result in an overflow that will not revert.
There are 3 instances of this issue.
File: core/solidity/contracts/core/VaultController.sol
// @audit uint256 _collateralLiquidated downcasted to uint192
637: _collateralLiquidated -= getLiquidationFee(uint192(_collateralLiquidated), _assetAddress);
// @audit uint256 _tokensToLiquidate downcasted to uint192
681: uint192 _liquidationFee = getLiquidationFee(uint192(_tokensToLiquidate), _assetAddress);
// @audit uint256 _ui18 downcasted to int256
937: int256 _reserveRatio = int256(_ui18);
These functions might be a problem if the logic changes before the contract is deployed, as the developer must remember to syncronize the logic between all the function instances.
Consider using a single function instead of duplicating the code, for example by using a library
, or through inheritance.
There are 10 instances of this issue.
Expand findings
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CTokenOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/WstEthOracle.sol -> peekValue
42: function peekValue() public view override returns (uint256 _price) {
[42]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol -> peekValue
40: function peekValue() public view override returns (uint256 _value) {
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol -> currentValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> currentValue
46: function currentValue() external override returns (uint256 _currentValue) {
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CTokenOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/WstEthOracle.sol -> peekValue
34: function peekValue() public view override returns (uint256 _price) {
[34]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CTokenOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/WstEthOracle.sol -> peekValue
22: function peekValue() public view override returns (uint256 _price) {
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol -> currentValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> currentValue
28: function currentValue() external override returns (uint256 _currentValue) {
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CTokenOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/WstEthOracle.sol -> peekValue
36: function peekValue() public view virtual override returns (uint256 _price) {
[36]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol -> peekValue
44: function peekValue() public view override returns (uint256 _value) {
[44]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CTokenOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/WstEthOracle.sol -> peekValue
60: function peekValue() public view virtual override returns (uint256 _price) {
[60]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
// @audit duplicated logic in core/solidity/contracts/periphery/oracles/CTokenOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol -> peekValue, core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol -> peekValue, core/solidity/contracts/periphery/oracles/WstEthOracle.sol -> peekValue
23: function peekValue() public view override returns (uint256 _price) {
[23]
These functions can be called with 0 value in the input and this value is not checked for being bigger than 0, that means in some scenarios this can potentially trigger a division by zero.
There are 2 instances of this issue.
File: core/solidity/contracts/core/WUSDA.sol
// @audit _totalUsdaSupply
247: _wusdaAmount = (_usdaAmount * MAX_wUSDA_SUPPLY) / _totalUsdaSupply;
[247]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
// @audit _run
83: int256 _mE6 = (_rise * 1e6) / _run;
[83]
Consider removing the casting to extend the lifespan of these contracts.
There are 4 instances of this issue.
File: core/solidity/contracts/core/VaultController.sol
103: interest = Interest(uint64(block.timestamp), 1 ether);
930: uint64 _timeDifference = uint64(block.timestamp) - interest.lastTime;
957: interest = Interest(uint64(block.timestamp), interest.factor + _e18FactorIncrease);
970: emit InterestEvent(uint64(block.timestamp), _e18FactorIncrease, _curveVal);
A draft status means that the EIPs they're based on are not finalized, and thus there may be breaking changes in even minor releases. Consider using a stable version for these libraries instead of a draft.
There is 1 instance of this issue.
File: core/solidity/contracts/core/WUSDA.sol
9: import {ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol';
[9]
There are some missing limits in these functions, and this could lead to unexpected scenarios. Consider adding a min/max limit for the following values, when appropriate.
There are 14 instances of this issue.
Expand findings
File: core/solidity/contracts/core/VaultController.sol
// @audit missing both checks -> _liquidationIncentive, _cap, _poolId
// @audit missing min check -> _ltv
383: function updateRegisteredErc20(
384: address _tokenAddress,
385: uint256 _ltv,
386: address _oracleAddress,
387: uint256 _liquidationIncentive,
388: uint256 _cap,
389: uint256 _poolId
[383-389]
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit missing both checks -> _second
575: function setMaxWhitelistPeriod(uint256 _second) external onlyGov {
// @audit missing both checks -> _proposalTimelockDelay
583: function setDelay(uint256 _proposalTimelockDelay) public override onlyGov {
// @audit missing both checks -> _emergencyTimelockDelay
594: function setEmergencyDelay(uint256 _emergencyTimelockDelay) public override onlyGov {
// @audit missing both checks -> _newVotingDelay
605: function setVotingDelay(uint256 _newVotingDelay) external override onlyGov {
// @audit missing both checks -> _newVotingPeriod
616: function setVotingPeriod(uint256 _newVotingPeriod) external override onlyGov {
// @audit missing both checks -> _newEmergencyVotingPeriod
627: function setEmergencyVotingPeriod(uint256 _newEmergencyVotingPeriod) external override onlyGov {
// @audit missing both checks -> _newProposalThreshold
638: function setProposalThreshold(uint256 _newProposalThreshold) external override onlyGov {
// @audit missing both checks -> _newQuorumVotes
649: function setQuorumVotes(uint256 _newQuorumVotes) external override onlyGov {
// @audit missing both checks -> _newEmergencyQuorumVotes
660: function setEmergencyQuorumVotes(uint256 _newEmergencyQuorumVotes) external override onlyGov {
// @audit missing min check -> _expiration
673: function setWhitelistAccountExpiration(address _account, uint256 _expiration) external override onlyGov {
// @audit missing both checks -> _newOptimisticVotingDelay
695: function setOptimisticDelay(uint256 _newOptimisticVotingDelay) external override onlyGov {
// @audit missing both checks -> _newOptimisticQuorumVotes
706: function setOptimisticQuorumVotes(uint256 _newOptimisticQuorumVotes) external override onlyGov {
[575, 583, 594, 605, 616, 627, 638, 649, 660, 673, 695, 706]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit missing both checks -> _stalePriceDelay
65: function setStalePriceDelay(uint256 _stalePriceDelay) external onlyOwner {
[65]
It is good to add a require
statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer
/safeTransferFrom
unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
There are 8 instances of this issue.
File: core/solidity/contracts/core/USDA.sol
103: sUSD.transferFrom(_msgSender(), address(this), _susdAmount);
153: sUSD.transfer(_target, _susdAmount);
206: sUSD.transferFrom(_msgSender(), address(this), _susdAmount);
216: sUSD.transfer(_to, _amount);
246: sUSD.transfer(_target, _susdAmount);
File: core/solidity/contracts/core/Vault.sol
194: _rewardToken.transfer(_msgSender(), _earnedReward);
223: if (_totalCvxReward > 0) CVX.transfer(_msgSender(), _totalCvxReward);
224: if (_totalCrvReward > 0) CRV.transfer(_msgSender(), _totalCrvReward);
The contract owner is not prevented from renouncing the ownership while the contract is paused, which would cause any user assets stored in the protocol to be locked indefinitely.
There is 1 instance of this issue.
File: core/solidity/contracts/core/USDA.sol
63: function setPauser(address _pauser) external override onlyOwner {
[63]
Low-level calls return success if there is no code present at the specified address, and this could lead to unexpected scenarios.
Ensure that the code is initialized by checking <address>.code.length > 0
.
There is 1 instance of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
350: (bool _success, /*bytes memory returnData*/ ) = _target.call{value: _value}(_callData);
[350]
Consider limiting the number of iterations in loops that make external calls, as just a single one of them failing will result in a revert.
There are 10 instances of this issue.
File: core/solidity/contracts/core/Vault.sol
// @audit tokenCollateralInfo (170), tokenId (171), collateralType (172), CurveLPStakedOnConvex (172), CollateralType (172), crvRewardsContract (176), earned (177), getReward (182), extraRewardsLength (187), extraRewards (189), rewardToken (190), earned (191), getReward (193), transfer (194)
169: for (uint256 _i; _i < _tokenAddresses.length;) {
// @audit extraRewards (255), rewardToken (256), earned (257)
254: for (_i; _i < _rewardsAmount;) {
File: core/solidity/contracts/core/VaultController.sol
// @audit tokenId (256), tokenCollateralInfo (260), tokenId (261), totalDeposited (262)
255: for (uint256 _i; _i < _tokenAddresses.length;) {
// @audit ltv (871), balances (876), currentValue (879), oracle (879), ltv (883), decimals (883)
868: for (uint192 _i; _i < enabledTokens.length; ++_i) {
// @audit ltv (899), balances (904), peekValue (907), oracle (907), ltv (911), decimals (911)
896: for (uint192 _i; _i < enabledTokens.length; ++_i) {
// @audit balances (999), vaultLiability (1006)
994: for (uint96 _i = _start; _i <= _stop;) {
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit targets (259), targets (263), values (263), signatures (263), calldatas (263), targets (268), values (269), signatures (270), calldatas (271), delay (273)
259: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
// @audit targets (313), executeTransaction (314), values (314), targets (315), values (315), signatures (315), calldatas (315), eta (315)
313: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
// @audit targets (382), targets (384), values (384), signatures (384), calldatas (384), eta (384)
382: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
// @audit min (45), peekValue (45)
44: for (uint256 _i = 1; _i < anchoredUnderlyingTokens.length;) {
[44]
In Solidity 0.8.20
's compiler, the default target EVM version has been changed to Shanghai. This version introduces a new op code called PUSH0
.
However, not all Layer 2 solutions have implemented this op code yet, leading to deployment failures on these chains. To overcome this problem, it is recommended to utilize an earlier EVM version.
There are 43 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/USDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/Vault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultDeployer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/WUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/GovernorCharlie.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/contracts/periphery/CurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/GovernanceStructs.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/UFragments.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/interfaces/core/IAMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IWUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAMPH.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IAnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveAddressesProvider.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBooster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurvePool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurveSlave.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
Add a two-step process for any critical address changes.
There are 5 instances of this issue.
Expand findings
File: core/solidity/contracts/core/USDA.sol
63: function setPauser(address _pauser) external override onlyOwner {
64: pauser = _pauser;
65:
66: emit PauserSet(_pauser);
67: }
[63-67]
File: core/solidity/contracts/core/VaultController.sol
383: function updateRegisteredErc20(
384: address _tokenAddress,
385: uint256 _ltv,
386: address _oracleAddress,
387: uint256 _liquidationIncentive,
388: uint256 _cap,
389: uint256 _poolId
390: ) external override onlyOwner {
391: CollateralInfo storage _collateral = tokenAddressCollateralInfo[_tokenAddress];
392: if (_collateral.tokenId == 0) revert VaultController_TokenNotRegistered();
393: // _ltv must be compatible with liquidation incentive
394: if (_ltv >= (EXP_SCALE - _liquidationIncentive)) revert VaultController_LTVIncompatible();
395: if (_poolId != 0) {
396: (address _lpToken,,, address _crvRewards,,) = BOOSTER.poolInfo(_poolId);
397: if (_lpToken != _tokenAddress) revert VaultController_TokenAddressDoesNotMatchLpAddress();
398: _collateral.collateralType = CollateralType.CurveLPStakedOnConvex;
399: _collateral.crvRewardsContract = IBaseRewardPool(_crvRewards);
400: _collateral.poolId = _poolId;
401: }
402: // set the oracle of the token
403: _collateral.oracle = IOracleRelay(_oracleAddress);
404: // set the ltv of the token
405: _collateral.ltv = _ltv;
406: // set the liquidation incentive of the token
407: _collateral.liquidationIncentive = _liquidationIncentive;
408: // set the cap
409: _collateral.cap = _cap;
410:
411: emit UpdateRegisteredErc20(_tokenAddress, _ltv, _oracleAddress, _liquidationIncentive, _cap, _poolId);
412: }
[383-412]
File: core/solidity/contracts/periphery/CurveMaster.sol
31: function setVaultController(address _vaultMasterAddress) external override onlyOwner {
32: address _oldCurveAddress = vaultControllerAddress;
33: vaultControllerAddress = _vaultMasterAddress;
34:
35: emit VaultControllerSet(_oldCurveAddress, _vaultMasterAddress);
36: }
41: function setCurve(address _tokenAddress, address _curveAddress) external override onlyOwner {
42: if (vaultControllerAddress != address(0)) IVaultController(vaultControllerAddress).calculateInterest();
43: address _oldCurve = curves[_tokenAddress];
44: curves[_tokenAddress] = _curveAddress;
45:
46: emit CurveSet(_oldCurve, _tokenAddress, _curveAddress);
47: }
File: core/solidity/contracts/utils/UFragments.sol
111: function setMonetaryPolicy(address _monetaryPolicy) external onlyOwner {
112: monetaryPolicy = _monetaryPolicy;
113: emit LogMonetaryPolicyUpdated(_monetaryPolicy);
114: }
[111-114]
A single step ownership change is risky due to the fact that the new owner address could be wrong.
Instead, consider using a contract like Ownable2Step, which provides a two-step ownership.
There are 7 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[6]
File: core/solidity/contracts/core/VaultController.sol
17: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[17]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[5]
File: core/solidity/contracts/periphery/CurveMaster.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/utils/UFragments.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[5]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[6]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
abi.encodePacked
should not be used with dynamic types when passing the result to a hash function such as keccak256
. Use abi.encode
instead, which will pad items to 32 bytes, to prevent any hash collisions.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
328: bytes32 _digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR(), _permitDataDigest));
[328]
Solidity doesn't support fractions, so division by large numbers could result in the quotient being zero.
To avoid this, it's recommended to require a minimum numerator amount to ensure that it is always greater than the denominator.
There are 27 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
153: _amount = (_total * _fraction) / _BASE;
195: uint256 _foo = (_TWENTY_FIVE_THOUSANDS * BASE_SUPPLY_PER_CLIFF) / Math.max(_distributedAmph, _FIFTY_MILLIONS);
196: uint256 _bar = (_distributedAmph * 1e12) / (BASE_SUPPLY_PER_CLIFF * _FIFTY);
232: uint256 _amountTokenToEnter = (_amphAvailableForThisCliff * 1e18) / _rate;
250: _cliff = _distributedAmph / BASE_SUPPLY_PER_CLIFF;
File: core/solidity/contracts/core/USDA.sol
262: _gonsPerFragment = _totalGons / _totalSupply;
269: _e18reserveRatio = _safeu192((reserveAmount * EXP_SCALE) / _totalSupply);
File: core/solidity/contracts/core/Vault.sol
337: uint256 _cliff = _supply / CVX.reductionPerCliff();
343: _cvxAmount = (_crv * _reduction) / _totalCliffs;
File: core/solidity/contracts/core/VaultController.sol
535: uint192 _baseAmount = _safeu192(uint256((_amount + _fee) * EXP_SCALE) / uint256(interest.factor));
597: _baseAmount = _safeu192((_amountInUSDA * EXP_SCALE) / interest.factor);
667: _vault.modifyLiability(false, (_usdaToRepurchase * 1e18) / interest.factor);
670: totalBaseLiability -= _safeu192((_usdaToRepurchase * 1e18) / interest.factor);
790: uint256 _maxTokensToLiquidate = (_usdaToSolvency * 1e18) / _denominator;
948: _truncate((uint256(_timeDifference) * uint256(1e18) * uint256(_curveVal)) / (365 days + 6 hours))
[535, 597, 667, 670, 790, 948]
File: core/solidity/contracts/core/WUSDA.sol
247: _wusdaAmount = (_usdaAmount * MAX_wUSDA_SUPPLY) / _totalUsdaSupply;
255: _usdaAmount = (_wusdaAmount * _totalUsdaSupply) / MAX_wUSDA_SUPPLY;
File: core/solidity/contracts/utils/ThreeLines0_100.sol
83: int256 _mE6 = (_rise * 1e6) / _run;
[83]
File: core/solidity/contracts/utils/UFragments.sol
104: _gonsPerFragment = _totalGons / _totalSupply;
129: return _gonBalances[_who] / _gonsPerFragment;
196: uint256 _value = _gonValue / _gonsPerFragment;
245: uint256 _value = _gonValue / _gonsPerFragment;
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
85: _buffer = (staleWidthNumerator * _anchorPrice) / staleWidthDenominator;
87: _buffer = (widthNumerator * _anchorPrice) / widthDenominator;
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
52: _value = (_currentValue * _exchangeRate) / div;
[52]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
75: _value = (uint256(_latest) * MULTIPLY) / DIVIDE;
[75]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
85: _e18Amount = (_decimals > 18) ? _amount / (10 ** (_decimals - 18)) : _amount * (10 ** (18 - _decimals));
[85]
A low-level call will copy any amount of bytes to local memory. When bytes are copied from returndata to memory, the memory expansion cost is paid.
This means that when using a standard solidity call, the callee can 'returnbomb' the caller, imposing an arbitrary gas cost.
Because this gas is paid by the caller and in the caller's context, it can cause the caller to run out of gas and halt execution.
Consider replacing all unsafe call
with excessivelySafeCall
from this repository.
There is 1 instance of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
350: (bool _success, /*bytes memory returnData*/ ) = _target.call{value: _value}(_callData);
[350]
The owner
is able to perform certain privileged activities, but it's possible to set the owner to address(0)
. This can represent a certain risk if the ownership is renounced for any other reason than by design.
Renouncing ownership will leave the contract without an owner
, therefore limiting any functionality that needs authority.
There are 19 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
119: function changeVaultController(address _newVaultController) external override onlyOwner {
128: function recoverDust(address _token, uint256 _amount) external override onlyOwner {
136: function changeCvxRewardFee(uint256 _newFee) external override onlyOwner {
144: function changeCrvRewardFee(uint256 _newFee) external override onlyOwner {
File: core/solidity/contracts/core/VaultController.sol
305: function registerUSDA(address _usdaAddress) external override onlyOwner {
312: function registerCurveMaster(address _masterCurveAddress) external override onlyOwner {
319: function changeProtocolFee(uint192 _newProtocolFee) external override onlyOwner {
338: ) external override onlyOwner {
390: ) external override onlyOwner {
416: function changeClaimerContract(IAMPHClaimer _newClaimerContract) external override onlyOwner {
425: function changeInitialBorrowingFee(uint192 _newBorrowingFee) external override onlyOwner {
435: function changeLiquidationFee(uint192 _newLiquidationFee) external override onlyOwner {
[305, 312, 319, 338, 390, 416, 425, 435]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
20: function mint(address _dst, uint256 _rawAmount) public onlyOwner {
[20]
File: core/solidity/contracts/periphery/CurveMaster.sol
31: function setVaultController(address _vaultMasterAddress) external override onlyOwner {
41: function setCurve(address _tokenAddress, address _curveAddress) external override onlyOwner {
52: function forceSetCurve(address _tokenAddress, address _curveAddress) external override onlyOwner {
File: core/solidity/contracts/utils/UFragments.sol
111: function setMonetaryPolicy(address _monetaryPolicy) external onlyOwner {
[111]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
57: function changeAnchoredView(address _anchoredViewUnderlying) external onlyOwner {
[57]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
65: function setStalePriceDelay(uint256 _stalePriceDelay) external onlyOwner {
[65]
This project is using a vulnerable version of some libraries, which have the following issues:
Current @openzeppelin/contracts
version: 4.8.2
Risk | Title | Min Version | Max Version |
---|---|---|---|
LOW | Denial of Service (DoS) | >=3.2.0 | <4.8.3 |
MEDIUM | Improper Input Validation | >=3.3.0 | <4.8.3 |
There are 40 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
4: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
7: import {SafeERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
File: core/solidity/contracts/core/USDA.sol
11: import {IERC20Metadata, IERC20} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
12: import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
13: import {Context} from '@openzeppelin/contracts/utils/Context.sol';
14: import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
File: core/solidity/contracts/core/Vault.sol
12: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
13: import {Context} from '@openzeppelin/contracts/utils/Context.sol';
14: import {SafeERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol';
15: import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol';
File: core/solidity/contracts/core/VaultController.sol
16: import {IERC20, IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
17: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
18: import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
File: core/solidity/contracts/core/VaultDeployer.sol
7: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[7]
File: core/solidity/contracts/core/WUSDA.sol
6: import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
7: import {ERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
9: import {ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol';
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
6: import {ERC20, ERC20Permit, ERC20VotesComp} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol';
File: core/solidity/contracts/periphery/CurveMaster.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/utils/UFragments.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
6: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/interfaces/core/IAMPHClaimer.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/core/IUSDA.sol
6: import {IERC20Metadata, IERC20} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
[6]
File: core/solidity/interfaces/core/IVault.sol
5: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[5]
File: core/solidity/interfaces/core/IVaultDeployer.sol
6: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[6]
File: core/solidity/interfaces/core/IWUSDA.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/ICVX.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/ICurvePool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IRoles.sol
4: import {IAccessControl} from '@openzeppelin/contracts/access/IAccessControl.sol';
[4]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IWStETH.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
7: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
6: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
[6]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
6: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
[6]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
7: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
[7]
Consider upgrading all the impacted libraries to a newer version.
Check for zero-address to avoid the risk of setting address(0)
for state variables when deploying.
There are 23 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
61: vaultController = IVaultController(_vaultController);
62: CVX = _cvx;
63: CRV = _crv;
64: AMPH = _amph;
File: core/solidity/contracts/core/USDA.sol
58: sUSD = _sUSDAddr;
[58]
File: core/solidity/contracts/core/Vault.sol
68: CONTROLLER = IVaultController(_controllerAddress);
70: CRV = _crv;
File: core/solidity/contracts/core/VaultController.sol
110: BOOSTER = IBooster(_booster);
[110]
File: core/solidity/contracts/core/VaultDeployer.sol
19: CVX = _cvx;
20: CRV = _crv;
File: core/solidity/contracts/core/WUSDA.sol
49: USDA = _usdaToken;
[49]
File: core/solidity/contracts/governance/GovernorCharlie.sol
89: amph = IAMPH(_amph);
[89]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
44: anchorRelay = IOracleRelay(_anchorAddress);
46: mainRelay = IOracleRelay(_mainAddress);
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
21: cToken = ICToken(_cToken);
22: anchoredViewUnderlying = _anchoredViewUnderlying;
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
29: CB_ETH_POOL = IV2Pool(_cbETHPool);
[29]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
40: _AGGREGATOR = AggregatorV2V3Interface(_feedAddress);
[40]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
24: AGGREGATOR = ChainlinkOracleRelay(_feedAddress);
25: BASE_AGGREGATOR = ChainlinkOracleRelay(_baseFeedAddress);
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
21: CRV_POOL = IStablePool(_crvPool);
[21]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
32: TRI_CRYPTO = IV2Pool(_triCryptoPool);
[32]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
44: POOL = IUniswapV3Pool(_poolAddress);
[44]
Check for zero-address to avoid the risk of setting address(0)
for state variables after an update.
There are 10 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
120: vaultController = IVaultController(_newVaultController);
[120]
File: core/solidity/contracts/core/USDA.sol
64: pauser = _pauser;
[64]
File: core/solidity/contracts/core/VaultController.sol
306: usda = IUSDA(_usdaAddress);
313: curveMaster = CurveMaster(_masterCurveAddress);
File: core/solidity/contracts/governance/GovernorCharlie.sol
568: amph = IAMPH(_token);
686: whitelistGuardian = _account;
File: core/solidity/contracts/periphery/CurveMaster.sol
33: vaultControllerAddress = _vaultMasterAddress;
[33]
File: core/solidity/contracts/utils/UFragments.sol
112: monetaryPolicy = _monetaryPolicy;
[112]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
58: anchoredViewUnderlying = IOracleRelay(_anchoredViewUnderlying);
[58]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
20: underlying = _underlying;
[20]
Locking the pragma helps avoid accidental deploys with an outdated compiler version that may introduce bugs and unexpected vulnerabilities.
Floating pragma is meant to be used for libraries and contracts that have external users and need backward compatibility.
There are 42 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/USDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/Vault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultDeployer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/WUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/GovernorCharlie.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/contracts/periphery/CurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/GovernanceStructs.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/UFragments.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/interfaces/core/IAMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IWUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAMPH.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IAnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveAddressesProvider.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBooster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurvePool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurveSlave.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
There are some arrays that can grow indefinitely in size, as they never shrink: this can lead to inefficient memory management and increase the likelihood of out-of-gas errors.
There is 1 instance of this issue.
File: core/solidity/contracts/core/VaultController.sol
264: enabledTokens.push(_tokenAddresses[_i]);
[264]
Events should be emitted when sensitive changes are made to the contracts, but some functions lack them.
There are 6 instances of this issue.
Expand findings
File: core/solidity/contracts/governance/GovernorCharlie.sol
567: function setNewToken(address _token) external onlyGov {
568: amph = IAMPH(_token);
569: }
575: function setMaxWhitelistPeriod(uint256 _second) external onlyGov {
576: maxWhitelistPeriod = _second;
577: }
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
70: function _updateVirtualPrice() internal {
71: uint256 _virtualPrice = CB_ETH_POOL.get_virtual_price();
72:
73: // We remove claim admin fees on the curve pool locked to avoid any manipulation
74: CB_ETH_POOL.claim_admin_fees();
75:
76: virtualPrice = _virtualPrice;
77: }
[70-77]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
65: function setStalePriceDelay(uint256 _stalePriceDelay) external onlyOwner {
66: if (_stalePriceDelay == 0) revert ChainlinkOracle_ZeroAmount();
67: stalePriceDelay = _stalePriceDelay;
68: }
[65]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
36: function _updateVirtualPrice() internal {
37: uint256 _virtualPrice = CRV_POOL.get_virtual_price();
38:
39: // We remove 0 liquidity to check the curve pool lock and avoid any manipulation
40: uint256[2] memory _amounts;
41: CRV_POOL.remove_liquidity(0, _amounts);
42:
43: virtualPrice = _virtualPrice;
44: }
[36-44]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
19: function _setUnderlying(address _underlying) internal {
20: underlying = _underlying;
21: }
[19-21]
Declaring named returns, but not using them, is confusing to the reader. Consider either completely removing them (by declaring just the type without a name), or remove the return statement and do a variable assignment.
This would improve the readability of the code, and it may also help reduce regressions during future code refactors.
There are 19 instances of this issue.
Expand findings
File: core/solidity/contracts/core/VaultController.sol
866: function _getVaultBorrowingPower(IVault _vault) private returns (uint192 _borrowPower) {
894: function _peekVaultBorrowingPower(IVault _vault) private view returns (uint192 _borrowPower) {
File: core/solidity/contracts/governance/GovernorCharlie.sol
424: address[] memory _targets,
431: return (_proposal.targets, _proposal.values, _proposal.signatures, _proposal.calldatas);
559: function isWhitelisted(address _account) public view override returns (bool _isWhitelisted) {
560: return (whitelistAccountExpirations[_account] > block.timestamp);
File: core/solidity/contracts/utils/ThreeLines0_100.sol
47: function valueAt(int256 _xValue) external view override returns (int256 _value) {
57: return _linearInterpolation(_rise, _run, _xValue, R0);
63: return _linearInterpolation(_rise, _run, _xValue - S1, R1);
67: return R2;
[47]
File: core/solidity/contracts/utils/UFragments.sol
120: function totalSupply() external view override returns (uint256 __totalSupply) {
121: return _totalSupply;
128: function balanceOf(address _who) external view override returns (uint256 _balance) {
129: return _gonBalances[_who] / _gonsPerFragment;
136: function scaledBalanceOf(address _who) external view returns (uint256 _balance) {
137: return _gonBalances[_who];
144: function scaledTotalSupply() external view returns (uint256 __totalGons) {
145: return _totalGons;
153: function nonces(address _who) public view returns (uint256 _addressNonces) {
154: return _nonces[_who];
163: function DOMAIN_SEPARATOR() public view returns (bytes32 _domainSeparator) {
168: return keccak256(
169: abi.encode(EIP712_DOMAIN, keccak256(bytes(name)), keccak256(bytes(EIP712_REVISION)), _chainId, address(this))
170: );
179: function transfer(address _to, uint256 _value) external override validRecipient(_to) returns (bool _success) {
186: return true;
194: function transferAll(address _to) external validRecipient(_to) returns (bool _success) {
202: return true;
211: function allowance(address _owner, address _spender) external view override returns (uint256 _remaining) {
212: return _allowedFragments[_owner][_spender];
226: ) external override validRecipient(_to) returns (bool _success) {
234: return true;
243: function transferAllFrom(address _from, address _to) external validRecipient(_to) returns (bool _success) {
253: return true;
268: function approve(address _spender, uint256 _value) external override returns (bool _success) {
272: return true;
283: function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool _success) {
287: return true;
297: function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool _success) {
302: return true;
[120, 128, 136, 144, 153, 163, 179, 194, 211, 226, 243, 268, 283, 297]
The following errors are never used, consider to remove them.
There are 4 instances of this issue.
File: core/solidity/interfaces/core/IVaultController.sol
155: error VaultController_OracleNotRegistered();
[155]
File: core/solidity/interfaces/core/IVaultDeployer.sol
20: error VaultDeployer_OnlyVaultController();
[20]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
12: error TriCryptoOracle_ZeroAmount();
[12]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
14: error UniswapV3OracleRelay_TickTimeDiffTooLarge();
[14]
The following events are never used, consider to remove them.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
39: event LogRebase(uint256 indexed epoch, uint256 totalSupply);
[39]
The following modifier are never used, consider to remove them.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
51: modifier onlyMonetaryPolicy() {
52: require(msg.sender == monetaryPolicy);
53: _;
54: }
[51-54]
These contracts import some OpenZeppelin libraries, but they are using an old version.
There are 40 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
4: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
7: import {SafeERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
File: core/solidity/contracts/core/USDA.sol
11: import {IERC20Metadata, IERC20} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
12: import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
13: import {Context} from '@openzeppelin/contracts/utils/Context.sol';
14: import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
File: core/solidity/contracts/core/Vault.sol
12: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
13: import {Context} from '@openzeppelin/contracts/utils/Context.sol';
14: import {SafeERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol';
15: import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol';
File: core/solidity/contracts/core/VaultController.sol
16: import {IERC20, IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
17: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
18: import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
File: core/solidity/contracts/core/VaultDeployer.sol
7: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[7]
File: core/solidity/contracts/core/WUSDA.sol
6: import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
7: import {ERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
9: import {ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol';
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
6: import {ERC20, ERC20Permit, ERC20VotesComp} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol';
File: core/solidity/contracts/periphery/CurveMaster.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/utils/UFragments.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
6: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/interfaces/core/IAMPHClaimer.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/core/IUSDA.sol
6: import {IERC20Metadata, IERC20} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
[6]
File: core/solidity/interfaces/core/IVault.sol
5: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[5]
File: core/solidity/interfaces/core/IVaultDeployer.sol
6: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[6]
File: core/solidity/interfaces/core/IWUSDA.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/ICVX.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/ICurvePool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IRoles.sol
4: import {IAccessControl} from '@openzeppelin/contracts/access/IAccessControl.sol';
[4]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IWStETH.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
7: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
6: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
[6]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
6: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
[6]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
7: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
[7]
Consider upgrading from version 4.8.2
to at least version 4.9.0
.
If the intention is for the ETH to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth))
)
There is 1 instance of this issue.
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
54: fallback() external {}
[54]
Upgrade to at least solidity version 0.8.19 to get additional gas savings. Check the documentation for reference.
Some additional details:
In earlier releases and in the default legacy code generation, when an internal library function or a free function accessed via a module was called only during contract creation, e.g. only in the constructor, a copy of the function still also occurred in the contract’s runtime bytecode.
So a function pointer in creation code also refers to the offset of the function in runtime code, which requires the function to actually be present in runtime code.
For direct calls to internal contract functions the full encoding of the function expression is bypassed by the compiler. However, this bypassing did not happen for internal library functions and for free functions called via modules, causing the undesirable behaviour that is now fixed in this release.
There are 45 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/USDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/Vault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultDeployer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/WUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/GovernorCharlie.sol
3: pragma solidity ^0.8.9;
4: pragma experimental ABIEncoderV2;
File: core/solidity/contracts/periphery/CurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/GovernanceStructs.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/UFragments.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/interfaces/core/IAMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IWUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAMPH.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
3: pragma experimental ABIEncoderV2;
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IAnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveAddressesProvider.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBooster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurvePool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurveSlave.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
It's better to declare the hardcoded addresses as immutable
state variables, as this will facilitate deployment on other chains.
There are 8 instances of this issue.
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
// @audit 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5
12: address public constant cETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
// @audit 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5
12: address public constant cETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
// @audit 0x0000000022D53366457F9d5E68Ec105046FC4383
9: ICurveAddressesProvider(0x0000000022D53366457F9d5E68Ec105046FC4383);
// @audit 0x0000000022D53366457F9d5E68Ec105046FC4383
9: ICurveAddressesProvider(0x0000000022D53366457F9d5E68Ec105046FC4383);
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
// @audit 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
8: address public constant wETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
// @audit 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
8: address public constant wETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
// @audit 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
10: IWStETH public constant WSTETH = IWStETH(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0);
// @audit 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
10: IWStETH public constant WSTETH = IWStETH(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0);
Consider using an enum instead of hardcoding an index access to make the code easier to understand.
There are 5 instances of this issue.
File: core/solidity/contracts/core/Vault.sol
250: _rewards[0] = Reward(CRV, _crvReward);
251: _rewards[1] = Reward(CVX, _cvxReward);
275: _rewards[0].amount = _crvReward - _takenCRV;
276: if (_cvxReward > 0) _rewards[1].amount = _cvxReward - _takenCVX;
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
43: uint256 _minStable = anchoredUnderlyingTokens[0].peekValue();
[43]
It's not necessary to initialize a variable with its default value, and it's actually worse in gas terms as it adds an overhead.
There are 3 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
259: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
313: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
382: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
Some parts of the codebase use require
statements, while others use custom error
s. Consider refactoring the code to use the same approach: the following findings represent the minority of require
vs error
, and they show the first occurance in each file, for brevity.
There are 2 instances of this issue.
File: core/solidity/contracts/utils/UFragments.sol
52: require(msg.sender == monetaryPolicy);
[52]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
77: require(_mainValue > 0, 'invalid oracle value');
[77]
Consider limiting the number of iterations in loops with an explicit revert reason to improve the user experience.
The function would eventually revert if out of gas anyway, but by limiting it the user avoids wasting too much gas, as the loop doesn't execute if an excessive value is provided.
There are 14 instances of this issue.
Expand findings
File: core/solidity/contracts/core/Vault.sol
169: for (uint256 _i; _i < _tokenAddresses.length;) {
170: IVaultController.CollateralInfo memory _collateralInfo = CONTROLLER.tokenCollateralInfo(_tokenAddresses[_i]);
171: if (_collateralInfo.tokenId == 0) revert Vault_TokenNotRegistered();
172: if (_collateralInfo.collateralType != IVaultController.CollateralType.CurveLPStakedOnConvex) {
173: revert Vault_TokenNotCurveLP();
174: }
175:
176: IBaseRewardPool _rewardsContract = _collateralInfo.crvRewardsContract;
177: uint256 _crvReward = _rewardsContract.earned(address(this));
178:
179: if (_crvReward != 0) {
180: // Claim the CRV reward
181: _totalCrvReward += _crvReward;
182: _rewardsContract.getReward(address(this), false);
183: _totalCvxReward += _calculateCVXReward(_crvReward);
184: }
185:
186: // Loop and claim all virtual rewards
187: uint256 _extraRewards = _rewardsContract.extraRewardsLength();
188: for (uint256 _j; _j < _extraRewards;) {
189: IVirtualBalanceRewardPool _virtualReward = _rewardsContract.extraRewards(_j);
190: IERC20 _rewardToken = _virtualReward.rewardToken();
191: uint256 _earnedReward = _virtualReward.earned(address(this));
192: if (_earnedReward != 0) {
193: _virtualReward.getReward();
194: _rewardToken.transfer(_msgSender(), _earnedReward);
195: emit ClaimedReward(address(_rewardToken), _earnedReward);
196: }
197: unchecked {
198: ++_j;
199: }
200: }
201: unchecked {
202: ++_i;
203: }
204: }
188: for (uint256 _j; _j < _extraRewards;) {
189: IVirtualBalanceRewardPool _virtualReward = _rewardsContract.extraRewards(_j);
190: IERC20 _rewardToken = _virtualReward.rewardToken();
191: uint256 _earnedReward = _virtualReward.earned(address(this));
192: if (_earnedReward != 0) {
193: _virtualReward.getReward();
194: _rewardToken.transfer(_msgSender(), _earnedReward);
195: emit ClaimedReward(address(_rewardToken), _earnedReward);
196: }
197: unchecked {
198: ++_j;
199: }
200: }
254: for (_i; _i < _rewardsAmount;) {
255: IVirtualBalanceRewardPool _virtualReward = _rewardsContract.extraRewards(_i);
256: IERC20 _rewardToken = _virtualReward.rewardToken();
257: uint256 _earnedReward = _virtualReward.earned(address(this));
258: _rewards[_i + 2] = Reward(_rewardToken, _earnedReward);
259:
260: unchecked {
261: ++_i;
262: }
263: }
File: core/solidity/contracts/core/VaultController.sol
240: for (uint256 _i = _start; _i < _end;) {
241: _collateralsInfo[_i - _start] = tokenAddressCollateralInfo[enabledTokens[_i]];
242:
243: unchecked {
244: ++_i;
245: }
246: }
255: for (uint256 _i; _i < _tokenAddresses.length;) {
256: _tokenId = _oldVaultController.tokenId(_tokenAddresses[_i]);
257: if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
258: _tokensRegistered++;
259:
260: CollateralInfo memory _collateral = _oldVaultController.tokenCollateralInfo(_tokenAddresses[_i]);
261: _collateral.tokenId = _tokensRegistered;
262: _collateral.totalDeposited = 0;
263:
264: enabledTokens.push(_tokenAddresses[_i]);
265: tokenAddressCollateralInfo[_tokenAddresses[_i]] = _collateral;
266:
267: unchecked {
268: ++_i;
269: }
270: }
868: for (uint192 _i; _i < enabledTokens.length; ++_i) {
869: CollateralInfo memory _collateral = tokenAddressCollateralInfo[enabledTokens[_i]];
870: // if the ltv is 0, continue
871: if (_collateral.ltv == 0) continue;
872: // get the address of the token through the array of enabled tokens
873: // note that index 0 of enabledTokens corresponds to a vaultId of 1, so we must subtract 1 from i to get the correct index
874: address _tokenAddress = enabledTokens[_i];
875: // the balance is the vault's token balance of the current collateral token in the loop
876: uint256 _balance = _vault.balances(_tokenAddress);
877: if (_balance == 0) continue;
878: // the raw price is simply the oracle price of the token
879: uint192 _rawPrice = _safeu192(_collateral.oracle.currentValue());
880: if (_rawPrice == 0) continue;
881: // the token value is equal to the price * balance * tokenLTV
882: uint192 _tokenValue = _safeu192(
883: _truncate(_truncate(_balance * _collateral.ltv * _getPriceWithDecimals(_rawPrice, _collateral.decimals)))
884: );
885: // increase the ltv of the vault by the token value
886: _borrowPower += _tokenValue;
887: }
896: for (uint192 _i; _i < enabledTokens.length; ++_i) {
897: CollateralInfo memory _collateral = tokenAddressCollateralInfo[enabledTokens[_i]];
898: // if the ltv is 0, continue
899: if (_collateral.ltv == 0) continue;
900: // get the address of the token through the array of enabled tokens
901: // note that index 0 of enabledTokens corresponds to a vaultId of 1, so we must subtract 1 from i to get the correct index
902: address _tokenAddress = enabledTokens[_i];
903: // the balance is the vault's token balance of the current collateral token in the loop
904: uint256 _balance = _vault.balances(_tokenAddress);
905: if (_balance == 0) continue;
906: // the raw price is simply the oracle price of the token
907: uint192 _rawPrice = _safeu192(_collateral.oracle.peekValue());
908: if (_rawPrice == 0) continue;
909: // the token value is equal to the price * balance * tokenLTV
910: uint192 _tokenValue = _safeu192(
911: _truncate(_truncate(_balance * _collateral.ltv * _getPriceWithDecimals(_rawPrice, _collateral.decimals)))
912: );
913: // increase the ltv of the vault by the token value
914: _borrowPower += _tokenValue;
915: }
994: for (uint96 _i = _start; _i <= _stop;) {
995: IVault _vault = _getVault(_i);
996: uint256[] memory _tokenBalances = new uint256[](enabledTokens.length);
997:
998: for (uint256 _j; _j < enabledTokens.length;) {
999: _tokenBalances[_j] = _vault.balances(enabledTokens[_j]);
1000:
1001: unchecked {
1002: ++_j;
1003: }
1004: }
1005: _vaultSummaries[_i - _start] =
1006: VaultSummary(_i, _peekVaultBorrowingPower(_vault), this.vaultLiability(_i), enabledTokens, _tokenBalances);
1007:
1008: unchecked {
1009: ++_i;
1010: }
1011: }
998: for (uint256 _j; _j < enabledTokens.length;) {
999: _tokenBalances[_j] = _vault.balances(enabledTokens[_j]);
1000:
1001: unchecked {
1002: ++_j;
1003: }
1004: }
[240-246, 255-270, 868-887, 896-915, 994-1011, 998-1004]
File: core/solidity/contracts/governance/GovernorCharlie.sol
259: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
260: if (
261: queuedTransactions[keccak256(
262: abi.encode(
263: _proposal.targets[_i], _proposal.values[_i], _proposal.signatures[_i], _proposal.calldatas[_i], _eta
264: )
265: )]
266: ) revert GovernorCharlie_ProposalAlreadyQueued();
267: _queueTransaction(
268: _proposal.targets[_i],
269: _proposal.values[_i],
270: _proposal.signatures[_i],
271: _proposal.calldatas[_i],
272: _eta,
273: _proposal.delay
274: );
275: }
313: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
314: this.executeTransaction{value: _proposal.values[_i]}(
315: _proposal.targets[_i], _proposal.values[_i], _proposal.signatures[_i], _proposal.calldatas[_i], _proposal.eta
316: );
317: }
382: for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
383: _cancelTransaction(
384: _proposal.targets[_i], _proposal.values[_i], _proposal.signatures[_i], _proposal.calldatas[_i], _proposal.eta
385: );
386: }
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
22: for (uint256 _i; _i < _anchoredUnderlyingTokens.length;) {
23: anchoredUnderlyingTokens.push(_anchoredUnderlyingTokens[_i]);
24:
25: unchecked {
26: ++_i;
27: }
28: }
44: for (uint256 _i = 1; _i < anchoredUnderlyingTokens.length;) {
45: _minStable = Math.min(_minStable, anchoredUnderlyingTokens[_i].peekValue());
46: unchecked {
47: ++_i;
48: }
49: }
Those functions should be declared as external
instead of public
, as they are never called internally by the contract.
Contracts are allowed to override their parents' functions and change the visibility from external to public.
There are 4 instances of this issue.
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
20: function mint(address _dst, uint256 _rawAmount) public onlyOwner {
[20]
File: core/solidity/contracts/utils/UFragments.sol
153: function nonces(address _who) public view returns (uint256 _addressNonces) {
283: function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool _success) {
315: function permit(
Use a scientific notation rather than decimal literals (e.g. 1e6
instead of 1000000
), for better code readability.
There are 3 instances of this issue.
File: core/solidity/contracts/core/WUSDA.sol
// @audit 10_000_000 -> 1e7
35: uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18); // 10 M
[35]
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit 1_000_000_000_000_000_000_000_000 -> 1e24
92: proposalThreshold = 1_000_000_000_000_000_000_000_000;
// @audit 10_000_000_000_000_000_000_000_000 -> 1e25
95: quorumVotes = 10_000_000_000_000_000_000_000_000;
Use a scientific notation rather than exponentiation (e.g. 1e18
instead of 10**18
): although the compiler is capable of optimizing it, it is considered good coding practice to utilize idioms that don't rely on compiler optimization, whenever possible.
There are 2 instances of this issue.
File: core/solidity/contracts/core/WUSDA.sol
35: uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18); // 10 M
[35]
File: core/solidity/contracts/utils/UFragments.sol
100: _totalGons = INITIAL_FRAGMENTS_SUPPLY * 10 ** 48;
[100]
EIP-5267 is a standard which allows for the retrieval and description of EIP-712 hash domains. This enable external tools to allow users to view the fields and values that describe their domain.
This is especially useful when a project may exist on multiple chains and or in multiple contracts, and allows users/tools to verify that the signature is for the right fork, chain, version, contract, etc.
There are 2 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
20: keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)');
[20]
File: core/solidity/contracts/utils/UFragments.sol
88: keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
[88]
Consider removing any unusued state variable to improve the readability of the codebase.
There are 2 instances of this issue.
File: core/solidity/contracts/utils/UFragments.sol
62: uint256 private constant MAX_UINT256 = 2 ** 256 - 1;
[62]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
8: address public constant wETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
[8]
Earlier versions of solidity can use uint<n>(-1)
instead. Expressions not including the - 1
can often be re-written to accomodate the change (e.g. by using a >
rather than a >=
, which will also save some gas).
There are 5 instances of this issue.
File: core/solidity/contracts/core/VaultController.sol
712: ) = _peekLiquidationMath(_id, _assetAddress, 2 ** 256 - 1);
[712]
File: core/solidity/contracts/utils/UFragments.sol
62: uint256 private constant MAX_UINT256 = 2 ** 256 - 1;
62: uint256 private constant MAX_UINT256 = 2 ** 256 - 1;
100: _totalGons = INITIAL_FRAGMENTS_SUPPLY * 10 ** 48;
101: MAX_SUPPLY = 2 ** 128 - 1;
Constants should be defined instead of using magic numbers.
There are 40 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
18: uint256 internal constant _FIFTY_MILLIONS = 50_000_000 * 1e6;
21: uint256 internal constant _TWENTY_FIVE_THOUSANDS = 25_000 * 1e6;
24: uint256 internal constant _FIFTY = 50 * 1e6;
27: uint256 public constant BASE_SUPPLY_PER_CLIFF = 8_000_000 * 1e6;
88: if (_crvAmountToSend != 0 && _claimedAmph != 0) distributedAmph += (_claimedAmph / 1e12); // scale back to 1e6
177: if (_getCliff((_amphByCrv / 1e12) + distributedAmph) >= TOTAL_CLIFFS) return (0, 0, 0);
196: uint256 _bar = (_distributedAmph * 1e12) / (BASE_SUPPLY_PER_CLIFF * _FIFTY);
198: _rate = 1e6 + (_foo - _bar);
222: _amphForThisTurn = ((_rate * _tempAmountReceived) / 1e12) / 1e6; // 1e6
232: uint256 _amountTokenToEnter = (_amphAvailableForThisCliff * 1e18) / _rate;
241: _amphToMint += (_amphForThisTurn * 1e12); // 1e18
[18, 21, 24, 27, 88, 177, 196, 198, 222, 232, 241]
File: core/solidity/contracts/core/Vault.sol
249: _rewards = new Reward[](_rewardsAmount+3);
[249]
File: core/solidity/contracts/core/VaultController.sol
320: if (_newProtocolFee >= 1e18) revert VaultController_FeeTooLarge();
436: if (_newLiquidationFee >= 1e18) revert VaultController_FeeTooLarge();
501: _fee = _safeu192(_truncate(uint256(_amount * (1e18 + initialBorrowingFee)))) - _amount;
515: _safeu192(_truncate(uint256(_tokensToLiquidate * (1e18 + _liquidationIncentive)))) - _tokensToLiquidate;
518: _safeu192(_truncate(uint256(_liquidatorExpectedProfit * (1e18 + liquidationFee)))) - _liquidatorExpectedProfit;
667: _vault.modifyLiability(false, (_usdaToRepurchase * 1e18) / interest.factor);
670: totalBaseLiability -= _safeu192((_usdaToRepurchase * 1e18) / interest.factor);
780: _badFillPrice = _truncate(_priceWithDecimals * (1e18 - _collateral.liquidationIncentive));
790: uint256 _maxTokensToLiquidate = (_usdaToSolvency * 1e18) / _denominator;
948: _truncate((uint256(_timeDifference) * uint256(1e18) * uint256(_curveVal)) / (365 days + 6 hours))
1040: _priceWithDecimals = _price * 10 ** (18 - _decimals);
[320, 436, 501, 515, 518, 667, 670, 780, 790, 948, 1040]
File: core/solidity/contracts/core/WUSDA.sol
35: uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18); // 10 M
[35]
File: core/solidity/contracts/governance/GovernorCharlie.sol
514: if (uint256(_s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
[514]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
35: if (!((0 < _s1) && (_s1 < _s2) && (_s2 < 1e18))) revert ThreeLines0_100_InvalidBreakpointValues();
51: if (_xValue > 1e18) _xValue = 1e18;
83: int256 _mE6 = (_rise * 1e6) / _run;
86: _result = (_mE6 * _distance) / 1e6 + _b;
File: core/solidity/contracts/utils/UFragments.sol
63: uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 1 * 10 ** DECIMALS;
100: _totalGons = INITIAL_FRAGMENTS_SUPPLY * 10 ** 48;
330: if (uint256(_s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
28: div = 10 ** (18 + _underlyingDecimals - cToken.decimals());
[28]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
51: _value = (_aggregatorPrice * _baseAggregatorPrice) / 1e18;
[51]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
53: _value = _lpPrice / 1e18;
[53]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
61: _maxPrice = (3 * _vp * FixedPointMathLib.cbrt(_basePrices)) / 1 ether;
[61]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
75: uint256 _uniswapPrice = _getPriceFromUniswap(_seconds, uint128(10 ** BASE_TOKEN_DECIMALS));
85: _e18Amount = (_decimals > 18) ? _amount / (10 ** (_decimals - 18)) : _amount * (10 ** (18 - _decimals));
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
37: _price = (_ethPrice * _priceInEth) / 1e18;
[37]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
32: _value = (_stETHPrice * _stETHPerWstEth) / 1e18;
[32]
Some functions don't have a body, consider commenting why, or refactor the code and remove these functions.
There is 1 instance of this issue.
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
54: fallback() external {}
[54]
There are some automated tools that will flag a project as having higher complexity if there is inline-assembly, so it's better to avoid using assembly if it's not needed.
Consider using the following alternatives:
-
id := chainid()
->uint256 id = block.chainid
-
size := extcodesize()
->uint256 size = address().code.length
-
hash := extcodehash()
->bytes32 hash = address().codehash
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
166: _chainId := chainid()
[166]
Follow the Solidity naming convention by naming all the contracts in CamelCase.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/ThreeLines0_100.sol
11: contract ThreeLines0_100 is ICurveSlave {
[11]
Follow the Solidity naming convention by adding an underscore before the function name, for any private
and internal
functions.
There is 1 instance of this issue.
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
11: function getCurrentPrice(AggregatorV2V3Interface _aggregator) internal view returns (uint256 _price) {
[11]
Use mixedCase
for local and state variables that are not constants, and add a trailing underscore for internal variables. Documentation
There are 18 instances of this issue.
Expand findings
File: core/solidity/contracts/core/VaultController.sol
34: IVaultDeployer public immutable VAULT_DEPLOYER;
[34]
File: core/solidity/contracts/utils/UFragments.sol
70: uint256 public MAX_SUPPLY; // = type(uint128).max; // (2^128) - 1
[70]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
13: IV2Pool public immutable CB_ETH_POOL;
16: IOracleRelay public immutable CB_ETH_ORACLE_RELAY;
19: IOracleRelay public immutable ETH_ORACLE_RELAY;
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
15: ChainlinkOracleRelay public immutable BASE_AGGREGATOR;
[15]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
15: IStablePool public immutable CRV_POOL;
[15]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
15: IV2Pool public immutable TRI_CRYPTO;
18: IOracleRelay public immutable WBTC_ORACLE_RELAY;
21: IOracleRelay public immutable ETH_ORACLE_RELAY;
24: IOracleRelay public immutable USDT_ORACLE_RELAY;
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
17: bool public immutable QUOTE_TOKEN_IS_TOKEN0;
26: uint8 public immutable BASE_TOKEN_DECIMALS;
29: uint8 public immutable QUOTE_TOKEN_DECIMALS;
32: address public immutable BASE_TOKEN;
35: address public immutable QUOTE_TOKEN;
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
12: UniswapV3OracleRelay public immutable ETH_ORACLE;
[12]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
12: IOracleRelay public immutable STETH_ANCHORED_VIEW_UNDERLYING;
[12]
Constants should be named with all capital letters with underscores separating words. Examples: MAX_BLOCKS
, TOKEN_NAME
. Documentation
There are 4 instances of this issue.
File: core/solidity/contracts/core/WUSDA.sol
35: uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18); // 10 M
[35]
File: core/solidity/contracts/utils/UFragments.sol
78: uint8 public constant decimals = uint8(DECIMALS);
[78]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
12: address public constant cETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
[12]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
8: address public constant wETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
[8]
Variables which are not constants or immutable should not be declared in all uppercase.
There are 2 instances of this issue.
File: core/solidity/contracts/utils/UFragments.sol
70: uint256 public MAX_SUPPLY; // = type(uint128).max; // (2^128) - 1
[70]
File: core/solidity/interfaces/utils/ICurvePool.sol
10: function A() external view returns (uint256 _A);
[10]
Consider grouping all the system constants under a single file. This finding shows only the first constant for each file, for brevity.
There are 10 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
15: uint256 internal constant _BASE = 1 ether;
[15]
File: core/solidity/contracts/core/USDA.sol
21: bytes32 public constant VAULT_CONTROLLER_ROLE = keccak256('VAULT_CONTROLLER');
[21]
File: core/solidity/contracts/core/VaultController.sol
25: uint8 public constant MAX_DECIMALS = 18;
[25]
File: core/solidity/contracts/core/WUSDA.sol
35: uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18); // 10 M
[35]
File: core/solidity/contracts/governance/GovernorCharlie.sol
13: string public constant NAME = 'Amphora Protocol Governor';
[13]
File: core/solidity/contracts/utils/UFragments.sol
61: uint256 private constant DECIMALS = 18;
[61]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
12: address public constant cETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
[12]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
8: ICurveAddressesProvider public constant CURVE_ADDRESSES_PROVIDER =
9: ICurveAddressesProvider(0x0000000022D53366457F9d5E68Ec105046FC4383);
[8-9]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
8: address public constant wETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
[8]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
10: IWStETH public constant WSTETH = IWStETH(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0);
[10]
Since solidity 0.8.18
or later it's possible to use named mappings to make it easier to understand the purpose of each mapping. Documentation
There are 16 instances of this issue.
Expand findings
File: core/solidity/contracts/core/Vault.sol
43: mapping(address => uint256) public balances;
46: mapping(address => bool) public isTokenStaked;
File: core/solidity/contracts/core/VaultController.sol
37: mapping(uint96 => address) public vaultIdVaultAddress;
40: mapping(address => uint96[]) public walletVaultIDs;
43: mapping(address => CollateralInfo) public tokenAddressCollateralInfo;
File: core/solidity/contracts/governance/GovernorCharlie.sol
53: mapping(uint256 => Proposal) public proposals;
56: mapping(address => uint256) public latestProposalIds;
59: mapping(bytes32 => bool) public queuedTransactions;
65: mapping(address => uint256) public whitelistAccountExpirations;
77: mapping(uint256 => mapping(address => Receipt)) public proposalReceipts;
// @audit mapping(address => Receipt)
77: mapping(uint256 => mapping(address => Receipt)) public proposalReceipts;
File: core/solidity/contracts/periphery/CurveMaster.sol
13: mapping(address => address) public curves;
[13]
File: core/solidity/contracts/utils/UFragments.sol
74: mapping(address => uint256) public _gonBalances;
82: mapping(address => mapping(address => uint256)) private _allowedFragments;
// @audit mapping(address => uint256)
82: mapping(address => mapping(address => uint256)) private _allowedFragments;
93: mapping(address => uint256) private _nonces;
The following events are never emitted, consider to remove them.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
39: event LogRebase(uint256 indexed epoch, uint256 totalSupply);
[39]
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields).
Each event should use three indexed
fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
There are 27 instances of this issue.
Expand findings
File: core/solidity/contracts/utils/UFragments.sol
40: event LogMonetaryPolicyUpdated(address monetaryPolicy);
[40]
File: core/solidity/interfaces/core/IAMPHClaimer.sol
42: event ChangedCvxRewardFee(uint256 _newCvxReward);
48: event ChangedCrvRewardFee(uint256 _newCrvReward);
File: core/solidity/interfaces/core/IUSDA.sol
33: event Mint(address _to, uint256 _value);
40: event Burn(address _from, uint256 _value);
68: event VaultControllerTransfer(address _target, uint256 _susdAmount);
File: core/solidity/interfaces/core/IVault.sol
20: event Deposit(address _token, uint256 _amount);
27: event Withdraw(address _token, uint256 _amount);
34: event ClaimedReward(address _token, uint256 _amount);
41: event Staked(address _token, uint256 _amount);
File: core/solidity/interfaces/core/IVaultController.sol
23: event InterestEvent(uint64 _epoch, uint192 _amount, uint256 _curveVal);
29: event NewProtocolFee(uint192 _protocolFee);
39: event RegisteredErc20(
40: address _tokenAddress, uint256 _ltv, address _oracleAddress, uint256 _liquidationIncentive, uint256 _cap
41: );
52: event UpdateRegisteredErc20(
53: address _tokenAddress,
54: uint256 _ltv,
55: address _oracleAddress,
56: uint256 _liquidationIncentive,
57: uint256 _cap,
58: uint256 _poolId
59: );
67: event NewVault(address _vaultAddress, uint256 _vaultId, address _vaultOwner);
73: event RegisterCurveMaster(address _curveMasterAddress);
81: event BorrowUSDA(uint256 _vaultId, address _vaultAddress, uint256 _borrowAmount, uint256 _fee);
89: event RepayUSDA(uint256 _vaultId, address _vaultAddress, uint256 _repayAmount);
99: event Liquidate(
100: uint256 _vaultId,
101: address _assetAddress,
102: uint256 _usdaToRepurchase,
103: uint256 _tokensToLiquidate,
104: uint256 _liquidationFee
105: );
112: event ChangedClaimerContract(IAMPHClaimer _oldClaimerContract, IAMPHClaimer _newClaimerContract);
118: event RegisterUSDA(address _usdaContractAddress);
125: event ChangedInitialBorrowingFee(uint192 _oldBorrowingFee, uint192 _newBorrowingFee);
132: event ChangedLiquidationFee(uint192 _oldLiquidationFee, uint192 _newLiquidationFee);
139: event CollateralsMigratedFrom(IVaultController _oldVaultController, address[] _tokenAddresses);
[23, 29, 39-41, 52-59, 67, 73, 81, 89, 99-105, 112, 118, 125, 132, 139]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
16: event VaultControllerSet(address _oldVaultControllerAddress, address _newVaultControllerAddress);
24: event CurveSet(address _oldCurveAddress, address _token, address _newCurveAddress);
32: event CurveForceSet(address _oldCurveAddress, address _token, address _newCurveAddress);
Some files use >=
, while others use ^
. The instances below are examples of the method that has the fewest instances for a specific version.
Occurrences: ^
: 43 >=
: 6
There are 6 instances of this issue.
File: core/solidity/interfaces/core/IVaultDeployer.sol
2: pragma solidity >=0.8.4 <0.9.0;
[2]
File: core/solidity/interfaces/utils/ICVX.sol
2: pragma solidity >=0.8.4 <0.9.0;
[2]
File: core/solidity/interfaces/utils/IRoles.sol
2: pragma solidity >=0.8.4 <0.9.0;
[2]
File: core/solidity/interfaces/utils/IWStETH.sol
2: pragma solidity >=0.8.4 <0.9.0;
[2]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
2: pragma solidity >=0.5.0 <0.9.0;
[2]
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
2: pragma solidity >=0.5.0 <0.9.0;
[2]
Consider using a normal Solidity version instead of an experimental one.
There are 2 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
4: pragma experimental ABIEncoderV2;
[4]
File: core/solidity/interfaces/governance/IAmphoraProtocolToken.sol
3: pragma experimental ABIEncoderV2;
[3]
Use a more recent version of Solidity: the latest version is 0.8.20, so it's safer to use at least the version 0.8.19 to get the latest bugfixes and features.
There are 43 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/USDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/Vault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/VaultDeployer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/core/WUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/governance/GovernorCharlie.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/contracts/periphery/CurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/GovernanceStructs.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/utils/UFragments.sol
3: pragma solidity ^0.8.9;
[3]
File: core/solidity/interfaces/core/IAMPHClaimer.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVault.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IVaultController.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/core/IWUSDA.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAMPH.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IAmphoraProtocolToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IAnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICToken.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveAddressesProvider.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/periphery/IOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IBooster.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurvePool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/ICurveSlave.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
2: pragma solidity ^0.8.9;
[2]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
2: pragma solidity ^0.8.9;
[2]
Consider using descriptive constants or an enum instead of passing zero directly on function calls, as that might be error-prone, to fully describe the caller's intention.
There are 3 instances of this issue.
File: core/solidity/contracts/core/VaultController.sol
576: _repay(_id, 0, true);
[576]
File: core/solidity/contracts/governance/GovernorCharlie.sol
187: Proposal memory _newProposal = Proposal({
188: id: proposalCount,
189: proposer: msg.sender,
190: eta: 0,
191: targets: _targets,
192: values: _values,
193: signatures: _signatures,
194: calldatas: _calldatas,
195: startBlock: block.number + votingDelay,
196: endBlock: block.number + votingDelay + votingPeriod,
197: forVotes: 0,
198: againstVotes: 0,
199: abstainVotes: 0,
200: canceled: false,
201: executed: false,
202: emergency: _emergency,
203: quorumVotes: quorumVotes,
204: delay: proposalTimelockDelay
205: });
[187-205]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
41: CRV_POOL.remove_liquidity(0, _amounts);
[41]
Starting from version 0.8.4
, the recommended approach for appending bytes is to use bytes.concat
instead of abi.encodePacked
.
There are 3 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
347: else _callData = abi.encodePacked(bytes4(keccak256(bytes(_signature))), _data);
512: bytes32 _digest = keccak256(abi.encodePacked('\x19\x01', _domainSeparator, _structHash));
File: core/solidity/contracts/utils/UFragments.sol
328: bytes32 _digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR(), _permitDataDigest));
[328]
Constant variables and immutable variables serve different purposes and should be used accordingly.
To clarify, constant variables are used for literal values in the code, whereas immutable variables are ideal for values calculated or passed into the constructor.
There are 5 instances of this issue.
File: core/solidity/contracts/core/USDA.sol
21: bytes32 public constant VAULT_CONTROLLER_ROLE = keccak256('VAULT_CONTROLLER');
[21]
File: core/solidity/contracts/governance/GovernorCharlie.sol
19: bytes32 public constant DOMAIN_TYPEHASH =
20: keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)');
23: bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)');
File: core/solidity/contracts/utils/UFragments.sol
87: bytes32 public constant EIP712_DOMAIN =
88: keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
89: bytes32 public constant PERMIT_TYPEHASH =
90: keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
If a transaction reverts, it can be confusing to debug if there aren't any messages. Add a descriptive message to all require
/revert
statements.
There are 3 instances of this issue.
File: core/solidity/contracts/utils/UFragments.sol
52: require(msg.sender == monetaryPolicy);
324: require(block.timestamp <= _deadline);
333: require(_owner == ecrecover(_digest, _v, _r, _s));
The IR-based code generator was developed to make code generation more performant by enabling optimization passes that can be applied across functions.
It is possible to activate the IR-based code generator through the command line by using the flag --via-ir
or by including the option {"viaIR": true}
.
Keep in mind that compiling with this option may take longer. However, you can simply test it before deploying your code. If you find that it provides better performance, you can add the --via-ir
flag to your deploy command.
The contract's interface should be imported first, followed by each of the interfaces it uses, followed by all other files. The examples below do not follow this layout.
There are 14 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
5: import {IAMPHClaimer} from '@interfaces/core/IAMPHClaimer.sol';
[5]
File: core/solidity/contracts/core/USDA.sol
8: import {IUSDA} from '@interfaces/core/IUSDA.sol';
[8]
File: core/solidity/contracts/core/Vault.sol
5: import {IVault} from '@interfaces/core/IVault.sol';
[5]
File: core/solidity/contracts/core/VaultController.sol
9: import {IVaultController} from '@interfaces/core/IVaultController.sol';
[9]
File: core/solidity/contracts/core/VaultDeployer.sol
5: import {IVaultDeployer} from '@interfaces/core/IVaultDeployer.sol';
[5]
File: core/solidity/contracts/core/WUSDA.sol
7: import {ERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
[7]
File: core/solidity/contracts/governance/GovernorCharlie.sol
7: import {IGovernorCharlie} from '@interfaces/governance/IGovernorCharlie.sol';
[7]
File: core/solidity/contracts/periphery/CurveMaster.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[6]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
8: import {CurveRegistryUtils} from '@contracts/periphery/oracles/CurveRegistryUtils.sol';
[8]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
[7]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
5: import {StableCurveLpOracle} from '@contracts/periphery/oracles/StableCurveLpOracle.sol';
[5]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
7: import {CurveRegistryUtils} from '@contracts/periphery/oracles/CurveRegistryUtils.sol';
[7]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
7: import {CurveRegistryUtils} from '@contracts/periphery/oracles/CurveRegistryUtils.sol';
[7]
The following functions are missing some parameters when emitting an event: when dealing with a source address which uses the value of msg.sender
, the msg.sender
value should be specified in every event.
Otherwise, a contract or web page listening to events cannot react to connected users: basically, those events cannot be used properly.
There are 5 instances of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
353: emit ExecuteTransaction(_txHash, _target, _value, _signature, _data, _eta);
388: emit ProposalCanceledIndexed(_proposalId);
389: emit ProposalCanceled(_proposalId);
File: core/solidity/contracts/utils/UFragments.sol
233: emit Transfer(_from, _to, _value);
252: emit Transfer(_from, _to, _value);
Events are generally emitted when sensitive changes are made to the contracts.
However, some are missing important parameters, as they should include both the new value and old value where possible.
There are 13 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
122: emit ChangedVaultController(_newVaultController);
139: emit ChangedCvxRewardFee(_newFee);
147: emit ChangedCrvRewardFee(_newFee);
File: core/solidity/contracts/core/USDA.sol
66: emit PauserSet(_pauser);
[66]
File: core/solidity/contracts/core/VaultController.sol
322: emit NewProtocolFee(_newProtocolFee);
411: emit UpdateRegisteredErc20(_tokenAddress, _ltv, _oracleAddress, _liquidationIncentive, _cap, _poolId);
420: emit ChangedClaimerContract(_oldClaimerContract, _newClaimerContract);
430: emit ChangedInitialBorrowingFee(_oldBorrowingFee, _newBorrowingFee);
440: emit ChangedLiquidationFee(_oldLiquidationFee, _newLiquidationFee);
File: core/solidity/contracts/governance/GovernorCharlie.sol
677: emit WhitelistAccountExpirationSet(_account, _expiration);
[677]
File: core/solidity/contracts/periphery/CurveMaster.sol
35: emit VaultControllerSet(_oldCurveAddress, _vaultMasterAddress);
46: emit CurveSet(_oldCurve, _tokenAddress, _curveAddress);
File: core/solidity/contracts/utils/UFragments.sol
113: emit LogMonetaryPolicyUpdated(_monetaryPolicy);
[113]
If a reentrancy occurs, some events may be emitted in an unexpected order, and this may be a problem if a third party expects a specific order for these events. Ensure that events follow the best practice of CEI.
There are 72 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
// @audit CVX.safeTransferFrom(msg.sender, owner(), _cvxAmountToSend)
96: emit ClaimedAmph(msg.sender, _cvxAmountToSend, _crvAmountToSend, _claimedAmph);
// @audit CVX.safeTransferFrom(msg.sender, owner(), _cvxAmountToSend)
122: emit ChangedVaultController(_newVaultController);
// @audit CVX.safeTransferFrom(msg.sender, owner(), _cvxAmountToSend)
131: emit RecoveredDust(_token, owner(), _amount);
// @audit CVX.safeTransferFrom(msg.sender, owner(), _cvxAmountToSend)
139: emit ChangedCvxRewardFee(_newFee);
// @audit CVX.safeTransferFrom(msg.sender, owner(), _cvxAmountToSend)
147: emit ChangedCrvRewardFee(_newFee);
File: core/solidity/contracts/core/USDA.sol
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
66: emit PauserSet(_pauser);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
108: emit Deposit(_target, _susdAmount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
156: emit Withdraw(_target, _susdAmount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
176: emit Transfer(address(0), _target, _amount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
177: emit Mint(_target, _amount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
196: emit Transfer(_target, address(0), _amount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
197: emit Burn(_target, _amount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
218: emit RecoveredDust(owner(), _amount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
248: emit VaultControllerTransfer(_target, _susdAmount);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
263: emit Donation(_msgSender(), _amount, _totalSupply);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
282: emit VaultControllerAdded(_vaultController);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
291: emit VaultControllerRemoved(_vaultController);
// @audit IVaultController(_vaultControllers.at(_i)).calculateInterest()
300: emit VaultControllerRemovedFromList(_vaultController);
[66, 108, 156, 176, 177, 196, 197, 218, 248, 263, 282, 291, 300]
File: core/solidity/contracts/core/Vault.sol
// @audit CONTROLLER.tokenId(_token)
108: emit Deposit(_token, _amount);
// @audit CONTROLLER.tokenId(_token)
132: emit Withdraw(_tokenAddress, _amount);
// @audit CONTROLLER.tokenId(_token)
150: emit Staked(_tokenAddress, balances[_tokenAddress]);
// @audit CONTROLLER.tokenId(_token)
195: emit ClaimedReward(address(_rewardToken), _earnedReward);
// @audit CONTROLLER.tokenId(_token)
226: emit ClaimedReward(address(CRV), _totalCrvReward);
// @audit CONTROLLER.tokenId(_token)
227: emit ClaimedReward(address(CVX), _totalCvxReward);
[108, 132, 150, 195, 226, 227]
File: core/solidity/contracts/core/VaultController.sol
// @audit usda.pauser()
273: emit CollateralsMigratedFrom(_oldVaultController, _tokenAddresses);
// @audit usda.pauser()
290: emit NewVault(_vaultAddress, vaultsMinted, _msgSender());
// @audit usda.pauser()
307: emit RegisterUSDA(_usdaAddress);
// @audit usda.pauser()
314: emit RegisterCurveMaster(_masterCurveAddress);
// @audit usda.pauser()
322: emit NewProtocolFee(_newProtocolFee);
// @audit usda.pauser()
373: emit RegisteredErc20(_tokenAddress, _ltv, _oracleAddress, _liquidationIncentive, _cap);
// @audit usda.pauser()
411: emit UpdateRegisteredErc20(_tokenAddress, _ltv, _oracleAddress, _liquidationIncentive, _cap, _poolId);
// @audit usda.pauser()
420: emit ChangedClaimerContract(_oldClaimerContract, _newClaimerContract);
// @audit usda.pauser()
430: emit ChangedInitialBorrowingFee(_oldBorrowingFee, _newBorrowingFee);
// @audit usda.pauser()
440: emit ChangedLiquidationFee(_oldLiquidationFee, _newLiquidationFee);
// @audit usda.pauser()
561: emit BorrowUSDA(_id, address(_vault), _amount, _fee);
// @audit usda.pauser()
609: emit RepayUSDA(_id, address(_vault), _amountInUSDA);
// @audit usda.pauser()
694: emit Liquidate(_id, _assetAddress, _usdaToRepurchase, _tokensToLiquidate - _liquidationFee, _liquidationFee);
// @audit usda.pauser()
970: emit InterestEvent(uint64(block.timestamp), _e18FactorIncrease, _curveVal);
[273, 290, 307, 314, 322, 373, 411, 420, 430, 440, 561, 609, 694, 970]
File: core/solidity/contracts/core/WUSDA.sol
// @audit IERC20(USDA).safeTransferFrom(_from, address(this), _usdaAmount)
218: emit Deposit(_from, _to, _usdaAmount, _wusdaAmount);
// @audit IERC20(USDA).safeTransferFrom(_from, address(this), _usdaAmount)
230: emit Withdraw(_from, _to, _usdaAmount, _wusdaAmount);
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
225: emit ProposalCreatedIndexed(
226: _newProposal.id,
227: msg.sender,
228: _targets,
229: _values,
230: _signatures,
231: _calldatas,
232: _newProposal.startBlock,
233: _newProposal.endBlock,
234: _description
235: );
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
237: emit ProposalCreated(
238: _newProposal.id,
239: msg.sender,
240: _targets,
241: _values,
242: _signatures,
243: _calldatas,
244: _newProposal.startBlock,
245: _newProposal.endBlock,
246: _description
247: );
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
277: emit ProposalQueuedIndexed(_proposalId, _eta);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
278: emit ProposalQueued(_proposalId, _eta);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
302: emit QueueTransaction(_txHash, _target, _value, _signature, _data, _eta);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
318: emit ProposalExecutedIndexed(_proposalId);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
319: emit ProposalExecuted(_proposalId);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
353: emit ExecuteTransaction(_txHash, _target, _value, _signature, _data, _eta);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
388: emit ProposalCanceledIndexed(_proposalId);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
389: emit ProposalCanceled(_proposalId);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
408: emit CancelTransaction(_txHash, _target, _value, _signature, _data, _eta);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
487: emit VoteCastIndexed(msg.sender, _proposalId, _support, _numberOfVotes, '');
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
488: emit VoteCast(msg.sender, _proposalId, _support, _numberOfVotes, '');
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
499: emit VoteCastIndexed(msg.sender, _proposalId, _support, _numberOfVotes, _reason);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
500: emit VoteCast(msg.sender, _proposalId, _support, _numberOfVotes, _reason);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
520: emit VoteCastIndexed(_signatory, _proposalId, _support, _numberOfVotes, '');
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
521: emit VoteCast(_signatory, _proposalId, _support, _numberOfVotes, '');
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
587: emit NewDelay(_oldTimelockDelay, proposalTimelockDelay);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
598: emit NewEmergencyDelay(_oldEmergencyTimelockDelay, emergencyTimelockDelay);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
609: emit VotingDelaySet(_oldVotingDelay, votingDelay);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
620: emit VotingPeriodSet(_oldVotingPeriod, votingPeriod);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
631: emit EmergencyVotingPeriodSet(_oldEmergencyVotingPeriod, emergencyVotingPeriod);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
642: emit ProposalThresholdSet(_oldProposalThreshold, proposalThreshold);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
653: emit NewQuorum(_oldQuorumVotes, quorumVotes);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
664: emit NewEmergencyQuorum(_oldEmergencyQuorumVotes, emergencyQuorumVotes);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
677: emit WhitelistAccountExpirationSet(_account, _expiration);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
688: emit WhitelistGuardianSet(_oldGuardian, whitelistGuardian);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
699: emit OptimisticVotingDelaySet(_oldOptimisticVotingDelay, optimisticVotingDelay);
// @audit amph.getPriorVotes(msg.sender, (block.number - 1))
710: emit OptimisticQuorumVotesSet(_oldOptimisticQuorumVotes, optimisticQuorumVotes);
[225-235, 237-247, 277, 278, 302, 318, 319, 353, 388, 389, 408, 487, 488, 499, 500, 520, 521, 587, 598, 609, 620, 631, 642, 653, 664, 677, 688, 699, 710]
File: core/solidity/contracts/periphery/CurveMaster.sol
// @audit _curve.valueAt(_xValue)
35: emit VaultControllerSet(_oldCurveAddress, _vaultMasterAddress);
// @audit _curve.valueAt(_xValue)
46: emit CurveSet(_oldCurve, _tokenAddress, _curveAddress);
// @audit _curve.valueAt(_xValue)
56: emit CurveForceSet(_oldCurve, _tokenAddress, _curveAddress);
If it is not within the scope of the project to ultimately relinquish all ownership control, it is recommended to override the renounceOwnership
function in OpenZeppelin's Ownable
contract in order to disable it.
There are 7 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
12: contract AMPHClaimer is IAMPHClaimer, Ownable {
[12]
File: core/solidity/contracts/core/VaultController.sol
23: contract VaultController is Pausable, IVaultController, ExponentialNoError, Ownable {
[23]
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
8: contract AmphoraProtocolToken is IAmphoraProtocolToken, ERC20VotesComp, Ownable {
[8]
File: core/solidity/contracts/periphery/CurveMaster.sol
11: contract CurveMaster is ICurveMaster, Ownable {
[11]
File: core/solidity/contracts/utils/UFragments.sol
20: contract UFragments is Ownable, IERC20Metadata {
[20]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
10: contract CTokenOracle is OracleRelay, Ownable {
[10]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
11: contract ChainlinkOracleRelay is OracleRelay, Ownable {
[11]
Consider adding some parameters to the error to indicate which user or values caused the failure.
There are 75 instances of this issue.
Expand findings
File: core/solidity/contracts/utils/ThreeLines0_100.sol
13: error ThreeLines0_100_InvalidCurve();
16: error ThreeLines0_100_InvalidBreakpointValues();
19: error ThreeLines0_100_InputTooSmall();
File: core/solidity/contracts/utils/UFragments.sol
43: error UFragments_InvalidSignature();
46: error UFragments_InvalidRecipient();
File: core/solidity/interfaces/core/IUSDA.sol
93: error USDA_ZeroAmount();
96: error USDA_InsufficientFunds();
99: error USDA_EmptyReserve();
102: error USDA_OnlyPauser();
105: error USDA_NotEnoughBalance();
File: core/solidity/interfaces/core/IVault.sol
49: error Vault_TokenNotRegistered();
54: error Vault_AmountZero();
57: error Vault_OverWithdrawal();
60: error Vault_RepayTooMuch();
63: error Vault_NotMinter();
66: error Vault_NotVaultController();
69: error Vault_DepositAndStakeOnConvexFailed();
72: error Vault_WithdrawAndUnstakeOnConvexFailed();
75: error Vault_TokenNotCurveLP();
78: error Vault_TokenZeroBalance();
81: error Vault_TokenCanNotBeStaked();
84: error Vault_TokenAlreadyStaked();
[49, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84]
File: core/solidity/interfaces/core/IVaultController.sol
146: error VaultController_TooManyDecimals();
149: error VaultController_OnlyPauser();
152: error VaultController_FeeTooLarge();
155: error VaultController_OracleNotRegistered();
158: error VaultController_TokenAlreadyRegistered();
161: error VaultController_TokenNotRegistered();
164: error VaultController_LTVIncompatible();
167: error VaultController_OnlyMinter();
170: error VaultController_VaultInsolvent();
173: error VaultController_RepayTooMuch();
176: error VaultController_LiquidateZeroTokens();
179: error VaultController_OverLiquidation();
182: error VaultController_VaultSolvent();
185: error VaultController_VaultDoesNotExist();
188: error VaultController_WrongCollateralAddress();
191: error VaultController_NotValidVault();
194: error VaultController_CapReached();
197: error VaultController_TokenAddressDoesNotMatchLpAddress();
[146, 149, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, 182, 185, 188, 191, 194, 197]
File: core/solidity/interfaces/core/IVaultDeployer.sol
20: error VaultDeployer_OnlyVaultController();
[20]
File: core/solidity/interfaces/governance/IAmphoraProtocolToken.sol
12: error AmphoraProtocolToken_InvalidAddress();
15: error AmphoraProtocolToken_InvalidSupply();
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
15: error GovernorCharlie_NotGovernorCharlie();
18: error GovernorCharlie_NotActive();
21: error GovernorCharlie_VotesBelowThreshold();
24: error GovernorCharlie_NoActions();
27: error GovernorCharlie_TooManyActions();
30: error GovernorCharlie_MultipleActiveProposals();
33: error GovernorCharlie_MultiplePendingProposals();
36: error GovernorCharlie_ArityMismatch();
39: error GovernorCharlie_ProposalNotSucceeded();
42: error GovernorCharlie_ProposalAlreadyQueued();
45: error GovernorCharlie_DelayNotReached();
48: error GovernorCharlie_ProposalNotQueued();
51: error GovernorCharlie_TimelockNotReached();
54: error GovernorCharlie_TransactionStale();
57: error GovernorCharlie_TransactionReverted();
60: error GovernorCharlie_ProposalAlreadyExecuted();
63: error GovernorCharlie_WhitelistedProposer();
66: error GovernorCharlie_ProposalAboveThreshold();
69: error GovernorCharlie_InvalidProposalId();
72: error GovernorCharlie_InvalidSignature();
75: error GovernorCharlie_VotingClosed();
78: error GovernorCharlie_InvalidVoteType();
81: error GovernorCharlie_AlreadyVoted();
84: error GovernorCharlie_ExpirationExceedsMax();
[15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
39: error CurveMaster_TokenNotEnabled();
42: error CurveMaster_ZeroResult();
File: core/solidity/interfaces/periphery/IOracleRelay.sol
8: error OracleRelay_DifferentUnderlyings();
[8]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
13: error ChainlinkOracle_ZeroAmount();
[13]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
8: error Chainlink_NegativePrice();
[8]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
12: error StableCurveLpOracle_TooFewAnchoredOracles();
[12]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
12: error TriCryptoOracle_ZeroAmount();
[12]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
14: error UniswapV3OracleRelay_TickTimeDiffTooLarge();
[14]
This is useful to avoid doing some typo bugs.
There are 53 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
88: if (_crvAmountToSend != 0 && _claimedAmph != 0) distributedAmph += (_claimedAmph / 1e12); // scale back to 1e6
88: if (_crvAmountToSend != 0 && _claimedAmph != 0) distributedAmph += (_claimedAmph / 1e12); // scale back to 1e6
152: if (_total == 0) return 0;
169: if (_crvTotalRewards == 0 || _amphBalance == 0) return (0, 0, 0);
169: if (_crvTotalRewards == 0 || _amphBalance == 0) return (0, 0, 0);
180: if (_amphByCrv == 0) return (0, 0, 0);
203: if (_tokenAmountToSend == 0) return 0;
[88, 88, 152, 169, 169, 180, 203]
File: core/solidity/contracts/core/USDA.sol
102: if (_susdAmount == 0) revert USDA_ZeroAmount();
148: if (reserveAmount == 0) revert USDA_EmptyReserve();
149: if (_susdAmount == 0) revert USDA_ZeroAmount();
162: if (_susdAmount == 0) revert USDA_ZeroAmount();
183: if (_susdAmount == 0) revert USDA_ZeroAmount();
203: if (_susdAmount == 0) revert USDA_ZeroAmount();
[102, 148, 149, 162, 183, 203]
File: core/solidity/contracts/core/Vault.sol
90: if (CONTROLLER.tokenId(_token) == 0) revert Vault_TokenNotRegistered();
91: if (_amount == 0) revert Vault_AmountZero();
118: if (CONTROLLER.tokenId(_tokenAddress) == 0) revert Vault_TokenNotRegistered();
141: if (_poolId == 0) revert Vault_TokenCanNotBeStaked();
142: if (balances[_tokenAddress] == 0) revert Vault_TokenZeroBalance();
158: if (_poolId != 0 && balances[_token] != 0 && !isTokenStaked[_token]) _canStake = true;
158: if (_poolId != 0 && balances[_token] != 0 && !isTokenStaked[_token]) _canStake = true;
171: if (_collateralInfo.tokenId == 0) revert Vault_TokenNotRegistered();
179: if (_crvReward != 0) {
192: if (_earnedReward != 0) {
211: if (_claimableAmph != 0) {
235: if (CONTROLLER.tokenId(_tokenAddress) == 0) revert Vault_TokenNotRegistered();
[90, 91, 118, 141, 142, 158, 158, 171, 179, 192, 211, 235]
File: core/solidity/contracts/core/VaultController.sol
257: if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
340: if (_collateral.tokenId != 0) revert VaultController_TokenAlreadyRegistered();
343: if (_poolId != 0) {
392: if (_collateral.tokenId == 0) revert VaultController_TokenNotRegistered();
395: if (_poolId != 0) {
625: if (_tokensToLiquidate == 0) revert VaultController_LiquidateZeroTokens();
627: if (tokenAddressCollateralInfo[_assetAddress].tokenId == 0) revert VaultController_TokenNotRegistered();
633: _collateralLiquidated = _tokenAmount != 0 ? _tokenAmount : _tokensToLiquidate;
652: if (_tokensToLiquidate == 0) revert VaultController_LiquidateZeroTokens();
654: if (tokenAddressCollateralInfo[_assetAddress].tokenId == 0) revert VaultController_TokenNotRegistered();
871: if (_collateral.ltv == 0) continue;
877: if (_balance == 0) continue;
880: if (_rawPrice == 0) continue;
899: if (_collateral.ltv == 0) continue;
905: if (_balance == 0) continue;
908: if (_rawPrice == 0) continue;
933: if (_timeDifference == 0) return 0;
1017: if (_collateral.tokenId == 0) revert VaultController_TokenNotRegistered();
[257, 340, 343, 392, 395, 625, 627, 633, 652, 654, 871, 877, 880, 899, 905, 908, 933, 1017]
File: core/solidity/contracts/governance/GovernorCharlie.sol
168: if (quorumVotes == 0) revert GovernorCharlie_NotActive();
176: if (_targets.length == 0) revert GovernorCharlie_NoActions();
180: if (_latestProposalId != 0) {
346: if (bytes(_signature).length == 0) _callData = _data;
474: else if (_proposal.eta == 0) return ProposalState.Succeeded;
543: if (_support == 0) _proposal.againstVotes = _proposal.againstVotes + _votes;
544: else if (_support == 1) _proposal.forVotes = _proposal.forVotes + _votes;
545: else if (_support == 2) _proposal.abstainVotes = _proposal.abstainVotes + _votes;
[168, 176, 180, 346, 474, 543, 544, 545]
File: core/solidity/contracts/periphery/CurveMaster.sol
26: if (_value == 0) revert CurveMaster_ZeroResult();
[26]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
66: if (_stalePriceDelay == 0) revert ChainlinkOracle_ZeroAmount();
[66]
The delete
keyword more closely matches the semantics of what is being done, and draws more attention to the changing of state, which may lead to a more thorough audit of its associated logic.
There are 6 instances of this issue.
File: core/solidity/contracts/core/AMPHClaimer.sol
236: _tempAmountReceived = 0;
[236]
File: core/solidity/contracts/core/VaultController.sol
262: _collateral.totalDeposited = 0;
352: _collateral.poolId = 0;
File: core/solidity/contracts/governance/GovernorCharlie.sol
94: proposalCount = 0;
342: queuedTransactions[_txHash] = false;
406: queuedTransactions[_txHash] = false;
The if
/else
statement can be written in a shorthand way using the ternary operator, as it increases readability and reduces the number of lines of code.
There is 1 instance of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
346: if (bytes(_signature).length == 0) _callData = _data;
347: else _callData = abi.encodePacked(bytes4(keccak256(bytes(_signature))), _data);
[346-347]
These files are never imported by any other source file. If any one of these files is needed for tests, it should be moved to a test directory.
There is 1 instance of this issue.
File: core/solidity/interfaces/periphery/IAnchoredViewRelay.sol
2: pragma solidity ^0.8.9;
[2]
This is a best practice that should be followed.
Inside each contract, library or interface, use the following order:
- Type declarations
- State variables
- Events
- Errors
- Modifiers
- Functions
There are 7 instances of this issue.
Expand findings
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit function constructor found on line 88
106: modifier onlyGov() {
[106]
File: core/solidity/contracts/utils/ThreeLines0_100.sol
// @audit error ThreeLines0_100_InputTooSmall found on line 19
21: int256 public immutable R0;
[21]
File: core/solidity/contracts/utils/UFragments.sol
// @audit error UFragments_InvalidRecipient found on line 46
49: address public monetaryPolicy;
[49]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit error ChainlinkOracle_ZeroAmount found on line 13
16: AggregatorV2V3Interface private immutable _AGGREGATOR;
[16]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
// @audit error StableCurveLpOracle_TooFewAnchoredOracles found on line 12
15: IStablePool public immutable CRV_POOL;
[15]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
// @audit error TriCryptoOracle_ZeroAmount found on line 12
15: IV2Pool public immutable TRI_CRYPTO;
[15]
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
// @audit error UniswapV3OracleRelay_TickTimeDiffTooLarge found on line 14
17: bool public immutable QUOTE_TOKEN_IS_TOKEN0;
[17]
This is a best practice that should be followed.
Functions should be grouped according to their visibility and ordered:
- constructor
- receive function (if exists)
- fallback function (if exists)
- external
- public
- internal
- private
Within a grouping, place the view and pure functions last.
There are 9 instances of this issue.
Expand findings
File: core/solidity/contracts/core/VaultController.sol
// @audit _getPriceWithDecimals on line 1039, which is internal
988: function vaultSummaries(
[988]
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit _getBlockTimestamp on line 733, which is internal
721: function delay() external view override returns (uint256 _delay) {
[721]
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
// @audit _get on line 48, which is internal
57: function changeAnchoredView(address _anchoredViewUnderlying) external onlyOwner {
[57]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
// @audit peekValue on line 40, which is public
46: function currentValue() external override returns (uint256 _currentValue) {
[46]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit peekValue on line 51, which is public
65: function setStalePriceDelay(uint256 _stalePriceDelay) external onlyOwner {
[65]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
// @audit peekValue on line 34, which is public
40: function isStale() external view returns (bool _stale) {
[40]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
// @audit peekValue on line 22, which is public
54: fallback() external {}
[54]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
// @audit _setUnderlying on line 19, which is internal
24: function currentValue() external virtual returns (uint256 _currentValue) {
// @audit _setUnderlying on line 19, which is internal
31: function peekValue() public view virtual override returns (uint256 _price);
Consider splitting long functions into multiple, smaller functions to improve the code readability.
There are 3 instances of this issue.
File: core/solidity/contracts/core/Vault.sol
164: function claimRewards(address[] memory _tokenAddresses) external override onlyMinter {
[164]
File: core/solidity/contracts/core/VaultController.sol
646: function liquidateVault(
[646]
File: core/solidity/contracts/governance/GovernorCharlie.sol
159: function _propose(
[159]
According to the documentation imports should use a double quote instead of a single one.
There are 127 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
4: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
5: import {IAMPHClaimer} from '@interfaces/core/IAMPHClaimer.sol';
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
7: import {SafeERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
8: import {IVaultController} from '@interfaces/core/IVaultController.sol';
9: import {IVault} from '@interfaces/core/IVault.sol';
File: core/solidity/contracts/core/USDA.sol
4: import {ExponentialNoError} from '@contracts/utils/ExponentialNoError.sol';
5: import {Roles} from '@contracts/utils/Roles.sol';
6: import {UFragments} from '@contracts/utils/UFragments.sol';
8: import {IUSDA} from '@interfaces/core/IUSDA.sol';
9: import {IVaultController} from '@interfaces/core/IVaultController.sol';
11: import {IERC20Metadata, IERC20} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
12: import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
13: import {Context} from '@openzeppelin/contracts/utils/Context.sol';
14: import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
[4, 5, 6, 8, 9, 11, 12, 13, 14]
File: core/solidity/contracts/core/Vault.sol
4: import {IUSDA} from '@interfaces/core/IUSDA.sol';
5: import {IVault} from '@interfaces/core/IVault.sol';
6: import {IVaultController} from '@interfaces/core/IVaultController.sol';
7: import {IAMPHClaimer} from '@interfaces/core/IAMPHClaimer.sol';
8: import {IBooster} from '@interfaces/utils/IBooster.sol';
9: import {IBaseRewardPool} from '@interfaces/utils/IBaseRewardPool.sol';
10: import {IVirtualBalanceRewardPool} from '@interfaces/utils/IVirtualBalanceRewardPool.sol';
12: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
13: import {Context} from '@openzeppelin/contracts/utils/Context.sol';
14: import {SafeERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol';
15: import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol';
16: import {ICVX} from '@interfaces/utils/ICVX.sol';
[4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16]
File: core/solidity/contracts/core/VaultController.sol
4: import {ExponentialNoError} from '@contracts/utils/ExponentialNoError.sol';
5: import {CurveMaster} from '@contracts/periphery/CurveMaster.sol';
7: import {IUSDA} from '@interfaces/core/IUSDA.sol';
8: import {IVault} from '@interfaces/core/IVault.sol';
9: import {IVaultController} from '@interfaces/core/IVaultController.sol';
10: import {IOracleRelay} from '@interfaces/periphery/IOracleRelay.sol';
11: import {IBooster} from '@interfaces/utils/IBooster.sol';
12: import {IBaseRewardPool} from '@interfaces/utils/IBaseRewardPool.sol';
13: import {IAMPHClaimer} from '@interfaces/core/IAMPHClaimer.sol';
14: import {IVaultDeployer} from '@interfaces/core/IVaultDeployer.sol';
16: import {IERC20, IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
17: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
18: import {Pausable} from '@openzeppelin/contracts/security/Pausable.sol';
[4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18]
File: core/solidity/contracts/core/VaultDeployer.sol
4: import {Vault, IVault} from '@contracts/core/Vault.sol';
5: import {IVaultDeployer} from '@interfaces/core/IVaultDeployer.sol';
6: import {IVaultController} from '@interfaces/core/IVaultController.sol';
7: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
File: core/solidity/contracts/core/WUSDA.sol
4: import {IWUSDA} from '@interfaces/core/IWUSDA.sol';
6: import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
7: import {ERC20, IERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
9: import {ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol';
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
4: import {IAmphoraProtocolToken} from '@interfaces/governance/IAmphoraProtocolToken.sol';
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
6: import {ERC20, ERC20Permit, ERC20VotesComp} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol';
File: core/solidity/contracts/governance/GovernorCharlie.sol
6: import {IAMPH} from '@interfaces/governance/IAMPH.sol';
7: import {IGovernorCharlie} from '@interfaces/governance/IGovernorCharlie.sol';
9: import {Receipt, ProposalState, Proposal} from '@contracts/utils/GovernanceStructs.sol';
File: core/solidity/contracts/periphery/CurveMaster.sol
4: import {ICurveMaster} from '@interfaces/periphery/ICurveMaster.sol';
5: import {ICurveSlave} from '@interfaces/utils/ICurveSlave.sol';
6: import {IVaultController} from '@interfaces/core/IVaultController.sol';
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
File: core/solidity/contracts/utils/ThreeLines0_100.sol
4: import {ICurveSlave} from '@interfaces/utils/ICurveSlave.sol';
[4]
File: core/solidity/contracts/utils/UFragments.sol
5: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
6: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/interfaces/core/IAMPHClaimer.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
5: import {IVaultController} from '@interfaces/core/IVaultController.sol';
File: core/solidity/interfaces/core/IUSDA.sol
4: import {IRoles} from '@interfaces/utils/IRoles.sol';
6: import {IERC20Metadata, IERC20} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/interfaces/core/IVault.sol
4: import {IVaultController} from '@interfaces/core/IVaultController.sol';
5: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
6: import {IBaseRewardPool} from '@interfaces/utils/IBaseRewardPool.sol';
7: import {ICVX} from '@interfaces/utils/ICVX.sol';
File: core/solidity/interfaces/core/IVaultController.sol
4: import {CurveMaster} from '@contracts/periphery/CurveMaster.sol';
5: import {IOracleRelay} from '@interfaces/periphery/IOracleRelay.sol';
6: import {IBooster} from '@interfaces/utils/IBooster.sol';
7: import {IBaseRewardPool} from '@interfaces/utils/IBaseRewardPool.sol';
8: import {IVaultDeployer} from '@interfaces/core/IVaultDeployer.sol';
9: import {IAMPHClaimer} from '@interfaces/core/IAMPHClaimer.sol';
10: import {IUSDA} from '@interfaces/core/IUSDA.sol';
File: core/solidity/interfaces/core/IVaultDeployer.sol
4: import {IVault} from '@interfaces/core/IVault.sol';
5: import {IVaultController} from '@interfaces/core/IVaultController.sol';
6: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
File: core/solidity/interfaces/core/IWUSDA.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
4: import {IGovernorCharlieEvents} from '@interfaces/governance/IGovernorCharlieEvents.sol';
5: import {IAMPH} from '@interfaces/governance/IAMPH.sol';
7: import {Receipt, ProposalState, Proposal} from '@contracts/utils/GovernanceStructs.sol';
File: core/solidity/interfaces/utils/IBaseRewardPool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
5: import {IVirtualBalanceRewardPool} from '@interfaces/utils/IVirtualBalanceRewardPool.sol';
File: core/solidity/interfaces/utils/ICVX.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/ICurvePool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IRoles.sol
4: import {IAccessControl} from '@openzeppelin/contracts/access/IAccessControl.sol';
[4]
File: core/solidity/interfaces/utils/IVirtualBalanceRewardPool.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/interfaces/utils/IWStETH.sol
4: import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
[4]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {IChainlinkOracleRelay} from '@interfaces/periphery/IChainlinkOracleRelay.sol';
File: core/solidity/contracts/periphery/oracles/CTokenOracle.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {ICToken} from '@interfaces/periphery/ICToken.sol';
6: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
7: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {IV2Pool} from '@interfaces/utils/ICurvePool.sol';
6: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
7: import {FixedPointMathLib} from 'solady/utils/FixedPointMathLib.sol';
8: import {CurveRegistryUtils} from '@contracts/periphery/oracles/CurveRegistryUtils.sol';
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {ChainlinkStalePriceLib} from '@contracts/periphery/oracles/ChainlinkStalePriceLib.sol';
6: import {AggregatorV2V3Interface} from '@chainlink/interfaces/AggregatorV2V3Interface.sol';
7: import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
4: import {AggregatorV2V3Interface} from '@chainlink/interfaces/AggregatorV2V3Interface.sol';
[4]
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {ChainlinkOracleRelay} from '@contracts/periphery/oracles/ChainlinkOracleRelay.sol';
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
4: import {ICurveRegistry, ICurveAddressesProvider} from '@interfaces/periphery/ICurveAddressesProvider.sol';
[4]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {StableCurveLpOracle} from '@contracts/periphery/oracles/StableCurveLpOracle.sol';
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
4: import {IOracleRelay} from '@interfaces/periphery/IOracleRelay.sol';
[4]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {IStablePool} from '@interfaces/utils/ICurvePool.sol';
6: import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
7: import {CurveRegistryUtils} from '@contracts/periphery/oracles/CurveRegistryUtils.sol';
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {IV2Pool} from '@interfaces/utils/ICurvePool.sol';
6: import {FixedPointMathLib} from 'solady/utils/FixedPointMathLib.sol';
7: import {CurveRegistryUtils} from '@contracts/periphery/oracles/CurveRegistryUtils.sol';
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
4: import {OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {IUniswapV3Pool} from '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';
6: import {OracleLibrary} from '@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol';
7: import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
4: import {UniswapV3OracleRelay} from '@contracts/periphery/oracles/UniswapV3OracleRelay.sol';
[4]
File: core/solidity/contracts/periphery/oracles/WstEthOracle.sol
4: import {IOracleRelay, OracleRelay} from '@contracts/periphery/oracles/OracleRelay.sol';
5: import {IWStETH} from '@interfaces/utils/IWStETH.sol';
According to the documentation strings should use a double quote instead of a single one.
There are 19 instances of this issue.
Expand findings
File: core/solidity/contracts/core/USDA.sol
21: bytes32 public constant VAULT_CONTROLLER_ROLE = keccak256('VAULT_CONTROLLER');
57: constructor(IERC20 _sUSDAddr) UFragments('USDA Token', 'USDA') {
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
12: ) ERC20('Amphora Protocol', 'AMPH') ERC20Permit('Amphora Protocol') {
[12]
File: core/solidity/contracts/governance/GovernorCharlie.sol
13: string public constant NAME = 'Amphora Protocol Governor';
20: keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)');
23: bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)');
487: emit VoteCastIndexed(msg.sender, _proposalId, _support, _numberOfVotes, '');
488: emit VoteCast(msg.sender, _proposalId, _support, _numberOfVotes, '');
512: bytes32 _digest = keccak256(abi.encodePacked('\x19\x01', _domainSeparator, _structHash));
520: emit VoteCastIndexed(_signatory, _proposalId, _support, _numberOfVotes, '');
521: emit VoteCast(_signatory, _proposalId, _support, _numberOfVotes, '');
[13, 20, 23, 487, 488, 512, 520, 521]
File: core/solidity/contracts/utils/UFragments.sol
86: string public constant EIP712_REVISION = '1';
88: keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
90: keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
328: bytes32 _digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR(), _permitDataDigest));
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
77: require(_mainValue > 0, 'invalid oracle value');
80: require(_anchorPrice > 0, 'invalid anchor value');
95: require(_mainValue < _upperBounds, 'anchor too low');
96: require(_mainValue > _lowerBounds, 'anchor too high');
Maximum suggested line length is 120 characters according to the documentation.
There are 19 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
213: // all cliffs start when a certain amount of CRV is accumulated and finish when a certain amount is reached, this is the start of the current cliff
[213]
File: core/solidity/contracts/core/USDA.sol
83: /// the calculations for deposit mimic the calculations done by mint in the ampleforth contract, simply with the susd transfer
169: // the gonbalances of the sender is in gons, therefore we must multiply the deposit amount, which is in fragments, by gonsperfragment
173: // and totalgons of course is in gons, and so we multiply amount by gonsperfragment to get the amount of gons we must add to totalGons
File: core/solidity/contracts/core/VaultController.sol
873: // note that index 0 of enabledTokens corresponds to a vaultId of 1, so we must subtract 1 from i to get the correct index
901: // note that index 0 of enabledTokens corresponds to a vaultId of 1, so we must subtract 1 from i to get the correct index
918: /// @notice Returns the increase amount of the interest factor. Accrues interest to borrowers and distribute it to USDA holders
File: core/solidity/contracts/governance/GovernorCharlie.sol
28: /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed
31: /// @notice The number of votes in support of a proposal required in order for an emergency quorum to be reached and for a vote to succeed
681: * @notice Governance function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from whitelisted addresses
File: core/solidity/contracts/utils/ThreeLines0_100.sol
113: /// | ***--------------------------------------------------------------\
118: /// +---------------------------------------------------------------------------------------------------------------------------------
119: /// (0,0) (100, R2)
File: core/solidity/interfaces/core/IUSDA.sol
132: /// the calculations for deposit mimic the calculations done by mint in the ampleforth contract, simply with the susd transfer
[132]
File: core/solidity/interfaces/core/IVaultController.sol
447: /// @notice Returns the increase amount of the interest factor. Accrues interest to borrowers and distribute it to USDA holders
[447]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
90: /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed
93: /// @notice The number of votes in support of a proposal required in order for an emergency quorum to be reached and for a vote to succeed
347: * @notice Governance function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from whitelisted addresses
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
9: /// quote_token refers to the token we are comparing to, so for an Aave price in ETH, Aave is the target and Eth is the quote
[9]
Use alternative variants, e.g. allowlist/denylist instead of whitelist/blacklist.
There are 63 instances of this issue.
Expand findings
File: core/solidity/contracts/governance/GovernorCharlie.sol
64: /// @notice Stores the expiration of account whitelist status as a timestamp
65: mapping(address => uint256) public whitelistAccountExpirations;
67: /// @notice Address which manages whitelisted proposals and whitelist accounts
68: address public whitelistGuardian;
85: /// @notice The maximum number of seconds an address can be whitelisted for
86: uint256 public maxWhitelistPeriod;
102: maxWhitelistPeriod = 31_536_000;
169: // Allow addresses above proposal threshold and whitelisted addresses to propose
170: if (amph.getPriorVotes(msg.sender, (block.number - 1)) < proposalThreshold && !isWhitelisted(msg.sender)) {
207: //whitelist can't make emergency
208: if (_emergency && !isWhitelisted(msg.sender)) {
215: //whitelist can only make optimistic proposals
216: if (isWhitelisted(msg.sender)) {
358: * @notice whitelistGuardian can cancel proposals from whitelisted addresses
368: // Whitelisted proposers can't be canceled for falling below proposal threshold
369: if (isWhitelisted(_proposal.proposer)) {
372: || msg.sender != whitelistGuardian
373: ) revert GovernorCharlie_WhitelistedProposer();
465: bool _whitelisted = isWhitelisted(_proposal.proposer);
470: (_whitelisted && _proposal.againstVotes > _proposal.quorumVotes)
471: || (!_whitelisted && _proposal.forVotes <= _proposal.againstVotes)
472: || (!_whitelisted && _proposal.forVotes < _proposal.quorumVotes)
555: * @notice View function which returns if an account is whitelisted
557: * @return _isWhitelisted If the account is whitelisted
559: function isWhitelisted(address _account) public view override returns (bool _isWhitelisted) {
560: return (whitelistAccountExpirations[_account] > block.timestamp);
572: * @notice Governance function for setting the max whitelist period
573: * @param _second How many seconds to whitelist for
575: function setMaxWhitelistPeriod(uint256 _second) external onlyGov {
576: maxWhitelistPeriod = _second;
668: * @notice Governance function for setting the whitelist expiration as a timestamp
669: * for an account. Whitelist status allows accounts to propose without meeting threshold
670: * @param _account Account address to set whitelist expiration for
671: * @param _expiration Expiration for account whitelist status as timestamp (if now < expiration, whitelisted)
673: function setWhitelistAccountExpiration(address _account, uint256 _expiration) external override onlyGov {
674: if (_expiration >= (maxWhitelistPeriod + block.timestamp)) revert GovernorCharlie_ExpirationExceedsMax();
675: whitelistAccountExpirations[_account] = _expiration;
677: emit WhitelistAccountExpirationSet(_account, _expiration);
681: * @notice Governance function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from whitelisted addresses
682: * @param _account Account to set whitelistGuardian to (0x0 to remove whitelistGuardian)
684: function setWhitelistGuardian(address _account) external override onlyGov {
685: address _oldGuardian = whitelistGuardian;
686: whitelistGuardian = _account;
688: emit WhitelistGuardianSet(_oldGuardian, whitelistGuardian);
[64, 65, 67, 68, 85, 86, 102, 169, 170, 207, 208, 215, 216, 358, 368, 369, 372, 373, 465, 470, 471, 472, 555, 557, 559, 560, 572, 573, 575, 576, 668, 669, 670, 671, 673, 674, 675, 677, 681, 682, 684, 685, 686, 688]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
62: /// @notice Thrown when trying to cancel a whitelisted proposer's proposal
63: error GovernorCharlie_WhitelistedProposer();
123: /// @notice Stores the expiration of account whitelist status as a timestamp
124: function whitelistAccountExpirations(address _account) external returns (uint256 _expiration);
126: /// @notice Address which manages whitelisted proposals and whitelist accounts
127: function whitelistGuardian() external view returns (address _guardian);
141: function maxWhitelistPeriod() external view returns (uint256 _maxWhitelistPeriod);
217: * @notice whitelistGuardian can cancel proposals from whitelisted addresses
284: * @notice View function which returns if an account is whitelisted
286: * @return _isWhitelisted If the account is whitelisted
288: function isWhitelisted(address _account) external view returns (bool _isWhitelisted);
339: * @notice Governance function for setting the whitelist expiration as a timestamp
340: * for an account. Whitelist status allows accounts to propose without meeting threshold
341: * @param _account Account address to set whitelist expiration for
342: * @param _expiration Expiration for account whitelist status as timestamp (if now < expiration, whitelisted)
344: function setWhitelistAccountExpiration(address _account, uint256 _expiration) external;
347: * @notice Governance function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from whitelisted addresses
348: * @param _account Account to set whitelistGuardian to (0x0 to remove whitelistGuardian)
350: function setWhitelistGuardian(address _account) external;
[62, 63, 123, 124, 126, 127, 141, 217, 284, 286, 288, 339, 340, 341, 342, 344, 347, 348, 350]
The SPDX identifier should be on the very first line of each source file.
There is 1 instance of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
1: // solhint-disable max-states-count
[1]
Avoid typos, and proper nouns should be capitalized.
There are 54 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
// @audit amph
224: // calculate the amph available for this cliff
// @audit amph
227: // check if the amount of amph to mint surpasses the cliff
File: core/solidity/contracts/core/USDA.sol
// @audit ampleforth
83: /// the calculations for deposit mimic the calculations done by mint in the ampleforth contract, simply with the susd transfer
// @audit gonsperfragment
169: // the gonbalances of the sender is in gons, therefore we must multiply the deposit amount, which is in fragments, by gonsperfragment
// @audit totalgons, gonsperfragment
173: // and totalgons of course is in gons, and so we multiply amount by gonsperfragment to get the amount of gons we must add to totalGons
// @audit gonsperfragment
190: // modify the gonbalances of the sender, subtracting the amount of gons, therefore amount * gonsperfragment
File: core/solidity/contracts/core/Vault.sol
// @audit liabilitiy
39: /// the vaultController in order to find the true liabilitiy
// @audit tokenv
101: /// In this case the user's balance isn't staked so we stake the amount + his balance for the specific tokenv
// @audit crv, cvx
162: /// @dev Transfers a percentage of the crv and cvx rewards to claim AMPH tokens
File: core/solidity/contracts/core/VaultController.sol
// @audit crv
382: /// @param _poolId The convex pool id of a crv lp token
// @audit liabilty
593: // get the total USDA liability, equal to the interest factor * vault's base liabilty
// @audit explaination
630: // see _liquidationMath for more detailed explaination of the math
// @audit explaination
657: // see _liquidationMath for more detailed explaination of the math
// @audit registed, indivuduals
867: // loop over each registed token, adding the indivuduals ltv to the total ltv of the vault
// @audit registed, indivuduals
895: // loop over each registed token, adding the indivuduals ltv to the total ltv of the vault
// @audit timedifference
945: // this is equal to (timedifference * (curve value) / (seconds in a year)) * (interest factor)
// @audit accured
960: // valueAfter - valueBefore is now equal to the true amount of interest accured
[382, 593, 630, 657, 867, 895, 945, 960]
File: core/solidity/contracts/core/WUSDA.sol
// @audit exusdae
21: * For exusdae: 100K wUSDA => 1% of the usda market cap
[21]
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit chaid
725: /// @notice Returns the chaid id of the blockchain
[725]
File: core/solidity/contracts/periphery/CurveMaster.sol
// @audit labled
18: /// @notice Returns the value of curve labled _tokenAddress at _xValue
[18]
File: core/solidity/contracts/utils/UFragments.sol
// @audit xn
37: // f(x0) + f(x1) + ... + f(xn) is not always equal to f(x0 + x1 + ... xn).
[37]
File: core/solidity/interfaces/core/IUSDA.sol
// @audit ampleforth
132: /// the calculations for deposit mimic the calculations done by mint in the ampleforth contract, simply with the susd transfer
[132]
File: core/solidity/interfaces/core/IVault.sol
// @audit crv, cvx
191: /// @dev Transfers a percentage of the crv and cvx rewards to claim AMPH tokens
[191]
File: core/solidity/interfaces/core/IVaultController.sol
// @audit addres
33: * @param _tokenAddress The addres of the erc20 token
34: * @param _ltv The loan to value amount of the erc20
35: * @param _oracleAddress The address of the oracle to use to fetch the price
// @audit addres, crv
45: * @param _tokenAddress The addres of the erc20 token to update
46: * @param _ltv The new loan to value amount of the erc20
47: * @param _oracleAddress The new address of the oracle to use to fetch the price
48: * @param _liquidationIncentive The new liquidation penalty for the token
49: * @param _cap The maximum amount that can be deposited
50: * @param _poolId The convex pool id of a crv lp token
// @audit amounnt
78: * @param _borrowAmount The amounnt that was borrowed
// @audit crv
196: /// @notice Thrown when registering a crv lp token with wrong address
// @audit targetted
361: /// @return _vaultAddress The address of the targetted vault
// @audit crv
556: /// @param _poolId The convex pool id of a crv lp token
[33-35, 45-50, 78, 196, 361, 556]
File: core/solidity/interfaces/governance/IGovernorCharlie.sol
// @audit arity
35: /// @notice Thrown when there is information arity mismatch
[35]
File: core/solidity/interfaces/periphery/ICurveMaster.sol
// @audit labled
51: /// @notice Returns the value of curve labled _tokenAddress at _xValue
[51]
File: core/solidity/interfaces/periphery/IOracleRelay.sol
// @audit underlyings
7: /// @notice Emited when the underlyings are different in the anchored view
[7]
File: core/solidity/contracts/periphery/oracles/AnchoredViewRelay.sol
// @audit chainlink
71: /// @notice Compares the main value (chainlink) to the anchor value (uniswap v3)
[71]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
// @audit chainlink
57: // Get the prices from chainlink and add 10 decimals
[57]
File: core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol
// @audit chainlink
9: /// @notice Oracle that wraps a chainlink oracle.
// @audit chainlink
15: /// @notice The chainlink aggregator
// @audit chainlink
29: /// @param _feedAddress The address of chainlink feed
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
// @audit chainlink
8: /// @dev Oracle that wraps a chainlink oracle
// @audit chainlink
11: /// @notice The chainlink aggregator
// @audit chainlink
14: /// @notice The chainlink aggregator for the base token
// @audit chainlink
18: /// @param _feedAddress The address of chainlink feed
// @audit chainlink
19: /// @param _baseFeedAddress The address of chainlink feed for the base token
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
// @audit inmutable
7: /// @notice The inmutable curve registry
[7]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
// @audit crv
9: /// @notice Oracle Relay for crv lps
// @audit crv
14: /// @notice The pool of the crv lp token
// @audit lastest
40: /// @notice Calculates the lastest exchange rate
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
// @audit chainlink
54: // Get the prices from chainlink and add 10 decimals
// @audit qbrt
79: // discount: uint256 = max(g**2 / 10**18 * a, 10**34) # handle qbrt nonconvergence
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
// @audit lookback
22: /// @notice The lookback for the oracle
// @audit twap
38: /// @param _lookback How many seconds to twap for
// @audit chainlink
39: /// @param _poolAddress The address of chainlink feed
// @audit twap
72: /// @param _seconds How many seconds to twap for
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
// @audit ethusdc
15: /// @param _ethOracle The uniswap oracle for ethusdc
// @audit twap
16: /// @param _lookback How many seconds to twap for
A 100% test coverage is not foolproof, but it helps immensely in reducing the amount of bugs that may occur.
This includes: large code bases, or code with lots of inline-assembly, complicated math, or complicated interactions between multiple contracts.
Invariant fuzzers such as Echidna require the test writer to come up with invariants which should not be violated under any circumstances, and the fuzzer tests various inputs and function calls to ensure that the invariants always hold.
Even code with 100% code coverage can still have bugs due to the order of the operations a user performs, and invariant fuzzers may help significantly.
Some lines use // x
and some use //x
. The instances below point out the usages that don't follow the majority, within each file.
There are 38 instances of this issue.
Expand findings
File: core/solidity/contracts/core/USDA.sol
16: /// @notice USDA token contract, handles all minting/burning of usda
[16]
File: core/solidity/contracts/core/Vault.sol
333: //use current supply to gauge cliff
334: //this will cause a bit of overflow into the next cliff range
335: //but should be within reasonable levels.
336: //requires a max supply check though
338: //mint if below total cliffs
340: //for reduction% take inverse of current cliff
342: //reduce
345: //supply cap check
[333, 334, 335, 336, 338, 340, 342, 345]
File: core/solidity/contracts/core/VaultController.sol
20: /// @notice Controller of all vaults in the USDA borrow/lend system
286: //push new vault ID onto mapping
726: //require that the vault is not solvent
748: //require that the vault is not solvent
791: //Cannot liquidate more than is necessary to make vault over-collateralized
796: //Cannot liquidate more collateral than there is in the vault
865: //solhint-disable-next-line code-complexity
893: //solhint-disable-next-line code-complexity
956: // this should save ~5000 gas/call
[20, 286, 726, 748, 791, 796, 865, 893, 956]
File: core/solidity/contracts/governance/GovernorCharlie.sol
207: //whitelist can't make emergency
215: //whitelist can only make optimistic proposals
734: // solium-disable-next-line security/no-block-members
File: core/solidity/contracts/utils/ThreeLines0_100.sol
70: /// @notice linear interpolation, calculates g(x) = (_rise/_run)x+b
[70]
File: core/solidity/contracts/utils/UFragments.sol
85: // https://eips.ethereum.org/EIPS/eip-2612
99: //set og initial values
103: _gonBalances[address(0x0)] = _totalGons; //send starting supply to a burner address so _totalSupply is never 0
File: core/solidity/interfaces/periphery/IOracleRelay.sol
27: /// @return _type the type (Chainlink/Uniswap/Price)
[27]
File: core/solidity/contracts/periphery/oracles/CbEthEthOracle.sol
10: /// @notice Oracle Relay for the cbETH/ETH pool
15: /// @notice The oracle relay for the cbETH/ETH price
18: /// @notice The oracle relay for the ETH/USD price
File: core/solidity/contracts/periphery/oracles/ChainlinkTokenOracleRelay.sol
7: /// @notice This oracle is for tokens that don't have a USD pair but do have a wETH/ETH pair
[7]
File: core/solidity/contracts/periphery/oracles/TriCrypto2Oracle.sol
9: /// @notice Oracle Relay for the TriCrypto pool (USDT/WBTC/WETH)
17: /// @notice The oracle relay for the WBTC/USD price
20: /// @notice The oracle relay for the ETH/USD price
23: /// @notice The oracle relay for the USDT/USD price
76: // # ((A/A0) * (gamma/gamma0)**2) ** (1/3)
File: core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol
40: /// @param _quoteTokenIsToken0 The marker for which token to use as quote/base in calculation
[40]
File: core/solidity/contracts/periphery/oracles/UniswapV3TokenOracleRelay.sol
11: /// @notice The oracle for eth/usdc
34: //get price of eth to convert _priceInEth to USD terms
Consider adding some comments on critical state variables to explain what they are supposed to do: this will help for future code reviews.
There are 20 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
15: uint256 internal constant _BASE = 1 ether;
[15]
File: core/solidity/contracts/core/USDA.sol
21: bytes32 public constant VAULT_CONTROLLER_ROLE = keccak256('VAULT_CONTROLLER');
23: EnumerableSet.AddressSet internal _vaultControllers;
File: core/solidity/contracts/utils/ThreeLines0_100.sol
21: int256 public immutable R0;
22: int256 public immutable R1;
23: int256 public immutable R2;
24: int256 public immutable S1;
25: int256 public immutable S2;
File: core/solidity/contracts/utils/UFragments.sol
61: uint256 private constant DECIMALS = 18;
62: uint256 private constant MAX_UINT256 = 2 ** 256 - 1;
63: uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 1 * 10 ** DECIMALS;
72: uint256 public _totalSupply;
73: uint256 public _gonsPerFragment;
74: mapping(address => uint256) public _gonBalances;
76: string public name;
77: string public symbol;
78: uint8 public constant decimals = uint8(DECIMALS);
87: bytes32 public constant EIP712_DOMAIN =
88: keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
89: bytes32 public constant PERMIT_TYPEHASH =
90: keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
[61, 62, 63, 72, 73, 74, 76, 77, 78, 87-88, 89-90]
File: core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol
9: uint256 public virtualPrice;
[9]
Large and/or complex functions should have more comments to better explain the purpose of each logic step.
There is 1 instance of this issue.
File: core/solidity/contracts/governance/GovernorCharlie.sol
159: function _propose(
[159]
Low-level languages like assembly should require extensive documentation and comments to clarify the purpose of each instruction.
There is 1 instance of this issue.
File: core/solidity/contracts/utils/UFragments.sol
165: assembly {
[165]
Some functions have an incomplete NatSpec: add a @param
notation to describe the function parameters to improve the code documentation.
There are 19 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
// @audit missing _total, _fraction
150: /// @dev Receives a total and a percentage, returns the amount equivalent of the percentage
151: function _totalToFraction(uint256 _total, uint256 _fraction) internal pure returns (uint256 _amount) {
// @audit missing _sender, _vaultId, _cvxTotalRewards, _crvTotalRewards
156: /// @dev Doesn't revert but returns 0 so the vault contract doesn't revert on calling the claim function
157: /// @dev Returns the claimable amount of AMPH, also the CVX and CRV the contract will take from the user
158: function _claimable(
// @audit missing _distributedAmph
193: /// @dev Returns the rate of the token, denominated in 1e6
194: function _getRate(uint256 _distributedAmph) internal pure returns (uint256 _rate) {
// @audit missing _tokenAmountToSend
201: /// @dev Returns how much AMPH would be minted given a token amount
202: function _calculate(uint256 _tokenAmountToSend) internal view returns (uint256 _amphAmount) {
// @audit missing _distributedAmph
248: /// @dev Returns the current cliff, it will round down but is on purpose
249: function _getCliff(uint256 _distributedAmph) internal pure returns (uint256 _cliff) {
[150-151, 156-158, 193-194, 201-202, 248-249]
File: core/solidity/contracts/core/USDA.sol
// @audit missing _pauser
61: /// @notice Sets the pauser for both USDA and VaultController
62: /// @dev The pauser is a separate role from the owner
63: function setPauser(address _pauser) external override onlyOwner {
// @audit missing _susdAmount, _target
100: /// @notice Business logic to deposit sUSD and mint USDA for the caller
101: function _deposit(uint256 _susdAmount, address _target) internal paysInterest whenNotPaused {
136: /// @notice Withdraw sUSD by burning USDA
137: /// @dev This function is effectively just withdraw, but we calculate the amount for the _target
138: /// @param _target should obtain 1 sUSD for every 1 USDA burned from caller
139: /// @param _susdWithdrawn The amount os sUSD withdrawn
140: function withdrawAllTo(address _target) external override returns (uint256 _susdWithdrawn) {
// @audit missing _susdAmount, _target
146: /// @notice business logic to withdraw sUSD and burn USDA from the caller
147: function _withdraw(uint256 _susdAmount, address _target) internal paysInterest whenNotPaused {
// @audit missing _target, _amount
166: /// @dev mint a specific `amount` of tokens to the `target`
167: function _mint(address _target, uint256 _amount) internal {
// @audit missing _target, _amount
187: /// @dev burn a specific `amount` of tokens from the `target`
188: function _burn(address _target, uint256 _amount) internal {
[61-63, 100-101, 136-140, 146-147, 166-167, 187-188]
File: core/solidity/contracts/core/Vault.sol
// @audit missing _token, _booster, _amount, _poolId
319: /// @dev Internal function for depositing and staking on convex
320: function _depositAndStakeOnConvex(address _token, IBooster _booster, uint256 _amount, uint256 _poolId) internal {
[319-320]
File: core/solidity/contracts/core/VaultController.sol
// @audit missing _poolId
325: /// @notice Register a new token to be used as collateral
326: /// @param _tokenAddress The address of the token to register
327: /// @param _ltv The ltv of the token, 1e18=100%
328: /// @param _oracleAddress The address of oracle to fetch the price of the token
329: /// @param _liquidationIncentive The liquidation penalty for the token, 1e18=100%
330: /// @param _cap The maximum amount to be deposited
331: function registerErc20(
// @audit missing _amount, _token, _increase
1014: /// @notice Modifies the total deposited in the protocol
1015: function _modifyTotalDeposited(uint256 _amount, address _token, bool _increase) internal {
File: core/solidity/contracts/governance/AmphoraProtocolToken.sol
// @audit missing _dst, _rawAmount
19: /// @notice Mint a specified amount of tokens to a specified address
20: function mint(address _dst, uint256 _rawAmount) public onlyOwner {
[19-20]
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit missing _proposalId, _support, _v, _r, _s
503: /**
504: * @notice Cast a vote for a proposal by signature
505: * @dev External override function that accepts EIP-712 signatures for voting on proposals.
506: */
507: function castVoteBySig(uint256 _proposalId, uint8 _support, uint8 _v, bytes32 _r, bytes32 _s) external override {
[503-507]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
// @audit missing _aggregator
10: /// @notice Returns the current price from the aggregator
11: function getCurrentPrice(AggregatorV2V3Interface _aggregator) internal view returns (uint256 _price) {
[10-11]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
// @audit missing _crvPool
11: /// @notice Returns the lp address of the curve pool
12: function _getLpAddress(address _crvPool) internal view returns (address _lpAddress) {
[11-12]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
// @audit missing _underlying
18: /// @notice set the underlying address
19: function _setUnderlying(address _underlying) internal {
[18-19]
Some functions have an incomplete NatSpec: add a @return
notation to describe the function return value to improve the code documentation.
There are 13 instances of this issue.
Expand findings
File: core/solidity/contracts/core/AMPHClaimer.sol
// @audit missing @return
150: /// @dev Receives a total and a percentage, returns the amount equivalent of the percentage
151: function _totalToFraction(uint256 _total, uint256 _fraction) internal pure returns (uint256 _amount) {
// @audit missing @return
156: /// @dev Doesn't revert but returns 0 so the vault contract doesn't revert on calling the claim function
157: /// @dev Returns the claimable amount of AMPH, also the CVX and CRV the contract will take from the user
158: function _claimable(
// @audit missing @return
193: /// @dev Returns the rate of the token, denominated in 1e6
194: function _getRate(uint256 _distributedAmph) internal pure returns (uint256 _rate) {
// @audit missing @return
201: /// @dev Returns how much AMPH would be minted given a token amount
202: function _calculate(uint256 _tokenAmountToSend) internal view returns (uint256 _amphAmount) {
// @audit missing @return
248: /// @dev Returns the current cliff, it will round down but is on purpose
249: function _getCliff(uint256 _distributedAmph) internal pure returns (uint256 _cliff) {
[150-151, 156-158, 193-194, 201-202, 248-249]
File: core/solidity/contracts/core/USDA.sol
// @audit missing @return
126: /// @notice Withdraw sUSD by burning USDA
127: /// @dev The caller should obtain 1 sUSD for every 1 USDA
128: /// @dev This function is effectively just withdraw, but we calculate the amount for the sender
129: /// @param _susdWithdrawn The amount os sUSD withdrawn
130: function withdrawAll() external override returns (uint256 _susdWithdrawn) {
// @audit missing @return
136: /// @notice Withdraw sUSD by burning USDA
137: /// @dev This function is effectively just withdraw, but we calculate the amount for the _target
138: /// @param _target should obtain 1 sUSD for every 1 USDA burned from caller
139: /// @param _susdWithdrawn The amount os sUSD withdrawn
140: function withdrawAllTo(address _target) external override returns (uint256 _susdWithdrawn) {
File: core/solidity/contracts/governance/GovernorCharlie.sol
// @audit missing @return
713: /// @notice Returns the timelock address
714: /// @param _timelock The timelock address
715: function timelock() external view override returns (address _timelock) {
[713-715]
File: core/solidity/contracts/periphery/oracles/ChainlinkStalePriceLib.sol
// @audit missing @return
10: /// @notice Returns the current price from the aggregator
11: function getCurrentPrice(AggregatorV2V3Interface _aggregator) internal view returns (uint256 _price) {
[10-11]
File: core/solidity/contracts/periphery/oracles/CurveRegistryUtils.sol
// @audit missing @return
11: /// @notice Returns the lp address of the curve pool
12: function _getLpAddress(address _crvPool) internal view returns (address _lpAddress) {
[11-12]
File: core/solidity/contracts/periphery/oracles/OracleRelay.sol
// @audit missing @return
23: /// @dev Most oracles don't require a state change for pricing, for those who do, override this function
24: function currentValue() external virtual returns (uint256 _currentValue) {
[23-24]
File: core/solidity/contracts/periphery/oracles/StableCurveLpOracle.sol
// @audit missing @return
40: /// @notice Calculates the lastest exchange rate
41: function _get() internal view returns (uint256 _value) {
// @audit missing @return
56: /// @notice returns the updated virtual price for the pool
57: function _getVirtualPrice() internal view virtual returns (uint256 _value) {
Consider the use of a custom error
, as it leads to a cheaper deploy cost and run time cost. The run time cost is only relevant when the revert condition is met.
There are 7 instances of this issue.
File: core/solidity/contracts/utils/UFragments.sol
52: require(msg.sender == monetaryPolicy);
324: require(block.timestamp <= _deadline);
333: require(_owner == ecrecover(_digest, _v, _r, _s));
File: core