# TypeScript SDK

## 安装

```bash
npm install @babydriver/sdk viem
# or
pnpm add @babydriver/sdk viem
```

依赖：`viem >=2.x` (推荐) 或 `ethers >=6.x` (兼容路径)。

## 初始化

```typescript
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import {
    PoBRegistryClient,
    PoDRegistryClient,
    PolicyRegistryClient,
    StakeManagerClient,
    ChallengeManagerClient,
    AxBladeChain, // chain object: id=391, rpcUrls
} from '@babydriver/sdk';

const account = privateKeyToAccount('0x...');

const publicClient = createPublicClient({
    chain: AxBladeChain,
    transport: http('https://rpc-testnet.axblade.io'),
});

const walletClient = createWalletClient({
    account,
    chain: AxBladeChain,
    transport: http(),
});

const pobClient = new PoBRegistryClient(publicClient, walletClient);
const podClient = new PoDRegistryClient(publicClient, walletClient);
const policyClient = new PolicyRegistryClient(publicClient, walletClient);
```

## 端到端：提交 PoB Batch + PoD Receipt

### 1. 准备 BehaviorEvent 列表

```typescript
import { encodeBehaviorEvent, type BehaviorEvent, Outcome } from '@babydriver/sdk';

const events: BehaviorEvent[] = [
    {
        agentId: keccak256(toBytes('did:axblade:agent_001')),
        actionId: keccak256(toBytes('decision.medical.triage')),
        specHash: '0xabc...spec_hash',
        inputHash: keccak256(stringify(userQuery)),
        outputHash: keccak256(stringify(modelOutput)),
        timestamp: BigInt(Math.floor(Date.now() / 1000)),
        outcome: Outcome.Allowed,
    },
    // ... more events
];
```

### 2. 构建 Merkle batch + 签名

```typescript
import { buildMerkleBatch } from '@babydriver/sdk';

const { merkleRoot, leaves, proofs } = buildMerkleBatch(events);

const batch = {
    merkleRoot,
    submitter: account.address,
    timestamp: BigInt(Math.floor(Date.now() / 1000)),
    leafCount: events.length,
    specHash: events[0].specHash,
    agentId: events[0].agentId,
    zkVerified: false,
};

const sig = await pobClient.signBatch(batch, account);
```

### 3. 抵押（首次）+ 上链

```typescript
// First time: deposit stake
const stakeManager = new StakeManagerClient(publicClient, walletClient);
await stakeManager.deposit({ value: parseEther('0.5') });

// Submit batch
const txHash = await pobClient.submitBatch(batch, sig);
console.log(`Batch submitted: ${txHash}`);

const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
const batchId = parseBatchIdFromReceipt(receipt);
```

### 4. 提交 PoD Receipt

```typescript
import { signInferenceAttestation } from '@babydriver/sdk';

const modelHash = '0xdef...model_hash';
const publicInput = keccak256(toBytes(JSON.stringify(modelOutput)));

// Off-chain: attestor signs (private key in HSM in prod)
const inferenceProof = signInferenceAttestation(
    attestorPrivateKey,
    publicInput,
);

const receiptId = await podClient.submitReceipt({
    modelHash,
    inferenceProof,
    publicInput,
    parents: [/* parent receiptIds */],
    metadata: '0x',
});

console.log(`Receipt: ${receiptId}`);
```

## L2 OPA — submitBatchWithPolicy 模式

```typescript
// 1. Verify policy is registered
const isRegistered = await policyClient.isRegistered(EU_AI_ACT_POLICY_HASH);
if (!isRegistered) {
    throw new Error('Policy not registered. Register first.');
}

// 2. Off-chain Rego evaluation (using @babydriver/opa-policy)
import { evaluateRego } from '@babydriver/sdk/opa';
const verdict = await evaluateRego({
    policyHash: EU_AI_ACT_POLICY_HASH,
    input: { event: behaviorEvent, spec: behaviorSpec },
});
// verdict: 'Compliant' | 'Denied' | 'NonCompliant'

// 3. Build batch with policy hash
const batchWithPolicy = { ...batch, policyHash: EU_AI_ACT_POLICY_HASH };

// 4. Submit (PoBRegistry 强制 batch.policyHash == configuredPolicyHash)
await pobClient.submitBatchWithPolicy(batchWithPolicy, sig);
```

详见 [L2 OPA Policy Engine](/protocol-mechanics/policy-engine-opa.md)。

## Challenger 集成

```typescript
import { ChallengeOpener, FraudDetector } from '@babydriver/sdk';

const challenger = new ChallengeOpener(publicClient, walletClient);
const detector = new FraudDetector({ /* config */ });

// 监听新 batch
publicClient.watchEvent({
    address: POB_REGISTRY_ADDRESS,
    event: parseAbiItem('event BatchSubmitted(uint256 batchId, ...)'),
    onLogs: async (logs) => {
        for (const log of logs) {
            const batch = await pobClient.getBatch(log.args.batchId);
            const result = await detector.check(batch);
            if (result.isFraud) {
                await challenger.openChallenge({
                    batchId: log.args.batchId,
                    leafIndex: result.fraudLeafIndex,
                    event: result.fraudLeafEvent,
                    proof: result.merkleProof,
                    bondValue: parseEther('0.1'),
                });
            }
        }
    },
});
```

## 错误处理 & Common Pitfalls

| 错误                                              | 原因                                            | 解决                                                   |
| ----------------------------------------------- | --------------------------------------------- | ---------------------------------------------------- |
| `InsufficientStake`                             | aggregator stake < MIN\_STAKE                 | 先 `stakeManager.deposit({value: parseEther('0.5')})` |
| `InvalidSignature`                              | sig 不是 aggregator key 签                       | 用 `pobClient.signBatch()` 而不是手工签                     |
| `PolicyNotRegistered`                           | submitBatchWithPolicy 时 policyHash 未 register | 先 `policyClient.registerPolicy(...)`                 |
| `BatchHashMismatch` (cast call)                 | scientific notation `[5e17]`                  | SDK 已自动 strip; 手写时用 `awk '{print $1}'`               |
| viem `BaseError: ContractFunctionRevertedError` | revert 解析                                     | catch + decode `error.shortMessage`                  |

## 测试

```typescript
// vitest 4.x 兼容
import { test, expect } from 'vitest';
import { createTestClient, http } from 'viem';

test('submitBatch happy path', async () => {
    const testClient = createTestClient({
        chain: AxBladeChain,
        mode: 'anvil',
        transport: http('http://localhost:8545'),
    });
    
    // ... setup + submit + assert
});
```

SDK 自带 9 test files / 83 test cases，全部 pass with vitest 4.1.5（commit `f57c7da`）。

## 依赖安全

`@babydriver/sdk` 在 `npm audit` 下 0 vulnerabilities (post commit `f57c7da`)。详见 [Dependency Audit](https://github.com/leeleeEcho/babyDriver_Layer2/blob/main/docs/audit/dependency-audit-2026-05-07.md)。

## 相关

* [Rust SDK](/integration-jie-ru-fang-shi/sdk-rust.md) — alloy + tokio aggregator/challenger 内嵌
* [合约 ABI](/integration-jie-ru-fang-shi/contract-abi.md) — 直接 import ABI JSON
* [RPC 端点](/integration-jie-ru-fang-shi/rpc-endpoints.md) — 主 / 备 RPC 配置
* [Examples → Submit Batch](/integration-jie-ru-fang-shi/examples/submit-batch.md) — 完整可跑代码
* [Examples → Open Challenge](/integration-jie-ru-fang-shi/examples/open-challenge.md) — challenger 实操


---

# Agent Instructions: 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:

```
GET https://yellowpaper.axblade.io/integration-jie-ru-fang-shi/sdk-typescript.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
