Skip to content

Artifacts

DISCLAIMER // NFA // DYOR

This analysis is based on observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.

⊙ generated by robots | curated by humans

METADATA
Contract Address 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D (etherscan)
Network Ethereum Mainnet
Analysis Date 2026-01-23

Overview

This document contains raw analysis artifacts including reconstructed source code, function selector mappings, event signatures, verification commands, and supporting data files. All artifacts are preserved for transparency and independent verification.

Artifact Location: /artifacts/33184cd3...8a606d/


Reconstructed Solidity Source

Based on bytecode analysis and transaction patterns, the contract logic appears to follow this structure:

// SPDX-License-Identifier: UNLICENSED
// Solidity Version: ^0.8.33
// WARNING: Reconstructed from bytecode - NOT the original source code

pragma solidity ^0.8.33;

interface IFlexibleAllocation {
    function getAllocation(address account) external view returns (uint256);
}

contract ClaimManager {

    //////////////////////////////////////////////////////////////
    //  STORAGE
    //////////////////////////////////////////////////////////////

    // Slot 0
    address public flexibleAllocation;

    // Slot 1 - Dual purpose: hasClaimed AND eligibilityStatus
    mapping(address => bool) public hasClaimed;  // Also used for eligibility

    // Slot 2 - Packed storage
    address private _owner;              // bytes 0-19
    bool private _paused;                // byte 20
    bool private _claimingEnabled;       // byte 21

    //////////////////////////////////////////////////////////////
    //  EVENTS
    //////////////////////////////////////////////////////////////

    event Claimed(address indexed account, uint256 allocation);
    event Paused(address account);
    event Unpaused(address account);
    event ClaimingEnabledUpdated(bool enabled);
    event EligibilityStatusUpdated(address indexed account, bool status);
    event FlexibleAllocationUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    //////////////////////////////////////////////////////////////
    //  MODIFIERS
    //////////////////////////////////////////////////////////////

    modifier onlyOwner() {
        require(msg.sender == _owner, "Only owner can call this function");
        _;
    }

    modifier whenNotPaused() {
        require(!_paused, "Contract is paused");
        _;
    }

    modifier whenPaused() {
        require(_paused, "Contract is not paused");
        _;
    }

    //////////////////////////////////////////////////////////////
    //  CONSTRUCTOR
    //////////////////////////////////////////////////////////////

    constructor(address _flexibleAllocation) {
        require(
            _flexibleAllocation != address(0),
            "Invalid FlexibleAllocation address"
        );

        flexibleAllocation = _flexibleAllocation;
        _owner = msg.sender;
        _paused = false;
        _claimingEnabled = true;  // Note: Not enforced in claim()
    }

    //////////////////////////////////////////////////////////////
    //  USER FUNCTIONS
    //////////////////////////////////////////////////////////////

    /// @notice Allows eligible users to claim (marks status as claimed)
    /// @dev Does NOT transfer tokens - only tracking mechanism
    function claim() external whenNotPaused {
        require(
            !hasClaimed[msg.sender],
            "Already claimed"
        );

        // External call to allocation contract
        uint256 allocation = IFlexibleAllocation(flexibleAllocation)
            .getAllocation(msg.sender);

        require(
            allocation >= 1,
            "Insufficient allocation - must have at least 1"
        );

        // Mark as claimed (permanent)
        hasClaimed[msg.sender] = true;

        emit Claimed(msg.sender, allocation);
    }

    //////////////////////////////////////////////////////////////
    //  VIEW FUNCTIONS
    //////////////////////////////////////////////////////////////

    /// @notice Check if an address can claim
    /// @param account Address to check
    /// @return bool True if can claim, false otherwise
    function canClaim(address account) external view returns (bool) {
        if (hasClaimed[account]) {
            return false;
        }

        uint256 allocation = IFlexibleAllocation(flexibleAllocation)
            .getAllocation(account);

        return allocation >= 1;
    }

    /// @notice Returns pause state
    function paused() external view returns (bool) {
        return _paused;
    }

    /// @notice Returns current owner
    function owner() external view returns (address) {
        return _owner;
    }

    /// @notice Returns claiming enabled state
    /// @dev Note: This flag is NOT checked in claim() function
    function claimingEnabled() external view returns (bool) {
        return _claimingEnabled;
    }

    /// @notice Returns FlexibleAllocation contract address
    function flexibleAllocation() external view returns (address) {
        return flexibleAllocation;
    }

    /// @notice Returns eligibility status (reads same storage as hasClaimed)
    /// @param account Address to check
    /// @return bool Status from slot 1
    function getEligibilityStatus(address account) external view returns (bool) {
        return hasClaimed[account];  // Same storage!
    }

    //////////////////////////////////////////////////////////////
    //  ADMIN FUNCTIONS
    //////////////////////////////////////////////////////////////

    /// @notice Pauses the contract
    function pause() external onlyOwner whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /// @notice Unpauses the contract
    function unpause() external onlyOwner whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }

    /// @notice Sets claiming enabled flag
    /// @param enabled New enabled state
    /// @dev Note: This flag is NOT enforced in claim()
    function setClaimingEnabled(bool enabled) external onlyOwner {
        _claimingEnabled = enabled;
        emit ClaimingEnabledUpdated(enabled);
    }

    /// @notice Changes FlexibleAllocation contract reference
    /// @param newAllocation New allocation contract address
    function setFlexibleAllocation(address newAllocation) external onlyOwner {
        require(
            newAllocation != address(0),
            "Invalid FlexibleAllocation address"
        );

        address oldAllocation = flexibleAllocation;
        flexibleAllocation = newAllocation;

        emit FlexibleAllocationUpdated(oldAllocation, newAllocation);
    }

    /// @notice Sets eligibility status for single address
    /// @param account Address to modify
    /// @param status New eligibility status
    /// @dev Writes to same storage as hasClaimed
    function setEligibilityStatus(address account, bool status) external onlyOwner {
        require(account != address(0), "Invalid account address");

        hasClaimed[account] = status;  // Dual-purpose storage

        emit EligibilityStatusUpdated(account, status);
    }

    /// @notice Sets eligibility status for multiple addresses
    /// @param accounts Array of addresses
    /// @param statuses Array of statuses
    function batchSetEligibilityStatus(
        address[] calldata accounts,
        bool[] calldata statuses
    ) external onlyOwner {
        require(accounts.length > 0, "Empty accounts array");
        require(
            accounts.length == statuses.length,
            "Arrays length mismatch"
        );

        for (uint256 i = 0; i < accounts.length; i++) {
            require(accounts[i] != address(0), "Invalid account address");

            hasClaimed[accounts[i]] = statuses[i];

            emit EligibilityStatusUpdated(accounts[i], statuses[i]);
        }
    }

    /// @notice Transfers ownership
    /// @param newOwner New owner address
    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "Invalid new owner address");

        address oldOwner = _owner;
        _owner = newOwner;

        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

Function Selector Mapping

Complete mapping of function selectors to signatures:

0x0fb50c26 => claimingEnabled() view returns (bool)
0x28c30c07 => setClaimingEnabled(bool)
0x2b2b14a4 => setEligibilityStatus(address,bool)
0x360cbe3e => batchSetEligibilityStatus(address[],bool[])
0x3f4ba83a => unpause()
0x4e71d92d => claim()
0x5c975abb => paused() view returns (bool)
0x73b2e80e => hasClaimed(address) view returns (bool)
0x8456cb59 => pause()
0x8da5cb5b => owner() view returns (address)
0x9d97e2bb => flexibleAllocation() view returns (address)
0xa074696a => getEligibilityStatus(address) view returns (bool)
0xba2f0e4c => setFlexibleAllocation(address)
0xf2fde38b => transferOwnership(address)
0xfd32ea70 => canClaim(address) view returns (bool)

Event Signatures

Event topic hashes and their corresponding signatures:

0x106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241
=> Claimed(address indexed account, uint256 allocation)

0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258
=> Paused(address account)

0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa
=> Unpaused(address account)

0x8259bcb199fe2662027c78039375d45439569d4d8f3d2a28451581fdf6f45307
=> ClaimingEnabledUpdated(bool enabled)

0x882c8cb812325c2f735789a0a790cc6a8a62fced20c77fe55dd6bcdccac2ffb7
=> EligibilityStatusUpdated(address indexed account, bool status)

0x4bde3f66dadc7c8dd7a250f6c68357730f7dbbc65bf2b8105a8e492896f7bba9
=> FlexibleAllocationUpdated(address indexed oldAddress, address indexed newAddress)

0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
=> OwnershipTransferred(address indexed previousOwner, address indexed newOwner)

External Contract Interface

The contract depends on this external interface:

// Address: 0xe6c328360439b91727ec854bf2b6caeeaff5dc66
// Status: UNVERIFIED

interface IFlexibleAllocation {
    /// @notice Returns allocation amount for an address
    /// @param account Address to check
    /// @return uint256 Allocation amount (must be >= 1 to claim)
    function getAllocation(address account) external view returns (uint256);
}

// Function selector: 0x0e022923

Storage Layout Diagram

┌───────────────────────────────────────────────────────────────────┐
│  SLOT 0 (32 bytes)                                                │
│  ┌────────────────────────────────────┬─────────────────────────┐ │
│  │  flexibleAllocation (address)      │  unused (12 bytes)      │ │
│  │  20 bytes                          │                         │ │
│  └────────────────────────────────────┴─────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────────────────┐
│  SLOT 1 (mapping - dynamic addressing)                            │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │  mapping(address => bool) hasClaimed / eligibilityStatus     │ │
│  │  Location: keccak256(abi.encodePacked(address, uint256(1))) │ │
│  └──────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────────────────┐
│  SLOT 2 (32 bytes - PACKED)                                       │
│  ┌─────────────┬─────┬────────────────┬───────────────────────┐   │
│  │  owner      │ p │ cE │ unused   │                           │   │
│  │  (address)  │ a │    │ (10 bytes)                         │   │
│  │  20 bytes   │ u │    │                                    │   │
│  │             │ s │    │                                    │   │
│  │             │ e │    │                                    │   │
│  │             │ d │    │                                    │   │
│  │             │   │    │                                    │   │
│  │             │ 1b│ 1b │                                    │   │
│  └─────────────┴───┴────┴────────────────────────────────────┘   │
│    bytes 0-19    20  21   bytes 22-31                            │
└───────────────────────────────────────────────────────────────────┘

Legend:
- p = paused (bool, 1 byte)
- cE = claimingEnabled (bool, 1 byte)

Verification Commands

Basic Contract Info

# Get contract bytecode
cast code 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D

# Get contract bytecode size
cast code 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D | wc -c

# Check if contract exists
cast codesize 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D

Storage Reading

# Read slot 0 (flexibleAllocation)
cast storage 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D 0

# Read slot 2 (owner + flags)
cast storage 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D 2

# Read hasClaimed for specific address
ADDRESS=0x...
cast index address $ADDRESS 1
# Then read from calculated slot

View Function Calls

# Get owner
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "owner()"

# Check pause status
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "paused()"

# Check claiming enabled
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "claimingEnabled()"

# Get FlexibleAllocation address
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "flexibleAllocation()"

# Check if address has claimed
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "hasClaimed(address)" 0xADDRESS

# Check if address can claim
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "canClaim(address)" 0xADDRESS

# Get eligibility status
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "getEligibilityStatus(address)" 0xADDRESS

Function Selector Verification

# Verify function selectors
cast sig "claim()"                                      # 0x4e71d92d
cast sig "pause()"                                      # 0x8456cb59
cast sig "unpause()"                                    # 0x3f4ba83a
cast sig "paused()"                                     # 0x5c975abb
cast sig "owner()"                                      # 0x8da5cb5b
cast sig "transferOwnership(address)"                   # 0xf2fde38b
cast sig "claimingEnabled()"                            # 0x0fb50c26
cast sig "setClaimingEnabled(bool)"                     # 0x28c30c07
cast sig "setEligibilityStatus(address,bool)"           # 0x2b2b14a4
cast sig "batchSetEligibilityStatus(address[],bool[])"  # 0x360cbe3e
cast sig "hasClaimed(address)"                          # 0x73b2e80e
cast sig "flexibleAllocation()"                         # 0x9d97e2bb
cast sig "getEligibilityStatus(address)"                # 0xa074696a
cast sig "setFlexibleAllocation(address)"               # 0xba2f0e4c
cast sig "canClaim(address)"                            # 0xfd32ea70

Event Topic Verification

# Verify event topics
cast keccak "Claimed(address,uint256)"
# Should return: 0x106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241

cast keccak "Paused(address)"
# Should return: 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258

cast keccak "Unpaused(address)"
# Should return: 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa

cast keccak "OwnershipTransferred(address,address)"
# Should return: 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0

Transaction Simulation

# Simulate claim (will revert if not eligible or already claimed)
cast call 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "claim()" --from 0xYOUR_ADDRESS

# Estimate gas for claim
cast estimate 0x33184cD3E5F9D27C6E102Da6BE33e779528A606D "claim()" --from 0xYOUR_ADDRESS

Raw Data Files

The following files are stored in /artifacts/33184cd3...8a606d/:

FILE SIZE DESCRIPTION
bytecode.txt 13.3 KB Full contract bytecode (hex)
selectors.txt 165 B List of function selectors
function-mapping.txt 2.1 KB Selector to signature mapping
storage-analysis.txt 3.5 KB Storage slot analysis notes
contract-summary.md 1.8 KB Quick reference summary
TODO.md 3.0 KB Analysis task checklist

RESOURCE URL
Etherscan Contract https://etherscan.io/address/0x33184cD3E5F9D27C6E102Da6BE33e779528A606D
Creation TX https://etherscan.io/tx/0x9b3eca091ce21a8f3d2f58c5e3b7c8544af48c0d7feb9358e7e15a7a1afaa6d8
FlexibleAllocation https://etherscan.io/address/0xe6c328360439b91727ec854bf2b6caeeaff5dc66
Owner Address https://etherscan.io/address/0x2a4a36b59c47f9ed95b562ebeaefa8c19ef04902
Deployer Address https://etherscan.io/address/0xfcFD812DDE04058EadD91414772b51De14223DBb

Analysis Metadata

{
  "contract_address": "0x33184cD3E5F9D27C6E102Da6BE33e779528A606D",
  "network": "ethereum-mainnet",
  "analysis_date": "2026-01-23",
  "analyst": "Claude Sonnet 4.5",
  "analysis_method": "Bytecode decompilation + transaction pattern analysis",
  "verification_status": "unverified",
  "total_functions": 15,
  "admin_functions": 6,
  "user_functions": 1,
  "view_functions": 7,
  "events": 7,
  "storage_slots": 3,
  "external_dependencies": 1,
  "deployment_block": 24140130,
  "deployment_timestamp": "2026-01-01T13:38:11Z",
  "compiler_version": "0.8.33",
  "transaction_count": 620,
  "token_cost": "65 tok"
}

Disclaimer

The reconstructed source code and all artifacts in this document are based on bytecode analysis of an unverified contract. They represent our best interpretation of the contract's behavior but may not perfectly match the original source code. Variables names, function logic, and internal structures are inferred and should not be considered authoritative.

For critical operations, always:
1. Request source code verification from the contract owner
2. Perform transaction simulation before execution
3. Consult with blockchain security professionals
4. Verify all findings independently using provided commands