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: 42/75
Findings: 2
Award: $87.37
🌟 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.1473 USDC - $56.15
The ERC20.transferFrom(), ERC20.transfer(), ERC20.approve() functions return a boolean value indicating success. This parameter needs to be checked for success. But in the code below ,it is not checked at all .
One should use safeTransfer instead of transfer only. As there are popular tokens, such as USDT that transfer/transferFrom method does'nt return anything. The transfer return value has to be checked (as there are some other tokens that returns false instead revert), that means you must check the transferFrom return value
2022-07-axelar/contracts/deposit-service/AxelarDepositService.sol::30 => IERC20(wrappedTokenAddress).approve(gateway, amount); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::23 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::38 => IERC20(tokenAddress).approve(gateway, amount); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::51 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::64 => IERC20(wrappedTokenAddress).approve(gateway, amount); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::71 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::86 => recipient.transfer(amount); 2022-07-axelar/contracts/gas-service/AxelarGasService.sol::128 => if (amount > 0) receiver.transfer(amount); 2022-07-axelar/contracts/gas-service/AxelarGasService.sol::144 => receiver.transfer(amount); 2022-07-axelar/contracts/test/TestWeth.sol::23 => payable(msg.sender).transfer(amount); 2022-07-axelar/contracts/test/gmp/DestinationChainSwapExecutable.sol::28 => IERC20(tokenA).approve(address(swapper), amount); 2022-07-axelar/contracts/test/gmp/DestinationChainSwapExecutable.sol::31 => IERC20(tokenB).approve(address(gateway), convertedAmount); 2022-07-axelar/contracts/test/gmp/DestinationChainSwapForecallable.sol::28 => IERC20(tokenA).approve(address(swapper), amount); 2022-07-axelar/contracts/test/gmp/DestinationChainSwapForecallable.sol::31 => IERC20(tokenB).approve(address(gateway), convertedAmount); 2022-07-axelar/contracts/test/gmp/DestinationChainTokenSwapper.sol::24 => IERC20(tokenAddress).transferFrom(msg.sender, address(this), amount); 2022-07-axelar/contracts/test/gmp/DestinationChainTokenSwapper.sol::36 => IERC20(toTokenAddress).transfer(recipient, convertedAmount); 2022-07-axelar/contracts/test/gmp/SourceChainSwapCaller.sol::37 => IERC20(tokenX).transferFrom(msg.sender, address(this), amount + gasFee); 2022-07-axelar/contracts/test/gmp/SourceChainSwapCaller.sol::39 => IERC20(tokenX).approve(address(gasService), gasFee); 2022-07-axelar/contracts/test/gmp/SourceChainSwapCaller.sol::52 => IERC20(tokenX).approve(address(gateway), amount); 2022-07-axelar/xc20/contracts/XC20Wrapper.sol::63 => payable(msg.sender).transfer(address(this).balance);
We still recommend checking the return value as a best practice. Consider using OpenZeppelin’s SafeERC20 versions with the safeTransfer and safeTransferFrom functions that handle the return value check as well as non-standard-compliant staking tokens.
https://github.com/code-423n4/2021-12-nftx-findings/issues/141
https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
Avoid floating pragmas for non-library contracts. While floating pragmas make sense for libraries to allow them to be included with multiple different versions of applications, it may be a security risk for application implementations. A known vulnerable compiler version may accidentally be selected or security tools might fall-back to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain. It is recommended to pin to a concrete compiler version.
2022-07-axelar/contracts/interfaces/IAxelarAuth.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IAxelarAuthWeighted.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IAxelarDepositService.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IAxelarExecutable.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IAxelarForecallable.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IAxelarGasService.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IAxelarGateway.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IBurnableMintableCappedERC20.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IDepositBase.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IERC20.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IERC20Burn.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IERC20BurnFrom.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IERC20Permit.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IMintableCappedERC20.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IOwnable.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IReceiverImplementation.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/ITokenDeployer.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IUpgradable.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/contracts/interfaces/IWETH9.sol::3 => pragma solidity ^0.8.9; 2022-07-axelar/xc20/contracts/interfaces/LocalAsset.sol::3 => pragma solidity ^0.8.0; 2022-07-axelar/xc20/contracts/interfaces/Permit.sol::3 => pragma solidity ^0.8.0;
Used a fixed compiler version
#0 - GalloDaSballo
2022-08-28T20:50:17Z
NC
L
1L 1NC
🌟 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.222 USDC - $31.22
Uninitialized variables are assigned with the types default value. Explicitly initializing a variable with it's default value costs unnecesary gas.
Bad:
uint256 x = 0; bool y = false;
Good:
uint256 x; bool y;
2022-07-axelar/contracts/AxelarGateway.sol::207 => for (uint256 i = 0; i < symbols.length; i++) { 2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::68 => uint256 totalWeight = 0; 2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::69 => for (uint256 i = 0; i < weightsLength; ++i) { 2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::94 => uint256 operatorIndex = 0; 2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::95 => uint256 weight = 0; 2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::98 => for (uint256 i = 0; i < signatures.length; ++i) {
Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop.
Bad:
for (uint256 i = 0; i < array.length; i++) { // invariant: array's length is not changed }
Good:
uint256 len = array.length for (uint256 i = 0; i < len; i++) { // invariant: array's length is not changed }
2022-07-axelar/contracts/AdminMultisigBase.sol::149 => uint256 adminLength = accounts.length; 2022-07-axelar/contracts/AxelarGateway.sol::49 => if (authModule.code.length == 0) revert InvalidAuthModule(); 2022-07-axelar/contracts/AxelarGateway.sol::50 => if (tokenDeployerImplementation.code.length == 0) revert InvalidTokenDeployer(); 2022-07-axelar/contracts/AxelarGateway.sol::205 => if (symbols.length != limits.length) revert InvalidSetDailyMintLimitsParams(); 2022-07-axelar/contracts/AxelarGateway.sol::207 => for (uint256 i = 0; i < symbols.length; i++) { 2022-07-axelar/contracts/AxelarGateway.sol::228 => if (setupParams.length != 0) { 2022-07-axelar/contracts/AxelarGateway.sol::255 => if (newOperatorsData.length > 0) { 2022-07-axelar/contracts/AxelarGateway.sol::288 => uint256 commandsLength = commandIds.length; 2022-07-axelar/contracts/AxelarGateway.sol::290 => if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands(); 2022-07-axelar/contracts/AxelarGateway.sol::355 => if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress); 2022-07-axelar/contracts/AxelarGateway.sol::388 => if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol); 2022-07-axelar/contracts/AxelarGateway.sol::462 => return success && (returnData.length == uint256(0) || abi.decode(returnData, (bool))); 2022-07-axelar/contracts/AxelarGatewayProxy.sol::19 => if (gatewayImplementation.code.length == 0) revert InvalidImplementation(); 2022-07-axelar/contracts/DepositHandler.sol::23 => if (callee.code.length == 0) revert NotContract(); 2022-07-axelar/contracts/ECDSA.sol::32 => // Check the signature length 2022-07-axelar/contracts/ECDSA.sol::33 => if (signature.length != 65) revert InvalidSignatureLength(); 2022-07-axelar/contracts/ECDSA.sol::75 => // 32 is the length in bytes of hash,
!= 0
instead of > 0
for Unsigned Integer ComparisonWhen dealing with unsigned integer types, comparisons with != 0
are cheaper
then with > 0
.
Bad:
// `a` being of type unsigned integer require(a > 0, "!a > 0");
Good:
// `a` being of type unsigned integer require(a != 0, "!a > 0");
2022-07-axelar/contracts/AxelarGateway.sol::255 => if (newOperatorsData.length > 0) { 2022-07-axelar/contracts/AxelarGateway.sol::613 => if (limit > 0 && amount > limit) revert ExceedDailyMintLimit(symbol); 2022-07-axelar/contracts/ECDSA.sol::58 => if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS(); 2022-07-axelar/contracts/ERC20Permit.sol::45 => if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS(); 2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::76 => if (epochForHash[newOperatorsHash] > 0) revert SameOperators(); 2022-07-axelar/contracts/deposit-service/AxelarDepositService.sol::165 => if (addressForNativeDeposit(salt, refundAddress, destinationChain, destinationAddress).balance > 0 && msg.sender != refundAddress) 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::23 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::51 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance); 2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::71 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance); 2022-07-axelar/contracts/gas-service/AxelarGasService.sol::128 => if (amount > 0) receiver.transfer(amount); 2022-07-axelar/contracts/gas-service/AxelarGasService.sol::131 => if (amount > 0) _safeTransfer(token, receiver, amount); 2022-07-axelar/contracts/util/Upgradable.sol::50 => if (params.length > 0) { 2022-07-axelar/xc20/contracts/ERC20Permit.sol::45 => if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS();
A division/multiplication by any number x
being a power of 2 can be
calculated by shifting log2(x)
to the right/left.
While the DIV
opcode uses 5 gas, the SHR
opcode only uses 3 gas.
Furthermore, Solidity's division operation also includes a division-by-0
prevention which is bypassed using shifting.
Bad:
uint256 b = a / 2; uint256 c = a / 4; uint256 d = a * 8;
Good:
uint256 b = a >> 1; uint256 c = a >> 2; uint256 d = a << 3;
2022-07-axelar/contracts/ECDSA.sol::56 => // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept 2022-07-axelar/contracts/ERC20.sol::15 => * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 2022-07-axelar/contracts/interfaces/IERC20.sol::49 => * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 2022-07-axelar/contracts/test/gmp/DestinationChainTokenSwapper.sol::29 => convertedAmount = amount * 2; 2022-07-axelar/contracts/test/gmp/DestinationChainTokenSwapper.sol::33 => convertedAmount = amount / 2; 2022-07-axelar/xc20/contracts/ERC20.sol::15 => * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 2022-07-axelar/xc20/contracts/interfaces/IERC20.sol::63 => * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
#0 - GalloDaSballo
2022-08-20T22:27:43Z
Less than 100 gas saved