SINAI STANDARD

Protocol Specification

Sinai Standard Transfer Hook Protocol v0.1

Abstract

Sinai Standard is an open protocol for programmable compliance on Solana. It uses the Token-2022 Transfer Hook interface to enforce regulatory rules — allowlists, transaction taxes, hold periods, and concentration limits — entirely on-chain at the runtime level. Every transfer_checked call passes through one or more hook programs that validate the transfer against issuer-defined policies. No off-chain gatekeeper can be bypassed.

This document specifies the protocol's architecture, hook interfaces, state accounts, composition model, and token creation flow.


Protocol Overview

Design Principles

  1. On-chain enforcement. Compliance rules execute inside the Solana runtime during token transfers. There is no off-chain oracle or relay in the transfer path.
  2. Composable hooks. Each compliance rule is an independent program. A Router Hook composes multiple rules into a single transfer validation pipeline.
  3. Issuer sovereignty. Token issuers configure their own compliance parameters. The protocol provides the enforcement layer, not the policy.

Architecture

The protocol consists of six on-chain programs built on Anchor 0.31.1:

LayerPrograms
Transfer HooksAllowlist Hook, Tax Hook, Hold Hook, Max Balance Hook
CompositionRouter Hook
Token LifecycleToken Factory

Token-2022 Integration

Sinai Standard relies on three Token-2022 extensions:

ExtensionRole
TransferHookPoints the mint to a hook program (or Router) invoked on every transfer_checked
PermanentDelegateGrants the Tax Hook authority to collect fees post-transfer
MetadataPointerStores token name, symbol, and URI on-chain

The ConfidentialTransfer extension is optionally supported via Token-2022's native ElGamal encryption and ZK range proofs — no custom program is required.


Hook Interface

Entry Point

Every hook program exposes a single validation entry point:

execute_transfer_hook(source, mint, destination, owner, amount, extra_account_metas...)

This function is invoked automatically by the Token-2022 runtime during any transfer_checked call on a mint with the TransferHook extension enabled. The hook program cannot be bypassed by the sender or receiver.

ExtraAccountMetas PDA

Each hook program derives an ExtraAccountMetas PDA that tells the Token-2022 runtime which additional accounts the hook needs during execution:

  • Seeds: ["extra-account-metas", mint]
  • Program: The hook program's own program ID

This PDA must be initialized before any transfer_checked call on the mint. If it is missing, the transaction fails.

The runtime reads the ExtraAccountMetas PDA, resolves the listed accounts, and passes them to the hook's execute instruction automatically.

Validation Semantics

  • If the hook's execute instruction succeeds, the transfer proceeds.
  • If it returns an error, the entire transaction reverts — the transfer never settles.
  • If is_active is false on the hook's config PDA, the hook permits all transfers (permissive kill switch).

Hooks Specification

Allowlist Hook

Purpose: Restricts transfers to an approved set of wallets, or blocks a denied set.

Modes:

ModeBehavior
AllowlistOnly wallets on the list may send or receive
DenylistAll wallets may transfer except those on the list

State Account — AllowlistRegistry PDA

Seeds: ["allowlist", mint]

FieldTypeDescription
authorityPubkeyAdmin who manages the registry
mintPubkeyThe token mint
is_activeboolKill switch (false = all transfers pass)
modeenumAllowlist or Denylist
wallet_countu32Number of wallets in the registry
walletsVec<Pubkey>Wallet addresses

Validation Logic:

  1. If is_active is false, the transfer is permitted.
  2. In Allowlist mode: both source owner and destination owner must appear in wallets.
  3. In Denylist mode: neither source owner nor destination owner may appear in wallets.

Constraints:

  • Maximum ~300 wallets per registry
  • Batch operations limited to 20 wallets per transaction
  • In Allowlist mode, the issuer must add themselves to distribute tokens

Error Conditions:

  • Transfer reverts if a wallet fails the allowlist/denylist check

Tax Hook

Purpose: Levies a percentage-based tax on every transfer, collected into an issuer-specified vault.

Two-Step Collection Design:

  1. execute (during TransferHook CPI): validates the transfer and logs the taxable amount.
  2. collect_tax (separate instruction): uses the Permanent Delegate PDA to transfer the tax to the vault.

This separation keeps the transfer CPI within compute limits.

State Account — TaxConfig PDA

Seeds: ["tax-config", mint]

FieldTypeDescription
authorityPubkeyAdmin who manages tax settings
mintPubkeyThe token mint
tax_vaultPubkeyDestination for collected taxes
tax_bpsu16Tax rate in basis points
max_tax_bpsu16Hard cap — immutable after creation
is_activeboolKill switch
exempt_countu32Number of exempt wallets
exempt_walletsVec<Pubkey>Tax-exempt addresses

State Account — TaxDelegate PDA

Seeds: ["tax-delegate", mint]

The Permanent Delegate authority used by collect_tax to debit sender accounts post-transfer.

Validation Logic:

  1. If is_active is false, the transfer is permitted (no tax logged).
  2. If the source wallet is in exempt_wallets, no tax is applied.
  3. Tax calculation: tax_amount = amount * tax_bps / 10000

Constraints:

  • tax_bps can never exceed max_tax_bps
  • max_tax_bps is set at initialization and cannot be changed

Error Conditions:

  • update_tax_rate reverts if the new rate exceeds max_tax_bps
  • collect_tax reverts if the Permanent Delegate PDA is not the mint's delegate authority

Hold Hook

Purpose: Enforces a minimum holding period before tokens can be transferred out of a wallet.

State Account — HoldConfig PDA

Seeds: ["hold-config", mint]

FieldTypeDescription
authorityPubkeyAdmin who manages hold settings
mintPubkeyThe token mint
hold_period_secondsi64Lock-up duration in seconds
is_activeboolKill switch

State Account — WalletLock PDA

Seeds: ["wallet-lock", mint, wallet]

FieldTypeDescription
walletPubkeyThe locked wallet
mintPubkeyThe token mint
acquired_ati64Unix timestamp of acquisition
unlock_ati64acquired_at + hold_period_seconds

Validation Logic:

  1. If is_active is false, the transfer is permitted.
  2. If no WalletLock PDA exists for the source wallet, the transfer is permitted.
  3. If current_timestamp is at or past unlock_at, the transfer is permitted.
  4. Otherwise, the transfer reverts.

Constraints:

  • update_hold_period only affects future record_acquisition calls — existing WalletLock PDAs retain their original unlock_at

Error Conditions:

  • Transfer reverts if the source wallet's lock-up has not expired

Max Balance Hook

Purpose: Caps the maximum token balance any single wallet can hold, preventing concentration.

State Account — MaxBalanceConfig PDA

Seeds: ["max-balance-config", mint]

FieldTypeDescription
authorityPubkeyAdmin who manages the config
mintPubkeyThe token mint
max_balanceu64Maximum allowed balance per wallet
is_activeboolKill switch

Validation Logic:

  1. If is_active is false, the transfer is permitted.
  2. The program reads the destination token account's current balance at byte offset 64 (the amount field in a Token-2022 account).
  3. If destination_balance + transfer_amount is greater than max_balance, the transfer reverts.

Constraints:

  • max_balance must be greater than zero
  • Wallets already above a newly lowered limit are not penalized but cannot receive more tokens

Error Codes:

CodeNameDescription
6000UnauthorizedSigner is not the config authority
6001MaxBalanceExceededTransfer would push destination above max_balance
6002InvalidMaxBalancemax_balance must be greater than zero

Router Composition

Purpose

The Router Hook composes up to four sub-hooks into a single TransferHook entry point. A mint's TransferHook extension points to the Router, and the Router validates against each enabled sub-hook in sequence.

Execution Order

The Router executes sub-hooks in a fixed order:

  1. Allowlist Hook — validates source and destination are approved
  2. Tax Hook — logs the transfer for tax collection
  3. Hold Hook — verifies the source wallet's lock-up has expired
  4. Max Balance Hook — ensures destination balance plus transfer amount does not exceed the cap

To skip a hook, set its program ID to PublicKey.default (all zeros) in the RouterConfig.

State Account — RouterConfig PDA

Seeds: ["router-config", mint]

FieldTypeDescription
authorityPubkeyAdmin who manages the router
mintPubkeyThe token mint
is_activeboolKill switch
allowlist_hook_programPubkeyAllowlist Hook program ID (or zero to skip)
tax_hook_programPubkeyTax Hook program ID (or zero to skip)
hold_hook_programPubkeyHold Hook program ID (or zero to skip)
max_balance_hook_programPubkeyMax Balance Hook program ID (or zero to skip)

Inline Deserialization

The Router does not use CPI to call sub-hooks. Instead, it reads each sub-hook's config PDA account data and deserializes the relevant fields inline using raw byte offsets. This design:

  • Avoids CPI depth limits (Solana caps CPI at 4 levels; transfer_checked already consumes one)
  • Reduces compute unit consumption
  • Keeps all validation in a single transaction context

Each sub-hook's config and ExtraAccountMetas PDAs must still be initialized independently.

Failure Semantics

  • If any enabled sub-hook's validation fails, the entire transfer reverts.
  • Sub-hooks are evaluated in order; a failure in hook 1 short-circuits hooks 2–4.
  • If is_active is false on the RouterConfig, all sub-hooks are bypassed entirely.

Hook Selection Logic

The SDK (AksumKit) automatically selects the correct mode when creating tokens:

Hooks SpecifiedTransferHook Target
0 hooksNo TransferHook extension
1 hookDirect hook program
2+ hooksRouter Hook program

Token Factory

Purpose

The Token Factory creates Token-2022 mints pre-configured with the extensions required for compliance enforcement.

Extensions

Every mint created by the Token Factory includes:

ExtensionPurpose
MetadataPointerOn-chain token name, symbol, and URI
TransferHookPoints to a hook program or Router for compliance checks
PermanentDelegateGrants the Tax Hook authority to collect fees post-transfer

The ConfidentialTransfer extension is optionally added for privacy-preserving transfers.

State Account — TokenRecord PDA

Seeds: ["token-record", mint]

Records the issuer, mint address, associated hook program, and pause state.

State Account — FreezeAuthority PDA

Seeds: ["freeze-authority", mint]

Used by freeze_account and thaw_account instructions for individual account-level freezing.

Instructions

InstructionDescription
create_tokenCreates a new Token-2022 mint with all extensions configured
mint_supplyMints additional supply (issuer only)
pause_tokenGlobal pause — halts all transfers (issuer only)
resume_tokenResume transfers after a global pause
freeze_accountFreeze an individual token account
thaw_accountUnfreeze an individual token account

PDA Reference

All PDA seeds used across the protocol:

PDASeedsProgram
AllowlistRegistry["allowlist", mint]Allowlist Hook
TaxConfig["tax-config", mint]Tax Hook
TaxDelegate["tax-delegate", mint]Tax Hook
HoldConfig["hold-config", mint]Hold Hook
WalletLock["wallet-lock", mint, wallet]Hold Hook
MaxBalanceConfig["max-balance-config", mint]Max Balance Hook
RouterConfig["router-config", mint]Router Hook
TokenRecord["token-record", mint]Token Factory
FreezeAuthority["freeze-authority", mint]Token Factory
ExtraAccountMetas["extra-account-metas", mint]Each hook program (distinct per program ID)

All hook programs use the seed "extra-account-metas" for their ExtraAccountMetas PDA, but each is derived against the respective program's own ID, producing distinct accounts.


Program IDs

All programs are deployed to Solana devnet.

ProgramAddress
Token FactoryVXQL8u4NVUYG1zaejujwh5gr21iinmk4yYCXn1g9TXr
Allowlist HookBo3Rd8qZeuxU1cmtCqKEFPRe5Uumx9tusjZ7B1hXtPgc
Tax HookACJXvcH4uaBfBwSwcVG48zJ177ydEvtCqGRMKXv53goZ
Hold Hook8HkukxWoo27BnNwqCzCim4ueKaGEfqLW4LdSZkHkCWzS
Max Balance HookCtx9ZtNzPFYyjqxdZSMYLgHdqNNpAS61G6ok1dYVBHWi
Router HookHHnt7Hfnp2fDftFNCFPqEhebgXGizuqubXqhiEi8C1of

SSTS Verifiers (devnet):

VerifierAddress
SSTS AllowlistA4uS8AYfWfap2ceMccdah1BWzhDYbUuCaHzqqx6b1dRK
SSTS Hold67UG9Xy6nDjVUc9j7g9nHR8xhw1izpLVw8JRC4hVfJWH
SSTS Tax75sNs3nyLMdjBMC3yL497ExZaEVgZtAJY6YSLr68yyce
SSTS Max Balance4WsYgQL7TntXbHZfEvGBm3HSCcUaLQncwfqNoFea6dSQ

Versioning

This is Protocol v0.1 (devnet). Programs are deployed to Solana devnet for testing and integration.

Mainnet deployment is pending a formal security audit. Program addresses will change for the mainnet release.

The protocol follows a versioned specification model. Breaking changes to hook interfaces, PDA layouts, or Router composition semantics will increment the major version number.