jpskill.com
🛠️ 開発・MCP コミュニティ

Base、ArbitrumなどのEthereumウォレットで、ユーザーの資金を預かり、安全なサブアカウントを作成して自動でDeFi利回りを最適化、いつでも入出金できる非管理型の利回り獲得を支援するSkill。

zyfai

Base、Arbitrum、Plasma上のあらゆるイーサリアムウォレットで利回りを得たいユーザーのために、非管理型のサブアカウントを展開し、自動化された利回り最適化を可能にするSkill。

📜 元の英語説明(参考)

Earn yield on any Ethereum wallet on Base, Arbitrum, and Plasma. Use when a user wants passive DeFi yield on their funds. Deploys a non-custodial deterministic subaccount (Safe) linked to their EOA, enables automated yield optimization, and lets them deposit/withdraw anytime.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Base、Arbitrum、Plasma上のあらゆるイーサリアムウォレットで利回りを得たいユーザーのために、非管理型のサブアカウントを展開し、自動化された利回り最適化を可能にするSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o zyfai.zip https://jpskill.com/download/5618.zip && unzip -o zyfai.zip && rm zyfai.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/5618.zip -OutFile "$d\zyfai.zip"; Expand-Archive "$d\zyfai.zip" -DestinationPath $d -Force; ri "$d\zyfai.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して zyfai.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → zyfai フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-17
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Zyfai — あらゆるウォレットにイールドを

あらゆるイーサリアムウォレットがイールド生成アカウントにアクセスできるようにします。

機能概要

ユーザーが自身の暗号資産でイールドを獲得したい場合、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    →  ユーザーのウォレットにリンクされた決定論的サブアカウントを作成します
2. SESSION   →  自動イールド最適化を有効にします
3. DEPOSIT   →  サブアカウントに資金を送金します(イールド獲得を開始します)
4. WITHDRAW  →  ウォレットに資金を引き戻します(いつでも可能です)

前提条件

  • APIキー — プログラムで(下記参照)またはsdk.zyf.aiで手動で取得してください
  • ウォレット接続 — ウォレットプロバイダー(ブラウザ)またはセキュアなキー管理(サーバー)のいずれか
  • Node.js 18+
npm install @zyfai/sdk viem

プログラムによるAPIキー作成(エージェントネイティブ)

エージェントは、人間の介入なしに独自のAPIキーを作成できます。エージェントのウォレットアドレス(公開鍵)が必要です。

POST https://sdk.zyf.ai/api/sdk-api-keys/create
Content-Type: application/json

{
  "clientName": "my-agent",
  "walletAddress": "0x...",
  "email": "agent@example.com"
}

レスポンス:

{
  "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メソッドを呼び出す際は、userAddressとして常にEOAアドレス(ユーザーのウォレットアドレス)を渡してください — サブアカウント/Safeアドレスは決して使用しないでください。SDKはEOAからサブアカウントアドレスを自動的に導出します。

ウォレット接続オプション

SDKは複数のウォレット接続方法をサポートしています。セキュリティ要件とデプロイコンテキストに基づいて選択してください。

オプション1: ウォレットプロバイダー(ブラウザ/dAppsに推奨)

MetaMaskのようなインジェクトされたウォレットプロバイダーを使用します。秘密鍵がユーザーのウォレットから離れることはありません。

import { ZyfaiSDK } from "@zyfai/sdk";

const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });

// インジェクトされたウォレットプロバイダー(MetaMask, WalletConnectなど)を使用して接続します
await sdk.connectAccount(window.ethereum, 8453);

セキュリティ: 秘密鍵はユーザーのウォレット内に留まります。SDKは必要な場合にのみ署名を要求します。

オプション2: Viem WalletClient(サーバーエージェントに推奨)

事前に設定されたviem WalletClientを使用します。これは、セキュアなキー管理ソリューションとの統合を可能にするため、サーバーサイドエージェントに推奨されるアプローチです。

import { ZyfaiSDK } from "@zyfai/sdk";
import { createWalletClient, http } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

// 任意のキー管理でウォレットクライアントを作成します
// オプションA: 環境変数から(シンプルですが、セキュアな環境管理が必要です)
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

// オプションB: KMSから(AWS, GCPなど) - 本番環境に推奨
// const account = await getAccountFromKMS();

// オプションC: Wallet-as-a-Serviceから(Turnkey, Privyなど)
// const account = await turnkeyClient.getAccount();

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

const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });

// WalletClientを使用して接続します
await sdk.connectAccount(walletClient, 8453);

セキュリティ: WalletClientの抽象化により、次のようなセキュアなキー管理ソリューションと統合できます。

  • AWS KMS / GCP Cloud KMS — ハードウェアバックアップされたキー保管
  • Turnkey / Privy / Dynamic — Wallet-as-a-Serviceプロバイダー
  • ハードウェアウォレット — WalletConnectなどを介して

オプション3: 秘密鍵文字列(開発のみ)

秘密鍵を直接使用します。

import { ZyfaiSDK } from "@zyfai/sdk";

const sdk = new ZyfaiSDK({ apiKey: "your-api-key", referralSource: "openclaw-skill" });

// 警告: 開発目的でのみ使用してください。本番環境で秘密鍵をハードコードしないでください。
await sdk.connectAccount(process.env.PRIVATE_KEY, 8453);

セキュリティ警告: 環境変数に生の秘密鍵を置くことはセキュリティリスクです。本番環境の自律型エージェントには、適切なキー管理ソリューションを備えたオプション2を使用してください。

セキュリティ比較

方法 セキュリティレベル ユースケース
ウォレットプロバイダー ブラウザdApps、ユーザー向けアプリ
WalletClient + KMS 本番サーバーエージェント
WalletClient + WaaS 本番サーバーエージェント
秘密鍵文字列 開発/テストのみ

ステップバイステップ

1. Zyfaiに接続する

import { ZyfaiSDK } from "@zyfai/sdk";
import { createWalletClient, http } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/acco
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Zyfai — Yield for Any Wallet

Let any Ethereum wallet access a yield-generating account.

What This Does

When a user wants to earn yield on their crypto, Zyfai creates a deterministic subaccount (Safe smart wallet) linked to their existing wallet (EOA). Funds deposited into this subaccount are automatically optimized across DeFi protocols. The user stays in full control and can withdraw anytime.

┌─────────────────┐      ┌──────────────────────┐
│   User's EOA    │ ───► │  Zyfai Subaccount    │
│  (their wallet) │      │  (Safe smart wallet) │
│                 │      │                      │
│  Owns & controls│      │  • Auto-rebalancing  │
│                 │      │  • Yield optimization│
│                 │      │  • Non-custodial     │
└─────────────────┘      └──────────────────────┘

Key points:

  • The subaccount is owned by the user's EOA — only they can withdraw
  • Session keys allow automated rebalancing but cannot withdraw to other addresses
  • Same EOA = same subaccount address across all chains

The Flow

1. DEPLOY    →  Create a deterministic 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)

Prerequisites

  • API Key — Get one programmatically (see below) or manually at sdk.zyf.ai
  • Wallet Connection — Either a wallet provider (browser) or secure key management (server)
  • Node.js 18+
npm install @zyfai/sdk viem

Programmatic API Key Creation (Agent-Native)

Agents can create their own API key without human intervention. You need the wallet address (public key) of the agent.

POST https://sdk.zyf.ai/api/sdk-api-keys/create
Content-Type: application/json

{
  "clientName": "my-agent",
  "walletAddress": "0x...",
  "email": "agent@example.com"
}

Response:

{
  "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..."
  }
}

Important: Store the apiKey securely — it cannot be retrieved later. The key is linked to the provided wallet address.

Supported Chains

Chain ID
Arbitrum 42161
Base 8453
Plasma 9745

Important: Always Use EOA Address

When calling SDK methods, always pass the EOA address (the user's wallet address) as userAddress — never the subaccount/Safe address. The SDK derives the subaccount address automatically from the EOA.

Wallet Connection Options

The SDK supports multiple ways to connect a wallet. Choose based on your security requirements and deployment context.

Option 1: Wallet Provider (Recommended for Browser/dApps)

Use an injected wallet provider like MetaMask. The private key never leaves the user's wallet.

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);

Security: The private key stays in the user's wallet. The SDK only requests signatures when needed.

Option 2: Viem WalletClient (Recommended for Server Agents)

Use a pre-configured viem WalletClient. This is the recommended approach for server-side agents as it allows integration with secure key management solutions.

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);

Security: The WalletClient abstraction allows you to integrate with secure key management solutions like:

  • AWS KMS / GCP Cloud KMS — Hardware-backed key storage
  • Turnkey / Privy / Dynamic — Wallet-as-a-Service providers
  • Hardware wallets — Via WalletConnect or similar

Option 3: Private Key String (Development Only)

Direct private key usage.

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);

Security Warning: Raw private keys in environment variables are a security risk. For production autonomous agents, use Option 2 with a proper key management solution.

Security Comparison

Method Security Level Use Case
Wallet Provider High Browser dApps, user-facing apps
WalletClient + KMS High Production server agents
WalletClient + WaaS High Production server agents
Private Key String Low Development/testing only

Step-by-Step

1. Connect to Zyfai

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. Deploy Subaccount

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);
}

Strategies:

  • "conservative" — Stable yield, lower risk
  • "aggressive" — Higher yield, higher risk

3. Enable Yield Optimization

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);

This allows Zyfai to rebalance funds automatically. Session keys cannot withdraw to arbitrary addresses — only optimize within the protocol.

Important: Always verify the session key is active by checking getUserDetails().user.hasActiveSessionKey after calling createSessionKey. If it returns false, retry the process. A session key must be active for automated yield optimization to work.

4. Deposit Funds

// Deposit 10 USDC (6 decimals)
await sdk.depositFunds(userAddress, chainId, "10000000");

Funds move from EOA -> Subaccount and start earning yield immediately.

5. Withdraw Funds

// Withdraw everything
await sdk.withdrawFunds(userAddress, chainId);

// Or withdraw partial (5 USDC)
await sdk.withdrawFunds(userAddress, chainId, "5000000");

Funds return to the user's EOA. Withdrawals are processed asynchronously.

6. Disconnect

await sdk.disconnectAccount();

Complete Example

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 Reference

Method Params Description
connectAccount (walletClientOrProvider, chainId) Authenticate with Zyfai
getSmartWalletAddress (userAddress, chainId) Get subaccount address & status
deploySafe (userAddress, chainId, strategy) Create subaccount
createSessionKey (userAddress, chainId) Enable auto-optimization
depositFunds (userAddress, chainId, amount) Deposit USDC (6 decimals)
withdrawFunds (userAddress, chainId, amount?) Withdraw (all if no amount)
getPositions (userAddress, chainId?) Get active DeFi positions
getAvailableProtocols (chainId) Get available protocols & pools
getAPYPerStrategy (crossChain?, days?, strategyType?) Get APY for conservative/aggressive strategies
getUserDetails () Get authenticated user details
getOnchainEarnings (walletAddress) Get earnings data
updateUserProfile (params) Update strategy, protocols, splitting, cross-chain settings
registerAgentOnIdentityRegistry (smartWallet, chainId) Register agent on ERC-8004 Identity Registry
disconnectAccount () End session

Note: All methods that take userAddress expect the EOA address, not the subaccount/Safe address.

Data Methods

getPositions

Get all active DeFi positions for a user across protocols. Optionally filter by chain.

Parameters:

Parameter Type Required Description
userAddress string Yes User's EOA address
chainId SupportedChainId No Optional: Filter by specific chain ID

Example:

// Get all positions across all chains
const positions = await sdk.getPositions("0xUser...");

// Get positions on Arbitrum only
const arbPositions = await sdk.getPositions("0xUser...", 42161);

Returns:

interface PositionsResponse {
  success: boolean;
  userAddress: string;
  positions: Position[];
}

getAvailableProtocols

Get available DeFi protocols and pools for a specific chain with APY data.

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"}%`);
    });
  }
});

Returns:

interface ProtocolsResponse {
  success: boolean;
  chainId: SupportedChainId;
  protocols: Protocol[];
}

getUserDetails

Get current authenticated user details including smart wallet, chains, protocols, and settings. Requires SIWE authentication.

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);

Returns:

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

Update the authenticated user's profile settings including strategy, protocols, splitting, and cross-chain options. Requires SIWE authentication.

sdk.updateUserProfile(params: UpdateUserProfileRequest): Promise<UpdateUserProfileResponse>

Parameters:

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;
}

Returns:

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;
}

Examples:

// 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);

Cross-chain strategies: Only enable cross-chain when the user explicitly requests it. For cross-chain to work, both crosschainStrategy and omniAccount must be set to true. Never enable cross-chain settings by default.

// 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);

Notes:

  • Strategy: Can be changed anytime. Subsequent rebalancing uses the new active strategy.
  • Protocols: Use getAvailableProtocols(chainId) to get valid protocol IDs before updating.
  • Smart Splitting (minSplits = 1): Default mode. To maximize returns, funds are automatically distributed across multiple DeFi pools — but only when beneficial. The system intelligently decides when splitting is advantageous based on current market conditions and opportunities. Funds may not split if no opportunity exists.
  • Forced Splitting (minSplits > 1): When minSplits is set to 2, 3, or 4, funds are always distributed across at least that many pools for improved risk diversification (up to 4 DeFi pools). This guarantees your funds will be split regardless of market conditions.
  • Cross-chain: Requires both crosschainStrategy: true AND omniAccount: true. Only activate when the user explicitly asks for cross-chain yield optimization. Chains are configured during initial setup and cannot be changed via this method.
  • Auto-compounding: Enabled by default. When true, yields are reinvested automatically.
  • Smart wallet address, chains, and executorProxy cannot be updated via this method.

getAPYPerStrategy

Get global APY by strategy type (conservative or aggressive), time period, and chain configuration. Use this to compare expected returns between strategies before deploying.

Parameters:

Parameter Type Required Description
crossChain boolean No If true, returns APY for cross-chain strategies; if false, single-chain
days number No Period over which APY is calculated. One of 7, 15, 30, 60
strategyType string No Strategy risk profile. One of 'conservative' or 'aggressive'

Example:

// 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}%`);

Returns:

interface APYPerStrategyResponse {
  success: boolean;
  count: number;
  data: APYPerStrategy[];
}

interface APYPerStrategy {
  strategyType: string;
  apy: number;
  period: number;
  crossChain: boolean;
}

getOnchainEarnings

Get onchain earnings for a wallet including total, current, and lifetime earnings.

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);

Returns:

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)

Register your Zyfai deployed agent on the Identity Registry following the ERC-8004 standard. This is used for OpenClaw agent registration. The method fetches a tokenUri containing the agent's metadata stored on IPFS, then registers it on-chain.

Supported Chains:

Chain Chain ID
Base 8453
Arbitrum 42161

Parameters:

Parameter Type Required Description
smartWallet string Yes The Zyfai deployed smart wallet address to register as an agent
chainId SupportedChainId Yes Chain ID (only 8453 or 42161)

Example:

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);

Returns:

interface RegisterAgentResponse {
  success: boolean;
  txHash: string;
  chainId: number;
  smartWallet: string;
}

How It Works:

  1. Fetches a tokenUri from the Zyfai API (agent metadata stored on IPFS)
  2. Encodes the register(tokenUri) call for the Identity Registry contract
  3. Sends the transaction from the connected wallet
  4. Waits for on-chain confirmation

Security

  • Non-custodial — User's EOA owns the subaccount
  • Session keys are limited — Can rebalance, cannot withdraw elsewhere
  • Deterministic — Same EOA = same subaccount on every chain
  • Flexible key management — Use wallet providers, WalletClients, or KMS integrations

Key Management Best Practices

For production autonomous agents, we recommend:

  1. Use a WalletClient with a secure key source (not raw private keys)
  2. Integrate with KMS (AWS KMS, GCP Cloud KMS) for hardware-backed key storage
  3. Consider Wallet-as-a-Service providers like Turnkey, Privy, or Dynamic
  4. Never hardcode private keys in source code
  5. Rotate keys periodically and implement key revocation procedures

Troubleshooting

Subaccount address mismatch across chains

The subaccount address should be identical across all chains for the same EOA. If you see different addresses:

// 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.");
}

If addresses don't match:

  1. Try redeploying on the affected chain
  2. If the issue persists, contact support on Telegram: @paul_zyfai

"Deposit address not found" error

This means the wallet isn't registered in the backend. Solution:

  1. Call deploySafe() first — even if the Safe is already deployed on-chain, this registers it with the backend
  2. Then retry createSessionKey()

"Invalid signature" error

This typically means:

  • The wallet/signer doesn't match the EOA you're passing
  • The Safe address on-chain doesn't match what the SDK expects

Verify you're using the correct wallet for the EOA.

Resources