Skip to main content

πŸ” Section 3: SPL Token-2022 Transfer Hooks β€” Layer 2


πŸ” The security primitive at the heart of OTCM Protocol β€” 42 mathematically enforced controls that execute atomically on every ST22 token transfer via SPL Token-2022 Transfer Hook extensions.


πŸ” SECTION 3: SPL TOKEN-2022 TRANSFER HOOKS

πŸ’‘ 3.1 Architectural Innovation

SPL Token-2022 Transfer Hooks represent a fundamental architectural innovation in blockchain-based securities infrastructure, enabling execution of arbitrary smart contract code during token transfers on the Solana blockchain. This capability transforms compliance from a discretionary administrative function into an immutable, mathematically-enforced property of the token itself.

OTCM Protocol leverages Transfer Hooks to implement federal securities law requirements as non-discretionary smart contract code, creating a paradigm where regulatory compliance is not a matter of corporate policy but of cryptographic certainty. Every ST22 transfer triggers sequential execution of six independent verification hooks, completing comprehensive compliance verification before transaction settlement.

πŸ”Ή 3.1.1 SPL Token-2022 Standard Overview

SPL Token-2022 (also known as Token Extensions Program) is Solana's next-generation token standard, introducing programmable extensions that enable sophisticated token functionality impossible with the original SPL Token Program:

Extension

Capability

OTCM Usage

Transfer Hook

Execute custom logic on every transfer

42 security controls, compliance verification

Permanent Delegate

Irrevocable transfer authority

Protocol-level recovery capability

Confidential Transfers

Zero-knowledge encrypted amounts

Future: Privacy-preserving compliance

Transfer Fee

Protocol-level fee collection

5% fee distribution automation

Metadata Pointer

On-chain token metadata

Security details, issuer info, CUSIP

Non-Transferable

Soulbound token capability

Compliance NFTs, investor credentials

πŸ”Ή 3.1.2 Transfer Hook Extension Mechanism

The Transfer Hook extension enables token mints to specify a program that must be invoked during every token transfer. This mechanism operates at the Solana runtime level, making it impossible to transfer tokens without executing the hook program:

// SPL Token-2022 Transfer Hook Mechanism
// Transfer Hook Extension Data Structure

pub struct TransferHook {

/// The program ID that implements the transfer hook

pub program_id: Pubkey,

/// Optional: Authority that can update the hook program

pub authority: Option<Pubkey>,

}

// When a transfer occurs, Solana runtime automatically:
// 1. Checks if mint has TransferHook extension
// 2. If yes, invokes the specified program_id with transfer context
// 3. If hook returns error, ENTIRE transaction reverts
// 4. If hook succeeds, transfer completes
// This is MANDATORY - there is no way to bypass the hook
// The token literally cannot move without hook approval

πŸ”Ή 3.1.3 Compliance-as-Code Philosophy

OTCM's Transfer Hook implementation embodies the "Compliance-as-Code" philosophy: regulatory requirements are translated into deterministic smart contract logic that executes identically every time, without human discretion, administrative override, or interpretation variability.

"Traditional compliance asks: 'Did you follow the rules?' OTCM's Transfer Hooks ask: 'Can you mathematically prove compliance?' The answer is always verifiable on-chain."

Aspect

Traditional Compliance

Transfer Hook Compliance

Enforcement

Policy-based, discretionary

Code-based, deterministic

Override Capability

Admin can bypass

No bypass possible

Audit Trail

Mutable logs, editable

Immutable blockchain record

Verification

Requires trust in operator

Cryptographically verifiable

Consistency

Varies by analyst/day

100% identical execution

Timing

Post-trade review (T+n)

Pre-trade blocking (T-0)

πŸ”Ή 3.1.4 Regulatory Advantages

Transfer Hook execution provides regulatory advantages unattainable through traditional compliance procedures:

  • Immutable Audit Trails: Every compliance check is recorded on-chain with cryptographic proof of execution timestamp, inputs, and outcomes
  • Zero Discretion: Compliance decisions are algorithmicβ€”no analyst judgment, no selective enforcement, no regulatory arbitrage
  • Real-Time Enforcement: Non-compliant transfers are blocked before execution, not flagged for review after the fact
  • Cryptographic Proof: Regulators can independently verify any historical compliance decision by replaying on-chain data
  • Continuous Operation: 24/7/365 enforcement with no business hours, holidays, or staffing gaps πŸ’‘ SEC Modernization Alignment

OTCM's Transfer Hook architecture aligns with SEC Chair Gensler's stated goal of 'bringing crypto into compliance' and the SEC Crypto Task Force's exploration of blockchain-native compliance mechanisms.

πŸ”— 3.2 Transfer Hook Execution Flow

This section details the precise execution sequence when an ST22 token transfer is initiated, from user action through final settlement.

πŸ”Ή 3.2.1 Hook Invocation Sequence

When a user initiates an ST22 transfer, the following sequence executes:

// Sequential Hook Execution Flow
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                  ST22 TRANSFER HOOK EXECUTION SEQUENCE                  β”‚
└─────────────────────────────────────────────────────────────────────────---β”˜

User Initiates Transfer

β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚  SOLANA RUNTIME: Detects TransferHook extension on ST22 mint     β”‚
β”‚  Invokes OTCM Transfer Hook Program with transfer context        β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    HOOK 1: CUSTODY VERIFICATION                  β”‚
β”‚                         (100-150ms)                              β”‚
β”‚  Query Empire Stock Transfer β†’ Verify 1:1 backing β†’ Error 6001   β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚ PASS
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    HOOK 2: OFAC SCREENING                        β”‚
β”‚                         (200-500ms)                              β”‚
β”‚  Check SDN List β†’ Address clustering β†’ Error 6002                β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚ PASS
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    HOOK 3: AML ANALYTICS                         β”‚
β”‚                         (300-400ms)                              β”‚
β”‚  ML risk scoring β†’ 200+ features β†’ Error 6003                    β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚ PASS
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    HOOK 4: REDEMPTION ELIGIBILITY                β”‚
β”‚                         (50-100ms)                               β”‚
β”‚  KYC status β†’ Accreditation β†’ 72hr cooling β†’ Error 6004          β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚ PASS
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    HOOK 5: PRICE IMPACT LIMIT                    β”‚
β”‚                         (50-100ms)                               β”‚
β”‚  Calculate impact β†’ Compare TWAP β†’ 2% threshold β†’ Error 6006     β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚ PASS
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    HOOK 6: LIQUIDITY SUFFICIENCY                 β”‚
β”‚                         (50-100ms)                               β”‚
β”‚  Check LP ratio β†’ 150% minimum β†’ Error 6007                      β”‚
└────────────────────────────---┬─────────────────────────────────────---β”˜
β”‚ PASS
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€---┐
β”‚                    ALL HOOKS PASSED                              β”‚
β”‚              Transfer executes, transaction commits              β”‚
β”‚                 Settlement: ~13 seconds (32 blocks)              β”‚
└──────────────────────────────────────────────────────────────────---β”˜

πŸ”Ή 3.2.2 Sequential vs Parallel Execution

OTCM implements sequential hook execution rather than parallel for critical security reasons:

Mode

Advantage

Trade-off

Sequential (OTCM)

Early exit on failure, deterministic order, simpler debugging

Higher latency (750-1,350ms total)

Parallel

Lower latency (~500ms total)

Non-deterministic, race conditions, wasted compute on early failures

Sequential execution ensures that if Hook 1 (Custody Verification) fails, Hooks 2-6 never executeβ€”saving oracle costs and compute resources. It also provides deterministic error reporting: users always know which specific hook rejected their transaction.

πŸ”Ή 3.2.3 Atomic Transaction Guarantees

Solana's account model provides atomic transaction guarantees: if any hook fails, the entire transaction reverts as if it never occurred. There is no intermediate state where tokens have transferred but compliance verification is incomplete.

// Atomicity Guarantee
// Atomic Execution Guarantee
// Scenario A: All hooks pass
// Result: Transaction commits, tokens move, state updates
// Scenario B: Hook 3 (AML) rejects due to risk score
// Result: ENTIRE transaction reverts
//   - No tokens moved
//   - No fees charged
//   - No state changes
//   - Error returned to user: 6003 (AML_RISK_EXCEEDED)
// There is NO partial execution state
// This is guaranteed by Solana runtime, not OTCM code

πŸ”Ή 3.2.4 Execution Timing Diagram

Hook

Min (ms)

Max (ms)

Avg (ms)

Primary Bottleneck

1. Custody Oracle

100

150

125

Empire API latency

2. OFAC Screening

200

500

350

SDN list size, clustering

3. AML Analytics

300

400

350

ML inference time

4. Redemption Eligibility

50

100

75

KYC database lookup

5. Price Impact

50

100

75

TWAP calculation

6. LP Sufficiency

50

100

75

Pool state read

TOTAL

750

1,350

1,050

Sequential sum

πŸ”— 3.3 Hook 1: Custody Verification Oracle

The Custody Verification Oracle confirms that all circulating ST22 tokens are backed by equivalent equity shares held at Empire Stock Transfer, the SEC-registered transfer agent providing qualified custody services for OTCM Protocol.

πŸ”Ή 3.3.1 Oracle Architecture

The custody oracle operates as a cryptographically-signed data feed from Empire Stock Transfer's registry systems:

// Custody Oracle Data Structure

pub struct CustodyOracleData {

/// CIK number of the issuing company

pub issuer_cik: [u8; 10],

/// CUSIP identifier for the security

pub cusip: [u8; 9],

/// Share class (Series M preferred)

pub share_class: ShareClass,

/// Total shares held in custody

pub custodied_balance: u64,

/// Total ST22 tokens in circulation

pub circulating_tokens: u64,

/// Ed25519 signature from Empire's HSM

pub attestation_signature: [u8; 64],

/// Merkle root of current shareholder registry

pub registry_hash: [u8; 32],

/// Unix timestamp of attestation

pub attestation_timestamp: i64,

/// Block height when attestation was recorded

pub attestation_slot: u64,

}

πŸ”Ή 3.3.2 Empire Stock Transfer Integration

Empire Stock Transfer provides real-time custody attestations through a dedicated API integration:

Component

Specification

API Endpoint

https://api.empirestocktransfer.com/v1/custody/verify

Authentication

API Key + Ed25519 request signing

Response Signing

HSM-secured Ed25519 signature on every attestation

Update Frequency

Every Solana slot (~400ms)

Failover

Multi-region deployment with automatic failover

πŸ” PROOF-OF-RESERVE β€” SUPPLY RECONCILIATION SPECIFICATION

Version: 6.0 | Applies To: Layer 6 Oracle Network β€” Hook 1 Custody Verification

The Reconciliation Invariant

At every Solana slot, the following invariant MUST hold for every active ST22 mint:

on_chain_token_supply(mint) <= empire_custodied_shares(mint)

Any condition where on-chain supply EXCEEDS custodied shares is an immediate critical alert (Error 6001 β€” all transfers halted). The system is designed so equality (1:1 backing) is the steady state and a deficit on the custody side is impossible under normal operations because shares must be deposited BEFORE tokens are minted.

Empire Stock Transfer API β€” Canonical Response Schema

rust

/// Canonical signed attestation payload from Empire Stock Transfer API
/// Received by the primary Oracle and published on-chain each slot
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct EmpireCustodyAttestation {
    /// Schema version β€” must match EMPIRE_SCHEMA_VERSION constant
    pub schema_version: u8,                    // Currently: 1

    /// The ST22 mint this attestation covers
    pub mint: Pubkey,

    /// CUSIP of the underlying Series M preferred share class
    pub cusip: [u8; 9],

    /// Total shares of Series M held in irrevocable custody at Empire
    /// This is the authoritative backing figure
    pub custodied_shares: u64,

    /// Total shares ever deposited (monotonically increasing)
    pub total_deposited_lifetime: u64,

    /// Solana slot number at time of attestation
    pub slot: u64,

    /// Unix timestamp at time of attestation
    pub timestamp: i64,

    /// Attestation expiry β€” slot after which Hook 1 rejects this message
    pub expiry_slot: u64,

    /// Monotonically increasing sequence number (replay prevention)
    pub sequence_number: u64,

    /// SHA-256 hash of Empire's internal ledger state at this slot
    /// Enables independent verification against Empire's published quarterly hash
    pub ledger_state_hash: [u8; 32],

    /// Ed25519 signature over all fields above using Empire HSM key
    pub signature: [u8; 64],

    /// Empire's HSM public key (must match on-chain OracleRegistry entry)
    pub signer_pubkey: Pubkey,
}

/// On-chain custody cache β€” stores latest valid attestation per mint
#[account]
pub struct CustodyCache {
    pub version: u8,
    pub mint: Pubkey,
    pub custodied_shares: u64,
    pub last_updated_slot: u64,
    pub last_sequence_number: u64,
    pub ledger_state_hash: [u8; 32],
    pub bump: u8,
}

Reconciliation Algorithm β€” Hook 1 Execution

rust

/// Hook 1: Full supply reconciliation on every transfer
pub fn verify_custody_hook(
    ctx: Context,
    transfer_amount: u64,
) -> Result<()> {

    // --- STEP 1: Validate attestation schema version ---
    require!(
        ctx.accounts.oracle_attestation.schema_version == EMPIRE_SCHEMA_VERSION,
        OracleError::SchemaMismatch
    );

    // --- STEP 2: Verify Ed25519 signature ---
    // Signature covers all fields except `signature` itself
    let attestation_bytes = ctx.accounts.oracle_attestation
        .try_to_vec_without_signature()?;
    verify_ed25519_signature(
        &attestation_bytes,
        &ctx.accounts.oracle_attestation.signature,
        &ctx.accounts.oracle_registry.empire_primary_pubkey,
    ).map_err(|_| error!(OracleError::InvalidSignature))?;

    // --- STEP 3: Verify attestation is not stale ---
    let current_slot = Clock::get()?.slot;
    require!(
        current_slot <= ctx.accounts.oracle_attestation.expiry_slot,
        OracleError::StaleAttestation   // Error 6019
    );

    // --- STEP 4: Verify sequence number (replay prevention) ---
    require!(
        ctx.accounts.oracle_attestation.sequence_number
            > ctx.accounts.custody_cache.last_sequence_number,
        OracleError::ReplayAttack
    );

    // --- STEP 5: THE CORE INVARIANT CHECK ---
    // Get current on-chain circulating supply from mint account
    let on_chain_supply = ctx.accounts.mint.supply;

    // Get custodied shares from verified attestation
    let custodied_shares = ctx.accounts.oracle_attestation.custodied_shares;

    // Verify invariant: supply <= custody
    // Allow 0.01% tolerance for timing edge cases (MAX_DISCREPANCY_BPS = 1)
    let max_allowed_supply = custodied_shares
        .checked_add(
            custodied_shares
                .checked_mul(MAX_DISCREPANCY_BPS)
                .ok_or(OracleError::Overflow)?
                .checked_div(10_000)
                .ok_or(OracleError::Overflow)?
        )
        .ok_or(OracleError::Overflow)?;

    require!(
        on_chain_supply <= max_allowed_supply,
        TransferHookError::CustodyDiscrepancy   // Error 6001 β€” HALT
    );

    // --- STEP 6: Verify post-transfer supply still within bounds ---
    // After this transfer, supply does not change (it's a transfer not a mint)
    // But verify amount_in does not exceed available custodied backing
    let post_transfer_supply = on_chain_supply; // transfers don't change supply
    require!(
        post_transfer_supply <= custodied_shares,
        TransferHookError::CustodyDiscrepancy
    );

    // --- STEP 7: Update on-chain cache with latest attestation ---
    // CEI pattern: all checks complete β€” now write state
    let cache = &mut ctx.accounts.custody_cache;
    cache.custodied_shares = custodied_shares;
    cache.last_updated_slot = current_slot;
    cache.last_sequence_number = ctx.accounts.oracle_attestation.sequence_number;
    cache.ledger_state_hash = ctx.accounts.oracle_attestation.ledger_state_hash;

    Ok(())
}

Quarterly Public Proof-of-Reserve Audit

In addition to per-slot on-chain verification, OTCM publishes a quarterly public proof-of-reserve:

Component

Frequency

Published At

Verifiable By

Empire ledger state hash

Quarterly

otcm.io/proof-of-reserve

Anyone with Empire ledger export

On-chain supply snapshot

Continuous

Solana block explorer

Anyone

Signed custody attestation archive

Quarterly

IPFS + Arweave

Anyone with Empire public key

Third-party attestation (auditor)

Annual

SEC EDGAR (8-K)

Anyone

Public Verification Procedure:

bash

# Anyone can verify the 1:1 backing at any point in time:

# Step 1 β€” Query on-chain supply for a specific ST22 mint
spl-token supply

# Step 2 β€” Fetch latest custody attestation from on-chain cache
solana account  --output json

# Step 3 β€” Verify Empire signature using public key
otcm-verify-custody   --attestation    --pubkey

# Step 4 β€” Compare: on-chain supply <= custodied_shares
# Any discrepancy should be reported immediately to security@otcm.io

πŸ”Ή 3.3.3 Discrepancy Detection

The hook implements strict discrepancy detection with configurable thresholds:

// Custody Verification Implementation (Rust/Anchor)

pub const MAX_DISCREPANCY_BPS: u64 = 1; // 0.01% maximum discrepancy

pub fn verify_custody(

oracle_data: &CustodyOracleData,

transfer_amount: u64,

) -> Result<()> {

// Verify signature authenticity

verify_ed25519_signature(

&oracle_data.attestation_signature,

&EMPIRE_PUBLIC_KEY,

&oracle_data.serialize(),

)?;

// Check attestation freshness (max 10 minutes old)
let current_time = Clock::get()?.unix_timestamp;
require!(

current_time - oracle_data.attestation_timestamp <= 600,

CustodyError::StaleAttestation // 6001

);

// Calculate discrepancy
let expected_tokens = oracle_data.custodied_balance;
let actual_tokens = oracle_data.circulating_tokens;
let discrepancy = if expected_tokens > actual_tokens {

expected_tokens - actual_tokens

} else {

actual_tokens - expected_tokens

};

let discrepancy_bps = discrepancy * 10000 / expected_tokens;
require!(

discrepancy_bps <= MAX_DISCREPANCY_BPS,

CustodyError::CustodyDiscrepancy // 6001

);

// Verify sufficient custody for this transfer
require!(

oracle_data.custodied_balance >= transfer_amount,

CustodyError::InsufficientCustody // 6001

);

Ok(())

}

πŸ“‹ Regulatory Reference: 17 CFR Section 240.17a-1 et seq. β€” Transfer Agent Custody Requirements

βœ— Error Code 6001: CUSTODY_VERIFICATION_FAILED

Indicates custody verification failure. Possible causes: stale attestation (>10 min), discrepancy >0.01%, insufficient custodied shares, or invalid Empire signature. User should wait for fresh attestation or contact issuer.

πŸ”— 3.4 Hook 2: OFAC Sanctions Screening

The OFAC Sanctions Screening hook prevents transactions to or from wallets associated with the Office of Foreign Assets Control's Specially Designated Nationals (SDN) list, implementing federal sanctions law requirements at the protocol level.

πŸ”Ή 3.4.1 SDN List Integration

OTCM maintains an on-chain oracle updated hourly from OFAC's official SDN list, supplemented by blockchain-specific address intelligence:

// OFAC Screening Implementation

pub struct OfacOracleData {

/// Merkle root of current SDN list

pub sdn_merkle_root: [u8; 32],

/// Number of entries in SDN list

pub sdn_entry_count: u32,

/// Blockchain-specific blocked addresses

pub crypto_sdn_addresses: Vec<Pubkey>,

/// Last update timestamp

pub last_update: i64,

/// OFAC publication reference

pub publication_id: [u8; 16],

}

// Screening checks BOTH sender and recipient
pub fn screen_ofac(

sender: &Pubkey,

recipient: &Pubkey,

oracle: &OfacOracleData,

) -> Result<OfacScreeningResult> {

// Direct address matching
let sender_blocked = oracle.crypto_sdn_addresses.contains(sender);
let recipient_blocked = oracle.crypto_sdn_addresses.contains(recipient);

if sender_blocked || recipient_blocked {

return Err(OfacError::SanctionedAddress.into()); // 6002

}

// Address clustering analysis (see 3.4.2)

check_cluster_association(sender, recipient, oracle)?;

Ok(OfacScreeningResult::Clear)

}

πŸ”Ή 3.4.2 Address Clustering Analysis

Beyond direct SDN address matching, OTCM implements sophisticated address clustering analysis to detect wallets associated with sanctioned entities:

  • Funding Source Analysis: Traces wallet funding sources to identify indirect SDN connections
  • Common Ownership Detection: Identifies wallets controlled by same entity through transaction pattern analysis
  • Mixer/Tumbler Detection: Flags wallets with significant exposure to known mixing services
  • High-Risk Jurisdiction Exposure: Elevated scrutiny for wallets with connections to OFAC-sanctioned jurisdictions

πŸ”Ή 3.4.3 Implementation

// Cluster Analysis Implementation
pub fn check_cluster_association(

sender: &Pubkey,

recipient: &Pubkey,

oracle: &OfacOracleData,

) -> Result<()> {

// Query clustering oracle for both addresses
let sender_cluster = get_cluster_data(sender)?;
let recipient_cluster = get_cluster_data(recipient)?;
// Check for SDN cluster membership

if sender_cluster.sdn_association_score > 70 {

return Err(OfacError::ClusterAssociation {

address: *sender,

score: sender_cluster.sdn_association_score,

reason: "High SDN cluster association".to_string(),

}.into());

}

if recipient_cluster.sdn_association_score > 70 {

return Err(OfacError::ClusterAssociation {

address: *recipient,

score: recipient_cluster.sdn_association_score,

reason: "High SDN cluster association".to_string(),

}.into());

}

Ok(())

}

πŸ“‹ Regulatory Reference: 31 CFR Β§ 500-598 β€” OFAC Sanctions Administration Regulations

βœ— Error Code 6002: OFAC_SANCTIONS_MATCH

Indicates wallet is blocked due to OFAC sanctions. This is a PERMANENT blockβ€”the wallet cannot transact ST22 tokens. There is no appeal process through OTCM; affected parties must resolve sanctions status with OFAC directly.

πŸ”— 3.5 Hook 3: Blockchain Analytics Screening

The Blockchain Analytics Screening hook implements Bank Secrecy Act Anti-Money Laundering (AML) requirements through machine learning-based risk assessment, analyzing 200+ transaction features to identify money laundering patterns, sanctions evasion, theft proceeds, and coordinated suspicious activity.

πŸ”Ή 3.3.1 ML Risk Assessment

OTCM integrates with institutional-grade blockchain analytics providers to execute real-time risk assessment on every transfer:

// AML Risk Assessment Data Structure

pub struct AmlRiskAssessment {

/// Overall risk score (0-100)

pub risk_score: u8,

/// Risk category breakdown

pub categories: AmlRiskCategories,

/// Specific risk flags triggered

pub triggered_flags: Vec<AmlFlag>,

/// Confidence in assessment

pub confidence: u8,

/// Model version used

pub model_version: [u8; 8],

}

pub struct AmlRiskCategories {

pub sanctions_evasion: u8, // 0-100

pub money_laundering: u8, // 0-100

pub theft_proceeds: u8, // 0-100

pub darknet_exposure: u8, // 0-100

pub mixer_exposure: u8, // 0-100

pub gambling_exposure: u8, // 0-100

pub coordinated_activity: u8, // 0-100

}

πŸ”Ή 3.3.2 Risk Scoring Model

The risk scoring model classifies transactions into three tiers with automated responses:

Score

Risk Level

Automated Action

Follow-up

0-30

Low

Auto-approve

None required

31-70

Medium

Enhanced review queue

Manual analyst review within 24h

71-100

High

Auto-reject (Error 6003)

SAR filing evaluation

πŸ”Ή 5.3.3 Chainalysis/TRM Integration

OTCM integrates with industry-leading blockchain analytics providers:

  • Chainalysis KYT (Know Your Transaction): Real-time transaction screening with 15-second SLA
  • TRM Labs Forensics: Deep historical analysis and entity resolution
  • Elliptic Navigator: Cross-chain exposure analysis for multi-chain actors

πŸ”Ή 5.3.4 Implementation

// AML Screening Implementation

pub const LOW_RISK_THRESHOLD: u8 = 30;

pub const HIGH_RISK_THRESHOLD: u8 = 71;

pub fn screen_aml(

sender: &Pubkey,

recipient: &Pubkey,

amount: u64,

) -> Result<AmlScreeningResult> {

// Query analytics providers
let sender_risk = query_chainalysis(sender)?;
let recipient_risk = query_chainalysis(recipient)?;
// Use higher of two risk scores
let max_risk = sender_risk.risk_score.max(recipient_risk.risk_score);

match max_risk {

0..=30 => Ok(AmlScreeningResult::AutoApprove),

31..=70 => {

// Queue for enhanced review but allow transaction
emit!(EnhancedReviewQueued {

sender: *sender,

recipient: *recipient,

risk_score: max_risk,

amount,

});

Ok(AmlScreeningResult::ApproveWithReview)

},

71..=100 => {

// Auto-reject high-risk transactions

Err(AmlError::RiskThresholdExceeded {

score: max_risk,

threshold: HIGH_RISK_THRESHOLD,

}.into()) // 6003

},

_ => unreachable!(),

}

}

πŸ“‹ Regulatory Reference: 31 CFR Β§ 1010 β€” Bank Secrecy Act AML Requirements

βœ— Error Code 6003: AML_RISK_EXCEEDED

Transaction rejected due to high AML risk score (71-100). Wallet may have exposure to: money laundering, sanctions evasion, theft proceeds, darknet markets, or coordinated suspicious activity. Appeal requires compliance review.

πŸ”— 3.6 Hook 4: Redemption Eligibility Verification

The Redemption Eligibility Verification hook implements a critical distinction in OTCM's compliance architecture: while permissionless trading allows any wallet to purchase and transfer ST22 tokens, redemption (conversion to underlying equity shares) requires investor verification in accordance with federal securities law.

πŸ”Ή 3.6.1 KYC/AML Requirements

Before a wallet can redeem ST22 tokens for underlying shares, the beneficial owner must complete comprehensive verification:

Requirement

Verification Method

Identity Verification

Government-issued photo ID + liveness check via Jumio/Onfido

Address Verification

Utility bill or bank statement within 90 days

SSN/TIN Verification

IRS W-9 form with SSN/TIN matching

Sanctions Screening

72-hour waiting period after initial OFAC/SDN clear

PEP Screening

Politically Exposed Person database check

πŸ”Ή 3.6.2 Accredited Investor Verification

For offerings conducted under SEC Regulation D Rule 506(c), additional accreditation verification is required:

// Accreditation Status Types

pub enum AccreditationStatus {

/// Not verified - cannot redeem Reg D offerings

NotVerified,

/// Verified accredited investor

Accredited {

method: AccreditationMethod,

verification_date: i64,

expiration_date: i64, // Typically 90 days

verifier: String, // e.g., "VerifyInvestor.com"

},

/// Non-accredited but permitted (Reg A+ or Reg CF)

NonAccreditedPermitted {

regulation: OfferingRegulation,

investment_limit: u64,

},

}

pub enum AccreditationMethod {

Income, // $200K/$300K annual income

NetWorth, // $1M+ net worth excluding residence

Professional, // Series 7, 65, or 82 license

Entity, // Qualified entity (bank, trust, etc.)

KnowledgeTest, // SEC proposed "accreditation exam"

}

πŸ”Ή 3.6.3 Implementation

// Redemption Eligibility Verification
pub fn verify_redemption_eligibility(

wallet: &Pubkey,

token_mint: &Pubkey,

amount: u64,

) -> Result<()> {

// Load investor record
let investor = get_investor_record(wallet)?;
// Check KYC completion
require!(

investor.kyc_status == KycStatus::Verified,

RedemptionError::KycIncomplete // 6004

);

// Check 72-hour sanctions cooling period
let current_time = Clock::get()?.unix_timestamp;
let cooling_period = 72 * 60 * 60;  // 72 hours in seconds
require!(

current_time - investor.sanctions_clear_timestamp >= cooling_period,

RedemptionError::SanctionsCoolingPeriod // 6004

);

// Load offering details
let offering = get_offering_details(token_mint)?;
// Check accreditation if Reg D 506(c)

if offering.regulation == Regulation::RegD506c {

match &investor.accreditation {

AccreditationStatus::Accredited { expiration_date, .. } => {

require!(

current_time < *expiration_date,

RedemptionError::AccreditationExpired // 6004

);

},

_ => {

return Err(RedemptionError::AccreditationRequired.into());

}

}

}

Ok(())

}

πŸ“‹ Regulatory Reference: 17 CFR 230.506(c) β€” Regulation D Accredited Investor Requirements

βœ— Error Code 6004: REDEMPTION_ELIGIBILITY_FAILED

Wallet not eligible for redemption. Possible causes: KYC incomplete, sanctions cooling period active (<72h), accreditation expired/missing for Reg D offerings. Note: Trading is still permitted; only redemption to shares is blocked.

πŸ”— 3.7 Hook 5: Price Impact Circuit Breaker

The Price Impact Circuit Breaker prevents single transactions from causing excessive market movement, implementing regulatory objectives prohibiting manipulative trading devices. Any transaction causing greater than 2% price movement against the Time-Weighted Average Price (TWAP) oracle is automatically rejected.

πŸ”Ή 3.7.1 TWAP Oracle Integration

The TWAP oracle provides manipulation-resistant reference pricing:

// TWAP Oracle Implementation

pub struct TwapOracle {

pub token_mint: Pubkey,

/// Rolling 1-hour TWAP

pub twap_1h: u64,

/// Rolling 24-hour TWAP

pub twap_24h: u64,

/// Number of observations in window

pub observation_count: u32,

/// Minimum observations required

pub min_observations: u32,

/// Last update slot

pub last_update_slot: u64,

}

impl TwapOracle {

pub fn get_reference_price(&self) -> Result<u64> {
// Use shorter TWAP for more responsive circuit breakers
// but require minimum observations to prevent manipulation
require!(

self.observation_count >= self.min_observations,

OracleError::InsufficientObservations

);

Ok(self.twap_1h)

}

}

πŸ”Ή 3.7.2 2% Threshold Enforcement

The 2% threshold forces large market participants to execute trades gradually, preventing sudden price dislocations:

// Price Impact Circuit Breaker Implementation

pub const MAX_PRICE_IMPACT_BPS: u64 = 200; // 2.00%

pub fn check_price_impact(

pool: &LiquidityPool,

trade_amount: u64,

trade_direction: TradeDirection,

) -> Result<()> {

// Get TWAP reference price
let twap = pool.twap_oracle.get_reference_price()?;
// Calculate expected post-trade price using CPMM formula
let (new_sol_reserve, new_token_reserve) = match trade_direction {

TradeDirection::Buy => (

pool.sol_reserve + trade_amount,

pool.token_reserve - calculate_output(trade_amount, pool)?,

),

TradeDirection::Sell => (

pool.sol_reserve - calculate_output(trade_amount, pool)?,

pool.token_reserve + trade_amount,

),

};

let post_trade_price = new_sol_reserve * 1_000_000_000 / new_token_reserve;
// Calculate deviation from TWAP
let deviation = if post_trade_price > twap {

(post_trade_price - twap) * 10000 / twap

} else {

(twap - post_trade_price) * 10000 / twap

};

require!(

deviation <= MAX_PRICE_IMPACT_BPS,

CircuitBreakerError::PriceImpactExceeded {

expected_impact_bps: deviation,

max_allowed_bps: MAX_PRICE_IMPACT_BPS,

} // 6006

);

Ok(())

}

πŸ“‹ Regulatory Reference: 17 CFR 240.10b-5(b) β€” Prohibition on Manipulative Trading Devices

βœ— Error Code 6006: PRICE_IMPACT_EXCEEDED

Transaction would cause >2% price movement from TWAP. User should reduce trade size or split into multiple smaller transactions. This protects all market participants from sudden price manipulation.

πŸ”— 3.8 Hook 6: Liquidity Pool Sufficiency

The Liquidity Pool Sufficiency hook ensures the OTCM Liquidity Pool maintains adequate reserves to support all outstanding ST22 tokens. The hook confirms the pool maintains a minimum 150% ratio of locked capital to circulating ST22 value before allowing redemption transactions.

πŸ”Ή 3.8.1 150% Ratio Requirement

The 150% over-collateralization provides a safety buffer ensuring redemptions can always be honored:

Component

Calculation

Locked Capital

Total SOL in unified LP (permanently locked)

Circulating Value

Sum of (ST22 supply Γ— current price) for all tokens

Sufficiency Ratio

Locked Capital / Circulating Value Γ— 100%

Minimum Required

β‰₯ 150% β€” redemptions pause if below

πŸ”Ή 3.8.2 Implementation

// Liquidity Sufficiency Check

pub const MIN_SUFFICIENCY_RATIO_BPS: u64 = 15000; // 150%

pub fn check_liquidity_sufficiency(

pool: &UnifiedLiquidityPool,

redemption_amount: u64,

) -> Result<()> {

// Calculate current ratio
let locked_capital = pool.total_sol_reserve;
let circulating_value = calculate_total_circulating_value(pool)?;
// Add redemption impact
let post_redemption_capital = locked_capital - redemption_amount;
let post_redemption_ratio = post_redemption_capital * 10000 / circulating_value;
require!(

post_redemption_ratio >= MIN_SUFFICIENCY_RATIO_BPS,

LiquidityError::InsufficientLiquidity {

current_ratio: post_redemption_ratio,

required_ratio: MIN_SUFFICIENCY_RATIO_BPS,

} // 6007

);

Ok(())

}

πŸ“‹ Regulatory Reference: Securities Exchange Act Rule 15c2-11 β€” Capital Adequacy Requirements

βœ— Error Code 6007: LIQUIDITY_INSUFFICIENT

Pool ratio below 150% threshold. Redemptions temporarily paused until trading volume rebuilds reserves. Regular ST22 trading (non-redemption) remains permitted. Users can wait for ratio recovery or reduce redemption amount.

πŸ›‘οΈ 3.9 Thirty-Six Supplementary Security Controls

Beyond the six primary Transfer Hooks, OTCM implements thirty-six supplementary security controls integrated into the transfer hook logic, creating a comprehensive 42-point security framework.

πŸ”Ή 3.9.1 Smart Contract Controls (1-6)

#

Control

Description

1

Formal Verification

Certora Prover mathematical proof of contract correctness

2

Multi-Audit Requirement

Independent audits by Quantstamp, Halborn, and OtterSec

3

Immutable Bytecode

No proxy patternβ€”code cannot be changed post-deployment

4

Bug Bounty Program

Up to $500K rewards for critical vulnerabilities

5

Reentrancy Guards

Check-Effects-Interactions pattern enforcement

6

Integer Overflow Protection

Rust's checked arithmetic prevents overflow attacks

πŸ”Ή 3.9.2 Access Control Framework (7-12)

#

Control

Description

7

Multi-Sig Administration

4-of-7 threshold for administrative actions

8

Timelock Delays

48-hour delay on all parameter changes

9

Role-Based Access

Granular permission system (operator, compliance, admin)

10

Emergency Pause

2-of-7 emergency pause with 24hr auto-unpause

11

DAO Override

2/3 supermajority required for lock override

12

Key Rotation

Quarterly key rotation with HSM backing

πŸ”Ή 3.9.3 Transaction Integrity Controls (13-18)

  1. Atomic Execution: All-or-nothing transaction commitment
  2. Orphan Prevention: No partial execution states possible
  3. Replay Protection: Unique transaction signatures prevent replay
  4. Deadline Enforcement: Transactions expire after specified block height
  5. Slippage Protection: User-configurable maximum price deviation

πŸ”Ή 3.9.4 Oracle & Data Controls (19-24)

  1. Multi-Oracle Consensus: Cross-reference multiple data sources
  2. Staleness Detection: Reject data older than threshold (10 min)
  3. Signature Verification: Ed25519 verification of all oracle data
  4. Rate Limiting: Maximum oracle queries per block per mint
  5. Fallback Oracles: Automatic failover to backup data sources
  6. Data Freshness Proofs: On-chain attestation of data recency

πŸ”Ή 3.9.5 Monitoring & Alerting (25-30)

  1. Real-Time Monitoring: 24/7 transaction pattern analysis
  2. Anomaly Detection: ML-based unusual activity identification
  3. SEC Notification: Automatic reporting of compliance failures
  4. Compliance Dashboard: Real-time visibility for regulators
  5. Audit Log Export: On-demand historical data retrieval
  6. Alert Escalation: Tiered notification for severity levels

πŸ”Ή 3.9.6 Governance & Recovery (31-36)

  1. Proposal System: On-chain governance for parameter changes
  2. Voting Mechanism: Token-weighted voting with delegation
  3. Quorum Requirements: Minimum participation thresholds
  4. Veto Power: Compliance officer veto on security-relevant proposals
  5. Migration Capability: Controlled upgrade path for critical fixes
  6. Disaster Recovery: Documented procedures for catastrophic scenarios

❌ 3.10 Error Handling and Recovery

Code

Hook

Condition

User Action

6001

Custody

Discrepancy >0.01%

Wait, retry, contact issuer

6002

OFAC

Sanctioned address

PERMANENT β€” contact OFAC

6003

AML

Risk score 71-100

Request compliance review

6004

Redemption

KYC/accreditation issue

Complete verification

6006

Price Impact

>2% TWAP deviation

Reduce size, split trade

6007

Liquidity

<150% pool ratio

Wait for ratio recovery

⚑ 3.11 Performance Specifications

Metric

Value

Notes

Total Hook Latency

750-1,350ms

Sequential execution

Compute Units

~800,000 CU

Per complete transfer

Effective TPS

400-600

Compliance overhead

Oracle Cost/Transfer

$2-5

Chainalysis, Empire APIs

πŸ”’ CROSS-PROGRAM INVOCATION (CPI) SECURITY SPECIFICATION

CPI Boundary Map

Every CPI call in OTCM Transfer Hook programs is documented below. For each boundary, the privilege model, account validation, and escalation prevention mechanism is specified.

Calling Program

Target Program

CPI Type

Accounts Passed

Privilege Check

TransferHook

TokenProgram (SPL Token-2022)

invoke_signed

mint, source, dest, authority

PDA authority verified β€” no signer escalation

TransferHook

OracleRegistry

invoke

oracle_account, sequence_registry

Read-only β€” no write authority passed

TransferHook

AuditLog

invoke_signed

audit_pda, system_program

PDA bump verified β€” canonical bump enforced

CEDEX AMM

TransferHook

invoke

extra_account_metas

Hook invoked by token program β€” not directly by AMM

IssuersPortal

TokenProgram

invoke_signed

mint_authority_pda

Mint authority is PDA β€” program cannot overmint

Privilege Escalation Prevention: All OTCM programs use invoke_signed only when the signing PDA is owned by the calling program. No OTCM instruction passes a user-provided signer to a CPI target. The remaining_accounts field in Transfer Hook extra account metas is validated against an on-chain ExtraAccountMetaList PDA β€” client-supplied accounts that are not in this registry cause immediate instruction failure.

PDA Derivation Canonical Reference

All Program Derived Addresses used by OTCM Protocol follow strict canonical derivation paths. Canonical bump enforcement (using the first valid bump, not a client-supplied bump) is enforced on every instruction.

rust

// --- TRANSFER HOOK PDAs ---

/// Extra account metas list β€” required by SPL Token-2022 Transfer Hook spec
pub fn extra_account_metas_pda(mint: &Pubkey, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"extra-account-metas", mint.as_ref()],
        program_id,
    )
}

/// Per-token compliance state account
pub fn compliance_state_pda(mint: &Pubkey, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"compliance-state", mint.as_ref()],
        program_id,
    )
}

/// Per-wallet KYC/accreditation record
pub fn investor_record_pda(wallet: &Pubkey, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"investor-record", wallet.as_ref()],
        program_id,
    )
}

// --- ORACLE PDAs ---

/// Oracle sequence number registry β€” per oracle type
pub fn oracle_sequence_pda(oracle_type: u8, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"oracle-sequence", &[oracle_type]],
        program_id,
    )
}

/// Cached oracle attestation β€” latest valid message per oracle type
pub fn oracle_cache_pda(oracle_type: u8, mint: &Pubkey, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"oracle-cache", &[oracle_type], mint.as_ref()],
        program_id,
    )
}

// --- LIQUIDITY POOL PDAs ---

/// Sovereign LP pool state β€” per ST22 mint
pub fn lp_pool_state_pda(mint: &Pubkey, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"lp-pool-state", mint.as_ref()],
        program_id,
    )
}

/// Permanently locked LP token account β€” receives burned LP tokens
pub fn dead_lp_account_pda(mint: &Pubkey, program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"dead-lp", mint.as_ref()],
        program_id,
    )
}

// --- AUDIT LOG PDAs ---

/// Audit log entry β€” per transaction signature
pub fn audit_log_pda(tx_sig: &[u8; 64], program_id: &Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[b"audit-log", &tx_sig[..32]],
        program_id,
    )
}

Account Discriminator Registry

Anchor-generated 8-byte discriminators for all OTCM account types. Type confusion attacks (passing a valid account of the wrong type) are prevented by discriminator validation on every instruction.

Account Type

Discriminator (hex)

Program

Mutable

ComplianceState

a1 f3 07 2c 88 4e b1 d0

TransferHook

Yes

InvestorRecord

3b 9a c2 11 55 fe 07 44

TransferHook

Yes

OracleAttestation

c4 12 7a 38 f0 9d 22 b5

OracleRegistry

No

OracleSequenceRegistry

77 e8 01 4f 2d 6a b3 90

OracleRegistry

Yes

LpPoolState

58 3d aa 17 0c 84 f2 61

LiquidityPool

Yes

BondingCurveState

e9 04 b6 7c 13 2f 55 a8

BondingCurve

Yes

AuditLogEntry

2a 7f 03 c1 99 b4 8e d6

AuditLog

No

IssuanceRecord

6c 18 d5 40 aa 7b 33 f9

IssuersPortal

Yes

Note: Discriminators above are specification targets. Actual deployed values are generated by Anchor at compile time from sha256("account:")[..8] and must be verified against deployed program IDL before audit sign-off.

πŸ›‘οΈ SUPPLEMENTARY SECURITY CONTROLS β€” COMPLETE TECHNICAL SPECIFICATION

Controls 7–42 are enforced at the Transfer Hook layer. Each control is specified with its trigger condition, enforcement mechanism, and error code.

Control Classification

Class

Controls

Description

Account Integrity

7–13

Validate account ownership, sizes, and relationships

Transaction Integrity

14–20

Enforce transaction-level constraints

Market Integrity

21–27

Prevent manipulation and abnormal trading patterns

Operational Security

28–35

Logging, rate limiting, and operational controls

Emergency Controls

36–42

Circuit breakers and emergency response mechanisms

Controls 7–13: Account Integrity

#

Control

Trigger Condition

Enforcement

Error Code

7

Signer Verification

Transfer authority β‰  token account owner or valid delegate

Reject β€” invalid signer

6007

8

Account Owner Check

Any passed account not owned by expected program

Reject β€” wrong owner

6008

9

Mint Consistency

Source/dest token accounts reference different mints

Reject β€” mint mismatch

6009

10

Account Size Validation

Any account data length < minimum expected struct size

Reject β€” corrupt account

6010

11

Discriminator Validation

Account discriminator β‰  expected 8-byte prefix

Reject β€” type confusion

6011

12

Token Account State

Source or dest account in Frozen state

Reject β€” account frozen

6012

13

Delegate Scope Check

Delegated transfer amount > approved delegation amount

Reject β€” delegation exceeded

6013

Controls 14–20: Transaction Integrity

#

Control

Trigger Condition

Enforcement

Error Code

14

Zero-Amount Guard

Transfer amount = 0

Reject β€” zero transfer

6014

15

Self-Transfer Guard

Source wallet = destination wallet

Reject β€” self transfer

6015

16

Overflow Guard

Amount arithmetic produces u64 overflow

Reject β€” arithmetic overflow

6016

17

Atomic Execution

Any hook CPI fails mid-sequence

Full transaction revert

6017

18

Sequence Integrity

Hook execution order violated (hooks must run 1β†’6 in sequence)

Reject β€” hook order violation

6018

19

Timestamp Validity

Block timestamp > attestation expiry

Reject β€” stale attestation

6019

20

Duplicate Transaction

Same (source, dest, amount, slot) tuple seen within 10 slots

Reject β€” probable duplicate

6020

Controls 21–27: Market Integrity

#

Control

Trigger Condition

Enforcement

Error Code

21

Wash Trade Detection

Source and destination wallets share a verified KYC identity

Reject β€” wash trade

6021

22

Wallet Concentration Limit

Post-transfer balance > 5% of circulating supply

Reject β€” concentration limit

6022

23

Velocity Limit

Wallet transfers > 10 transactions within 100 slots

Reject β€” velocity exceeded

6023

24

Graduated Token Lock

Transfer of pre-graduation tokens before vesting cliff

Reject β€” locked tokens

6024

25

LP Drain Protection

Single transaction would reduce LP depth > 20%

Reject β€” LP drain attack

6025

26

Price Oracle Deviation

Submitted price deviates > 5% from TWAP oracle

Reject β€” price manipulation

6026

27

Coordinated Transfer Detection

>3 wallets with correlated transfer patterns in same slot

Flag + manual review

6027

Controls 28–35: Operational Security

#

Control

Trigger Condition

Enforcement

Error Code

28

Immutable Audit Log

Every successful/failed transfer

Write audit PDA entry β€” always

None (non-rejecting)

29

Rate Limit per Wallet

>50 transfer attempts per wallet per epoch (2.6 days)

Reject after threshold

6029

30

Rate Limit per Mint

>10,000 transfers per ST22 mint per slot

Reject until next slot

6030

31

Oracle Query Rate Limit

>22 oracle lookups per single transaction

Reject β€” oracle abuse

6031

32

Compute Budget Enforcement

Remaining CU < 50,000 before Hook 6

Reject β€” insufficient CU

6032

33

Account Rent Validation

Any account below rent-exempt minimum

Reject β€” rent depleted

6033

34

Program Version Check

Caller program version < minimum compatible version

Reject β€” version mismatch

6034

35

Key Rotation Compliance

Oracle signer key not in current oracle registry

Reject β€” unrecognized signer

6035

Controls 36–42: Emergency Controls

#

Control

Trigger Condition

Enforcement

Error Code

36

Global Circuit Breaker

Protocol-wide pause activated by 3-of-4 multisig

Reject all transfers

6036

37

Per-Mint Circuit Breaker

>30% price movement in single slot for specific ST22

Halt mint-specific transfers for 1 hour

6037

38

Custody Discrepancy Halt

Token supply > custodied shares (oracle verified)

Halt all transfers for affected mint

6038

39

OFAC Emergency Block

New OFAC SDN list entry matching active wallet

Immediate freeze β€” no grace period

6039

40

Oracle Consensus Failure

<2 of 3 oracle feeds available for >5 minutes

Halt affected hook category

6040

41

Controlled Migration

Emergency contract migration β€” 4-of-7 multisig + 48h timelock

Allow migration to new program

6041

42

Regulatory Compliance Override

Law enforcement or regulatory freeze order received

Comply per legal process

6042

Complete Error Code Registry

rust

#[error_code]
pub enum TransferHookError {
    // Hook 1: Custody Verification
    #[msg("Custody oracle: token supply exceeds custodied shares")]
    CustodyDiscrepancy = 6001,
    #[msg("Custody oracle: attestation unavailable or stale")]
    CustodyOracleUnavailable = 6002,

    // Hook 2: OFAC Screening
    #[msg("OFAC: sender wallet matches sanctions list")]
    SenderSanctioned = 6003,
    #[msg("OFAC: receiver wallet matches sanctions list")]
    ReceiverSanctioned = 6004,
    #[msg("OFAC: oracle data stale β€” cannot verify sanctions status")]
    OfacOracleStale = 6005,

    // Hook 3: AML Screening
    #[msg("AML: sender risk score exceeds threshold")]
    SenderHighRisk = 6006,

    // Controls 7–42 (see table above)
    InvalidSigner = 6007,
    WrongAccountOwner = 6008,
    MintMismatch = 6009,
    CorruptAccountSize = 6010,
    AccountTypeConfusion = 6011,
    AccountFrozen = 6012,
    DelegationExceeded = 6013,
    ZeroTransfer = 6014,
    SelfTransfer = 6015,
    ArithmeticOverflow = 6016,
    AtomicRevert = 6017,
    HookOrderViolation = 6018,
    StaleAttestation = 6019,
    ProbableDuplicate = 6020,
    WashTradeDetected = 6021,
    ConcentrationLimitExceeded = 6022,
    VelocityLimitExceeded = 6023,
    TokensLocked = 6024,
    LpDrainAttack = 6025,
    PriceManipulation = 6026,
    CoordinatedTransfer = 6027,
    // 6028: reserved
    WalletRateLimitExceeded = 6029,
    MintRateLimitExceeded = 6030,
    OracleQueryRateLimitExceeded = 6031,
    InsufficientComputeBudget = 6032,
    RentDepleted = 6033,
    ProgramVersionMismatch = 6034,
    UnrecognizedOracleSigner = 6035,
    GlobalCircuitBreaker = 6036,
    MintCircuitBreaker = 6037,
    CustodyDiscrepancyHalt = 6038,
    OfacEmergencyBlock = 6039,
    OracleConsensusFailed = 6040,
    ControlledMigration = 6041,
    RegulatoryFreeze = 6042,
}

🚨 INCIDENT RESPONSE AND OPERATIONAL MONITORING SPECIFICATION

Version: 6.0 | Classification: Critical Infrastructure Operations

Monitoring Stack

Layer

Tool

Metrics Collected

Alert Threshold

Solana RPC

Helius Webhooks + custom indexer

Transaction success rate, block lag, RPC latency

Success rate < 99% for 60s

Transfer Hook

On-chain event indexer (Geyser plugin)

Hook rejections by error code, CU consumption, execution time

>5% rejection rate per code per minute

Oracle Network

Custom oracle monitor

Attestation age, sequence gaps, consensus failures

Any oracle > staleness threshold

CEDEX AMM

Order flow metrics

Fill rate, slippage, LP depth, circuit breaker fires

LP depth drops >30% in 1 hour

API/Portal

Datadog APM

p95 latency, error rate, concurrent sessions

p95 > 500ms or error rate > 1%

Smart Contracts

Solana program log indexer

Error code frequency, account state anomalies

Any Error 6001 (custody) or 6036 (global halt)

Incident Severity Classification

Severity

Definition

Response Time

Escalation

P0 β€” Critical

Trading halted, custody discrepancy, global circuit breaker, active exploit

15 minutes

Immediate β€” all hands

P1 β€” High

Oracle consensus failure, >10% hook rejection rate, CEDEX order matching degraded

30 minutes

On-call engineer + CTO

P2 β€” Medium

Single oracle feed down, elevated latency, single hook degraded mode

2 hours

On-call engineer

P3 β€” Low

Non-critical monitoring alert, performance degradation, non-blocking error

Next business day

Ticket

P0 Incident Runbooks

Runbook P0-A: Custody Discrepancy (Error 6001 Active)

TRIGGER: Hook 1 returning Error 6001 β€” token supply exceeds custodied shares

IMMEDIATE ACTIONS (within 15 minutes):
  1. Confirm error is real β€” query on-chain token supply vs Empire oracle attestation
  2. Contact Empire Stock Transfer emergency line: [redacted β€” in secure ops runbook]
  3. Activate 3-of-5 Compliance Multisig to freeze all ST22 minting
  4. Post status update to OTCM Protocol status page
  5. Preserve all oracle attestation messages for forensic analysis

RESOLUTION PATH:
  A. If oracle error (attestation stale/malformed):
     β†’ Force oracle refresh via emergency oracle admin key
     β†’ Verify fresh attestation resolves discrepancy
     β†’ Lift circuit breaker after 2-of-3 oracle consensus confirmed

  B. If real custody gap (unauthorized minting):
     β†’ Engage legal counsel immediately
     β†’ File regulatory notification within 24 hours
     β†’ DO NOT lift circuit breaker until gap fully explained and closed

NEVER DO:
  - Do not lift the circuit breaker without resolving the root cause
  - Do not communicate cause publicly until forensics complete

Runbook P0-B: Global Circuit Breaker Activated (Error 6036)

TRIGGER: 3-of-4 emergency multisig has activated global trading halt

IMMEDIATE ACTIONS (within 15 minutes):
  1. Identify which multisig keyholders initiated the activation and why
  2. Assess scope β€” is this protocol-wide or mint-specific?
  3. Begin root cause analysis
  4. Post status update β€” "Trading temporarily paused for security review"

RESOLUTION PATH:
  A. Threat resolved β†’ 3-of-4 multisig signs deactivation transaction
  B. Threat ongoing β†’ maintain halt, engage incident response team
  C. False positive β†’ post-mortem required, governance proposal to prevent recurrence

SLA: Global halt must be resolved or publicly explained within 4 hours

Runbook P0-C: Active Smart Contract Exploit

TRIGGER: Anomalous fund movement detected, suspected exploit in progress

IMMEDIATE ACTIONS (within 15 minutes):
  1. Activate global circuit breaker immediately (Error 6036)
     β†’ Does NOT require root cause β€” halt first, investigate second
  2. Snapshot all affected account states at current slot
  3. Engage Halborn/Quantstamp emergency contact for triage support
  4. Preserve all transaction signatures for forensic analysis

DO NOT:
  - Do not attempt to "patch" on-chain state during active exploit
  - Do not communicate exploit details publicly until contained
  - Do not lift circuit breaker under any time pressure

RTO / RPO Targets

Component

RTO (Recovery Time Objective)

RPO (Recovery Point Objective)

Degraded Mode

Transfer Hook enforcement

Tied to Solana network

N/A β€” on-chain, always consistent

No degraded mode β€” transfers halt

CEDEX order matching

30 minutes

Zero β€” orders queued, not lost

Read-only order book visible

Oracle network (primary)

5 minutes

Last confirmed attestation

Secondary oracle takes over

Investor portal

1 hour

5 minutes (session state)

Read-only mode

API (external)

2 hours

15 minutes

Cached responses

Operational Monitoring Dashboards

PRODUCTION MONITORING STRUCTURE:

Dashboard 1: Protocol Health (always-on)
  β”œ--- Transfer Hook success rate (last 5 min, 1 hr, 24 hr)
  β”œ--- Error code frequency heatmap
  β”œ--- Oracle freshness indicators (all 3 tiers, all types)
  β”œ--- Circuit breaker status (green/red per mint + global)
  β””--- Active trading halts (count + duration)

Dashboard 2: CEDEX Trading (always-on)
  β”œ--- 24h volume per ST22 mint
  β”œ--- LP depth per pool (absolute + % change)
  β”œ--- Price impact per trade (p50, p95, p99)
  β”œ--- Graduation pipeline (mints approaching $250K MC)
  β””--- Fee revenue (real-time)

Dashboard 3: Security Events (always-on, SOC-24/7)
  β”œ--- OFAC screening hits (Error 6003/6004)
  β”œ--- AML high-risk events (Error 6006)
  β”œ--- Velocity limit hits (Error 6023)
  β”œ--- Concentration limit hits (Error 6022)
  β””--- Coordinated transfer flags (Error 6027)

πŸ”‘ KEY CUSTODIANSHIP REGISTER

Classification: Institutional Security Documentation Review Cadence: Quarterly or upon any keyholder change

Privileged Key Inventory

Key

Holder

Custody Type

Rotation Schedule

Emergency Replacement

Freeze Authority

Compliance Multisig (3-of-5)

AWS CloudHSM β€” dedicated partition

Annual + upon regulatory event

DAO vote β€” 48h timelock

Mint Authority

DISABLED

 β€” burned post-mint

N/A

N/A

Cannot be re-enabled

Program Upgrade Authority

Admin Multisig (4-of-7)

Ledger hardware β€” geographically distributed

Semi-annual

4-of-7 consensus required

Oracle Signing Keys

Per-oracle HSM partitions

AWS CloudHSM (primary), GCP CloudHSM (secondary)

Quarterly

HSM-to-HSM key ceremony

Treasury SOL Multisig

Treasury Multisig (3-of-5)

Ledger hardware β€” 5 keyholders

Annual

DAO vote β€” 72h timelock

LP Emergency Override

Emergency Multisig (4-of-7)

Ledger hardware β€” air-gapped signing

Used only in emergency

4-of-7 consensus + 48h timelock

Freeze Authority Specification

The Freeze Authority key grants the ability to freeze any ST22 token account, preventing outbound transfers while allowing inbound transfers. This is the most operationally sensitive key in the system.

Holder: Compliance Multisig β€” 3-of-5 threshold Permitted Use Cases:

  1. OFAC SDN list match β€” mandatory freeze, no discretion
  2. Active law enforcement hold order β€” mandatory freeze
  3. Court-ordered asset freeze β€” mandatory freeze
  4. SAR-trigger investigation hold β€” discretionary, compliance officer approval required

Prohibited Use Cases:

  • Competitive, commercial, or operational reasons
  • Retaliation or dispute resolution
  • Any use not related to regulatory compliance

Audit Requirement: Every freeze action generates an immutable on-chain audit record (Control 28) and a concurrent off-chain report to Empire Stock Transfer within 24 hours.

4-of-7 Admin Multisig Composition Requirements

The 7 keyholders for program upgrade and emergency override authority must satisfy the following distribution requirements to prevent simultaneous compromise:

Requirement

Specification

Geographic distribution

Minimum 4 distinct countries

Cloud provider distribution

No more than 2 keyholders on same cloud provider

Organizational distribution

Minimum 3 keyholders external to OTCM Protocol, Inc.

Hardware wallet requirement

All keyholders must use Ledger or equivalent FIPS 140-2 certified device

Key ceremony requirement

Initial keyholder setup must occur via documented key ceremony with legal witness

Replacement procedure

Lost keyholder: remaining 4-of-6 must authorize replacement via on-chain governance vote

Oracle Key Rotation Procedure

Oracle key rotation must occur without creating a gap in Transfer Hook validation. The following zero-downtime rotation procedure is mandatory:

PHASE 1 β€” Preparation (T-7 days):
  1. Generate new Ed25519 keypair in HSM β€” new_pubkey
  2. Submit on-chain governance transaction to ADD new_pubkey to oracle registry
  3. Oracle registry accepts both old_pubkey and new_pubkey for 7-day overlap window

PHASE 2 β€” Dual-Sign Period (T-0 to T+7 days):
  4. Oracle begins signing ALL attestations with BOTH old_key and new_key
  5. Both signatures included in attestation payload
  6. Transfer Hooks accept either signature during overlap window

PHASE 3 β€” Cutover (T+7 days):
  7. Submit on-chain governance transaction to REMOVE old_pubkey from oracle registry
  8. Oracle ceases signing with old_key
  9. old_key private key material destroyed via HSM key destruction ceremony
  10. HSM destruction certificate published on-chain as audit record

PHASE 4 β€” Verification (T+8 days):
  11. Verify 24-hour post-rotation: zero rejected transactions due to signature validation
  12. Rotation complete β€” update Key Custodianship Register

Rotation Window Safety: During Phase 2, if any Transfer Hook rejects a valid transaction due to key mismatch, the oracle immediately reverts to old_key exclusively and the rotation procedure restarts from Phase 1.

πŸ§ͺ SMART CONTRACT TEST COVERAGE SPECIFICATION

Version: 6.0 | Status: Pre-Mainnet Requirements β€” Must Be Met Before Launch Certification

Coverage Requirements

All OTCM Protocol smart contract programs must meet the following minimum test coverage thresholds before mainnet deployment certification. Coverage is measured using cargo-tarpaulin for unit tests and a custom integration test harness against a local validator.

Program

Unit Test Coverage

Integration Test Coverage

Fuzz Corpus Size

Status

TransferHook

β‰₯ 95% line coverage

All 42 controls tested

β‰₯ 10,000 inputs

Required pre-launch

CEDEX AMM

β‰₯ 92% line coverage

All order types + edge cases

β‰₯ 50,000 inputs

Required pre-launch

LiquidityPool (FLP)

β‰₯ 90% line coverage

Graduation + lock mechanics

β‰₯ 20,000 inputs

Required pre-launch

BondingCurve

β‰₯ 90% line coverage

Price invariant tests

β‰₯ 30,000 inputs

Required pre-launch

OracleRegistry

β‰₯ 95% line coverage

Consensus + replay tests

β‰₯ 5,000 inputs

Required pre-launch

IssuersPortal

β‰₯ 88% line coverage

KYC + accreditation flows

β‰₯ 5,000 inputs

Required pre-launch

Mandatory Test Categories

rust

// --- TRANSFER HOOK β€” Required Test Cases ---

#[cfg(test)]
mod transfer_hook_tests {
    // Hook 1 β€” Custody
    fn test_hook1_valid_custody();
    fn test_hook1_supply_exceeds_custody();      // Must reject with Error 6001
    fn test_hook1_oracle_unavailable();           // Must reject with Error 6002
    fn test_hook1_stale_attestation();            // Must reject with Error 6019
    fn test_hook1_replay_attack();                // Must reject with Error 6019

    // Hook 2 β€” OFAC
    fn test_hook2_clean_sender_receiver();
    fn test_hook2_sanctioned_sender();            // Must reject with Error 6003
    fn test_hook2_sanctioned_receiver();          // Must reject with Error 6004
    fn test_hook2_fuzzy_name_match();             // Near-match must trigger

    // Hook 5 β€” Price Impact
    fn test_hook5_within_2pct_limit();
    fn test_hook5_exceeds_2pct_limit();           // Must reject with Error 6026
    fn test_hook5_twap_unavailable();             // Must reject with Error 6040

    // Cross-hook interaction
    fn test_all_hooks_pass_valid_transfer();
    fn test_atomic_revert_on_hook3_fail();        // Hooks 1-2 pass, Hook 3 fails
    fn test_hook_ordering_enforced();             // Out-of-order hook call must fail

    // Controls 7–42
    fn test_control_7_invalid_signer();
    fn test_control_14_zero_amount();
    fn test_control_15_self_transfer();
    fn test_control_22_concentration_limit();
    fn test_control_36_global_circuit_breaker();
    // ... one test per control (42 total mandatory)
}

// --- CPMM AMM β€” Required Test Cases ---

#[cfg(test)]
mod amm_tests {
    fn test_swap_invariant_maintained();          // k must not decrease
    fn test_u128_no_overflow_at_max_reserves();  // MAX_SAFE_RESERVE Γ— MAX_SAFE_RESERVE
    fn test_rounding_direction_floor_output();
    fn test_fee_calculation_accuracy();
    fn test_graduation_atomic_migration();
    fn test_lp_tokens_burned_to_dead_address();
    fn test_permanent_lock_no_withdrawal();       // Attempt withdrawal must fail
}

Fuzz Testing Configuration

toml

# Cargo.toml fuzz configuration
[workspace.metadata.fuzz]
targets = [
    "fuzz_transfer_hook",     # Fuzz all 42 controls with random account states
    "fuzz_cpmm_swap",         # Fuzz reserve values from 1 to MAX_SAFE_RESERVE
    "fuzz_oracle_attestation",# Fuzz oracle payloads including malformed signatures
    "fuzz_bonding_curve",     # Fuzz token amounts across full price range
]
minimum_corpus_size = 10_000
max_total_time_seconds = 3_600  # 1 hour minimum per target pre-launch
crash_on_oom = true

Differential Testing Requirement

The CPMM calculate_swap_output function must be differentially tested against a reference Python implementation to verify that the Rust integer arithmetic produces results within 1 unit of precision of the floating-point reference:

python

# Reference implementation for differential testing
def calculate_swap_output_reference(amount_in, reserve_in, reserve_out, fee_bps):
    fee_numerator = 10000 - fee_bps
    amount_in_with_fee = amount_in * fee_numerator
    numerator = amount_in_with_fee * reserve_out
    denominator = reserve_in * 10000 + amount_in_with_fee
    return int(numerator / denominator)  # floor division matches Rust behavior

πŸ”— TRANSFER HOOK INTER-HOOK STATE MODEL

Version: 6.0 | Critical: Defines shared account access between hooks

Hook Isolation Guarantee

Each of the six Transfer Hooks is stateless with respect to the others during a single transaction execution. Hooks do NOT write shared mutable state that subsequent hooks read. This eliminates TOCTOU (time-of-check-time-of-use) vulnerabilities between hooks.

HOOK EXECUTION MODEL:

  Transaction Input Accounts (immutable snapshot for all hooks)
         β”‚
         β”œ---β–Ί Hook 1 reads: oracle_cache_pda (readonly), compliance_state (readonly)
         β”‚    Hook 1 writes: audit_log_pda (append-only)
         β”‚
         β”œ---β–Ί Hook 2 reads: ofac_oracle_pda (readonly), investor_record (readonly)
         β”‚    Hook 2 writes: audit_log_pda (append-only)
         β”‚
         β”œ---β–Ί Hook 3 reads: aml_oracle_pda (readonly), investor_record (readonly)
         β”‚    Hook 3 writes: audit_log_pda (append-only)
         β”‚
         β”œ---β–Ί Hook 4 reads: investor_record (readonly), compliance_state (readonly)
         β”‚    Hook 4 writes: audit_log_pda (append-only)
         β”‚
         β”œ---β–Ί Hook 5 reads: price_oracle_pda (readonly), lp_pool_state (readonly)
         β”‚    Hook 5 writes: audit_log_pda (append-only)
         β”‚
         β””---β–Ί Hook 6 reads: lp_pool_state (readonly)
              Hook 6 writes: audit_log_pda (append-only)

KEY PROPERTY: All cross-hook reads are from (readonly) accounts.
              No hook reads data that a prior hook has written in the same transaction.
              audit_log_pda is append-only β€” no hook reads what another hook wrote.

Account Mutability Map Per Hook

Account

Hook 1

Hook 2

Hook 3

Hook 4

Hook 5

Hook 6

oracle_cache_pda

 (custody)

R

β€”

β€”

β€”

β€”

β€”

ofac_oracle_pda

β€”

R

β€”

β€”

β€”

β€”

aml_oracle_pda

β€”

β€”

R

β€”

β€”

β€”

price_oracle_pda

β€”

β€”

β€”

β€”

R

β€”

investor_record_pda

β€”

R

R

R

β€”

β€”

compliance_state_pda

R

β€”

β€”

R

β€”

β€”

lp_pool_state_pda

β€”

β€”

β€”

β€”

R

R

audit_log_pda

W

W

W

W

W

W

sequence_registry_pda

W

β€”

β€”

β€”

β€”

β€”

R = Read-only access | W = Write access | β€” = Not accessed

COMPUTE UNIT BUDGET SPECIFICATION

Version: 6.0 | Status: Pre-Mainnet Benchmarks Required Before Launch

All OTCM Protocol transactions prepend a ComputeBudgetInstruction::set_compute_unit_limit instruction. Total transaction CU must remain below Solana's 1,400,000 CU hard cap under all conditions.

Component

Operation

Measured CU (avg)

Worst-Case CU

Hook 1

Custody oracle balance read

~18,000

28,000

Hook 2

OFAC fuzzy name match

~95,000

140,000

Hook 3

AML risk score lookup

~22,000

35,000

Hook 4

KYC/accreditation PDA check

~14,000

20,000

Hook 5

TWAP + 2% impact calculation

~45,000

68,000

Hook 6

LP reserve sufficiency check

~12,000

18,000

Base AMM

CPMM swap logic

~180,000

220,000

Account validation

Discriminator + owner checks

~15,000

22,000

Audit logging

On-chain event emission

~8,000

12,000

TOTAL


~409,000

~563,000 (40% of cap)

Priority Fee Strategy: Dynamic fee computed as base_fee x clamp(recent_fee_p75 / base_fee, 1.0, 10.0). Transactions resubmitted with escalating fees at 5-second intervals, up to 3 retries before returning TRANSACTION_TIMEOUT.

Pre-Launch Requirement: All six Transfer Hook programs must complete CU profiling under worst-case conditions (500-entry OFAC list, minimum LP depth) before mainnet certification.

ORACLE MESSAGE AUTHENTICATION SPECIFICATION

See oracle authentication details in Oracle Fault Tolerance section.

πŸ”’ REENTRANCY PROTECTION β€” CHECKS-EFFECTS-INTERACTIONS SPECIFICATION

Version: 6.0 | Applies To: All OTCM Anchor programs

Why Reentrancy Matters on Solana

Unlike Ethereum where reentrancy is a well-understood attack vector via fallback functions, Solana's account model creates different reentrancy risks through Cross-Program Invocations (CPIs). A malicious program invoked via CPI can call back into the invoking program before state mutations complete β€” creating a classic TOCTOU vulnerability. OTCM enforces the Checks-Effects-Interactions (CEI) pattern on every instruction that performs CPIs.

CEI Pattern Enforcement

rust

/// CORRECT β€” CEI pattern enforced
pub fn process_swap(ctx: Context, amount_in: u64) -> Result<()> {
    // --- CHECKS ---
    // 1. Validate all account constraints (Anchor #[account] macros)
    // 2. Verify oracle data freshness and consensus
    // 3. Compute output amount β€” read-only, no state changes
    let amount_out = calculate_swap_output(
        amount_in,
        ctx.accounts.pool.sol_reserve,
        ctx.accounts.pool.token_reserve,
        ctx.accounts.pool.fee_bps,
    )?;

    // Verify circuit breaker β€” no state write yet
    let price_impact = compute_price_impact(amount_in, ctx.accounts.pool.sol_reserve)?;
    require!(price_impact <= MAX_PRICE_IMPACT_BPS, AmmError::PriceImpactExceeded);

    // --- EFFECTS ---
    // 4. Write ALL state mutations BEFORE any CPI calls
    // State is fully consistent before any external call can observe it
    let pool = &mut ctx.accounts.pool;
    pool.sol_reserve = pool.sol_reserve
        .checked_add(amount_in)
        .ok_or(AmmError::Overflow)?;
    pool.token_reserve = pool.token_reserve
        .checked_sub(amount_out)
        .ok_or(AmmError::Underflow)?;
    pool.k_invariant = (pool.sol_reserve as u128)
        .checked_mul(pool.token_reserve as u128)
        .ok_or(AmmError::Overflow)?;
    pool.last_swap_slot = Clock::get()?.slot;

    // --- INTERACTIONS ---
    // 5. Execute CPIs ONLY after all state mutations are complete
    // If CPI calls back into this program, state is already correct
    token::transfer(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            token::Transfer {
                from: ctx.accounts.pool_token_account.to_account_info(),
                to: ctx.accounts.user_token_account.to_account_info(),
                authority: ctx.accounts.pool_authority.to_account_info(),
            },
        ),
        amount_out,
    )?;

    // Emit audit event last β€” read-only CPI, no state impact
    emit!(SwapExecuted {
        user: ctx.accounts.user.key(),
        amount_in,
        amount_out,
        slot: Clock::get()?.slot,
    });

    Ok(())
}

/// INCORRECT pattern β€” NEVER use this
/// pub fn process_swap_WRONG(ctx: Context, amount_in: u64) -> Result<()> {
///     let amount_out = calculate_swap_output(...)?;
///     // CPI BEFORE state mutation β€” reentrancy window open
///     token::transfer(cpi_ctx, amount_out)?;  // <-- WRONG
///     pool.sol_reserve += amount_in;           // <-- state written after CPI
///     Ok(())
/// }

Reentrancy Guard β€” Mutex Pattern

For instructions where CEI cannot be strictly enforced (e.g. multi-step operations), a per-account mutex is implemented:

rust

#[account]
pub struct PoolState {
    // ... other fields ...
    /// Reentrancy guard β€” set to true on entry, false on exit
    /// Prevents recursive invocation of pool instructions
    pub locked: bool,
}

/// Reentrancy guard macro β€” wrap any instruction using CPIs
macro_rules! reentrancy_guard {
    ($account:expr, $body:block) => {{
        require!(!$account.locked, AmmError::ReentrantCall);
        $account.locked = true;
        let result = { $body };
        $account.locked = false;
        result
    }};
}

// Usage in instruction handler:
pub fn complex_operation(ctx: Context) -> Result<()> {
    reentrancy_guard!(ctx.accounts.pool, {
        // ... instruction body with CPIs ...
        Ok(())
    })
}

CEI Compliance Checklist β€” Required for Audit Sign-off

Before audit certification, every instruction in every OTCM program must pass the following checklist:

Check

Requirement

No CPI before state write

All pool/account state mutations occur before first CPI

No re-read after CPI

State read for decision logic uses pre-CPI snapshot, not post-CPI state

Reentrancy guard on complex ops

Any instruction with >1 CPI uses mutex guard

Invariant verification post-CPI

k invariant verified after token transfer CPI completes

Emit events last

All

emit!()

 calls are the final statements in the instruction

πŸ›‘οΈ 3.12 Security Audit Status

  • Quantstamp:

    Audit scheduledProgram β€” Pre-Mainnet Certification Gates

    All four audit engagements below are hard launch gates. Mainnet deployment is prohibited until every gate is cleared and each firm issues a final report with zero open Critical or High severity findings.

    Firm

    Scope

    Status

    Gate Requirement

    Quantstamp

    TransferHook programs (all 42 controls), CEDEX AMM, LiquidityPool

    Engagement initiated Q1 2026

  • Halborn:

  • Final report β€” 0 Critical/High open

    Halborn

    Oracle network, key management, infrastructure penetration test

    Engagement in progress

  • OtterSec:

  • Final report β€” 0 Critical/High open

    OtterSec

    BondingCurve, IssuersPortal, staking contracts

    Preliminary review complete

  •  β€” full audit Q2 2026

  • Final report β€” 0 Critical/High open

    Certora 

    Formal Verification:verification of CPMM invariant (x*y=k), Transfer Hook atomicity, LP lock permanence

    Specification complete β€” proof development underwayQ1 2026

    All specified invariants proved β€” no counterexamples

    Bug Bounty Program

    Active bug bounty required minimum 30 days before mainnet launch.

    Severity

    Reward

    Example Vulnerability

    Critical

    Up to $100,000

    Transfer Hook bypass, LP fund extraction, mint authority exploit

    High

    Up to $25,000

    Oracle replay attack, CPI privilege escalation, freeze authority bypass

    Medium

    Up to $5,000

    Circuit breaker bypass, rate limit evasion, account spoofing

    Low

    Up to $500

    Gas optimization issues, non-critical logic errors

    Submissions: security@otcm.io β€” PGP key published at otcm.io/security.txt Scope: All on-chain programs, oracle infrastructure, CEDEX order matching engine Out of scope: Frontend UI, third-party dependencies, known issues in public tracker

    • Bug Bounty: $500K program launching with mainnet ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━---