SoCrazy Info
Traditional lotteries are opaque, centralized, and require blind trust in operators. SoCrazy changes everything by putting the entire lottery infrastructure on-chain. Every ticket purchase, draw, and payout is executed through smart contracts on Solana. Results are cryptographically verifiable. Prize pools are transparent. Winners are paid instantly and automatically. No central authority can manipulate outcomes, delay payments, or take unauthorized cuts. It's gambling as it should be: trustless, transparent, and fair.
TrustNet Score
The TrustNet Score evaluates crypto projects based on audit results, security, KYC verification, and social media presence. This score offers a quick, transparent view of a project's credibility, helping users make informed decisions in the Web3 space.
Real-Time Threat Detection
Real-time threat detection, powered by Cyvers.io,
is currently not
activated
for this project.
This advanced feature provides continuous monitoring and instant alerts to safeguard your assets from potential security threats. Real-time detection enhances your project's security by proactively identifying and mitigating risks.
For more information, click here.
Security Assessments
Summary and Final Words
No crucial issues found
The contract does not contain issues of high or medium criticality. This means that no known vulnerabilities were found in the source code.
Ownership is not renounced
The owner retains significant control, which could potentially be used to modify key contract parameters.
Contract is upgradeable
The contract uses a proxy pattern or similar mechanism, enabling future upgrades. This can introduce risks if the upgrade mechanism is not securely managed.
Scope of Work
This audit encompasses the evaluation of the files listed below, each verified with a SHA-1 Hash. The team referenced above has provided the necessary files for assessment.
The auditing process consists of the following systematic steps:
- Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
- Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
- Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
- Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
- Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
- Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
- Actionable Recommendations: Provide detailed, specific, and actionable steps to secure and optimize the smart contracts.
A file with a different Hash has been intentionally or otherwise modified after the security review. A different Hash may indicate a changed condition or potential vulnerability that was not within the scope of this review.
Final Words
The following provides a concise summary of the audit report, accompanied by insightful comments from the auditor. This overview captures the key findings and observations, offering valuable context and clarity.
Smart Contract Analysis Statement (V2 Re-Audit)
Contract Analysis
The Token ICO contract implements a Solana-based multi-stage presale program built with Anchor 0.32, featuring configurable token pricing, stablecoin and native SOL payment acceptance (via Pyth oracle), staged token claiming, and admin-gated lifecycle management across 15 on-chain instructions. This is a re-audit following the V1 report; the development team addressed several findings and provided explicit design-decision responses for others. While the overall design follows sound Anchor patterns and the core arithmetic and PDA logic is correct, the following items remain noteworthy:
- No vault balance guard in
buy(Low — downgraded from Critical, acknowledged by client): Thebuyinstruction does not verify that the token vault holds enough tokens to fulfill the purchase. Users can pay real funds (stablecoins or SOL) for tokens that may not yet be available to claim. The client explicitly chose this design: the admin is responsible for funding the vault before enabling claims viaenable_stage_claim. Theclaiminstruction does verifyvault.amount >= claimable(claim.rs line 26-29), providing a safety net at claim time. The README at line 13 still incorrectly states that buy performs this check. - Single-step admin transfer (Low — downgraded from High, acknowledged by client): The
transfer_admininstruction performs an irrevocable, single-transaction reassignment of the admin key. A typo or compromised RPC endpoint permanently locks all admin-gated functionality and traps all funds in program PDAs. The client declined to implement the 2-step nominate/accept pattern, stating no requirement for complex admin transfer logic. The README was updated with an explicit warning about irreversibility. The zero-address check (Pubkey::default()) prevents the most common accidental lockout. - Stablecoin payments hardcoded at $1.00 (Low — downgraded from High, acknowledged by client): All whitelisted stablecoins are valued at exactly $1.00 regardless of market conditions. During a depeg event (historically observed with USDC and USDT), buyers can acquire ICO tokens at a discount. The client confirmed this is the intended design — USDC/USDT are converted at a 1:1 ratio by agreement. The README was updated to document this. The admin can use
toggle_pauseto halt sales during a depeg event. - Residual README-to-code divergence (Informational): The README was substantially updated in V2 — the dual-path fund architecture is now documented, the admin transfer warning was added, the NoPendingAdmin error was removed, and the stablecoin pricing note was added. However, 10 residual inaccuracies remain, including: a documented
update_treasuryinstruction that does not exist, references to atreasuryfield in IcoConfig, the staleness threshold stated as 300s when code uses 120s, and apending_adminreference.
Resolved Findings from V1
The following V1 findings were confirmed as properly addressed in V2:
- M-03 (Premature Stage Closure):
close_stagenow requirestokens_claimed_total == tokens_soldbefore a stage can be closed, preventing permanent loss of unclaimed user entitlements. New errorUnclaimedTokensRemainingadded. - M-04 (Input Validation Gap): Both
create_stageandupdate_stagenow validate that timestamps are non-negative, thatend_timeis in the future when set, and thatend_time > start_timewhen both are set. New errorsInvalidTimeRangeandEndTimeExpiredadded. - L-03 (Price Oracle Staleness): Pyth staleness threshold reduced from 300s to 120s.
- O-01 (Double Clock::get()):
Clockinstance is now passed as a parameter tocompute_sol_usd_value, eliminating the redundant syscall. - I-02, I-06, L-04: Documentation inaccuracies corrected (NoPendingAdmin removed, dual-path architecture documented,
set_whitelist_tokenparams corrected).
Ownership Privileges
The ownership of the contract is centralized in a single admin key stored in the IcoConfig PDA. The admin retains full privileges including:
- Creating, updating, activating, and closing presale stages with arbitrary pricing and allocation
- Enabling or disabling token claiming per stage, including while a stage is still active for purchases (acknowledged race condition — M-02)
- Emergency withdrawal of any SPL token (including ICO tokens and collected payments) from any ATA of the
ico_configPDA, at any time, with no minimum balance enforcement (acknowledged centralization risk — M-01) - Emergency withdrawal of SOL from the
ico_configPDA (above rent-exempt minimum) - Pausing and unpausing the contract, which disables
buyandclaimfor all users - Whitelisting and disabling payment tokens
- Irrevocable single-step transfer of admin privileges to any non-zero address
Limitations on the admin:
- The admin cannot mint new ICO tokens (mint authority is external to the contract)
- The admin cannot modify a user's purchase record or claim on their behalf
- The admin cannot bypass PDA seed constraints or forge CPI signatures
- The admin cannot re-initialize the ICO after the initial
initialize_icocall (PDA already exists) - The admin cannot close a stage while users still have unclaimed balances (
tokens_claimed_total == tokens_soldrequired — M-03 resolved)
Security Features
The contract implements several positive security features:
- Checked arithmetic throughout: All arithmetic operations use
checked_add,checked_sub,checked_mul,checked_div, andu64::try_fromwith explicitIcoError::Overflowhandling. The workspace release profile also setsoverflow-checks = true. - Correct PDA derivation and bump verification: All program-derived addresses use deterministic seeds with stored bump values, and all account constraints verify bumps on access.
- Pyth oracle validation: SOL/USD price feeds are validated for program ownership (Pyth Push Oracle or Receiver), data integrity (Anchor deserialization), feed identity (SOL/USD feed ID), price positivity, and staleness (120-second threshold, reduced from 300s in V2).
- Manual UncheckedAccount validation for payment accounts: The
buyhandler manually deserializes and validatesuser_payment_accountandpayment_vaultfor mint, owner, and token-program ownership in the stablecoin path, preventing account spoofing. - Single-active-stage invariant: The
current_stagefield onIcoConfigensures only one stage can be active for purchases at any time, preventing cross-stage conflicts. - Rent-exemption protection on SOL withdrawal: The
emergency_withdraw_solhandler correctly computes and preserves the minimum rent-exempt balance before allowing SOL extraction from the PDA. - Settlement guard on stage closure (V2): The
close_stageinstruction now requires all purchased tokens to be claimed (tokens_claimed_total == tokens_sold) before the stage account can be closed, preventing permanent loss of user entitlements. - Stage time window validation (V2): Both
create_stageandupdate_stagenow enforce non-negative timestamps, futureend_time, and properend_time > start_timeordering. Thebuyinstruction enforces the time window at purchase time.
Testing Assessment
The test suite (62 tests, all passing) covers the core happy-path operations and basic error conditions for all 15 instructions. The expectError helper was improved to use exact matching on AnchorError.error.errorCode.code as the primary assertion path. However, significant gaps remain: zero coverage for the SOL/Pyth payment flow, zero coverage for the newly added stage time-window enforcement (V2 code with zero tests), no vault-underfunding scenarios (despite the claim-time vault check being the critical safety net for C-02), no account-spoofing resistance tests for the UncheckedAccount fields in buy, and no test for the InvalidAdmin error path. The emergency_withdraw_sol test uses synthetic airdrop funding instead of actual SOL buy transactions, and two test cases serve only as state setup without assertions. The entire suite remains a single monolithic describe block with sequential test coupling — no test can run in isolation.
Note — This re-audit report consists of a security analysis of the Token ICO smart contract deployed on Solana, following the initial V1 audit and the client’s response addressing or acknowledging each finding. This analysis did not include economic analysis of the project’s tokenomics, token distribution schedule, or vesting mechanisms. Moreover, we only audited the on-chain Anchor program under programs/contract/ and its associated TypeScript test suite. Off-chain CLI scripts in app/, deployment tooling, and any other contracts or programs associated with the project were not audited by our team. We recommend investors do their own research before participating in the token sale.
Files and details
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Functions
public
/
State variables
public
/
Total lines
of code
/
Capabilities
Hover on items
/
Findings and Audit result
low Issues | 6 findings
Acknowledged
#1 low Issue
Access Control / Admin Transfer
Admin transfer remains a single-step direct assignment. If the admin passes an incorrect pubkey, all admin-gated functionality (stage management, claim enabling, emergency withdrawals, pausing) becomes permanently inaccessible and all funds in program PDAs are irrecoverable. Client declined to implement the 2-step nominate/accept pattern, stating no requirement for complex admin transfer logic.
Acknowledged
#2 low Issue
Stablecoin Depeg Risk
All stablecoins are hardcoded at exactly $1.00 via compute_stablecoin_usd_value(). During a stablecoin depeg event (historically occurred with USDC/USDT), users can buy ICO tokens at a discount — paying $0.95 real value while tokens are calculated at $1.00. No price_usd field exists in WhitelistToken and no secondary oracle is integrated. Client confirmed this is the intended design.
Acknowledged
#3 low Issue
Logic / Race Condition
The enable_stage_claim instruction has no check for whether the stage is currently active. An admin can enable claiming while the stage is still active for purchases, creating a race condition where users simultaneously buy and claim from the same stage. Since the vault balance is shared across all stages, early claimers could drain the vault and cause later claimers to fail. Client stated this is an admin operational responsibility.
Acknowledged
#4 low Issue
Inconsistent Arithmetic Safety
The comparison stage_id == ico_config.stage_count + 1 at line 30 uses unchecked u8 addition. When stage_count == 255, this overflows and panics with a generic runtime error instead of the descriptive InvalidStageId error. This is inconsistent with the checked_add used on lines 47-50 for the actual increment. Client declined to fix, stating only 7 stages are planned.
Resolved
#5 low Issue
Price Oracle Staleness
The Pyth price staleness threshold was 300 seconds (5 minutes). This has been reduced to 120 seconds (2 minutes) as recommended. The code fix is confirmed at buy.rs line 19. Note: the README still references 300 seconds in multiple locations (lines 111, 206, 562, 581) and should be updated to reflect the actual 120s threshold.
Acknowledged
#6 low Issue
Missing Validation / Fund Safety
The buy instruction has no vault balance check. The vault token account is not included in the Buy accounts struct. The handler only checks remaining stage allocation (tokens_total - tokens_sold), not whether the vault actually holds sufficient tokens. This allows overselling: users pay real money (stablecoins/SOL) but claims may fail later with InsufficientVaultBalance if the admin hasn't funded the vault. The README at line 13 still falsely claims 'Vault balance guard — buy verifies the vault holds enough tokens before selling.' Client explicitly chose this design, stating the admin will fund the vault before enabling claims.
optimization Issues | 3 findings
Resolved
#1 optimization Issue
Compute Unit Optimization
The buy handler previously called Clock::get() twice — once for time validation and once inside compute_sol_usd_value. Now Clock::get() is called once at line 37 and passed as a &Clock parameter to compute_sol_usd_value (line 224), eliminating the redundant syscall and saving compute units.
Acknowledged
#2 optimization Issue
Compute Unit / Code Simplification
The handler manually borrows, deserializes, and validates user_payment_account and payment_vault data for stablecoin payments. This duplicates work that Anchor's typed Account<> constraints could handle. Client declined the change, stating the current logic works and changes would require additional frontend/backend effort.
Acknowledged
#3 optimization Issue
Transaction Size Optimization
The Buy instruction requires 12 accounts regardless of payment method. For stablecoin payments, price_update is unused. For SOL payments, user_payment_account and payment_vault are unused. Splitting into buy_with_token and buy_with_sol would reduce account count per transaction. Client declined the change.
informational Issues | 10 findings
Acknowledged
#1 informational Issue
Centralization Risk / Missing Safeguard
The emergency_withdraw instruction allows the admin to withdraw ANY amount of ANY SPL token from ANY ATA of the ico_config PDA at any time, with no pause check, no minimum balance enforcement, and no restriction during active sales. A compromised admin key can drain all vault tokens and collected payments. Client confirmed this is the intended design — no updates required.
Resolved
#2 informational Issue
Funds Availability / Premature Stage Closure
Previously, close_stage only validated that a stage was inactive and claim was disabled, without verifying all purchases were claimed. Now a settlement guard (line 12-15) requires tokens_claimed_total == tokens_sold before a stage can be closed. The new UnclaimedTokensRemaining error is properly defined in errors.rs line 51-52.
Resolved
#3 informational Issue
Input Validation Gap
Stage time window validation previously only checked end_time > start_time when both were non-zero. Now both create_stage and update_stage validate that timestamps are non-negative, that end_time is in the future when set, and that end_time > start_time when both are set. New error codes InvalidTimeRange and EndTimeExpired added to errors.rs.
Pending
#4 informational Issue
Documentation Mismatch
The README was partially updated but still contains inaccuracies: (1) Line 12 mentions 'Treasury update' feature that doesn't exist. (2) Line 13 falsely claims buy checks vault balance. (3) Line 96 mentions 'treasury' in IcoConfig. (4) Line 111 says 300s staleness but code uses 120s. (5) Line 157 lists 'treasury' as initialize_ico param. (6) Line 158 mentions 'pending_admin' that doesn't exist. (7) Lines 267-272 document update_treasury instruction that doesn't exist. (8) Line 562 says 300s staleness. (9) Line 581 says 300s in error description. (10) Line 608 says 16 instructions instead of 15.
Resolved
#5 informational Issue
Documentation Mismatch
The README previously documented set_whitelist_token as accepting mint, enabled, and price_usd. The price_usd reference has been removed and the hardcoded $1.00 stablecoin note was added. The 'mint' is listed as a param but is actually determined by the payment_mint account in the instruction context — minor doc convention discrepancy.
Pending
#6 informational Issue
Documentation Inaccuracy
The README instruction count was updated to 15 in the summary table and section header, but the update_treasury instruction (lines 267-272) is still documented despite not existing in code. The project structure section at line 608 still references '16 instructions'. These residual references should be removed.
Resolved
#7 informational Issue
Documentation Inaccuracy
The README error table previously listed NoPendingAdmin which was not defined in errors.rs. This has been removed from the error table, resolving the documentation mismatch.
Acknowledged
#8 informational Issue
Feature Flag Risk
The init-if-needed Anchor feature is enabled in Cargo.toml. This feature has historically been controversial due to reinitialization attack surfaces. In Anchor 0.32, the discriminator check mitigates this. All current uses appear safe, but care must be taken when adding new instructions using this feature.
Acknowledged
#9 informational Issue
Code Quality
The #![allow(ambiguous_glob_reexports)] attribute suppresses a Rust compiler warning about ambiguous glob re-exports. While functional, it may mask future naming conflicts if new modules are added. Client acknowledged and chose to keep the current pattern.
Resolved
#10 informational Issue
Asymmetric Fund Architecture
Stablecoin payments flow to ATAs of ico_config; SOL payments flow directly to the ico_config PDA as lamports. This dual-path architecture is now thoroughly documented in the README with tables showing payment routing and withdrawal instructions for each path.