code-423n4 / 2022-09-vtvl-findings

0 stars 0 forks source link

Design decision: use merkle tree to config and validate the claimable address instead of using a batch for loop to avoid gas issue in loops. #14

Closed code423n4 closed 1 year ago

code423n4 commented 1 year ago

Lines of code

https://github.com/code-423n4/2022-09-vtvl/blob/f68b7f3e61dad0d873b5b5a1e8126b839afeab5f/contracts/VTVLVesting.sol#L354

Vulnerability details

Impact

Detailed description of the impact of this finding.

the function below config a list of addresses that are eligile to claim the linear vested or cliff vested token

in VTVLVesting.sol contract

        for (uint256 i = 0; i < length; i++) {
            _createClaimUnchecked(_recipients[i], _startTimestamps[i], _endTimestamps[i], _cliffReleaseTimestamps[i], _releaseIntervalsSecs[i], _linearVestAmounts[i], _cliffAmounts[i]);
        }

but practically speaking, the admin may need to set a lot of addresses that are claimable to claim the tokens.

the unbound gas consumption can be expensive for admin.

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

A project need to set 1000 address to claim the vested token. the massive for loop revert because of gas issue. the admin has to pay expensive gas to complete the transactions.

Tools Used

Foundry

Hardhat

Manual Review

Recommended Mitigation Steps

We recommand the project to create a merkle tree root offline and verify the msg.sender of the claimer as the merkle leaf.

combining with whitelist or blacklist, the admin can still control who can claim the token on chain.

below are the implementation.

https://github.com/Anish-Agnihotri/merkle-airdrop-starter/blob/master/contracts/src/MerkleClaimERC20.sol

import { MerkleProof } from "@openzeppelin/utils/cryptography/MerkleProof.sol"; // OZ: MerkleProof

bytes32 public immutable merkleRoot;

 constructor(
    bytes32 _merkleRoot
  ) {
    merkleRoot = _merkleRoot; // Update root
  }

function validate(address to, uint256 amount) {
   bytes32 leaf = keccak256(abi.encodePacked(to, amount));
  bool isValidLeaf = MerkleProof.verify(proof, merkleRoot, leaf);
  if (!isValidLeaf) revert NotInMerkle();
}

to generate a merkle root based on the token claim configuration, please refer to

https://github.com/Anish-Agnihotri/merkle-airdrop-starter/tree/master/generator

give the configuration below

 {
  "decimals": 18,
  "airdrop": {
    "0x016C8780e5ccB32E5CAA342a926794cE64d9C364": 10,
    "0x185a4dc360ce69bdccee33b3784b0282f7961aea": 100
  }
}

a merkle root can be generated.

0xean commented 1 year ago

downgrading to QA /informational dupe of #9