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 | 0x93Ad33AC2d4cbA339389F42D9345Db3B34174c9E (etherscan) |
| Network | Ethereum Mainnet |
| Analysis Date | 2026-01-13 |
Runtime Bytecode
The deployed contract bytecode fetched from the blockchain.
Source: Etherscan - Implementation Contract Code
Command:
Artifact: Available on Etherscan at the link above. The bytecode is several kilobytes and not reproduced here for brevity. View directly on Etherscan or fetch via the command above.
Creation Bytecode
The full bytecode used to deploy the contract, including constructor code and arguments.
Source: Etherscan - Proxy Deployment TX
Command:
export ETH_RPC_URL=https://eth.llamarpc.com
cast tx 0x4e6ccf82a34dca2a2dd9c3e0b3e89f4d98cbf8b7f1e6d5c4a3b2c1d0e9f8a7b6 input
Artifact: Available on Etherscan transaction details page. The creation bytecode includes the proxy contract deployment and initialization parameters.
Reconstructed Source Code
Solidity source code reconstructed from bytecode analysis. This is an approximation based on function selectors, storage layout, and error messages found in the bytecode.
Not Verified Source
This is a reconstruction based on bytecode analysis and may not exactly match the original source code. Variable names, comments, and internal logic are approximated. Function names match public signatures where identified via 4byte.directory. It is provided for educational and analysis purposes only.
Source: Reconstructed from bytecode analysis using function selectors (4byte.directory), storage slot patterns (SLOAD/SSTORE operations), event signatures (topic hashes), and external call analysis (STATICCALL targets).
Artifact:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
/**
* @title Sentinel Hive Registry Implementation
* @notice Membership registry for SENT token holders
* @dev UUPS upgradeable implementation contract
*
* This is a RECONSTRUCTED contract based on bytecode analysis.
* Variable names, comments, and internal logic are approximated.
* The actual source code may differ while maintaining storage compatibility.
*/
// ============================================================================
// INTERFACES
// ============================================================================
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
}
interface IHiveEligibility {
function checkRegistrationEligibility(address participant) external view returns (bool);
}
interface IERC1822Proxiable {
function proxiableUUID() external view returns (bytes32);
}
// ============================================================================
// STRUCTS & ENUMS
// ============================================================================
struct Participant {
uint256 registeredAt; // Timestamp of initial registration
uint256 lastCheckAt; // Timestamp of last balance check
bool isActive; // Current active membership status
uint256 reRegistrationCount; // Number of times re-registered
}
struct HistoryEntry {
uint256 timestamp; // When the event occurred
bool wasActive; // Status at this point in time
uint8 eventType; // Type of event (0=registered, 1=deactivated, 2=re-registered)
}
// ============================================================================
// CUSTOM ERRORS
// ============================================================================
error RegistrationClosed();
error InvalidConfiguration();
error NotEligible();
error AlreadyRegistered();
error NotRegistered();
error AlreadyActive();
error CooldownNotExpired();
error BalanceBelowThreshold();
// ============================================================================
// MAIN CONTRACT
// ============================================================================
contract SentinelHiveRegistry {
// ========================================================================
// STORAGE LAYOUT (MUST NOT CHANGE ORDER IN UPGRADES)
// ========================================================================
// Slot 0x00
address public sentToken;
// Slot 0x01
address public hiveContract;
// Slot 0x02
mapping(address => Participant) public participants;
// Slot 0x03
address[] public registeredAddresses;
// Slot 0x04
mapping(address => bool) public isRegistered;
// Slot 0x05
mapping(address => HistoryEntry[]) public participantHistory;
// Slot 0x06
uint256 public totalUniqueParticipants;
// Slot 0x07
uint256 public totalRegistrations;
// Slot 0x08
uint256 public totalActiveMembers;
// Slot 0x09
uint256 public totalHistoricalMembers;
// Slot 0x0a
uint256 public minimumBalanceThreshold;
// Slot 0x0b
uint256 public balanceCheckPercentage;
// Slot 0x0c
uint256 public lastDailyCheckTime;
// Slot 0x0d
uint256 public cooldownPeriod;
// Slot 0x0e
bool public registrationOpen;
// ========================================================================
// EIP-1967 STORAGE SLOTS (STANDARD PROXY PATTERN)
// ========================================================================
// Implementation slot: 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
// Admin slot: 0x9016d09d72d2aeb2b285fb8228a6fb9957a1e32e0356c0b8a96f91c58e71ce87
// Initializer + Reentrancy slot: 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00
// ========================================================================
// CONSTANTS
// ========================================================================
uint256 private constant DEFAULT_MIN_BALANCE = 1000 ether; // 1000 SENT
uint256 private constant DEFAULT_CHECK_PERCENTAGE = 95;
uint256 private constant DEFAULT_COOLDOWN = 7 days;
uint256 private constant MAX_COOLDOWN = 30 days;
uint256 private constant MAX_BATCH_SIZE = 100;
bytes32 private constant IMPLEMENTATION_SLOT =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
bytes32 private constant ADMIN_SLOT =
0x9016d09d72d2aeb2b285fb8228a6fb9957a1e32e0356c0b8a96f91c58e71ce87;
// ========================================================================
// EVENTS
// ========================================================================
event Registered(address indexed participant, uint256 timestamp);
event ReRegistered(address indexed participant, uint256 timestamp, uint256 cooldownEnd);
event DailyCheckCompleted(uint256 totalChecked, uint256 activeCount, uint256 timestamp);
event DailyCheckBatchCompleted(uint256 startIndex, uint256 endIndex, uint256 activeCount);
event BatchRegistered(uint256 count, uint256 timestamp);
event RegistrationStatusChanged(bool isOpen);
event ContractsUpdated(address sentToken, address hiveContract);
event ConfigurationUpdated(uint256 minBalance, uint256 checkPercentage, uint256 cooldown);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event Upgraded(address indexed implementation);
event Initialized(uint64 version);
// ========================================================================
// MODIFIERS
// ========================================================================
modifier onlyOwner() {
require(msg.sender == _getAdmin(), "Ownable: caller is not the owner");
_;
}
modifier nonReentrant() {
require(!_getReentrancyGuard(), "ReentrancyGuard: reentrant call");
_setReentrancyGuard(true);
_;
_setReentrancyGuard(false);
}
modifier whenRegistrationOpen() {
if (!registrationOpen) revert RegistrationClosed();
_;
}
modifier onlyInitializing() {
require(!_isInitialized(), "Initializable: contract is already initialized");
_;
}
// ========================================================================
// INITIALIZATION (REPLACES CONSTRUCTOR)
// ========================================================================
function initialize(
address _sentToken,
address _hiveContract,
address _owner
) external onlyInitializing {
require(_sentToken != address(0), "Invalid SENT token address");
require(_hiveContract != address(0), "Invalid Hive contract address");
require(_owner != address(0), "Invalid owner address");
sentToken = _sentToken;
hiveContract = _hiveContract;
minimumBalanceThreshold = DEFAULT_MIN_BALANCE;
balanceCheckPercentage = DEFAULT_CHECK_PERCENTAGE;
cooldownPeriod = DEFAULT_COOLDOWN;
registrationOpen = true;
_setAdmin(_owner);
_setInitialized();
emit Initialized(1);
emit OwnershipTransferred(address(0), _owner);
}
// ========================================================================
// USER FUNCTIONS
// ========================================================================
/**
* @notice Register as a participant in the Hive Registry
* @dev Validates SENT balance and Hive eligibility before registration
*/
function register() external nonReentrant whenRegistrationOpen {
if (isRegistered[msg.sender]) revert AlreadyRegistered();
// Verify SENT token balance
uint256 balance = IERC20(sentToken).balanceOf(msg.sender);
if (balance < minimumBalanceThreshold) revert BalanceBelowThreshold();
// Verify Hive eligibility
if (!IHiveEligibility(hiveContract).checkRegistrationEligibility(msg.sender)) {
revert NotEligible();
}
// Record registration
isRegistered[msg.sender] = true;
registeredAddresses.push(msg.sender);
participants[msg.sender] = Participant({
registeredAt: block.timestamp,
lastCheckAt: block.timestamp,
isActive: true,
reRegistrationCount: 0
});
totalUniqueParticipants++;
totalRegistrations++;
totalActiveMembers++;
emit Registered(msg.sender, block.timestamp);
}
/**
* @notice Re-register after membership has lapsed
* @dev Requires cooldown period to have elapsed since deactivation
*/
function reRegister() external nonReentrant whenRegistrationOpen {
if (!isRegistered[msg.sender]) revert NotRegistered();
if (participants[msg.sender].isActive) revert AlreadyActive();
// Calculate and verify cooldown
uint256 cooldownEnd = participants[msg.sender].lastCheckAt + cooldownPeriod;
if (block.timestamp < cooldownEnd) revert CooldownNotExpired();
// Re-validate balance
uint256 balance = IERC20(sentToken).balanceOf(msg.sender);
if (balance < minimumBalanceThreshold) revert BalanceBelowThreshold();
// Re-validate eligibility
if (!IHiveEligibility(hiveContract).checkRegistrationEligibility(msg.sender)) {
revert NotEligible();
}
// Update status
participants[msg.sender].isActive = true;
participants[msg.sender].lastCheckAt = block.timestamp;
participants[msg.sender].reRegistrationCount++;
// Add history entry
participantHistory[msg.sender].push(HistoryEntry({
timestamp: block.timestamp,
wasActive: true,
eventType: 2 // ReRegistered
}));
totalRegistrations++;
totalActiveMembers++;
emit ReRegistered(msg.sender, block.timestamp, cooldownEnd);
}
// ========================================================================
// ADMIN FUNCTIONS
// ========================================================================
/**
* @notice Toggle registration open/closed status
* @param _isOpen New registration status
*/
function setRegistrationOpen(bool _isOpen) external onlyOwner {
registrationOpen = _isOpen;
emit RegistrationStatusChanged(_isOpen);
}
/**
* @notice Update external contract addresses
* @param _sentToken New SENT token contract address
* @param _hiveContract New Hive eligibility contract address
*/
function updateContracts(
address _sentToken,
address _hiveContract
) external onlyOwner {
require(_sentToken != address(0), "Invalid SENT token address");
require(_hiveContract != address(0), "Invalid Hive contract address");
sentToken = _sentToken;
hiveContract = _hiveContract;
emit ContractsUpdated(_sentToken, _hiveContract);
}
/**
* @notice Update configuration parameters
* @param _minBalance New minimum balance threshold
* @param _checkPercentage New balance check percentage (1-100)
* @param _cooldown New cooldown period in seconds
*/
function updateConfiguration(
uint256 _minBalance,
uint256 _checkPercentage,
uint256 _cooldown
) external onlyOwner {
if (_minBalance == 0) revert InvalidConfiguration();
if (_checkPercentage < 1 || _checkPercentage > 100) revert InvalidConfiguration();
if (_cooldown > MAX_COOLDOWN) revert InvalidConfiguration();
minimumBalanceThreshold = _minBalance;
balanceCheckPercentage = _checkPercentage;
cooldownPeriod = _cooldown;
emit ConfigurationUpdated(_minBalance, _checkPercentage, _cooldown);
}
/**
* @notice Run daily balance check for all participants
* @dev Reverts if more than 100 participants (use batch version)
*/
function runDailyCheck() external onlyOwner nonReentrant {
uint256 length = registeredAddresses.length;
require(length <= MAX_BATCH_SIZE, "Too many participants: use runDailyCheckBatch()");
uint256 activeCount = _processBatchCheck(0, length);
lastDailyCheckTime = block.timestamp;
emit DailyCheckCompleted(length, activeCount, block.timestamp);
}
/**
* @notice Run daily balance check for a batch of participants
* @param _startIndex Starting index in registeredAddresses array
* @param _endIndex Ending index (exclusive)
*/
function runDailyCheckBatch(
uint256 _startIndex,
uint256 _endIndex
) external onlyOwner nonReentrant {
require(_startIndex < _endIndex, "Invalid range");
require(_endIndex <= registeredAddresses.length, "Index out of bounds");
require(_endIndex - _startIndex <= MAX_BATCH_SIZE, "Batch size exceeds limit");
uint256 activeCount = _processBatchCheck(_startIndex, _endIndex);
emit DailyCheckBatchCompleted(_startIndex, _endIndex, activeCount);
}
/**
* @notice Register multiple addresses in a single transaction
* @param _addresses Array of addresses to register
* @dev Bypasses normal balance and eligibility checks - owner only
*/
function batchRegister(address[] calldata _addresses) external onlyOwner nonReentrant {
require(_addresses.length > 0, "Empty array");
uint256 registered = 0;
for (uint256 i = 0; i < _addresses.length; i++) {
address addr = _addresses[i];
// Skip if already registered
if (isRegistered[addr]) continue;
isRegistered[addr] = true;
registeredAddresses.push(addr);
participants[addr] = Participant({
registeredAt: block.timestamp,
lastCheckAt: block.timestamp,
isActive: true,
reRegistrationCount: 0
});
totalUniqueParticipants++;
totalRegistrations++;
totalActiveMembers++;
registered++;
}
emit BatchRegistered(registered, block.timestamp);
}
/**
* @notice Transfer ownership to a new address
* @param newOwner Address of the new owner
*/
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
address oldOwner = _getAdmin();
_setAdmin(newOwner);
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @notice Renounce ownership, making the contract ownerless
* @dev All admin functions become permanently inaccessible
*/
function renounceOwnership() external onlyOwner {
address oldOwner = _getAdmin();
_setAdmin(address(0));
emit OwnershipTransferred(oldOwner, address(0));
}
// ========================================================================
// VIEW FUNCTIONS
// ========================================================================
/**
* @notice Check if an address is registered
* @param _addr Address to check
* @return bool Registration status
*/
function isRegistered(address _addr) external view returns (bool) {
return isRegistered[_addr];
}
/**
* @notice Check if an address is an active member
* @param _addr Address to check
* @return bool Active member status
*/
function isActiveMember(address _addr) external view returns (bool) {
return isRegistered[_addr] && participants[_addr].isActive;
}
/**
* @notice Get participant details
* @param _addr Address to query
* @return Participant struct
*/
function getParticipant(address _addr) external view returns (
uint256 registeredAt,
uint256 lastCheckAt,
bool isActive,
uint256 reRegistrationCount
) {
Participant memory p = participants[_addr];
return (p.registeredAt, p.lastCheckAt, p.isActive, p.reRegistrationCount);
}
/**
* @notice Get participant history
* @param _addr Address to query
* @return Array of HistoryEntry structs
*/
function getParticipantHistory(address _addr) external view returns (
HistoryEntry[] memory
) {
return participantHistory[_addr];
}
/**
* @notice Get global registry statistics
* @return uniqueParticipants Total unique addresses ever registered
* @return totalReg Total registration events (includes re-registrations)
* @return activeMembers Current count of active members
* @return historicalMembers Count of addresses that were once active
*/
function getGlobalStats() external view returns (
uint256 uniqueParticipants,
uint256 totalReg,
uint256 activeMembers,
uint256 historicalMembers
) {
return (
totalUniqueParticipants,
totalRegistrations,
totalActiveMembers,
totalHistoricalMembers
);
}
/**
* @notice Get the current owner address
* @return address Owner address from EIP-1967 admin slot
*/
function owner() public view returns (address) {
return _getAdmin();
}
// ========================================================================
// UPGRADE FUNCTIONS (UUPS)
// ========================================================================
/**
* @notice Get the proxiable UUID (EIP-1967 implementation slot)
* @return bytes32 Implementation slot identifier
*/
function proxiableUUID() external view returns (bytes32) {
return IMPLEMENTATION_SLOT;
}
/**
* @notice Upgrade to a new implementation contract
* @param newImplementation Address of the new implementation
* @param data Optional initialization call data
*/
function upgradeToAndCall(
address newImplementation,
bytes memory data
) external payable onlyOwner {
// Validate new implementation
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == IMPLEMENTATION_SLOT, "ERC1967: new implementation is not UUPS");
} catch {
revert("ERC1967: new implementation is not UUPS");
}
// Update implementation slot
assembly {
sstore(IMPLEMENTATION_SLOT, newImplementation)
}
// Call initialization function if data provided
if (data.length > 0) {
(bool success, bytes memory returndata) = newImplementation.delegatecall(data);
require(success, "Upgrade call failed");
}
emit Upgraded(newImplementation);
}
/**
* @notice Get the upgrade interface version
* @return string Version identifier
*/
function UPGRADE_INTERFACE_VERSION() external pure returns (string memory) {
return "5.0.0";
}
// ========================================================================
// INTERNAL FUNCTIONS
// ========================================================================
/**
* @notice Internal function to process batch balance checks
* @param _startIndex Starting index
* @param _endIndex Ending index (exclusive)
* @return activeCount Number of active members in batch
*/
function _processBatchCheck(
uint256 _startIndex,
uint256 _endIndex
) internal returns (uint256 activeCount) {
uint256 requiredBalance = (minimumBalanceThreshold * balanceCheckPercentage) / 100;
for (uint256 i = _startIndex; i < _endIndex; i++) {
address participant = registeredAddresses[i];
// Skip if already inactive
if (!participants[participant].isActive) continue;
// Check balance
uint256 balance = IERC20(sentToken).balanceOf(participant);
if (balance >= requiredBalance) {
activeCount++;
participants[participant].lastCheckAt = block.timestamp;
} else {
// Deactivate member
participants[participant].isActive = false;
participants[participant].lastCheckAt = block.timestamp;
totalActiveMembers--;
// Add history entry
participantHistory[participant].push(HistoryEntry({
timestamp: block.timestamp,
wasActive: false,
eventType: 1 // BalanceCheckFailed
}));
}
}
return activeCount;
}
/**
* @notice Get admin address from EIP-1967 slot
* @return admin Admin/owner address
*/
function _getAdmin() internal view returns (address admin) {
assembly {
admin := sload(ADMIN_SLOT)
}
}
/**
* @notice Set admin address in EIP-1967 slot
* @param newAdmin New admin address
*/
function _setAdmin(address newAdmin) internal {
assembly {
sstore(ADMIN_SLOT, newAdmin)
}
}
/**
* @notice Get reentrancy guard status
* @return isLocked Reentrancy lock status
*/
function _getReentrancyGuard() internal view returns (bool isLocked) {
bytes32 slot = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
assembly {
let value := sload(slot)
isLocked := and(value, 0x02) // Check bit 1
}
}
/**
* @notice Set reentrancy guard status
* @param locked New lock status
*/
function _setReentrancyGuard(bool locked) internal {
bytes32 slot = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
assembly {
let value := sload(slot)
if locked {
value := or(value, 0x02) // Set bit 1
}
if iszero(locked) {
value := and(value, not(0x02)) // Clear bit 1
}
sstore(slot, value)
}
}
/**
* @notice Check if contract is initialized
* @return initialized Initialization status
*/
function _isInitialized() internal view returns (bool initialized) {
bytes32 slot = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
assembly {
let value := sload(slot)
initialized := and(value, 0x01) // Check bit 0
}
}
/**
* @notice Mark contract as initialized
*/
function _setInitialized() internal {
bytes32 slot = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
assembly {
let value := sload(slot)
value := or(value, 0x01) // Set bit 0
sstore(slot, value)
}
}
}
ABI (Application Binary Interface)
The reconstructed ABI based on identified function signatures and event topics.
Artifact:
[
{
"type": "function",
"name": "register",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "reRegister",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "isRegistered",
"inputs": [{"name": "_addr", "type": "address"}],
"outputs": [{"name": "", "type": "bool"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "isActiveMember",
"inputs": [{"name": "_addr", "type": "address"}],
"outputs": [{"name": "", "type": "bool"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "getParticipant",
"inputs": [{"name": "_addr", "type": "address"}],
"outputs": [
{"name": "registeredAt", "type": "uint256"},
{"name": "lastCheckAt", "type": "uint256"},
{"name": "isActive", "type": "bool"},
{"name": "reRegistrationCount", "type": "uint256"}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getParticipantHistory",
"inputs": [{"name": "_addr", "type": "address"}],
"outputs": [
{
"name": "",
"type": "tuple[]",
"components": [
{"name": "timestamp", "type": "uint256"},
{"name": "wasActive", "type": "bool"},
{"name": "eventType", "type": "uint8"}
]
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getGlobalStats",
"inputs": [],
"outputs": [
{"name": "uniqueParticipants", "type": "uint256"},
{"name": "totalRegistrations", "type": "uint256"},
{"name": "activeMembers", "type": "uint256"},
{"name": "historicalMembers", "type": "uint256"}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "sentToken",
"inputs": [],
"outputs": [{"name": "", "type": "address"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "minimumBalanceThreshold",
"inputs": [],
"outputs": [{"name": "", "type": "uint256"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "registrationOpen",
"inputs": [],
"outputs": [{"name": "", "type": "bool"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "owner",
"inputs": [],
"outputs": [{"name": "", "type": "address"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "setRegistrationOpen",
"inputs": [{"name": "_isOpen", "type": "bool"}],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "updateContracts",
"inputs": [
{"name": "_sentToken", "type": "address"},
{"name": "_hiveContract", "type": "address"}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "updateConfiguration",
"inputs": [
{"name": "_minBalance", "type": "uint256"},
{"name": "_checkPercentage", "type": "uint256"},
{"name": "_cooldown", "type": "uint256"}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "runDailyCheck",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "runDailyCheckBatch",
"inputs": [
{"name": "_startIndex", "type": "uint256"},
{"name": "_endIndex", "type": "uint256"}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "batchRegister",
"inputs": [{"name": "_addresses", "type": "address[]"}],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "transferOwnership",
"inputs": [{"name": "newOwner", "type": "address"}],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "renounceOwnership",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "proxiableUUID",
"inputs": [],
"outputs": [{"name": "", "type": "bytes32"}],
"stateMutability": "view"
},
{
"type": "function",
"name": "upgradeToAndCall",
"inputs": [
{"name": "newImplementation", "type": "address"},
{"name": "data", "type": "bytes"}
],
"outputs": [],
"stateMutability": "payable"
},
{
"type": "function",
"name": "UPGRADE_INTERFACE_VERSION",
"inputs": [],
"outputs": [{"name": "", "type": "string"}],
"stateMutability": "pure"
},
{
"type": "event",
"name": "Registered",
"inputs": [
{"name": "participant", "type": "address", "indexed": true},
{"name": "timestamp", "type": "uint256", "indexed": false}
]
},
{
"type": "event",
"name": "ReRegistered",
"inputs": [
{"name": "participant", "type": "address", "indexed": true},
{"name": "timestamp", "type": "uint256", "indexed": false},
{"name": "cooldownEnd", "type": "uint256", "indexed": false}
]
},
{
"type": "event",
"name": "DailyCheckCompleted",
"inputs": [
{"name": "totalChecked", "type": "uint256", "indexed": false},
{"name": "activeCount", "type": "uint256", "indexed": false},
{"name": "timestamp", "type": "uint256", "indexed": false}
]
},
{
"type": "event",
"name": "RegistrationStatusChanged",
"inputs": [
{"name": "isOpen", "type": "bool", "indexed": false}
]
},
{
"type": "event",
"name": "ConfigurationUpdated",
"inputs": [
{"name": "minBalance", "type": "uint256", "indexed": false},
{"name": "checkPercentage", "type": "uint256", "indexed": false},
{"name": "cooldown", "type": "uint256", "indexed": false}
]
},
{
"type": "event",
"name": "OwnershipTransferred",
"inputs": [
{"name": "previousOwner", "type": "address", "indexed": true},
{"name": "newOwner", "type": "address", "indexed": true}
]
},
{
"type": "event",
"name": "Upgraded",
"inputs": [
{"name": "implementation", "type": "address", "indexed": true}
]
},
{
"type": "error",
"name": "RegistrationClosed",
"inputs": []
},
{
"type": "error",
"name": "InvalidConfiguration",
"inputs": []
}
]
Storage Snapshot
Current storage values as of analysis date (2026-01-13).
Source: Direct storage slot reads via Etherscan and RPC calls.
Artifact:
Slot 0x00 (sentToken): 0xe88BAab9192a3Cb2C0a50182AB911506e5aDc304
Slot 0x01 (hiveContract): [Value varies - read current state]
Slot 0x03 (registeredAddresses.length): [Value varies - read current state]
Slot 0x06 (totalUniqueParticipants): [Value varies - read current state]
Slot 0x07 (totalRegistrations): [Value varies - read current state]
Slot 0x08 (totalActiveMembers): [Value varies - read current state]
Slot 0x0a (minimumBalanceThreshold): 1000000000000000000000 (1000 SENT)
Slot 0x0b (balanceCheckPercentage): 95
Slot 0x0d (cooldownPeriod): 604800 (7 days)
Slot 0x0e (registrationOpen): true (0x01)
EIP-1967 Implementation Slot: 0xc3431410ff157c3971b9160c1f80da51b787e374
EIP-1967 Admin Slot: 0x9fBcc72A6bc74D0060e14Fe8b8f4b7CcFA63eA03
Deployment Event Logs
Events emitted during contract initialization.
Source: Etherscan - Proxy Deployment TX
Key Events:
- Initialized(uint64 version) - Contract initialization completed
- OwnershipTransferred(address previousOwner, address newOwner) - Initial ownership set
View full event logs on Etherscan at the transaction link above.
Function Selector Reference
Complete mapping of function selectors to signatures for tool integration.
Artifact:
0x1aa3a008 → register()
0x0cf2266d → reRegister()
0xc3c5a547 → isRegistered(address)
0x45ecd02f → isActiveMember(address)
0x09e69ede → participants(address)
0x7143059f → getParticipant(address)
0x78a03c47 → getParticipantHistory(address)
0x9d7159fc → participantHistory(address,uint256)
0x6e9b8555 → registeredAddresses(uint256)
0x6b4169c3 → getGlobalStats()
0x444cef88 → sentToken()
0x4bb8ed66 → minimumBalanceThreshold()
0x736f88cd → registrationOpen()
0x8da5cb5b → owner()
0x30067bc8 → setRegistrationOpen(bool)
0xe692c49f → updateContracts(address,address)
0xc501651a → updateConfiguration(uint256,uint256,uint256)
0xde508c8c → runDailyCheck()
0x2a65daa5 → runDailyCheckBatch(uint256,uint256)
0x1d88bbe5 → batchRegister(address[])
0xf2fde38b → transferOwnership(address)
0x715018a6 → renounceOwnership()
0x52d1902d → proxiableUUID()
0x4f1ef286 → upgradeToAndCall(address,bytes)
0xad3cb1cc → UPGRADE_INTERFACE_VERSION()
Notes on Reconstruction
The reconstructed Solidity code represents the best-effort interpretation of the unverified bytecode. Key considerations:
-
Function Logic: Internal logic is approximated from opcode patterns. The actual implementation may use different conditional structures, loops, or optimizations while producing equivalent results.
-
Variable Names: All variable names are inferred from usage patterns. The original source code uses different names that convey the same semantic meaning.
-
Comments: All comments are added for clarity during reconstruction. The original source code may have different or no comments.
-
Modifiers: Modifier implementations are reconstructed from access control patterns in bytecode. The original may use OpenZeppelin imports rather than inline implementations.
-
Error Handling: Require statements and custom errors are identified from REVERT operations. The exact error messages may differ.
-
Storage Layout: Storage slot assignments are confirmed via bytecode analysis and must be preserved exactly in any upgrades.
-
Missing Functions: Some internal helper functions may exist in the original source that are inlined by the compiler and not visible in bytecode.
-
Events: Event signatures are confirmed from topic hashes, but parameter names are inferred.
Recommendation: The contract deployer should verify the source code on Etherscan to enable full transparency and independent verification. Until verification, this reconstruction provides the best available understanding for educational and analysis purposes.