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.
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"
functionbuySentinelWithEth()externalpayablenonReentrant{require(isPresaleActive,"Presale has ended");require(TokenRates[sentinelToken]>0,"Rate not set");require(msg.value>0,"Amount must be greater than 0");uint256sentinelAmount=calculateSentinelAmount(sentinelToken,msg.value);require(sentinelAmount>0,"Sentinel amount too small");(boolsuccess,)=beneficiary.call{value:msg.value}("");require(success,"Failed to send Ether");totalSentinelRaised+=sentinelAmount;totalSentinelBought+=sentinelAmount;SentinelBoughtTotal[msg.sender]+=sentinelAmount;emitTokenPurchased(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"
functionbuySentinelWithToken(addresstoken,uint256amount)externalnonReentrant{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");uint256sentinelAmount=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;emitTokenPurchased(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"
functionstartPresale()externalonlyOwner{require(!isPresaleActive,"Presale is already active");isPresaleActive=true;emitPresaleStarted(block.timestamp);}
Function: endPresale()
Deactivates the presale, preventing further purchases.
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"
functionaddSupportedTokens(address[]calldatatokens,uint8[]calldatadecimals,uint256[]calldatarates
)externalonlyOwner{require(isPresaleActive,"Presale has ended");require(tokens.length==decimals.length&&decimals.length==rates.length,"Array length mismatch");uint256count=tokens.length;uint256diff=totalSentinelRaised-lastTotalSentinelRaised;uint256usdValue=(diff*TokenRates[usdt])/(10**_decimals);lastTotalSentinelRaised=totalSentinelRaised;totalSentinelRaisedInUsdWei+=usdValue;for(uint256i=0;i<count;i++){addresstoken=tokens[i];uint8dec=decimals[i];uint256rate=rates[i];require(rate>0,"Rate must be greater than 0");SupportedTokens[token]=true;TokenDecimals[token]=dec;TokenRates[token]=rate;emitSupportedTokenAdded(token,dec,rate);}emitTokensAdded(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"
functionremoveSupportedTokens(address[]calldatatokens)externalonlyOwner{require(isPresaleActive,"Presale has ended");for(uint256i=0;i<tokens.length;i++){addresstoken=tokens[i];require(SupportedTokens[token],"Token not supported");SupportedTokens[token]=false;deleteTokenDecimals[token];deleteTokenRates[token];emitSupportedTokenRemoved(token);}}
Function: setBeneficiary(address)
Changes the address that receives all presale funds.
Calculates Sentinel token amount for a given payment token and amount.
ATTRIBUTE
VALUE
Selector
0xb34a385f
Parameters
token (address), amount (uint256)
Returns
uint256
functioncalculateSentinelAmount(addresstoken,uint256amount)publicviewreturns(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.