Platform: Code4rena
Start Date: 29/07/2022
Pot Size: $50,000 USDC
Total HM: 6
Participants: 75
Period: 5 days
Judge: GalloDaSballo
Total Solo HM: 3
Id: 149
League: ETH
Rank: 37/75
Findings: 2
Award: $88.01
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: oyc_109
Also found by: 0x1f8b, 0x52, 0xNazgul, 0xSmartContract, 0xf15ers, 8olidity, Aymen0909, Bnke0x0, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, IllIllI, JC, Lambda, Noah3o6, NoamYakov, RedOneN, Respx, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, TomJ, Twpony, Waze, Yiko, __141345__, ajtra, apostle0x01, ashiq0x01, asutorufos, bardamu, benbaessler, berndartmueller, bharg4v, bulej93, c3phas, cccz, ch13fd357r0y3r, codexploder, cryptonue, cryptphi, defsec, djxploit, durianSausage, fatherOfBlocks, gogo, hansfriese, horsefacts, ignacio, kyteg, lucacez, mics, rbserver, robee, sashik_eth, simon135, sseefried, tofunmi, xiaoming90
56.1273 USDC - $56.13
If the intention is for the Ether to be used, the function should call another function, otherwise it should revert
deposit-service/DepositReceiver.sol:29: receive() external payable {} deposit-service/AxelarDepositServiceProxy.sol:13: receive() external payable override {}
https://github.com/code-423n4/2022-07-axelar/tree/main/contracts/deposit-service/DepositReceiver.sol#L29 https://github.com/code-423n4/2022-07-axelar/tree/main/contracts/deposit-service/AxelarDepositServiceProxy.sol#L13
approve
is subject to a known front-running attack. Consider using safeApprove
instead:
deposit-service/ReceiverImplementation.sol:38: IERC20(tokenAddress).approve(gateway, amount); deposit-service/ReceiverImplementation.sol:64: IERC20(wrappedTokenAddress).approve(gateway, amount); deposit-service/AxelarDepositService.sol:30: IERC20(wrappedTokenAddress).approve(gateway, amount);
Update to _token.safeApprove(spender, type(uint256).max) in the function.
#0 - re1ro
2022-08-05T09:12:56Z
Dup #3
#1 - GalloDaSballo
2022-08-28T20:39:22Z
AxelarDepositServiceProxy cannot sweep out, so valid L
Simply not true, both approve and safeApprove are subject to front-run of allowance changes, while the code will not be front-runnable if the gateway will move the tokens in the same tx in which the approval is done. For that reason I disagree.
1 L
๐ Selected for report: IllIllI
Also found by: 0x1f8b, 0xNazgul, 0xsam, 8olidity, Aymen0909, Bnke0x0, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, Fitraldys, JC, Lambda, MiloTruck, Noah3o6, NoamYakov, RedOneN, Respx, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, TomJ, Tomio, Waze, __141345__, a12jmx, ajtra, ak1, apostle0x01, asutorufos, benbaessler, bharg4v, bulej93, c3phas, defsec, djxploit, durianSausage, erictee, fatherOfBlocks, gerdusx, gogo, kyteg, lucacez, medikko, mics, owenthurm, oyc_109, rbserver, robee, sashik_eth, simon135, tofunmi
31.8812 USDC - $31.88
Anytime you are reading from storage more than once, it is cheaper to cache variables in memory. An SLOAD cost 100 GAS while MLOAD and MSTORE only cost 3 GAS.
This is especially true in for loops when using the length of a storage array as the condition being checked after each loop. Caching the array length in memory can yield significant gas savings when the array length is high.
// Before for(uint 1; i < approvals.length; i++); // approvals is a storage variable // After uint memory numApprovals = approvals.length; for(uint 1; i < numApprovals; i++);
auth/AxelarAuthWeighted.sol:98: for (uint256 i = 0; i < signatures.length; ++i) { AxelarGateway.sol:207: for (uint256 i = 0; i < symbols.length; i++) { deposit-service/AxelarDepositService.sol:114: for (uint256 i; i < refundTokens.length; i++) { deposit-service/AxelarDepositService.sol:168: for (uint256 i; i < refundTokens.length; i++) { deposit-service/AxelarDepositService.sol:204: for (uint256 i; i < refundTokens.length; i++) {
auth/AxelarAuthWeighted.sol:69: for (uint256 i = 0; i < weightsLength; ++i) { auth/AxelarAuthWeighted.sol:98: for (uint256 i = 0; i < signatures.length; ++i) { AxelarGateway.sol:207: for (uint256 i = 0; i < symbols.length; i++) {
As an example: for (uint256 i = 0; i < weightsLength;) {
should be replaced with for (uint256 i; i < weightLength;) {
In Solidity 0.8+, there's a default overflow check on unsigned integers. It's possible to uncheck this in for-loops and save some gas at each iteration, but at the cost of some code readability, as this uncheck cannot be made inline.
Instances include:
deposit-service/AxelarDepositService.sol:114: for (uint256 i; i < refundTokens.length; i++) { deposit-service/AxelarDepositService.sol:168: for (uint256 i; i < refundTokens.length; i++) { deposit-service/AxelarDepositService.sol:204: for (uint256 i; i < refundTokens.length; i++) { AxelarGateway.sol:207: for (uint256 i = 0; i < symbols.length; i++) {
The code would go from:
for (uint256 i; i < refundTokens.length; i++) { // ... }
to:
for (uint256 i; i < refundTokens.length;) { // ... unchecked { ++i; } }
The risk of overflow is inexistant for a uint256 here.
++i costs less gas compared to i++ or i += 1 for unsigned integers. This is because the pre-increment operation is cheaper (about 5 GAS per iteration). This is implemented in other sol files but looks like its missing from Vault.sol .
deposit-service/AxelarDepositService.sol:114: for (uint256 i; i < refundTokens.length; i++) { deposit-service/AxelarDepositService.sol:168: for (uint256 i; i < refundTokens.length; i++) { deposit-service/AxelarDepositService.sol:204: for (uint256 i; i < refundTokens.length; i++) { AxelarGateway.sol:207: for (uint256 i = 0; i < symbols.length; i++) {
#0 - re1ro
2022-08-05T09:17:03Z
Dup #18 #2
#1 - GalloDaSballo
2022-08-25T01:43:24Z
300 gas as other loop like reports