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: 45/144
Findings: 2
Award: $82.02
🌟 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
55.6726 USDC - $55.67
It is good to add a require() statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer/safeTransferFrom unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
Reference: This similar medium-severity finding from Consensys Diligence Audit of Fei Protocol: https://consensys.net/diligence/audits/2021/01/fei-protocol/#unchecked-return-value-for-iweth-transfer-call
400 _utilityToken().transfer(job.operator, leftovers); 596 payable(hToken).transfer(hlgFee); 839 require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed"); 889 require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed"); 932 require(_utilityToken().transfer(recipient, amount), "HOLOGRAPH: token transfer failed");
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
396 addresses[i].transfer(sending); 416 require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token"); 439 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
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment
701 // TODO: move the bit-shifting around to have it be sequential
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
Use OpenZeppelin’s ECDSA
contract rather than calling ecrecover()
directly
333 return (ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)), v, r, s) == signer || 334 ecrecover(hash, v, r, s) == signer);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol
Check here for NatSpec rules: https://docs.soliditylang.org/en/develop/natspec-format.html
missing @return 162 function init(bytes memory initPayload) external override returns (bytes4) { 301 ) external returns (string memory revertReason) { 402 function getFactory() external view returns (address factory) { 462 function getHolograph() external view returns (address holograph) { 482 function getJobNonce() external view returns (uint256 jobNonce) { 492 function getOperator() external view returns (address operator) { 512 function getRegistry() external view returns (address registry) { 531 function _factory() private view returns (HolographFactoryInterface factory) { 540 function _holograph() private view returns (HolographInterface holograph) { 549 function _jobNonce() private returns (uint256 jobNonce) { 559 function _operator() private view returns (HolographOperatorInterface operator) { 568 function _registry() private view returns (HolographRegistryInterface registry) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographBridge.sol
missing @return 240 function init(bytes memory initPayload) external override returns (bytes4) { 717 function getTotalPods() external view returns (uint256 totalPods) { 939 function getBridge() external view returns (address bridge) { 959 function getHolograph() external view returns (address holograph) { 979 function getInterfaces() external view returns (address interfaces) { 999 function getMessagingModule() external view returns (address messagingModule) { 1019 function getRegistry() external view returns (address registry) { 1039 function getUtilityToken() external view returns (address utilityToken) { 1058 function _bridge() private view returns (address bridge) { 1112 function _jobNonce() private returns (uint256 jobNonce) { 1160 function _getBaseBondAmount(uint256 pod) private view returns (uint256) { 1167 function _getCurrentBondAmount(uint256 pod) private view returns (uint256) { 1189 ) private view returns (uint256) { 1198 function _isContract(address contractAddress) private view returns (bool) { missing @param bridgeInRequestPayload 484 function crossChainMessage(bytes calldata bridgeInRequestPayload) external payable {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
missing @return 143 function init(bytes memory initPayload) external override returns (bytes4) { 270 function getHolograph() external view returns (address holograph) { 290 function getRegistry() external view returns (address registry) { 309 function _isContract(address contractAddress) private view returns (bool) { 326 ) private pure returns (bool) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol
missing @return 158 function init(bytes memory initPayload) external override returns (bytes4) { 256 ) external view returns (uint256 hlgFee, uint256 msgFee) { 281 ) external view returns (uint256 hlgFee) { 299 returns (uint128 dstPriceRatio, uint128 dstGasPriceInWei) 310 function getBridge() external view returns (address bridge) { 330 function getInterfaces() external view returns (address interfaces) { 350 function getLZEndpoint() external view returns (address lZEndpoint) { 370 function getOperator() external view returns (address operator) { 389 function _bridge() private view returns (address bridge) { 431 function getBaseGas() external view returns (uint256 baseGas) { 450 function _baseGas() private view returns (uint256 baseGas) { 460 function getGasPerByte() external view returns (uint256 gasPerByte) { 479 function _gasPerByte() private view returns (uint256 gasPerByte) { missing @param for all variables 227 function send( 251 function getMessageFee( 277 function getHlgFee( 296 function _getPricing(LayerZeroOverrides lz, uint16 lzDestChain)
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
missing @title missing @author missing @return 147 function init(bytes memory initPayload) external override returns (bytes4) { 174 function getDeploymentBlock() external view returns (address holograph) { 183 function getHolograph() external view returns (address holograph) { 192 function getHolographEnforcer() public view returns (address) { 205 function getOriginChain() external view returns (uint32 originChain) { 214 function getSourceContract() external view returns (address sourceContract) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/Holographer.sol
missing @return 173 function init(bytes memory initPayload) external override returns (bytes4) { 185 function initPA1D(bytes memory initPayload) external returns (bytes4) { 298 function _getPayoutAddresses() private view returns (address payable[] memory addresses) { 332 function _getPayoutBps() private view returns (uint256[] memory bps) { missing @param initPayload 185 function initPA1D(bytes memory initPayload) external returns (bytes4) { missing @param addresses 316 function _setPayoutAddresses(address payable[] memory addresses) private { missing @param bps 349 function _setPayoutBps(uint256[] memory bps) private { missing @param tokenName, @return 365 function _getTokenAddress(string memory tokenName) private view returns (address tokenAddress) { missing @param tokenName, @param tokenAddress 372 function _setTokenAddress(string memory tokenName, address tokenAddress) private { missing @param tokenId, @param value, @return, @return 549 function royaltyInfo(uint256 tokenId, uint256 value) public view returns (address, uint256) { missing @param tokenId, @return 558 function getFeeBps(uint256 tokenId) public view returns (uint256[] memory) { missing @param tokenId, @return 569 function getFeeRecipients(uint256 tokenId) public view returns (address payable[] memory) { missing @param tokenId, @return, @return 590 function getRoyalties(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) { missing @param tokenId, @return, @return 604 function getFees(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol
missing @return 218 function init(bytes memory initPayload) external override returns (bytes4) { 306 function DOMAIN_SEPARATOR() public view returns (bytes32) { 310 function name() public view returns (string memory) { 318 function symbol() public view returns (string memory) { 322 function totalSupply() public view returns (uint256) { missing @param interfaceId, @return 282 function supportsInterface(bytes4 interfaceId) external view returns (bool) { missing @param account, @param spender, @ return 297 function allowance(address account, address spender) public view returns (uint256) { missing @param account, @ return 301 function balanceOf(address account) public view returns (uint256) { missing @param account, @ return 314 function nonces(address account) public view returns (uint256) { missing @param spender, @param amount, @ return 326 function approve(address spender, uint256 amount) public returns (bool) { missing @param account, @param amount, @ return 347 function burnFrom(address account, uint256 amount) public returns (bool) { missing @param spender, @param subtractedValue, @ return 363 function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { missing @param fromChain, @param payload, @ return 380 function bridgeIn(uint32 fromChain, bytes calldata payload) external onlyBridge returns (bytes4) { missing @param for all variables 392 function bridgeOut( 415 function holographBridgeMint(address to, uint256 amount) external onlyBridge returns (bytes4) { 420 function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 439 function onERC20Received( 460 function permit( 492 function safeTransfer(address recipient, uint256 amount) public returns (bool) { 496 function safeTransfer( 512 function safeTransferFrom( 520 function safeTransferFrom( 549 function sourceBurn(address from, uint256 amount) external onlySource { 563 function sourceMintBatch(address[] calldata wallets, uint256[] calldata amounts) external onlySource { 572 unction sourceTransfer( 580 function transfer(address recipient, uint256 amount) public returns (bool) { 591 function transferFrom( 615 function _approve( 626 function _burn(address account, uint256 amount) private { 637 function _checkOnERC20Received( 690 function _transfer( 711 function _useNonce(address account) private returns (uint256 current) { 736 function _interfaces() private view returns (address) { 740 function owner() public view override returns (address) { 748 function _holograph() private view returns (HolographInterface holograph) { 754 function _isEventRegistered(HolographERC20Event _eventName) private view returns (bool) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol
missing @title missing @author
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC721H.sol
missing @title missing @author
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC20H.sol
Events help non-contract tools to track changes, and events prevent users from being surprised by changes
452 function setFactory(address factory) external onlyAdmin { 472 function setHolograph(address holograph) external onlyAdmin { 502 function setOperator(address operator) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographBridge.sol
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/blob/main/contracts/HolographOperator.sol
280 function setHolograph(address holograph) external onlyAdmin { 300 function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol
320 function setBridge(address bridge) external onlyAdmin { 340 function setInterfaces(address interfaces) external onlyAdmin { 360 function setLZEndpoint(address lZEndpoint) external onlyAdmin { 380 function setOperator(address operator) external onlyAdmin { 470 function setGasPerByte(uint256 gasPerByte) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
438 //// _bondedOperators[msg.sender] += reward;
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
397 // sent = sent + sending; 417 // sent = sent + sending; 440 // sent = sent + sending; ... 580 // struct Part { 581 // address payable account; 582 // uint96 value; 583 // } 584 // function getRoyalties(uint256 tokenId) public view returns (Part[] memory) { 585 // return royalties[id]; 586 // }
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol
527 // function sourceMintBatch(address to, uint224[] calldata tokenIds) external onlySource { 528 // require(tokenIds.length < 1000, "ERC721: max batch size is 1000"); 529 // uint32 chain = _chain(); 530 // uint256 token; 531 // for (uint256 i = 0; i < tokenIds.length; i++) { 532 // require(!_burnedTokens[token], "ERC721: can't mint burned token"); 533 // token = uint256(bytes32(abi.encodePacked(chain, tokenIds[i]))); 534 // require(!_burnedTokens[token], "ERC721: can't mint burned token"); 535 // _mint(to, token); 536 // } 537 // } ... 542 // function sourceMintBatch(address[] calldata wallets, uint224[] calldata tokenIds) external onlySource { 543 // require(wallets.length == tokenIds.length, "ERC721: array length missmatch"); 544 // require(tokenIds.length < 1000, "ERC721: max batch size is 1000"); 545 // uint32 chain = _chain(); 546 // uint256 token; 547 // for (uint256 i = 0; i < tokenIds.length; i++) { 548 // token = uint256(bytes32(abi.encodePacked(chain, tokenIds[i]))); 549 // require(!_burnedTokens[token], "ERC721: can't mint burned token"); 550 // _mint(wallets[i], token); 551 // } 552 // } ... 557 // function sourceMintBatchIncremental( 558 // address to, 559 // uint224 startingTokenId, 560 // uint256 length 561 // ) external onlySource { 562 // uint32 chain = _chain(); 563 // uint256 token; 564 // for (uint256 i = 0; i < length; i++) { 565 // token = uint256(bytes32(abi.encodePacked(chain, startingTokenId))); 566 // require(!_burnedTokens[token], "ERC721: can't mint burned token"); 567 // _mint(to, token); 568 // startingTokenId++; 569 // } 570 // }
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC721.sol
Scientific notation should be used for better code readability
256 _baseBondAmount = 100 * (10**18); // one single token unit * 100
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
274 return (((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10), nativeFee); 293 return ((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents’ functions and change the visibility from external
to public
and can save gas by doing so
472 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) { 683 function getTokenAddress(string memory tokenName) public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol
306 function DOMAIN_SEPARATOR() public view returns (bytes32) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol
require()
/revert()
statements should have descriptive reason strings328 require(SourceERC20().beforeApprove(msg.sender, spender, amount)); 332 require(SourceERC20().afterApprove(msg.sender, spender, amount)); 339 require(SourceERC20().beforeBurn(msg.sender, amount)); 343 require(SourceERC20().afterBurn(msg.sender, amount)); 354 require(SourceERC20().beforeBurn(account, amount)); 358 require(SourceERC20().afterBurn(account, amount)); 371 require(SourceERC20().beforeApprove(msg.sender, spender, newAllowance)); 375 require(SourceERC20().afterApprove(msg.sender, spender, newAllowance)); 430 require(SourceERC20().beforeApprove(msg.sender, spender, newAllowance)); 434 require(SourceERC20().afterApprove(msg.sender, spender, newAllowance)); 447 require(SourceERC20().beforeOnERC20Received(account, sender, address(this), amount, data)); 455 require(SourceERC20().afterOnERC20Received(account, sender, address(this), amount, data)); 484 require(SourceERC20().beforeApprove(account, spender, amount)); 488 require(SourceERC20().afterApprove(account, spender, amount)); 502 require(SourceERC20().beforeSafeTransfer(msg.sender, recipient, amount, data)); 507 require(SourceERC20().afterSafeTransfer(msg.sender, recipient, amount, data)); 536 require(SourceERC20().beforeSafeTransfer(account, recipient, amount, data)); 541 require(SourceERC20().afterSafeTransfer(account, recipient, amount, data)); 582 require(SourceERC20().beforeTransfer(msg.sender, recipient, amount)); 586 require(SourceERC20().afterTransfer(msg.sender, recipient, amount)); 606 require(SourceERC20().beforeTransfer(account, recipient, amount)); 610 require(SourceERC20().afterTransfer(account, recipient, amount));
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol
Consider changing the variable to be an unnamed one
301 ) external returns (string memory revertReason) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographBridge.sol
717 function getTotalPods() external view returns (uint256 totalPods) { 804 function getBondedAmount(address operator) external view returns (uint256 amount) { 814 function getBondedPod(address operator) external view returns (uint256 pod) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
256 ) external view returns (uint256 hlgFee, uint256 msgFee) { 281 ) external view returns (uint256 hlgFee) { 299 returns (uint128 dstPriceRatio, uint128 dstGasPriceInWei)
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
If the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth))
). Having no access control on the function means that someone may send Ether to the contract, and have no way to get anything back out, which is a loss of funds
1209 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
223 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/Holographer.sol
251 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol
962 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC721.sol
212 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC721H.sol
212 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC20H.sol
🌟 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
In Solidity 0.8+, there’s a default overflow check on unsigned integers. It’s possible to uncheck this in for-loops and save some gas at each iteration, but at the cost of some code readability, as this uncheck cannot be made inline. This saves 30-40 gas PER LOOP.
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/blob/main/contracts/HolographOperator.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/blob/main/contracts/enforcer/PA1D.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/blob/main/contracts/enforcer/HolographERC721.sol
564 for (uint256 i = 0; i < wallets.length; i++) {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.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
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/blob/main/contracts/enforcer/PA1D.sol
require()
statements that use && saves gasInstead of using the && operator in a single require statement to check multiple conditions,use multiple require statements with 1 condition per require statement.
See this issue which describes the fact that there is a larger deployment gas cost, but with enough runtime calls, the change ends up being cheaper
857 require(_bondedOperators[operator] == 0 && _bondedAmounts[operator] == 0, "HOLOGRAPH: operator is bonded");
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
166 require(success && selector == InitializableInterface.init.selector, "initialization failed");
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/Holographer.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/blob/main/contracts/enforcer/HolographERC721.sol
uint/int
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.
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{...}}
). Empty receive()
/fallback()
payable functions that are not used, can be removed to save deployment gas.
155 constructor() {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographBridge.sol
233 constructor() {} 1209 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
136 constructor() {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol
151 constructor() {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
149 constructor() {} 223 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/Holographer.sol
166 constructor() {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol
231 constructor() {} 962 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC721.sol
211 constructor() {} 251 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol
133 constructor() {} 212 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC721H.sol
133 constructor() {} 212 receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC20H.sol
718 return _operatorPods.length; 729 return _operatorPods[pod - 1].length; 1191 return (random + uint256(blockhash(block.number - n))) % podSize; 1203 return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
152 return InitializableInterface.init.selector; 169 return Holographable.bridgeIn.selector; 314 return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); 333 return (ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)), v, r, s) == signer ||
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol
274 return (((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10), nativeFee); 293 return ((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
206 return (msg.sender == getOwner() || 551 return (_getDefaultReceiver(), (_getDefaultBp() * value) / 10000); 553 return (_getReceiver(tokenId), (_getBp(tokenId) * value) / 10000); 641 return (_getDefaultBp() * amount) / 10000; 643 return (_getBp(tokenId) * amount) / 10000;
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol
328 return sourceContract.tokenURI(tokenId); 337 return _ownedTokens[wallet]; 521 return uint256(bytes32(abi.encodePacked(_chain(), uint224(0)))); 653 return 0; 678 return _operatorApprovals[wallet][operator]; 908 return (spender == tokenOwner || _tokenApprovals[tokenId] == spender || _operatorApprovals[tokenOwner][spender]); 916 return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); 1003 return ((_eventConfig >> uint256(_eventName)) & uint256(1) == 1 ? true : false);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC721.sol
262 returndatacopy(0, 0, returndatasize()) 298 return _allowances[account][spender]; 302 return _balances[account]; 315 return _nonces[account]; 334 return true; 360 return true; 377 return true; 409 return (Holographable.bridgeOut.selector, abi.encode(from, to, amount, data)); 417 return HolographERC20Interface.holographBridgeMint.selector; 436 return true; 493 return safeTransfer(recipient, amount, ""); 517 return safeTransferFrom(account, recipient, amount, ""); 543 return true; 721 return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); 755 return ((_eventConfig >> uint256(_eventName)) & uint256(1) == 1 ? true : false);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol
153 return InitializableInterface.init.selector; 175 return false;
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC721H.sol
153 return InitializableInterface.init.selector; 175 return false;
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/abstract/ERC20H.sol
From the Solidity doc:
Why do Solidity examples use bytes32 type instead of string?
If data can fit into 32 bytes, then you should use bytes32 datatype rather than bytes or strings as it is cheaper in solidity. Basically, any fixed size variable in solidity is cheaper than variable size. That will save gas on the contract.
Instances of string constant that can be replaced by bytes(1..32) constant
142 string constant _bpString = "eip1967.Holograph.PA1D.bp"; 143 string constant _receiverString = "eip1967.Holograph.PA1D.receiver"; 144 string constant _tokenAddressString = "eip1967.Holograph.PA1D.tokenAddress";
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/PA1D.sol
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. The extra opcodes avoided are CALLVALUE
(2),DUP1
(3),ISZERO
(3),PUSH2
(3),JUMPI
(10),PUSH1
(3),DUP1
(3),REVERT
(0),JUMPDEST
(1),POP
(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
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/blob/main/contracts/HolographBridge.sol
278 function resetOperator( 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/blob/main/contracts/HolographOperator.sol
280 function setHolograph(address holograph) external onlyAdmin { 300 function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol
320 function setBridge(address bridge) external onlyAdmin { 340 function setInterfaces(address interfaces) external onlyAdmin { 360 function setLZEndpoint(address lZEndpoint) external onlyAdmin { 380 function setOperator(address operator) external onlyAdmin { 441 function setBaseGas(uint256 baseGas) external onlyAdmin { 470 function setGasPerByte(uint256 gasPerByte) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/module/LayerZeroModule.sol
##9. Multiple address
/ID
mappings can be combined into a single mapping
of an address
/ID
to a struct
, where appropriate
Saves 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. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key’s keccak256 hash (Gkeccak256 - 30 gas) and that calculation’s associated stack operations.
218 mapping(address => uint256) private _bondedOperators; 223 mapping(address => uint256) private _operatorPodIndex; 228 mapping(address => uint256) private _bondedAmounts;
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographOperator.sol
156 mapping(address => uint256) private _balances; 161 mapping(address => mapping(address => uint256)) private _allowances; 186 mapping(address => uint256) private _nonces;
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/enforcer/HolographERC20.sol