Peer review of Raft Finance contracts performed by Antonio Viggiano on June 21, 2023 and June 22, 2023.
v1.0..master
(i.e.,25abf14da8cbb233255ea4641ea098f5f8f04fed..d5ca8febd9b7f33e1a3ad1eff1f2ae1d9dcd5b5f
)- Files under
contracts/
- [L-01] In
PositionManager.sol
, the functionredeemCollateral
should calculate theminimumCollateral
parameter aslowTotalDebt.divUp(price)
, and notlowTotalDebt.divDown(price)
, as this is the minimum collateral required to completely redeem, so it requires rounding up - [L-02] In
FlashLoanLiquidator.sol
, the contract contains hardcoded constants that could be passed in as constructor or function arguments, such as the address for theIPoolAddressesProvider
and theTARGET_CR
. In particular, the hardcodedTARGET_CR
means the liquidator will not optimize their returns, as the flashloaned collateral might be more than what's necessary to pay the position's debt (higherpremium
). - [L-03] In
PositionManagerWETH.sol
, mistakenlymsg.value
sent to contract will be trapped ifisCollateralIncrease && collateralChange > 0
check does not pass (e.g. ifcollateralChange
is zero butmsg.value
is not zero). As a recommendation, themsg.value
check could be moved to the beginning of the function. [L-04]- [L-05] In
PositionManagerWrappedCollateralToken.sol
, users can sweep excesswrappedCollateralToken
trapped there by mistake due toredeemCollateral
transfering the whole contract's balance. A possible solution would be to haveIPositionManager.redeemCollateral
return the actual collateral redeemed to the caller. - [L-06] In
PositionManagerWrappedCollateralToken.sol
, there are unchecked return values of_underlyingCollateralToken.transferFrom
(useSafeERC20.safeTransferFrom
or manually validate collateral token contracts to guarantee that they revert on failure) - [I-01] In
PositionManagerStETH.sol
andOneStepLeverageStETH.sol
, the information emitted in events might not be sufficient for off-chain monitoring systems. The eventsStETHPositionChanged
andStETHLeveragedPositionChange
do not take into account the actual values changed returned by thePositionManager
. - [I-02] In
PositionManager.sol
, there is a redundant comparison to triggerTotalCollateralCannotBeLowerThanMinCollateral
, sincex == 0 || x < POSITIVE
can be simplified byx < POSITIVE
- In
SplitLiquidationCollateral.sol
, [I-03]collateralToSentToLiquidator
now returnstotalCollateral
, which effectively sets the liquidation reward as 100%. Further analysis (see here) should be performed in order to properly assess how this change will impact the protocol cryptoeconomic incentives, comparing it to other protocols such as AAVE or Compound. - [I-04] In
FlashLoanLiquidator.sol
, there is an unnecessaryrToken.approve
to own token address on constructor: this is only required when performing a R token flashmint, such as inFlashMintLiquidator
orOneStepLeverage
- [I-05] In
WrappedCollateralToken
, there is missing input validation on setter functions [U-01] Unclear motivation behind the- After creating a unit test for the hyphothetical scenario where a liquidation would leave the protocol with collateral below the minimum debt value, I was not able to validate this case, asTotalDebtCannotBeLowerThanMinDebt error
liquidate
already prevents the last position from being liquidated, which serves a similar purpose asTotalCollateralCannotBeLowerThanMinCollateral
[U-02]- [U-03] In
ChainlinkPriceOracleRETH.sol
, calculating the price A/C through A/B and B/C require some additional considerations.In particular, taking into account the difference in price feed decimals (rETH/ETH 18 decimals vs ETH/USD 8 decimals)(_formatPrice
already does that). The difference in deviation between rETH/ETH (2%) and ETH/USD (0.5%). The difference in heartbeat/timeout between rETH/ETH (24 hours) and ETH/USD (1 hour). The impact of the deviation of ETH/USD on the final rETH/USD price (it should "compound", i.e.,deviation(A/C) = deviation(A,B) * deviation(B,C))
). The fact that Tellor does not seem to have a rETH/ETH or rETH/USD price feed, so thePriceFeed
should be deployed with the same address for both primary and secondary. - [U-04] In
ERC20Indexable.sol
, it is unclear ifmint
andburn
should both round up for the Raft debt token and collateral token. Generally speaking, when considering rounding errors, user's losses should be always be rounded up and gains always rounded down (see "Keep the change" rule of thumb by Runtime Verification). This means the debt token should always round up on mint and down on burn. The collateral token should have the opposite logic: it should round down onmint
, and up on burn. A further research could be carried out to analyze the impact of these rounding errors in the context of the protocol.
Severity | Description |
---|---|
H | High |
M | Medium |
L | Low |
I | Informational |
U | Undefined |
N/A | Not Applicable |
- Review changes
v1.0..master
commit by commit - Review full diff side by side
- Review codebase as a whole at the updated version
Commit hash | Description | Findings |
---|---|---|
4ac809e |
Add Certora Prover rules | [N/A] Not in scope |
64d170d |
Add events to PositionManagerStETH.sol |
[I-01] Information in StETHPositionChanged event might not be sufficient for off-chain monitoring systems, as stETHCollateralChange is converted to wstETHCollateralChange , which is the actual value used by IPositionManager to change the position |
bd2bd4f |
Add new error to disallow redeeming collateral in a way that the system would be left with a total collateral value below the minimum debt value | [I-02] Redundant comparison to trigger TotalCollateralCannotBeLowerThanMinCollateral , since `x == 0 |
18d79fb |
Add events to OneStepLeverageStETH.sol |
[I-01] Information in StETHLeveragedPositionChange might not be sufficient for off-chain monitoring systems, as stETHCollateralChange is converted to wstETHCollateralChange , which is the actual value used by _manageLeveragedPosition to change the leveraged position |
28f7a67 |
Change SplitLiquidationCollateral calculation for collateral given to liquidator. The documentation has been updated to match the code implementation. |
[I-03] collateralToSentToLiquidator now returns totalCollateral , which effectively sets the liquidation reward as 100%. Further analysis (see here) should be performed in order to properly assess how this change will impact the protocol cryptoeconomic incentives, comparing it to other protocols such as AAVE or Compound. |
5f60502 |
Generalize flash liquidations interface. Implement new FlashLoanLiquidator interface that utilizes AAVE for flash loans. |
[N/A] Not in scope [L-02] FlashLoanLiquidator contains hardcoded constants that could be passed in as constructor or function arguments, such as the address for the IPoolAddressesProvider and the TARGET_CR . In particular, the hardcoded TARGET_CR means the liquidator will not optimize their returns, as the flashloaned collateral might be more than what's necessary to pay the position's debt (higher premium ). [I-04] Unnecessary rToken.approve to own token address on FlashLoanLiquidator constructor: this is only required when performing a R-token flashloan, such as in FlashMintLiquidator or OneStepLeverage |
93669c1 |
Add support for 1inch Router v5 Balancer | [N/A] Not in scope |
226ea50 |
Add WETH position manager | managePositionETH does not use return values actualCollateralChange and actualDebtChange of managePosition [L-03] Mistakenly msg.value sent to contract will be trapped if isCollateralIncrease && collateralChange > 0 check does not pass (e.g. if collateralChange is zero but msg.value is not zero) PositionManager permitSugnature.token and collateralChange equals 0, making PermitHelper.applyPermit no-op and the debt increase succeed, but neither the user or the attacker should benefit from this) |
fdcaad5 |
Refactor oracle contracts. Functions moved around and contracts generalized | [N/A] |
a35ad63 |
Add WETH oracle fetching data from ETH/USD data feeds. Code generalized | [N/A] |
7cac57e |
Refactor oracle contracts to use immutable instead of constant variables for query ID. Functions moved around | [N/A] |
308568b |
Fix PositionManagerWETH to use return values from managePosition |
|
5a60456 |
Add wrapped collateral token contract | [I-05] Missing input validation on setter functions of WrappedCollateralToken |
85464a8 |
Add position manager for wrapped collateral token. Logic derived from existing position managers | [N/A] |
cb346f2 |
Refactor oracle contracts. Functions moved around | [N/A] |
6930cae |
Add redeemCollateral in PositionManagerWrappedCollateralToken |
[L-05] Users can sweep excess wrappedCollateralToken in PositionManagerWrappedCollateralToken trapped there by mistake due to redeemCollateral transfering the whole contract's balance. A possible solution would be to have IPositionManager.redeemCollateral return the actual collateral redeemed to the caller. [L-06] Unchecked return value of _underlyingCollateralToken.transferFrom (use SafeERC20.safeTransferFrom or manually validate collateral token contracts to guarantee that they revert on failure) |
a8d1446 |
Change oracle timeout from constant to immutable. Functions moved around | [N/A] |
7b8e8bc |
Add rETH oracles | [U-03] Calculating price A/C through A/B and B/C require some additional considerations. _formatPrice already does that). The difference in deviation between rETH/ETH (2%) and ETH/USD (0.5%). The difference in heartbeat/timeout between rETH/ETH (24 hours) and ETH/USD (1 hour). The impact of the deviation (ignored here) of ETH/USD affects the rETH/USD price (it should "compound", i.e., deviation(A/C) = deviation(A,B) * deviation(B,C)) ). The fact that Tellor does not seem to have a rETH/ETH or rETH/USD price feed, so the PriceFeed should be deployed with the same address for both primary and secondary. |
4441ce8 |
Rename files | [N/A] |
0704ff8 |
Support wrapped collateral position manager for WETH | [N/A] |
7e35630 |
Add error when WETH collateral change amount does not match msg.value |
[L-03] Not fixed. msg.value check should be moved to the beginning of the function. |
805bc2c |
Support wrapped collateral position manager for stETH | [N/A] |
96affd4 |
Refactor WrappedCollateralToken balance checks |
|
d5ca8fe |
Add tests | [N/A] |