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 0x8d33666c83f7f17a1b8dc0e950d8ff2e7e37c563 (etherscan)
Network Ethereum Mainnet
Analysis Date 2025-12-26

Function Selectors

SELECTOR FUNCTION SIGNATURE CATEGORY
0x09069443 addSupportedTokens(address[],uint8[],uint256[]) Admin
0x09dac061 initializeSentinel(address) Admin
0x12efb3f4 SupportedTokens(address) View
0x1803751f mySentinelBought() View
0x22aa67e6 buySentinelWithToken(address,uint256) User
0x2575cdaa totalSentinelBought() View
0x2f48ab7d usdt() View
0x3246c689 TokenDecimals(address) View
0x3417fa5f TokenRates(address) View
0x38af3eed beneficiary() View
0x40c4cdb0 sentinelBoughtOf(address) View
0x54f63ee5 startPresale() Admin
0x60d938dc isPresaleActive() View
0x715018a6 renounceOwnership() Admin
0x7299a729 sentinelToken() View
0x8a5f1822 totalSentinelRaisedInUsdWei() View
0x8da5cb5b owner() View
0x9e281a98 withdrawToken(address,uint256) Admin
0x9f1166a0 buySentinelWithEth() User
0xa0ef91df withdrawEth() Admin
0xa43be57b endPresale() Admin
0xa80a50b9 removeSupportedTokens(address[]) Admin
0xb34a385f calculateSentinelAmount(address,uint256) View
0xb373fb9d totalSentinelRaised() View
0xc35fb403 SentinelBoughtTotal(address) View
0xc6290df0 lastTotalSentinelRaised() View
0xdc070657 setBeneficiary(address) Admin
0xeacd36ed getPresaleStats() View
0xf2fde38b transferOwnership(address) Admin

Summary

CATEGORY NUM FUNCTIONS
Total Functions 29
User Functions 2
Admin Functions 11
View Functions 16

User Functions

Function: buySentinelWithEth()

Purchase Sentinel tokens using ETH. The contract calculates the equivalent Sentinel amount based on configured exchange rates and records the purchase. ETH is immediately forwarded to the beneficiary.

ATTRIBUTE VALUE
Selector 0x9f1166a0
Parameters None
Access Public, Payable, NonReentrant
FLAG OBSERVATION
ETH is sent directly to beneficiary - no escrow
User receives nothing on-chain immediately
Protected by reentrancy guard
Requires presale to be active
CONDITION REQUIREMENT
Presale Active isPresaleActive == true
ETH Rate Set TokenRates[sentinelToken] > 0
Amount Valid msg.value > 0
Result Valid calculateSentinelAmount(...) > 0
STEP ACTION
1 Check reentrancy lock
2 Validate presale is active
3 Validate ETH rate is configured
4 Validate msg.value > 0
5 Calculate Sentinel amount
6 Send ETH to beneficiary
7 Update totalSentinelRaised
8 Update totalSentinelBought
9 Update SentinelBoughtTotal[msg.sender]
10 Emit TokenPurchased event
VARIABLE CHANGE
totalSentinelRaised += sentinelAmount
totalSentinelBought += sentinelAmount
SentinelBoughtTotal[msg.sender] += sentinelAmount
CONDITION REVERT MESSAGE
Presale ended "Presale has ended"
Rate not set "Rate not set"
Zero value "Amount must be greater than 0"
Calculation fails "Sentinel amount too small"
ETH transfer fails "Failed to send Ether"
function buySentinelWithEth() external payable nonReentrant {
    require(isPresaleActive, "Presale has ended");
    require(TokenRates[sentinelToken] > 0, "Rate not set");
    require(msg.value > 0, "Amount must be greater than 0");

    uint256 sentinelAmount = calculateSentinelAmount(sentinelToken, msg.value);
    require(sentinelAmount > 0, "Sentinel amount too small");

    (bool success, ) = beneficiary.call{value: msg.value}("");
    require(success, "Failed to send Ether");

    totalSentinelRaised += sentinelAmount;
    totalSentinelBought += sentinelAmount;
    SentinelBoughtTotal[msg.sender] += sentinelAmount;

    emit TokenPurchased(msg.sender, sentinelToken, sentinelAmount);
}

Function: buySentinelWithToken(address,uint256)

Purchase Sentinel tokens using a supported ERC20 token. The contract transfers the specified token amount from the user to the beneficiary and records the equivalent Sentinel purchase.

ATTRIBUTE VALUE
Selector 0x22aa67e6
Parameters token (address), amount (uint256)
Access Public, NonReentrant
FLAG OBSERVATION
Tokens sent directly to beneficiary via transferFrom
User receives nothing on-chain immediately
Protected by reentrancy guard
Validates token is in supported whitelist
Cannot use sentinelToken address
CONDITION REQUIREMENT
Presale Active isPresaleActive == true
Token Supported SupportedTokens[token] == true
Rate Set TokenRates[token] > 0
Amount Valid amount > 0
Not Sentinel Token token != sentinelToken
User Approval User must have approved contract for token transfer
STEP ACTION
1 Check reentrancy lock
2 Validate presale is active
3 Validate token is supported
4 Validate rate is configured
5 Validate amount > 0
6 Validate not using sentinelToken
7 Calculate Sentinel amount
8 Transfer tokens from user to beneficiary
9 Update totalSentinelRaised
10 Update totalSentinelBought
11 Update SentinelBoughtTotal[msg.sender]
12 Emit TokenPurchased event
VARIABLE CHANGE
totalSentinelRaised += sentinelAmount
totalSentinelBought += sentinelAmount
SentinelBoughtTotal[msg.sender] += sentinelAmount
CONDITION REVERT MESSAGE
Presale ended "Presale has ended"
Token not supported "Token not supported"
Rate not set "Rate not set"
Zero amount "Amount must be greater than 0"
Is sentinel token "Use buySentinelWithEth for ETH"
Calculation fails "Sentinel amount too small"
function buySentinelWithToken(address token, uint256 amount) external nonReentrant {
    require(isPresaleActive, "Presale has ended");
    require(SupportedTokens[token], "Token not supported");
    require(TokenRates[token] > 0, "Rate not set");
    require(amount > 0, "Amount must be greater than 0");
    require(token != sentinelToken, "Use buySentinelWithEth for ETH");

    uint256 sentinelAmount = calculateSentinelAmount(token, amount);
    require(sentinelAmount > 0, "Sentinel amount too small");

    IERC20(token).transferFrom(msg.sender, beneficiary, amount);

    totalSentinelRaised += sentinelAmount;
    totalSentinelBought += sentinelAmount;
    SentinelBoughtTotal[msg.sender] += sentinelAmount;

    emit TokenPurchased(msg.sender, token, sentinelAmount);
}

Admin Functions

Function: startPresale()

Activates the presale, allowing users to purchase Sentinel tokens.

ATTRIBUTE VALUE
Selector 0x54f63ee5
Parameters None
Access Owner Only
FLAG OBSERVATION
No timelock - immediate effect
Prevents double-start
CONDITION REQUIREMENT
Caller msg.sender == owner
Presale State isPresaleActive == false
VARIABLE CHANGE
isPresaleActive = true
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Already active "Presale is already active"
function startPresale() external onlyOwner {
    require(!isPresaleActive, "Presale is already active");
    isPresaleActive = true;
    emit PresaleStarted(block.timestamp);
}

Function: endPresale()

Deactivates the presale, preventing further purchases.

ATTRIBUTE VALUE
Selector 0xa43be57b
Parameters None
Access Owner Only
FLAG OBSERVATION
No timelock - immediate effect
Can be re-started by owner
CONDITION REQUIREMENT
Caller msg.sender == owner
Presale State isPresaleActive == true
VARIABLE CHANGE
isPresaleActive = false
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Already ended "Presale already ended"
function endPresale() external onlyOwner {
    require(isPresaleActive, "Presale already ended");
    isPresaleActive = false;
    emit PresaleEnded(block.timestamp, totalSentinelBought, totalSentinelRaised);
}

Function: addSupportedTokens(address[],uint8[],uint256[])

Adds multiple payment tokens to the whitelist with their decimals and exchange rates. Also calculates and updates USD value tracking.

ATTRIBUTE VALUE
Selector 0x09069443
Parameters tokens[], decimals[], rates[]
Access Owner Only
FLAG OBSERVATION
Owner can set arbitrary exchange rates
Includes USD tracking calculation using USDT rate
Validates array lengths match
Validates rates are > 0
CONDITION REQUIREMENT
Caller msg.sender == owner
Presale State isPresaleActive == true
Arrays tokens.length == decimals.length == rates.length
Rates All rates must be > 0
VARIABLE CHANGE
SupportedTokens[token] = true for each token
TokenDecimals[token] = decimals[i] for each token
TokenRates[token] = rates[i] for each token
lastTotalSentinelRaised = totalSentinelRaised
totalSentinelRaisedInUsdWei += calculated USD value
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Presale ended "Presale has ended"
Array mismatch "Array length mismatch"
Zero rate "Rate must be greater than 0"
function addSupportedTokens(
    address[] calldata tokens,
    uint8[] calldata decimals,
    uint256[] calldata rates
) external onlyOwner {
    require(isPresaleActive, "Presale has ended");
    require(
        tokens.length == decimals.length && decimals.length == rates.length,
        "Array length mismatch"
    );

    uint256 count = tokens.length;
    uint256 diff = totalSentinelRaised - lastTotalSentinelRaised;
    uint256 usdValue = (diff * TokenRates[usdt]) / (10 ** _decimals);
    lastTotalSentinelRaised = totalSentinelRaised;
    totalSentinelRaisedInUsdWei += usdValue;

    for (uint256 i = 0; i < count; i++) {
        address token = tokens[i];
        uint8 dec = decimals[i];
        uint256 rate = rates[i];

        require(rate > 0, "Rate must be greater than 0");

        SupportedTokens[token] = true;
        TokenDecimals[token] = dec;
        TokenRates[token] = rate;

        emit SupportedTokenAdded(token, dec, rate);
    }

    emit TokensAdded(block.timestamp, count, usdValue);
}

Function: removeSupportedTokens(address[])

Removes tokens from the supported whitelist.

ATTRIBUTE VALUE
Selector 0xa80a50b9
Parameters tokens[]
Access Owner Only
FLAG OBSERVATION
Validates tokens are currently supported
Cleans up all related mappings
CONDITION REQUIREMENT
Caller msg.sender == owner
Presale State isPresaleActive == true
Tokens Each token must be currently supported
VARIABLE CHANGE
SupportedTokens[token] = false for each token
TokenDecimals[token] delete
TokenRates[token] delete
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Presale ended "Presale has ended"
Token not supported "Token not supported"
function removeSupportedTokens(address[] calldata tokens) external onlyOwner {
    require(isPresaleActive, "Presale has ended");

    for (uint256 i = 0; i < tokens.length; i++) {
        address token = tokens[i];
        require(SupportedTokens[token], "Token not supported");

        SupportedTokens[token] = false;
        delete TokenDecimals[token];
        delete TokenRates[token];

        emit SupportedTokenRemoved(token);
    }
}

Function: setBeneficiary(address)

Changes the address that receives all presale funds.

ATTRIBUTE VALUE
Selector 0xdc070657
Parameters newBeneficiary (address)
Access Owner Only
FLAG OBSERVATION
No timelock - immediate effect
No validation that address is non-zero
Can redirect all future funds instantly
CONDITION REQUIREMENT
Caller msg.sender == owner
VARIABLE CHANGE
beneficiary = newBeneficiary
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
function setBeneficiary(address newBeneficiary) external onlyOwner {
    address old = beneficiary;
    beneficiary = newBeneficiary;
    emit BeneficiaryChanged(old, newBeneficiary);
}

Function: withdrawEth()

Withdraws any ETH held by the contract to the beneficiary.

ATTRIBUTE VALUE
Selector 0xa0ef91df
Parameters None
Access Owner Only
FLAG OBSERVATION
Sends to beneficiary, not arbitrary address
Contract normally holds no ETH (immediate forwarding)
CONDITION REQUIREMENT
Caller msg.sender == owner
VARIABLE CHANGE
Contract ETH balance = 0
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Transfer fails "Failed to send Ether"
function withdrawEth() external onlyOwner {
    (bool success, ) = beneficiary.call{value: address(this).balance}("");
    require(success, "Failed to send Ether");
}

Function: withdrawToken(address,uint256)

Withdraws ERC20 tokens held by the contract to the beneficiary.

ATTRIBUTE VALUE
Selector 0x9e281a98
Parameters token (address), amount (uint256)
Access Owner Only
FLAG OBSERVATION
Sends to beneficiary, not arbitrary address
Cannot withdraw sentinelToken
CONDITION REQUIREMENT
Caller msg.sender == owner
Token token != sentinelToken
VARIABLE CHANGE
External token balance Decreased by amount
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Is sentinel token "Use withdrawEth()"
function withdrawToken(address token, uint256 amount) external onlyOwner {
    require(token != sentinelToken, "Use withdrawEth()");
    IERC20(token).transfer(beneficiary, amount);
}

Function: initializeSentinel(address)

Sets the Sentinel token contract address. Can only be called once.

ATTRIBUTE VALUE
Selector 0x09dac061
Parameters _sentinelToken (address)
Access Owner Only, One-Time
FLAG OBSERVATION
One-time operation - cannot be changed
Currently not initialized (address(0))
CONDITION REQUIREMENT
Caller msg.sender == owner
Init Status _initStatus == 0
Address _sentinelToken != sentinelToken (not same as current)
VARIABLE CHANGE
_initStatus = 1
sentinelToken Remains unchanged (note: appears to only emit event)
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Already initialized "Sentinel already initialized"
Invalid address "Invalid address"
function initializeSentinel(address _sentinelToken) external onlyOwner {
    require(_initStatus == 0, "Sentinel already initialized");
    _initStatus = 1;
    require(_sentinelToken != sentinelToken, "Invalid address");
    emit SentinelInitialized(block.timestamp, _sentinelToken);
}

Function: transferOwnership(address)

Transfers contract ownership to a new address. Standard Ownable pattern.

ATTRIBUTE VALUE
Selector 0xf2fde38b
Parameters newOwner (address)
Access Owner Only
FLAG OBSERVATION
No timelock - immediate transfer
Validates new owner is not address(0)
CONDITION REQUIREMENT
Caller msg.sender == owner
New Owner newOwner != address(0)
VARIABLE CHANGE
_owner = newOwner
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
Zero address "OwnableInvalidOwner"
function transferOwnership(address newOwner) external onlyOwner {
    require(newOwner != address(0), "OwnableInvalidOwner");
    address oldOwner = _owner;
    _owner = newOwner;
    emit OwnershipTransferred(oldOwner, newOwner);
}

Function: renounceOwnership()

Permanently renounces ownership, making the contract ownerless.

ATTRIBUTE VALUE
Selector 0x715018a6
Parameters None
Access Owner Only
FLAG OBSERVATION
Irreversible - contract becomes unmanaged
Would lock admin functions permanently
CONDITION REQUIREMENT
Caller msg.sender == owner
VARIABLE CHANGE
_owner = address(0)
CONDITION REVERT MESSAGE
Not owner "OwnableUnauthorizedAccount"
function renounceOwnership() external onlyOwner {
    address oldOwner = _owner;
    _owner = address(0);
    emit OwnershipTransferred(oldOwner, address(0));
}

View Functions

Function: owner()

Returns the current contract owner address.

ATTRIBUTE VALUE
Selector 0x8da5cb5b
Returns address
function owner() external view returns (address) {
    return _owner;
}

Function: beneficiary()

Returns the current beneficiary address that receives funds.

ATTRIBUTE VALUE
Selector 0x38af3eed
Returns address
function beneficiary() external view returns (address) {
    return beneficiary;
}

Function: isPresaleActive()

Returns whether the presale is currently active.

ATTRIBUTE VALUE
Selector 0x60d938dc
Returns bool
function isPresaleActive() external view returns (bool) {
    return isPresaleActive;
}

Function: sentinelToken()

Returns the Sentinel token contract address (may be address(0) if not initialized).

ATTRIBUTE VALUE
Selector 0x7299a729
Returns address
function sentinelToken() external view returns (address) {
    return sentinelToken;
}

Function: usdt()

Returns the USDT contract address (hardcoded mainnet address).

ATTRIBUTE VALUE
Selector 0x2f48ab7d
Returns address
function usdt() external view returns (address) {
    return usdt;
}

Function: totalSentinelBought()

Returns the total amount of Sentinel tokens purchased.

ATTRIBUTE VALUE
Selector 0x2575cdaa
Returns uint256
function totalSentinelBought() external view returns (uint256) {
    return totalSentinelBought;
}

Function: totalSentinelRaised()

Returns the total Sentinel raised amount.

ATTRIBUTE VALUE
Selector 0xb373fb9d
Returns uint256
function totalSentinelRaised() external view returns (uint256) {
    return totalSentinelRaised;
}

Function: totalSentinelRaisedInUsdWei()

Returns the USD value of raised funds (in wei units).

ATTRIBUTE VALUE
Selector 0x8a5f1822
Returns uint256
function totalSentinelRaisedInUsdWei() external view returns (uint256) {
    return totalSentinelRaisedInUsdWei;
}

Function: lastTotalSentinelRaised()

Returns the checkpoint value used for USD calculations.

ATTRIBUTE VALUE
Selector 0xc6290df0
Returns uint256
function lastTotalSentinelRaised() external view returns (uint256) {
    return lastTotalSentinelRaised;
}

Function: mySentinelBought()

Returns the calling user's total Sentinel purchase amount.

ATTRIBUTE VALUE
Selector 0x1803751f
Returns uint256
function mySentinelBought() external view returns (uint256) {
    return SentinelBoughtTotal[msg.sender];
}

Function: sentinelBoughtOf(address)

Returns a specific user's total Sentinel purchase amount.

ATTRIBUTE VALUE
Selector 0x40c4cdb0
Parameters user (address)
Returns uint256
function sentinelBoughtOf(address user) external view returns (uint256) {
    return SentinelBoughtTotal[user];
}

Function: calculateSentinelAmount(address,uint256)

Calculates Sentinel token amount for a given payment token and amount.

ATTRIBUTE VALUE
Selector 0xb34a385f
Parameters token (address), amount (uint256)
Returns uint256
function calculateSentinelAmount(address token, uint256 amount) public view returns (uint256) {
    require(SupportedTokens[token], "Token not supported");
    require(TokenRates[token] > 0, "Rate not set");

    return (amount * TokenRates[token]) / (10 ** _decimals);
}

Function: getPresaleStats()

Returns multiple presale statistics in a single call.

ATTRIBUTE VALUE
Selector 0xeacd36ed
Returns (uint256 totalRaised, uint256 usdRaised, uint256 totalBought)
function getPresaleStats() external view returns (
    uint256 totalRaised,
    uint256 usdRaised,
    uint256 totalBought
) {
    return (totalSentinelRaised, totalSentinelRaisedInUsdWei, totalSentinelBought);
}

Function: SupportedTokens(address)

Returns whether a token is in the supported whitelist.

ATTRIBUTE VALUE
Selector 0x12efb3f4
Parameters token (address)
Returns bool
// Auto-generated mapping getter
function SupportedTokens(address token) external view returns (bool) {
    return SupportedTokens[token];
}

Function: TokenDecimals(address)

Returns the configured decimals for a supported token.

ATTRIBUTE VALUE
Selector 0x3246c689
Parameters token (address)
Returns uint8
// Auto-generated mapping getter
function TokenDecimals(address token) external view returns (uint8) {
    return TokenDecimals[token];
}

Function: TokenRates(address)

Returns the exchange rate for a supported token.

ATTRIBUTE VALUE
Selector 0x3417fa5f
Parameters token (address)
Returns uint256
// Auto-generated mapping getter
function TokenRates(address token) external view returns (uint256) {
    return TokenRates[token];
}

Function: SentinelBoughtTotal(address)

Returns a user's total Sentinel purchase amount (mapping getter).

ATTRIBUTE VALUE
Selector 0xc35fb403
Parameters user (address)
Returns uint256
// Auto-generated mapping getter
function SentinelBoughtTotal(address user) external view returns (uint256) {
    return SentinelBoughtTotal[user];
}