介绍
# Zyfai — Yield for Any Wallet
将任何以太坊钱包转变为收益生成账户。
## 功能说明
当用户想要在其加密货币上**赚取收益**时,Zyfai 会创建一个与其现有钱包 (EOA) 关联的**子账户**(Safe 智能钱包)。存入该子账户的资金会在 DeFi 协议中自动进行优化。用户保持完全控制,并可随时提取。
``` ┌─────────────────┐ ┌──────────────────────┐ │ User's EOA │ ───► │ Zyfai Subaccount │ │ (their wallet) │ │ (Safe smart wallet) │ │ │ │ │ │ Owns & controls│ │ • Auto-rebalancing │ │ │ │ • Yield optimization│ │ │ │ • Non-custodial │ └─────────────────┘ └──────────────────────┘ ```
**关键点:** - 子账户由**用户的 EOA 所有** —— 只有他们可以提取 - 会话密钥允许**自动再平衡**,但无法提取到其他地址 - 同一个 EOA = 在所有链上对应相同的子账户地址
## 流程
``` 1. DEPLOY → Create subaccount linked to user's wallet 2. SESSION → Enable automated yield optimization 3. DEPOSIT → Send funds to subaccount (starts earning) 4. WITHDRAW → Pull funds back to wallet (anytime) ```
## 前置条件
- **API 密钥** — 以编程方式获取(见下文)或在 [sdk.zyf.ai](https://sdk.zyf.ai) 手动获取 - **钱包连接** — 钱包提供商(浏览器)或安全密钥管理(服务器) - **Node.js 18+**
```bash npm install @zyfai/sdk viem ```
### 以编程方式创建 API 密钥(Agent 原生)
代理可以在没有人工干预的情况下创建自己的 API 密钥。您需要代理的钱包地址(公钥)。
```bash POST https://sdk.zyf.ai/api/sdk-api-keys/create Content-Type: application/json
{ "clientName": "my-agent", "walletAddress": "0x...", "email": "[email protected]" } ```
**响应:** ```json { "success": true, "message": "SDK API key created successfully. Store the apiKey securely - it cannot be retrieved later!", "data": { "id": "936...", "apiKey": "zyfai_361ad41d083c2fe.....", "keyPrefix": "zyfai_361ad4", "clientName": "my-agent", "ownerWalletAddress": "0x..." } } ```
> **重要提示:** 请安全存储 `apiKey` —— 之后无法再次检索。该密钥与提供的钱包地址绑定。
## 支持的链
| 链 | ID | |----------|-------| | Arbitrum | 42161 | | Base | 8453 | | Plasma | 9745 |
## 重要提示:始终使用 EOA 地址
调用 SDK 方法时,**始终传入 EOA 地址**(用户的钱包地址)作为 `userAddress` —— 切勿使用子账户/Safe 地址。SDK 会自动从 EOA 推导出子账户地址。
## 钱包连接选项
SDK 支持多种连接钱包的方式。请根据您的安全要求和部署环境进行选择。
### 选项 1:钱包提供商(推荐用于浏览器/dApps)
使用注入的钱包提供商,如 MetaMask。私钥永远不会离开用户的钱包。
```typescript import { ZyfaiSDK } from "@zyfai/sdk";
const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });
// Connect using injected wallet provider (MetaMask, WalletConnect, etc.) await sdk.connectAccount(window.ethereum, 8453); ```
**安全性:** 私钥保留在用户的钱包中。SDK 仅在需要时请求签名。
### 选项 2:Viem WalletClient(推荐用于服务器代理)
使用预配置的 viem WalletClient。这是服务器端代理的推荐方法,因为它允许与安全密钥管理解决方案集成。
```typescript import { ZyfaiSDK } from "@zyfai/sdk"; import { createWalletClient, http } from "viem"; import { base } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts";
// Create wallet client with your preferred key management // Option A: From environment variable (simple but requires secure env management) const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
// Option B: From KMS (AWS, GCP, etc.) - recommended for production // const account = await getAccountFromKMS();
// Option C: From Wallet-as-a-Service (Turnkey, Privy, etc.) // const account = await turnkeyClient.getAccount();
const walletClient = createWalletClient({ account, chain: base, transport: http(), });
const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });
// Connect using the WalletClient await sdk.connectAccount(walletClient, 8453); ```
**安全性:** WalletClient 抽象允许您与以下安全密钥管理解决方案集成: - **AWS KMS** / **GCP Cloud KMS** — 硬件支持的密钥存储 - **Turnkey** / **Privy** / **Dynamic** — 钱包即服务提供商 - **硬件钱包** — 通过 WalletConnect 或类似方式
### 选项 3:私钥字符串(仅限开发)
直接使用私钥。
```typescript import { ZyfaiSDK } from "@zyfai/sdk";
const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });
// WARNING: Only use for development. Never hardcode private keys in production. await sdk.connectAccount(process.env.PRIVATE_KEY, 8453); ```
**安全警告:** 环境变量中的原始私钥存在安全风险。对于生产环境的自主代理,请使用选项 2 并配合适当的密钥管理解决方案。
### 安全性对比
| 方法 | 安全级别 | 使用场景 | |--------|---------------|----------| | 钱包提供商 | 高 | 浏览器 dApps,面向用户的应用 | | WalletClient + KMS | 高 | 生产环境服务器代理 | | WalletClient + WaaS | 高 | 生产环境服务器代理 | | 私钥字符串 | 低 | 仅限开发/测试 |
## 分步指南
### 1. 连接到 Zyfai
```typescript import { ZyfaiSDK } from "@zyfai/sdk"; import { createWalletClient, http } from "viem"; import { base } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts";
const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });
// For browser: use wallet provider await sdk.connectAccount(window.ethereum, 8453);
// For server: use WalletClient (see Wallet Connection Options above) const walletClient = createWalletClient({ account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`), chain: base, transport: http(), }); await sdk.connectAccount(walletClient, 8453); ```
### 2. 部署子账户
```typescript const userAddress = "0x..."; // User's EOA (NOT the subaccount address!) const chainId = 8453; // Base
// Check if subaccount exists const wallet = await sdk.getSmartWalletAddress(userAddress, chainId); console.log(`Subaccount: ${wallet.address}`); console.log(`Deployed: ${wallet.isDeployed}`);
// Deploy if needed if (!wallet.isDeployed) { const result = await sdk.deploySafe(userAddress, chainId, "conservative"); console.log("Subaccount deployed:", result.safeAddress); } ```
**策略:** - `"conservative"` — 稳健收益,低风险 - `"aggressive"` — 更高收益,高风险
### 3. 启用收益优化
```typescript await sdk.createSessionKey(userAddress, chainId);
// Always verify the session key was activated const user = await sdk.getUserDetails(); if (!user.user.hasActiveSessionKey) { // Session key not active — retry the process console.log("Session key not active, retrying..."); await sdk.createSessionKey(userAddress, chainId); // Verify again const userRetry = await sdk.getUserDetails(); if (!userRetry.user.hasActiveSessionKey) { throw new Error("Session key activation failed after retry. Contact support."); } } console.log("Session key active:", user.user.hasActiveSessionKey); ```
这允许 Zyfai 自动重新平衡资金。会话密钥**无法**提取到任意地址 —— 只能在协议内进行优化。
> **重要提示:** 在调用 `createSessionKey` 后,始终通过检查 `getUserDetails().user.hasActiveSessionKey` 来验证会话密钥是否处于激活状态。如果返回 `false`,请重试该过程。必须激活会话密钥才能使自动收益优化生效。
### 4. 存入资金
```typescript // Deposit 10 USDC (6 decimals) await sdk.depositFunds(userAddress, chainId, "10000000"); ```
资金从 EOA 转移到子账户,并立即开始赚取收益。
### 5. 提取资金
```typescript // Withdraw everything await sdk.withdrawFunds(userAddress, chainId);
// Or withdraw partial (5 USDC) await sdk.withdrawFunds(userAddress, chainId, "5000000"); ```
资金返回到用户的 EOA。提现是异步处理的。
### 6. 断开连接
```typescript await sdk.disconnectAccount(); ```
## 完整示例
```typescript import { ZyfaiSDK } from "@zyfai/sdk"; import { createWalletClient, http } from "viem"; import { base } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts";
async function startEarningYield(userAddress: string) { const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! }); const chainId = 8453; // Base // Connect using WalletClient (recommended for server agents) const walletClient = createWalletClient({ account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`), chain: base, transport: http(), }); await sdk.connectAccount(walletClient, chainId); // Deploy subaccount if needed (always pass EOA as userAddress) const wallet = await sdk.getSmartWalletAddress(userAddress, chainId); if (!wallet.isDeployed) { await sdk.deploySafe(userAddress, chainId, "conservative"); console.log("Subaccount created:", wallet.address); } // Enable automated optimization await sdk.createSessionKey(userAddress, chainId); // Verify session key is active const user = await sdk.getUserDetails(); if (!user.user.hasActiveSessionKey) { console.log("Session key not active, retrying..."); await sdk.createSessionKey(userAddress, chainId); const userRetry = await sdk.getUserDetails(); if (!userRetry.user.hasActiveSessionKey) { throw new Error("Session key activation failed. Contact support."); } } // Deposit 100 USDC await sdk.depositFunds(userAddress, chainId, "100000000"); console.log("Deposited! Now earning yield."); await sdk.disconnectAccount(); }
async function withdrawYield(userAddress: string, amount?: string) { const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! }); const chainId = 8453; // Base // Connect using WalletClient const walletClient = createWalletClient({ account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`), chain: base, transport: http(), }); await sdk.connectAccount(walletClient, chainId); // Withdraw funds (pass EOA as userAddress) if (amount) { // Partial withdrawal await sdk.withdrawFunds(userAddress, chainId, amount); console.log(`Withdrawn ${amount} (6 decimals) to EOA`); } else { // Full withdrawal await sdk.withdrawFunds(userAddress, chainId); console.log("Withdrawn all funds to EOA"); } await sdk.disconnectAccount(); } ```
## API 参考
| 方法 | 参数 | 描述 | |--------|--------|-------------| | `connectAccount` | `(walletClientOrProvider, chainId)` | 使用 Zyfai 进行身份验证 | | `getSmartWalletAddress` | `(userAddress, chainId)` | 获取子账户地址及状态 | | `deploySafe` | `(userAddress, chainId, strategy)` | 创建子账户 | | `createSessionKey` | `(userAddress, chainId)` | 启用自动优化 | | `depositFunds` | `(userAddress, chainId, amount)` | 存入 USDC (6 位小数) | | `withdrawFunds` | `(userAddress, chainId, amount?)` | 提取(如果未提供金额则提取全部) | | `getPositions` | `(userAddress, chainId?)` | 获取活跃的 DeFi 头寸 | | `getAvailableProtocols` | `(chainId)` | 获取可用的协议及资金池 | | `getAPYPerStrategy` | `(crossChain?, days?, strategyType?)` | 获取保守/激进策略的 APY | | `getUserDetails` | `()` | 获取已验证用户的详细信息 | | `getOnchainEarnings` | `(walletAddress)` | 获取收益数据 | | `updateUserProfile` | `(params)` | 更新策略、协议、分配、跨链设置 | | `registerAgentOnIdentityRegistry` | `(smartWallet, chainId)` | 在 ERC-8004 身份注册表上注册代理 | | `disconnectAccount` | `()` | 结束会话 |
**注意:** 所有接受 `userAddress` 的方法均期望传入 **EOA 地址**,而非子账户/Safe 地址。
## 数据方法
### getPositions
获取用户在所有协议中的所有活跃 DeFi 头寸。可选择按链进行筛选。
**参数:**
| 参数 | 类型 | 必填 | 描述 | |-----------|------|----------|-------------| | userAddress | string | 是 | 用户的 EOA 地址 | | chainId | SupportedChainId | 否 | 可选:按特定链 ID 筛选 |
**示例:**
```typescript // Get all positions across all chains const positions = await sdk.getPositions("0xUser...");
// Get positions on Arbitrum only const arbPositions = await sdk.getPositions("0xUser...", 42161); ```
**返回:**
```typescript interface PositionsResponse { success: boolean; userAddress: string; positions: Position[]; } ```
### getAvailableProtocols
获取特定链上可用的 DeFi 协议和资金池及其 APY 数据。
```typescript const protocols = await sdk.getAvailableProtocols(42161); // Arbitrum
protocols.protocols.forEach((protocol) => { console.log(`${protocol.name} (ID: ${protocol.id})`); if (protocol.pools) { protocol.pools.forEach((pool) => { console.log(` Pool: ${pool.name} - APY: ${pool.apy || "N/A"}%`); }); } }); ```
返回: ```typescript interface ProtocolsResponse { success: boolean; chainId: SupportedChainId; protocols: Protocol[]; } ```
### getUserDetails
获取当前已验证用户的详细信息,包括智能钱包、链、协议和设置。需要 SIWE 身份验证。
```typescript await sdk.connectAccount(walletClient, chainId); const user = await sdk.getUserDetails();
console.log("Smart Wallet:", user.user.smartWallet); console.log("Chains:", user.user.chains); console.log("Has Active Session:", user.user.hasActiveSessionKey); ```
返回: ```typescript interface UserDetailsResponse { success: boolean; user: { id: string; address: string; smartWallet?: string; chains: number[]; protocols: Protocol[]; hasActiveSessionKey: boolean; email?: string; strategy?: string; telegramId?: string; walletType?: string; autoSelectProtocols: boolean; autocompounding?: boolean; omniAccount?: boolean; crosschainStrategy?: boolean; agentName?: string; customization?: Record<string, string[]>; }; } ```
### updateUserProfile
更新已验证用户的个人资料设置,包括策略、协议、分配和跨链选项。需要 SIWE 身份验证。
```typescript sdk.updateUserProfile(params: UpdateUserProfileRequest): Promise<UpdateUserProfileResponse> ```
**参数:**
```typescript interface UpdateUserProfileRequest { /** Investment strategy: "conservative" for safer yields, "aggressive" for higher risk/reward */ strategy?: "conservative" | "aggressive";
/** Array of protocol IDs to use for yield optimization */ protocols?: string[];
/** Enable omni-account feature for cross-chain operations */ omniAccount?: boolean;
/** Enable automatic compounding of earned yields (default: true) */ autocompounding?: boolean;
/** Custom name for your agent */ agentName?: string;
/** Enable cross-chain strategy execution */ crosschainStrategy?: boolean;
/** Enable position splitting across multiple protocols */ splitting?: boolean;
/** Minimum number of splits when position splitting is enabled (1-4) */ minSplits?: number; } ```
**返回:**
```typescript interface UpdateUserProfileResponse { success: boolean; userId: string; smartWallet?: string; chains?: number[]; strategy?: string; protocols?: string[]; omniAccount?: boolean; autocompounding?: boolean; agentName?: string; crosschainStrategy?: boolean; executorProxy?: boolean; splitting?: boolean; minSplits?: number; } ```
**示例:**
```typescript // Update strategy from conservative to aggressive await sdk.updateUserProfile({ strategy: "aggressive", });
// Configure specific protocols const protocolsResponse = await sdk.getAvailableProtocols(8453); const selectedProtocols = protocolsResponse.protocols .filter(p => ["Aave", "Compound", "Moonwell"].includes(p.name)) .map(p => p.id);
await sdk.updateUserProfile({ protocols: selectedProtocols, });
// Enable position splitting (distribute across multiple protocols) await sdk.updateUserProfile({ splitting: true, minSplits: 3, // Split across at least 3 protocols });
// Verify changes const userDetails = await sdk.getUserDetails(); console.log("Strategy:", userDetails.user.strategy); console.log("Splitting:", userDetails.user.splitting); ```
> **跨链策略:** 仅当用户**明确请求**时才启用跨链。为了使跨链正常工作,`crosschainStrategy` 和 `omniAccount` **都必须**设置为 `true`。切勿默认启用跨链设置。
```typescript // Enable cross-chain ONLY when explicitly requested by the user await sdk.updateUserProfile({ crosschainStrategy: true, omniAccount: true, });
// Now funds can be rebalanced across configured chains const user = await sdk.getUserDetails(); console.log("Operating on chains:", user.user.chains); ```
**说明:** - **策略:** 可随时更改。随后的再平衡将使用新的活跃策略。 - **协议:** 在更新之前,使用 `getAvailableProtocols(chainId)` 获取有效的协议 ID。 - **智能分配 (minSplits = 1):** 默认模式。为了最大化回报,资金会自动分配到多个 DeFi 资金池 —— 但仅在有利可图时。系统会根据当前市场状况和机会智能地决定何时分配是有利的。如果不存在机会,资金可能不会分配。 - **强制分配 (minSplits > 1):** 当 `minSplits` 设置为 2、3 或 4 时,资金将始终分配到至少相应数量的资金池,以改善风险分散(最多 4 个 DeFi 资金池)。无论市场状况如何,这都能保证您的资金会被分配。 - **跨链:** 需要**同时**设置 `crosschainStrategy: true` 和 `omniAccount: true`。仅当用户明确要求进行跨链收益优化时才激活。链在初始设置期间配置,无法通过此方法更改。 - **自动复利:** 默认启用。当为 `true` 时,收益会自动再投资。 - 智能钱包地址、链和 `executorProxy` 无法通过此方法更新。
### getAPYPerStrategy
按策略类型(保守或激进)、时间范围和链配置获取全局 APY。在部署前使用此方法比较策略之间的预期回报。
**参数:**
| 参数 | 类型 | 必填 | 描述 | |-----------|------|----------|-------------| | crossChain | boolean | 否 | 如果为 `true`,返回跨链策略的 APY;如果为 `false`,则返回单链 | | days | number | 否 | 计算 APY 的周期。`7`、`15`、`30`、`60` 之一 | | strategyType | string | 否 | 策略风险概况。`'conservative'` 或 `'aggressive'` 之一 |
**示例:**
```typescript // Get 7-day APY for conservative single-chain strategy const conservativeApy = await sdk.getAPYPerStrategy(false, 7, 'conservative'); console.log("Conservative APY:", conservativeApy.data);
// Get 30-day APY for aggressive cross-chain strategy const aggressiveApy = await sdk.getAPYPerStrategy(true, 30, 'aggressive'); console.log("Aggressive APY:", aggressiveApy.data);
// Compare strategies const conservative = await sdk.getAPYPerStrategy(false, 30, 'conservative'); const aggressive = await sdk.getAPYPerStrategy(false, 30, 'aggressive'); console.log(`Conservative 30d APY: ${conservative.data[0]?.apy}%`); console.log(`Aggressive 30d APY: ${aggressive.data[0]?.apy}%`); ```
**返回:**
```typescript interface APYPerStrategyResponse { success: boolean; count: number; data: APYPerStrategy[]; }
interface APYPerStrategy { strategyType: string; apy: number; period: number; crossChain: boolean; } ```
### getOnchainEarnings
获取钱包的链上收益,包括总收益、当前收益和终身收益。
```typescript const earnings = await sdk.getOnchainEarnings(smartWalletAddress);
console.log("Total earnings:", earnings.data.totalEarnings); console.log("Current earnings:", earnings.data.currentEarnings); console.log("Lifetime earnings:", earnings.data.lifetimeEarnings); ```
返回: ```typescript interface OnchainEarningsResponse { success: boolean; data: { walletAddress: string; totalEarnings: number; currentEarnings: number; lifetimeEarnings: number; unrealizedEarnings?: number; currentEarningsByChain?: Record<string, number>; unrealizedEarningsByChain?: Record<string, number>; lastCheckTimestamp?: string; }; } ```
### registerAgentOnIdentityRegistry (ERC-8004)
按照 ERC-8004 标准在身份注册表上注册您通过 Zyfai 部署的代理。这用于 OpenClaw 代理注册。该方法获取一个包含代理元数据(存储在 IPFS 上)的 tokenUri,然后将其在链上注册。
**支持的链:**
| 链 | 链 ID | |-------|----------| | Base | 8453 | | Arbitrum | 42161 |
**参数:**
| 参数 | 类型 | 必填 | 描述 | |-----------|------|----------|-------------| | smartWallet | string | 是 | 要注册为代理的 Zyfai 部署智能钱包地址 | | chainId | SupportedChainId | 是 | 链 ID(仅限 8453 或 42161) |
**示例:**
```typescript const sdk = new ZyfaiSDK({ apiKey: "your-api-key" }); await sdk.connectAccount(walletClient, 8453);
// Get smart wallet address const walletInfo = await sdk.getSmartWalletAddress(userAddress, 8453); const smartWallet = walletInfo.address;
// Register agent on Identity Registry const result = await sdk.registerAgentOnIdentityRegistry(smartWallet, 8453);
console.log("Registration successful:"); console.log(" Tx Hash:", result.txHash); console.log(" Chain ID:", result.chainId); console.log(" Smart Wallet:", result.smartWallet); ```
**返回:**
```typescript interface RegisterAgentResponse { success: boolean; txHash: string; chainId: number; smartWallet: string; } ```
**工作原理:**
1. 从 Zyfai API 获取 `tokenUri`(存储在 IPFS 上的代理元数据) 2. 为身份注册表合约编码 `register(tokenUri)` 调用 3. 从已连接的钱包发送交易 4. 等待链上确认
## 安全性
- **非托管** —— 用户的 EOA 拥有子账户 - **会话密钥受限** —— 可以重新平衡,但不能提取到其他地方 - **确定性** —— 同一个 EOA = 在每条链上都是相同的子账户 - **灵活的密钥管理** —— 使用钱包提供商、WalletClients 或 KMS 集成
### 密钥管理最佳实践
对于**生产环境的自主智能体**,我们建议:
1. **使用 WalletClient**,并配合安全的密钥源(而非原始私钥) 2. **集成 KMS**(AWS KMS、GCP Cloud KMS)以实现硬件支持的密钥存储 3. **考虑钱包即服务** 提供商,如 Turnkey、Privy 或 Dynamic 4. **切勿硬编码** 私钥到源代码中 5. **定期轮换密钥** 并实施密钥撤销流程
## 故障排查
### 子账户地址在各链上不匹配
对于同一个 EOA,子账户地址在所有链上应该是**完全一致**的。如果你看到不同的地址:
```typescript // Check addresses on both chains const baseWallet = await sdk.getSmartWalletAddress(userAddress, 8453); const arbWallet = await sdk.getSmartWalletAddress(userAddress, 42161);
if (baseWallet.address !== arbWallet.address) { console.error("Address mismatch! Contact support."); } ```
**如果地址不匹配:** 1. 尝试在受影响的链上重新部署 2. 如果问题持续存在,请在 Telegram 上联系支持:[@paul_zyfai](https://t.me/paul_zyfai)
### "Deposit address not found" 错误
这意味着钱包尚未在后端注册。解决方案: 1. 首先调用 `deploySafe()` —— 即使 Safe 已经在链上部署,这也会将其注册到后端 2. 然后重试 `createSessionKey()`
### "Invalid signature" 错误
这通常意味着: - 钱包/签名者与你传入的 EOA 不匹配 - 链上的 Safe 地址与 SDK 期望的不符
请确认你为该 EOA 使用了正确的钱包。
## 资源
- **获取 API Key:** [sdk.zyf.ai](https://sdk.zyf.ai) 或通过 `POST /api/sdk-api-keys/create` 以编程方式获取 - **文档:** [docs.zyf.ai](https://docs.zyf.ai) - **演示:** [github.com/ondefy/zyfai-sdk-demo](https://github.com/ondefy/zyfai-sdk-demo) - **MCP 服务器:** [mcp.zyf.ai](https://mcp.zyf.ai/mcp) —— 配合 Claude 或其他 MCP 兼容的智能体使用 - **智能体注册:** [zyf.ai/.well-known/agent-registration.json](https://www.zyf.ai/.well-known/agent-registration.json)