Platform: Code4rena
Start Date: 09/09/2022
Pot Size: $42,000 USDC
Total HM: 2
Participants: 101
Period: 3 days
Judge: hickuphh3
Total Solo HM: 2
Id: 161
League: ETH
Rank: 17/101
Findings: 1
Award: $38.41
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: GalloDaSballo
Also found by: 0x040, 0x1f8b, 0x4non, 0x52, 0x85102, 0xNazgul, 0xSky, 0xSmartContract, Aymen0909, Bnke0x0, CertoraInc, Chandr, Chom, CodingNameKiki, Deivitto, Diana, Funen, JC, Jeiwan, Junnon, KIntern_NA, Lambda, Mohandes, Noah3o6, Ocean_Sky, Picodes, R2, Randyyy, RaymondFam, ReyAdmirado, Rohan16, Rolezn, Samatak, Sm4rty, SnowMan, SooYa, StevenL, Tagir2003, Tointer, TomJ, Tomo, V_B, Waze, _Adam, __141345__, a12jmx, ajtra, ak1, asutorufos, bharg4v, bobirichman, brgltd, c3phas, cccz, cryptonue, cryptostellar5, cryptphi, csanuragjain, d3e4, datapunk, delfin454000, dipp, djxploit, durianSausage, erictee, fatherOfBlocks, gogo, got_targ, hansfriese, horsefacts, hyh, ignacio, innertia, izhuer, karanctf, ladboy233, leosathya, lucacez, lukris02, mics, oyc_109, pashov, pauliax, prasantgupta52, rbserver, ret2basic, rfa, robee, rokinot, rotcivegaf, rvierdiiev, sach1r0, scaraven, sikorico, simon135, smiling_heretic, sorrynotsorry, unforgiven, wagmi, yixxas
38.4075 USDC - $38.41
mint
to the PSM contractThe project README notes that the SimpleFeiDaiPSM
"should stay synced between the FEI and DAI supplies after each call to burnFeiHeld()
, assuming it is seeded with enough DAI to match the circulating supply."
However, it's possible to specify the SimpleFeiDaiPSM
contract itself as the to
address in a call to mint
, which will violate this assumption, leaving extra DAI locked in the contract once burnFeiHeld()
is called to burn the contract's FEI balance:
/// @notice mint `amountFeiOut` FEI to address `to` for `amountIn` underlying tokens /// @dev see getMintAmountOut() to pre-calculate amount out function mint( address to, uint256 amountIn, uint256 minAmountOut ) external returns (uint256 amountFeiOut) { amountFeiOut = amountIn; require(amountFeiOut >= minAmountOut, "SimpleFeiDaiPSM: Mint not enough out"); DAI.safeTransferFrom(msg.sender, address(this), amountIn); FEI.mint(to, amountFeiOut); emit Mint(to, amountIn, amountIn); }
Recommendation: Do not rely on the assumption that supply will remain synced between DAI and FEI in the PSM, since users may mint to the PSM or send FEI/DAI directly to the contract. Consider reverting if the to
address is the SimpleFeiDaiPSM
contract. (However, note that users might still transfer FEI to this contract directly, with a similar effect).
The temporary claim message used in MultiMerkleRedeemer
should be updated before deployment.
MultiMerkleRedeemer.sol#L52-L53
/// @notice The message to be signed by any users claiming on cTokens string public constant MESSAGE = "Sample message, please update.";
The Redeem
and Mint
events in SimpleFeiDaiPSM
are missing indexes for the caller address. It's probably useful to index these parameters to make it easy to filter and query events by caller address.
/// @notice event emitted upon a redemption event Redeem(address to, uint256 amountFeiIn, uint256 amountAssetOut); /// @notice event emitted when fei gets minted event Mint(address to, uint256 amountIn, uint256 amountFeiOut);
The SimpleFeiDaiPSM
includes several functions meant to make it as close as possible to the interface of the FixedPricePSM
:
// ---------------------------------------------------------------------------- // These view functions are meant to make this contract's interface // as similar as possible to the FixedPricePSM as possible. // ---------------------------------------------------------------------------- uint256 public constant mintFeeBasisPoints = 0; uint256 public constant redeemFeeBasisPoints = 0; address public constant underlyingToken = address(DAI); uint256 public constant getMaxMintAmountOut = type(uint256).max; bool public constant paused = false; bool public constant redeemPaused = false; bool public constant mintPaused = false;
However, these are not enforced at compile time. Consider extracting and using a Solidity interface to define these common methods and enforce this behavior. This is a safer pattern, since the compiler will check that the necessary methods are implemented.
The contract CoreRef.sol
is imported but unused in RariMerkleRedeemer
.
import "../../refs/CoreRef.sol";