Platform: Code4rena
Start Date: 05/01/2023
Pot Size: $90,500 USDC
Total HM: 55
Participants: 103
Period: 14 days
Judge: Picodes
Total Solo HM: 18
Id: 202
League: ETH
Rank: 34/103
Findings: 1
Award: $363.16
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0x1f8b, 0xAgro, 0xSmartContract, 0xackermann, 0xkato, Aymen0909, Bnke0x0, CloudX, IllIllI, PaludoX0, Rageur, Rahoz, RaymondFam, ReyAdmirado, Rolezn, SadBase, SaeedAlipoor01988, caventa, chaduke, chrisdior4, fatherOfBlocks, fs0c, kaden, nogo, pfapostol, shark, synackrst
363.1567 USDC - $363.16
• In the CollateralToken contract and in function liquidatorNFTClaim, we use param to get collateralId, then we use collateralId to get the desired auction from mapping and check that this auction is exist and ended.
But again, we check that the desired auction is matched with keccak256 hash value of the param.
This last computing is unnecessary because we used collateralId at L117 to get matched auction from mapping. The answer from mapping is unique and there cannot be mistakes. If there is a mistake, we should first check for matched auction and then check that matched auction exists and ends.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In the ClearingHouse contract, in 3 functions we duplicated code to check that msg.sender is address(ASTARIA_ROUTER.COLLATERAL_TOKEN()). We can create a modifier and use this modifier In functions to avoid code duplication.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In the CollateralToken, and function isValidOrder, we get orderHash, caller, offerer, and zoneHash as input.
We used orderHash and zoneHash to validate order but we don’t use offerer and caller in the function so we can remove them from the function as input.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In the CollateralToken, and function isValidOrderIncludingExtraData, we get orderHash, caller, order, priorOrderHashes, and criteriaResolvers as input.
We used orderHash and order to validate the order but we don’t use priorOrderHashes and caller and criteriaResolvers in the function so we can remove them from the function as input.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In the CollateralToken contract and function releaseToAddress, we check the owner of collateralId twice. By modifier and by code in the function body.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In PublicVault contract and function transferWithdrawReserve, there is a variable called currentWithdrawProxy, but the value is s.epochData[s.currentEpoch - 1].withdrawProxy;
To get currentWithdrawProxy we should use s.epochData[s.currentEpoch].withdrawProxy.
And currentWithdrawProxy is defined multiple times with the same value.
And we can remove s.epochData[s.currentEpoch - 1].withdrawProxy and replace it with currentWithdrawProxy.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In the PublicVault contract and function and function processEpoch, when we want to call the claim function from WithdrawProxy contract, we check that finalAuctionEnd is not equal to zero.
But in WithdrawProxy and claim function, already we used this check to be sure that finalAuctionEnd is not zero. So this check is duplicated and we can remove it from the processEpoch function.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
• In the WithdrawProxy contract and claim function we check that if (balance < s.expected), then we use (s.expected - balance).mulWadDown(1e18 - s.withdrawRatio). we can add the unchecked block and add (s.expected - balance).mulWadDown(1e18 - s.withdrawRatio) to it, to decrease gas usage.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
<x> += <y> costs more gas than <x> = <x> + <y> for state variables Using the addition operator instead of plus-equals saves 113 gas.
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/AstariaRouter.sol#L512 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L160 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L480 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L524 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L525 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L679 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L735 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L174 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L179 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L380 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L405 ////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
in PublicVault.sol and function _redeemFutureEpoch at below line,
we make the comparison between epoch from input and s.currentEpoch (reading from storage). this function is internal and getting calls from functions redeemFutureEpoch, withdraw, and redeem. in redeem and withdraw we pass currentEpoch (current epoch) to _redeemFutureEpoch and we don't need again read s.currentEpoch from storage to check the current epoch. so every time we call _redeemFutureEpoch from withdraw and redeem functions, we are wasting gas to again read current epoch from storage.
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L123 https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L135
just in redeemFutureEpoch, we can add the below code to check whether the passed epoch to function is the current epoch or no.
if (epoch < s.currentEpoch) { revert InvalidState(InvalidStates.EPOCH_TOO_LOW); }
then call _redeemFutureEpoch function.
this will save gas and prevent repeat read variable from storage.
////////////////////////////////////////////////////////////////////////////// *** //////////////////////////////////////////////////////////////////////////////
require() or revert() statements that check input arguments should be at the top of the function Checks that involve constants should come before checks that involve state variables, function calls, and calculations. By doing these checks first, the function is able to revert before wasting a Gcoldsload (2100 gas*) in a function that may ultimately revert in the unhappy case.
#0 - c4-judge
2023-01-22T16:22:05Z
Picodes marked the issue as grade-b
#1 - c4-judge
2023-01-26T00:04:34Z
Picodes marked the issue as grade-a