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: 27/144
Findings: 3
Award: $277.94
🌟 Selected for report: 0
🚀 Solo Findings: 0
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol#L839 https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol#L889 https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol#L932 https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol#L416 https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol#L439
Some ERC20 tokens functions don't return a boolean, for example, USDT, BNB, OMG. So the contracts simply won't work with tokens like that as the token.
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol#L839
'require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed");'
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol#L889
'require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed");'
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol#L932
'require(_utilityToken().transfer(recipient, amount), "HOLOGRAPH: token transfer failed");'
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol#L416
'require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token");'
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol#L439
'require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token");'
Manual auditing
Use the OpenZepplin's safeTransfer and safeTransferFrom functions
#0 - gzeoneth
2022-10-28T10:02:14Z
Duplicate of #456
🌟 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
55.6726 USDC - $55.67
receive()
function will lock Ether in contractIf the intention is for the Ether to be used, the function should call another function, otherwise it should revert
2022-10-holograph/HolographBridge.sol::577 => receive() external payable { 2022-10-holograph/HolographFactory.sol::340 => receive() external payable { 2022-10-holograph/HolographOperator.sol::1209 => receive() external payable {} 2022-10-holograph/abstract/ERC20H.sol::212 => receive() external payable {} 2022-10-holograph/abstract/ERC721H.sol::212 => receive() external payable {} 2022-10-holograph/enforcer/HolographERC20.sol::251 => receive() external payable {} 2022-10-holograph/enforcer/HolographERC721.sol::962 => receive() external payable {} 2022-10-holograph/enforcer/Holographer.sol::223 => receive() external payable {} 2022-10-holograph/module/LayerZeroModule.sol::416 => receive() external payable {
address.call{value:x}()
should be used instead of payable.transfer()
The use of payable.transfer()
is heavily frowned upon because it can lead to the locking of funds. The transfer()
call requires that the recipient has a payable
callback, only provides 2300 gas for its operation. This means the following cases can cause the transfer to fail:
payable
callbackpayable
callback spends more than 2300 gas (which is only enough to emit something)2022-10-holograph/HolographOperator.sol::596 => payable(hToken).transfer(hlgFee);
_safeMint()
should be used rather than _mint()
wherever possible_mint() is discouraged in favor of _safeMint() which ensures that the recipient is either an EOA or implements IERC721Receiver. Both OpenZeppelin and solmate have versions of this function
2022-10-holograph/enforcer/HolographERC20.sol::385 => _mint(to, amount); 2022-10-holograph/enforcer/HolographERC20.sol::416 => _mint(to, amount); 2022-10-holograph/enforcer/HolographERC20.sol::557 => _mint(to, amount); 2022-10-holograph/enforcer/HolographERC20.sol::565 => _mint(wallets[i], amounts[i]); 2022-10-holograph/enforcer/HolographERC721.sol::406 => _mint(to, tokenId); 2022-10-holograph/enforcer/HolographERC721.sol::514 => _mint(to, token);
2022-10-holograph/HolographBridge.sol::325 => return reason; 2022-10-holograph/HolographOperator.sol::1170 => return current; 2022-10-holograph/HolographOperator.sol::1179 => return current; 2022-10-holograph/enforcer/HolographERC20.sol::274 => return _decimals; 2022-10-holograph/enforcer/HolographERC20.sol::311 => return _name; 2022-10-holograph/enforcer/HolographERC20.sol::319 => return _symbol; 2022-10-holograph/enforcer/HolographERC20.sol::323 => return _totalSupply; 2022-10-holograph/enforcer/HolographERC721.sol::283 => return _name; 2022-10-holograph/enforcer/HolographERC721.sol::314 => return _symbol; 2022-10-holograph/enforcer/HolographERC721.sol::882 => return currentChain; 2022-10-holograph/enforcer/HolographERC721.sol::884 => return uint32(0); 2022-10-holograph/enforcer/PA1D.sol::630 => return receiver; 2022-10-holograph/enforcer/PA1D.sol::660 => return receiver; 2022-10-holograph/enforcer/PA1D.sol::674 => return bidShares;
require()
/revert()
statements should have descriptive reason strings2022-10-holograph/HolographBridge.sol::322 => revert(add(payload, 0x20), mload(payload)) 2022-10-holograph/HolographBridge.sol::366 => revert(revertReason); 2022-10-holograph/HolographBridge.sol::430 => revert(0, returndatasize()) 2022-10-holograph/HolographBridge.sol::578 => revert(); 2022-10-holograph/HolographBridge.sol::585 => revert(); 2022-10-holograph/HolographFactory.sol::341 => revert(); 2022-10-holograph/HolographFactory.sol::348 => revert(); 2022-10-holograph/HolographOperator.sol::474 => revert(0, 0) 2022-10-holograph/HolographOperator.sol::562 => revert(0, returndatasize()) 2022-10-holograph/HolographOperator.sol::676 => revert(0, returndatasize())); 2022-10-holograph/HolographOperator.sol::1215 => revert(); 2022-10-holograph/abstract/ERC20H.sol::225 => revert(0x00, 0x00) 2022-10-holograph/abstract/ERC721H.sol::225 => revert(0x00, 0x00) 2022-10-holograph/enforcer/HolographERC20.sol::265 => revert(0, returndatasize()) 2022-10-holograph/enforcer/HolographERC20.sol::328 => require(SourceERC20().beforeApprove(msg.sender, spender, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::332 => require(SourceERC20().afterApprove(msg.sender, spender, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::339 => require(SourceERC20().beforeBurn(msg.sender, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::343 => require(SourceERC20().afterBurn(msg.sender, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::354 => require(SourceERC20().beforeBurn(account, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::358 => require(SourceERC20().afterBurn(account, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::371 => require(SourceERC20().beforeApprove(msg.sender, spender, newAllowance)); 2022-10-holograph/enforcer/HolographERC20.sol::375 => require(SourceERC20().afterApprove(msg.sender, spender, newAllowance));; 2022-10-holograph/enforcer/HolographERC20.sol::430 => require(SourceERC20().beforeApprove(msg.sender, spender, newAllowance)); 2022-10-holograph/enforcer/HolographERC20.sol::434 => require(SourceERC20().afterApprove(msg.sender, spender, newAllowance)); 2022-10-holograph/enforcer/HolographERC20.sol::484 => require(SourceERC20().beforeApprove(account, spender, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::488 => require(SourceERC20().afterApprove(account, spender, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::502 => require(SourceERC20().beforeSafeTransfer(msg.sender, recipient, amount, data)); 2022-10-holograph/enforcer/HolographERC20.sol::582 => require(SourceERC20().beforeTransfer(msg.sender, recipient, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::586 => require(SourceERC20().afterTransfer(msg.sender, recipient, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::606 => require(SourceERC20().beforeTransfer(account, recipient, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::610 => require(SourceERC20().afterTransfer(account, recipient, amount)); 2022-10-holograph/enforcer/HolographERC20.sol::668 => revert(add(32, reason), mload(reason)) 2022-10-holograph/enforcer/HolographERC721.sol::391 => require(SourceERC721().beforeBurn(wallet, tokenId)); 2022-10-holograph/enforcer/HolographERC721.sol::395 => require(SourceERC721().afterBurn(wallet, tokenId)); 2022-10-holograph/enforcer/HolographERC721.sol::460 => require(SourceERC721().beforeSafeTransfer(from, to, tokenId, data)); 2022-10-holograph/enforcer/HolographERC721.sol::473 => require(SourceERC721().afterSafeTransfer(from, to, tokenId, data)); 2022-10-holograph/enforcer/HolographERC721.sol::486 => require(SourceERC721().beforeApprovalAll(to, approved)); 2022-10-holograph/enforcer/HolographERC721.sol::491 => require(SourceERC721().afterApprovalAll(to, approved)); 2022-10-holograph/enforcer/HolographERC721.sol::624 => require(SourceERC721().beforeTransfer(from, to, tokenId, data)); 2022-10-holograph/enforcer/HolographERC721.sol::628 => require(SourceERC721().afterTransfer(from, to, tokenId, data)); 2022-10-holograph/enforcer/HolographERC721.sol::759 => require(SourceERC721().beforeOnERC721Received(_operator, _from, address(this), _tokenId, _data)); 2022-10-holograph/enforcer/HolographERC721.sol::767 => require(SourceERC721().afterOnERC721Received(_operator, _from, address(this), _tokenId, _data)); 2022-10-holograph/enforcer/HolographERC721.sol::979 => revert(0, returndatasize()) 2022-10-holograph/enforcer/HolographERC721.sol::993 => revert(0, returndatasize()) 2022-10-holograph/enforcer/Holographer.sol::236 => revert(0, returndatasize()) 2022-10-holograph/module/LayerZeroModule.sol::199 => revert(0x80, 0xc4) 2022-10-holograph/module/LayerZeroModule.sol::215 => revert(0x80, 0xc4) 2022-10-holograph/module/LayerZeroModule.sol::417 => revert(); 2022-10-holograph/module/LayerZeroModule.sol::424 => revert();
2022-10-holograph/HolographBridge.sol::551 => jobNonce := add(sload(_jobNonceSlot), 0x0000000000000000000000000000000000000000000000000000000000000001) 2022-10-holograph/HolographOperator.sol::256 => _baseBondAmount = 100 * (10**18); // one single token unit * 100 2022-10-holograph/HolographOperator.sol::265 => _operatorThresholdDivisor = 100; // == * 0.01 2022-10-holograph/HolographOperator.sol::528 => (_randomBlockHash(random, podSize, 3) << 128) | 2022-10-holograph/HolographOperator.sol::706 => uint16(packed >> 128), 2022-10-holograph/HolographOperator.sol::1114 => jobNonce := add(sload(_jobNonceSlot), 0x0000000000000000000000000000000000000000000000000000000000000001) 2022-10-holograph/HolographOperator.sol::1203 => return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); 2022-10-holograph/abstract/ERC20H.sol::221 => mstore(0x80, 0x0000000000000000000000000000000000000000000000000000000000000001) 2022-10-holograph/abstract/ERC721H.sol::216 => */ 2022-10-holograph/abstract/ERC721H.sol::221 => mstore(0x80, 0x0000000000000000000000000000000000000000000000000000000000000001) 2022-10-holograph/enforcer/HolographERC20.sol::222 => sstore(_reentrantSlot, 0x0000000000000000000000000000000000000000000000000000000000000001) 2022-10-holograph/enforcer/HolographERC721.sol::955 => 0x0000000000000000000000000000000000000000000000000000000050413144 2022-10-holograph/enforcer/PA1D.sol::388 => uint256 gasCost = (23300 * length) + length; 2022-10-holograph/enforcer/PA1D.sol::390 => require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer"); 2022-10-holograph/enforcer/PA1D.sol::395 => sending = ((bps[i] * balance) / 10000); 2022-10-holograph/enforcer/PA1D.sol::411 => require(balance > 10000, "PA1D: Not enough tokens to transfer"); 2022-10-holograph/enforcer/PA1D.sol::415 => sending = ((bps[i] * balance) / 10000); 2022-10-holograph/enforcer/PA1D.sol::435 => require(balance > 10000, "PA1D: Not enough tokens to transfer"); 2022-10-holograph/enforcer/PA1D.sol::438 => sending = ((bps[i] * balance) / 10000); 2022-10-holograph/enforcer/PA1D.sol::477 => require(totalBp == 10000, "PA1D: bps down't equal 10000"); 2022-10-holograph/enforcer/PA1D.sol::551 => return (_getDefaultReceiver(), (_getDefaultBp() * value) / 10000); 2022-10-holograph/enforcer/PA1D.sol::553 => return (_getReceiver(tokenId), (_getBp(tokenId) * value) / 10000); 2022-10-holograph/enforcer/PA1D.sol::641 => return (_getDefaultBp() * amount) / 10000; 2022-10-holograph/enforcer/PA1D.sol::643 => return (_getBp(tokenId) * amount) / 10000; 2022-10-holograph/module/LayerZeroModule.sol::195 => mstore(0x80, 0x08c379a000000000000000000000000000000000000000000000000000000000) 2022-10-holograph/module/LayerZeroModule.sol::196 => mstore(0xa0, 0x0000002000000000000000000000000000000000000000000000000000000000) 2022-10-holograph/module/LayerZeroModule.sol::198 => mstore(0xe0, 0x0000000000000000000000000000000000000000000000000000000000000000) 2022-10-holograph/module/LayerZeroModule.sol::211 => mstore(0x80, 0x08c379a000000000000000000000000000000000000000000000000000000000) 2022-10-holograph/module/LayerZeroModule.sol::212 => mstore(0xa0, 0x0000002000000000000000000000000000000000000000000000000000000000) 2022-10-holograph/module/LayerZeroModule.sol::214 => mstore(0xe0, 0x6572000000000000000000000000000000000000000000000000000000000000)
indexed
fieldsEach event should use three indexed fields if there are three or more fields
2022-10-holograph/enforcer/PA1D.sol::153 => event SecondarySaleFees(uint256 tokenId, address[] recipients, uint256[] bps);
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment
2022-10-holograph/HolographOperator.sol::701 => // TODO: move the bit-shifting around to have it be sequential
2**<n> - 1
should be re-written as type(uint<n>).max
Earlier versions of solidity can use uint<n>(-1) instead. Expressions not including the - 1 can often be re-written to accomodate the change (e.g. by using a > rather than a >=, which will also save some gas)
2022-10-holograph/HolographOperator.sol::1172 => uint256 threshold = _operatorThreshold / (2**pod);
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents’ functions and change the visibility from public to external.
2022-10-holograph/HolographOperator.sol::690 => function getJobDetails(bytes32 jobHash) public view returns (OperatorJob memory) { 2022-10-holograph/enforcer/HolographERC20.sol::273 => function decimals() public view returns (uint8) { 2022-10-holograph/enforcer/HolographERC20.sol::297 => function allowance(address account, address spender) public view returns (uint256) { 2022-10-holograph/enforcer/HolographERC20.sol::301 => function balanceOf(address account) public view returns (uint256) { 2022-10-holograph/enforcer/HolographERC20.sol::306 => function DOMAIN_SEPARATOR() public view returns (bytes32) { 2022-10-holograph/enforcer/HolographERC20.sol::310 => function name() public view returns (string memory) { 2022-10-holograph/enforcer/HolographERC20.sol::314 => function nonces(address account) public view returns (uint256) { 2022-10-holograph/enforcer/HolographERC20.sol::318 => function symbol() public view returns (string memory) { 2022-10-holograph/enforcer/HolographERC20.sol::322 => function totalSupply() public view returns (uint256) { 2022-10-holograph/enforcer/HolographERC20.sol::326 => function approve(address spender, uint256 amount) public returns (bool) { 2022-10-holograph/enforcer/HolographERC20.sol::337 => function burn(uint256 amount) public { 2022-10-holograph/enforcer/HolographERC20.sol::347 => function burnFrom(address account, uint256 amount) public returns (bool) { 2022-10-holograph/enforcer/HolographERC20.sol::363 => function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 2022-10-holograph/enforcer/HolographERC20.sol::420 => function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 2022-10-holograph/enforcer/HolographERC20.sol::492 => function safeTransfer(address recipient, uint256 amount) public returns (bool) { 2022-10-holograph/enforcer/HolographERC20.sol::580 => function transfer(address recipient, uint256 amount) public returns (bool) { 2022-10-holograph/enforcer/HolographERC20.sol::740 => function owner() public view override returns (address) { 2022-10-holograph/enforcer/HolographERC721.sol::638 => function balanceOf(address wallet) public view returns (uint256) { 2022-10-holograph/enforcer/HolographERC721.sol::643 => function burned(uint256 tokenId) public view returns (bool) { 2022-10-holograph/enforcer/HolographERC721.sol::656 => function exists(uint256 tokenId) public view returns (bool) { 2022-10-holograph/enforcer/HolographERC721.sol::935 => function owner() public view override returns (address) { 2022-10-holograph/enforcer/Holographer.sol::192 => function getHolographEnforcer() public view returns (address) { 2022-10-holograph/enforcer/PA1D.sol::471 => function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner { 2022-10-holograph/enforcer/PA1D.sol::488 => function getPayoutInfo() public view returns (address payable[] memory addresses, uint256[] memory bps) { 2022-10-holograph/enforcer/PA1D.sol::497 => function getEthPayout() public { 2022-10-holograph/enforcer/PA1D.sol::507 => function getTokenPayout(address tokenAddress) public { 2022-10-holograph/enforcer/PA1D.sol::517 => function getTokensPayout(address[] memory tokenAddresses) public { 2022-10-holograph/enforcer/PA1D.sol::549 => function royaltyInfo(uint256 tokenId, uint256 value) public view returns (address, uint256) { 2022-10-holograph/enforcer/PA1D.sol::558 => function getFeeBps(uint256 tokenId) public view returns (uint256[] memory) { 2022-10-holograph/enforcer/PA1D.sol::569 => function getFeeRecipients(uint256 tokenId) public view returns (address payable[] memory) { 2022-10-holograph/enforcer/PA1D.sol::590 => function getRoyalties(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) { 2022-10-holograph/enforcer/PA1D.sol::604 => function getFees(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) { 2022-10-holograph/enforcer/PA1D.sol::649 => function marketContract() public view returns (address) { 2022-10-holograph/enforcer/PA1D.sol::655 => function tokenCreators(uint256 tokenId) public view returns (address) { 2022-10-holograph/enforcer/PA1D.sol::665 => function bidSharesForToken(uint256 tokenId) public view returns (ZoraBidShares memory bidShares) { 2022-10-holograph/enforcer/PA1D.sol::683 => function getTokenAddress(string memory tokenName) public view returns (address) {
There are units for seconds, minutes, hours, days, and weeks
2022-10-holograph/HolographOperator.sol::254 => _blockTime = 60; // 60 seconds allowed for execution
Consider defining in only one contract so that values cannot become out of sync when only one location is updated
2022-10-holograph/HolographFactory.sol::206 => bytes32 hash = keccak256( 2022-10-holograph/HolographOperator.sol::305 => bytes32 hash = keccak256(bridgeInRequestPayload); 2022-10-holograph/HolographOperator.sol::491 => bytes32 jobHash = keccak256(bridgeInRequestPayload); 2022-10-holograph/enforcer/HolographERC20.sol::470 => bytes32 structHash = keccak256( 2022-10-holograph/enforcer/PA1D.sol::308 => slot = keccak256(abi.encodePacked(i, slot)); 2022-10-holograph/enforcer/PA1D.sol::324 => slot = keccak256(abi.encodePacked(i, slot)); 2022-10-holograph/enforcer/PA1D.sol::341 => slot = keccak256(abi.encodePacked(i, slot)); 2022-10-holograph/enforcer/PA1D.sol::357 => slot = keccak256(abi.encodePacked(i, slot));
🌟 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
222.2506 USDC - $222.25
immutable
2022-10-holograph/HolographOperator.sol::158 => uint256 private _blockTime; 2022-10-holograph/HolographOperator.sol::163 => uint256 private _baseBondAmount; 2022-10-holograph/HolographOperator.sol::168 => uint256 private _podMultiplier; 2022-10-holograph/HolographOperator.sol::173 => uint256 private _operatorThreshold; 2022-10-holograph/HolographOperator.sol::178 => uint256 private _operatorThresholdStep; 2022-10-holograph/HolographOperator.sol::183 => uint256 private _operatorThresholdDivisor; 2022-10-holograph/HolographOperator.sol::188 => uint256 private _inboundMessageCounter; 2022-10-holograph/HolographOperator.sol::208 => uint32 private _operatorTempStorageCounter; 2022-10-holograph/HolographOperator.sol::213 => address[][] private _operatorPods; 2022-10-holograph/enforcer/HolographERC20.sol::151 => uint256 private _eventConfig; 2022-10-holograph/enforcer/HolographERC20.sol::166 => uint256 private _totalSupply; 2022-10-holograph/enforcer/HolographERC20.sol::171 => string private _name; 2022-10-holograph/enforcer/HolographERC20.sol::176 => string private _symbol; 2022-10-holograph/enforcer/HolographERC20.sol::181 => uint8 private _decimals; 2022-10-holograph/enforcer/HolographERC721.sol::145 => uint256 private _eventConfig; 2022-10-holograph/enforcer/HolographERC721.sol::150 => string private _name; 2022-10-holograph/enforcer/HolographERC721.sol::155 => string private _symbol; 2022-10-holograph/enforcer/HolographERC721.sol::160 => uint16 private _bps; 2022-10-holograph/enforcer/HolographERC721.sol::165 => uint256[] private _allTokens;
<array>.length
should not be looked up in every loop of a for
loopEven memory arrays incur the overhead of bit tests and bit shifts to calculate the array length. Storage array length checks incur an extra Gwarmaccess (100 gas) PER-LOOP.
2022-10-holograph/HolographOperator.sol::781 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/HolographOperator.sol::871 => for (uint256 i = _operatorPods.length; i <= pod; i++) { 2022-10-holograph/enforcer/HolographERC20.sol::564 => for (uint256 i = 0; i < wallets.length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::357 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::716 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::307 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::323 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::340 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::356 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::394 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::414 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::432 => for (uint256 t = 0; t < tokenAddresses.length; t++) { 2022-10-holograph/enforcer/PA1D.sol::437 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::454 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::474 => for (uint256 i = 0; i < addresses.length; i++) {
++i/i++
should be unchecked{++i}
/unchecked{++i}
when it is not possible for them to overflow, as is the case when used in for
and while
loops2022-10-holograph/HolographOperator.sol::433 => ++_inboundMessageCounter; 2022-10-holograph/HolographOperator.sol::495 => ++_operatorTempStorageCounter; 2022-10-holograph/HolographOperator.sol::781 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/HolographOperator.sol::871 => for (uint256 i = _operatorPods.length; i <= pod; i++) { 2022-10-holograph/enforcer/HolographERC20.sol::564 => for (uint256 i = 0; i < wallets.length; i++) { 2022-10-holograph/enforcer/HolographERC20.sol::713 => _nonces[account]++; 2022-10-holograph/enforcer/HolographERC721.sol::357 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::531 => // for (uint256 i = 0; i < tokenIds.length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::547 => // for (uint256 i = 0; i < tokenIds.length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::564 => // for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::568 => // startingTokenId++; 2022-10-holograph/enforcer/HolographERC721.sol::716 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::779 => _ownedTokensCount[to]++; 2022-10-holograph/enforcer/PA1D.sol::307 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::323 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::340 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::356 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::394 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::397 => // sent = sent + sending; 2022-10-holograph/enforcer/PA1D.sol::414 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::432 => for (uint256 t = 0; t < tokenAddresses.length; t++) { 2022-10-holograph/enforcer/PA1D.sol::437 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::454 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::474 => for (uint256 i = 0; i < addresses.length; i++) {
require()
/revert()
strings longer than 32 bytes cost extra gas2022-10-holograph/enforcer/PA1D.sol::411 => require(balance > 10000, "PA1D: Not enough tokens to transfer"); 2022-10-holograph/enforcer/PA1D.sol::435 => require(balance > 10000, "PA1D: Not enough tokens to transfer");
2022-10-holograph/HolographOperator.sol::718 => return _operatorPods.length; 2022-10-holograph/HolographOperator.sol::729 => return _operatorPods[pod - 1].length; 2022-10-holograph/HolographOperator.sol::805 => return _bondedAmounts[operator]; 2022-10-holograph/HolographOperator.sol::815 => return _bondedOperators[operator]; 2022-10-holograph/abstract/ERC20H.sol::141 => return _init(initPayload); 2022-10-holograph/abstract/ERC20H.sol::182 => return _getOwner(); 2022-10-holograph/abstract/ERC721H.sol::141 => return _init(initPayload); 2022-10-holograph/abstract/ERC721H.sol::182 => return _getOwner(); 2022-10-holograph/enforcer/HolographERC20.sol::274 => return _decimals; 2022-10-holograph/enforcer/HolographERC20.sol::298 => return _allowances[account][spender]; 2022-10-holograph/enforcer/HolographERC20.sol::302 => return _balances[account]; 2022-10-holograph/enforcer/HolographERC20.sol::307 => return _domainSeparatorV4(); 2022-10-holograph/enforcer/HolographERC20.sol::311 => return _name; 2022-10-holograph/enforcer/HolographERC20.sol::315 => return _nonces[account]; 2022-10-holograph/enforcer/HolographERC20.sol::319 => return _symbol; 2022-10-holograph/enforcer/HolographERC20.sol::323 => return _totalSupply; 2022-10-holograph/enforcer/HolographERC20.sol::737 => return _holograph().getInterfaces(); 2022-10-holograph/enforcer/HolographERC721.sol::283 => return _name; 2022-10-holograph/enforcer/HolographERC721.sol::314 => return _symbol; 2022-10-holograph/enforcer/HolographERC721.sol::337 => return _ownedTokens[wallet]; 2022-10-holograph/enforcer/HolographERC721.sol::640 => return _ownedTokensCount[wallet]; 2022-10-holograph/enforcer/HolographERC721.sol::644 => return _burnedTokens[tokenId]; 2022-10-holograph/enforcer/HolographERC721.sol::657 => return _tokenOwner[tokenId] != address(0); 2022-10-holograph/enforcer/HolographERC721.sol::667 => return _tokenApprovals[tokenId]; 2022-10-holograph/enforcer/HolographERC721.sol::678 => return _operatorApprovals[wallet][operator]; 2022-10-holograph/enforcer/HolographERC721.sol::701 => return _allTokens[index]; 2022-10-holograph/enforcer/HolographERC721.sol::730 => return _ownedTokens[wallet][index]; 2022-10-holograph/enforcer/HolographERC721.sol::739 => return _allTokens.length; 2022-10-holograph/enforcer/HolographERC721.sol::932 => return _holograph().getInterfaces(); 2022-10-holograph/enforcer/PA1D.sol::628 => return _getDefaultReceiver(); 2022-10-holograph/enforcer/PA1D.sol::658 => return _getDefaultReceiver(); 2022-10-holograph/enforcer/PA1D.sol::684 => return _getTokenAddress(tokenName);
> 0
costs more gas than != 0
when used on a uint
in a require()
statement2022-10-holograph/HolographBridge.sol::218 => if (hTokenValue > 0) { 2022-10-holograph/HolographOperator.sol::309 => require(_operatorJobs[hash] > 0, "HOLOGRAPH: invalid job"); 2022-10-holograph/HolographOperator.sol::350 => require(timeDifference > 0, "HOLOGRAPH: operator has time"); 2022-10-holograph/HolographOperator.sol::363 => if (podIndex > 0 && podIndex < _operatorPods[pod].length) { 2022-10-holograph/HolographOperator.sol::398 => if (leftovers > 0) { 2022-10-holograph/HolographOperator.sol::1126 => if (operatorIndex > 0) { 2022-10-holograph/enforcer/HolographERC721.sol::815 => require(tokenId > 0, "ERC721: token id cannot be zero");
2022-10-holograph/HolographBridge.sol::380 => uint256 fee = 0; 2022-10-holograph/HolographOperator.sol::310 => uint256 gasLimit = 0; 2022-10-holograph/HolographOperator.sol::311 => uint256 gasPrice = 0; 2022-10-holograph/HolographOperator.sol::399 => _bondedAmounts[job.operator] = 0; 2022-10-holograph/HolographOperator.sol::781 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/HolographOperator.sol::924 => _bondedAmounts[operator] = 0; 2022-10-holograph/HolographOperator.sol::1132 => _bondedOperators[operator] = 0; 2022-10-holograph/HolographOperator.sol::1136 => _operatorPodIndex[operator] = 0; 2022-10-holograph/enforcer/HolographERC20.sol::564 => for (uint256 i = 0; i < wallets.length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::357 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::716 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::307 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::323 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::340 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::356 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::394 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::414 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::432 => for (uint256 t = 0; t < tokenAddresses.length; t++) { 2022-10-holograph/enforcer/PA1D.sol::437 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::454 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::474 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::667 => bidShares.prevOwner.value = 0; 2022-10-holograph/enforcer/PA1D.sol::668 => bidShares.owner.value = 0;
++i
costs less gas than i++
, especially when it’s used in forloops (--i
/i--
too)2022-10-holograph/HolographOperator.sol::781 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/HolographOperator.sol::871 => for (uint256 i = _operatorPods.length; i <= pod; i++) { 2022-10-holograph/enforcer/HolographERC20.sol::564 => for (uint256 i = 0; i < wallets.length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::357 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/HolographERC721.sol::716 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::307 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::323 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::340 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::356 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::394 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::414 => for (uint256 i = 0; i < length; i++) { 2022-10-holograph/enforcer/PA1D.sol::432 => for (uint256 t = 0; t < tokenAddresses.length; t++) { 2022-10-holograph/enforcer/PA1D.sol::437 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::454 => for (uint256 i = 0; i < addresses.length; i++) { 2022-10-holograph/enforcer/PA1D.sol::474 => for (uint256 i = 0; i < addresses.length; i++) {
require()
statements that use &&
Cost gasSee this issue for an example
2022-10-holograph/HolographOperator.sol::857 => require(_bondedOperators[operator] == 0 && _bondedAmounts[operator] == 0, "HOLOGRAPH: operator is bonded"); 2022-10-holograph/enforcer/HolographERC721.sol::263 => require(success && selector == InitializableInterface.init.selector, "ERC721: coud not init PA1D"); 2022-10-holograph/enforcer/Holographer.sol::166 => require(success && selector == InitializableInterface.init.selector, "initialization failed");
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadWhen 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.11/internals/layout_in_storage.html Use a larger size then downcast where needed
2022-10-holograph/HolographBridge.sol::192 => uint32 fromChain, 2022-10-holograph/HolographBridge.sol::246 => uint32 toChain, 2022-10-holograph/HolographBridge.sol::298 => uint32 toChain, 2022-10-holograph/HolographBridge.sol::343 => uint32 toChain, 2022-10-holograph/HolographFactory.sol::161 => uint32, /* fromChain*/ 2022-10-holograph/HolographFactory.sol::178 => uint32, /* toChain*/ 2022-10-holograph/HolographFactory.sol::323 => uint8 v, 2022-10-holograph/HolographOperator.sol::208 => uint32 private _operatorTempStorageCounter; 2022-10-holograph/HolographOperator.sol::585 => uint32 toChain, 2022-10-holograph/HolographOperator.sol::665 => uint32, 2022-10-holograph/HolographOperator.sol::697 => uint8(packed >> 248), 2022-10-holograph/HolographOperator.sol::698 => uint16(_blockTime), 2022-10-holograph/HolographOperator.sol::699 => _operatorTempStorage[uint32(packed >> 216)], 2022-10-holograph/HolographOperator.sol::700 => uint40(packed >> 176), 2022-10-holograph/HolographOperator.sol::702 => uint64(packed >> 16), 2022-10-holograph/HolographOperator.sol::704 => uint16(packed >> 160), 2022-10-holograph/HolographOperator.sol::705 => uint16(packed >> 144), 2022-10-holograph/HolographOperator.sol::706 => uint16(packed >> 128), 2022-10-holograph/HolographOperator.sol::707 => uint16(packed >> 112), 2022-10-holograph/HolographOperator.sol::708 => uint16(packed >> 96) 2022-10-holograph/enforcer/HolographERC20.sol::181 => uint8 private _decimals; 2022-10-holograph/enforcer/HolographERC20.sol::229 => uint8 contractDecimals, 2022-10-holograph/enforcer/HolographERC20.sol::380 => function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { 2022-10-holograph/enforcer/HolographERC20.sol::393 => uint32 toChain, 2022-10-holograph/enforcer/HolographERC20.sol::465 => uint8 v, 2022-10-holograph/enforcer/HolographERC721.sol::160 => uint16 private _bps; 2022-10-holograph/enforcer/HolographERC721.sol::248 => uint16 contractBps, 2022-10-holograph/enforcer/HolographERC721.sol::414 => uint32 toChain, 2022-10-holograph/enforcer/HolographERC721.sol::878 => function _chain() private view returns (uint32) { 2022-10-holograph/enforcer/HolographERC721.sol::879 => uint32 currentChain = HolographInterface(HolographerInterface(payable(address(this))).getHolograph()) 2022-10-holograph/enforcer/HolographERC721.sol::884 => return uint32(0); 2022-10-holograph/enforcer/Holographer.sol::150 => (uint32 originChain, address holograph, bytes32 contractType, address sourceContract) = abi.decode( 2022-10-holograph/enforcer/Holographer.sol::152 => (uint32, address, bytes32, address) 2022-10-holograph/enforcer/Holographer.sol::205 => function getOriginChain() external view returns (uint32 originChain) { 2022-10-holograph/module/LayerZeroModule.sol::181 => uint16, /* _srcChainId*/ 2022-10-holograph/module/LayerZeroModule.sol::183 => uint64, /* _nonce*/ 2022-10-holograph/module/LayerZeroModule.sol::230 => uint32 toChain, 2022-10-holograph/module/LayerZeroModule.sol::252 => uint32 toChain, 2022-10-holograph/module/LayerZeroModule.sol::257 => uint16 lzDestChain = uint16( 2022-10-holograph/module/LayerZeroModule.sol::265 => (uint128 dstPriceRatio, uint128 dstGasPriceInWei) = _getPricing(lz, lzDestChain); 2022-10-holograph/module/LayerZeroModule.sol::270 => uint16(1), 2022-10-holograph/module/LayerZeroModule.sol::278 => uint32 toChain, 2022-10-holograph/module/LayerZeroModule.sol::286 => uint16 lzDestChain = uint16(
require()
or revert()
statements that check input arguments should be at the top of the functionChecks that involve constants should come before checks that involve state variables
2022-10-holograph/enforcer/HolographERC20.sol::620 => require(account != address(0), "ERC20: account is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::621 => require(spender != address(0), "ERC20: spender is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::627 => require(account != address(0), "ERC20: account is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::684 => require(to != address(0), "ERC20: minting to burn address"); 2022-10-holograph/enforcer/HolographERC20.sol::695 => require(account != address(0), "ERC20: account is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::696 => require(recipient != address(0), "ERC20: recipient is zero address"); 2022-10-holograph/enforcer/HolographERC721.sol::419 => require(to != address(0), "ERC721: zero address"); 2022-10-holograph/enforcer/HolographERC721.sol::639 => require(wallet != address(0), "ERC721: zero address"); 2022-10-holograph/enforcer/HolographERC721.sol::689 => require(tokenOwner != address(0), "ERC721: token does not exist"); 2022-10-holograph/enforcer/HolographERC721.sol::816 => require(to != address(0), "ERC721: minting to burn address"); 2022-10-holograph/enforcer/HolographERC721.sol::870 => require(to != address(0), "ERC721: use burn instead");
revert()
/require()
strings to save deployment gas2022-10-holograph/HolographBridge.sol::148 => require(msg.sender == address(_operator()), "HOLOGRAPH: operator only call"); 2022-10-holograph/HolographBridge.sol::163 => require(!_isInitialized(), "HOLOGRAPH: already initialized"); 2022-10-holograph/HolographBridge.sol::214 => require(selector == Holographable.bridgeIn.selector, "HOLOGRAPH: bridge in failed"); 2022-10-holograph/HolographBridge.sol::233 => require(doNotRevert, "HOLOGRAPH: reverted"); 2022-10-holograph/HolographBridge.sol::270 => require(selector == Holographable.bridgeOut.selector, "HOLOGRAPH: bridge out failed"); 2022-10-holograph/HolographFactory.sol::144 => require(!_isInitialized(), "HOLOGRAPH: already initialized"); 2022-10-holograph/HolographFactory.sol::220 => require(_verifySigner(signature.r, signature.s, signature.v, hash, signer), "HOLOGRAPH: invalid signature"); 2022-10-holograph/HolographFactory.sol::228 => require(!_isContract(holographerAddress), "HOLOGRAPH: already deployed"); 2022-10-holograph/HolographOperator.sol::241 => require(!_isInitialized(), "HOLOGRAPH: already initialized"); 2022-10-holograph/HolographOperator.sol::309 => require(_operatorJobs[hash] > 0, "HOLOGRAPH: invalid job"); 2022-10-holograph/HolographOperator.sol::350 => require(timeDifference > 0, "HOLOGRAPH: operator has time"); 2022-10-holograph/HolographOperator.sol::354 => require(gasPrice >= tx.gasprice, "HOLOGRAPH: gas spike detected"); 2022-10-holograph/HolographOperator.sol::368 => require(fallbackOperator == msg.sender, "HOLOGRAPH: invalid fallback"); 2022-10-holograph/HolographOperator.sol::415 => require(gasleft() > gasLimit, "HOLOGRAPH: not enough gas left"); 2022-10-holograph/HolographOperator.sol::446 => require(msg.sender == address(this), "HOLOGRAPH: operator only call"); 2022-10-holograph/HolographOperator.sol::485 => require(msg.sender == address(_messagingModule()), "HOLOGRAPH: messaging only call"); 2022-10-holograph/HolographOperator.sol::591 => require(msg.sender == _bridge(), "HOLOGRAPH: bridge only call"); 2022-10-holograph/HolographOperator.sol::595 => require(hlgFee < msg.value, "HOLOGRAPH: not enough value"); 2022-10-holograph/HolographOperator.sol::728 => require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 2022-10-holograph/HolographOperator.sol::739 => require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 2022-10-holograph/HolographOperator.sol::756 => require(_operatorPods.length >= pod, "HOLOGRAPH: pod does not exist"); 2022-10-holograph/HolographOperator.sol::829 => require(_bondedOperators[operator] != 0, "HOLOGRAPH: operator not bonded"); 2022-10-holograph/HolographOperator.sol::839 => require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed"); 2022-10-holograph/HolographOperator.sol::857 => require(_bondedOperators[operator] == 0 && _bondedAmounts[operator] == 0, "HOLOGRAPH: operator is bonded"); 2022-10-holograph/HolographOperator.sol::863 => require(current <= amount, "HOLOGRAPH: bond amount too small"); 2022-10-holograph/HolographOperator.sol::881 => require(_operatorPods[pod - 1].length < type(uint16).max, "HOLOGRAPH: too many operators"); 2022-10-holograph/HolographOperator.sol::889 => require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed"); 2022-10-holograph/HolographOperator.sol::903 => require(_bondedOperators[operator] != 0, "HOLOGRAPH: operator not bonded"); 2022-10-holograph/HolographOperator.sol::911 => require(_isContract(operator), "HOLOGRAPH: operator not contract"); 2022-10-holograph/HolographOperator.sol::915 => require(Ownable(operator).isOwner(msg.sender), "HOLOGRAPH: sender not owner"); 2022-10-holograph/HolographOperator.sol::932 => require(_utilityToken().transfer(recipient, amount), "HOLOGRAPH: token transfer failed"); 2022-10-holograph/abstract/ERC20H.sol::117 => require(msg.sender == holographer(), "ERC20: holographer only"); 2022-10-holograph/abstract/ERC20H.sol::123 => require(msgSender() == _getOwner(), "ERC20: owner only function"); 2022-10-holograph/abstract/ERC20H.sol::125 => require(msg.sender == _getOwner(), "ERC20: owner only function"); 2022-10-holograph/abstract/ERC20H.sol::147 => require(!_isInitialized(), "ERC20: already initialized"); 2022-10-holograph/abstract/ERC721H.sol::117 => require(msg.sender == holographer(), "ERC721: holographer only"); 2022-10-holograph/abstract/ERC721H.sol::123 => require(msgSender() == _getOwner(), "ERC721: owner only function"); 2022-10-holograph/abstract/ERC721H.sol::125 => require(msg.sender == _getOwner(), "ERC721: owner only function"); 2022-10-holograph/abstract/ERC721H.sol::147 => require(!_isInitialized(), "ERC721: already initialized"); 2022-10-holograph/enforcer/HolographERC20.sol::192 => require(msg.sender == _holograph().getBridge(), "ERC20: bridge only call"); 2022-10-holograph/enforcer/HolographERC20.sol::204 => require(msg.sender == sourceContract, "ERC20: source only call"); 2022-10-holograph/enforcer/HolographERC20.sol::219 => require(!_isInitialized(), "ERC20: already initialized"); 2022-10-holograph/enforcer/HolographERC20.sol::241 => require(sourceContract.init(initCode) == InitializableInterface.init.selector, "ERC20: could not init source"); 2022-10-holograph/enforcer/HolographERC20.sol::349 => require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 2022-10-holograph/enforcer/HolographERC20.sol::365 => require(currentAllowance >= subtractedValue, "ERC20: decreased below zero"); 2022-10-holograph/enforcer/HolographERC20.sol::387 => require(SourceERC20().bridgeIn(fromChain, from, to, amount, data), "HOLOGRAPH: bridge in failed"); 2022-10-holograph/enforcer/HolographERC20.sol::400 => require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 2022-10-holograph/enforcer/HolographERC20.sol::427 => require(newAllowance >= currentAllowance, "ERC20: increased above max value"); 2022-10-holograph/enforcer/HolographERC20.sol::445 => require(_isContract(account), "ERC20: operator not contract"); 2022-10-holograph/enforcer/HolographERC20.sol::450 => require(balance >= amount, "ERC20: balance check failed"); 2022-10-holograph/enforcer/HolographERC20.sol::452 => revert("ERC20: failed getting balance"); 2022-10-holograph/enforcer/HolographERC20.sol::469 => require(block.timestamp <= deadline, "ERC20: expired deadline"); 2022-10-holograph/enforcer/HolographERC20.sol::482 => require(signer == account, "ERC20: invalid signature"); 2022-10-holograph/enforcer/HolographERC20.sol::505 => require(_checkOnERC20Received(msg.sender, recipient, amount, data), "ERC20: non ERC20Receiver"); 2022-10-holograph/enforcer/HolographERC20.sol::529 => require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 2022-10-holograph/enforcer/HolographERC20.sol::539 => require(_checkOnERC20Received(account, recipient, amount, data), "ERC20: non ERC20Receiver"); 2022-10-holograph/enforcer/HolographERC20.sol::599 => require(currentAllowance >= amount, "ERC20: amount exceeds allowance"); 2022-10-holograph/enforcer/HolographERC20.sol::620 => require(account != address(0), "ERC20: account is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::621 => require(spender != address(0), "ERC20: spender is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::627 => require(account != address(0), "ERC20: account is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::629 => require(accountBalance >= amount, "ERC20: amount exceeds balance"); 2022-10-holograph/enforcer/HolographERC20.sol::645 => require(erc165support, "ERC20: no ERC165 support"); 2022-10-holograph/enforcer/HolographERC20.sol::653 => revert("ERC20: non ERC20Receiver"); 2022-10-holograph/enforcer/HolographERC20.sol::656 => revert(add(32, reason), mload(reason)) 2022-10-holograph/enforcer/HolographERC20.sol::661 => revert("ERC20: eip-4524 not supported"); 2022-10-holograph/enforcer/HolographERC20.sol::665 => revert("ERC20: no ERC165 support"); 2022-10-holograph/enforcer/HolographERC20.sol::684 => require(to != address(0), "ERC20: minting to burn address"); 2022-10-holograph/enforcer/HolographERC20.sol::695 => require(account != address(0), "ERC20: account is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::696 => require(recipient != address(0), "ERC20: recipient is zero address"); 2022-10-holograph/enforcer/HolographERC20.sol::698 => require(accountBalance >= amount, "ERC20: amount exceeds balance"); 2022-10-holograph/enforcer/HolographERC721.sol::212 => require(msg.sender == _holograph().getBridge(), "ERC721: bridge only call"); 2022-10-holograph/enforcer/HolographERC721.sol::224 => require(msg.sender == sourceContract, "ERC721: source only call"); 2022-10-holograph/enforcer/HolographERC721.sol::239 => require(!_isInitialized(), "ERC721: already initialized"); 2022-10-holograph/enforcer/HolographERC721.sol::258 => require(sourceContract.init(initCode) == InitializableInterface.init.selector, "ERC721: could not init source"); 2022-10-holograph/enforcer/HolographERC721.sol::263 => require(success && selector == InitializableInterface.init.selector, "ERC721: coud not init PA1D"); 2022-10-holograph/enforcer/HolographERC721.sol::323 => require(_exists(tokenId), "ERC721: token does not exist"); 2022-10-holograph/enforcer/HolographERC721.sol::370 => require(to != tokenOwner, "ERC721: cannot approve self"); 2022-10-holograph/enforcer/HolographERC721.sol::371 => require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 2022-10-holograph/enforcer/HolographERC721.sol::373 => require(SourceERC721().beforeApprove(tokenOwner, to, tokenId)); 2022-10-holograph/enforcer/HolographERC721.sol::378 => require(SourceERC721().afterApprove(tokenOwner, to, tokenId)); 2022-10-holograph/enforcer/HolographERC721.sol::388 => require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 2022-10-holograph/enforcer/HolographERC721.sol::404 => require(!_exists(tokenId), "ERC721: token already exists"); 2022-10-holograph/enforcer/HolographERC721.sol::408 => require(SourceERC721().bridgeIn(fromChain, from, to, tokenId, data), "HOLOGRAPH: bridge in failed"); 2022-10-holograph/enforcer/HolographERC721.sol::419 => require(to != address(0), "ERC721: zero address"); 2022-10-holograph/enforcer/HolographERC721.sol::420 => require(_isApproved(sender, tokenId), "ERC721: sender not approved"); 2022-10-holograph/enforcer/HolographERC721.sol::421 => require(from == _tokenOwner[tokenId], "ERC721: from is not owner"); 2022-10-holograph/enforcer/HolographERC721.sol::458 => require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 2022-10-holograph/enforcer/HolographERC721.sol::484 => require(to != msg.sender, "ERC721: cannot approve self"); 2022-10-holograph/enforcer/HolographERC721.sol::513 => require(!_burnedTokens[token], "ERC721: can't mint burned token"); 2022-10-holograph/enforcer/HolographERC721.sol::622 => require(_isApproved(msg.sender, tokenId), "ERC721: not approved sender"); 2022-10-holograph/enforcer/HolographERC721.sol::639 => require(wallet != address(0), "ERC721: zero address"); 2022-10-holograph/enforcer/HolographERC721.sol::689 => require(tokenOwner != address(0), "ERC721: token does not exist"); 2022-10-holograph/enforcer/HolographERC721.sol::700 => require(index < _allTokens.length, "ERC721: index out of bounds"); 2022-10-holograph/enforcer/HolographERC721.sol::729 => require(index < balanceOf(wallet), "ERC721: index out of bounds"); 2022-10-holograph/enforcer/HolographERC721.sol::757 => require(_isContract(_operator), "ERC721: operator not contract"); 2022-10-holograph/enforcer/HolographERC721.sol::762 => require(tokenOwner == address(this), "ERC721: contract not token owner"); 2022-10-holograph/enforcer/HolographERC721.sol::764 => revert("ERC721: token does not exist"); 2022-10-holograph/enforcer/HolographERC721.sol::815 => require(tokenId > 0, "ERC721: token id cannot be zero"); 2022-10-holograph/enforcer/HolographERC721.sol::816 => require(to != address(0), "ERC721: minting to burn address"); 2022-10-holograph/enforcer/HolographERC721.sol::817 => require(!_exists(tokenId), "ERC721: token already exists"); 2022-10-holograph/enforcer/HolographERC721.sol::818 => require(!_burnedTokens[tokenId], "ERC721: token has been burned"); 2022-10-holograph/enforcer/HolographERC721.sol::869 => require(_tokenOwner[tokenId] == from, "ERC721: token not owned"); 2022-10-holograph/enforcer/HolographERC721.sol::870 => require(to != address(0), "ERC721: use burn instead"); 2022-10-holograph/enforcer/HolographERC721.sol::906 => require(_exists(tokenId), "ERC721: token does not exist"); 2022-10-holograph/enforcer/Holographer.sol::148 => require(!_isInitialized(), "HOLOGRAPHER: already initialized"); 2022-10-holograph/enforcer/Holographer.sol::166 => require(success && selector == InitializableInterface.init.selector, "initialization failed"); 2022-10-holograph/enforcer/Holographer.sol::236 => revert(0, returndatasizer not an owner"); 2022-10-holograph/enforcer/PA1D.sol::174 => require(!_isInitialized(), "PA1D: already initialized"); 2022-10-holograph/enforcer/PA1D.sol::190 => require(initialized == 0, "PA1D: already initialized"); 2022-10-holograph/enforcer/PA1D.sol::390 => require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer"); 2022-10-holograph/enforcer/PA1D.sol::411 => require(balance > 10000, "PA1D: Not enough tokens to transfer"); 2022-10-holograph/enforcer/PA1D.sol::416 => require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token"); 2022-10-holograph/enforcer/PA1D.sol::435 => require(balance > 10000, "PA1D: Not enough tokens to transfer"); 2022-10-holograph/enforcer/PA1D.sol::439 => require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token"); 2022-10-holograph/enforcer/PA1D.sol::460 => require(matched, "PA1D: sender not authorized"); 2022-10-holograph/enforcer/PA1D.sol::472 => require(addresses.length == bps.length, "PA1D: missmatched array lenghts"); 2022-10-holograph/enforcer/PA1D.sol::477 => require(totalBp == 10000, "PA1D: bps down't equal 10000"); 2022-10-holograph/module/LayerZeroModule.sol::159 => require(!_isInitialized(), "HOLOGRAPH: already initialized"); 2022-10-holograph/module/LayerZeroModule.sol::235 => require(msg.sender == address(_operator()), "HOLOGRAPH: operator only call"); s
payable
If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
2022-10-holograph/HolographBridge.sol::452 => function setFactory(address factory) external onlyAdmin { 2022-10-holograph/HolographBridge.sol::472 => function setHolograph(address holograph) external onlyAdmin { 2022-10-holograph/HolographBridge.sol::502 => function setOperator(address operator) external onlyAdmin { 2022-10-holograph/HolographBridge.sol::522 => function setRegistry(address registry) external onlyAdmin { 2022-10-holograph/HolographFactory.sol::280 => function setHolograph(address holograph) external onlyAdmin { 2022-10-holograph/HolographFactory.sol::300 => function setRegistry(address registry) external onlyAdmin { 2022-10-holograph/HolographOperator.sol::949 => function setBridge(address bridge) external onlyAdmin { 2022-10-holograph/HolographOperator.sol::969 => function setHolograph(address holograph) external onlyAdmin { 2022-10-holograph/HolographOperator.sol::989 => function setInterfaces(address interfaces) external onlyAdmin { 2022-10-holograph/HolographOperator.sol::1009 => function setMessagingModule(address messagingModule) external onlyAdmin { 2022-10-holograph/HolographOperator.sol::1029 => function setRegistry(address registry) external onlyAdmin { 2022-10-holograph/HolographOperator.sol::1049 => function setUtilityToken(address utilityToken) external onlyAdmin { 2022-10-holograph/enforcer/HolographERC20.sol::380 => function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { 2022-10-holograph/enforcer/HolographERC20.sol::415 => function holographBridgeMint(address to, uint256 amount) external onlyBridge returns (bytes4) { 2022-10-holograph/enforcer/HolographERC20.sol::549 => function sourceBurn(address from, uint256 amount) external onlySource { 2022-10-holograph/enforcer/HolographERC20.sol::556 => function sourceMint(address to, uint256 amount) external onlySource { 2022-10-holograph/enforcer/HolographERC20.sol::563 => function sourceMintBatch(address[] calldata wallets, uint256[] calldata amounts) external onlySource { 2022-10-holograph/enforcer/HolographERC721.sol::399 => function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { 2022-10-holograph/enforcer/HolographERC721.sol::500 => function sourceBurn(uint256 tokenId) external onlySource { 2022-10-holograph/enforcer/HolographERC721.sol::508 => function sourceMint(address to, uint224 tokenId) external onlySource { 2022-10-holograph/enforcer/HolographERC721.sol::520 => function sourceGetChainPrepend() external view onlySource returns (uint256) { 2022-10-holograph/enforcer/HolographERC721.sol::577 => function sourceTransfer(address to, uint256 tokenId) external onlySource { 2022-10-holograph/enforcer/PA1D.sol::471 => function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner { 2022-10-holograph/module/LayerZeroModule.sol::320 => function setBridge(address bridge) external onlyAdmin { 2022-10-holograph/module/LayerZeroModule.sol::340 => function setInterfaces(address interfaces) external onlyAdmin { 2022-10-holograph/module/LayerZeroModule.sol::360 => function setLZEndpoint(address lZEndpoint) external onlyAdmin { 2022-10-holograph/module/LayerZeroModule.sol::380 => function setOperator(address operator) external onlyAdmin { 2022-10-holograph/module/LayerZeroModule.sol::441 => function setBaseGas(uint256 baseGas) external onlyAdmin { 2022-10-holograph/module/LayerZeroModule.sol::470 => function setGasPerByte(uint256 gasPerByte) external onlyAdmin {
Use a solidity version of at least 0.8.16 to have external calls skip contract existence checks if the external call has a return value
2022-10-holograph/HolographBridge.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/HolographFactory.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/HolographOperator.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/abstract/ERC20H.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/abstract/ERC721H.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/enforcer/HolographERC20.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/enforcer/HolographERC721.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/enforcer/Holographer.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/enforcer/PA1D.sol::102 => pragma solidity 0.8.13; 2022-10-holograph/module/LayerZeroModule.sol::102 => pragma solidity 0.8.13;
calldata
instead of memory
for function parametersUse calldata instead of memory for function parameters. Having function arguments use calldata instead of memory can save gas.
2022-10-holograph/HolographBridge.sol::162 => function init(bytes memory initPayload) external override returns (bytes4) { 2022-10-holograph/HolographFactory.sol::143 => function init(bytes memory initPayload) external override returns (bytes4) { 2022-10-holograph/HolographOperator.sol::240 => function init(bytes memory initPayload) external override returns (bytes4) { 2022-10-holograph/abstract/ERC20H.sol::140 => function init(bytes memory initPayload) external virtual override returns (bytes4) { 2022-10-holograph/abstract/ERC721H.sol::140 => function init(bytes memory initPayload) external virtual override returns (bytes4) { 2022-10-holograph/enforcer/HolographERC20.sol::218 => function init(bytes memory initPayload) external override returns (bytes4) { 2022-10-holograph/enforcer/Holographer.sol::147 => function init(bytes memory initPayload) external override returns (bytes4) { 2022-10-holograph/enforcer/PA1D.sol::173 => function init(bytes memory initPayload) external override returns (bytes4) { 2022-10-holograph/enforcer/PA1D.sol::185 => function initPA1D(bytes memory initPayload) external returns (bytes4) { 2022-10-holograph/enforcer/PA1D.sol::316 => function _setPayoutAddresses(address payable[] memory addresses) private { 2022-10-holograph/enforcer/PA1D.sol::349 => function _setPayoutBps(uint256[] memory bps) private { 2022-10-holograph/enforcer/PA1D.sol::365 => function _getTokenAddress(string memory tokenName) private view returns (address tokenAddress) { 2022-10-holograph/enforcer/PA1D.sol::372 => function _setTokenAddress(string memory tokenName, address tokenAddress) private { 2022-10-holograph/enforcer/PA1D.sol::426 => function _payoutTokens(address[] memory tokenAddresses) private { 2022-10-holograph/enforcer/PA1D.sol::471 => function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner { 2022-10-holograph/enforcer/PA1D.sol::517 => function getTokensPayout(address[] memory tokenAddresses) public { 2022-10-holograph/enforcer/PA1D.sol::683 => function getTokenAddress(string memory tokenName) public view returns (address) { 2022-10-holograph/module/LayerZeroModule.sol::158 => function init(bytes memory initPayload) external override returns (bytes4) {
Checking non-zero transfer values can avoid an expensive external call and save gas.
While this is done in some places, it’s not consistently done in the solution.
I suggest adding a non-zero-value check here
2022-10-holograph/HolographOperator.sol::400 => _utilityToken().transfer(job.operator, leftovers); 2022-10-holograph/HolographOperator.sol::596 => payable(hToken).transfer(hlgFee); 2022-10-holograph/enforcer/PA1D.sol::396 => addresses[i].transfer(sending);
address
mappings can be combined into a single mapping
of an address
to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot
2022-10-holograph/HolographOperator.sol::193 => mapping(bytes32 => uint256) private _operatorJobs; 2022-10-holograph/HolographOperator.sol::198 => mapping(bytes32 => bool) private _failedJobs; 2022-10-holograph/HolographOperator.sol::203 => mapping(uint256 => address) private _operatorTempStorage; 2022-10-holograph/HolographOperator.sol::218 => mapping(address => uint256) private _bondedOperators; 2022-10-holograph/HolographOperator.sol::223 => mapping(address => uint256) private _operatorPodIndex; 2022-10-holograph/HolographOperator.sol::228 => mapping(address => uint256) private _bondedAmounts; 2022-10-holograph/enforcer/HolographERC20.sol::156 => mapping(address => uint256) private _balances; 2022-10-holograph/enforcer/HolographERC20.sol::161 => mapping(address => mapping(address => uint256)) private _allowances; 2022-10-holograph/enforcer/HolographERC20.sol::186 => mapping(address => uint256) private _nonces; 2022-10-holograph/enforcer/HolographERC721.sol::170 => mapping(uint256 => uint256) private _ownedTokensIndex; 2022-10-holograph/enforcer/HolographERC721.sol::175 => mapping(uint256 => address) private _tokenOwner; 2022-10-holograph/enforcer/HolographERC721.sol::180 => mapping(uint256 => address) private _tokenApprovals; 2022-10-holograph/enforcer/HolographERC721.sol::185 => mapping(address => uint256) private _ownedTokensCount; 2022-10-holograph/enforcer/HolographERC721.sol::190 => mapping(address => uint256[]) private _ownedTokens; 2022-10-holograph/enforcer/HolographERC721.sol::196 => mapping(address => mapping(address => bool)) private _operatorApprovals; 2022-10-holograph/enforcer/HolographERC721.sol::201 => mapping(uint256 => uint256) private _allTokensIndex; 2022-10-holograph/enforcer/HolographERC721.sol::206 => mapping(uint256 => bool) private _burnedTokens;
bools
for storage incurs overhead2022-10-holograph/HolographOperator.sol::198 => mapping(bytes32 => bool) private _failedJobs; 2022-10-holograph/enforcer/HolographERC721.sol::196 => mapping(address => mapping(address => bool)) private _operatorApprovals; 2022-10-holograph/enforcer/HolographERC721.sol::206 => mapping(uint256 => bool) private _burnedTokens;
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}})
2022-10-holograph/HolographBridge.sol::155 => constructor() {} 2022-10-holograph/HolographFactory.sol::136 => constructor() {} 2022-10-holograph/HolographOperator.sol::233 => constructor() {} 2022-10-holograph/HolographOperator.sol::1209 => receive() external payable {} 2022-10-holograph/abstract/ERC20H.sol::133 => constructor() {} 2022-10-holograph/abstract/ERC20H.sol::212 => receive() external payable {} 2022-10-holograph/abstract/ERC721H.sol::133 => constructor() {} 2022-10-holograph/abstract/ERC721H.sol::212 => receive() external payable {} 2022-10-holograph/enforcer/HolographERC20.sol::211 => constructor() {} 2022-10-holograph/enforcer/HolographERC20.sol::251 => receive() external payable {} 2022-10-holograph/enforcer/HolographERC721.sol::231 => constructor() {} 2022-10-holograph/enforcer/HolographERC721.sol::962 => receive() external payable {} 2022-10-holograph/enforcer/Holographer.sol::140 => constructor() {} 2022-10-holograph/enforcer/Holographer.sol::223 => receive() external payable {} 2022-10-holograph/enforcer/PA1D.sol::166 => constructor() {} 2022-10-holograph/module/LayerZeroModule.sol::151 => constructor() {}
Saves a storage slot. If the variable is assigned a non-zero value, saves Gsset (20000 gas). If it’s assigned a zero value, saves Gsreset (2900 gas). If the variable remains unassigned, there is no gas savings unless the variable is public, in which case the compiler-generated non-payable getter deployment cost is saved. If the state variable is overriding an interface’s public function, mark the variable as constant or immutable so that it does not use a storage slot
2022-10-holograph/enforcer/HolographERC721.sol::165 => uint256[] private _allTokens; 2022-10-holograph/enforcer/HolographERC721.sol::190 => mapping(address => uint256[]) private _ownedTokens;
keccak256()
should only need to be called on a specific string literal onceIt should be saved to an immutable variable, and the variable used instead. If the hash is being used as a part of a function selector, the cast to bytes4 should also only be done once
2022-10-holograph/HolographBridge.sol::388 => bytes memory encodedData = abi.encodeWithSelector( 2022-10-holograph/HolographOperator.sol::597 => bytes memory encodedData = abi.encodeWithSelector( 2022-10-holograph/module/LayerZeroModule.sol::269 => bytes memory adapterParams = abi.encodePacked(
abi.encode()
is less efficient than abi.encodePacked()2022-10-holograph/HolographFactory.sol::252 => abi.encode(abi.encode(config.chainType, holograph, config.contractType, sourceContractAddress), config.initCode) 2022-10-holograph/enforcer/HolographERC20.sol::471 => abi.encode( 2022-10-holograph/enforcer/HolographERC721.sol::260 => abi.encodeWithSignature("initPA1D(bytes)", abi.encode(address(this), uint256(contractBps))) 2022-10-holograph/enforcer/HolographERC721.sol::426 => return (Holographable.bridgeOut.selector, abi.encode(from, to, tokenId, data));
public/external function names and public member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, [per sorted position shifted](https://medium.com/joyso/solidity-how-does-function-n
2022-10-holograph/abstract/ERC20H.sol::106 => abstract contract ERC20H is Initializable { 2022-10-holograph/abstract/ERC721H.sol::106 => abstract contract ERC721H is Initializable {