Skip to main content

Section 3: SPL Token-2022 Transfer Hooks — Layer 2

The complete technical specification for OTCM Protocol’s 42-control Transfer Hook security architecture — the foundational compliance enforcement mechanism that makes regulatory bypass structurally impossible.

Metric

Value

Document reference

OTCM-TH-SPEC-001 v3.0 (aligned with Whitepaper V8.0)

Total security controls

42

Transfer coverage

100% — every ST22 transfer invokes all 42 controls

Bypass possibility

Zero — enforced at SPL Token-2022 program level

Target validation latency

< 1,000ms (parallel execution)

Compute unit budget

< 5,000 CU per validation

Implementation language

Rust / Anchor framework

Immutability

Transfer Hook cannot be removed or disabled after mint creation

V8 change vs V7

Category 1 custody verification updated: Common Class B shares replace Preferred Series M as backing instrument. Control 24 unchanged from V7.

3.1 The Alesia Doctrine — Compliance by Encirclement

The Transfer Hook architecture embodies what OTCM Protocol calls the Alesia Doctrine: the principle that compliance should be enforced through structural encirclement rather than trust. In traditional securities markets, compliance depends on intermediaries — broker-dealers, clearinghouses, and regulators — acting in good faith. These actors can fail, be compromised, or simply be absent in the OTC microcap context where infrastructure has been abandoned.

OTCM Protocol’s Transfer Hook architecture eliminates the dependency on good-faith intermediary behavior by embedding compliance enforcement in the token transfer primitive itself. Every ST22 token transfer — regardless of which wallet, front-end, or trading venue initiates it — must pass through all 42 controls before the transaction executes on-chain. There is no path around this enforcement. There is no administrative override. There is no whitelist for trusted parties. The controls execute identically for every participant on every transfer, including OTCM Protocol itself.

3.1.1 Why Application-Layer Compliance Fails

The January 28, 2026 Joint Staff Statement on Tokenized Securities explicitly identified the compliance gap that results when securities compliance is implemented at the application layer rather than the token standard level. When compliance is enforced by an issuer’s portal or a specific trading venue, any participant who routes around that portal or venue bypasses all compliance controls. This is the architectural vulnerability that defines Category 2 (Third-Party Sponsored) tokenization — and it is precisely what the Transfer Hook architecture eliminates.

Compliance Location

Vulnerability

OTCM Protocol Approach

Application layer (portal)

Any alternative front-end bypasses all controls

Layer 2 enforcement — no front-end can bypass

Trading venue (exchange)

Any DEX that doesn’t enforce compliance disables all controls

CEDEX exclusive — only venue that preserves all 42 hooks

Issuer policy

Policy can be changed, ignored, or overridden

Immutable smart contract — policy is code, code is law

Third-party custodian

Custodian can withdraw backing assets, creating de-peg risk

Transfer Hook Control 1 verifies custody on every transfer

Transfer Hook (Layer 2)

Cannot be bypassed — any failure reverts entire transaction

This is the OTCM approach — compliance at the primitive

3.2 Architecture

3.2.1 Transaction Flow

The Transfer Hook is invoked by the SPL Token-2022 program on every ST22 token transfer via Cross-Program Invocation (CPI). This invocation is mandatory at the protocol level — it cannot be disabled by the issuer, by OTCM Protocol, or by any trading venue. The six-step flow is as follows:

•          Step 1 — Transfer initiation — User initiates transfer through any entry point: CEDEX order execution, hardware wallet, mobile wallet, or programmatic call

•          Step 2 — Token-2022 receives instruction — SPL Token-2022 program receives the transfer instruction from the initiating party

•          Step 3 — Transfer Hook invoked via CPI — Token-2022 automatically invokes OTCM’s Transfer Hook program via Cross-Program Invocation. This step is mandatory and cannot be skipped

•          Step 4 — All 42 controls execute — The Transfer Hook validates the transaction against all 42 security controls in parallel and sequential groups. Oracle data from Layer 6 is consumed in real-time

•          Step 5 — Atomic result — If ANY control fails: the entire transaction reverts atomically with a specific error code. If ALL controls pass: execution proceeds to Layer 1 settlement

•          Step 6 — Settlement and audit — Passing transactions settle on Solana. An immutable audit record of all control results is written on-chain for every transfer

3.2.2 Program Structure

The Transfer Hook program is implemented in Rust using the Anchor framework. The program structure follows strict separation of concerns, with each component having a well-defined responsibility:

programs/
└── transfer-hook/
    └── src/
        ├── lib.rs                  // Program entrypoint
        ├── instructions/
        │   ├── mod.rs
        │   ├── initialize.rs       // SecurityConfig initialization
        │   └── transfer_hook.rs    // Main hook logic (42 controls)
        ├── state/
        │   ├── mod.rs
        │   ├── security_config.rs  // Security parameters per mint
        │   ├── circuit_breaker.rs  // Circuit breaker state
        │   └── holding_period.rs   // Rule 144 / Reg S enforcement (V8)
        ├── errors.rs               // Custom error codes (6001–6042)
        └── utils/
            ├── validation.rs       // Validation helpers
            └── math.rs             // u128 overflow-safe arithmetic

3.2.3 Account Architecture

The Transfer Hook utilizes Program Derived Addresses (PDAs) to store security configuration and state for each token mint. One SecurityConfig account is created per ST22 Security Token at the time of minting, establishing the security parameters that govern all transfers of that token for its entire existence.

#[account]
pub struct SecurityConfig {
    pub mint:                       Pubkey,   // Associated token mint
    pub authority:                  Pubkey,   // 5-of-9 multi-sig admin
    pub max_wallet_percent:          u16,     // 499 = 4.99% (basis points)
    pub circuit_breaker_threshold:   u16,     // 3000 = 30% daily volume
    pub circuit_breaker_cooldown:    i64,     // 86400 = 24 hours
    pub circuit_breaker_triggered:   bool,    // Current CB state
    pub circuit_breaker_triggered_at: i64,   // CB trigger timestamp
    pub reference_price:             u64,     // TWAP baseline
    pub holding_period_config:  HoldingPeriodConfig, // V8: Rule 144/Reg S
    pub volume_tracker:         VolumeTracker,       // 24h rolling window
    pub blacklisted_wallets:    Vec<Pubkey>,         // OFAC-blocked addresses
    pub is_paused:              bool,                // Emergency pause
    pub bump:                   u8,                  // PDA bump seed
}

3.2.4 V8 Architecture Note: Backing Instrument Change

In Version 8.0, the backing instrument verified by Category 1 controls (Controls 1–7, 38, 40) has changed from Preferred Series M shares to Common Class B shares. The custody oracle now verifies Common B share counts held by Empire Stock Transfer. The HoldingPeriodConfig structure and Control 24 logic are unchanged from V7 — the Rule 144 / Reg S holding period enforcement operates identically regardless of the backing instrument type. UPDATED V8

The HoldingPeriodAccount structure (introduced in V7, replacing V6’s VestingConfig) remains unchanged:

// V7+ HOLDING PERIOD ENFORCEMENT (unchanged in V8)
#[account]
pub struct HoldingPeriodAccount {
    pub version:               u8,       // Schema version — 8
    pub beneficiary:           Pubkey,   // Investor wallet address
    pub mint:                  Pubkey,   // ST22 mint address
    pub purchase_timestamp:    i64,      // Unix timestamp at token delivery
    pub jurisdiction:          Jurisdiction, // US or NonUS
    pub holding_period_secs:   i64,      // 15_778_800 (US) | 31_536_000 (non-US)
    pub is_locked:             bool,     // True until holding period elapses
    pub bump:                  u8,       // PDA bump seed
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq)]
pub enum Jurisdiction {
    US,    // Rule 144 — 6-month holding period
    NonUS, // Regulation S — 12-month distribution compliance period
}

// Constants
pub const RULE_144_HOLDING_SECS:  i64 = 15_778_800; // 6 months
pub const REG_S_COMPLIANCE_SECS:  i64 = 31_536_000; // 12 months

3.3 The 42 Security Controls

The 42 controls are organized into six categories. Every control executes on every transfer — there are no exceptions, no bypass mechanisms, and no administrative overrides. The categories are not sequential phases; most controls execute in parallel. The sequential dependency exists only within the critical path (Controls 1→2→3→4→24).

Category 1: Custody & Asset Backing Verification · 9 controls (1–7, 38, 40)

Verify at every transfer that circulating token supply never exceeds Common Class B shares held in Empire custody UPDATED V8

#

Control Name

Trigger Condition

Enforcement Action

Error

1

Custody Oracle Check

Circulating supply would exceed Empire-custodied Common B share count

Reject — Error 6001 (CustodyDiscrepancy)

6001

2

Oracle Availability

Empire custody feed unavailable or attestation > 400ms stale

Reject — Error 6002 (CustodyOracleUnavailable)

6002

3

Supply Integrity

Total supply inconsistency detected across mint accounts

Reject — atomic revert

6007

4

Locked Balance

Transfer would draw from locked (holding-period) balance

Reject — Error 6024 per Control 24

6024

5

Zero Balance Guard

Transfer from zero-balance account or dust amount

Reject — zero transfer guard

6014

6

Precision Validation

Decimal precision exceeds mint-defined limit

Reject — precision error

6016

7

Supply Integrity Cross-Check

Secondary oracle cross-reference disagrees with primary

Circuit breaker — halt transfers for affected mint

6038

38

Custody Discrepancy Halt

Token supply confirmed > custodied Common B shares (oracle verified)

Halt all transfers for affected mint indefinitely

6038

40

Oracle Consensus Failure

< 2 of 3 oracle feeds available for > 5 minutes

Halt affected hook category

6040

Category 2: Sanctions & AML Compliance · 4 controls (8–11)

OFAC/SDN real-time screening and AML risk scoring on every transfer — not just at onboarding

Controls 8–11 implement continuous sanctions and AML compliance. Empire Stock Transfer performs these checks at investor onboarding — Controls 8–11 ensure they are re-applied on every subsequent transfer. A wallet that was clean at onboarding but later added to the OFAC SDN list is blocked immediately on its next transfer attempt.

#

Control Name

Trigger Condition

Enforcement Action

Error

8

OFAC Sender Screen

Sender wallet matches OFAC SDN list (updated hourly)

Reject permanently — Error 6003 (SenderSanctioned)

6003

9

OFAC Receiver Screen

Receiver wallet matches OFAC SDN list

Reject permanently — Error 6004 (ReceiverSanctioned)

6004

10

OFAC Oracle Staleness

OFAC SDN feed not updated within 90 minutes

Reject — stale oracle, Error 6005

6005

11

AML Risk Score

ML risk score for sender or receiver exceeds 70/100 threshold

Reject — Error 6006 (SenderHighRisk). Score 31–70: flag for compliance review

6006

// Control 11: AML Risk Scoring — three-tier system
pub fn check_aml_risk(risk_score: u8) -> Result<AMLDecision> {
    match risk_score {
        0..=30  => Ok(AMLDecision::Approve),
        31..=70 => Ok(AMLDecision::EnhancedReview), // flag, don't reject
        71..=100 => Err(TransferHookError::SenderHighRisk.into()),
        _ => Err(TransferHookError::InvalidRiskScore.into()),
    }
}

Category 3: Investor Eligibility & Holding Period Enforcement · 8 controls (12–19)

Accreditation verification, KYB entity checks, and Rule 144 / Reg S holding period enforcement on every transfer

Category 3 is the most significant change introduced in the V7 Transfer Hook specification and carried forward unchanged in V8. In V6, this category was called ‘Vesting Enforcement’ and enforced the 5-tranche issuer vesting schedule over 30 months. In V7+, the vesting schedule was removed. Control 24 now enforces the Rule 144 and Regulation S mandatory holding periods for accredited investors. The control number is retained for error code continuity; the underlying logic was completely rewritten in V7.

#

Control Name

Trigger Condition

Enforcement Action

Error

12

Accreditation Check

Buyer wallet not in Empire’s verified accredited investor registry

Reject — accreditation required. Error 6004

6004

13

KYC Status Check

Buyer or seller KYC status expired or flagged in Empire system

Reject — re-verification required

6004

14

KYB Entity Check

Entity investor UBO verification lapsed or flagged

Reject — KYB re-verification required

6004

15

Wallet Registration

Destination wallet not registered in Empire Master Securityholder File

Reject — unregistered wallet cannot receive ST22 tokens

6004

16

Redemption Eligibility

Redemption transaction: KYC completion and accreditation not current

Reject — Error 6004 (KYCInvalid)

6004

17

Jurisdiction Flag

Wallet jurisdiction flag missing or invalid

Reject — jurisdiction cannot be determined

6024

18

Reg S US Person Check

Non-US wallet attempting US market transaction during compliance period

Reject — Reg S restriction

6024

24

Holding Period Lock

Purchase timestamp + holding_period_secs > current_timestamp

Reject — Error 6024 (TokensLocked). US: 6-month Rule 144. Non-US: 12-month Reg S

6024

3.3.1 Control 24 Deep Dive — Rule 144 / Reg S On-Chain Enforcement

Control 24 is the mechanism that makes OTCM Protocol’s issuance model legally compliant without relying on investor self-discipline or post-hoc regulatory action. It is the on-chain expression of the mandatory holding periods that securities law imposes on restricted security holders.

// Control 24: Holding Period Enforcement
pub fn check_holding_period(
    ctx: Context<TransferHook>,
    transfer_amount: u64,
) -> Result<()> {
    let holding = &ctx.accounts.holding_period_account;
    let current_ts = Clock::get()?.unix_timestamp;

    // Check if holding period has elapsed
    let required_period = match holding.jurisdiction {
        Jurisdiction::US    => RULE_144_HOLDING_SECS,  // 15_778_800s (6 months)
        Jurisdiction::NonUS => REG_S_COMPLIANCE_SECS,  // 31_536_000s (12 months)
    };

    let elapsed = current_ts - holding.purchase_timestamp;

    require!(
        elapsed >= required_period,
        TransferHookError::TokensLocked // Error 6024
    );

    Ok(())
}

Key properties of Control 24:

•          Purchase timestamp is immutable — Set by Empire Stock Transfer at token delivery and recorded on-chain. Cannot be altered by any party after it is set.

•          Jurisdiction determines holding period — US investors (Reg D) hold 6 months under Rule 144. Non-US investors (Reg S) hold 12 months under the Regulation S distribution compliance period. Determined by Empire’s KYC/KYB determination at onboarding.

•          No grace period — The check is exact to the second. A transfer attempt at 6 months minus 1 second is rejected identically to a transfer attempt at day 1.

•          No administrative override — No wallet, no key, no multisig, and no governance vote can override Control 24. The holding period is enforced by the immutable Transfer Hook program.

•          Automatic clearance — Once the holding period elapses, Control 24 clears on the next transfer attempt with no action required from any party.

•          Volume limits still apply after clearance — After Control 24 clears, the remaining 41 controls still apply. Investors can trade but are subject to the 4.99% wallet concentration limit, 1% daily sell limit, price impact circuit breaker, and all other protections.

Category 4: Market Integrity & Position Limits · 9 controls (20–28)

Wallet concentration limits, circuit breakers, volume halts, and price impact controls

#

Control Name

Trigger Condition

Enforcement Action

Error

20

Max Wallet Limit

Post-transfer balance would exceed 4.99% of total supply for destination

Reject — whale concentration limit. Error: WalletLimitExceeded

6020

21

Pre-Transfer Balance

Source wallet has insufficient transferable balance (excluding locked)

Reject — insufficient balance

6008

22

Zero-Amount Guard

Transfer amount = 0

Reject — zero transfer

6014

23

Self-Transfer Guard

Source wallet = destination wallet

Reject — self transfer

6015

25

Price Impact Limit

Transaction would cause > 2% price deviation from TWAP

Reject — Error 6006 circuit breaker trigger

6006

26

TWAP Oracle Integrity

TWAP feed stale or deviation > 10% from secondary price feed

Reject — stale oracle, cannot enforce price impact

6019

27

Volume Halt

Single wallet attempts to sell > 30% of circulating supply in 24 hours

24-hour trading suspension for that wallet

6037

28

Circuit Breaker

> 30% price movement in single Solana slot for affected ST22

Halt mint-specific transfers for 1 hour

6037

36

Global Circuit Breaker

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

Reject all ST22 transfers platform-wide

6036

// Control 20: Max Wallet Limit (4.99%)
pub fn check_wallet_limit(
    destination_balance: u64,
    transfer_amount: u64,
    total_supply: u64,
    config: &SecurityConfig,
) -> Result<()> {
    let new_balance = destination_balance
        .checked_add(transfer_amount)
        .ok_or(TransferHookError::ArithmeticOverflow)?;

    let max_allowed = (total_supply as u128)
        .checked_mul(config.max_wallet_percent as u128) // 499 bps
        .ok_or(TransferHookError::ArithmeticOverflow)?
        .checked_div(10_000)
        .ok_or(TransferHookError::ArithmeticOverflow)? as u64;

    require!(new_balance <= max_allowed, TransferHookError::WalletLimitExceeded);
    Ok(())
}

Category 5: CEI Pattern & Reentrancy Prevention · 9 controls (29–35, 41, 42)

Checks-Effects-Interactions enforcement preventing reentrancy and CPI privilege escalation attacks

Category 5 enforces the Checks-Effects-Interactions (CEI) pattern across all Cross-Program Invocations in the Transfer Hook execution chain. This prevents reentrancy attacks — a class of exploit that has drained hundreds of millions of dollars from DeFi protocols by calling back into a contract before state updates complete. In OTCM’s context, a reentrancy attack could theoretically allow an attacker to transfer tokens multiple times before balance state is updated.

#

Control Name

Trigger Condition

Enforcement Action

Error

29

Signer Validation

Expected signer(s) not present in transaction

Reject — invalid signer. Error 6007

6007

30

Account Owner Check

Account not owned by expected program

Reject — wrong account owner. Error 6008

6008

31

Mint Consistency

Source/destination token accounts reference different mints

Reject — mint mismatch. Error 6009

6009

32

Account Size Validation

Account data length < minimum expected struct size

Reject — corrupt account. Error 6010

6010

33

Discriminator Check

Account discriminator ≠ expected 8-byte Anchor prefix

Reject — type confusion. Error 6011

6011

34

Token Account State

Source or destination account in Frozen state

Reject — account frozen. Error 6012

6012

35

Delegate Scope

Delegated transfer amount > approved delegation amount

Reject — delegation exceeded. Error 6013

6013

41

Controlled Migration

Emergency contract migration: 4-of-7 multisig + 48h timelock required

Allow migration only with full governance approval

6041

42

Regulatory Compliance Override

Law enforcement or SEC regulatory freeze order received

Comply per legal process — targeted freeze only

6042

Category 6: Transaction Integrity & Audit · 13 controls (mapped as 3, 5, 6, 16–19, 32–35, 37, 39)

Arithmetic safety, atomic reversion guarantees, compute budget enforcement, and immutable audit log writes

Note on numbering: The Transfer Hook technical specification numbers controls 1–42 with some controls mapped to operational sub-functions. The following table presents the transaction integrity and audit controls with their operational identifiers for reference. All execute on every transfer.

#

Control Name

Trigger Condition

Enforcement Action

Error

16

Arithmetic Overflow Guard

Any u64 arithmetic would overflow

Reject — overflow detected. All arithmetic uses u128 intermediate

6016

17

Atomic Revert Guarantee

Any prior control in chain has failed

Full atomic rollback — no partial state changes persist

6017

18

Hook Order Validation

Controls not executing in defined sequence

Reject — hook order violation

6018

19

Duplicate Detection

Highly similar transaction signature seen within 1 slot

Reject — probable duplicate

6019

32

Compute Budget Enforcement

Remaining CU < 50,000 before Hook 6

Reject — insufficient compute budget

6032

33

Account Rent Validation

Any account below rent-exempt minimum

Reject — rent depleted

6033

34

Program Version Check

Caller program version < minimum compatible

Reject — version mismatch

6034

35

Key Rotation Compliance

Oracle signer key not in current oracle registry

Reject — unrecognized signer

6035

37

Per-Mint Circuit Breaker

> 30% price movement in single slot

Halt mint-specific transfers 1 hour

6037

39

OFAC Emergency Block

New OFAC SDN entry matching active wallet

Immediate freeze — no grace period

6039

3.4 Complete Error Code Registry

Every control failure produces a specific error code enabling precise diagnosis and compliance reporting. The following is the authoritative error code registry for V8:

#[error_code]
pub enum TransferHookError {
    // Custody & Asset Backing
    #[msg("Custody oracle: token supply exceeds custodied Common B shares")]
    CustodyDiscrepancy = 6001,
    #[msg("Custody oracle: attestation unavailable or stale (>400ms)")]
    CustodyOracleUnavailable = 6002,

    // Sanctions & AML
    #[msg("OFAC: sender wallet matches SDN list")]
    SenderSanctioned = 6003,
    #[msg("OFAC: receiver wallet matches SDN list")]
    ReceiverSanctioned = 6004,
    #[msg("OFAC: oracle data stale — cannot verify sanctions status")]
    OfacOracleStale = 6005,
    #[msg("AML: sender or receiver risk score exceeds 70/100")]
    SenderHighRisk = 6006,

    // Investor Eligibility
    #[msg("KYC/Accreditation: buyer not verified accredited investor")]
    KYCInvalid = 6004,
    #[msg("Holding period: tokens locked — Rule 144 / Reg S not satisfied")]
    TokensLocked = 6024,   // V7+: replaces VestingLocked from V6

    // Market Integrity
    #[msg("Wallet limit: destination would exceed 4.99% of supply")]
    WalletLimitExceeded = 6020,
    #[msg("Circuit breaker: price impact exceeds 2% TWAP deviation")]
    CircuitBreakerTriggered = 6006,
    #[msg("Volume halt: single wallet exceeds 30% daily sell limit")]
    DailySellLimitExceeded = 6037,

    // CEI & Integrity
    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,

    // Emergency
    GlobalCircuitBreaker = 6036,
    PerMintCircuitBreaker = 6037,
    CustodyDiscrepancyHalt = 6038,
    OFACEmergencyBlock = 6039,
    OracleConsensusFail = 6040,
    ControlledMigration = 6041,
    RegulatoryOverride = 6042,
}

3.5 Main Transfer Hook Entry Point

The main Transfer Hook entry point coordinates all 42 controls through a structured validation sequence. Critical path controls (1, 8, 11, 12, 24) execute sequentially — each must pass before the next runs. All other controls execute in parallel groups to minimize total latency.

#[program]
pub mod transfer_hook {
    use super::*;

    pub fn transfer_hook(ctx: Context<TransferHook>, amount: u64) -> Result<()> {
        let config = &ctx.accounts.security_config;

        // ── CRITICAL PATH: Sequential ─────────────────────────
        // Control 1: Custody verification (Empire oracle — Common B shares)
        verify_custody_oracle(&ctx.accounts.custody_oracle, amount, config)?;

        // Controls 8-10: OFAC sanctions screening
        check_ofac_sender(&ctx.accounts.sender, config)?;
        check_ofac_receiver(&ctx.accounts.receiver, config)?;
        check_ofac_oracle_freshness(&ctx.accounts.ofac_oracle)?;

        // Control 11: AML risk scoring
        check_aml_risk(ctx.accounts.aml_oracle.sender_score)?;

        // Controls 12-18: Investor eligibility & holding period
        check_accreditation(&ctx.accounts.receiver, config)?;
        check_holding_period(&ctx.accounts.holding_period_account)?; // Control 24

        // ── PARALLEL: Market integrity, CEI, Audit ───────────
        check_wallet_limit(amount, config)?;        // Control 20
        check_price_impact(amount, config)?;        // Control 25
        check_volume_halt(amount, config)?;         // Control 27
        check_circuit_breaker(config)?;             // Control 28
        validate_cei_pattern(&ctx.accounts)?;       // Controls 29-35
        enforce_arithmetic_safety(amount)?;         // Controls 16-19
        // ... remaining controls 36-42 (emergency + audit) ...

        // ── AUDIT: Write immutable on-chain compliance record ─
        emit!(TransferValidated {
            mint:      ctx.accounts.mint.key(),
            from:      ctx.accounts.source.key(),
            to:        ctx.accounts.destination.key(),
            amount,
            timestamp: Clock::get()?.unix_timestamp,
            all_controls_passed: true,
        });

        Ok(())
    }
}

3.6 Immutability Guarantee

The Transfer Hook cannot be removed or disabled after mint creation. This is a property of the SPL Token-2022 standard: once a token mint is created with a Transfer Hook extension, the hook program address is permanently stored in the mint account. The Token-2022 program will invoke that hook on every transfer for the entire existence of the token.

OTCM Protocol’s Transfer Hook program upgrade authority is held by a 5-of-9 multi-signature wallet with geographically distributed key holders. All upgrades require a 24-hour timelock period during which the upgrade can be cancelled through governance. Critically, even an upgrade cannot remove the 42 security controls — the controls are defined in the program logic, and any upgrade that would materially weaken investor protections requires a governance vote that passes the 66.67% supermajority threshold and satisfies the account schema compatibility attestation requirement.

Property

Mechanism

Who Controls It

Hook address permanence

SPL Token-2022 stores hook address in mint account permanently

No one — Token-2022 program level, cannot be changed

Hook invocation

Token-2022 automatically calls hook via CPI on every transfer

No one — mandatory at protocol level

Program upgrade authority

5-of-9 multi-sig with 24-hour timelock

5 of 9 designated key holders (geographically distributed)

Security control immutability

Controls in immutable on-chain program — outside governance scope

Cannot be weakened by any party including OTCM Protocol

Parameter adjustments

Governance vote with 66.67% supermajority, 48-hour timelock, audit attestation

OTCM Security Token stakers

V8 Change Summary — Transfer Hook Architecture

The V8 changes to the Transfer Hook architecture are limited to the backing instrument reference. In V7, Category 1 controls (1–7, 38, 40) verified that circulating token supply did not exceed Preferred Series M shares held in Empire custody. In V8, these controls verify against Common Class B shares held in Empire custody. The custody oracle API field names update from series_m_balance to common_b_balance. The error message for Error 6001 (CustodyDiscrepancy) now references “Common B shares” instead of “custodied shares.” All other controls (8–42) are unchanged from V7. Control 24 (holding period enforcement) is unchanged — Rule 144 and Reg S holding periods operate identically regardless of the backing instrument type.

Groovy Company, Inc. dba OTCM Protocol | CIK: 1499275 | Version 8.0 | March 2026 | Confidential