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: 46/75
Findings: 2
Award: $87.35
🌟 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
 | Issue |
---|---|
1 | Custom errors could be used with parameters for better user experience |
2 | Due to syntax error, custom errors are compiled as revert strings |
3 | Natspec comments are not used in the source code |
Custom errors can take in parameters and are useful in certain situations for knowing what actually went wrong. This will help the user to make the next transaction smartly.
The following custom errors could have had a parameter:
File: contracts/AxelarGateway.sol Line 286: if (chainId != block.chainid) revert InvalidChainId(); File: contracts/auth/AxelarAuthWeighted.sol Line 066: if (weightsLength != operatorsLength) revert InvalidWeights(); Line 072: if (newThreshold == 0 || totalWeight < newThreshold) revert InvalidThreshold();
custom errors
are compiled as revert strings
</ins>In XC20Wrapper.sol, there are custom errors declared. But due to a mistake in syntax, they are not used. But the compiler uses regular revert strings instead.
Note that making this correction will also reduce the deployment cost by a huge amount. As per this example test I implemented, the gas cost will be reduced by 15*11,000 = 165,000.
See the below 15 instances of this issue:
File: xc20/contracts/XC20Wrapper.sol Line 055: if (axelarToken == address(0)) revert('NotAxelarToken()'); Line 056: if (xc20Token.codehash != xc20Codehash) revert('NotXc20Token()'); Line 057: if (wrapped[axelarToken] != address(0)) revert('AlreadyWrappingAxelarToken()'); Line 058: if (unwrapped[xc20Token] != address(0)) revert('AlreadyWrappingXC20Token()'); Line 061: if (!LocalAsset(xc20Token).set_team(address(this), address(this), address(this))) revert('NotOwner()'); Line 062: if (!LocalAsset(xc20Token).set_metadata(newName, newSymbol, IERC20(axelarToken).decimals())) revert('CannotSetMetadata()'); Line 068: if (axelarToken == address(0)) revert('NotAxelarToken()'); Line 070: if (xc20Token == address(0)) revert('NotWrappingToken()'); Line 078: if (wrappedToken == address(0)) revert('NotAxelarToken()'); Line 079: if (!LocalAsset(wrappedToken).mint(msg.sender, amount)) revert('CannotMint()'); Line 084: if (axelarToken == address(0)) revert('NotXc20Token()'); Line 085: if (IERC20(wrappedToken).balanceOf(msg.sender) < amount) revert('InsufficientBalance()'); Line 086: if (!LocalAsset(wrappedToken).burn(msg.sender, amount)) revert('CannotBurn()'); Line 098: if (!transferred || tokenAddress.code.length == 0) revert('TransferFailed()'); Line 111: if (!transferred || tokenAddress.code.length == 0) revert('TransferFailed()');
The <ins>mitigation</ins> would be to correct the syntax. Lets take the first instance in the above list:
Line 055: if (axelarToken == address(0)) revert('NotAxelarToken()'); //should be if (axelarToken == address(0)) revert NotAxelarToken();
The following files doesn't use natspec comments:
#0 - re1ro
2022-08-05T04:31:01Z
Good spot Ack
Good spot
https://github.com/axelarnetwork/axelar-xc20-wrapper/pull/4 Duplicate of #13 9
Ack
#1 - GalloDaSballo
2022-08-31T23:29:54Z
Nice idea, valid R
Valid R
NC
Interesting report, wish the warden wrote more!
2R 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.2158 USDC - $31.22
 | Issue |
---|---|
1 | Emit events at the end of the function |
2 | Use custom errors instead of revert strings |
Emitting events at the end of the function will save any gas cost of emitting incase the transaction reverts after that.
Instances listed below:
```solidity File: contracts/AxelarGateway.sol Line 224: emit Upgraded(newImplementation);
Note that, since it looked like a syntax mistake, I have made a submission in the QA report as well. Please remove one of them as deemed necessary.
File : XC20Wrapper.sol
As per this example test I implemented, custom errors can cut down around 11,000 gas in deployment cost and around 55 gas (upon a revert) per external/public function.
See the below 15 instances of this issue:
File: xc20/contracts/XC20Wrapper.sol Line 055: if (axelarToken == address(0)) revert('NotAxelarToken()'); Line 056: if (xc20Token.codehash != xc20Codehash) revert('NotXc20Token()'); Line 057: if (wrapped[axelarToken] != address(0)) revert('AlreadyWrappingAxelarToken()'); Line 058: if (unwrapped[xc20Token] != address(0)) revert('AlreadyWrappingXC20Token()'); Line 061: if (!LocalAsset(xc20Token).set_team(address(this), address(this), address(this))) revert('NotOwner()'); Line 062: if (!LocalAsset(xc20Token).set_metadata(newName, newSymbol, IERC20(axelarToken).decimals())) revert('CannotSetMetadata()'); Line 068: if (axelarToken == address(0)) revert('NotAxelarToken()'); Line 070: if (xc20Token == address(0)) revert('NotWrappingToken()'); Line 078: if (wrappedToken == address(0)) revert('NotAxelarToken()'); Line 079: if (!LocalAsset(wrappedToken).mint(msg.sender, amount)) revert('CannotMint()'); Line 084: if (axelarToken == address(0)) revert('NotXc20Token()'); Line 085: if (IERC20(wrappedToken).balanceOf(msg.sender) < amount) revert('InsufficientBalance()'); Line 086: if (!LocalAsset(wrappedToken).burn(msg.sender, amount)) revert('CannotBurn()'); Line 098: if (!transferred || tokenAddress.code.length == 0) revert('TransferFailed()'); Line 111: if (!transferred || tokenAddress.code.length == 0) revert('TransferFailed()');
Number of instances = 15. Deployment gas cost saved = 15 * 11,000 = 165,000. Number of affected external functions = 4. Dynamic gas cost saved(on a revert) = 4 * 55 = 220.
#0 - re1ro
2022-08-05T04:32:20Z
#1 - GalloDaSballo
2022-08-23T00:40:47Z
Cannot rate without a benchmark