Platform: Code4rena
Start Date: 28/11/2022
Pot Size: $192,500 USDC
Total HM: 33
Participants: 106
Period: 11 days
Judge: LSDan
Total Solo HM: 15
Id: 186
League: ETH
Rank: 74/106
Findings: 1
Award: $103.92
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x4non, 0x52, 0xAgro, 0xNazgul, 0xSmartContract, 0xackermann, 9svR6w, Awesome, Aymen0909, B2, BRONZEDISC, Bnke0x0, Deekshith99, Deivitto, Diana, Dravee, HE1M, Jeiwan, Kaiziron, KingNFT, Lambda, Mukund, PaludoX0, RaymondFam, Rolezn, Sathish9098, Secureverse, SmartSek, __141345__, ahmedov, ayeslick, brgltd, cccz, ch0bu, chrisdior4, cryptonue, cryptostellar5, csanuragjain, datapunk, delfin454000, erictee, gz627, gzeon, helios, i_got_hacked, ignacio, imare, jadezti, jayphbee, joestakey, kankodu, ksk2345, ladboy233, martin, nadin, nicobevi, oyc_109, pashov, pavankv, pedr02b2, pzeus, rbserver, ronnyx2017, rvierdiiev, shark, unforgiven, xiaoming90, yjrwkk
103.9175 USDC - $103.92
There need some address zero check to protect user from accidently losing funds in the WETHGateway
contract.
function repayETH(uint256 amount, address onBehalfOf)
The onBehalfOf
address should be checked if it is zero.
function repayETH(uint256 amount, address onBehalfOf)
The onBehalfOf
address should be checked if it is zero.
function withdrawETHWithPermit( uint256 amount, address to, uint256 deadline, uint8 permitV, bytes32 permitR, bytes32 permitS ) external override nonReentrant {
The to
address should be checked if it is zero.
There are three locations:
Revert string should clearly describe the revert reason.
receive() external payable { //only contracts can send ETH to the core require(msg.sender.isContract(), "22"); }
ParaReentrancyGuard
storage variable isn't initialized in PoolApeStaking
and PoolMarketplace
.The construtor in ParaReentrancyGuard
was commentted out.
// constructor() { // _status = _NOT_ENTERED; // }
This indicates that contract inherited from ParaReentrancyGuard
must initialize the _status
variable itself. The PoolCore.sol
contract initialize it in the initialize
function
function initialize(IPoolAddressesProvider provider) external virtual initializer { require( provider == ADDRESSES_PROVIDER, Errors.INVALID_ADDRESSES_PROVIDER ); RGStorage storage rgs = rgStorage(); rgs._status = _NOT_ENTERED; }
But we didn't find it is initialized like PoolCore
do in the PoolApeStaking
and PoolMarketplace
contract.
The impact is that ParaReentrancyGuard
's usage doesn't follow design spec, which could result in unexpected behavior in the future.
Either
_status
variable in the construtor of ParaReentrancyGuard
or_status
variable like PoolCore
do in the PoolApeStaking
and PoolMarketplace
contract.msg.value > paybackAmount
In the repayETH
function, paybackAmount
eth will be deposit to WETH contract to get paybackAmount
weth back.
WETH.deposit{value: paybackAmount}();
And then repay msg.value
to pool
IPool(pool).repay(address(WETH), msg.value, onBehalfOf);
Here if msg.value > paybackAmount
, IPool(pool).repay
will revert due to insufficient weth.
change
IPool(pool).repay(address(WETH), msg.value, onBehalfOf);
to
IPool(pool).repay(address(WETH), paybackAmount, onBehalfOf);
#0 - c4-judge
2023-01-25T16:26:18Z
dmvt marked the issue as grade-b