Platform: Code4rena
Start Date: 18/10/2022
Pot Size: $75,000 USDC
Total HM: 27
Participants: 144
Period: 7 days
Judge: gzeon
Total Solo HM: 13
Id: 170
League: ETH
Rank: 77/144
Findings: 2
Award: $26.35
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Rolezn
Also found by: 0x1f8b, 0x52, 0x5rings, 0xNazgul, 0xSmartContract, 0xZaharina, 0xhunter, 0xzh, 8olidity, Amithuddar, Aymen0909, B2, Bnke0x0, Chom, Deivitto, Diana, Diraco, Dravee, Franfran, JC, Jeiwan, Josiah, JrNet, Jujic, KingNFT, KoKo, Lambda, Margaret, Migue, Ocean_Sky, PaludoX0, Picodes, Rahoz, RaoulSchaffranek, RaymondFam, RedOneN, ReyAdmirado, Shinchan, Tagir2003, Trust, Waze, Yiko, __141345__, a12jmx, adriro, ajtra, arcoun, aysha, ballx, bin2chen, bobirichman, brgltd, bulej93, catchup, catwhiskeys, caventa, cccz, cdahlheimer, ch0bu, chaduke, chrisdior4, cloudjunky, cryptostellar5, cryptphi, csanuragjain, cylzxje, d3e4, delfin454000, djxploit, durianSausage, erictee, fatherOfBlocks, francoHacker, gianganhnguyen, gogo, hansfriese, i_got_hacked, ignacio, imare, karanctf, kv, leosathya, louhk, lukris02, lyncurion, m_Rassska, malinariy, martin, mcwildy, mics, minhtrng, nicobevi, oyc_109, pashov, peanuts, pedr02b2, peiw, rbserver, ret2basic, rotcivegaf, rvierdiiev, ryshaw, sakman, sakshamguruji, saneryee, securerodd, seyni, sikorico, svskaushik, teawaterwire, tnevler, w0Lfrum
0 USDC - $0.00
return
statement when the function defines a named return variable, is redundantThere are 1 instances of this issue:
File: contracts/enforcer/PA1D.sol 665: function bidSharesForToken(uint256 tokenId) public view returns (ZoraBidShares memory bidShares) { 674: return bidShares;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
Emmiting events is recommended each time when a state variable's value is being changed or just some critical event for the contract has occurred. It also helps off-chain monitoring of the contract's state.
There are 3 instances of this issue:
File: contracts/HolographOperator.sol 240: function init(bytes memory initPayload) external override returns (bytes4) { 278: function resetOperator(
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 218: function init(bytes memory initPayload) external override returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
public
functions not called by the contract should be declared external
insteadThere are 28 instances of this issue:
File: contracts/enforcer/HolographERC20.sol 273: function decimals() public view returns (uint8) { 297: function allowance(address account, address spender) public view returns (uint256) { 306: function DOMAIN_SEPARATOR() public view returns (bytes32) { 310: function name() public view returns (string memory) { 314: function nonces(address account) public view returns (uint256) { 318: function symbol() public view returns (string memory) { 322: function totalSupply() public view returns (uint256) { 363: function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 420: function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 460: function permit(
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 599: function transferFrom( 616: function transferFrom(
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/Holographer.sol 192: function getHolographEnforcer() public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
File: contracts/enforcer/PA1D.sol 471: function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner { 488: function getPayoutInfo() public view returns (address payable[] memory addresses, uint256[] memory bps) { 497: function getEthPayout() public { 507: function getTokenPayout(address tokenAddress) public { 517: function getTokensPayout(address[] memory tokenAddresses) public { 549: function royaltyInfo(uint256 tokenId, uint256 value) public view returns (address, uint256) { 558: function getFeeBps(uint256 tokenId) public view returns (uint256[] memory) { 569: function getFeeRecipients(uint256 tokenId) public view returns (address payable[] memory) { 590: function getRoyalties(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) { 604: function getFees(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) { 621: function tokenCreator( 634: function calculateRoyaltyFee( 649: function marketContract() public view returns (address) { 655: function tokenCreators(uint256 tokenId) public view returns (address) { 665: function bidSharesForToken(uint256 tokenId) public view returns (ZoraBidShares memory bidShares) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
receive()
/fallback()
functionsThere are 6 instances of this issue:
File: contracts/HolographOperator.sol 1209: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/abstract/ERC20H.sol 212: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol
File: contracts/abstract/ERC721H.sol 212: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol
File: contracts/enforcer/HolographERC20.sol 251: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 962: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/Holographer.sol 223: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
1e18
instead of 10**18
or 1000000000000000000
There are 1 instances of this issue:
File: contracts/HolographOperator.sol 256: _baseBondAmount = 100 * (10**18);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
indexed
fieldsThere are 1 instances of this issue:
File: contracts/enforcer/PA1D.sol 153: event SecondarySaleFees(uint256 tokenId, address[] recipients, uint256[] bps);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
There are 7 instances of this issue:
File: contracts/enforcer/HolographERC20.sol 114: import "../interface/ERC20Burnable.sol"; 116: import "../interface/ERC20Metadata.sol"; 119: import "../interface/ERC20Safer.sol"; 124: import "../interface/HolographerInterface.sol"; 125: import "../interface/HolographRegistryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 123: import "../interface/PA1DInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/PA1D.sol 110: import "../interface/PA1DInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
#0 - alexanderattar
2022-11-09T20:31:26Z
Lots of helpful cleanup here
🌟 Selected for report: oyc_109
Also found by: 0x040, 0x1f8b, 0x5rings, 0xNazgul, 0xSmartContract, 0xZaharina, 0xsam, 0xzh, 2997ms, Amithuddar, Aymen0909, B2, Bnke0x0, Deivitto, Diana, Dinesh11G, Franfran, JC, JrNet, Jujic, KingNFT, KoKo, Mathieu, Metatron, Mukund, Olivierdem, PaludoX0, Pheonix, Picodes, RaymondFam, RedOneN, ReyAdmirado, Rolezn, Saintcode_, Satyam_Sharma, Shinchan, Tagir2003, Tomio, Waze, Yiko, __141345__, adriro, ajtra, aysha, ballx, beardofginger, bobirichman, brgltd, bulej93, catchup, catwhiskeys, cdahlheimer, ch0bu, chaduke, chrisdior4, cryptostellar5, cylzxje, d3e4, delfin454000, dharma09, djxploit, durianSausage, emrekocak, erictee, exolorkistis, fatherOfBlocks, gianganhnguyen, gogo, halden, hxzy, i_got_hacked, iepathos, karanctf, leosathya, lucacez, lukris02, lyncurion, m_Rassska, martin, mcwildy, mics, nicobevi, peanuts, peiw, rbserver, ret2basic, rotcivegaf, ryshaw, sakman, sakshamguruji, saneryee, sikorico, skyle, svskaushik, tnevler, vv7, w0Lfrum, zishansami
26.3525 USDC - $26.35
++i
will cost less gas than i++
. The same change can be applied to i--
as well.This change would save up to 6 gas per instance/loop.
There are 17 instances of this issue:
File: contracts/HolographOperator.sol 520: podSize--; 760: pod--; 781: for (uint256 i = 0; i < length; i++) { 871: for (uint256 i = _operatorPods.length; i <= pod; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 564: for (uint256 i = 0; i < wallets.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 357: for (uint256 i = 0; i < length; i++) { 716: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/PA1D.sol 307: for (uint256 i = 0; i < length; i++) { 323: for (uint256 i = 0; i < length; i++) { 340: for (uint256 i = 0; i < length; i++) { 356: for (uint256 i = 0; i < length; i++) { 394: for (uint256 i = 0; i < length; i++) { 414: for (uint256 i = 0; i < length; i++) { 432: for (uint256 t = 0; t < tokenAddresses.length; t++) { 437: for (uint256 i = 0; i < addresses.length; i++) { 454: for (uint256 i = 0; i < addresses.length; i++) { 474: for (uint256 i = 0; i < addresses.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 5 instances of this issue:
File: contracts/HolographOperator.sol /// @audit Cache `_operatorTempStorageCounter`. Used 3 times in `crossChainMessage` 495: ++_operatorTempStorageCounter; 517: _operatorTempStorage[_operatorTempStorageCounter] = _operatorPods[pod][operatorIndex]; 524: (uint256(_operatorTempStorageCounter) << 216) | /// @audit Cache `_operatorPods`. Used 6 times in `executeJob` 363: if (podIndex > 0 && podIndex < _operatorPods[pod].length) { 364: address fallbackOperator = _operatorPods[pod][podIndex]; 390: _operatorPods[pod].push(job.operator); 391: _operatorPodIndex[job.operator] = _operatorPods[pod].length - 1; 407: _operatorPods[pod].push(msg.sender); 408: _operatorPodIndex[job.operator] = _operatorPods[pod].length - 1; /// @audit Cache `_operatorPods`. Used 3 times in `crossChainMessage` 503: uint256 pod = random % _operatorPods.length; 507: uint256 podSize = _operatorPods[pod].length; 517: _operatorTempStorage[_operatorTempStorageCounter] = _operatorPods[pod][operatorIndex]; /// @audit Cache `_operatorPods`. Used 5 times in `bondUtilityToken` 867: if (_operatorPods.length < pod) { 875: _operatorPods.push([address(0)]); 881: require(_operatorPods[pod - 1].length < type(uint16).max, "HOLOGRAPH: too many operators"); 882: _operatorPods[pod - 1].push(operator); 883: _operatorPodIndex[operator] = _operatorPods[pod - 1].length - 1; /// @audit Cache `_operatorPods`. Used 4 times in `_popOperator` 1128: address operator = _operatorPods[pod][operatorIndex]; 1137: uint256 lastIndex = _operatorPods[pod].length - 1; 1148: delete _operatorPods[pod][lastIndex]; 1152: _operatorPods[pod].pop();
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
internal
and private
functions that are called only once should be inlined.The execution of a non-inlined function would cost up to 40 more gas because of two extra jump
s as well as some other instructions.
There are 20 instances of this issue:
File: contracts/HolographBridge.sol 549: function _jobNonce() private returns (uint256 jobNonce) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographFactory.sol 309: function _isContract(address contractAddress) private view returns (bool) { 320: function _verifySigner(
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol
File: contracts/HolographOperator.sol 1058: function _bridge() private view returns (address bridge) { 1094: function _registry() private view returns (HolographRegistryInterface registry) { 1112: function _jobNonce() private returns (uint256 jobNonce) { 1198: function _isContract(address contractAddress) private view returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 711: function _useNonce(address account) private returns (uint256 current) { 736: function _interfaces() private view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 824: function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/PA1D.sol 226: function _setDefaultReceiver(address receiver) private { 246: function _setDefaultBp(uint256 bp) private { 268: function _setReceiver(uint256 tokenId, address receiver) private { 291: function _setBp(uint256 tokenId, uint256 bp) private { 316: function _setPayoutAddresses(address payable[] memory addresses) private { 349: function _setPayoutBps(uint256[] memory bps) private { 365: function _getTokenAddress(string memory tokenName) private view returns (address tokenAddress) { 382: function _payoutEth() private { 405: function _payoutToken(address tokenAddress) private { 426: function _payoutTokens(address[] memory tokenAddresses) private {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
!= 0
on uints
costs less gas than > 0
.This change saves 3 gas per instance/loop
There are 6 instances of this issue:
File: contracts/HolographBridge.sol 218: if (hTokenValue > 0) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographOperator.sol 350: require(timeDifference > 0, "HOLOGRAPH: operator has time"); 363: if (podIndex > 0 && podIndex < _operatorPods[pod].length) { 398: if (leftovers > 0) { 1126: if (operatorIndex > 0) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC721.sol 815: require(tokenId > 0, "ERC721: token id cannot be zero");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
constant
/non-immutable
variables to zero than to let the default of zero be appliedNot overwriting the default for stack variables saves 8 gas. Storage and memory variables have larger savings
There are 17 instances of this issue:
File: contracts/HolographBridge.sol 380: uint256 fee = 0;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographOperator.sol 310: uint256 gasLimit = 0; 311: uint256 gasPrice = 0; 781: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 564: for (uint256 i = 0; i < wallets.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 357: for (uint256 i = 0; i < length; i++) { 716: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/PA1D.sol 307: for (uint256 i = 0; i < length; i++) { 323: for (uint256 i = 0; i < length; i++) { 340: for (uint256 i = 0; i < length; i++) { 356: for (uint256 i = 0; i < length; i++) { 394: for (uint256 i = 0; i < length; i++) { 414: for (uint256 i = 0; i < length; i++) { 432: for (uint256 t = 0; t < tokenAddresses.length; t++) { 437: for (uint256 i = 0; i < addresses.length; i++) { 454: for (uint256 i = 0; i < addresses.length; i++) { 474: for (uint256 i = 0; i < addresses.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
payable
Marking a function as payable
reduces gas cost since the compiler does not have to check whether a payment was provided or not. This change will save around 21 gas per function call.
There are 20 instances of this issue:
File: contracts/HolographBridge.sol 452: function setFactory(address factory) external onlyAdmin { 472: function setHolograph(address holograph) external onlyAdmin { 502: function setOperator(address operator) external onlyAdmin { 522: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographFactory.sol 280: function setHolograph(address holograph) external onlyAdmin { 300: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol
File: contracts/HolographOperator.sol 445: function nonRevertingBridgeCall(address msgSender, bytes calldata payload) external payable { 484: function crossChainMessage(bytes calldata bridgeInRequestPayload) external payable { 949: function setBridge(address bridge) external onlyAdmin { 969: function setHolograph(address holograph) external onlyAdmin { 989: function setInterfaces(address interfaces) external onlyAdmin { 1009: function setMessagingModule(address messagingModule) external onlyAdmin { 1029: function setRegistry(address registry) external onlyAdmin { 1049: function setUtilityToken(address utilityToken) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/abstract/ERC20H.sol 123: require(msgSender() == _getOwner(), "ERC20: owner only function");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol
File: contracts/abstract/ERC721H.sol 123: require(msgSender() == _getOwner(), "ERC721: owner only function");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol
File: contracts/enforcer/HolographERC20.sol 380: function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { 415: function holographBridgeMint(address to, uint256 amount) external onlyBridge returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 399: function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/PA1D.sol 471: function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
<array>.length
should not be looked up in every loop of a for
-loopThe overheads outlined below are PER LOOP, excluding the first loop \ - storage arrays incur a Gwarmaccess (100 gas) \ - memory arrays use MLOAD
(3 gas) \ - calldata arrays use CALLDATALOAD
(3 gas)
Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset
There are 1 instances of this issue:
File: contracts/HolographOperator.sol 871: for (uint256 i = _operatorPods.length; i <= pod; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
++i
/i++
should be unchecked{++I}
/unchecked{I++}
in for
-loopsWhen an increment or any arithmetic operation is not possible to overflow it should be placed in unchecked{}
block. \This is because of the default compiler overflow and underflow safety checks since Solidity version 0.8.0. \In for-loops it saves around 30-40 gas per loop
There are 15 instances of this issue:
File: contracts/HolographOperator.sol 781: for (uint256 i = 0; i < length; i++) { 871: for (uint256 i = _operatorPods.length; i <= pod; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 564: for (uint256 i = 0; i < wallets.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 357: for (uint256 i = 0; i < length; i++) { 716: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/PA1D.sol 307: for (uint256 i = 0; i < length; i++) { 323: for (uint256 i = 0; i < length; i++) { 340: for (uint256 i = 0; i < length; i++) { 356: for (uint256 i = 0; i < length; i++) { 394: for (uint256 i = 0; i < length; i++) { 414: for (uint256 i = 0; i < length; i++) { 432: for (uint256 t = 0; t < tokenAddresses.length; t++) { 437: for (uint256 i = 0; i < addresses.length; i++) { 454: for (uint256 i = 0; i < addresses.length; i++) { 474: for (uint256 i = 0; i < addresses.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 7 instances of this issue:
File: contracts/HolographOperator.sol 378: _bondedAmounts[job.operator] -= amount; 382: _bondedAmounts[msg.sender] += amount; 834: _bondedAmounts[operator] += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 686: _balances[to] += amount; 702: _balances[recipient] += amount; 633: _totalSupply -= amount; 685: _totalSupply += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
uint
s/int
s smaller than 32 bytes (256 bits) incurs overhead'When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.' \ https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html \ Use a larger size then downcast where needed
There are 19 instances of this issue:
File: contracts/HolographBridge.sol 192: uint32 fromChain, 246: uint32 toChain, 298: uint32 toChain, 343: uint32 toChain,
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographFactory.sol 323: uint8 v,
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol
File: contracts/HolographOperator.sol 208: uint32 private _operatorTempStorageCounter; 585: uint32 toChain,
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 181: uint8 private _decimals; 229: uint8 contractDecimals, 380: function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { 393: uint32 toChain, 465: uint8 v,
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 160: uint16 private _bps; 248: uint16 contractBps, 399: function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { 414: uint32 toChain, 879: uint32 currentChain = HolographInterface(HolographerInterface(payable(address(this))).getHolograph())
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/Holographer.sol 150: (uint32 originChain, address holograph, bytes32 contractType, address sourceContract) = abi.decode( 205: function getOriginChain() external view returns (uint32 originChain) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
require()
statements that use &&
saves gasInstead of using &&
on single require
check using two require
checks can save gas
There are 4 instances of this issue:
File: contracts/HolographOperator.sol 857: require(_bondedOperators[operator] == 0 && _bondedAmounts[operator] == 0, "HOLOGRAPH: operator is bonded");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC721.sol 263: require(success && selector == InitializableInterface.init.selector, "ERC721: coud not init PA1D"); 464: require( 465: (ERC165(to).supportsInterface(ERC165.supportsInterface.selector) && 466: ERC165(to).supportsInterface(ERC721TokenReceiver.onERC721Received.selector) && 467: ERC721TokenReceiver(to).onERC721Received(address(this), from, tokenId, data) == 468: ERC721TokenReceiver.onERC721Received.selector), 469: "ERC721: onERC721Received fail" 470: );
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/Holographer.sol 166: require(success && selector == InitializableInterface.init.selector, "initialization failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
calldata
instead of memory
for function parametersIf a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory. Try to use calldata as a data location because it will avoid copies and also makes sure that the data cannot be modified.
There are 26 instances of this issue:
File: contracts/HolographBridge.sol 162: function init(bytes memory initPayload) external override returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographFactory.sol 143: function init(bytes memory initPayload) external override returns (bytes4) { 193: DeploymentConfig memory config, 194: Verification memory signature,
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol
File: contracts/HolographOperator.sol 240: function init(bytes memory initPayload) external override returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/abstract/ERC20H.sol 140: function init(bytes memory initPayload) external virtual override returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol
File: contracts/abstract/ERC721H.sol 140: function init(bytes memory initPayload) external virtual override returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol
File: contracts/enforcer/HolographERC20.sol 218: function init(bytes memory initPayload) external override returns (bytes4) { 499: bytes memory data 524: bytes memory data 641: bytes memory data
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 238: function init(bytes memory initPayload) external override returns (bytes4) { 456: bytes memory data 620: bytes memory data
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/Holographer.sol 147: function init(bytes memory initPayload) external override returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
File: contracts/enforcer/PA1D.sol 173: function init(bytes memory initPayload) external override returns (bytes4) { 185: function initPA1D(bytes memory initPayload) external returns (bytes4) { 316: function _setPayoutAddresses(address payable[] memory addresses) private { 349: function _setPayoutBps(uint256[] memory bps) private { 365: function _getTokenAddress(string memory tokenName) private view returns (address tokenAddress) { 372: function _setTokenAddress(string memory tokenName, address tokenAddress) private { 426: function _payoutTokens(address[] memory tokenAddresses) private { /// @audit Store `addresses` in calldata. 471: function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner { /// @audit Store `bps` in calldata. 471: function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner { 517: function getTokensPayout(address[] memory tokenAddresses) public { 683: function getTokenAddress(string memory tokenName) public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM, there is no opcode for >=
or <=
. When using greater than or equal, two operations are performed: >
and =
. Using strict comparison operators hence saves gas
There are 18 instances of this issue:
File: contracts/HolographOperator.sol 354: require(gasPrice >= tx.gasprice, "HOLOGRAPH: gas spike detected"); 386: if (_bondedAmounts[job.operator] >= amount) { 728: require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 739: require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 756: require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 863: require(current <= amount, "HOLOGRAPH: bond amount too small"); 871: for (uint256 i = _operatorPods.length; i <= pod; i++) { 1169: if (pod >= _operatorPods.length) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/enforcer/HolographERC20.sol 349: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 365: require(currentAllowance >= subtractedValue, "ERC20: decreased below zero"); 400: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 427: require(newAllowance >= currentAllowance, "ERC20: increased above max value"); 450: require(balance >= amount, "ERC20: balance check failed"); 469: require(block.timestamp <= deadline, "ERC20: expired deadline"); 529: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 599: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 629: require(accountBalance >= amount, "ERC20: amount exceeds balance"); 698: require(accountBalance >= amount, "ERC20: amount exceeds balance");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
immutable
& constant
for state variables that do not change their valueThere are 8 instances of this issue:
File: contracts/enforcer/HolographERC20.sol 151: uint256 private _eventConfig; 171: string private _name; 176: string private _symbol; 181: uint8 private _decimals;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 762: require(tokenOwner == address(this), "ERC721: contract not token owner"); 764: revert("ERC721: token does not exist"); 767: require(SourceERC721().afterOnERC721Received(_operator, _from, address(this), _tokenId, _data)); 769: return ERC721TokenReceiver.onERC721Received.selector;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
require()/revert()
strings longer than 32 bytes cost extra gasEach extra memory word of bytes past the original 32 incurs an MSTORE which costs 3 gas
There are 2 instances of this issue:
File: contracts/enforcer/PA1D.sol 411: require(balance > 10000, "PA1D: Not enough tokens to transfer"); 435: require(balance > 10000, "PA1D: Not enough tokens to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
revert()
/require()
strings to save gasCustom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hitby avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas
There are 120 instances of this issue:
File: contracts/HolographBridge.sol 148: require(msg.sender == address(_operator()), "HOLOGRAPH: operator only call"); 163: require(!_isInitialized(), "HOLOGRAPH: already initialized"); 203: require( 204: _registry().isHolographedContract(holographableContract) || address(_factory()) == holographableContract, 205: "HOLOGRAPH: not holographed" 206: ); 214: require(selector == Holographable.bridgeIn.selector, "HOLOGRAPH: bridge in failed"); 224: require( 225: HolographERC20Interface(hToken).holographBridgeMint(hTokenRecipient, hTokenValue) == 226: HolographERC20Interface.holographBridgeMint.selector, 227: "HOLOGRAPH: hToken mint failed" 228: ); 233: require(doNotRevert, "HOLOGRAPH: reverted"); 255: require( 256: _registry().isHolographedContract(holographableContract) || address(_factory()) == holographableContract, 257: "HOLOGRAPH: not holographed" 258: ); 270: require(selector == Holographable.bridgeOut.selector, "HOLOGRAPH: bridge out failed"); 352: require( 353: _registry().isHolographedContract(holographableContract) || address(_factory()) == holographableContract, 354: "HOLOGRAPH: not holographed" 355: );
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol
File: contracts/HolographFactory.sol 144: require(!_isInitialized(), "HOLOGRAPH: already initialized"); 220: require(_verifySigner(signature.r, signature.s, signature.v, hash, signer), "HOLOGRAPH: invalid signature"); 228: require(!_isContract(holographerAddress), "HOLOGRAPH: already deployed"); 250: require( 251: InitializableInterface(holographerAddress).init( 252: abi.encode(abi.encode(config.chainType, holograph, config.contractType, sourceContractAddress), config.initCode) 253: ) == InitializableInterface.init.selector, 254: "initialization failed" 255: );
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol
File: contracts/HolographOperator.sol 241: require(!_isInitialized(), "HOLOGRAPH: already initialized"); 309: require(_operatorJobs[hash] > 0, "HOLOGRAPH: invalid job"); 350: require(timeDifference > 0, "HOLOGRAPH: operator has time"); 354: require(gasPrice >= tx.gasprice, "HOLOGRAPH: gas spike detected"); 368: require(fallbackOperator == msg.sender, "HOLOGRAPH: invalid fallback"); 415: require(gasleft() > gasLimit, "HOLOGRAPH: not enough gas left"); 446: require(msg.sender == address(this), "HOLOGRAPH: operator only call"); 485: require(msg.sender == address(_messagingModule()), "HOLOGRAPH: messaging only call"); 591: require(msg.sender == _bridge(), "HOLOGRAPH: bridge only call"); 595: require(hlgFee < msg.value, "HOLOGRAPH: not enough value"); 728: require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 739: require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 756: require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 829: require(_bondedOperators[operator] != 0, "HOLOGRAPH: operator not bonded"); 839: require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed"); 857: require(_bondedOperators[operator] == 0 && _bondedAmounts[operator] == 0, "HOLOGRAPH: operator is bonded"); 863: require(current <= amount, "HOLOGRAPH: bond amount too small"); 881: require(_operatorPods[pod - 1].length < type(uint16).max, "HOLOGRAPH: too many operators"); 889: require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed"); 903: require(_bondedOperators[operator] != 0, "HOLOGRAPH: operator not bonded"); 911: require(_isContract(operator), "HOLOGRAPH: operator not contract"); 915: require(Ownable(operator).isOwner(msg.sender), "HOLOGRAPH: sender not owner"); 932: require(_utilityToken().transfer(recipient, amount), "HOLOGRAPH: token transfer failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: contracts/abstract/ERC20H.sol 117: require(msg.sender == holographer(), "ERC20: holographer only"); 123: require(msgSender() == _getOwner(), "ERC20: owner only function"); 125: require(msg.sender == _getOwner(), "ERC20: owner only function"); 147: require(!_isInitialized(), "ERC20: already initialized");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol
File: contracts/abstract/ERC721H.sol 117: require(msg.sender == holographer(), "ERC721: holographer only"); 123: require(msgSender() == _getOwner(), "ERC721: owner only function"); 125: require(msg.sender == _getOwner(), "ERC721: owner only function"); 147: require(!_isInitialized(), "ERC721: already initialized");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol
File: contracts/enforcer/HolographERC20.sol 192: require(msg.sender == _holograph().getBridge(), "ERC20: bridge only call"); 204: require(msg.sender == sourceContract, "ERC20: source only call"); 219: require(!_isInitialized(), "ERC20: already initialized"); 241: require(sourceContract.init(initCode) == InitializableInterface.init.selector, "ERC20: could not init source"); 349: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 365: require(currentAllowance >= subtractedValue, "ERC20: decreased below zero"); 387: require(SourceERC20().bridgeIn(fromChain, from, to, amount, data), "HOLOGRAPH: bridge in failed"); 400: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 427: require(newAllowance >= currentAllowance, "ERC20: increased above max value"); 445: require(_isContract(account), "ERC20: operator not contract"); 450: require(balance >= amount, "ERC20: balance check failed"); 452: revert("ERC20: failed getting balance"); 469: require(block.timestamp <= deadline, "ERC20: expired deadline"); 482: require(signer == account, "ERC20: invalid signature"); 505: require(_checkOnERC20Received(msg.sender, recipient, amount, data), "ERC20: non ERC20Receiver"); 529: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 539: require(_checkOnERC20Received(account, recipient, amount, data), "ERC20: non ERC20Receiver"); 599: require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 620: require(account != address(0), "ERC20: account is zero address"); 621: require(spender != address(0), "ERC20: spender is zero address"); 627: require(account != address(0), "ERC20: account is zero address"); 629: require(accountBalance >= amount, "ERC20: amount exceeds balance"); 645: require(erc165support, "ERC20: no ERC165 support"); 653: revert("ERC20: non ERC20Receiver"); 661: revert("ERC20: eip-4524 not supported"); 665: revert("ERC20: no ERC165 support"); 684: require(to != address(0), "ERC20: minting to burn address"); 695: require(account != address(0), "ERC20: account is zero address"); 696: require(recipient != address(0), "ERC20: recipient is zero address"); 698: require(accountBalance >= amount, "ERC20: amount exceeds balance");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: contracts/enforcer/HolographERC721.sol 212: require(msg.sender == _holograph().getBridge(), "ERC721: bridge only call"); 224: require(msg.sender == sourceContract, "ERC721: source only call"); 239: require(!_isInitialized(), "ERC721: already initialized"); 258: require(sourceContract.init(initCode) == InitializableInterface.init.selector, "ERC721: could not init source"); 263: require(success && selector == InitializableInterface.init.selector, "ERC721: coud not init PA1D"); 323: require(_exists(tokenId), "ERC721: token does not exist"); 370: require(to != tokenOwner, "ERC721: cannot approve self"); 371: require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 388: require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 404: require(!_exists(tokenId), "ERC721: token already exists"); 408: require(SourceERC721().bridgeIn(fromChain, from, to, tokenId, data), "HOLOGRAPH: bridge in failed"); 419: require(to != address(0), "ERC721: zero address"); 420: require(_isApproved(sender, tokenId), "ERC721: sender not approved"); 421: require(from == _tokenOwner[tokenId], "ERC721: from is not owner"); 458: require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 464: require( 465: (ERC165(to).supportsInterface(ERC165.supportsInterface.selector) && 466: ERC165(to).supportsInterface(ERC721TokenReceiver.onERC721Received.selector) && 467: ERC721TokenReceiver(to).onERC721Received(address(this), from, tokenId, data) == 468: ERC721TokenReceiver.onERC721Received.selector), 469: "ERC721: onERC721Received fail" 470: ); 484: require(to != msg.sender, "ERC721: cannot approve self"); 513: require(!_burnedTokens[token], "ERC721: can't mint burned token"); 622: require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 639: require(wallet != address(0), "ERC721: zero address"); 689: require(tokenOwner != address(0), "ERC721: token does not exist"); 700: require(index < _allTokens.length, "ERC721: index out of bounds"); 729: require(index < balanceOf(wallet), "ERC721: index out of bounds"); 757: require(_isContract(_operator), "ERC721: operator not contract"); 762: require(tokenOwner == address(this), "ERC721: contract not token owner"); 764: revert("ERC721: token does not exist"); 815: require(tokenId > 0, "ERC721: token id cannot be zero"); 816: require(to != address(0), "ERC721: minting to burn address"); 817: require(!_exists(tokenId), "ERC721: token already exists"); 818: require(!_burnedTokens[tokenId], "ERC721: token has been burned"); 869: require(_tokenOwner[tokenId] == from, "ERC721: token not owned"); 870: require(to != address(0), "ERC721: use burn instead"); 906: require(_exists(tokenId), "ERC721: token does not exist");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: contracts/enforcer/Holographer.sol 148: require(!_isInitialized(), "HOLOGRAPHER: already initialized"); 166: require(success && selector == InitializableInterface.init.selector, "initialization failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
File: contracts/enforcer/PA1D.sol 159: require(isOwner(), "PA1D: caller not an owner"); 174: require(!_isInitialized(), "PA1D: already initialized"); 190: require(initialized == 0, "PA1D: already initialized"); 390: require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer"); 411: require(balance > 10000, "PA1D: Not enough tokens to transfer"); 416: require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token"); 435: require(balance > 10000, "PA1D: Not enough tokens to transfer"); 439: require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token"); 460: require(matched, "PA1D: sender not authorized"); 472: require(addresses.length == bps.length, "PA1D: missmatched array lenghts"); 477: require(totalBp == 10000, "PA1D: bps down't equal 10000");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol