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: 10/101
Findings: 4
Award: $2,093.64
π Selected for report: 1
π Solo Findings: 0
1238.1649 USDC - $1,238.16
According to scoping
- Does it use a side-chain? Yes - If yes, is the sidechain evm-compatible? Yes, Avalanche
The address 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 is an EOA on Avalanche, which will lead to revert when called from the vault contract (empty return value).
IV3SwapRouter public constant SWAP_ROUTER = IV3SwapRouter(0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45);
gmxAmountOut = SWAP_ROUTER.exactInputSingle( IV3SwapRouter.ExactInputSingleParams({ tokenIn: address(gmxBaseReward), tokenOut: address(gmx), fee: fee, recipient: address(this), amountIn: gmxBaseRewardAmountIn, amountOutMinimum: amountOutMinimum, sqrtPriceLimitX96: sqrtPriceLimitX96 }) );
Set the swap router address in constructor.
#0 - c4-judge
2022-12-04T13:17:43Z
Picodes marked the issue as primary issue
#1 - drahrealm
2022-12-08T05:15:17Z
The vault is not fully ready yet for deployment to Avalanche currently (also, we are going to adapt it to use TraderJoe instead of Uniswap for it), so the current implementation is still only geared towards Arbitrum
#2 - c4-sponsor
2022-12-08T05:15:28Z
drahrealm marked the issue as disagree with severity
#3 - Picodes
2022-12-30T21:10:38Z
Satisfactory considering the codebase during the audit
#4 - c4-judge
2022-12-30T21:10:43Z
Picodes marked the issue as satisfactory
#5 - C4-Staff
2023-01-10T21:59:24Z
JeeberC4 marked the issue as duplicate of #132
π Selected for report: deliriusz
Also found by: 0x52, 0xLad, 0xbepresent, Englave, R2, Ruhum, cccz, gzeon, hihen, keccak123, ladboy233, pashov, pedroais, perseverancesuccess, rbserver, rvierdiiev, simon135, unforgiven, wagmi, xiaoming90
15.9293 USDC - $15.93
When calling deposit, withdraw, and redeem it default to use `amountOutMinimum:1 sqrtPriceLimitX96:0 which may lead to unexpected slippage. Although it is not currently subject to sandwich attack (assuming you trust the Arbitrum sequencer) since there are no mempool.
compound(poolFee, 1, 0, true);
#0 - c4-judge
2022-12-04T00:11:33Z
Picodes marked the issue as duplicate of #185
#1 - c4-judge
2023-01-01T11:16:49Z
Picodes marked the issue as satisfactory
#2 - C4-Staff
2023-01-10T22:10:37Z
JeeberC4 marked the issue as duplicate of #137
π 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
Per EIP-4626, maxDeposit
returns the maximum amount of underlying assets that can be deposited in a single deposit call by the receiver. When balance > 0
, you can only deposit type(uint256).max - balance
amount of token.
function maxDeposit(address) public view virtual returns (uint256) { return type(uint256).max; }
Per EIP-4626, maxMint
returns the maximum amount of underlying assets that can be deposited in a single deposit call by the receiver. When totalsupply > 0
, you can only deposit type(uint256).max - totalsupply
amount of token.
function maxMint(address) public view virtual returns (uint256) { return type(uint256).max; }
uint256 public constant EXPANDED_DECIMALS = 1e30;
Multiple value of FEE_PERCENT_DENOMINATOR
is used across the codebase, this might easily lead to configuration mistake.
assert()
will consume all gas, use require()
instead
assert(feeAmount + postFeeAmount == assets);
#0 - c4-judge
2022-12-05T09:28:29Z
Picodes marked the issue as grade-b
π Selected for report: gzeon
Also found by: 0xPanda, 0xSmartContract, B2, Deivitto, Diana, JohnSmith, PaludoX0, Rahoz, RaymondFam, ReyAdmirado, Rolezn, Schlagatron, Secureverse, Tomio, __141345__, adriro, ajtra, aphak5010, c3phas, chaduke, codeislight, cryptonue, datapunk, dharma09, halden, karanctf, keccak123, oyc_109, pavankv, sakshamguruji, saneryee, unforgiven
786.0593 USDC - $786.06
Since GMX is on Arbitrum, a L2 rollup, it is much more important to optimize for calldata when considering gas optimization. In fact, EVM gas optimizations have minimal effect when compared to calldata optimizations. For example at 9 gwei L1 gas price and 0.1 gwei Arbitrum gas price, each byte of calldata after compression cost ~640 calldata gas. Here are some suggestions to reduce the calldata size:
For all the function with a receiver
parameter (e.g. depositGmx(uint256 amount, address receiver)
), add a helper function which default it with msg.sender. This saves 20 bytes (or 32 bytes, but those 0 will mostly be compressed away) of calldata ~= 12800 gas.
For deposit and withdraw functions, allow the user to specify some magic value to deposit/withdraw max. This saves 32 bytes of calldata ~= 20480 gas.
On the UI level, use more compressible value (e.g. 1024(0x400) instead of 1000(0x3E8)) for amounts like minGlp
Consider integrate with ArbAddressTable for token addresses and other common addresses.
Resources
#0 - c4-judge
2022-12-05T14:14:30Z
Picodes marked the issue as grade-a
#1 - c4-sponsor
2022-12-09T06:21:02Z
drahrealm marked the issue as sponsor confirmed
#2 - drahrealm
2022-12-09T06:21:09Z
These are interesting tips π
#3 - c4-judge
2023-01-01T10:36:30Z
Picodes marked the issue as selected for report
#4 - Picodes
2023-01-01T10:37:12Z
Flagging as best as I believe this was the submission providing the more value to the sponsor