π 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
}
// 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)
/// 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 | |
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)
- Atomic Execution: All-or-nothing transaction commitment
- Orphan Prevention: No partial execution states possible
- Replay Protection: Unique transaction signatures prevent replay
- Deadline Enforcement: Transactions expire after specified block height
- Slippage Protection: User-configurable maximum price deviation
πΉ 3.9.4 Oracle & Data Controls (19-24)
- Multi-Oracle Consensus: Cross-reference multiple data sources
- Staleness Detection: Reject data older than threshold (10 min)
- Signature Verification: Ed25519 verification of all oracle data
- Rate Limiting: Maximum oracle queries per block per mint
- Fallback Oracles: Automatic failover to backup data sources
- Data Freshness Proofs: On-chain attestation of data recency
πΉ 3.9.5 Monitoring & Alerting (25-30)
- Real-Time Monitoring: 24/7 transaction pattern analysis
- Anomaly Detection: ML-based unusual activity identification
- SEC Notification: Automatic reporting of compliance failures
- Compliance Dashboard: Real-time visibility for regulators
- Audit Log Export: On-demand historical data retrieval
- Alert Escalation: Tiered notification for severity levels
πΉ 3.9.6 Governance & Recovery (31-36)
- Proposal System: On-chain governance for parameter changes
- Voting Mechanism: Token-weighted voting with delegation
- Quorum Requirements: Minimum participation thresholds
- Veto Power: Compliance officer veto on security-relevant proposals
- Migration Capability: Controlled upgrade path for critical fixes
- 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 |
|---|---|---|---|
|
| TransferHook | Yes |
|
| TransferHook | Yes |
|
| OracleRegistry | No |
|
| OracleRegistry | Yes |
|
| LiquidityPool | Yes |
|
| BondingCurve | Yes |
|
| AuditLog | No |
|
| 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
Holder: Compliance Multisig β 3-of-5 threshold Permitted Use Cases:
- OFAC SDN list match β mandatory freeze, no discretion
- Active law enforcement hold order β mandatory freeze
- Court-ordered asset freeze β mandatory freeze
- 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 |
|---|---|---|---|---|---|---|
(custody) | R | β | β | β | β | β |
| β | R | β | β | β | β |
| β | β | R | β | β | β |
| β | β | β | β | R | β |
| β | R | R | R | β | β |
| R | β | β | R | β | β |
| β | β | β | β | R | R |
| W | W | W | W | W | W |
| 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
calls are the final statements in the instruction |
π‘οΈ 3.12 Security Audit Status
Quantstamp:Audit
scheduledProgram β Pre-Mainnet Certification GatesAll 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 permanenceSpecification complete β proof development
underwayQ1 2026All 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
βββββββββββββββββββββββββββββββββββββ---