Arcade.xyz - T1MOH's results

The first of its kind Web3 platform to enable liquid lending markets for NFTs.

General Information

Platform: Code4rena

Start Date: 21/07/2023

Pot Size: $90,500 USDC

Total HM: 8

Participants: 60

Period: 7 days

Judge: 0xean

Total Solo HM: 2

Id: 264

League: ETH

Arcade.xyz

Findings Distribution

Researcher Performance

Rank: 5/60

Findings: 1

Award: $2,663.87

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: 0x3b

Also found by: T1MOH, osmanozdemir1

Labels

bug
2 (Med Risk)
satisfactory
duplicate-213

Awards

2663.8738 USDC - $2,663.87

External Links

Lines of code

https://github.com/code-423n4/2023-07-arcade/blob/f8ac4e7c4fdea559b73d9dd5606f618d4e6c73cd/contracts/libraries/ArcadeMerkleRewards.sol#L106

Vulnerability details

Impact

Admin is allowed to update merkleRoot. But some users won't be able to claim correct amount because of inconsistent check in claiming function.

Proof of Concept

Current implementation reverts if user claimed some amount before.

    function claimAndDelegate(address delegate, uint128 totalGrant, bytes32[] calldata merkleProof) external {
        ...
        _validateWithdraw(totalGrant, merkleProof);

        ...
    }

    function _validateWithdraw(uint256 totalGrant, bytes32[] memory merkleProof) internal {
        // validate proof and leaf hash
        bytes32 leafHash = keccak256(abi.encodePacked(msg.sender, totalGrant));
        if (!MerkleProof.verify(merkleProof, rewardsRoot, leafHash)) revert AA_NonParticipant();

        // ensure the user has not already claimed the airdrop
        if (claimed[msg.sender] != 0) revert AA_AlreadyClaimed();
        claimed[msg.sender] = totalGrant;
    }

However this can be the case when admin by some reason (for example by mistake setted incorrect amounts before) wants to increase amount for user and submits new merkleRoot.

  1. User claims his 1 token
  2. Admin notices error and submits new merkleRoot with user amount = 1000
  3. User can't claim it because of revert
        if (claimed[msg.sender] != 0) revert AA_AlreadyClaimed();

Tools Used

Manual Review

    function claimAndDelegate(address delegate, uint128 totalGrant, bytes32[] calldata merkleProof) external {
        ...

        // validate the withdraw
-        _validateWithdraw(totalGrant, merkleProof);
+        totalGrant = _validateWithdraw(totalGrant, merkleProof);

        ...
    }
-    function _validateWithdraw(uint256 totalGrant, bytes32[] memory merkleProof) internal {
+    function _validateWithdraw(uint256 totalGrant, bytes32[] memory merkleProof) internal returns(uint128 grantedAmount) {
         // validate proof and leaf hash
         bytes32 leafHash = keccak256(abi.encodePacked(msg.sender, totalGrant));
         if (!MerkleProof.verify(merkleProof, rewardsRoot, leafHash)) revert AA_NonParticipant();
 
         // ensure the user has not already claimed the airdrop
-        if (claimed[msg.sender] != 0) revert AA_AlreadyClaimed();
+        if (claimed[msg.sender] >= totalGrant) revert AA_AlreadyClaimed();
+        grantedAmount = uint128(totalGrant - claimed[msg.sender]);
         claimed[msg.sender] = totalGrant;
     }

Assessed type

Other

#0 - c4-pre-sort

2023-07-30T05:43:57Z

141345 marked the issue as duplicate of #213

#1 - c4-judge

2023-08-11T16:34:14Z

0xean marked the issue as satisfactory

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