# @flop-labs/sdk

Ordinary HTLC creation requires a registered EconomicCritical appraisal profile.
Supply `tee_requirements` / `teeRequirements` as `{profile: {profile_id, version}, model_hash, measurement_hash}` (32-byte hex hashes), or its canonical 100-byte SCALE hex.
The runtime checks that the registered profile and immutable commitments match its policy; there is no simulator default.
For the examples, set `FLOP_HTLC_TEE_REQUIREMENTS` to that canonical hex from your network's registered profile.

TypeScript SDK for the FLOP Network — HTLC workflows, PoUI proofs, and account management.

`SUPPORTED_SPEC_VERSIONS` admits exactly `1013000`, `1014000`, `1014001`, `1014002`, `1014003`, `1014004`, `1014005` and `1014006`.
`SUPPORTED_SPEC_VERSION_RANGE` retains its exported shape as the envelope
`1013000..1014006`; intermediate versions are not admitted. Qualification covers
runtime `1013000` at `44a5fedc88614b9a6e8c97605c2ec943faf47d9d`, the
registrar runtime `1014000` at `e4f01cc849fa6c768d5c0f9c111dffb450ea4fa9`
(PR #2726), runtime `1014001` at `de4e2779dbf6f8d25348953ce0992ef8e89756bd`
(PR #2803), runtime `1014002`, the #2637 devnet hybrid-verifier fast path, and runtime
`1014003` at `9035450361681a69c6c02c9c53e47351999ef6f8` (PR #3096). Candidate runtime
`1014004` (1.14.4, PR #3006) has source compatibility coverage for uploader-funded
qualification. Candidate runtime `1014005` (1.14.5) has source compatibility coverage for the
preactivation FCU name replacement; this does not qualify physical latency or deployment.
Candidate runtime `1014006` (1.14.6) has source compatibility coverage for the
preactivation FCU governed adapter; this does not qualify physical latency or deployment.
Other versions require separate qualification.
Every `FlopClient` connection path checks it. Unsupported runtime upgrades detected
by polkadot.js metadata events disconnect the API and make subsequent SDK operations
raise `FlopError` with code `RUNTIME_INCOMPATIBLE`, the qualified versions, and upgrade guidance.
Generated clients apply the same exact-version guard; explicit profile constraints can
narrow compatibility and require a spec name. Upgrade with `pnpm add @flop-labs/sdk@latest` to a release
supporting the chain's runtime; allowlist changes require compatibility validation.

## Installation

```bash
npm install @flop-labs/sdk
```

### Peer Dependencies

React is optional (only needed if using React hooks):

```bash
npm install @flop-labs/sdk react  # Optional: for React integration
```

## Quick Start

```typescript
import { FlopClient, createAgentWallet } from '@flop-labs/sdk';

// Connect to FLOP node
const client = new FlopClient({
  rpcUrl: 'http://127.0.0.1:16111/rpc'
});

// Check node health
const health = await client.health();
console.log('Node healthy:', health);

// Create an agent wallet
const wallet = await createAgentWallet(client, {
  agentId: 'my-agent',
  dailyLimit: 100,  // FLOP tokens
});

// Create HTLC for inference purchase
const htlc = await client.createHtlc({
  agent: 'my-agent',
  task: {
    model: 'llama-3-8b',
    prompt: 'Hello, world!',
    tee_requirements: process.env.FLOP_HTLC_TEE_REQUIREMENTS
  },
  rewardAmount: 5.0,
  timeoutBlocks: 60
});

console.log('HTLC created:', htlc.htlcId);

// Wait for settlement
const status = await client.waitForSettlement(htlc.hashLock);
console.log('Settlement:', status);
```

## API Reference

### FlopClient

Main client for interacting with the FLOP Network.

#### Constructor

```typescript
new FlopClient(options?: FlopClientOptions)
```

**Options:**
- `rpcUrl` (string, optional): RPC endpoint URL. Default: `http://127.0.0.1:16111/rpc`
- `wsUrl` (string, optional): WebSocket endpoint for subscriptions

#### Methods

##### `health()`

Check node health status.

```typescript
await client.health();
// Returns: { isSyncing: boolean, peers: number, shouldHavePeers: boolean }
```

##### `createHtlc(params)`

Create a Hash Time Lock Contract for atomic inference purchase.

```typescript
await client.createHtlc({
  agent: string,
  task: ComputeTask,
  rewardAmount: number,
  timeoutBlocks: number,
  hashLock?: string  // Auto-generated if not provided
});
```

**Returns:**
```typescript
{
  htlcId: string;
  hashLock: string;
  preImage: string;
  status: 'CREATED';
}
```

##### `createCrossChainHtlc(params)`

Create a cross-chain HTLC for a FLOP ↔ BTC atomic swap (bilateral HTLC path). The
FLOP leg must outlive the counter-chain leg (timelock symmetry, enforced on-chain),
so `timeoutBlocks` is the longer leg and `btcTimelockHours` the shorter. USDT on
TON/TRON settles via NEAR Intents instead — see `docs/bridge/settlement.md`.

```typescript
await client.createCrossChainHtlc({
  agent: string,
  task: ComputeTask,
  rewardFlop: number,
  btcAddress: string,
  btcAmountSats: number | bigint,
  timeoutBlocks?: number,    // FLOP side, default 7200 (~2h)
  btcTimelockHours?: number, // counter-chain side, default 1
  hashLock?: string          // auto-generated if omitted
});
```

##### `checkHtlcStatus(hashLock)`

Query HTLC status by hash lock.

```typescript
await client.checkHtlcStatus('0x...');
// Returns: { status: string, agent: string, rewardAmount: number, timeoutBlock: number }
```

##### `waitForSettlement(hashLock, timeoutSeconds?, pollInterval?)`

Poll HTLC until settled or timeout.

```typescript
await client.waitForSettlement('0x...', 30, 1.0);
// Returns: { status: 'SETTLED', miner: string, gnUsed: number } | null
```

##### `getBalance(address)`

Get account balance in FLOP tokens.

```typescript
await client.getBalance('flop1qyq...');
// Returns: number
```

##### `submitPoUI(proofs, gnWeight, taskHash)`

Submit TEE-verified PoUI proof batch.

```typescript
await client.submitPoUI(proofs, 1450, '0x...');
```

##### `getAccountInfo(address)`

Get account information including nonce and metadata.

```typescript
await client.getAccountInfo('flop1qyq...');
```

##### `getComputeTask(taskId)`

Get compute task details.

```typescript
await client.getComputeTask('task_0x...');
```

##### `getTeeQuote(task)`

Get TEE quote for compute task.

```typescript
await client.getTeeQuote({ model: 'llama-3-8b', prompt: '...' });
```

### Agent Wallet

Create and manage agent wallets with session keys.

#### `createAgentWallet(client, options)`

Create a new agent wallet.

```typescript
import { createAgentWallet } from '@flop-labs/sdk';

const wallet = await createAgentWallet(client, {
  agentId: 'my-agent',
  dailyLimit: 100,
  allowedPallets: ['htlc', 'poui']
});
```

#### `fundAgentWallet(client, walletAddress, amount)`

Fund an agent wallet from owner account.

```typescript
import { fundAgentWallet } from '@flop-labs/sdk';

await fundAgentWallet(client, 'flop1agent...', 50.0);
```

#### `agentTransfer(client, fromWallet, toAddress, amount)`

Transfer funds between agent wallets.

```typescript
import { agentTransfer } from '@flop-labs/sdk';

await agentTransfer(client, 'flop1agent1...', 'flop1agent2...', 10.0);
```

#### `ownerWithdraw(client, walletAddress, amount)`

Withdraw funds from agent wallet to owner account.

```typescript
import { ownerWithdraw } from '@flop-labs/sdk';

await ownerWithdraw(client, 'flop1agent...', 25.0);
```

#### `createSession(client, walletAddress, options)`

Create a session key with spending limits.

```typescript
import { createSession } from '@flop-labs/sdk';

const session = await createSession(client, 'flop1agent...', {
  spendingLimit: 10.0,
  expiresAt: Date.now() + 3600000  // 1 hour
});
```

#### `executeViaSession(client, sessionKey, call)`

Execute a call using session key.

```typescript
import { executeViaSession } from '@flop-labs/sdk';

await executeViaSession(client, sessionKey, {
  pallet: 'htlc',
  method: 'create',
  args: { ... }
});
```

### x402 Payment Protocol

Utilities for x402 payment headers.

#### `x402Fetch(url, options, paymentParams)`

Fetch with x402 payment headers.

```typescript
import { x402Fetch } from '@flop-labs/sdk';

const response = await x402Fetch('https://api.example.com/inference', {
  method: 'POST',
  body: JSON.stringify({ prompt: '...' })
}, {
  amount: 5.0,
  recipient: 'flop1qyq...'
});
```

#### `parsePaymentHeaders(headers)`

Parse x402 payment headers from response.

```typescript
import { parsePaymentHeaders } from '@flop-labs/sdk';

const payment = parsePaymentHeaders(response.headers);
```

### Named-miner sessions

`runDirectSession({ api, signer, miner, model, endpoint, prompt, maxFlop, maxTokens })`
opens a channel on the named miner, verifies its identity and signed response, and
settles or recovers escrow. `maxFlop` is raw chain units; `maxTokens` is a positive
safe integer and defaults to 256 completion tokens. The request carries that limit
in the chat envelope bound by the verified receipt. Inspect `receipts[0].finishReason` and
`completionTokens` for truncation. The 60-second turn deadline remains in force;
larger token budgets do not extend it. Settlement separately waits for the channel's
finalized calibration allowance before submitting payment. Cooperative delivery and
finalized-event discovery share a 60-second deadline; expired channels use timeout recovery.

### Session Estimation (compute channel)

Size a compute-channel session before opening it, entirely off chain, using the chain's own meter:

- `computeChannel.estimateSession` turns a turn profile into `G_n`, minimum blocks, channel count and escrow.
- `computeChannel.sessionPrior` returns P50/P90/P99 profiles for a task you have not run yet.
- `computeChannel.calibrateSessionPrior` fits that prior to your model and agent configuration from about 10 probe runs.
- `computeChannel.reforecastSession` updates the quantiles mid-run.

See the [session estimation guide](https://github.com/flop-labs/flop-core/blob/main/docs/sdk/session-estimation.md).

### React Hooks (Optional)

```typescript
import { useFlopClient, useWalletBalance, useHtlcStatus } from '@flop-labs/sdk/react';

function MyComponent() {
  const client = useFlopClient('http://127.0.0.1:16111/rpc');
  const { balance } = useWalletBalance(client, 'flop1qyq...');
  const { status } = useHtlcStatus(client, '0x...');
  
  return <div>Balance: {balance} FLOP</div>;
}
```

## Types

```typescript
interface ComputeTask {
  model: string;
  prompt: string;
  maxTokens?: number;
  temperature?: number;
}

interface HtlcInfo {
  htlcId: string;
  hashLock: string;
  rewardAmount: number;
  timeoutBlock: number;
  status: 'CREATED' | 'SETTLED' | 'REFUNDED';
}

interface PoUISubmission {
  proofHash: string;
  gnMeasured: number;
  teeQuote: string;
  timestamp: number;
}

interface WalletInfo {
  address: string;
  balance: number;
  dailyLimit: number;
  dailySpent: number;
  allowedPallets: string[];
}
```

## Error Handling

```typescript
import { FlopClient } from '@flop-labs/sdk';

const client = new FlopClient();

try {
  await client.createHtlc({ ... });
} catch (error) {
  if (error.code === 'INSUFFICIENT_BALANCE') {
    console.error('Not enough FLOP tokens');
  } else if (error.code === 'HTLC_NOT_FOUND') {
    console.error('Invalid hash lock');
  } else {
    console.error('RPC error:', error.message);
  }
}
```

## Complete Example

```typescript
import { FlopClient, createAgentWallet, generateHtlcSecrets } from '@flop-labs/sdk';

async function main() {
  // Connect to FLOP node
  const client = new FlopClient({
    rpcUrl: 'http://127.0.0.1:16111/rpc'
  });

  // Check connection
  const health = await client.health();
  if (!health.isSyncing) {
    console.log('✓ Node is healthy');
  }

  // Create agent wallet
  const wallet = await createAgentWallet(client, {
    agentId: 'trading-agent-01',
    dailyLimit: 100,
    allowedPallets: ['htlc', 'poui']
  });
  console.log('✓ Agent wallet created:', wallet.address);

  // Fund wallet
  await fundAgentWallet(client, wallet.address, 50.0);
  console.log('✓ Wallet funded with 50 FLOP');

  // Generate HTLC secrets
  const { preImage, hashLock } = generateHtlcSecrets();

  // Create HTLC for inference
  const htlc = await client.createHtlc({
    agent: 'trading-agent-01',
    task: {
      model: 'llama-3-8b',
      prompt: 'Analyze BTC price trend for last 24h',
      tee_requirements: process.env.FLOP_HTLC_TEE_REQUIREMENTS
    },
    rewardAmount: 5.0,
    timeoutBlocks: 60,
    hashLock
  });
  console.log('✓ HTLC created:', htlc.htlcId);

  // Wait for miner to settle
  console.log('Waiting for settlement...');
  const settlement = await client.waitForSettlement(hashLock, 30);
  
  if (settlement) {
    console.log('✓ Settled by miner:', settlement.miner);
    console.log('✓ Compute used:', settlement.gnUsed, 'G_n');
  } else {
    console.log('⚠ Timeout - funds refunded');
  }
}

main().catch(console.error);
```

## Development

```bash
# Install dependencies
npm install

# Build the SDK
npm run build

# Watch mode
npm run dev

# Clean build artifacts
npm clean
```

## License

Apache-2.0 © FLOP Network

## NVIDIA GPU Operators

For miners operating NVIDIA GPUs to earn rewards, see the complete guide:

- **[Run a FLOP miner on a GPU host](https://ask.flop.finance/docs/run-miner)** - Mining setup and workflows
- [Put your GPU to work on FLOP](https://ask.flop.finance/docs/run-gpu-provider) - Plain-language start for GPU owners new to crypto

Quick example for GPU operators:

```typescript
import { FlopClient, type TeeQuote } from '@flop-labs/sdk';

// Connect as miner
const client = await FlopClient.create({ 
  endpoint: 'ws://127.0.0.1:9944',
  signer: '//Miner'
});

// Monitor for HTLCs
const htlc = await client.checkHtlcStatus(hashLock);
if (htlc && htlc.status === 'CREATED') {
  // Execute inference on NVIDIA GPU
  const result = await executeOnGpu(htlc.task); // Your GPU execution logic
  
  // Generate TEE quote
  const teeQuote: TeeQuote = {
    version: '1.0',
    miner_address: client.address,
    task_reference: {
      htlc_hash_lock: htlc.hashLock,
      model_hash: `sha256:${htlc.task.model}`,
      task_timestamp: Math.floor(Date.now() / 1000),
    },
    compute_output: {
      gn_weight: result.gnWeight,  // G_n weight (BFLOPs)
      execution_time_ms: result.executionTime,
      encrypted_result: result.encryptedOutput,
    },
    attestation: {
      tee_type: 'NVIDIA_HOPPER_CC',  // or 'NVIDIA_RUBIN_CC', 'CPU_WRAPPED_TEE'
      hardware_pubkey: hardwarePubkey,
      quote_hex: teeQuoteHex,
      signature: minerSignature,
    },
  };
  
  // Redeem HTLC with TEE quote
  const txHash = await client.redeemHtlc(
    htlc.htlcId,
    preImage,
    teeQuote,
  );
  console.log('✓ HTLC redeemed:', txHash);
  
  // Submit PoUI proof batch (optional, for additional rewards)
  const proofs = generateStarkProofs(result);
  const taskHash = generateTaskHash(htlc);
  const proofTxHash = await client.submitPoUI(proofs, result.gnWeight, taskHash);
  console.log('✓ PoUI proof submitted:', proofTxHash);
}
```

### TEE Quote Format

```typescript
interface TeeQuote {
  version: string;           // "1.0"
  miner_address: string;     // flop1... address
  task_reference: {
    htlc_hash_lock: string;  // HTLC identifier
    model_hash: string;      // sha256:model...
    task_timestamp: number;  // Unix timestamp (seconds)
  };
  compute_output: {
    gn_weight: number;       // G_n weight (BFLOPs)
    execution_time_ms: number;
    encrypted_result: string; // 0x... encrypted output
  };
  attestation: {
    tee_type: string;        // "NVIDIA_HOPPER_CC" | "NVIDIA_RUBIN_CC" | "CPU_WRAPPED_TEE"
    hardware_pubkey: string; // 0x... hardware public key
    quote_hex: string;       // 0x... raw TEE quote
    signature: string;       // 0x... miner signature
  };
}
```

### Supported TEE Types

| TEE Type | Hardware | Production Ready |
|----------|----------|------------------|
| `NVIDIA_HOPPER_CC` | H100, H200 | ✅ Yes |
| `NVIDIA_RUBIN_CC` | B100, B200 | ✅ Yes |
| `CPU_WRAPPED_TEE` | RTX 4090+ + AMD SEV/Intel TDX | ⚠️ Testnet only |

### TEE Verification

The TEE bridge validates quotes with:

- **Timestamp freshness:** Quotes must be < 60 seconds old
- **Signature verification:** Validates miner signature
- **Replay protection:** Tracks task hashes to prevent double-spending
- **Hardware verification:** Checks hardware keys against registry (production only)

```typescript
import { verifyTeeQuote, type PouiPayload } from '@flop-labs/sdk/tee';

const bridge = new TeeBridge({ simulatorMode: false });

// Register known hardware keys (production)
bridge.registerHardwareKey('0x...');

// Verify TEE quote
const payload: PouiPayload = parseTeeQuote(quoteJson);
const result = await bridge.verify(payload);

if (result.valid) {
  console.log(`✓ TEE verified: ${result.gnWeight} G_n`);
} else {
  console.error(`✗ Verification failed: ${result.error}`);
}
```

For complete setup instructions, hardware requirements, and production deployment guide:

- **[Run a FLOP miner on a GPU host](https://ask.flop.finance/docs/run-miner)** - Production setup and workflows
- **[Put your GPU to work on FLOP](https://ask.flop.finance/docs/run-gpu-provider)** - Plain-language start for GPU owners: hardware, account, deposit, access

## Links

- [FLOP documentation](https://ask.flop.finance/docs/what-is-flop)
- [Operator configuration and RPC reference](https://ask.flop.finance/docs/operator-config-reference)
- [Agent accounts and spend control](https://ask.flop.finance/docs/agent-accounts-and-spend-control)
