> For the complete documentation index, see [llms.txt](https://bitbook.rwatokens.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bitbook.rwatokens.net/sdk-and-development/sdk-and-development/sdk-reference.md).

# SDK Reference

## SDK Reference

**`@rwatokens/sdk` · TypeScript · v1.0.0 · Module-Aware Throughout**

Complete TypeScript SDK for interacting with the platform's nine-layer infrastructure — ST22 Digital Securities token operations, Transfer Hook verification, custody oracle queries, NAV oracle queries (Module 2), Classification oracle queries (Module 3), CEDEX trading, portfolio management, and real-time data subscriptions. The SDK serves all three production modules — Equities (Module 1), Real Estate (Module 2), and CORECM — Carbon Ore, Rare Earth, and Critical Minerals (Module 3) — through a single client with module-aware helpers.

The SDK is published by Groovy Company, Inc. and is the primary integration surface for institutional integrators, trading-desk operators, custody systems, and analytics tooling. The same client instance handles mints from any of the three modules; module-specific behavior is surfaced through module-specific oracle helpers and module-aware fields on standard methods.

***

### Table of Contents<br>

1. ​Installation​
2. Configuration
3. ​Client Initialization​
4. ​Core Types​
5. ​Transfer Hook Operations​
6. ​Custody Oracle​
7. ​NAV Oracle (Module 2)​
8. ​Classification Oracle (Module 3)​
9. ​Holding Period​
10. ​CEDEX Trading​
11. ​Portfolio Management​
12. ​Market Data​
13. ​WebSocket Subscriptions​
14. ​Error Handling​
15. ​Utilities​
16. ​Security Best Practices​
17. ​Network Configuration​
18. ​Examples​

***

### 1. Installation

```bash
# npm
npm install @rwatokens/sdk

# yarn
yarn add @rwatokens/sdk

# pnpm
pnpm add @rwatokens/sdk
```

#### Peer Dependencies

```json
{
  "@solana/web3.js":   "^1.95.0",
  "@solana/spl-token": "^0.4.0",
  "@coral-xyz/anchor": "^0.30.0"
}
```

#### Requirements

| Requirement | Version                       |
| ----------- | ----------------------------- |
| Node.js     | 20 LTS+                       |
| TypeScript  | 5.0+                          |
| Solana CLI  | 1.18+ (for local development) |

***

### 2. Configuration

```typescript
import { RwaTokensConfig } from '@rwatokens/sdk';

const config: RwaTokensConfig = {
  // Required
  network: 'mainnet-beta',           // 'mainnet-beta' | 'devnet' | 'localnet'

  // Optional — defaults shown
  rpcEndpoint: undefined,            // Custom RPC (default: Helius cluster)
  wsEndpoint:  undefined,            // Custom WebSocket endpoint
  commitment:  'confirmed',          // 'processed' | 'confirmed' | 'finalized'
  preflight:   true,                 // Simulate transactions before sending
  maxRetries:  3,                    // Retry count with exponential backoff
  timeoutMs:   30_000,               // Request timeout
  priorityFee: 'auto',               // 'auto' | 'none' | number (microlamports)
  jitoEnabled: true,                 // Use Jito Block Engine for MEV protection
};
```

#### Environment Variables

```bash
# .env
RWA_TOKENS_NETWORK=mainnet-beta
RWA_TOKENS_RPC_ENDPOINT=https://mainnet.helius-rpc.com/?api-key=YOUR_KEY
RWA_TOKENS_WS_ENDPOINT=wss://mainnet.helius-rpc.com/?api-key=YOUR_KEY
RWA_TOKENS_JITO_ENABLED=true
```

***

### 3. Client Initialization

```typescript
import { RwaTokensClient } from '@rwatokens/sdk';
import { Keypair, Connection } from '@solana/web3.js';

// Basic initialization (uses environment variables)
const client = new RwaTokensClient({ network: 'mainnet-beta' });

// With custom RPC
const client = new RwaTokensClient({
  network:     'mainnet-beta',
  rpcEndpoint: 'https://mainnet.helius-rpc.com/?api-key=YOUR_KEY',
});

// With wallet for signing (trading operations)
const wallet = Keypair.fromSecretKey(/* ... */);
const client = new RwaTokensClient({
  network: 'mainnet-beta',
  wallet,
});

// With existing Connection object
const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=YOUR_KEY');
const client = RwaTokensClient.fromConnection(connection);
```

#### Client Properties

```typescript
class RwaTokensClient {
  readonly connection: Connection;
  readonly network:    Network;
  readonly programIds: ProgramIds;

  // Sub-clients for specific operations
  readonly hooks:         TransferHookClient;
  readonly custody:       CustodyOracleClient;       // All modules
  readonly oracle:        OracleClient;               // Includes NAV (M2) and Classification (M3) helpers
  readonly holdingPeriod: HoldingPeriodClient;
  readonly cedex:         CedexClient;
  readonly portfolio:     PortfolioClient;
  readonly markets:       MarketDataClient;
  readonly ws:            WebSocketClient;
}
```

The same `RwaTokensClient` instance handles mints from any of the three modules. There is no per-module client — module-aware helpers (`client.oracle.getNAV()` for Module 2; `client.oracle.getClassification()` for Module 3) work alongside cross-module methods (`client.cedex.placeOrder()`, `client.custody.getAttestation()`) on the same instance.

#### Program IDs

```typescript
interface ProgramIds {
  transferHook:     PublicKey;  // Transfer Hook program (all modules)
  amm:              PublicKey;  // Custom CPMM AMM (all modules)
  liquidityPool:    PublicKey;  // Global Unified CEDEX Liquidity Pool (all modules)
  governance:       PublicKey;  // Protocol governance (all modules)
  oracleAggregator: PublicKey;  // Oracle aggregation program — hosts NAV (M2) and Classification (M3) PDAs
  token2022:        PublicKey;  // SPL Token-2022 program
}

// Mainnet program IDs are published in the Network Configuration document
// at mainnet deployment (Q3 2026).
```

***

### 4. Core Types

#### Token Types

```typescript
/** Module identifier */
type ModuleId = 'equities' | 'real_estate' | 'corecm';

/** ST22 mint information */
interface ST22Mint {
  address:          PublicKey;
  symbol:           string;
  name:             string;
  decimals:         number;
  supply:           bigint;
  issuer:           PublicKey;       // Issuer authority
  module:           ModuleId;        // Which module this mint belongs to
  transferHook:     PublicKey;       // Transfer Hook program ID
  hookAttached:     boolean;         // true (always — irreversible)
  metadata: {
    issuerName:      string;
    assetIdentifier: string;         // CUSIP (M1), property ID (M2), or basin ID (M3)
    custodyAuth:     string;         // Empire Stock Transfer custody reference
    classification:  'ST22DigitalSecurity';
  };
}

/** Transfer Hook verification result */
interface TransferHookStatus {
  mint:           PublicKey;
  hookProgramId:  PublicKey;
  controlsActive: 42;              // Always 42
  bypassPossible: false;           // Always false
  securityConfig: SecurityConfig;
  isValid:        boolean;
}

/** Jurisdiction for holding period — drives the Reg D / Reg S / Reg CF regime */
type Jurisdiction = 'US' | 'NonUS' | 'RegCF';

/** Order side */
type OrderSide = 'buy' | 'sell';

/** Order type */
type OrderType = 'market' | 'limit';

/** Order status */
type OrderStatus = 'open' | 'filled' | 'partially_filled' | 'cancelled' | 'expired';
```

#### Account Types

```typescript
/** SecurityConfig PDA — one per ST22 mint, schema covers all modules */
interface SecurityConfig {
  mint:                      PublicKey;
  authority:                 PublicKey;        // 5-of-9 multi-sig
  version:                   number;
  module:                    ModuleId;
  maxWalletPercent:          number;           // 499 = 4.99% (bps); M2 may use up to 999
  maxSingleTransferPercent:  number;
  circuitBreakerThreshold:   number;           // 3000 = 30% (bps)
  circuitBreakerCooldown:    number;           // Seconds (86400)
  circuitBreakerTriggered:   boolean;
  circuitBreakerTriggeredAt: number | null;
  priceImpactMaxBps:         number;           // 200 = 2%
  referencePrice:            bigint;           // TWAP baseline (lamports)
  twapWindowSecs:            number;           // 1800 = 30 min
  twapMinObservations:       number;           // 60 (immutable)
  holdingPeriodConfig:       HoldingPeriodConfig;
  volumeTracker:             VolumeTracker;
  isPaused:                  boolean;

  // Module 2 only — undefined on Module 1 / Module 3
  navDeviationMaxBps?:       number;           // typically 2200 = 22%
  navReappraisalMaxAgeSecs?: number;
  navCircuitBreakerEnabled?: boolean;

  // Module 3 only — undefined on Module 1 / Module 2
  classificationMaxAgeSecs?: number;           // typically 86400 = 24h
  federalActionFreezeEnabled?: boolean;

  bump: number;
}

/** Holding period configuration — same schema across all modules */
interface HoldingPeriodConfig {
  enabled:    boolean;
  regDSecs:   number;  // 15_778_800 — Reg D 6 months
  regSSecs:   number;  // 31_536_000 — Reg S 12 months
  regCfSecs:  number;  // 31_536_000 — Reg CF 12 months
}

/** Custody oracle state — same schema across all modules; asset class
 * recorded in the SecurityConfig metadata, not the oracle */
interface CustodyOracleState {
  mint:                 PublicKey;
  custodiedBalance:     bigint;     // Empire-custodied unit count (asset class per module)
  tokenSupply:          bigint;     // On-chain circulating supply
  ratio:                number;     // Must be exactly 1.0
  attestationSlot:      bigint;
  attestationTimestamp: number;
  empirePubkey:         PublicKey;
  ed25519Verified:      boolean;
  discrepancyDetected:  boolean;
}

/** NAV oracle state — Module 2 only */
interface NAVOracleState {
  mint:                  PublicKey;
  appraisedNavUsd:       bigint;     // USD-pegged stablecoin units
  appraiserId:           string;
  appraisalTimestamp:    number;
  nextReappraisalTarget: number;
  deviationToleranceBps: number;     // typically 2200 = 22%
  staleThresholdSecs:    number;
  isStale:               boolean;
  ed25519Verified:       boolean;
}

/** Classification oracle state — Module 3 only */
interface ClassificationOracleState {
  mint:                  PublicKey;
  usgsCriticalStatus:    string;     // e.g., "critical_mineral_rare_earth"
  doeMaterialsStatus:    string;     // e.g., "high_priority"
  section232Applicable:  boolean;
  dpaTitleIIIApplicable: boolean;
  federalActionActive:   boolean;
  activeActionRefs:      string[];   // e.g., ["EO-14118"]
  lastRefreshTimestamp:  number;
  staleThresholdSecs:    number;
  isStale:               boolean;
}

/** Holding period account — one per investor-mint pair */
interface HoldingPeriodAccount {
  beneficiary:        PublicKey;
  mint:               PublicKey;
  purchaseTimestamp:  number;
  jurisdiction:       Jurisdiction;          // Drives the regime
  regime:             'RegD' | 'RegS' | 'RegCF';
  holdingPeriodSecs:  number;                // 6mo (Reg D) or 12mo (Reg S / Reg CF)
  isLocked:           boolean;
  unlockTimestamp:    number;
  secondsRemaining:   number;
}
```

***

### 5. Transfer Hook Operations

#### Verify Transfer Hook

Confirm an ST22 mint has the Transfer Hook permanently attached. The same method serves Module 1, Module 2, and Module 3 mints uniformly.

```typescript
const status = await client.hooks.verify(mintAddress);

console.log(status.hookProgramId.toBase58());  // Hook program ID
console.log(status.controlsActive);             // 42
console.log(status.bypassPossible);             // false
console.log(status.isValid);                    // true
```

#### Get SecurityConfig

Read the full security configuration for an ST22 mint. Module-specific fields are populated per the mint's module.

```typescript
const config = await client.hooks.getSecurityConfig(mintAddress);

console.log(config.module);                      // 'equities' | 'real_estate' | 'corecm'
console.log(config.maxWalletPercent);            // 499 (4.99%) — or up to 999 on M2
console.log(config.priceImpactMaxBps);           // 200 (2%)
console.log(config.circuitBreakerTriggered);     // false
console.log(config.holdingPeriodConfig.enabled); // true
console.log(config.isPaused);                    // false

// Module 2 — additional fields populated
if (config.module === 'real_estate') {
  console.log(config.navDeviationMaxBps);        // 2200 (22%)
  console.log(config.navReappraisalMaxAgeSecs);  // per tripartite cadence
  console.log(config.navCircuitBreakerEnabled);  // true
}

// Module 3 — additional fields populated
if (config.module === 'corecm') {
  console.log(config.classificationMaxAgeSecs);  // 86400 (24h)
  console.log(config.federalActionFreezeEnabled);// true
}
```

#### Simulate Transfer

Dry-run a transfer against all 42 controls without submitting on chain. Returns which controls would pass or fail. Module-specific control extensions (Module 2 NAV-deviation, Module 3 federal-action) are evaluated automatically.

```typescript
const simulation = await client.hooks.simulateTransfer({
  mint:        mintAddress,
  source:      senderWallet,
  destination: receiverWallet,
  amount:      1_000_000n,  // bigint — raw token amount (with decimals)
});

console.log(simulation.wouldSucceed);   // boolean
console.log(simulation.controlResults); // Map<ControlId, ControlResult>

// Check specific control
const control24 = simulation.controlResults.get('HP-24');
console.log(control24.passed);   // false
console.log(control24.error);    // 'TokensLocked'
console.log(control24.code);     // 6024
console.log(control24.details);  // { secondsRemaining, jurisdiction, regime }

// Module 2: check NAV-deviation variant of CB-21
const cb21 = simulation.controlResults.get('CB-21');
if (cb21.details?.variant === 'nav_deviation') {
  console.log('NAV-deviation circuit breaker triggered');
}

// Module 3: check federal-action variant of REG-42
const reg42 = simulation.controlResults.get('REG-42');
if (reg42.details?.variant === 'federal_action') {
  console.log('Federal action freeze active:', reg42.details.actionReferences);
}
```

**`ControlResult` type:**

```typescript
interface ControlResult {
  controlId: string;             // 'CV-01', 'HP-24', 'REG-42', etc.
  category:  string;             // 'Custody', 'HoldingPeriod', 'Regulatory', etc.
  passed:    boolean;
  error:     string | null;
  code:      number | null;
  details:   Record<string, unknown> | null;
  latencyMs: number;
}
```

#### Check Wallet Eligibility

Verify if a wallet can receive ST22 tokens (passes investor verification controls IV-07 through IV-14). The eligibility check is module-agnostic at the wallet level — module-specific eligibility (e.g., Module 3 enhanced beneficial-ownership depth) is enforced at Empire onboarding, not at this method.

```typescript
const eligibility = await client.hooks.checkWalletEligibility({
  mint:   mintAddress,
  wallet: receiverWallet,
});

console.log(eligibility.eligible);        // boolean
console.log(eligibility.kycVerified);     // boolean
console.log(eligibility.regimes);         // Array<'RegD' | 'RegS' | 'RegCF'>
console.log(eligibility.ofacClear);       // boolean
console.log(eligibility.amlScore);        // number (0-100)
console.log(eligibility.amlDisposition);  // 'approve' | 'review' | 'reject'
console.log(eligibility.walletPercent);   // current holdings as % of supply
console.log(eligibility.withinLimit);     // boolean
```

***

### 6. Custody Oracle

The Custody Oracle is module-agnostic. The same Empire Ed25519-signed attestation flow serves Module 1 (Common Class B equity), Module 2 (single-asset entity equity), and Module 3 (basin-asset entity equity). The asset class is recorded in the SecurityConfig metadata; the custody oracle tracks the unit count and the on-chain supply.

#### Get Custody Attestation

```typescript
const custody = await client.custody.getAttestation(mintAddress);

console.log(custody.custodiedBalance);     // 1_000_000_000n (Empire-custodied)
console.log(custody.tokenSupply);          // 1_000_000_000n (on-chain supply)
console.log(custody.ratio);                // 1.0 (must be exactly 1:1)
console.log(custody.ed25519Verified);      // true
console.log(custody.discrepancyDetected);  // false
console.log(custody.attestationSlot);      // 285_000_000n
console.log(custody.attestationTimestamp); // 1711929600
```

#### Verify Ed25519 Signature

Independently verify the Empire attestation signature.

```typescript
const verified = await client.custody.verifySignature(mintAddress);

console.log(verified.valid);          // boolean
console.log(verified.empirePubkey);   // PublicKey
console.log(verified.payload);        // CustodyAttestationPayload
console.log(verified.signature);      // Uint8Array (64 bytes)
```

#### Watch Custody (Real-Time)

Subscribe to custody attestation updates (\~400ms per block). Works uniformly across modules.

```typescript
const unsubscribe = client.custody.watch(mintAddress, (attestation) => {
  console.log(`Slot ${attestation.attestationSlot}: ratio=${attestation.ratio}`);

  if (attestation.discrepancyDetected) {
    console.error('CUSTODY DISCREPANCY — Error 6001');
    // All transfers halted on this mint
  }
});

// Stop watching
unsubscribe();
```

***

### 7. NAV Oracle (Module 2)

The NAV Oracle holds the most recent appraised Net Asset Value for a Module 2 ST22 mint. Calls are valid only for Module 2 mints — calling these methods against a Module 1 or Module 3 mint returns `null`.

#### Get NAV Oracle

```typescript
const nav = await client.oracle.getNAV(module2MintAddress);

if (!nav) {
  // mint is not Module 2, or NAV oracle not initialized
  return;
}

console.log(nav.appraisedNavUsd);       // bigint — USD-pegged stablecoin units
console.log(nav.appraiserId);            // licensed appraiser identifier
console.log(nav.appraisalTimestamp);     // 1729785600
console.log(nav.nextReappraisalTarget); // 1745510400
console.log(nav.deviationToleranceBps);  // 2200 (22%)
console.log(nav.isStale);                // false
console.log(nav.ed25519Verified);        // true
```

#### Compute NAV Deviation

Convenience helper to compute the on-chain price's deviation from the most recent NAV.

```typescript
const deviation = await client.oracle.computeNAVDeviation(module2MintAddress);

console.log(deviation.onChainPriceUsd);  // current AMM price in USD-pegged units
console.log(deviation.appraisedNavUsd);  // most recent NAV
console.log(deviation.deviationBps);     // signed basis points
console.log(deviation.withinTolerance);  // boolean — true if |deviationBps| <= deviationToleranceBps
console.log(deviation.daysSinceAppraisal); // float
```

#### Watch NAV (Real-Time)

```typescript
const unsubscribe = client.oracle.watchNAV(module2MintAddress, (update) => {
  console.log(`NAV updated: $${update.appraisedNavUsd}`);
  console.log(`Next reappraisal: ${new Date(update.nextReappraisalTarget * 1000).toISOString()}`);
});
```

***

### 8. Classification Oracle (Module 3)

The Classification Oracle holds the most recent USGS Critical Minerals List classification, DOE Critical Materials Strategy status, and federal-action status for a Module 3 ST22 mint's basin asset. Calls are valid only for Module 3 mints — calling these methods against a Module 1 or Module 2 mint returns `null`.

#### Get Classification Oracle

```typescript
const classification = await client.oracle.getClassification(module3MintAddress);

if (!classification) {
  // mint is not Module 3, or Classification oracle not initialized
  return;
}

console.log(classification.usgsCriticalStatus);    // "critical_mineral_rare_earth"
console.log(classification.doeMaterialsStatus);    // "high_priority"
console.log(classification.section232Applicable);  // false
console.log(classification.dpaTitleIIIApplicable); // false
console.log(classification.federalActionActive);   // false
console.log(classification.activeActionRefs);      // []
console.log(classification.lastRefreshTimestamp);  // 1729828800
console.log(classification.isStale);               // false
```

#### Watch Classification (Real-Time)

The classification subscription emits both routine refresh events and high-severity federal-action events. Federal-action events warrant immediate operational response under the Incident Response Playbook §13.

```typescript
const unsubscribe = client.oracle.watchClassification(module3MintAddress, (update) => {
  if (update.eventType === 'federal_action_detected') {
    console.error('[P0] Federal action detected:', update.actionReferences);
    console.error('Detection-to-freeze SLA: 60 minutes');
    return;
  }

  if (update.eventType === 'federal_action_freeze_applied') {
    console.error('Control 42 freeze applied to mint:', update.mint.toBase58());
    return;
  }

  // Routine classification update
  console.log(`USGS: ${update.usgsCriticalStatus}, DOE: ${update.doeMaterialsStatus}`);
});
```

***

### 9. Holding Period

#### Get Holding Period Status

Check an investor's holding period status for a specific ST22 mint. The same method serves Reg D, Reg S, and Reg CF investors regardless of which module the mint belongs to.

```typescript
const holding = await client.holdingPeriod.getStatus({
  mint:        mintAddress,
  beneficiary: investorWallet,
});

console.log(holding.jurisdiction);      // 'US' | 'NonUS' | 'RegCF'
console.log(holding.regime);            // 'RegD' | 'RegS' | 'RegCF'
console.log(holding.holdingPeriodSecs); // 15_778_800 (Reg D) or 31_536_000 (Reg S / Reg CF)
console.log(holding.purchaseTimestamp); // 1711929600
console.log(holding.unlockTimestamp);   // 1727708400
console.log(holding.isLocked);          // true
console.log(holding.secondsRemaining);  // 1572300

// Human-readable unlock date
console.log(holding.unlockDate);    // Date object
console.log(holding.unlockDateISO); // '2026-09-30T00:00:00Z'
```

#### Batch Holding Period Query

Check holding status across multiple mints for a single wallet. The query handles mints from any combination of modules in a single call.

```typescript
const statuses = await client.holdingPeriod.getBatch({
  beneficiary: investorWallet,
  mints:       [mintM1, mintM2, mintM3],
});

for (const status of statuses) {
  console.log(`${status.mint}: regime=${status.regime}, locked=${status.isLocked}, ` +
              `remaining=${status.secondsRemaining}s`);
}
```

#### PDA Derivation

```typescript
const [holdingPda, bump] = client.holdingPeriod.derivePDA(mintAddress, investorWallet);
// Seeds: [b"holding-period", mint, beneficiary]
```

***

### 10. CEDEX Trading

All CEDEX trading operations require an authenticated wallet that has passed Empire Stock Transfer KYC, KYB, AML, OFAC, and KYW verification. The same method signatures serve mints from all three modules; module-specific behavior surfaces inside the pre-flight compliance pipeline.

#### Place Order

```typescript
// Market buy
const marketOrder = await client.cedex.placeOrder({
  mint:        mintAddress,
  side:        'buy',
  type:        'market',
  amount:      50_000_000n,      // ST22 token amount (with decimals)
  slippageBps: 100,              // 1% max slippage
});

console.log(marketOrder.orderId);
console.log(marketOrder.status);            // 'filled'
console.log(marketOrder.executedAmount);    // bigint
console.log(marketOrder.executedPrice);     // number (SOL per token)
console.log(marketOrder.txSignature);       // Solana transaction signature
console.log(marketOrder.complianceCheck);   // 'passed'
console.log(marketOrder.controlsExecuted);  // 42

// Limit sell
const limitOrder = await client.cedex.placeOrder({
  mint:       mintAddress,
  side:       'sell',
  type:       'limit',
  amount:     100_000_000n,
  limitPrice: 0.0001153,         // SOL per token
  expiry:     Math.floor(Date.now() / 1000) + 86400,  // 24h
});

console.log(limitOrder.orderId);
console.log(limitOrder.status);  // 'open'
```

**Compliance flow.** Every order passes through pre-flight compliance verification (2–3 seconds) before on-chain execution. The pre-flight pipeline includes module-aware checks: Module 2 orders are pre-validated against the NAV-deviation tolerance; Module 3 orders are pre-validated against Classification freshness and federal-action status. If any check would reject the trade, the SDK returns the specific error code before submitting on chain — saving the user transaction fees.

#### Cancel Order

```typescript
const result = await client.cedex.cancelOrder(orderId);
console.log(result.status);  // 'cancelled'
```

#### Get Open Orders

```typescript
const orders = await client.cedex.getOpenOrders({
  wallet: myWallet,
  mint:   mintAddress,   // Optional — filter by mint
});

for (const order of orders) {
  console.log(`${order.orderId}: ${order.side} ${order.amount} @ ${order.limitPrice}`);
}
```

#### Estimate Swap Output

Preview a swap without executing — returns expected output, price impact, fee breakdown, and module-aware pre-flight result.

```typescript
const estimate = await client.cedex.estimateSwap({
  mint:        mintAddress,
  side:        'buy',
  inputAmount: 10_000_000_000n,  // 10 SOL in lamports
});

console.log(estimate.outputAmount);    // bigint — ST22 tokens received
console.log(estimate.effectivePrice);  // number — SOL per token
console.log(estimate.priceImpactBps);  // number — basis points impact
console.log(estimate.fee);             // { total, pool, issuer, staking, protocol }
console.log(estimate.wouldTriggerCircuitBreaker);  // boolean

// Module-aware pre-flight result
console.log(estimate.preFlightResult);
// {
//   passed: boolean,
//   failureReason: 'HOLDING_PERIOD_LOCKED' | 'PRICE_IMPACT_EXCEEDED' |
//                  'NAV_DEVIATION_EXCEEDED' (M2) |
//                  'NAV_STALE' (M2) |
//                  'CLASSIFICATION_STALE' (M3) |
//                  'FEDERAL_ACTION_FROZEN' (M3) | ...,
//   moduleScope: 'all_modules' | 'module_2' | 'module_3'
// }

// Fee breakdown — same across all modules
console.log(estimate.fee.totalBps);    // 500 (5%)
console.log(estimate.fee.poolBps);     // 44 (0.44% → Global Pool, permanently locked)
console.log(estimate.fee.issuerBps);   // 200 (2% → issuer treasury)
console.log(estimate.fee.stakingBps);  // 150 (1.5% → GROO staking pool)
console.log(estimate.fee.protocolBps); // 106 (1.06% → protocol operations)
```

***

### 11. Portfolio Management

#### Get Portfolio

Returns all ST22 holdings for a wallet across all modules with holding-period status, custody-verification status, and module-aware oracle status.

```typescript
const portfolio = await client.portfolio.get(myWallet);

for (const position of portfolio.positions) {
  console.log(`${position.symbol} (${position.module}): ${position.balance} tokens`);
  console.log(`  Value: ${position.valueSol} SOL`);
  console.log(`  Locked: ${position.isLocked}`);
  console.log(`  Unlock: ${position.unlockDateISO ?? 'unlocked'}`);
  console.log(`  Regime: ${position.regime}`);   // 'RegD' | 'RegS' | 'RegCF'
  console.log(`  Custody verified: ${position.custodyVerified}`);
  console.log(`  % of supply: ${position.percentOfSupply}%`);

  // Module 2: NAV status surfaced
  if (position.module === 'real_estate' && position.navStatus) {
    console.log(`  NAV deviation: ${position.navStatus.deviationBps} bps`);
    console.log(`  NAV stale: ${position.navStatus.isStale}`);
  }

  // Module 3: Classification status surfaced
  if (position.module === 'corecm' && position.classificationStatus) {
    console.log(`  Federal action active: ${position.classificationStatus.federalActionActive}`);
    console.log(`  Classification stale: ${position.classificationStatus.isStale}`);
  }
}

console.log(`Total positions: ${portfolio.positions.length}`);
console.log(`Module 1 positions: ${portfolio.byModule.equities}`);
console.log(`Module 2 positions: ${portfolio.byModule.realEstate}`);
console.log(`Module 3 positions: ${portfolio.byModule.corecm}`);
console.log(`Total value: ${portfolio.totalValueSol} SOL`);
```

#### Get Position Detail

```typescript
const position = await client.portfolio.getPosition({
  wallet: myWallet,
  mint:   mintAddress,
});

console.log(position.balance);            // bigint
console.log(position.holdingPeriod);      // HoldingPeriodAccount
console.log(position.custodyAttestation); // CustodyOracleState
console.log(position.securityConfig);     // SecurityConfig
console.log(position.navOracle);          // NAVOracleState | null (M2 only)
console.log(position.classificationOracle); // ClassificationOracleState | null (M3 only)
```

***

### 12. Market Data

#### List Markets

```typescript
// All markets across all modules
const markets = await client.markets.list();

// Filter by module
const m2Markets = await client.markets.list({ module: 'real_estate' });
const m3Markets = await client.markets.list({ module: 'corecm' });

for (const market of markets) {
  console.log(`${market.symbol} (${market.module}): $${market.price} | Vol: ${market.volume24h}`);
  console.log(`  Mint: ${market.mint}`);
  console.log(`  Issuer: ${market.issuerName}`);
  console.log(`  Pool depth: ${market.poolDepthSol} SOL`);
}
```

#### Get Order Book

```typescript
const book = await client.markets.getOrderBook(mintAddress);

console.log('Bids:', book.bids.map(b => `${b.price} x ${b.amount}`));
console.log('Asks:', book.asks.map(a => `${a.price} x ${a.amount}`));
console.log('Spread:', book.spreadBps, 'bps');
```

#### Get Recent Trades

```typescript
const trades = await client.markets.getRecentTrades(mintAddress, {
  limit: 50,
});

for (const trade of trades) {
  console.log(`${trade.side} ${trade.amount} @ ${trade.price} | ${trade.txSignature}`);
}
```

#### Get OHLCV (Candlestick Data)

```typescript
const candles = await client.markets.getOHLCV(mintAddress, {
  interval: '1h',
  from:     Math.floor(Date.now() / 1000) - 86400,  // 24h ago
  to:       Math.floor(Date.now() / 1000),
});

for (const c of candles) {
  console.log(`${c.timestamp}: O=${c.open} H=${c.high} L=${c.low} C=${c.close} V=${c.volume}`);
}
```

***

### 13. WebSocket Subscriptions

Real-time data via WebSocket connection to CEDEX. Module-specific channels (`nav` for Module 2; `classification` for Module 3) work alongside cross-module channels on the same WebSocket connection.

```typescript
// Initialize WebSocket client
await client.ws.connect();
```

#### Subscribe to Order Book

```typescript
client.ws.subscribeOrderBook(mintAddress, (update) => {
  console.log('Bids:',      update.bids);
  console.log('Asks:',      update.asks);
  console.log('Timestamp:', update.timestamp);
});
```

#### Subscribe to Trades

```typescript
client.ws.subscribeTrades(mintAddress, (trade) => {
  console.log(`${trade.side}: ${trade.amount} @ ${trade.price}`);
  console.log(`TX: ${trade.txSignature}`);
});
```

#### Subscribe to Custody Oracle

Real-time custody attestation updates (\~400ms per block). Cross-module — works for Module 1, Module 2, and Module 3 mints.

```typescript
client.ws.subscribeCustody(mintAddress, (attestation) => {
  console.log(`Ratio: ${attestation.ratio} | Ed25519: ${attestation.ed25519Verified}`);
  if (attestation.discrepancyDetected) {
    console.error('CUSTODY DISCREPANCY DETECTED');
  }
});
```

#### Subscribe to NAV Oracle (Module 2)

```typescript
client.ws.subscribeNAV(module2MintAddress, (update) => {
  console.log(`NAV: $${update.appraisedNavUsd}`);
  console.log(`Deviation: ${update.deviationBps} bps`);
  console.log(`Stale: ${update.isStale}`);
});
```

#### Subscribe to Classification Oracle (Module 3)

```typescript
client.ws.subscribeClassification(module3MintAddress, (update) => {
  if (update.eventType === 'federal_action_detected') {
    console.error('[P0] Federal action detected:', update.actionReferences);
    return;
  }
  if (update.eventType === 'federal_action_freeze_applied') {
    console.error('Control 42 freeze applied');
    return;
  }
  console.log(`USGS: ${update.usgsCriticalStatus}, DOE: ${update.doeMaterialsStatus}`);
});
```

#### Subscribe to Circuit Breaker Events

```typescript
client.ws.subscribeCircuitBreaker(mintAddress, (event) => {
  console.log(`Breaker: ${event.type}`);
  // 'price_halt' | 'price_impact' | 'volume_halt' | 'nav_deviation' (M2) |
  // 'classification_stale' (M3)
  console.log(`Triggered: ${event.triggered}`);
  console.log(`Cooldown: ${event.cooldownSecs}s`);
  console.log(`Resume at: ${event.resumeTimestamp}`);
});
```

#### Disconnect

```typescript
client.ws.disconnect();
```

***

### 14. Error Handling

#### RwaTokensError Class

All SDK errors extend `RwaTokensError` with structured error data. Module-specific control failures expose a `moduleScope` field on `details` indicating which module's variant fired.

```typescript
import { RwaTokensError, TransferHookError } from '@rwatokens/sdk';

try {
  await client.cedex.placeOrder({ /* ... */ });
} catch (error) {
  if (error instanceof TransferHookError) {
    console.log(error.code);        // 6024
    console.log(error.name);        // 'TokensLocked'
    console.log(error.message);     // 'Tokens locked — Reg D / Reg S / Reg CF holding period not elapsed'
    console.log(error.controlId);   // 'HP-24'
    console.log(error.category);    // 'HoldingPeriod'
    console.log(error.details);     // { secondsRemaining, jurisdiction, regime, unlockTimestamp }
    console.log(error.moduleScope); // 'all_modules' | 'module_2' | 'module_3'
    console.log(error.recoverable); // true (will unlock after holding period)
  }
}
```

#### Error Code Registry

| Code      | Name                     | Category        | Recoverable       | Module Scope                            | Action                                                                                     |
| --------- | ------------------------ | --------------- | ----------------- | --------------------------------------- | ------------------------------------------------------------------------------------------ |
| 6001      | CustodyDiscrepancy       | Custody         | No — system-level | All                                     | Wait for oracle consensus. Contact platform support.                                       |
| 6002      | CustodyOracleUnavailable | Custody         | Yes — transient   | All                                     | Retry after 1 block (\~400ms).                                                             |
| 6003      | SenderSanctioned         | Sanctions       | No                | All                                     | OFAC-flagged wallet. Cannot trade.                                                         |
| 6004      | ReceiverSanctioned       | Sanctions       | No                | All                                     | Receiver is OFAC-flagged. Cannot receive.                                                  |
| 6005      | OfacOracleStale          | Sanctions       | Yes — transient   | All                                     | OFAC oracle refreshing. Retry in minutes.                                                  |
| 6006      | AMLHighRisk              | AML             | No                | All                                     | AML score >70. Contact Empire Stock Transfer.                                              |
| 6007      | InvalidSigner            | CEI             | No                | All                                     | Transaction not properly signed.                                                           |
| 6008–6019 | Structural Integrity     | CEI             | Varies            | All                                     | See detailed error message.                                                                |
| 6020      | WalletLimitExceeded      | Position        | Yes               | All                                     | Reduce order size below per-mint cap (4.99% default; up to 9.99% for some Module 2 mints). |
| 6021      | PriceImpactExceeded      | Circuit Breaker | Yes               | All; M2 includes NAV-deviation variant  | Reduce order size or split. M2: check NAV deviation.                                       |
| 6022      | VelocityExceeded         | Position        | Yes — timed       | All                                     | Slow down — wait for velocity window.                                                      |
| 6023      | CrossWalletDetected      | Position        | No                | All                                     | Behavioral clustering flagged. Contact compliance.                                         |
| 6024      | TokensLocked             | Holding Period  | Yes — timed       | All; Reg D / Reg S / Reg CF variants    | Wait for the applicable Reg D / Reg S / Reg CF holding period.                             |
| 6036      | GlobalCircuitBreaker     | Emergency       | Yes — timed       | All                                     | All trading halted. Wait for cooldown (15 min).                                            |
| 6037      | DailySellLimitExceeded   | Volume          | Yes — timed       | All                                     | 30% daily sell limit reached. Wait 24h.                                                    |
| 6038      | CustodyDiscrepancyHalt   | Emergency       | No — system-level | All                                     | Custody issue. Wait for 2-of-3 oracle consensus.                                           |
| 6039      | OFACEmergencyBlock       | Emergency       | No                | All                                     | Treasury emergency SDN update.                                                             |
| 6040      | OracleConsensusFail      | Emergency       | Yes — transient   | All                                     | Oracle consensus not reached. Retry.                                                       |
| 6041      | ControlledMigration      | Governance      | Yes — timed       | All                                     | Upgrade in progress. Wait for completion.                                                  |
| 6042      | RegulatoryOverride       | Regulatory      | No                | All; M3 includes federal-action variant | Legal Counsel + 3-of-5 multi-sig freeze. M3: federal action active.                        |

#### Error Recovery Pattern

```typescript
import { RwaTokensError, TransferHookError, isRetryable } from '@rwatokens/sdk';

async function executeWithRetry(fn: () => Promise<void>, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (error instanceof TransferHookError) {
        if (!isRetryable(error.code)) {
          // Non-recoverable — surface to user
          throw error;
        }

        // Retryable error — exponential backoff
        const delay = Math.pow(2, attempt) * 1000;
        console.warn(`Retryable error ${error.code}: ${error.name}. Retry in ${delay}ms`);
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}
```

***

### 15. Utilities

#### PDA Derivation

```typescript
import { derivePDA } from '@rwatokens/sdk';

// Cross-module PDAs
const [securityConfig, b1] = derivePDA.securityConfig(mintAddress);
// Seeds: [b"security-config", mint]

const [holdingPeriod, b2] = derivePDA.holdingPeriod(mintAddress, beneficiaryWallet);
// Seeds: [b"holding-period", mint, beneficiary]

const [custodyOracle, b3] = derivePDA.custodyOracle(mintAddress);
// Seeds: [b"custody-oracle", mint]

const [ofacOracle,   b4] = derivePDA.ofacOracle();
// Seeds: [b"ofac-oracle"]

const [amlOracle,    b5] = derivePDA.amlOracle(walletAddress);
// Seeds: [b"aml-oracle", wallet]

// Module 2 — NAV oracle
const [navOracle,    b6] = derivePDA.navOracle(module2MintAddress);
// Seeds: [b"nav-oracle", mint]

// Module 3 — Classification oracle
const [classificationOracle, b7] = derivePDA.classificationOracle(module3MintAddress);
// Seeds: [b"classification-oracle", mint]
```

#### Format Helpers

```typescript
import { format } from '@rwatokens/sdk';

format.bpsToPercent(499);                    // '4.99%'
format.bpsToPercent(200);                    // '2.00%'
format.bpsToPercent(2200);                   // '22.00%' (default M2 NAV deviation tolerance)
format.lamportsToSol(10_000_000_000n);       // '10.000000000'
format.tokenAmount(1_000_000_000n, 9);       // '1.000000000'
format.holdingPeriod(15_778_800);            // '6 months (Reg D)'
format.holdingPeriod(31_536_000, 'NonUS');   // '12 months (Reg S)'
format.holdingPeriod(31_536_000, 'RegCF');   // '12 months (Reg CF)'
format.secondsToHuman(1572300);              // '18d 4h 45m'
format.controlId(24);                        // 'HP-24'
format.errorCode(6024);                      // 'TokensLocked (6024): Holding Period'
format.module('equities');                   // 'Module 1 — Equities'
format.module('real_estate');                // 'Module 2 — Real Estate'
format.module('corecm');                     // 'Module 3 — CORECM'
```

#### Anchor IDL

Access the raw Anchor IDL for advanced use cases.

```typescript
import { IDL } from '@rwatokens/sdk';

// Transfer Hook IDL
const hookIdl = IDL.transferHook;

// AMM IDL
const ammIdl = IDL.amm;

// Oracle Aggregator IDL (includes NAV and Classification oracle accounts)
const oracleIdl = IDL.oracleAggregator;

// Use with Anchor Program
import { Program } from '@coral-xyz/anchor';
const hookProgram = new Program(hookIdl, programId, provider);
```

***

### 16. Security Best Practices

#### Wallet Key Management

```typescript
// NEVER hardcode private keys
// Bad
const wallet = Keypair.fromSecretKey(new Uint8Array([1, 2, 3, /* ... */]));

// Use environment variables
const wallet = Keypair.fromSecretKey(
  Uint8Array.from(JSON.parse(process.env.WALLET_PRIVATE_KEY!))
);

// Use Ledger hardware wallet for institutional operations
import { LedgerWallet } from '@rwatokens/sdk/ledger';
const wallet = await LedgerWallet.connect();
```

#### Transaction Verification

```typescript
// Always verify Transfer Hook status before interacting with a mint
const status = await client.hooks.verify(mintAddress);
if (!status.isValid || status.controlsActive !== 42) {
  throw new Error('Mint does not have valid Transfer Hook');
}

// Always verify custody before trading (cross-module)
const custody = await client.custody.getAttestation(mintAddress);
if (custody.ratio !== 1.0 || custody.discrepancyDetected) {
  throw new Error('Custody discrepancy — do not trade');
}

// Module 2: verify NAV freshness and deviation
const config = await client.hooks.getSecurityConfig(mintAddress);
if (config.module === 'real_estate') {
  const dev = await client.oracle.computeNAVDeviation(mintAddress);
  if (!dev.withinTolerance) {
    throw new Error(`NAV deviation ${dev.deviationBps} bps outside tolerance`);
  }
}

// Module 3: verify federal-action status
if (config.module === 'corecm') {
  const cls = await client.oracle.getClassification(mintAddress);
  if (cls?.federalActionActive) {
    throw new Error('Federal action freeze active — cannot trade');
  }
}
```

#### Rate Limiting

```typescript
// SDK enforces rate limits to prevent RPC throttling
// Default: 100 requests/second, 50 sendTransaction/second
const client = new RwaTokensClient({
  network:    'mainnet-beta',
  rateLimits: {
    requestsPerSecond: 100,
    sendTxPerSecond:   50,
  },
});
```

***

### 17. Network Configuration

#### Devnet

```typescript
const client = new RwaTokensClient({
  network:     'devnet',
  rpcEndpoint: 'https://devnet.helius-rpc.com/?api-key=YOUR_KEY',
});

// Devnet has the same program structure but uses test oracle data:
//   Custody oracle:        simulated Empire attestations
//   OFAC oracle:           test SDN list
//   AML oracle:            configurable test scores
//   NAV oracle (M2):       simulated NAV with configurable cadence
//   Classification (M3):   test critical-mineral and federal-action data
```

#### Mainnet

```typescript
const client = new RwaTokensClient({
  network:     'mainnet-beta',
  rpcEndpoint: 'https://mainnet.helius-rpc.com/?api-key=YOUR_KEY',
  jitoEnabled: true,    // MEV protection for production trades
  commitment:  'confirmed',
  priorityFee: 'auto',  // Dynamic Jito tip
});
```

#### Localnet (Development)

```typescript
const client = new RwaTokensClient({
  network:     'localnet',
  rpcEndpoint: 'http://localhost:8899',
});

// Deploy local programs first:
// anchor deploy --provider.cluster localnet
```

***

### 18. Examples

#### Example 1: Verify an ST22 Token (any module)

```typescript
import { RwaTokensClient } from '@rwatokens/sdk';
import { PublicKey }       from '@solana/web3.js';

const client = new RwaTokensClient({ network: 'mainnet-beta' });
const mint   = new PublicKey('7xK...');

// 1. Verify Transfer Hook is attached
const hook = await client.hooks.verify(mint);
console.log(`Hook active: ${hook.isValid}`);
console.log(`Controls: ${hook.controlsActive}`);
console.log(`Bypass possible: ${hook.bypassPossible}`);

// 2. Read security config — surfaces module
const config = await client.hooks.getSecurityConfig(mint);
console.log(`Module: ${config.module}`);
console.log(`Max wallet: ${config.maxWalletPercent / 100}%`);
console.log(`Price impact limit: ${config.priceImpactMaxBps / 100}%`);
console.log(`Circuit breaker: ${config.circuitBreakerTriggered ? 'ACTIVE' : 'normal'}`);

// 3. Check custody attestation (cross-module)
const custody = await client.custody.getAttestation(mint);
console.log(`Custodied balance: ${custody.custodiedBalance}`);
console.log(`Token supply: ${custody.tokenSupply}`);
console.log(`1:1 ratio: ${custody.ratio === 1.0}`);
console.log(`Ed25519 verified: ${custody.ed25519Verified}`);

// 4. Module-specific oracle checks
if (config.module === 'real_estate') {
  const nav = await client.oracle.getNAV(mint);
  console.log(`NAV: $${nav?.appraisedNavUsd}`);
  console.log(`NAV stale: ${nav?.isStale}`);
}

if (config.module === 'corecm') {
  const cls = await client.oracle.getClassification(mint);
  console.log(`USGS: ${cls?.usgsCriticalStatus}`);
  console.log(`Federal action active: ${cls?.federalActionActive}`);
}
```

#### Example 2: Check Holding Period Before Selling

```typescript
import { RwaTokensClient, TransferHookError } from '@rwatokens/sdk';

const client = new RwaTokensClient({ network: 'mainnet-beta', wallet });

const holding = await client.holdingPeriod.getStatus({
  mint:        mintAddress,
  beneficiary: wallet.publicKey,
});

if (holding.isLocked) {
  console.log(`Tokens locked until ${holding.unlockDateISO}`);
  console.log(`${holding.secondsRemaining} seconds remaining`);
  console.log(`Regime: ${holding.regime}`);
  console.log(
    `Rule: ${holding.regime === 'RegD'  ? 'Reg D (6 months)'
        : holding.regime === 'RegS'  ? 'Reg S (12 months)'
        : 'Reg CF (12 months)'}`
  );
} else {
  // Safe to sell
  const order = await client.cedex.placeOrder({
    mint:        mintAddress,
    side:        'sell',
    type:        'market',
    amount:      holding.balance,
    slippageBps: 100,
  });
  console.log(`Sold: TX ${order.txSignature}`);
}
```

#### Example 3: Real-Time Custody Monitoring (cross-module)

```typescript
import { RwaTokensClient } from '@rwatokens/sdk';

const client = new RwaTokensClient({ network: 'mainnet-beta' });
await client.ws.connect();

// Monitor all custody attestations for a mint — works for any module
client.ws.subscribeCustody(mintAddress, (attestation) => {
  const { custodiedBalance, tokenSupply, ratio, ed25519Verified } = attestation;

  if (ratio !== 1.0 || !ed25519Verified) {
    console.error(`[ALERT] Custody issue on ${mintAddress}`);
    console.error(`  Custodied: ${custodiedBalance}, Supply: ${tokenSupply}, Ratio: ${ratio}`);
    // All transfers will be halted by Transfer Hook Controls CV-01 to CV-06
  }
});

// Monitor circuit breaker events (includes M2 nav_deviation, M3 classification_stale)
client.ws.subscribeCircuitBreaker(mintAddress, (event) => {
  console.warn(`[BREAKER] ${event.type} triggered on ${mintAddress}`);
  console.warn(`  Cooldown: ${event.cooldownSecs}s`);
});
```

#### Example 4: Module 2 NAV Monitoring

```typescript
import { RwaTokensClient } from '@rwatokens/sdk';

const client = new RwaTokensClient({ network: 'mainnet-beta' });
await client.ws.connect();

// Monitor NAV oracle for a Module 2 mint
client.ws.subscribeNAV(module2MintAddress, async (update) => {
  console.log(`NAV updated: $${update.appraisedNavUsd}`);
  console.log(`Next reappraisal: ${new Date(update.nextReappraisalTarget * 1000).toISOString()}`);

  // Check current deviation from on-chain price
  const dev = await client.oracle.computeNAVDeviation(module2MintAddress);
  console.log(`Deviation: ${dev.deviationBps} bps`);
  console.log(`Within tolerance: ${dev.withinTolerance}`);

  if (!dev.withinTolerance) {
    console.warn('[ALERT] Mint paused on AMM until NAV deviation restored');
  }
});
```

#### Example 5: Module 3 Federal-Action Monitoring

```typescript
import { RwaTokensClient } from '@rwatokens/sdk';

const client = new RwaTokensClient({ network: 'mainnet-beta' });
await client.ws.connect();

// Monitor Classification oracle for a Module 3 mint
client.ws.subscribeClassification(module3MintAddress, (update) => {
  if (update.eventType === 'federal_action_detected') {
    console.error('[P0] Federal action detected:', update.actionReferences);
    console.error('Detection-to-freeze SLA: 60 minutes');
    // Operational response per Incident Response Playbook §13
    return;
  }

  if (update.eventType === 'federal_action_freeze_applied') {
    console.error('Control 42 freeze applied — mint frozen');
    return;
  }

  // Routine classification refresh
  console.log(`USGS: ${update.usgsCriticalStatus}`);
  console.log(`DOE: ${update.doeMaterialsStatus}`);
});
```

#### Example 6: Simulate Before Trading (module-aware)

```typescript
import { RwaTokensClient, TransferHookError, isRetryable } from '@rwatokens/sdk';

const client = new RwaTokensClient({ network: 'mainnet-beta', wallet });

// Step 1: Simulate the transfer
const sim = await client.hooks.simulateTransfer({
  mint:        mintAddress,
  source:      wallet.publicKey,
  destination: recipientWallet,
  amount:      50_000_000n,
});

if (!sim.wouldSucceed) {
  // Find which control failed
  for (const [id, result] of sim.controlResults) {
    if (!result.passed) {
      console.error(`Control ${id} failed: ${result.error} (${result.code})`);
      console.error(`  Details: ${JSON.stringify(result.details)}`);

      if (result.code === 6024) {
        console.log(`  Regime: ${result.details.regime}`);
        console.log(`  Unlock in: ${result.details.secondsRemaining}s`);
      }
      if (result.code === 6020) {
        console.log(`  Current: ${result.details.currentPercent}%, Max: ${result.details.maxPercent}%`);
      }
      if (result.code === 6021 && result.details?.variant === 'nav_deviation') {
        console.log(`  NAV deviation: ${result.details.deviationBps} bps`);
        console.log(`  Tolerance: ${result.details.toleranceBps} bps`);
      }
      if (result.code === 6042 && result.details?.variant === 'federal_action') {
        console.log(`  Federal action references: ${result.details.actionReferences}`);
      }
    }
  }
  return;
}

// Step 2: Estimate the swap (module-aware pre-flight surfaces here)
const estimate = await client.cedex.estimateSwap({
  mint:        mintAddress,
  side:        'sell',
  inputAmount: 50_000_000n,
});

console.log(`Output: ${estimate.outputAmount} SOL`);
console.log(`Impact: ${estimate.priceImpactBps} bps`);
console.log(`Fee: ${estimate.fee.totalBps} bps`);
console.log(`Pre-flight: ${estimate.preFlightResult.passed ? 'PASS' : 'FAIL'}`);

// Step 3: Execute
if (estimate.preFlightResult.passed && !estimate.wouldTriggerCircuitBreaker) {
  const order = await client.cedex.placeOrder({
    mint:        mintAddress,
    side:        'sell',
    type:        'market',
    amount:      50_000_000n,
    slippageBps: 100,
  });
  console.log(`Executed: ${order.txSignature}`);
}
```

***

### Changelog

#### v1.0.0 (Q3 2026)

* Initial release — mainnet support across all three modules at launch.
* Module-aware client supporting Module 1 (Equities), Module 2 (Real Estate), and Module 3 (CORECM) on a single `RwaTokensClient` instance.
* Transfer Hook verification and module-aware simulation.
* Custody oracle queries with Ed25519 verification (cross-module).
* NAV oracle queries (Module 2) and Classification oracle queries (Module 3).
* Holding period status with Reg D, Reg S, and Reg CF regime support; batch queries.
* CEDEX order placement, cancellation, and module-aware pre-flight estimation.
* Portfolio management with module-aware position surfacing (NAV status, classification status).
* Market data (order book, trades, OHLCV) with module filter.
* WebSocket subscriptions including module-specific NAV (M2) and Classification (M3) channels.
* Full error code registry with module-aware variants for 6021 (NAV-deviation) and 6042 (federal-action).
* PDA derivation utilities including NAV oracle and Classification oracle.
* Anchor IDL exports.
* Ledger hardware wallet support.

***

### License

Business Source License 1.1 — See `LICENSE`.

***

### Related Documentation

* **CEDEX API Reference** — REST and WebSocket endpoints with module-aware surface.
* **CEDEX API Changelog** — Version history with module-aware migration guides.
* **Smart Contract Reference** — On-chain program documentation including module-aware program behavior.
* **Transfer Hook Reference** — Standalone reference for the 42 controls and module-aware extensions.
* **Oracle Integration Guide** — Custody, OFAC, AML, TWAP, EDGAR (M1), NAV (M2), and Classification (M3) relay architecture.
* **Network Configuration** — Mainnet program IDs, RPC endpoints, oracle PDAs.
* **Incident Response Playbook** — P0 through P3 runbooks; Module 3 federal-action freeze runbook (§13).

***

*`@rwatokens/sdk` · RWA Tokens · Groovy Company, Inc.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://bitbook.rwatokens.net/sdk-and-development/sdk-and-development/sdk-reference.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
