Platform: Code4rena
Start Date: 21/11/2022
Pot Size: $90,500 USDC
Total HM: 18
Participants: 101
Period: 7 days
Judge: Picodes
Total Solo HM: 4
Id: 183
League: ETH
Rank: 28/101
Findings: 3
Award: $207.69
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: cccz
Also found by: Englave, Jeiwan, aphak5010, hansfriese, immeas, rbserver, xiaoming90
82.2514 USDC - $82.25
A malicious user might call AutoPxGmx.compound()
with a higher fee than poolFee
.
As a result, there would be a fund loss for the users because they paid more than expected for the swap router.
As we can see here, Uniswap V3 introduces multiple pools for each token pair.
In the AutoPxGmx.sol
, all functions like withdraw(), redeem() and beforeDeposit() use the poolFee
set by admin.
But compound()
itself is a public function and users can call this function for the incentive.
Users can set the fee
as a parameter and the below situation would be possible.
poolFee = 0.3%
and all functions mentioned above will use this fee percent.compound()
with fee = 1%
.fee = 1%
might exist here, the swap router will take 1% as a fee.gmx
than expected.Manual Review
I think we should remove the fee
param from compound()
function and use poolFee
by default.
#0 - c4-judge
2022-12-03T18:18:54Z
Picodes marked the issue as duplicate of #391
#1 - c4-judge
2022-12-03T18:25:03Z
Picodes marked the issue as duplicate of #179
#2 - c4-judge
2022-12-05T10:47:46Z
Picodes marked the issue as duplicate of #91
#3 - c4-judge
2023-01-01T10:44:03Z
Picodes marked the issue as satisfactory
#4 - Picodes
2023-01-01T11:04:08Z
Partial credit as this issue does not highlight the main risk which is the use of a highly illiquid pool
#5 - c4-judge
2023-01-01T11:04:12Z
Picodes marked the issue as partial-50
🌟 Selected for report: xiaoming90
Also found by: 0x52, 8olidity, aphak5010, bin2chen, cccz, hansfriese, hihen, joestakey, ladboy233, rvierdiiev, unforgiven
71.9536 USDC - $71.95
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L152 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L130
In AutoPxGmx.sol
and AudotPxGlp.sol
, it doesn't approve properly when platform
is changed.
As a result, PirexGmx
contract can't transfer gmx
or gmxBaseReward
from these contracts and the main logic won't work as expected.
As we can see here and here, it approves the platform
in the constructor.
But in the AutoPxGmx.setPlatform() and AudotPxGlp.setPlatform(), it doesn't approve again for the updated platform
.
As a result, AutoPxGmx.depositGmx() and AudotPxGlp.depositGlp() wouldn't work properly and always revert.
// Convert sender GMX into pxGMX and get the post-fee amount (i.e. assets) (, uint256 assets, ) = PirexGmx(platform).depositGmx( amount, address(this) );
// Approve as needed here since it can be a new whitelisted token (unless it's the baseReward) if (erc20Token != gmxBaseReward) { erc20Token.safeApprove(platform, tokenAmount); } (, uint256 assets, ) = PirexGmx(platform).depositGlp( token, tokenAmount, minUsdg, minGlp, address(this) );
Manual Review
We should approve the new platform
again after it's changed.
#0 - c4-judge
2022-12-03T22:13:49Z
Picodes marked the issue as duplicate of #182
#1 - c4-judge
2023-01-01T10:43:54Z
Picodes marked the issue as satisfactory
🌟 Selected for report: 0xSmartContract
Also found by: 0xAgro, 0xNazgul, 0xPanda, 0xbepresent, 0xfuje, Awesome, B2, Bnke0x0, Deivitto, Diana, Funen, Jeiwan, JohnSmith, Josiah, R2, RaymondFam, Rolezn, Sathish9098, Waze, adriro, aphak5010, brgltd, btk, carrotsmuggler, ch0bu, chaduke, codeislight, codexploder, cryptostellar5, csanuragjain, danyams, datapunk, delfin454000, deliriusz, eierina, erictee, fatherOfBlocks, gz627, gzeon, hansfriese, hihen, jadezti, joestakey, keccak123, martin, nameruse, oyc_109, pedr02b2, perseverancesuccess, rbserver, rotcivegaf, rvierdiiev, sakshamguruji, shark, simon135, subtle77, unforgiven, xiaoming90, yixxas
53.4851 USDC - $53.49
// Approve the Uniswap V3 router to manage our base reward (inbound swap token)
It should be removed as this contract doesn't use the swap router.
beforeDeposit()
if (totalAssets() != 0) beforeDeposit(receiver, assets, shares); // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
It calls beforeDeposit()
before shares
is calculated so shares
will be 0 always.
Although beforeDeposit()
doesn't use the parameters now, it's recommened to pass correct values. (Or we can just use 0 for all).
if (totalAssets() != 0) beforeDeposit(receiver, assets, shares); assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.
It's almost the same as the above case and assets
is used before calculated.
@return rewardAmounts ERC20[] Reward token amounts
Change ERC20[]
to uint256[]
.
#0 - c4-judge
2022-12-04T20:52:11Z
Picodes marked the issue as grade-b