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: 12/144
Findings: 2
Award: $936.00
🌟 Selected for report: 1
🚀 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
713.753 USDC - $713.75
Issue | Instances | |
---|---|---|
LOW‑1 | Missing Checks for Address(0x0) | 69 |
LOW‑2 | Use safetransfer Instead Of transfer | 8 |
LOW‑3 | Unused receive() Function Will Lock Ether In Contract | 6 |
LOW‑4 | Use _safeMint instead of _mint | 6 |
LOW‑5 | Missing Contract-existence Checks Before Low-level Calls | 2 |
LOW‑6 | Critical Changes Should Use Two-step Procedure | 20 |
LOW‑7 | Low Level Calls With Solidity Version 0.8.14 Can Result In Optimiser Bug | 5 |
LOW‑8 | Usage of payable.transfer can lead to loss of funds | 1 |
LOW‑9 | ecrecover may return empty address | 2 |
LOW‑10 | HolographFactory.deployHolographableContract() can overpopulate HolographRegistry._holographableContracts | 1 |
Total: 120 instances over 10 issues
Issue | Instances | |
---|---|---|
NC‑1 | Event Is Missing Indexed Fields | 1 |
NC‑2 | Public Functions Not Called By The Contract Should Be Declared External Instead | 11 |
NC‑3 | Constants Should Be Defined Rather Than Using Magic Numbers | 22 |
NC‑4 | Missing event for critical parameter change | 18 |
NC‑5 | require() / revert() Statements Should Have Descriptive Reason Strings | 4 |
NC‑6 | Implementation contract may not be initialized | 8 |
NC‑7 | Large multiples of ten should use scientific notation | 19 |
NC‑8 | Use of Block.Timestamp | 4 |
NC‑9 | Non-usage of specific imports | 98 |
NC‑10 | Lines are too long | 4 |
NC‑11 | Use bytes.concat() | 44 |
NC‑12 | Use of ecrecover is susceptible to signature malleability | 2 |
NC‑13 | Commented code | 1 |
Total: 236 instances over 13 issues
Lack of zero-address validation on address parameters may lead to transaction reverts, waste gas, require resubmission of transactions and may even force contract redeployments in certain cases within the protocol.
193: function bridgeInRequest: address holographableContract
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L193
194: function bridgeInRequest: address hToken
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L194
195: function bridgeInRequest: address hTokenRecipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L195
247: function bridgeOutRequest: address holographableContract
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L247
297: function revertedBridgeOutRequest: address sender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L297
299: function revertedBridgeOutRequest: address holographableContract
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L299
344: function getBridgeOutRequestPayload: address holographableContract
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L344
452: function setFactory: address factory
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L452
472: function setHolograph: address holograph
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L472
502: function setOperator: address operator
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L502
522: function setRegistry: address registry
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L522
195: function deployHolographableContract: address signer
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L195
280: function setHolograph: address holograph
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L280
300: function setRegistry: address registry
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L300
445: function nonRevertingBridgeCall: address msgSender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L445
586: function send: address msgSender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L586
588: function send: address holographableContract
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L588
825: function topupUtilityToken: address operator
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L825
850: function bondUtilityToken: address operator
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L850
899: function unbondUtilityToken: address operator
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L899
899: function unbondUtilityToken: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L899
949: function setBridge: address bridge
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L949
969: function setHolograph: address holograph
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L969
989: function setInterfaces: address interfaces
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L989
1009: function setMessagingModule: address messagingModule
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1009
1029: function setRegistry: address registry
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1029
1049: function setUtilityToken: address utilityToken
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1049
326: function approve: address spender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L326
347: function burnFrom: address account
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L347
363: function decreaseAllowance: address spender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L363
415: function holographBridgeMint: address to
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L415
420: function increaseAllowance: address spender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L420
440: function onERC20Received: address account
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L440
441: function onERC20Received: address sender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L441
461: function permit: address account
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L461
462: function permit: address spender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L462
497: function safeTransfer: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L497
497: function safeTransfer: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L497
521: function safeTransferFrom: address account
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L521
522: function safeTransferFrom: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L522
522: function safeTransferFrom: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L522
549: function sourceBurn: address from
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L549
556: function sourceMint: address to
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L556
573: function sourceTransfer: address from
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L573
574: function sourceTransfer: address to
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L574
580: function transfer: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L580
593: function transferFrom: address recipient
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L593
415: function bridgeOut: address sender
453: function safeTransferFrom: address from
454: function safeTransferFrom: address to
453: function safeTransferFrom: address from
454: function safeTransferFrom: address to
508: function sourceMint: address to
577: function sourceTransfer: address to
588: function transfer: address to
617: function transferFrom: address from
618: function transferFrom: address to
617: function transferFrom: address from
618: function transferFrom: address to
752: function onERC721Received: address _operator
753: function onERC721Received: address _from
471: function configurePayouts: address payable[] memory addresses
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L471
507: function getTokenPayout: address tokenAddress
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L507
531: function setRoyalties: address payable receiver
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L531
231: function send: address msgSender
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L231
320: function setBridge: address bridge
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L320
340: function setInterfaces: address interfaces
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L340
360: function setLZEndpoint: address lZEndpoint
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L360
380: function setOperator: address operator
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L380
Consider adding explicit zero-address validation on input parameters of address type.
safetransfer
Instead Of transfer
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.
For example, Some tokens do not implement the ERC20 standard properly but are still accepted by most code that accepts ERC20 tokens. For example Tether (USDT)'s transfer() and transferFrom() functions do not return booleans as the specification requires, and instead have no return value. When these sorts of tokens are cast to IERC20, their function signatures do not match and therefore the calls made, revert.
400: _utilityToken().transfer(job.operator, leftovers);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L400
596: payable(hToken).transfer(hlgFee);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L596
839: require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L839
889: require(_utilityToken().transferFrom(msg.sender, address(this), amount), "HOLOGRAPH: token transfer failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L889
932: require(_utilityToken().transfer(recipient, amount), "HOLOGRAPH: token transfer failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L932
396: addresses[i].transfer(sending);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L396
416: require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L416
439: require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L439
Consider using safeTransfer
/safeTransferFrom
or require()
consistently.
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
1209: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1209
212: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol#L212
212: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol#L212
223: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L223
251: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L251
962: receive() external payable {}
The function should call another function, otherwise it should revert
_safeMint
instead of _mint
According to openzepplin's ERC721, the use of _mint
is discouraged, use _safeMint whenever possible.
https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#ERC721-_mint-address-uint256-
385: _mint(to, amount);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L385
416: _mint(to, amount);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L416
557: _mint(to, amount);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L557
565: _mint(wallets[i], amounts[i]);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L565
406: _mint(to, tokenId);
514: _mint(to, token);
Use _safeMint
whenever possible instead of _mint
Low-level calls return success if there is no code present at the specified address.
164: .delegatecall(abi.encodeWithSignature("init(bytes)", initCode));
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L164
259: (bool success, bytes memory returnData) = _royalties().delegatecall(
In addition to the zero-address checks, add a check to verify that <address>.code.length > 0
The critical procedures should be two step process.
See similar findings in previous Code4rena contests for reference: https://code4rena.com/reports/2022-06-illuminate/#2-critical-changes-should-use-two-step-procedure
452: function setFactory(address factory) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L452
472: function setHolograph(address holograph) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L472
502: function setOperator(address operator) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L502
522: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L522
280: function setHolograph(address holograph) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L280
300: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L300
949: function setBridge(address bridge) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L949
969: function setHolograph(address holograph) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L969
989: function setInterfaces(address interfaces) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L989
1009: function setMessagingModule(address messagingModule) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1009
1029: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1029
1049: function setUtilityToken(address utilityToken) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1049
483: function setApprovalForAll(address to, bool approved) external {
529: function setRoyalties(
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L529
320: function setBridge(address bridge) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L320
340: function setInterfaces(address interfaces) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L340
360: function setLZEndpoint(address lZEndpoint) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L360
380: function setOperator(address operator) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L380
441: function setBaseGas(uint256 baseGas) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L441
470: function setGasPerByte(uint256 gasPerByte) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L470
Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.
The project contracts in scope are using low level calls with solidity version before 0.8.14 which can result in optimizer bug. https://medium.com/certora/overly-optimistic-optimizer-certora-bug-disclosure-2101e3f7994d
Simliar findings in Code4rena contests for reference: https://code4rena.com/reports/2022-06-illuminate/#5-low-level-calls-with-solidity-version-0814-can-result-in-optimiser-bug
POC can be found in the above medium reference url.
Functions that execute low level calls in contracts with solidity version under 0.8.14
447: assembly { /** * @dev remove gas price from end */ calldatacopy(0, payload.offset, sub(payload.length, 0x20)) /** * @dev hToken recipient is injected right before making the call */ mstore(0x84, msgSender) /** * @dev make non-reverting call */ let result := call( /// @dev gas limit is retrieved from last 32 bytes of payload in-memory value mload(sub(payload.length, 0x40)), /// @dev destination is bridge contract sload(_bridgeSlot), /// @dev any value is passed along callvalue(), /// @dev data is retrieved from 0 index memory position 0, /// @dev everything except for last 32 bytes (gas limit) is sent sub(payload.length, 0x40), 0, 0 ) if eq(result, 0) { revert(0, 0) } return(0, 0) } }
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L447-478
550: assembly { calldatacopy(0, bridgeInRequestPayload.offset, sub(bridgeInRequestPayload.length, 0x40)) /** * @dev bridgeInRequest doNotRevert is purposefully set to false so a rever would happen */ mstore8(0xE3, 0x00) let result := call(gas(), sload(_bridgeSlot), callvalue(), 0, sub(bridgeInRequestPayload.length, 0x40), 0, 0) /** * @dev if for some reason the call does not revert, it is force reverted */ if eq(result, 1) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } /** * @dev remaining gas is set as the return value */ mstore(0x00, gas()) return(0x00, 0x20) } }
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L550-570
221: assembly { sstore(_reentrantSlot, 0x0000000000000000000000000000000000000000000000000000000000000001) sstore(_ownerSlot, caller()) sourceContract := sload(_sourceContractSlot) }
973: assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), _target, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } else { assembly { calldatacopy(0, 0, calldatasize()) mstore(calldatasize(), caller()) let result := call(gas(), sload(_sourceContractSlot), callvalue(), 0, add(calldatasize(), 32), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } }
186: assembly { /** * @dev check if msg.sender is LayerZero Endpoint */ switch eq(sload(_lZEndpointSlot), caller()) case 0 { /** * @dev this is the assembly version of -> revert("HOLOGRAPH: LZ only endpoint"); */ mstore(0x80, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(0xa0, 0x0000002000000000000000000000000000000000000000000000000000000000) mstore(0xc0, 0x0000001b484f4c4f47524150483a204c5a206f6e6c7920656e64706f696e7400) mstore(0xe0, 0x0000000000000000000000000000000000000000000000000000000000000000) revert(0x80, 0xc4) } let ptr := mload(0x40) calldatacopy(add(ptr, 0x0c), _srcAddress.offset, _srcAddress.length) /** * @dev check if LZ from address is same as address(this) */ switch eq(mload(ptr), address()) case 0 { /** * @dev this is the assembly version of -> revert("HOLOGRAPH: unauthorized sender"); */ mstore(0x80, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(0xa0, 0x0000002000000000000000000000000000000000000000000000000000000000) mstore(0xc0, 0x0000001e484f4c4f47524150483a20756e617574686f72697a65642073656e64) mstore(0xe0, 0x6572000000000000000000000000000000000000000000000000000000000000) revert(0x80, 0xc4) } }
Consider upgrading to at least solidity v0.8.15.
payable.transfer
can lead to loss of fundsThe funds that are to be sent can be lost. The issues with transfer()
are outlined here:
https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
596: payable(hToken).transfer(hlgFee);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L596
Using low-level call.value(amount)
with the corresponding result check or using the OpenZeppelin Address.sendValue
is advised:
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L60
ecrecover
may return empty addressThere is a common issue that ecrecover returns empty (0x0) address when the signature is invalid. function _verifySigner
should check that before returning the result of ecrecover.
351: return (ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)), v, r, s) == signer ||
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L333
334: ecrecover(hash, v, r, s) == signer);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L334
See the solution here: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/cryptography/ECDSA.sol#L68
HolographFactory.deployHolographableContract()
can overpopulate HolographRegistry._holographableContracts
The require
checks in HolographFactory.deployHolographableContract()
can easily by bypassed by sending an invalid signature and signer
= 0x0.
As a result, this will deploy a holographableContract and update the HolographRegistry
and push an additional item to HolographRegistry._holographableContracts
.
Due to _holographableContracts.push(contractAddress);
in HolographRegistryInterface(registry).setHolographedHashAddress(hash, holographerAddress);
A malicious user can overpopulate the _holographableContracts
array with redundant data, increasing gas costs when _holographableContracts
is iterated through.
HolographRegistryInterface(registry).setHolographedHashAddress(hash, holographerAddress);
https://github.com/code-423n4/2022-10-holograph/blob/main/contracts/HolographFactory.sol#L259
Implement valid access control on the HolographFactory.deployHolographableContract()
to ensure only the relevant can deploy
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields).
Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
event SecondarySaleFees(uint256 tokenId, address[] recipients, uint256[] bps);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L153
Contracts are allowed to override their parents’ functions and change the visibility from external to public.
function burnFrom(address account, uint256 amount) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L347
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L363
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L420
function onERC20Received( address account, address sender, uint256 amount, bytes calldata data ) public returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L439
function permit( address account, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L460
function safeTransfer(address recipient, uint256 amount) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L492
function safeTransfer( address recipient, uint256 amount, bytes memory data ) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L496
function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L471
function getEthPayout() public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L497
function getTokenPayout(address tokenAddress) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L507
function getTokensPayout(address[] memory tokenAddresses) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L517
function setRoyalties( uint256 tokenId, address payable receiver, uint256 bp ) public onlyOwner {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L529
314: return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L314
254: _blockTime = 60;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L254
256: _baseBondAmount = 100 * (10**18);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L256
261: _operatorThreshold = 1000;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L261
263: _operatorThresholdStep = 10;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L263
265: _operatorThresholdDivisor = 100;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L265
358: if (timeDifference < 6) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L358
1203: return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1203
721: return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L721
916: return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
390: require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L390
395: sending = ((bps[i] * balance) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L395
411: require(balance > 10000, "PA1D: Not enough tokens to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L411
415: sending = ((bps[i] * balance) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L415
435: require(balance > 10000, "PA1D: Not enough tokens to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L435
438: sending = ((bps[i] * balance) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L438
477: require(totalBp == 10000, "PA1D: bps down't equal 10000");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L477
551: return (_getDefaultReceiver(), (_getDefaultBp() * value) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L551
553: return (_getReceiver(tokenId), (_getBp(tokenId) * value) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L553
213: mstore(0xc0, 0x0000001e484f4c4f47524150483a20756e617574686f72697a65642073656e64)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L213
274: return (((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10), nativeFee);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L274
293: return ((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L293
When changing state variables events are not emitted. Emitting events allows monitoring activities with off-chain monitoring tools.
452: function setFactory(address factory) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L452
472: function setHolograph(address holograph) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L472
502: function setOperator(address operator) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L502
522: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L522
280: function setHolograph(address holograph) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L280
300: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L300
949: function setBridge(address bridge) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L949
969: function setHolograph(address holograph) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L969
989: function setInterfaces(address interfaces) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L989
1009: function setMessagingModule(address messagingModule) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1009
1029: function setRegistry(address registry) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1029
1049: function setUtilityToken(address utilityToken) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1049
320: function setBridge(address bridge) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L320
340: function setInterfaces(address interfaces) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L340
360: function setLZEndpoint(address lZEndpoint) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L360
380: function setOperator(address operator) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L380
441: function setBaseGas(uint256 baseGas) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L441
470: function setGasPerByte(uint256 gasPerByte) external onlyAdmin {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L470
require()
/ revert()
Statements Should Have Descriptive Reason Strings578: revert();
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L578
341: revert();
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L341
1215: revert();
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1215
417: revert();
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L417
OpenZeppelin recommends that the initializer modifier be applied to constructors. Per OZs Post implementation contract should be initialized to avoid potential griefs or exploits. https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680/5
contract HolographBridge is Admin, Initializable, HolographBridgeInterface
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L122
contract HolographFactory is Admin, Initializable, Holographable, HolographFactoryInterface
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L123
contract HolographOperator is Admin, Initializable, HolographOperatorInterface
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L125
contract Holographer is Admin, Initializable, HolographerInterface
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L115
contract HolographERC20 is Admin, Owner, Initializable, NonReentrant, EIP712, HolographERC20Interface
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L138
contract HolographERC721 is Admin, Owner, HolographERC721Interface, Initializable
contract PA1D is Admin, Owner, Initializable
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L120
contract LayerZeroModule is Admin, Initializable, CrossChainMessageInterface, LayerZeroModuleInterface
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L122
Use (e.g. 1e6) rather than decimal literals (e.g. 100000), for better code readability.
390: require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L390
395: sending = ((bps[i] * balance) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L395
415: sending = ((bps[i] * balance) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L415
438: sending = ((bps[i] * balance) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L438
411: require(balance > 10000, "PA1D: Not enough tokens to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L411
435: require(balance > 10000, "PA1D: Not enough tokens to transfer");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L435
477: require(totalBp == 10000, "PA1D: bps down't equal 10000");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L477
551: return (_getDefaultReceiver(), (_getDefaultBp() * value) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L551
553: return (_getReceiver(tokenId), (_getBp(tokenId) * value) / 10000);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L553
641: return (_getDefaultBp() * amount) / 10000;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L641
643: return (_getBp(tokenId) * amount) / 10000;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L643
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the Entropy Illusion for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts. References: SWC ID: 116
345: uint256 elapsedTime = block.timestamp - uint256(job.startTimestamp);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L345
499: uint256 random = uint256(keccak256(abi.encodePacked(jobHash, _jobNonce(), block.number, block.timestamp)));
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L499
531: (block.timestamp << 16) |
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L531
469: require(block.timestamp <= deadline, "ERC20: expired deadline");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L469
Block timestamps should not be used for entropy or generating random numbers—i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.
Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable to easily manipulate the block number.
The current form of relative path import is not recommended for use because it can unpredictably pollute the namespace. Instead, the Solidity docs recommend specifying imported symbols explicitly. https://docs.soliditylang.org/en/v0.8.15/layout-of-source-files.html#importing-other-source-files
104: import "./abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L104
105: import "./abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L105
107: import "./interface/HolographERC20Interface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L107
108: import "./interface/Holographable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L108
109: import "./interface/HolographInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L109
110: import "./interface/HolographBridgeInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L110
111: import "./interface/HolographFactoryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L111
112: import "./interface/HolographOperatorInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L112
113: import "./interface/HolographRegistryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L113
114: import "./interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L114
104: import "./abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L104
105: import "./abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L105
107: import "./enforcer/Holographer.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L107
109: import "./interface/Holographable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L109
110: import "./interface/HolographFactoryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L110
111: import "./interface/HolographRegistryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L111
112: import "./interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L112
114: import "./struct/DeploymentConfig.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L114
115: import "./struct/Verification.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L115
104: import "./abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L104
105: import "./abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L105
107: import "./interface/CrossChainMessageInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L107
108: import "./interface/HolographBridgeInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L108
109: import "./interface/HolographERC20Interface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L109
110: import "./interface/HolographInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L110
111: import "./interface/HolographOperatorInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L111
112: import "./interface/HolographRegistryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L112
113: import "./interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L113
114: import "./interface/HolographInterfacesInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L114
115: import "./interface/Ownable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L115
117: import "./struct/OperatorJob.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L117
104: import "../abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol#L104
104: import "../abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol#L104
104: import "../abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L104
105: import "../abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L105
107: import "../interface/HolographInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L107
108: import "../interface/HolographerInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L108
109: import "../interface/HolographRegistryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L109
110: import "../interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L110
104: import "../abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L104
105: import "../abstract/EIP712.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L105
106: import "../abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L106
107: import "../abstract/NonReentrant.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L107
108: import "../abstract/Owner.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L108
110: import "../enum/HolographERC20Event.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L110
111: import "../enum/InterfaceType.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L111
113: import "../interface/ERC20.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L113
114: import "../interface/ERC20Burnable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L114
115: import "../interface/HolographERC20Interface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L115
116: import "../interface/ERC20Metadata.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L116
117: import "../interface/ERC20Permit.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L117
118: import "../interface/ERC20Receiver.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L118
119: import "../interface/ERC20Safer.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L119
120: import "../interface/ERC165.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L120
121: import "../interface/Holographable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L121
122: import "../interface/HolographedERC20.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L122
123: import "../interface/HolographInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L123
124: import "../interface/HolographerInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L124
125: import "../interface/HolographRegistryInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L125
126: import "../interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L126
127: import "../interface/HolographInterfacesInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L127
128: import "../interface/Ownable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L128
130: import "../library/ECDSA.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L130
104: import "../abstract/Admin.sol";
105: import "../abstract/Initializable.sol";
106: import "../abstract/Owner.sol";
108: import "../enum/HolographERC721Event.sol";
109: import "../enum/InterfaceType.sol";
111: import "../interface/ERC165.sol";
112: import "../interface/ERC721.sol";
113: import "../interface/HolographERC721Interface.sol";
114: import "../interface/ERC721Metadata.sol";
115: import "../interface/ERC721TokenReceiver.sol";
116: import "../interface/Holographable.sol";
117: import "../interface/HolographedERC721.sol";
118: import "../interface/HolographInterface.sol";
119: import "../interface/HolographerInterface.sol";
120: import "../interface/HolographRegistryInterface.sol";
121: import "../interface/InitializableInterface.sol";
122: import "../interface/HolographInterfacesInterface.sol";
123: import "../interface/PA1DInterface.sol";
124: import "../interface/Ownable.sol";
104: import "../abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L104
105: import "../abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L105
106: import "../abstract/Owner.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L106
108: import "../interface/ERC20.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L108
109: import "../interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L109
110: import "../interface/PA1DInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L110
112: import "../struct/ZoraBidShares.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L112
104: import "../abstract/Admin.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L104
105: import "../abstract/Initializable.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L105
107: import "../enum/ChainIdType.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L107
109: import "../interface/CrossChainMessageInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L109
110: import "../interface/HolographOperatorInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L110
111: import "../interface/InitializableInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L111
112: import "../interface/HolographInterfacesInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L112
113: import "../interface/LayerZeroModuleInterface.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L113
114: import "../interface/LayerZeroOverrides.sol";
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L114
Use specific imports syntax per solidity docs recommendation.
Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. Since the files will most likely reside in GitHub, and GitHub starts using a scroll bar in all cases when the length is over 164 characters, the lines below should be split when they reach that length Reference: https://docs.soliditylang.org/en/v0.8.10/style-guide.html#maximum-line-length
511: // this will prevent possible tokenId overlap if minting simultaneously on multiple chains is possible
542: // function sourceMintBatch(address[] calldata wallets, uint224[] calldata tokenIds) external onlySource {
618: // Hint taken from Manifold's RoyaltyEngine(https://github.com/manifoldxyz/royalty-registry-solidity/blob/main/contracts/RoyaltyEngineV1.sol)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L618
619: // To be quite honest, SuperRare is a closed marketplace. They're working on opening it up but looks like they want to use private smart contracts.
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L619
bytes.concat()
Solidity version 0.8.4 introduces bytes.concat()
(vs abi.encodePacked(<bytes>,<bytes>)
)
405: samplePayload = abi.encodePacked(encodedData, gasLimit, gasPrice)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographBridge.sol#L405
207: abi.encodePacked( config.contractType, config.chainType, config.salt, keccak256(config.byteCode)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L207
226: uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L226
333: return (ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L333
499: uint256 random = uint256(keccak256(abi.encodePacked(jobHash, _jobNonce()
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L499
635: encodedData = abi.encodePacked(encodedData, gasLimit, gasPrice)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L635
512: uint256 token = uint256(bytes32(abi.encodePacked(_chain()
521: return uint256(bytes32(abi.encodePacked(_chain()
533: // token = uint256(bytes32(abi.encodePacked(chain, tokenIds[i])
548: // token = uint256(bytes32(abi.encodePacked(chain, tokenIds[i])
565: // token = uint256(bytes32(abi.encodePacked(chain, startingTokenId)
257: bytes32 slot = bytes32(uint256(keccak256(abi.encodePacked(_receiverString, tokenId)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L257
269: bytes32 slot = bytes32(uint256(keccak256(abi.encodePacked(_receiverString, tokenId)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L269
280: bytes32 slot = bytes32(uint256(keccak256(abi.encodePacked(_bpString, tokenId)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L280
292: bytes32 slot = bytes32(uint256(keccak256(abi.encodePacked(_bpString, tokenId)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L292
308: slot = keccak256(abi.encodePacked(i, slot)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L308
324: slot = keccak256(abi.encodePacked(i, slot)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L324
341: slot = keccak256(abi.encodePacked(i, slot)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L341
357: slot = keccak256(abi.encodePacked(i, slot)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L357
366: bytes32 slot = bytes32(uint256(keccak256(abi.encodePacked(_tokenAddressString, tokenName)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L366
373: bytes32 slot = bytes32(uint256(keccak256(abi.encodePacked(_tokenAddressString, tokenName)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L373
243: abi.encodePacked(address(this)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L243
247: abi.encodePacked(uint16(1)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L247
269: bytes memory adapterParams = abi.encodePacked( uint16(1)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L269
Use bytes.concat()
and upgrade to at least Solidity version 0.8.4 if required.
ecrecover
is susceptible to signature malleabilityThe built-in EVM precompile ecrecover
is susceptible to signature malleability, which could lead to replay attacks.
References: https://swcregistry.io/docs/SWC-117, https://swcregistry.io/docs/SWC-121, and https://medium.com/cryptronics/signature-replay-vulnerabilities-in-smart-contracts-3b6f7596df57.
While this is not immediately exploitable, this may become a vulnerability if used elsewhere.
351: return (ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)), v, r, s) == signer ||
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L351
334: ecrecover(hash, v, r, s) == signer);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L334
Consider using OpenZeppelin’s ECDSA library (which prevents this malleability) instead of the built-in function.
// function sourceMintBatch(address to, uint224[] calldata tokenIds) external onlySource { // require(tokenIds.length < 1000, "ERC721: max batch size is 1000"); // uint32 chain = _chain(); // uint256 token; // for (uint256 i = 0; i < tokenIds.length; i++) { // require(!_burnedTokens[token], "ERC721: can't mint burned token"); // token = uint256(bytes32(abi.encodePacked(chain, tokenIds[i]))); // require(!_burnedTokens[token], "ERC721: can't mint burned token"); // _mint(to, token); // } // } /** * @dev Allows for source smart contract to mint a batch of tokens. */ // function sourceMintBatch(address[] calldata wallets, uint224[] calldata tokenIds) external onlySource { // require(wallets.length == tokenIds.length, "ERC721: array length missmatch"); // require(tokenIds.length < 1000, "ERC721: max batch size is 1000"); // uint32 chain = _chain(); // uint256 token; // for (uint256 i = 0; i < tokenIds.length; i++) { // token = uint256(bytes32(abi.encodePacked(chain, tokenIds[i]))); // require(!_burnedTokens[token], "ERC721: can't mint burned token"); // _mint(wallets[i], token); // } // } /** * @dev Allows for source smart contract to mint a batch of tokens. */ // function sourceMintBatchIncremental( // address to, // uint224 startingTokenId, // uint256 length // ) external onlySource { // uint32 chain = _chain(); // uint256 token; // for (uint256 i = 0; i < length; i++) { // token = uint256(bytes32(abi.encodePacked(chain, startingTokenId))); // require(!_burnedTokens[token], "ERC721: can't mint burned token"); // _mint(to, token); // startingTokenId++; // } // }
#0 - alexanderattar
2022-11-09T21:59:11Z
Well done!
🌟 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
Issue | Instances | |
---|---|---|
GAS‑1 | Multiple Address Mappings Can Be Combined Into A Single Mapping Of An Address To A Struct, Where Appropriate | 9 |
GAS‑2 | Empty Blocks Should Be Removed Or Emit Something | 6 |
GAS‑3 | <x> += <y> Costs More Gas Than <x> = <x> + <y> For State Variables | 9 |
GAS‑4 | ++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-loops | 15 |
GAS‑5 | Splitting require() Statements That Use && Saves Gas | 3 |
GAS‑6 | abi.encode() Is Less Efficient Than abi.encodepacked() | 5 |
GAS‑7 | Help The Optimizer By Saving A Storage Variable’s Reference Instead Of Repeatedly Fetching It | 2 |
GAS‑8 | Use calldata instead of memory for function parameters | 17 |
GAS‑9 | Use assembly to check for address(0) | 1 |
GAS‑10 | Using 10**X for constants isn't gas efficient | 3 |
GAS‑11 | Public Functions To External | 48 |
GAS‑12 | Usage of uints /ints smaller than 32 bytes (256 bits) incurs overhead | 3 |
GAS‑13 | Optimize names to save gas | 9 |
Total: 130 instances over 13 issues
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.
218: mapping(address => uint256) private _bondedOperators;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L218
223: mapping(address => uint256) private _operatorPodIndex;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L223
228: mapping(address => uint256) private _bondedAmounts;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L228
156: mapping(address => uint256) private _balances;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L156
161: mapping(address => mapping(address => uint256)) private _allowances;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L161
186: mapping(address => uint256) private _nonces;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L186
185: mapping(address => uint256) private _ownedTokensCount;
190: mapping(address => uint256[]) private _ownedTokens;
196: mapping(address => mapping(address => bool)) private _operatorApprovals;
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{...}})
1209: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1209
212: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol#L212
212: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol#L212
223: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L223
251: receive() external payable {}
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L251
962: receive() external payable {}
<x> += <y>
Costs More Gas Than <x> = <x> + <y>
For State Variables378: _bondedAmounts[job.operator] -= amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L378
382: _bondedAmounts[msg.sender] += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L382
834: _bondedAmounts[operator] += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L834
1175: position -= threshold;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1175
1177: current += (current / _operatorThresholdDivisor) * (position / _operatorThresholdStep);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L1177
633: _totalSupply -= amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L633
685: _totalSupply += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L685
686: _balances[to] += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L686
702: _balances[recipient] += amount;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L702
++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-loopsThe unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP
781: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L781
871: for (uint256 i = _operatorPods.length; i <= pod; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L871
564: for (uint256 i = 0; i < wallets.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L564
357: for (uint256 i = 0; i < length; i++) {
716: for (uint256 i = 0; i < length; i++) {
307: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L307
323: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L323
340: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L340
356: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L356
394: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L394
414: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L414
432: for (uint256 t = 0; t < tokenAddresses.length; t++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L432
437: for (uint256 i = 0; i < addresses.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L437
454: for (uint256 i = 0; i < addresses.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L454
474: for (uint256 i = 0; i < addresses.length; i++) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L474
require()
Statements That Use &&
Saves GasSee https://github.com/code-423n4/2022-01-xdefi-findings/issues/128 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/tree/main/contracts/HolographOperator.sol#L857
166: require(success && selector == InitializableInterface.init.selector, "initialization failed");
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L166
263: require(success && selector == InitializableInterface.init.selector, "ERC721: coud not init PA1D");
abi.encode()
Is Less Efficient Than abi.encodepacked()
252: abi.encode(abi.encode(config.chainType, holograph, config.contractType, sourceContractAddress), config.initCode)
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol#L252
409: return (Holographable.bridgeOut.selector, abi.encode(from, to, amount, data));
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L409
471: abi.encode(
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L471
260: abi.encodeWithSignature("initPA1D(bytes)", abi.encode(address(this), uint256(contractBps)))
426: return (Holographable.bridgeOut.selector, abi.encode(from, to, tokenId, data));
To help the optimizer, declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array. The effect can be quite significant. As an example, instead of repeatedly calling someMap[someIndex], save its reference like this: SomeStruct storage someStruct = someMap[someIndex] and use it.
782: operators[i] = _operatorPods[pod][index + i];
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L782
358: tokenIds[i] = _ownedTokens[wallet][index + i];
In some cases, having function arguments in calldata instead of memory is more optimal.
Consider the following generic example:
contract C { function add(uint[] memory arr) external returns (uint sum) { uint length = arr.length; for (uint i = 0; i < arr.length; i++) { sum += arr[i]; } } }
In the above example, the dynamic array arr has the storage location memory. When the function gets called externally, the array values are kept in calldata and copied to memory during ABI decoding (using the opcode calldataload and mstore). And during the for loop, arr[i] accesses the value in memory using a mload. However, for the above example this is inefficient. Consider the following snippet instead:
contract C { function add(uint[] calldata arr) external returns (uint sum) { uint length = arr.length; for (uint i = 0; i < arr.length; i++) { sum += arr[i]; } } }
In the above snippet, instead of going via memory, the value is directly read from calldata using calldataload. That is, there are no intermediate memory operations that carries this value.
Gas savings: In the former example, the ABI decoding begins with copying value from calldata to memory in a for loop. Each iteration would cost at least 60 gas. In the latter example, this can be completely avoided. This will also reduce the number of instructions and therefore reduces the deploy time cost of the contract.
In short, use calldata instead of memory if the function argument is only read.
Note that in older Solidity versions, changing some function arguments from memory to calldata may cause "unimplemented feature error". This can be avoided by using a newer (0.8.*) Solidity compiler.
Examples Note: The following pattern is prevalent in the codebase:
function f(bytes memory data) external { (...) = abi.decode(data, (..., types, ...)); }
Here, changing to bytes calldata will decrease the gas. The total savings for this change across all such uses would be quite significant.
function getPodOperators(uint256 pod) external view returns (address[] memory operators) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L738
function getPodOperators( uint256 pod, uint256 index, uint256 length ) external view returns (address[] memory operators) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L738
function tokensOfOwner(address wallet) external view returns (uint256[] memory) {
function tokensOfOwner( address wallet, uint256 index, uint256 length ) external view returns (uint256[] memory tokenIds) {
function tokens(uint256 index, uint256 length) external view returns (uint256[] memory tokenIds) {
function _getPayoutAddresses() private view returns (address payable[] memory addresses) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L298
function _setPayoutAddresses(address payable[] memory addresses) private {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L316
function _getPayoutBps() private view returns (uint256[] memory bps) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L332
function _setPayoutBps(uint256[] memory bps) private {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L349
function _payoutTokens(address[] memory tokenAddresses) private {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L426
function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L471
function getPayoutInfo() public view returns (address payable[] memory addresses, uint256[] memory bps) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L488
function getTokensPayout(address[] memory tokenAddresses) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L517
function getFeeBps(uint256 tokenId) public view returns (uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L558
function getFeeRecipients(uint256 tokenId) public view returns (address payable[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L569
function getRoyalties(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L585
function getFees(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L604
address(0)
Save 6 gas per instance if using assembly to check for address(0)
e.g.
assembly { if iszero(_addr) { mstore(0x00, "AddressZero") revert(0x00, 0x20) } }
function balanceOf(address wallet) public view returns (uint256) {
10**X
for constants isn't gas efficientIn Solidity, a constant expression in a variable will compute the expression everytime the variable is called. It's not the result of the expression that is stored, but the expression itself.
As Solidity supports the scientific notation, constants of form 10**X can be rewritten as 1eX to save the gas cost from the calculation with the exponentiation operator **.
256: _baseBondAmount = 100 * (10**18); // one single token unit * 100
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L256
274: return (((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10), nativeFee);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L274
293: return ((gasPrice * (gasLimit + (gasLimit / 10))) * dstPriceRatio) / (10**10);
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol#L293
Replace 10**X with 1eX
The following functions could be set external to save gas and improve code quality. External call cost is less expensive than of public functions.
function getJobDetails(bytes32 jobHash) public view returns (OperatorJob memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L690
function getHolographEnforcer() public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol#L192
function decimals() public view returns (uint8) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L273
function allowance(address account, address spender) public view returns (uint256) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L297
function balanceOf(address account) public view returns (uint256) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L301
function DOMAIN_SEPARATOR() public view returns (bytes32) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L306
function name() public view returns (string memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L310
function nonces(address account) public view returns (uint256) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L314
function symbol() public view returns (string memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L318
function totalSupply() public view returns (uint256) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L322
function approve(address spender, uint256 amount) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L326
function burn(uint256 amount) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L337
function burnFrom(address account, uint256 amount) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L347
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L363
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L420
function onERC20Received( address account, address sender, uint256 amount, bytes calldata data ) public returns (bytes4) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L439
function permit( address account, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L460
function safeTransfer(address recipient, uint256 amount) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L492
function safeTransfer( address recipient, uint256 amount, bytes memory data ) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L492
function safeTransferFrom( address account, address recipient, uint256 amount ) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L512
function safeTransferFrom( address account, address recipient, uint256 amount, bytes memory data ) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L512
function transfer(address recipient, uint256 amount) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L580
function transferFrom( address account, address recipient, uint256 amount ) public returns (bool) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L591
function owner() public view override returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L740
function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public payable {
function transferFrom( address from, address to, uint256 tokenId ) public payable {
function transferFrom( address from, address to, uint256 tokenId, bytes memory data ) public payable {
function balanceOf(address wallet) public view returns (uint256) {
function burned(uint256 tokenId) public view returns (bool) {
function exists(uint256 tokenId) public view returns (bool) {
function owner() public view override returns (address) {
function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L471
function getPayoutInfo() public view returns (address payable[] memory addresses, uint256[] memory bps) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L488
function getEthPayout() public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L497
function getTokenPayout(address tokenAddress) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L507
function getTokensPayout(address[] memory tokenAddresses) public {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L517
function setRoyalties( uint256 tokenId, address payable receiver, uint256 bp ) public onlyOwner {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L529
function royaltyInfo(uint256 tokenId, uint256 value) public view returns (address, uint256) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L549
function getFeeBps(uint256 tokenId) public view returns (uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L558
function getFeeRecipients(uint256 tokenId) public view returns (address payable[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L569
function getRoyalties(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L585
function getFees(uint256 tokenId) public view returns (address payable[] memory, uint256[] memory) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L604
function tokenCreator( address, uint256 tokenId ) public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L621
function calculateRoyaltyFee( address, uint256 tokenId, uint256 amount ) public view returns (uint256) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L634
function marketContract() public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L649
function tokenCreators(uint256 tokenId) public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L655
function bidSharesForToken(uint256 tokenId) public view returns (ZoraBidShares memory bidShares) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L665
function getTokenAddress(string memory tokenName) public view returns (address) {
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol#L683
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
Each operation involving a uint8
costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8
) as compared to ones involving uint256
, due to the compiler having to clear the higher bits of the memory word before operating on the uint8
, as well as the associated stack operations of doing so. Use a larger size then downcast where needed
208: uint32 private _operatorTempStorageCounter;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol#L208
181: uint8 private _decimals;
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol#L181
160: uint16 private _bps;
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. 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
File: \2022-10-holograph\contracts\HolographFactory.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographFactory.sol
File: \2022-10-holograph\contracts\HolographOperator.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/HolographOperator.sol
File: \2022-10-holograph\contracts\abstract\ERC20H.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC20H.sol
File: \2022-10-holograph\contracts\abstract\ERC721H.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/abstract/ERC721H.sol
File: \2022-10-holograph\contracts\enforcer\Holographer.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/Holographer.sol
File: \2022-10-holograph\contracts\enforcer\HolographERC20.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC20.sol
File: \2022-10-holograph\contracts\enforcer\HolographERC721.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/HolographERC721.sol
File: \2022-10-holograph\contracts\enforcer\PA1D.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/enforcer/PA1D.sol
File: \2022-10-holograph\contracts\module\LayerZeroModule.sol
https://github.com/code-423n4/2022-10-holograph/tree/main/contracts/module/LayerZeroModule.sol