Skip to content

Functions

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

Function Selectors

SELECTOR FUNCTION SIGNATURE CATEGORY
0x1aa3a008 register() User
0x0cf2266d reRegister() User
0xc3c5a547 isRegistered(address) View
0x45ecd02f isActiveMember(address) View
0x09e69ede participants(address) View
0x7143059f getParticipant(address) View
0x78a03c47 getParticipantHistory(address) View
0x9d7159fc participantHistory(address,uint256) View
0x6e9b8555 registeredAddresses(uint256) View
0x6b4169c3 getGlobalStats() View
0x444cef88 sentToken() View
0x4bb8ed66 minimumBalanceThreshold() View
0x736f88cd registrationOpen() View
0x8da5cb5b owner() View
0x30067bc8 setRegistrationOpen(bool) Admin
0xe692c49f updateContracts(address,address) Admin
0xc501651a updateConfiguration(uint256,uint256,uint256) Admin
0xde508c8c runDailyCheck() Admin
0x2a65daa5 runDailyCheckBatch(uint256,uint256) Admin
0x1d88bbe5 batchRegister(address[]) Admin
0xf2fde38b transferOwnership(address) Admin
0x715018a6 renounceOwnership() Admin
0x52d1902d proxiableUUID() Upgrade
0x4f1ef286 upgradeToAndCall(address,bytes) Upgrade
0xad3cb1cc UPGRADE_INTERFACE_VERSION() View

Summary

CATEGORY NUM FUNCTIONS
Total Functions 25
User Functions 2
Admin Functions 7
View Functions 14
Upgrade Functions 2

User Functions

Function: register()

Registers the caller as a participant in the Hive Registry if they meet balance and eligibility requirements.

ATTRIBUTE VALUE
Selector 0x1aa3a008
Parameters None
Access Public, requires registration to be open
Modifiers nonReentrant, whenRegistrationOpen
FLAG OBSERVATION
Validates SENT token balance before registration
Checks Hive contract eligibility via external call
Reverts if registration is closed (owner-controlled)
External calls to SENT and Hive contracts could fail
Emits Registered event on success
CONDITION REQUIREMENT
Registration Open registrationOpen == true
Not Already Registered isRegistered[msg.sender] == false
Sufficient Balance SENT.balanceOf(msg.sender) >= minimumBalanceThreshold
Hive Eligible hiveContract.checkRegistrationEligibility(msg.sender) == true
graph TD
    Start([User calls register]) --> CheckOpen{Registration<br/>Open?}
    CheckOpen -->|No| RevertClosed[Revert: RegistrationClosed]
    CheckOpen -->|Yes| CheckReg{Already<br/>Registered?}
    CheckReg -->|Yes| RevertDupe[Revert: Already registered]
    CheckReg -->|No| CheckBalance{Balance >=<br/>Minimum?}
    CheckBalance -->|No| RevertBalance[Revert: Balance below threshold]
    CheckBalance -->|Yes| CheckHive{Hive<br/>Eligible?}
    CheckHive -->|No| RevertEligible[Revert: Not eligible]
    CheckHive -->|Yes| Register[Record registration]
    Register --> EmitEvent[Emit Registered event]
    EmitEvent --> Success([Return success])
STEP ACTION
1 Verify registration is open
2 Check caller is not already registered
3 Call SENT token contract to verify balance >= minimum threshold
4 Call Hive contract to verify eligibility
5 Set isRegistered[msg.sender] = true
6 Add address to registeredAddresses array
7 Create participant record with timestamp and active status
8 Increment totalUniqueParticipants
9 Increment totalRegistrations
10 Increment totalActiveMembers
11 Emit Registered(msg.sender, block.timestamp) event
VARIABLE CHANGE
isRegistered[msg.sender] falsetrue
registeredAddresses Append msg.sender
participants[msg.sender] Create new struct with registration timestamp
totalUniqueParticipants Increment by 1
totalRegistrations Increment by 1
totalActiveMembers Increment by 1
CONDITION REVERT MESSAGE
registrationOpen == false "RegistrationClosed" (custom error 0x2fc209f3)
isRegistered[msg.sender] == true "Already registered"
SENT.balanceOf(msg.sender) < minimumBalanceThreshold "Balance below threshold"
hiveContract.checkRegistrationEligibility(msg.sender) == false "Not eligible"
SENT token call fails Propagate external error
Hive contract call fails Propagate external error
function register() external nonReentrant whenRegistrationOpen {
    require(!isRegistered[msg.sender], "Already registered");

    // Check SENT token balance
    uint256 balance = IERC20(sentToken).balanceOf(msg.sender);
    require(balance >= minimumBalanceThreshold, "Balance below threshold");

    // Check Hive eligibility
    require(
        IHive(hiveContract).checkRegistrationEligibility(msg.sender),
        "Not eligible"
    );

    // 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);
}

Function: reRegister()

Allows a previously registered participant to re-register after their membership has lapsed and the cooldown period has expired.

ATTRIBUTE VALUE
Selector 0x0cf2266d
Parameters None
Access Public, requires registration to be open
Modifiers nonReentrant, whenRegistrationOpen
FLAG OBSERVATION
Requires cooldown period to have elapsed since membership lapse
Re-validates SENT balance and Hive eligibility
Preserves historical participation data
Cooldown period controlled by owner (default 7 days)
CONDITION REQUIREMENT
Registration Open registrationOpen == true
Already Registered isRegistered[msg.sender] == true
Currently Inactive participants[msg.sender].isActive == false
Cooldown Expired block.timestamp >= cooldownEndTime
Sufficient Balance SENT.balanceOf(msg.sender) >= minimumBalanceThreshold
Hive Eligible hiveContract.checkRegistrationEligibility(msg.sender) == true
STEP ACTION
1 Verify registration is open
2 Check caller is already registered but inactive
3 Verify cooldown period has expired
4 Call SENT token contract to verify balance >= minimum threshold
5 Call Hive contract to verify eligibility
6 Update participant record: set active = true, update timestamp
7 Increment reRegistrationCount for this address
8 Add history entry to participantHistory mapping
9 Increment totalRegistrations
10 Increment totalActiveMembers
11 Emit ReRegistered(msg.sender, block.timestamp, cooldownEnd) event
VARIABLE CHANGE
participants[msg.sender].isActive falsetrue
participants[msg.sender].lastCheckAt Update to block.timestamp
participants[msg.sender].reRegistrationCount Increment by 1
participantHistory[msg.sender] Append new history entry
totalRegistrations Increment by 1
totalActiveMembers Increment by 1
CONDITION REVERT MESSAGE
registrationOpen == false "RegistrationClosed"
isRegistered[msg.sender] == false "Not registered"
participants[msg.sender].isActive == true "Already active"
block.timestamp < cooldownEndTime "Cooldown period not expired"
SENT.balanceOf(msg.sender) < minimumBalanceThreshold "Balance below threshold"
hiveContract.checkRegistrationEligibility(msg.sender) == false "Not eligible"
function reRegister() external nonReentrant whenRegistrationOpen {
    require(isRegistered[msg.sender], "Not registered");
    require(!participants[msg.sender].isActive, "Already active");

    // Calculate cooldown end time
    uint256 cooldownEnd = participants[msg.sender].lastCheckAt + cooldownPeriod;
    require(block.timestamp >= cooldownEnd, "Cooldown period not expired");

    // Re-validate balance
    uint256 balance = IERC20(sentToken).balanceOf(msg.sender);
    require(balance >= minimumBalanceThreshold, "Balance below threshold");

    // Re-validate Hive eligibility
    require(
        IHive(hiveContract).checkRegistrationEligibility(msg.sender),
        "Not eligible"
    );

    // Update participant 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: EventType.ReRegistered
    }));

    totalRegistrations++;
    totalActiveMembers++;

    emit ReRegistered(msg.sender, block.timestamp, cooldownEnd);
}

Admin Functions

Function: setRegistrationOpen(bool)

Toggles whether new registrations and re-registrations are permitted. Owner-only control.

ATTRIBUTE VALUE
Selector 0x30067bc8
Parameters bool _isOpen
Access Owner only
Modifiers onlyOwner
FLAG OBSERVATION
Owner can disable registration at any time
No time lock or warning period
Emits event for transparency
STEP ACTION
1 Verify caller is owner
2 Update registrationOpen flag
3 Emit RegistrationStatusChanged(_isOpen) event
VARIABLE CHANGE
registrationOpen Update to _isOpen value
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
function setRegistrationOpen(bool _isOpen) external onlyOwner {
    registrationOpen = _isOpen;
    emit RegistrationStatusChanged(_isOpen);
}

Function: updateContracts(address,address)

Updates the external contract addresses for SENT token and Hive eligibility verification. Owner-only control.

ATTRIBUTE VALUE
Selector 0xe692c49f
Parameters address _sentToken, address _hiveContract
Access Owner only
Modifiers onlyOwner
FLAG OBSERVATION
Owner can swap dependencies at any time
No validation that addresses are contracts
No time lock or migration period
Changing contracts could break existing registrations
CONDITION REQUIREMENT
Valid Addresses Both addresses should be non-zero (likely validated)
STEP ACTION
1 Verify caller is owner
2 Validate addresses are non-zero
3 Update sentToken storage slot
4 Update hiveContract storage slot
5 Emit ContractsUpdated(_sentToken, _hiveContract) event
VARIABLE CHANGE
sentToken Update to _sentToken address
hiveContract Update to _hiveContract address
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
_sentToken == address(0) "Invalid address" (likely)
_hiveContract == address(0) "Invalid address" (likely)
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);
}

Function: updateConfiguration(uint256,uint256,uint256)

Updates configuration parameters for minimum balance threshold, balance check percentage, and cooldown period. Owner-only control with bounds validation.

ATTRIBUTE VALUE
Selector 0xc501651a
Parameters uint256 _minBalance, uint256 _checkPercentage, uint256 _cooldown
Access Owner only
Modifiers onlyOwner
FLAG OBSERVATION
Validates percentage is between 1-100
Validates cooldown is not more than 30 days
Validates minimum balance is greater than zero
Owner can make eligibility more restrictive immediately
CONDITION REQUIREMENT
Minimum Balance _minBalance > 0
Check Percentage 1 <= _checkPercentage <= 100
Cooldown Period _cooldown <= 2592000 (30 days)
graph TD
    Start([Owner calls updateConfiguration]) --> CheckBalance{MinBalance<br/>> 0?}
    CheckBalance -->|No| RevertBalance[Revert: InvalidConfiguration]
    CheckBalance -->|Yes| CheckPct{Percentage<br/>1-100?}
    CheckPct -->|No| RevertPct[Revert: InvalidConfiguration]
    CheckPct -->|Yes| CheckCooldown{Cooldown<br/><= 30 days?}
    CheckCooldown -->|No| RevertCooldown[Revert: InvalidConfiguration]
    CheckCooldown -->|Yes| Update[Update configuration]
    Update --> EmitEvent[Emit ConfigurationUpdated]
    EmitEvent --> Success([Return success])
STEP ACTION
1 Verify caller is owner
2 Validate _minBalance > 0
3 Validate _checkPercentage between 1-100
4 Validate _cooldown <= 2592000 (30 days)
5 Update minimumBalanceThreshold
6 Update balanceCheckPercentage
7 Update cooldownPeriod
8 Emit ConfigurationUpdated(_minBalance, _checkPercentage, _cooldown) event
VARIABLE CHANGE
minimumBalanceThreshold Update to _minBalance
balanceCheckPercentage Update to _checkPercentage
cooldownPeriod Update to _cooldown
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
_minBalance == 0 "InvalidConfiguration" (custom error 0xc52a9bd3)
_checkPercentage < 1 or > 100 "InvalidConfiguration"
_cooldown > 2592000 "InvalidConfiguration"
function updateConfiguration(
    uint256 _minBalance,
    uint256 _checkPercentage,
    uint256 _cooldown
) external onlyOwner {
    if (_minBalance == 0) revert InvalidConfiguration();
    if (_checkPercentage < 1 || _checkPercentage > 100) revert InvalidConfiguration();
    if (_cooldown > 2592000) revert InvalidConfiguration(); // Max 30 days

    minimumBalanceThreshold = _minBalance;
    balanceCheckPercentage = _checkPercentage;
    cooldownPeriod = _cooldown;

    emit ConfigurationUpdated(_minBalance, _checkPercentage, _cooldown);
}

Function: runDailyCheck()

Iterates through all registered addresses to verify their SENT token balances still meet the threshold. Deactivates members who fall below the required balance. Owner-only control.

ATTRIBUTE VALUE
Selector 0xde508c8c
Parameters None
Access Owner only
Modifiers onlyOwner, nonReentrant
FLAG OBSERVATION
Reverts if more than 100 participants (must use batch version)
Gas cost scales linearly with participant count
Uses staticcall to read balances (no state changes in SENT contract)
Owner determines when checks run (not automated)
CONDITION REQUIREMENT
Participant Count registeredAddresses.length <= 100
STEP ACTION
1 Verify caller is owner
2 Check participant count <= 100
3 For each registered address:
3a Skip if already inactive
3b Read SENT balance via staticcall
3c Calculate required balance (threshold * checkPercentage / 100)
3d If balance < required: set isActive = false, decrement totalActiveMembers
3e Add history entry if status changed
4 Update lastDailyCheckTime to current timestamp
5 Emit DailyCheckCompleted(totalChecked, activeCount, timestamp) event
VARIABLE CHANGE
participants[addr].isActive May change to false for addresses below threshold
participants[addr].lastCheckAt Update to block.timestamp for checked addresses
totalActiveMembers Decrement for each deactivated member
participantHistory[addr] Append entry for status changes
lastDailyCheckTime Update to block.timestamp
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
registeredAddresses.length > 100 "Too many participants: use runDailyCheckBatch()"
SENT token call fails Propagate external error
function runDailyCheck() external onlyOwner nonReentrant {
    uint256 length = registeredAddresses.length;
    require(length <= 100, "Too many participants: use runDailyCheckBatch()");

    uint256 activeCount = 0;
    uint256 requiredBalance = (minimumBalanceThreshold * balanceCheckPercentage) / 100;

    for (uint256 i = 0; i < length; 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: EventType.BalanceCheckFailed
            }));
        }
    }

    lastDailyCheckTime = block.timestamp;
    emit DailyCheckCompleted(length, activeCount, block.timestamp);
}

Function: runDailyCheckBatch(uint256,uint256)

Batch version of daily check that processes a specified range of registered addresses. Enables processing of large registries without hitting gas limits. Owner-only control.

ATTRIBUTE VALUE
Selector 0x2a65daa5
Parameters uint256 _startIndex, uint256 _endIndex
Access Owner only
Modifiers onlyOwner, nonReentrant
FLAG OBSERVATION
Allows chunked processing to avoid gas limits
Batch size limited to 100 addresses per call
Requires owner to track progress across multiple transactions
Validates index bounds to prevent out-of-range errors
CONDITION REQUIREMENT
Valid Range _startIndex < _endIndex
Within Bounds _endIndex <= registeredAddresses.length
Batch Size _endIndex - _startIndex <= 100
STEP ACTION
1 Verify caller is owner
2 Validate _startIndex < _endIndex
3 Validate _endIndex <= array length
4 Validate batch size <= 100
5 For each address in range [_startIndex, _endIndex):
5a Skip if already inactive
5b Read SENT balance via staticcall
5c Calculate required balance
5d If balance < required: deactivate and record history
6 Update lastDailyCheckTime if this is the final batch
7 Emit DailyCheckBatchCompleted(startIndex, endIndex, activeCount) event
VARIABLE CHANGE
participants[addr].isActive May change to false for addresses in range
participants[addr].lastCheckAt Update for checked addresses
totalActiveMembers Decrement for deactivated members
participantHistory[addr] Append entries for status changes
lastDailyCheckTime Update if final batch
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
_startIndex >= _endIndex "Invalid range"
_endIndex > registeredAddresses.length "Index out of bounds"
_endIndex - _startIndex > 100 "Batch size exceeds limit"
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 <= 100, "Batch size exceeds limit");

    uint256 activeCount = 0;
    uint256 requiredBalance = (minimumBalanceThreshold * balanceCheckPercentage) / 100;

    for (uint256 i = _startIndex; i < _endIndex; i++) {
        address participant = registeredAddresses[i];

        if (!participants[participant].isActive) continue;

        uint256 balance = IERC20(sentToken).balanceOf(participant);

        if (balance >= requiredBalance) {
            activeCount++;
            participants[participant].lastCheckAt = block.timestamp;
        } else {
            participants[participant].isActive = false;
            participants[participant].lastCheckAt = block.timestamp;
            totalActiveMembers--;

            participantHistory[participant].push(HistoryEntry({
                timestamp: block.timestamp,
                wasActive: false,
                eventType: EventType.BalanceCheckFailed
            }));
        }
    }

    emit DailyCheckBatchCompleted(_startIndex, _endIndex, activeCount);
}

Function: batchRegister(address[])

Registers multiple addresses in a single transaction. Owner-only function likely used for initial setup or migration. Bypasses normal registration checks.

ATTRIBUTE VALUE
Selector 0x1d88bbe5
Parameters address[] _addresses
Access Owner only
Modifiers onlyOwner, nonReentrant
FLAG OBSERVATION
Owner can add addresses without balance or eligibility checks
Bypasses normal registration requirements
Could be used to add ineligible addresses
Batch size likely limited to avoid gas limits
CONDITION REQUIREMENT
Non-empty Array _addresses.length > 0
Valid Addresses All addresses should be non-zero
STEP ACTION
1 Verify caller is owner
2 For each address in array:
2a Skip if already registered
2b Set isRegistered = true
2c Add to registeredAddresses array
2d Create participant record
2e Increment counters
3 Emit BatchRegistered event with count
VARIABLE CHANGE
isRegistered[addr] Set to true for each address
registeredAddresses Append each new address
participants[addr] Create records for each address
totalUniqueParticipants Increment for each new registration
totalRegistrations Increment for each registration
totalActiveMembers Increment for each registration
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
_addresses.length == 0 "Empty array"
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);
}

Function: transferOwnership(address)

Transfers ownership of the contract to a new address. OpenZeppelin Ownable pattern implementation.

ATTRIBUTE VALUE
Selector 0xf2fde38b
Parameters address newOwner
Access Owner only
Modifiers onlyOwner
FLAG OBSERVATION
No time lock or two-step transfer process
Immediate ownership transfer
Validates new owner is not zero address
STEP ACTION
1 Verify caller is current owner
2 Validate newOwner != address(0)
3 Update owner address in EIP-1967 admin slot
4 Emit OwnershipTransferred(oldOwner, newOwner) event
VARIABLE CHANGE
owner (EIP-1967 slot 0x9016d09d...) Update to newOwner
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
newOwner == address(0) "Ownable: new owner is the zero address"
function transferOwnership(address newOwner) public virtual onlyOwner {
    require(newOwner != address(0), "Ownable: new owner is the zero address");
    _transferOwnership(newOwner);
}

function _transferOwnership(address newOwner) internal virtual {
    address oldOwner = owner();
    // Update owner in EIP-1967 admin slot
    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newOwner;
    emit OwnershipTransferred(oldOwner, newOwner);
}

Function: renounceOwnership()

Permanently removes ownership, making the contract ownerless. All owner-only functions become permanently inaccessible. OpenZeppelin Ownable pattern implementation.

ATTRIBUTE VALUE
Selector 0x715018a6
Parameters None
Access Owner only
Modifiers onlyOwner
FLAG OBSERVATION
Irreversible - contract becomes permanently locked
No upgrades possible after renouncement
No configuration changes possible after renouncement
No confirmation or time lock
STEP ACTION
1 Verify caller is current owner
2 Set owner to address(0)
3 Emit OwnershipTransferred(oldOwner, address(0)) event
VARIABLE CHANGE
owner (EIP-1967 slot) Set to address(0)
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
function renounceOwnership() public virtual onlyOwner {
    _transferOwnership(address(0));
}

View Functions

Function: isRegistered(address)

Returns whether an address has ever registered, regardless of current active status.

ATTRIBUTE VALUE
Selector 0xc3c5a547
Parameters address _addr
Access Public view
Returns bool
function isRegistered(address _addr) external view returns (bool) {
    return isRegistered[_addr];
}

Function: isActiveMember(address)

Returns whether an address is currently an active member (registered and passed recent balance checks).

ATTRIBUTE VALUE
Selector 0x45ecd02f
Parameters address _addr
Access Public view
Returns bool
function isActiveMember(address _addr) external view returns (bool) {
    return isRegistered[_addr] && participants[_addr].isActive;
}

Function: getParticipant(address)

Returns the full participant record for an address including registration timestamp, last check time, active status, and re-registration count.

ATTRIBUTE VALUE
Selector 0x7143059f
Parameters address _addr
Access Public view
Returns Participant memory
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);
}

Function: getParticipantHistory(address)

Returns the complete history array for a participant showing all status changes over time.

ATTRIBUTE VALUE
Selector 0x78a03c47
Parameters address _addr
Access Public view
Returns HistoryEntry[] memory
function getParticipantHistory(address _addr) external view returns (
    HistoryEntry[] memory
) {
    return participantHistory[_addr];
}

Function: getGlobalStats()

Returns global statistics about the registry including total unique participants, total registrations, active members, and historical member count.

ATTRIBUTE VALUE
Selector 0x6b4169c3
Parameters None
Access Public view
Returns (uint256, uint256, uint256, uint256)
function getGlobalStats() external view returns (
    uint256 uniqueParticipants,
    uint256 totalRegistrations,
    uint256 activeMembers,
    uint256 historicalMembers
) {
    return (
        totalUniqueParticipants,
        totalRegistrations,
        totalActiveMembers,
        totalHistoricalMembers
    );
}

Function: sentToken()

Returns the address of the SENT token contract used for balance verification.

ATTRIBUTE VALUE
Selector 0x444cef88
Parameters None
Access Public view
Returns address
function sentToken() external view returns (address) {
    return sentToken;
}

Function: minimumBalanceThreshold()

Returns the current minimum SENT token balance required for registration and active membership.

ATTRIBUTE VALUE
Selector 0x4bb8ed66
Parameters None
Access Public view
Returns uint256
function minimumBalanceThreshold() external view returns (uint256) {
    return minimumBalanceThreshold;
}

Function: registrationOpen()

Returns whether new registrations and re-registrations are currently permitted.

ATTRIBUTE VALUE
Selector 0x736f88cd
Parameters None
Access Public view
Returns bool
function registrationOpen() external view returns (bool) {
    return registrationOpen;
}

Function: owner()

Returns the current owner address from EIP-1967 admin slot. OpenZeppelin Ownable pattern implementation.

ATTRIBUTE VALUE
Selector 0x8da5cb5b
Parameters None
Access Public view
Returns address
function owner() public view virtual returns (address) {
    return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}

Upgrade Functions

Function: proxiableUUID()

Returns the EIP-1967 implementation slot identifier to verify UUPS compatibility. Part of ERC-1822 standard.

ATTRIBUTE VALUE
Selector 0x52d1902d
Parameters None
Access Public view
Returns bytes32
function proxiableUUID() external view returns (bytes32) {
    return 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
}

Function: upgradeToAndCall(address,bytes)

Upgrades the implementation contract to a new address and optionally calls a function on the new implementation. Owner-only control with no time lock.

ATTRIBUTE VALUE
Selector 0x4f1ef286
Parameters address newImplementation, bytes calldata data
Access Owner only
Modifiers onlyOwner
FLAG OBSERVATION
Owner can upgrade immediately without warning
No time lock or community approval
Validates new implementation has proxiableUUID()
Could introduce malicious logic
CONDITION REQUIREMENT
Valid Implementation newImplementation must implement proxiableUUID()
Owner Authorization Caller must be current owner
STEP ACTION
1 Verify caller is owner
2 Validate new implementation supports UUPS (proxiableUUID check)
3 Update implementation address in EIP-1967 slot
4 If data.length > 0: delegatecall to new implementation with data
5 Emit Upgraded(newImplementation) event
VARIABLE CHANGE
Implementation slot (0x360894a1...) Update to newImplementation
CONDITION REVERT MESSAGE
msg.sender != owner "Ownable: caller is not the owner"
Invalid implementation "ERC1967: new implementation is not UUPS"
Delegatecall fails Propagate error from new implementation
function upgradeToAndCall(
    address newImplementation,
    bytes memory data
) external payable onlyOwner {
    // Validate new implementation
    try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
        require(
            slot == 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,
            "ERC1967: new implementation is not UUPS"
        );
    } catch {
        revert("ERC1967: new implementation is not UUPS");
    }

    // Update implementation slot
    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = 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);
}