Holograph contest - hansfriese's results

Omnichain protocol for deploying, minting, & bridging NFTs between blockchains.

General Information

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

Holograph

Findings Distribution

Researcher Performance

Rank: 106/144

Findings: 1

Award: $0.00

QA:
grade-c

🌟 Selected for report: 0

🚀 Solo Findings: 0

[L-01] Use of Solidity version 0.8.13 which has known issues

The version 0.8.13 has some issues like Vulnerability related to ABI-encoding and Vulnerability related to 'Optimizer Bug Regarding Memory Side Effects of Inline Assembly'.

Many contracts contain the encoding logics and there are many assemblies in the protocol also.

Recommend using the latest solidity version like 0.8.17.

[L-02] Wrong gas limit

    // accommodating the 2300 gas stipend
    // adding 1x for each item in array to accomodate rounding errors
    uint256 gasCost = (23300 * length) + length;

Currently, it distrubute smaller eth than expected and we should change 23300 to 2300 like the comment.

[L-03] We should check if bps[i] > 0 in configurePayouts()

  function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner {
    require(addresses.length == bps.length, "PA1D: missmatched array lenghts");
    uint256 totalBp;
    for (uint256 i = 0; i < addresses.length; i++) {
      totalBp = totalBp + bps[i];
    }
    require(totalBp == 10000, "PA1D: bps down't equal 10000"); //@audit-N5
    _setPayoutAddresses(addresses);
    _setPayoutBps(bps);
  }

If bps[i] == 0, it will just increase the length and produce unnecessary transfers in _payoutEth() and _payoutToken().

Also, with the revert-on-zero-value-tranfer tokens, _payoutToken() will revert here.

  function _payoutToken(address tokenAddress) private {
    address payable[] memory addresses = _getPayoutAddresses();
    uint256[] memory bps = _getPayoutBps();
    uint256 length = addresses.length;
    ERC20 erc20 = ERC20(tokenAddress);
    uint256 balance = erc20.balanceOf(address(this));
    require(balance > 10000, "PA1D: Not enough tokens to transfer");
    uint256 sending;
    //uint256 sent;
    for (uint256 i = 0; i < length; i++) {
      sending = ((bps[i] * balance) / 10000);
      require(erc20.transfer(addresses[i], sending), "PA1D: Couldn't transfer token");
      // sent = sent + sending;
    }
  }

[L-04] There should be an upper limit of addresses.length in configurePayouts()

  function configurePayouts(address payable[] memory addresses, uint256[] memory bps) public onlyOwner {
    require(addresses.length == bps.length, "PA1D: missmatched array lenghts");
    uint256 totalBp;
    for (uint256 i = 0; i < addresses.length; i++) {
      totalBp = totalBp + bps[i];
    }
    require(totalBp == 10000, "PA1D: bps down't equal 10000"); //@audit-N5
    _setPayoutAddresses(addresses);
    _setPayoutBps(bps);
  }

Currently, addresses.length can be 10000 at most(when we check if bps > 0) and _payoutEth() and _payoutToken() will revert because of block gas limit.

We should check an upper limit like 50.

[L-05] Check address(0) for addresses in _setPayoutAddresses()

  function _setPayoutAddresses(address payable[] memory addresses) private {
    bytes32 slot = _payoutAddressesSlot;
    uint256 length = addresses.length;
    assembly {
      sstore(slot, length)
    }
    address payable value;
    for (uint256 i = 0; i < length; i++) {
      slot = keccak256(abi.encodePacked(i, slot));
      value = addresses[i];
      assembly {
        sstore(slot, value)
      }
    }
  }

Currently, there is no validation of address(0) and the tokens might be lost in _payoutEth() and _payoutToken().

[N-01] Typo

require(totalBp == 10000, "PA1D: bps down't equal 10000");

Change down't to doesn't.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter