{
  "schemaVersion": "1.0",
  "item": {
    "slug": "zyfai-sdk",
    "name": "Zyfai Yield Automation",
    "source": "tencent",
    "type": "skill",
    "category": "AI 智能",
    "sourceUrl": "https://clawhub.ai/PaulDeFi/zyfai-sdk",
    "canonicalUrl": "https://clawhub.ai/PaulDeFi/zyfai-sdk",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/zyfai-sdk",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=zyfai-sdk",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/zyfai-sdk"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/zyfai-sdk",
    "agentPageUrl": "https://openagent3.xyz/skills/zyfai-sdk/agent",
    "manifestUrl": "https://openagent3.xyz/skills/zyfai-sdk/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/zyfai-sdk/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Zyfai — Yield for Any Wallet",
        "body": "Let any Ethereum wallet access a yield-generating account."
      },
      {
        "title": "What This Does",
        "body": "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.\n\n┌─────────────────┐      ┌──────────────────────┐\n│   User's EOA    │ ───► │  Zyfai Subaccount    │\n│  (their wallet) │      │  (Safe smart wallet) │\n│                 │      │                      │\n│  Owns & controls│      │  • Auto-rebalancing  │\n│                 │      │  • Yield optimization│\n│                 │      │  • Non-custodial     │\n└─────────────────┘      └──────────────────────┘\n\nKey points:\n\nThe subaccount is owned by the user's EOA — only they can withdraw\nSession keys allow automated rebalancing but cannot withdraw to other addresses\nSame EOA = same subaccount address across all chains"
      },
      {
        "title": "The Flow",
        "body": "1. DEPLOY    →  Create a deterministic subaccount linked to user's wallet\n2. SESSION   →  Enable automated yield optimization  \n3. DEPOSIT   →  Send funds to subaccount (starts earning)\n4. WITHDRAW  →  Pull funds back to wallet (anytime)"
      },
      {
        "title": "Prerequisites",
        "body": "API Key — Get one programmatically (see below) or manually at sdk.zyf.ai\nWallet Connection — Either a wallet provider (browser) or secure key management (server)\nNode.js 18+\n\nnpm install @zyfai/sdk viem"
      },
      {
        "title": "Programmatic API Key Creation (Agent-Native)",
        "body": "Agents can create their own API key without human intervention. You need the wallet address (public key) of the agent.\n\nPOST https://sdk.zyf.ai/api/sdk-api-keys/create\nContent-Type: application/json\n\n{\n  \"clientName\": \"my-agent\",\n  \"walletAddress\": \"0x...\",\n  \"email\": \"agent@example.com\"\n}\n\nResponse:\n\n{\n  \"success\": true,\n  \"message\": \"SDK API key created successfully. Store the apiKey securely - it cannot be retrieved later!\",\n  \"data\": {\n    \"id\": \"936...\",\n    \"apiKey\": \"zyfai_361ad41d083c2fe.....\",\n    \"keyPrefix\": \"zyfai_361ad4\",\n    \"clientName\": \"my-agent\",\n    \"ownerWalletAddress\": \"0x...\"\n  }\n}\n\nImportant: Store the apiKey securely — it cannot be retrieved later. The key is linked to the provided wallet address."
      },
      {
        "title": "Supported Chains",
        "body": "ChainIDArbitrum42161Base8453Plasma9745"
      },
      {
        "title": "Important: Always Use EOA Address",
        "body": "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."
      },
      {
        "title": "Wallet Connection Options",
        "body": "The SDK supports multiple ways to connect a wallet. Choose based on your security requirements and deployment context."
      },
      {
        "title": "Option 1: Wallet Provider (Recommended for Browser/dApps)",
        "body": "Use an injected wallet provider like MetaMask. The private key never leaves the user's wallet.\n\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// Connect using injected wallet provider (MetaMask, WalletConnect, etc.)\nawait sdk.connectAccount(window.ethereum, 8453);\n\nSecurity: The private key stays in the user's wallet. The SDK only requests signatures when needed."
      },
      {
        "title": "Option 2: Viem WalletClient (Recommended for Server Agents)",
        "body": "Use a pre-configured viem WalletClient. This is the recommended approach for server-side agents as it allows integration with secure key management solutions.\n\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\nimport { createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\n// Create wallet client with your preferred key management\n// Option A: From environment variable (simple but requires secure env management)\nconst account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);\n\n// Option B: From KMS (AWS, GCP, etc.) - recommended for production\n// const account = await getAccountFromKMS();\n\n// Option C: From Wallet-as-a-Service (Turnkey, Privy, etc.)\n// const account = await turnkeyClient.getAccount();\n\nconst walletClient = createWalletClient({\n  account,\n  chain: base,\n  transport: http(),\n});\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// Connect using the WalletClient\nawait sdk.connectAccount(walletClient, 8453);\n\nSecurity: The WalletClient abstraction allows you to integrate with secure key management solutions like:\n\nAWS KMS / GCP Cloud KMS — Hardware-backed key storage\nTurnkey / Privy / Dynamic — Wallet-as-a-Service providers\nHardware wallets — Via WalletConnect or similar"
      },
      {
        "title": "Option 3: Private Key String (Development Only)",
        "body": "Direct private key usage.\n\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// WARNING: Only use for development. Never hardcode private keys in production.\nawait sdk.connectAccount(process.env.PRIVATE_KEY, 8453);\n\nSecurity Warning: Raw private keys in environment variables are a security risk. For production autonomous agents, use Option 2 with a proper key management solution."
      },
      {
        "title": "Security Comparison",
        "body": "MethodSecurity LevelUse CaseWallet ProviderHighBrowser dApps, user-facing appsWalletClient + KMSHighProduction server agentsWalletClient + WaaSHighProduction server agentsPrivate Key StringLowDevelopment/testing only"
      },
      {
        "title": "1. Connect to Zyfai",
        "body": "import { ZyfaiSDK } from \"@zyfai/sdk\";\nimport { createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// For browser: use wallet provider\nawait sdk.connectAccount(window.ethereum, 8453);\n\n// For server: use WalletClient (see Wallet Connection Options above)\nconst walletClient = createWalletClient({\n  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),\n  chain: base,\n  transport: http(),\n});\nawait sdk.connectAccount(walletClient, 8453);"
      },
      {
        "title": "2. Deploy Subaccount",
        "body": "const userAddress = \"0x...\"; // User's EOA (NOT the subaccount address!)\nconst chainId = 8453; // Base\n\n// Check if subaccount exists\nconst wallet = await sdk.getSmartWalletAddress(userAddress, chainId);\nconsole.log(`Subaccount: ${wallet.address}`);\nconsole.log(`Deployed: ${wallet.isDeployed}`);\n\n// Deploy if needed\nif (!wallet.isDeployed) {\n  const result = await sdk.deploySafe(userAddress, chainId, \"conservative\");\n  console.log(\"Subaccount deployed:\", result.safeAddress);\n}\n\nStrategies:\n\n\"conservative\" — Stable yield, lower risk\n\"aggressive\" — Higher yield, higher risk"
      },
      {
        "title": "3. Enable Yield Optimization",
        "body": "await sdk.createSessionKey(userAddress, chainId);\n\n// Always verify the session key was activated\nconst user = await sdk.getUserDetails();\nif (!user.user.hasActiveSessionKey) {\n  // Session key not active — retry the process\n  console.log(\"Session key not active, retrying...\");\n  await sdk.createSessionKey(userAddress, chainId);\n  \n  // Verify again\n  const userRetry = await sdk.getUserDetails();\n  if (!userRetry.user.hasActiveSessionKey) {\n    throw new Error(\"Session key activation failed after retry. Contact support.\");\n  }\n}\nconsole.log(\"Session key active:\", user.user.hasActiveSessionKey);\n\nThis allows Zyfai to rebalance funds automatically. Session keys cannot withdraw to arbitrary addresses — only optimize within the protocol.\n\nImportant: 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."
      },
      {
        "title": "4. Deposit Funds",
        "body": "// Deposit 10 USDC (6 decimals)\nawait sdk.depositFunds(userAddress, chainId, \"10000000\");\n\nFunds move from EOA -> Subaccount and start earning yield immediately."
      },
      {
        "title": "5. Withdraw Funds",
        "body": "// Withdraw everything\nawait sdk.withdrawFunds(userAddress, chainId);\n\n// Or withdraw partial (5 USDC)\nawait sdk.withdrawFunds(userAddress, chainId, \"5000000\");\n\nFunds return to the user's EOA. Withdrawals are processed asynchronously."
      },
      {
        "title": "6. Disconnect",
        "body": "await sdk.disconnectAccount();"
      },
      {
        "title": "Complete Example",
        "body": "import { ZyfaiSDK } from \"@zyfai/sdk\";\nimport { createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nasync function startEarningYield(userAddress: string) {\n  const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! });\n  const chainId = 8453; // Base\n  \n  // Connect using WalletClient (recommended for server agents)\n  const walletClient = createWalletClient({\n    account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),\n    chain: base,\n    transport: http(),\n  });\n  await sdk.connectAccount(walletClient, chainId);\n  \n  // Deploy subaccount if needed (always pass EOA as userAddress)\n  const wallet = await sdk.getSmartWalletAddress(userAddress, chainId);\n  if (!wallet.isDeployed) {\n    await sdk.deploySafe(userAddress, chainId, \"conservative\");\n    console.log(\"Subaccount created:\", wallet.address);\n  }\n  \n  // Enable automated optimization\n  await sdk.createSessionKey(userAddress, chainId);\n  \n  // Verify session key is active\n  const user = await sdk.getUserDetails();\n  if (!user.user.hasActiveSessionKey) {\n    console.log(\"Session key not active, retrying...\");\n    await sdk.createSessionKey(userAddress, chainId);\n    const userRetry = await sdk.getUserDetails();\n    if (!userRetry.user.hasActiveSessionKey) {\n      throw new Error(\"Session key activation failed. Contact support.\");\n    }\n  }\n  \n  // Deposit 100 USDC\n  await sdk.depositFunds(userAddress, chainId, \"100000000\");\n  console.log(\"Deposited! Now earning yield.\");\n  \n  await sdk.disconnectAccount();\n}\n\nasync function withdrawYield(userAddress: string, amount?: string) {\n  const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! });\n  const chainId = 8453; // Base\n  \n  // Connect using WalletClient\n  const walletClient = createWalletClient({\n    account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),\n    chain: base,\n    transport: http(),\n  });\n  await sdk.connectAccount(walletClient, chainId);\n  \n  // Withdraw funds (pass EOA as userAddress)\n  if (amount) {\n    // Partial withdrawal\n    await sdk.withdrawFunds(userAddress, chainId, amount);\n    console.log(`Withdrawn ${amount} (6 decimals) to EOA`);\n  } else {\n    // Full withdrawal\n    await sdk.withdrawFunds(userAddress, chainId);\n    console.log(\"Withdrawn all funds to EOA\");\n  }\n  \n  await sdk.disconnectAccount();\n}"
      },
      {
        "title": "API Reference",
        "body": "MethodParamsDescriptionconnectAccount(walletClientOrProvider, chainId)Authenticate with ZyfaigetSmartWalletAddress(userAddress, chainId)Get subaccount address & statusdeploySafe(userAddress, chainId, strategy)Create subaccountcreateSessionKey(userAddress, chainId)Enable auto-optimizationdepositFunds(userAddress, chainId, amount)Deposit USDC (6 decimals)withdrawFunds(userAddress, chainId, amount?)Withdraw (all if no amount)getPositions(userAddress, chainId?)Get active DeFi positionsgetAvailableProtocols(chainId)Get available protocols & poolsgetAPYPerStrategy(crossChain?, days?, strategyType?)Get APY for conservative/aggressive strategiesgetUserDetails()Get authenticated user detailsgetOnchainEarnings(walletAddress)Get earnings dataupdateUserProfile(params)Update strategy, protocols, splitting, cross-chain settingsregisterAgentOnIdentityRegistry(smartWallet, chainId)Register agent on ERC-8004 Identity RegistrydisconnectAccount()End session\n\nNote: All methods that take userAddress expect the EOA address, not the subaccount/Safe address."
      },
      {
        "title": "getPositions",
        "body": "Get all active DeFi positions for a user across protocols. Optionally filter by chain.\n\nParameters:\n\nParameterTypeRequiredDescriptionuserAddressstringYesUser's EOA addresschainIdSupportedChainIdNoOptional: Filter by specific chain ID\n\nExample:\n\n// Get all positions across all chains\nconst positions = await sdk.getPositions(\"0xUser...\");\n\n// Get positions on Arbitrum only\nconst arbPositions = await sdk.getPositions(\"0xUser...\", 42161);\n\nReturns:\n\ninterface PositionsResponse {\n  success: boolean;\n  userAddress: string;\n  positions: Position[];\n}"
      },
      {
        "title": "getAvailableProtocols",
        "body": "Get available DeFi protocols and pools for a specific chain with APY data.\n\nconst protocols = await sdk.getAvailableProtocols(42161); // Arbitrum\n\nprotocols.protocols.forEach((protocol) => {\n  console.log(`${protocol.name} (ID: ${protocol.id})`);\n  if (protocol.pools) {\n    protocol.pools.forEach((pool) => {\n      console.log(`  Pool: ${pool.name} - APY: ${pool.apy || \"N/A\"}%`);\n    });\n  }\n});\n\nReturns:\n\ninterface ProtocolsResponse {\n  success: boolean;\n  chainId: SupportedChainId;\n  protocols: Protocol[];\n}"
      },
      {
        "title": "getUserDetails",
        "body": "Get current authenticated user details including smart wallet, chains, protocols, and settings. Requires SIWE authentication.\n\nawait sdk.connectAccount(walletClient, chainId);\nconst user = await sdk.getUserDetails();\n\nconsole.log(\"Smart Wallet:\", user.user.smartWallet);\nconsole.log(\"Chains:\", user.user.chains);\nconsole.log(\"Has Active Session:\", user.user.hasActiveSessionKey);\n\nReturns:\n\ninterface UserDetailsResponse {\n  success: boolean;\n  user: {\n    id: string;\n    address: string;\n    smartWallet?: string;\n    chains: number[];\n    protocols: Protocol[];\n    hasActiveSessionKey: boolean;\n    email?: string;\n    strategy?: string;\n    telegramId?: string;\n    walletType?: string;\n    autoSelectProtocols: boolean;\n    autocompounding?: boolean;\n    omniAccount?: boolean;\n    crosschainStrategy?: boolean;\n    agentName?: string;\n    customization?: Record<string, string[]>;\n  };\n}"
      },
      {
        "title": "updateUserProfile",
        "body": "Update the authenticated user's profile settings including strategy, protocols, splitting, and cross-chain options. Requires SIWE authentication.\n\nsdk.updateUserProfile(params: UpdateUserProfileRequest): Promise<UpdateUserProfileResponse>\n\nParameters:\n\ninterface UpdateUserProfileRequest {\n  /** Investment strategy: \"conservative\" for safer yields, \"aggressive\" for higher risk/reward */\n  strategy?: \"conservative\" | \"aggressive\";\n\n  /** Array of protocol IDs to use for yield optimization */\n  protocols?: string[];\n\n  /** Enable omni-account feature for cross-chain operations */\n  omniAccount?: boolean;\n\n  /** Enable automatic compounding of earned yields (default: true) */\n  autocompounding?: boolean;\n\n  /** Custom name for your agent */\n  agentName?: string;\n\n  /** Enable cross-chain strategy execution */\n  crosschainStrategy?: boolean;\n\n  /** Enable position splitting across multiple protocols */\n  splitting?: boolean;\n\n  /** Minimum number of splits when position splitting is enabled (1-4) */\n  minSplits?: number;\n}\n\nReturns:\n\ninterface UpdateUserProfileResponse {\n  success: boolean;\n  userId: string;\n  smartWallet?: string;\n  chains?: number[];\n  strategy?: string;\n  protocols?: string[];\n  omniAccount?: boolean;\n  autocompounding?: boolean;\n  agentName?: string;\n  crosschainStrategy?: boolean;\n  executorProxy?: boolean;\n  splitting?: boolean;\n  minSplits?: number;\n}\n\nExamples:\n\n// Update strategy from conservative to aggressive\nawait sdk.updateUserProfile({\n  strategy: \"aggressive\",\n});\n\n// Configure specific protocols\nconst protocolsResponse = await sdk.getAvailableProtocols(8453);\nconst selectedProtocols = protocolsResponse.protocols\n  .filter(p => [\"Aave\", \"Compound\", \"Moonwell\"].includes(p.name))\n  .map(p => p.id);\n\nawait sdk.updateUserProfile({\n  protocols: selectedProtocols,\n});\n\n// Enable position splitting (distribute across multiple protocols)\nawait sdk.updateUserProfile({\n  splitting: true,\n  minSplits: 3, // Split across at least 3 protocols\n});\n\n// Verify changes\nconst userDetails = await sdk.getUserDetails();\nconsole.log(\"Strategy:\", userDetails.user.strategy);\nconsole.log(\"Splitting:\", userDetails.user.splitting);\n\nCross-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.\n\n// Enable cross-chain ONLY when explicitly requested by the user\nawait sdk.updateUserProfile({\n  crosschainStrategy: true,\n  omniAccount: true,\n});\n\n// Now funds can be rebalanced across configured chains\nconst user = await sdk.getUserDetails();\nconsole.log(\"Operating on chains:\", user.user.chains);\n\nNotes:\n\nStrategy: Can be changed anytime. Subsequent rebalancing uses the new active strategy.\nProtocols: Use getAvailableProtocols(chainId) to get valid protocol IDs before updating.\nSmart 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.\nForced 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.\nCross-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.\nAuto-compounding: Enabled by default. When true, yields are reinvested automatically.\nSmart wallet address, chains, and executorProxy cannot be updated via this method."
      },
      {
        "title": "getAPYPerStrategy",
        "body": "Get global APY by strategy type (conservative or aggressive), time period, and chain configuration. Use this to compare expected returns between strategies before deploying.\n\nParameters:\n\nParameterTypeRequiredDescriptioncrossChainbooleanNoIf true, returns APY for cross-chain strategies; if false, single-chaindaysnumberNoPeriod over which APY is calculated. One of 7, 15, 30, 60strategyTypestringNoStrategy risk profile. One of 'conservative' or 'aggressive'\n\nExample:\n\n// Get 7-day APY for conservative single-chain strategy\nconst conservativeApy = await sdk.getAPYPerStrategy(false, 7, 'conservative');\nconsole.log(\"Conservative APY:\", conservativeApy.data);\n\n// Get 30-day APY for aggressive cross-chain strategy\nconst aggressiveApy = await sdk.getAPYPerStrategy(true, 30, 'aggressive');\nconsole.log(\"Aggressive APY:\", aggressiveApy.data);\n\n// Compare strategies\nconst conservative = await sdk.getAPYPerStrategy(false, 30, 'conservative');\nconst aggressive = await sdk.getAPYPerStrategy(false, 30, 'aggressive');\nconsole.log(`Conservative 30d APY: ${conservative.data[0]?.apy}%`);\nconsole.log(`Aggressive 30d APY: ${aggressive.data[0]?.apy}%`);\n\nReturns:\n\ninterface APYPerStrategyResponse {\n  success: boolean;\n  count: number;\n  data: APYPerStrategy[];\n}\n\ninterface APYPerStrategy {\n  strategyType: string;\n  apy: number;\n  period: number;\n  crossChain: boolean;\n}"
      },
      {
        "title": "getOnchainEarnings",
        "body": "Get onchain earnings for a wallet including total, current, and lifetime earnings.\n\nconst earnings = await sdk.getOnchainEarnings(smartWalletAddress);\n\nconsole.log(\"Total earnings:\", earnings.data.totalEarnings);\nconsole.log(\"Current earnings:\", earnings.data.currentEarnings);\nconsole.log(\"Lifetime earnings:\", earnings.data.lifetimeEarnings);\n\nReturns:\n\ninterface OnchainEarningsResponse {\n  success: boolean;\n  data: {\n    walletAddress: string;\n    totalEarnings: number;\n    currentEarnings: number;\n    lifetimeEarnings: number;\n    unrealizedEarnings?: number;\n    currentEarningsByChain?: Record<string, number>;\n    unrealizedEarningsByChain?: Record<string, number>;\n    lastCheckTimestamp?: string;\n  };\n}"
      },
      {
        "title": "registerAgentOnIdentityRegistry (ERC-8004)",
        "body": "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.\n\nSupported Chains:\n\nChainChain IDBase8453Arbitrum42161\n\nParameters:\n\nParameterTypeRequiredDescriptionsmartWalletstringYesThe Zyfai deployed smart wallet address to register as an agentchainIdSupportedChainIdYesChain ID (only 8453 or 42161)\n\nExample:\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\" });\nawait sdk.connectAccount(walletClient, 8453);\n\n// Get smart wallet address\nconst walletInfo = await sdk.getSmartWalletAddress(userAddress, 8453);\nconst smartWallet = walletInfo.address;\n\n// Register agent on Identity Registry\nconst result = await sdk.registerAgentOnIdentityRegistry(smartWallet, 8453);\n\nconsole.log(\"Registration successful:\");\nconsole.log(\"  Tx Hash:\", result.txHash);\nconsole.log(\"  Chain ID:\", result.chainId);\nconsole.log(\"  Smart Wallet:\", result.smartWallet);\n\nReturns:\n\ninterface RegisterAgentResponse {\n  success: boolean;\n  txHash: string;\n  chainId: number;\n  smartWallet: string;\n}\n\nHow It Works:\n\nFetches a tokenUri from the Zyfai API (agent metadata stored on IPFS)\nEncodes the register(tokenUri) call for the Identity Registry contract\nSends the transaction from the connected wallet\nWaits for on-chain confirmation"
      },
      {
        "title": "Security",
        "body": "Non-custodial — User's EOA owns the subaccount\nSession keys are limited — Can rebalance, cannot withdraw elsewhere\nDeterministic — Same EOA = same subaccount on every chain\nFlexible key management — Use wallet providers, WalletClients, or KMS integrations"
      },
      {
        "title": "Key Management Best Practices",
        "body": "For production autonomous agents, we recommend:\n\nUse a WalletClient with a secure key source (not raw private keys)\nIntegrate with KMS (AWS KMS, GCP Cloud KMS) for hardware-backed key storage\nConsider Wallet-as-a-Service providers like Turnkey, Privy, or Dynamic\nNever hardcode private keys in source code\nRotate keys periodically and implement key revocation procedures"
      },
      {
        "title": "Subaccount address mismatch across chains",
        "body": "The subaccount address should be identical across all chains for the same EOA. If you see different addresses:\n\n// Check addresses on both chains\nconst baseWallet = await sdk.getSmartWalletAddress(userAddress, 8453);\nconst arbWallet = await sdk.getSmartWalletAddress(userAddress, 42161);\n\nif (baseWallet.address !== arbWallet.address) {\n  console.error(\"Address mismatch! Contact support.\");\n}\n\nIf addresses don't match:\n\nTry redeploying on the affected chain\nIf the issue persists, contact support on Telegram: @paul_zyfai"
      },
      {
        "title": "\"Deposit address not found\" error",
        "body": "This means the wallet isn't registered in the backend. Solution:\n\nCall deploySafe() first — even if the Safe is already deployed on-chain, this registers it with the backend\nThen retry createSessionKey()"
      },
      {
        "title": "\"Invalid signature\" error",
        "body": "This typically means:\n\nThe wallet/signer doesn't match the EOA you're passing\nThe Safe address on-chain doesn't match what the SDK expects\n\nVerify you're using the correct wallet for the EOA."
      },
      {
        "title": "Resources",
        "body": "Get API Key: sdk.zyf.ai or programmatically via POST /api/sdk-api-keys/create\nDocs: docs.zyf.ai\nDemo: github.com/ondefy/zyfai-sdk-demo\nMCP Server: mcp.zyf.ai — Use with Claude or other MCP-compatible agents\nAgent Registration: zyf.ai/.well-known/agent-registration.json"
      }
    ],
    "body": "Zyfai — Yield for Any Wallet\n\nLet any Ethereum wallet access a yield-generating account.\n\nWhat This Does\n\nWhen 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.\n\n┌─────────────────┐      ┌──────────────────────┐\n│   User's EOA    │ ───► │  Zyfai Subaccount    │\n│  (their wallet) │      │  (Safe smart wallet) │\n│                 │      │                      │\n│  Owns & controls│      │  • Auto-rebalancing  │\n│                 │      │  • Yield optimization│\n│                 │      │  • Non-custodial     │\n└─────────────────┘      └──────────────────────┘\n\n\nKey points:\n\nThe subaccount is owned by the user's EOA — only they can withdraw\nSession keys allow automated rebalancing but cannot withdraw to other addresses\nSame EOA = same subaccount address across all chains\nThe Flow\n1. DEPLOY    →  Create a deterministic subaccount linked to user's wallet\n2. SESSION   →  Enable automated yield optimization  \n3. DEPOSIT   →  Send funds to subaccount (starts earning)\n4. WITHDRAW  →  Pull funds back to wallet (anytime)\n\nPrerequisites\nAPI Key — Get one programmatically (see below) or manually at sdk.zyf.ai\nWallet Connection — Either a wallet provider (browser) or secure key management (server)\nNode.js 18+\nnpm install @zyfai/sdk viem\n\nProgrammatic API Key Creation (Agent-Native)\n\nAgents can create their own API key without human intervention. You need the wallet address (public key) of the agent.\n\nPOST https://sdk.zyf.ai/api/sdk-api-keys/create\nContent-Type: application/json\n\n{\n  \"clientName\": \"my-agent\",\n  \"walletAddress\": \"0x...\",\n  \"email\": \"agent@example.com\"\n}\n\n\nResponse:\n\n{\n  \"success\": true,\n  \"message\": \"SDK API key created successfully. Store the apiKey securely - it cannot be retrieved later!\",\n  \"data\": {\n    \"id\": \"936...\",\n    \"apiKey\": \"zyfai_361ad41d083c2fe.....\",\n    \"keyPrefix\": \"zyfai_361ad4\",\n    \"clientName\": \"my-agent\",\n    \"ownerWalletAddress\": \"0x...\"\n  }\n}\n\n\nImportant: Store the apiKey securely — it cannot be retrieved later. The key is linked to the provided wallet address.\n\nSupported Chains\nChain\tID\nArbitrum\t42161\nBase\t8453\nPlasma\t9745\nImportant: Always Use EOA Address\n\nWhen 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.\n\nWallet Connection Options\n\nThe SDK supports multiple ways to connect a wallet. Choose based on your security requirements and deployment context.\n\nOption 1: Wallet Provider (Recommended for Browser/dApps)\n\nUse an injected wallet provider like MetaMask. The private key never leaves the user's wallet.\n\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// Connect using injected wallet provider (MetaMask, WalletConnect, etc.)\nawait sdk.connectAccount(window.ethereum, 8453);\n\n\nSecurity: The private key stays in the user's wallet. The SDK only requests signatures when needed.\n\nOption 2: Viem WalletClient (Recommended for Server Agents)\n\nUse a pre-configured viem WalletClient. This is the recommended approach for server-side agents as it allows integration with secure key management solutions.\n\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\nimport { createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\n// Create wallet client with your preferred key management\n// Option A: From environment variable (simple but requires secure env management)\nconst account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);\n\n// Option B: From KMS (AWS, GCP, etc.) - recommended for production\n// const account = await getAccountFromKMS();\n\n// Option C: From Wallet-as-a-Service (Turnkey, Privy, etc.)\n// const account = await turnkeyClient.getAccount();\n\nconst walletClient = createWalletClient({\n  account,\n  chain: base,\n  transport: http(),\n});\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// Connect using the WalletClient\nawait sdk.connectAccount(walletClient, 8453);\n\n\nSecurity: The WalletClient abstraction allows you to integrate with secure key management solutions like:\n\nAWS KMS / GCP Cloud KMS — Hardware-backed key storage\nTurnkey / Privy / Dynamic — Wallet-as-a-Service providers\nHardware wallets — Via WalletConnect or similar\nOption 3: Private Key String (Development Only)\n\nDirect private key usage.\n\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// WARNING: Only use for development. Never hardcode private keys in production.\nawait sdk.connectAccount(process.env.PRIVATE_KEY, 8453);\n\n\nSecurity Warning: Raw private keys in environment variables are a security risk. For production autonomous agents, use Option 2 with a proper key management solution.\n\nSecurity Comparison\nMethod\tSecurity Level\tUse Case\nWallet Provider\tHigh\tBrowser dApps, user-facing apps\nWalletClient + KMS\tHigh\tProduction server agents\nWalletClient + WaaS\tHigh\tProduction server agents\nPrivate Key String\tLow\tDevelopment/testing only\nStep-by-Step\n1. Connect to Zyfai\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\nimport { createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\", referralSource: \"openclaw-skill\" });\n\n// For browser: use wallet provider\nawait sdk.connectAccount(window.ethereum, 8453);\n\n// For server: use WalletClient (see Wallet Connection Options above)\nconst walletClient = createWalletClient({\n  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),\n  chain: base,\n  transport: http(),\n});\nawait sdk.connectAccount(walletClient, 8453);\n\n2. Deploy Subaccount\nconst userAddress = \"0x...\"; // User's EOA (NOT the subaccount address!)\nconst chainId = 8453; // Base\n\n// Check if subaccount exists\nconst wallet = await sdk.getSmartWalletAddress(userAddress, chainId);\nconsole.log(`Subaccount: ${wallet.address}`);\nconsole.log(`Deployed: ${wallet.isDeployed}`);\n\n// Deploy if needed\nif (!wallet.isDeployed) {\n  const result = await sdk.deploySafe(userAddress, chainId, \"conservative\");\n  console.log(\"Subaccount deployed:\", result.safeAddress);\n}\n\n\nStrategies:\n\n\"conservative\" — Stable yield, lower risk\n\"aggressive\" — Higher yield, higher risk\n3. Enable Yield Optimization\nawait sdk.createSessionKey(userAddress, chainId);\n\n// Always verify the session key was activated\nconst user = await sdk.getUserDetails();\nif (!user.user.hasActiveSessionKey) {\n  // Session key not active — retry the process\n  console.log(\"Session key not active, retrying...\");\n  await sdk.createSessionKey(userAddress, chainId);\n  \n  // Verify again\n  const userRetry = await sdk.getUserDetails();\n  if (!userRetry.user.hasActiveSessionKey) {\n    throw new Error(\"Session key activation failed after retry. Contact support.\");\n  }\n}\nconsole.log(\"Session key active:\", user.user.hasActiveSessionKey);\n\n\nThis allows Zyfai to rebalance funds automatically. Session keys cannot withdraw to arbitrary addresses — only optimize within the protocol.\n\nImportant: 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.\n\n4. Deposit Funds\n// Deposit 10 USDC (6 decimals)\nawait sdk.depositFunds(userAddress, chainId, \"10000000\");\n\n\nFunds move from EOA -> Subaccount and start earning yield immediately.\n\n5. Withdraw Funds\n// Withdraw everything\nawait sdk.withdrawFunds(userAddress, chainId);\n\n// Or withdraw partial (5 USDC)\nawait sdk.withdrawFunds(userAddress, chainId, \"5000000\");\n\n\nFunds return to the user's EOA. Withdrawals are processed asynchronously.\n\n6. Disconnect\nawait sdk.disconnectAccount();\n\nComplete Example\nimport { ZyfaiSDK } from \"@zyfai/sdk\";\nimport { createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nasync function startEarningYield(userAddress: string) {\n  const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! });\n  const chainId = 8453; // Base\n  \n  // Connect using WalletClient (recommended for server agents)\n  const walletClient = createWalletClient({\n    account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),\n    chain: base,\n    transport: http(),\n  });\n  await sdk.connectAccount(walletClient, chainId);\n  \n  // Deploy subaccount if needed (always pass EOA as userAddress)\n  const wallet = await sdk.getSmartWalletAddress(userAddress, chainId);\n  if (!wallet.isDeployed) {\n    await sdk.deploySafe(userAddress, chainId, \"conservative\");\n    console.log(\"Subaccount created:\", wallet.address);\n  }\n  \n  // Enable automated optimization\n  await sdk.createSessionKey(userAddress, chainId);\n  \n  // Verify session key is active\n  const user = await sdk.getUserDetails();\n  if (!user.user.hasActiveSessionKey) {\n    console.log(\"Session key not active, retrying...\");\n    await sdk.createSessionKey(userAddress, chainId);\n    const userRetry = await sdk.getUserDetails();\n    if (!userRetry.user.hasActiveSessionKey) {\n      throw new Error(\"Session key activation failed. Contact support.\");\n    }\n  }\n  \n  // Deposit 100 USDC\n  await sdk.depositFunds(userAddress, chainId, \"100000000\");\n  console.log(\"Deposited! Now earning yield.\");\n  \n  await sdk.disconnectAccount();\n}\n\nasync function withdrawYield(userAddress: string, amount?: string) {\n  const sdk = new ZyfaiSDK({ apiKey: process.env.ZYFAI_API_KEY! });\n  const chainId = 8453; // Base\n  \n  // Connect using WalletClient\n  const walletClient = createWalletClient({\n    account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),\n    chain: base,\n    transport: http(),\n  });\n  await sdk.connectAccount(walletClient, chainId);\n  \n  // Withdraw funds (pass EOA as userAddress)\n  if (amount) {\n    // Partial withdrawal\n    await sdk.withdrawFunds(userAddress, chainId, amount);\n    console.log(`Withdrawn ${amount} (6 decimals) to EOA`);\n  } else {\n    // Full withdrawal\n    await sdk.withdrawFunds(userAddress, chainId);\n    console.log(\"Withdrawn all funds to EOA\");\n  }\n  \n  await sdk.disconnectAccount();\n}\n\nAPI Reference\nMethod\tParams\tDescription\nconnectAccount\t(walletClientOrProvider, chainId)\tAuthenticate with Zyfai\ngetSmartWalletAddress\t(userAddress, chainId)\tGet subaccount address & status\ndeploySafe\t(userAddress, chainId, strategy)\tCreate subaccount\ncreateSessionKey\t(userAddress, chainId)\tEnable auto-optimization\ndepositFunds\t(userAddress, chainId, amount)\tDeposit USDC (6 decimals)\nwithdrawFunds\t(userAddress, chainId, amount?)\tWithdraw (all if no amount)\ngetPositions\t(userAddress, chainId?)\tGet active DeFi positions\ngetAvailableProtocols\t(chainId)\tGet available protocols & pools\ngetAPYPerStrategy\t(crossChain?, days?, strategyType?)\tGet APY for conservative/aggressive strategies\ngetUserDetails\t()\tGet authenticated user details\ngetOnchainEarnings\t(walletAddress)\tGet earnings data\nupdateUserProfile\t(params)\tUpdate strategy, protocols, splitting, cross-chain settings\nregisterAgentOnIdentityRegistry\t(smartWallet, chainId)\tRegister agent on ERC-8004 Identity Registry\ndisconnectAccount\t()\tEnd session\n\nNote: All methods that take userAddress expect the EOA address, not the subaccount/Safe address.\n\nData Methods\ngetPositions\n\nGet all active DeFi positions for a user across protocols. Optionally filter by chain.\n\nParameters:\n\nParameter\tType\tRequired\tDescription\nuserAddress\tstring\tYes\tUser's EOA address\nchainId\tSupportedChainId\tNo\tOptional: Filter by specific chain ID\n\nExample:\n\n// Get all positions across all chains\nconst positions = await sdk.getPositions(\"0xUser...\");\n\n// Get positions on Arbitrum only\nconst arbPositions = await sdk.getPositions(\"0xUser...\", 42161);\n\n\nReturns:\n\ninterface PositionsResponse {\n  success: boolean;\n  userAddress: string;\n  positions: Position[];\n}\n\ngetAvailableProtocols\n\nGet available DeFi protocols and pools for a specific chain with APY data.\n\nconst protocols = await sdk.getAvailableProtocols(42161); // Arbitrum\n\nprotocols.protocols.forEach((protocol) => {\n  console.log(`${protocol.name} (ID: ${protocol.id})`);\n  if (protocol.pools) {\n    protocol.pools.forEach((pool) => {\n      console.log(`  Pool: ${pool.name} - APY: ${pool.apy || \"N/A\"}%`);\n    });\n  }\n});\n\n\nReturns:\n\ninterface ProtocolsResponse {\n  success: boolean;\n  chainId: SupportedChainId;\n  protocols: Protocol[];\n}\n\ngetUserDetails\n\nGet current authenticated user details including smart wallet, chains, protocols, and settings. Requires SIWE authentication.\n\nawait sdk.connectAccount(walletClient, chainId);\nconst user = await sdk.getUserDetails();\n\nconsole.log(\"Smart Wallet:\", user.user.smartWallet);\nconsole.log(\"Chains:\", user.user.chains);\nconsole.log(\"Has Active Session:\", user.user.hasActiveSessionKey);\n\n\nReturns:\n\ninterface UserDetailsResponse {\n  success: boolean;\n  user: {\n    id: string;\n    address: string;\n    smartWallet?: string;\n    chains: number[];\n    protocols: Protocol[];\n    hasActiveSessionKey: boolean;\n    email?: string;\n    strategy?: string;\n    telegramId?: string;\n    walletType?: string;\n    autoSelectProtocols: boolean;\n    autocompounding?: boolean;\n    omniAccount?: boolean;\n    crosschainStrategy?: boolean;\n    agentName?: string;\n    customization?: Record<string, string[]>;\n  };\n}\n\nupdateUserProfile\n\nUpdate the authenticated user's profile settings including strategy, protocols, splitting, and cross-chain options. Requires SIWE authentication.\n\nsdk.updateUserProfile(params: UpdateUserProfileRequest): Promise<UpdateUserProfileResponse>\n\n\nParameters:\n\ninterface UpdateUserProfileRequest {\n  /** Investment strategy: \"conservative\" for safer yields, \"aggressive\" for higher risk/reward */\n  strategy?: \"conservative\" | \"aggressive\";\n\n  /** Array of protocol IDs to use for yield optimization */\n  protocols?: string[];\n\n  /** Enable omni-account feature for cross-chain operations */\n  omniAccount?: boolean;\n\n  /** Enable automatic compounding of earned yields (default: true) */\n  autocompounding?: boolean;\n\n  /** Custom name for your agent */\n  agentName?: string;\n\n  /** Enable cross-chain strategy execution */\n  crosschainStrategy?: boolean;\n\n  /** Enable position splitting across multiple protocols */\n  splitting?: boolean;\n\n  /** Minimum number of splits when position splitting is enabled (1-4) */\n  minSplits?: number;\n}\n\n\nReturns:\n\ninterface UpdateUserProfileResponse {\n  success: boolean;\n  userId: string;\n  smartWallet?: string;\n  chains?: number[];\n  strategy?: string;\n  protocols?: string[];\n  omniAccount?: boolean;\n  autocompounding?: boolean;\n  agentName?: string;\n  crosschainStrategy?: boolean;\n  executorProxy?: boolean;\n  splitting?: boolean;\n  minSplits?: number;\n}\n\n\nExamples:\n\n// Update strategy from conservative to aggressive\nawait sdk.updateUserProfile({\n  strategy: \"aggressive\",\n});\n\n// Configure specific protocols\nconst protocolsResponse = await sdk.getAvailableProtocols(8453);\nconst selectedProtocols = protocolsResponse.protocols\n  .filter(p => [\"Aave\", \"Compound\", \"Moonwell\"].includes(p.name))\n  .map(p => p.id);\n\nawait sdk.updateUserProfile({\n  protocols: selectedProtocols,\n});\n\n// Enable position splitting (distribute across multiple protocols)\nawait sdk.updateUserProfile({\n  splitting: true,\n  minSplits: 3, // Split across at least 3 protocols\n});\n\n// Verify changes\nconst userDetails = await sdk.getUserDetails();\nconsole.log(\"Strategy:\", userDetails.user.strategy);\nconsole.log(\"Splitting:\", userDetails.user.splitting);\n\n\nCross-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.\n\n// Enable cross-chain ONLY when explicitly requested by the user\nawait sdk.updateUserProfile({\n  crosschainStrategy: true,\n  omniAccount: true,\n});\n\n// Now funds can be rebalanced across configured chains\nconst user = await sdk.getUserDetails();\nconsole.log(\"Operating on chains:\", user.user.chains);\n\n\nNotes:\n\nStrategy: Can be changed anytime. Subsequent rebalancing uses the new active strategy.\nProtocols: Use getAvailableProtocols(chainId) to get valid protocol IDs before updating.\nSmart 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.\nForced 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.\nCross-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.\nAuto-compounding: Enabled by default. When true, yields are reinvested automatically.\nSmart wallet address, chains, and executorProxy cannot be updated via this method.\ngetAPYPerStrategy\n\nGet global APY by strategy type (conservative or aggressive), time period, and chain configuration. Use this to compare expected returns between strategies before deploying.\n\nParameters:\n\nParameter\tType\tRequired\tDescription\ncrossChain\tboolean\tNo\tIf true, returns APY for cross-chain strategies; if false, single-chain\ndays\tnumber\tNo\tPeriod over which APY is calculated. One of 7, 15, 30, 60\nstrategyType\tstring\tNo\tStrategy risk profile. One of 'conservative' or 'aggressive'\n\nExample:\n\n// Get 7-day APY for conservative single-chain strategy\nconst conservativeApy = await sdk.getAPYPerStrategy(false, 7, 'conservative');\nconsole.log(\"Conservative APY:\", conservativeApy.data);\n\n// Get 30-day APY for aggressive cross-chain strategy\nconst aggressiveApy = await sdk.getAPYPerStrategy(true, 30, 'aggressive');\nconsole.log(\"Aggressive APY:\", aggressiveApy.data);\n\n// Compare strategies\nconst conservative = await sdk.getAPYPerStrategy(false, 30, 'conservative');\nconst aggressive = await sdk.getAPYPerStrategy(false, 30, 'aggressive');\nconsole.log(`Conservative 30d APY: ${conservative.data[0]?.apy}%`);\nconsole.log(`Aggressive 30d APY: ${aggressive.data[0]?.apy}%`);\n\n\nReturns:\n\ninterface APYPerStrategyResponse {\n  success: boolean;\n  count: number;\n  data: APYPerStrategy[];\n}\n\ninterface APYPerStrategy {\n  strategyType: string;\n  apy: number;\n  period: number;\n  crossChain: boolean;\n}\n\ngetOnchainEarnings\n\nGet onchain earnings for a wallet including total, current, and lifetime earnings.\n\nconst earnings = await sdk.getOnchainEarnings(smartWalletAddress);\n\nconsole.log(\"Total earnings:\", earnings.data.totalEarnings);\nconsole.log(\"Current earnings:\", earnings.data.currentEarnings);\nconsole.log(\"Lifetime earnings:\", earnings.data.lifetimeEarnings);\n\n\nReturns:\n\ninterface OnchainEarningsResponse {\n  success: boolean;\n  data: {\n    walletAddress: string;\n    totalEarnings: number;\n    currentEarnings: number;\n    lifetimeEarnings: number;\n    unrealizedEarnings?: number;\n    currentEarningsByChain?: Record<string, number>;\n    unrealizedEarningsByChain?: Record<string, number>;\n    lastCheckTimestamp?: string;\n  };\n}\n\nregisterAgentOnIdentityRegistry (ERC-8004)\n\nRegister 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.\n\nSupported Chains:\n\nChain\tChain ID\nBase\t8453\nArbitrum\t42161\n\nParameters:\n\nParameter\tType\tRequired\tDescription\nsmartWallet\tstring\tYes\tThe Zyfai deployed smart wallet address to register as an agent\nchainId\tSupportedChainId\tYes\tChain ID (only 8453 or 42161)\n\nExample:\n\nconst sdk = new ZyfaiSDK({ apiKey: \"your-api-key\" });\nawait sdk.connectAccount(walletClient, 8453);\n\n// Get smart wallet address\nconst walletInfo = await sdk.getSmartWalletAddress(userAddress, 8453);\nconst smartWallet = walletInfo.address;\n\n// Register agent on Identity Registry\nconst result = await sdk.registerAgentOnIdentityRegistry(smartWallet, 8453);\n\nconsole.log(\"Registration successful:\");\nconsole.log(\"  Tx Hash:\", result.txHash);\nconsole.log(\"  Chain ID:\", result.chainId);\nconsole.log(\"  Smart Wallet:\", result.smartWallet);\n\n\nReturns:\n\ninterface RegisterAgentResponse {\n  success: boolean;\n  txHash: string;\n  chainId: number;\n  smartWallet: string;\n}\n\n\nHow It Works:\n\nFetches a tokenUri from the Zyfai API (agent metadata stored on IPFS)\nEncodes the register(tokenUri) call for the Identity Registry contract\nSends the transaction from the connected wallet\nWaits for on-chain confirmation\nSecurity\nNon-custodial — User's EOA owns the subaccount\nSession keys are limited — Can rebalance, cannot withdraw elsewhere\nDeterministic — Same EOA = same subaccount on every chain\nFlexible key management — Use wallet providers, WalletClients, or KMS integrations\nKey Management Best Practices\n\nFor production autonomous agents, we recommend:\n\nUse a WalletClient with a secure key source (not raw private keys)\nIntegrate with KMS (AWS KMS, GCP Cloud KMS) for hardware-backed key storage\nConsider Wallet-as-a-Service providers like Turnkey, Privy, or Dynamic\nNever hardcode private keys in source code\nRotate keys periodically and implement key revocation procedures\nTroubleshooting\nSubaccount address mismatch across chains\n\nThe subaccount address should be identical across all chains for the same EOA. If you see different addresses:\n\n// Check addresses on both chains\nconst baseWallet = await sdk.getSmartWalletAddress(userAddress, 8453);\nconst arbWallet = await sdk.getSmartWalletAddress(userAddress, 42161);\n\nif (baseWallet.address !== arbWallet.address) {\n  console.error(\"Address mismatch! Contact support.\");\n}\n\n\nIf addresses don't match:\n\nTry redeploying on the affected chain\nIf the issue persists, contact support on Telegram: @paul_zyfai\n\"Deposit address not found\" error\n\nThis means the wallet isn't registered in the backend. Solution:\n\nCall deploySafe() first — even if the Safe is already deployed on-chain, this registers it with the backend\nThen retry createSessionKey()\n\"Invalid signature\" error\n\nThis typically means:\n\nThe wallet/signer doesn't match the EOA you're passing\nThe Safe address on-chain doesn't match what the SDK expects\n\nVerify you're using the correct wallet for the EOA.\n\nResources\nGet API Key: sdk.zyf.ai or programmatically via POST /api/sdk-api-keys/create\nDocs: docs.zyf.ai\nDemo: github.com/ondefy/zyfai-sdk-demo\nMCP Server: mcp.zyf.ai — Use with Claude or other MCP-compatible agents\nAgent Registration: zyf.ai/.well-known/agent-registration.json"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/PaulDeFi/zyfai-sdk",
    "publisherUrl": "https://clawhub.ai/PaulDeFi/zyfai-sdk",
    "owner": "PaulDeFi",
    "version": "1.0.9",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/zyfai-sdk",
    "downloadUrl": "https://openagent3.xyz/downloads/zyfai-sdk",
    "agentUrl": "https://openagent3.xyz/skills/zyfai-sdk/agent",
    "manifestUrl": "https://openagent3.xyz/skills/zyfai-sdk/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/zyfai-sdk/agent.md"
  }
}