Skip to content

Instantly share code, notes, and snippets.

@0xcuriousapple
Last active September 1, 2023 19:00
Show Gist options
  • Save 0xcuriousapple/d5777b11dc6c109dcb207150e8bb3b56 to your computer and use it in GitHub Desktop.
Save 0xcuriousapple/d5777b11dc6c109dcb207150e8bb3b56 to your computer and use it in GitHub Desktop.
Raft-4

Raft Finance

ChaiPSM Module

Prepared by: Curiousapple, Independent Security Researcher

Duration: 2 days, Aug 31, 2023

About

In their own words, "Raft is a governance-minimized, decentralized protocol that allows people to generate R (a USD stablecoin) by depositing capital-efficient collateral."
This audit is for their ChaiPSM Module.
It serves to swap reserve token (DAI) to and from R at 1:1 rate (minus the fee).
Two main user facing methods are BuyR() and BuyReserveToken()

BuyR()

image

Reverse of above for BuyReserveToken()

  1. User sends "X" R
  2. Contract sends R to position manager back and gets "X" ChaiPSM back
  3. Contract burns "X" ChaiPSM.
  4. Contract deducts fee, withdraws "X-fee" amount of dai from chai and sends that to the user

Curiousapple 🦇

Abhishek Vispute, known online as 'Curiousapple', is an independent smart contract security researcher. Previously, he served as a lead smart contract auditor at Macro and is currently working independently.
His auditing experience covers diverse set of protocols, including DeFi, Bridges, NFTs, DAOs, and Games, in all of which he has discovered severe bugs.
You can find his previous work and contact here

Scope

Pull Request: PSM plus ChaiPSM
Contracts:

  1. contracts/PSM/BasePSM.sol
  2. contracts/PSM/ChaiPSM.sol
  3. contracts/PSM/ConstantPriceFeed.sol
  4. contracts/PSM/FixedFee.sol
  5. contracts/PSM/Lock.sol
  6. contracts/PSM/PSMSplitLiquidationCollateral.sol

Summary of Findings

No severe issues were found.

Acronym
QQuality
IInformational
ID Title Status
Q-01   Unnecessary Check of minReturn Ack
Q-02   Incorrect Comment inside ConstantPriceFeed Fixed
I-01   withdrawReserve(), recoverTokens(), and setFees() could allow the owner/treasury to withdraw more reserve tokens than the yield alone Ack
I-02   Impact of PSM on other position holders Ack
I-03   R will be soft-pegged to DAI Ack

Detailed Findings

[Q-01] Unnecessary Check of minReturn

The minReturn parameter is used in both the buyR() and buyReserveToken().
Its purpose is to allow users to specify the minimum amount of R or reserve token they should receive.
This is usually done to protect users against dynamic state changes, such as slippage.
However, in this case, the fees applied are fixed, so there won't be any change between transaction initiation and execution, unless Raft team updates the fee in between.
If fee updates are not regular and if big jumps are unlikely, minReturn parameter could be removed.

Recommendation

Consider removing the minReturn parameter from both buyR() and buyReserveToken() if fee updates are not regular and if big fee jumps are unlikely.

Status

Ack

Mijovic (Raft) : 
Regarding Q1, if we ever implement dynamic fees based on price oracles of reserve and R we might have a problem there. Also, we might build a fee for buying reserve based on the actual reserve in PSM. I know, we could just remove it and deploy new PSM with these features, but would try to do it without redeployment. LMK what do you think?

Curiousapple: 
makes sense

[Q-02] Incorrect Comment inside ConstantPriceFeed

/// @dev Price oracle to be used for peg stability module to mint R.
/// Returns constant price of 2 USD per token with 0 deviation.
contract ConstantPriceFeed is IPriceFeed, Lock {

/// Returns constant price of 2 USD per token with 0 deviation.
It should be "Returns constant price of 1 USD per token" instead.

Recommendation

Consider correcting the comment

Status

Fixed


[I-01] withdrawReserve(), recoverTokens(), and setFees() could allow the owner/treasury to withdraw more reserve tokens than the yield alone.

withdrawReserve:
The treasury or owner is expected to call withdrawReserve to collect the yield accrued on deposited DAI.
However, since there is no check on the amount passed, theoretically, withdrawal of more reserve tokens is also possible.

recoverTokens:
The same applies to recover tokens, as there is no check on the token passed, transfer of CHAI token from the PSM module is possible.

setFees:
Since there is no immutable check of the maximum on fees passed, fees could be set to any number < 100%.

Recommendation

There is no quick solution for the withdrawReserve() function.
Explicit on-chain accounting for yield accrued would be required to resolve it.
Solving the other two functions without solving withdrawReserve() is equivalent to solving none as well.
Hence, consider safeguarding the owner's address with all the best op-sec measures for now, until it is resolved.

Status

Ack

Mijovic (Raft): We are aware if this. Originally I implemented it so that only yield can be taken out. With allowing removal of more we allow divesrsification of reserves by swapping it and deploying new PSM. This will be governance decision.


[I-02] Impact of PSM on other position holders

Please note that,
users who have deposited DAI in exchange for R would not be guaranteed to receive DAI back if someone else with different underlying collateral uses the PSM for their R → DAI conversion.
Since redemptions are currently disabled, users of (DAI → R) cannot redeem $1 worth of other collateral either.
Their only option would be to sell in the open market.

The reverse of the scenario mentioned above becomes possible once redemptions are enabled for other collateral types.
If someone with R derived from the PSM module redeems different collateral, the initial position owner who had created that position using different collateral cannot fully exit all of their R using the position manager alone.
They would need to exit some R using the position manager and remaining using the PSM module or open market.

Status

Ack

Mijovic (Raft):
Redemptions are not going to be turned on ever. 
Soon we will move all positions to interest based borrowing

[I-03] R will be soft-pegged to DAI.

Since there are no liquidations in the case of ChaiPSM collateral,
if DAI depegs, there won't be equivalent collateral backing for a given R.
Since redemptions are disabled forever moving forward, this won't impact other collateral positions for the position manager.
However, this would have an impact on the market value of R, since R, derived from PSM, now has a lower equivalent value.
People who had minted R using PSM, would look to sell their R in the open market.

Status

Ack

Mijovic (Raft):
We are aware of this. 
And we also plan to launch different PSMs for different reserves. 
However, regarding soft peg to DAI, it is still true as most of our liquidity is paired with DAI anyway.

Disclaimer

curiousapple's review is limited to identifying potential vulnerabilities in the code. It does not investigate security practices, operational security, or evaluate the code relative to a standard or specification.
curiousapple makes no warranties, either express or implied, regarding the code's merchantability, fitness for a particular purpose, or that it's free from defects.
curiousapple will not be liable for any lost profits, business, contracts, revenue, goodwill, production, anticipated savings, loss of data, procurement costs of substitute goods or services, or any claim by any other party.
curiousapple will not be liable for any consequential, incidental, special, indirect, or exemplary damages, even if it has been advised of the possibility of such damages.
This review does not constitute investment advice, is not an endorsement, and is not a guarantee as to the absolute security of the project.
By deploying or using the code, users agree to use the code at their own risk.
curiousapple is not responsible for the content or operation of any third-party websites or software linked or referenced in the review, and shall have no liability for the use of such.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment