{
  "schemaVersion": "1.0",
  "item": {
    "slug": "vultisig-sdk",
    "name": "vultisig-sdk",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/realpaaao/vultisig-sdk",
    "canonicalUrl": "https://clawhub.ai/realpaaao/vultisig-sdk",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/vultisig-sdk",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=vultisig-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-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-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/vultisig-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/vultisig-sdk",
    "agentPageUrl": "https://openagent3.xyz/skills/vultisig-sdk/agent",
    "manifestUrl": "https://openagent3.xyz/skills/vultisig-sdk/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/vultisig-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": "What this Skill is for",
        "body": "Creating and managing self-custodial crypto vaults (Fast Vault for agents, Secure Vault for multi-device)\nSending transactions across 36+ blockchains (Bitcoin, Ethereum, Solana, Cosmos, and more)\nSwapping tokens cross-chain via THORChain, MayaChain, 1inch, LiFi, KyberSwap\nQuerying balances and gas fees across all supported chains\nImporting/exporting vault backups (.vult files)\nImporting existing wallets via BIP39 seedphrase\nBuilding automated strategies: DCA, rebalancing, conditional swaps, agent-to-agent payments"
      },
      {
        "title": "Default stack decisions",
        "body": "Fast Vault (2-of-2) for all agent use cases\n\nAgent holds one key share, VultiServer holds the other\nVultiServer auto-co-signs based on policy rules — no human in the loop\nUse Secure Vault only when multi-device human approval is required\n\n\n\nTypeScript SDK (@vultisig/sdk) as primary interface\n\nnpm install @vultisig/sdk\nSource: github.com/vultisig/vultisig-sdk\nSDK Users Guide: docs/SDK-USERS-GUIDE.md\n\n\n\nMemoryStorage for ephemeral agents, implement Storage interface for persistent agents\n\nMemoryStorage is the only storage exported from the SDK\nFor persistent vaults, implement the Storage interface backed by your preferred store\n\n\n\n3-step transaction flow: prepare → sign → broadcast\n\nNever skip steps. Always prepare the keysign payload first, then sign, then broadcast.\nFast Vault signing is automatic (VultiServer co-signs). Secure Vault requires device coordination.\n\n\n\nAmounts as bigint (smallest unit) for sends, number (human-readable) for swaps\n\nprepareSendTx takes amount: bigint (e.g., BigInt('100000000000000000') for 0.1 ETH)\ngetSwapQuote takes amount: number (e.g., 0.1 for 0.1 ETH)"
      },
      {
        "title": "1. Initialize SDK",
        "body": "import { Vultisig, MemoryStorage } from '@vultisig/sdk';\n\nconst sdk = new Vultisig({ storage: new MemoryStorage() });\nawait sdk.initialize();\n\nSource: Vultisig.ts"
      },
      {
        "title": "2. Create a Fast Vault",
        "body": "Two-step process: create (triggers email verification) then verify.\n\nconst vaultId = await sdk.createFastVault({\n  name: 'my-agent-vault',\n  email: 'agent@example.com',\n  password: 'secure-password',\n});\n\n// Verify with the code sent to the email\nconst vault = await sdk.verifyVault(vaultId, '123456');\n// Returns: FastVault instance — ready for operations\n\nRisk notes:\n\nThe password encrypts the vault share. If lost, the vault cannot be recovered.\nThe email verification code is required — agents must have email access or an email relay."
      },
      {
        "title": "2b. Create a Secure Vault (human co-signing)",
        "body": "When agents need human approval before executing transactions (high-value transfers, treasury ops, compliance flows), use a Secure Vault. The agent holds one share, the human holds the other. The human co-signs via the Vultisig mobile app by scanning a QR code — the transaction only executes when both parties agree.\n\nconst { vault, vaultId, sessionId } = await sdk.createSecureVault({\n  name: 'agent-with-human-approval',\n  onQRCodeReady: (qrPayload) => {\n    // Display QR for the human co-signer to scan with Vultisig app\n    displayQRCode(qrPayload);\n  },\n  onDeviceJoined: (deviceId, total, required) => {\n    console.log(`Device joined: ${total}/${required}`);\n  },\n});\n\nSigning requires the human to participate:\n\nconst signature = await vault.sign(payload, {\n  onQRCodeReady: (qr) => {\n    // Human must scan this QR with Vultisig app to co-sign\n    displayQRCode(qr);\n  },\n  onDeviceJoined: (id, total, required) => {\n    console.log(`Signing: ${total}/${required} devices ready`);\n  },\n});\n// Completes only when the human co-signer participates\n\nSource: SecureVault.ts\n\nWhen to use Secure Vault over Fast Vault:\n\nTransactions above a risk threshold that need human sign-off\nTreasury or DAO operations requiring human approval\nCompliance workflows where an agent should not act unilaterally"
      },
      {
        "title": "3. Get addresses",
        "body": "const ethAddress = await vault.address('Ethereum');\nconst btcAddress = await vault.address('Bitcoin');\nconst solAddress = await vault.address('Solana');\n\n// All addresses at once\nconst allAddresses = await vault.addresses();\n// Returns: Record<string, string>\n\nSource: VaultBase.ts\n\nChain identifiers use PascalCase strings matching the Chain enum: 'Bitcoin', 'Ethereum', 'Solana', 'THORChain', 'Cosmos', 'Polygon', 'Arbitrum', 'Base', 'Optimism', 'Avalanche', 'BSC', etc.\n\nFull chain list: Chain.ts"
      },
      {
        "title": "4. Check balances",
        "body": "// Native chain balance\nconst ethBalance = await vault.balance('Ethereum');\n// Returns Balance: {\n//   amount: string,      // Raw amount in smallest unit\n//   decimals: number,    // Chain decimals (18 for ETH)\n//   symbol: string,      // \"ETH\"\n//   chainId: string,\n//   fiatValue?: number,  // USD value if available\n// }\n\n// Multiple chains\nconst allBalances = await vault.balances();\n// Returns: Record<string, Balance>\n\n// Force refresh (clears cache)\nconst fresh = await vault.updateBalance('Ethereum');\n\nToken balances (ERC-20, SPL, etc.)\n\n// Get a specific token balance by contract address\nconst usdcBalance = await vault.balance('Ethereum', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48');\n// Returns Balance: { amount: \"1000000\", decimals: 6, symbol: \"USDC\", ... }\n\n// Get all token balances on a chain\nconst ethTokens = await vault.tokenBalances('Ethereum');\n// Returns: Token[] — all tokens with non-zero balances\n\n// Include tokens when fetching multi-chain balances\nconst everything = await vault.balances(undefined, true); // includeTokens = true\n\nRisk notes:\n\nNative balance and token balances are separate queries. vault.balance('Ethereum') returns only ETH, not ERC-20s.\nToken balances require the contract address as the tokenId parameter."
      },
      {
        "title": "5. Estimate gas",
        "body": "// Returns chain-specific gas info\nconst evmGas = await vault.gas('Ethereum');\n// EvmGasInfo: { gasPrice, gasPriceGwei, maxFeePerGas, maxPriorityFeePerGas, gasLimit, estimatedCostUSD }\n\nconst utxoGas = await vault.gas('Bitcoin');\n// UtxoGasInfo: { gasPrice, byteFee, estimatedCostUSD }\n\nconst cosmosGas = await vault.gas('Cosmos');\n// CosmosGasInfo: { gasPrice, gas, estimatedCostUSD }\n\nSource: VaultBase.ts — gas<C extends Chain>(chain: C): Promise<GasInfoForChain<C>>"
      },
      {
        "title": "6. Send a transaction",
        "body": "3-step flow: prepareSendTx → sign → broadcastTx\n\n// Step 1: Prepare keysign payload\nconst payload = await vault.prepareSendTx({\n  coin: {\n    chain: 'Ethereum',\n    address: ethAddress,     // Sender address (from vault.address())\n    decimals: 18,\n    ticker: 'ETH',\n  },\n  receiver: '0xRecipientAddress...',\n  amount: BigInt('100000000000000000'), // 0.1 ETH in wei\n  memo: '',                             // Optional\n});\n// Returns: KeysignPayload\n\n// Step 2: Sign (Fast Vault — VultiServer co-signs automatically)\nconst signature = await vault.sign(payload);\n// Returns: Signature { signature: string, recovery?: number, format: 'DER' | 'ECDSA' | 'EdDSA' }\n\n// Step 3: Broadcast\nconst txHash = await vault.broadcastTx({\n  chain: 'Ethereum',\n  keysignPayload: payload,\n  signature: signature,\n});\n// Returns: string (transaction hash)\n\n// Explorer URL\nconst url = Vultisig.getTxExplorerUrl('Ethereum', txHash);\n\nSource: VaultBase.prepareSendTx(), FastVault.sign()\n\nRisk notes:\n\namount is in the chain's smallest unit (wei for ETH, satoshi for BTC). Miscalculating decimals will send wrong amounts.\nAlways verify the receiver address. Transactions are irreversible.\nCheck gas estimation before sending to avoid stuck transactions.\n\nSending ERC-20 / tokens\n\nTo send tokens instead of native currency, add the id field (contract address) to the coin object:\n\n// Send 10 USDC on Ethereum\nconst tokenPayload = await vault.prepareSendTx({\n  coin: {\n    chain: 'Ethereum',\n    address: ethAddress,\n    decimals: 6,            // USDC has 6 decimals\n    ticker: 'USDC',\n    id: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token contract address\n  },\n  receiver: '0xRecipientAddress...',\n  amount: BigInt('10000000'), // 10 USDC (6 decimals)\n});\n\nconst sig = await vault.sign(tokenPayload);\nconst txHash = await vault.broadcastTx({\n  chain: 'Ethereum',\n  keysignPayload: tokenPayload,\n  signature: sig,\n});\n\nRisk notes:\n\nThe id field is the token contract address. Without it, the SDK treats it as a native transfer.\nUse the token's decimals, not the chain's. USDC = 6, WETH = 18, WBTC = 8.\nThe sender still needs native ETH/gas token to pay transaction fees."
      },
      {
        "title": "7. Swap tokens",
        "body": "4-step flow: getSwapQuote → prepareSwapTx → sign → broadcastTx\n\n// Step 1: Get quote\nconst quote = await vault.getSwapQuote({\n  fromCoin: {\n    chain: 'Ethereum',\n    address: ethAddress,\n    decimals: 18,\n    ticker: 'ETH',\n  },\n  toCoin: {\n    chain: 'Ethereum',\n    address: usdcAddress,\n    decimals: 6,\n    ticker: 'USDC',\n    id: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token contract\n  },\n  amount: 0.1, // Human-readable (NOT bigint)\n});\n// Returns: SwapQuoteResult {\n//   provider: string,\n//   estimatedOutput: bigint,\n//   estimatedOutputFiat?: number,\n//   requiresApproval: boolean,\n//   fees: SwapFees,\n//   warnings: string[],\n// }\n\n// Step 2: Prepare swap transaction\nconst swapResult = await vault.prepareSwapTx({\n  fromCoin: quote.fromCoin,\n  toCoin: quote.toCoin,\n  amount: 0.1,\n  swapQuote: quote,\n});\n// Returns: SwapPrepareResult {\n//   keysignPayload: KeysignPayload,\n//   approvalPayload?: KeysignPayload,  // If token approval needed\n//   quote: SwapQuoteResult,\n// }\n\n// Step 2.5: If approval required, sign and broadcast approval first\nif (swapResult.approvalPayload) {\n  const approvalSig = await vault.sign(swapResult.approvalPayload);\n  await vault.broadcastTx({\n    chain: 'Ethereum',\n    keysignPayload: swapResult.approvalPayload,\n    signature: approvalSig,\n  });\n}\n\n// Step 3: Sign swap\nconst swapSig = await vault.sign(swapResult.keysignPayload);\n\n// Step 4: Broadcast swap\nconst swapTxHash = await vault.broadcastTx({\n  chain: 'Ethereum',\n  keysignPayload: swapResult.keysignPayload,\n  signature: swapSig,\n});\n\nSwap providers (auto-routed for best rate):\n\nTHORChain — Native cross-chain (BTC <> ETH, etc.)\nMayaChain — Additional cross-chain pairs\n1inch — EVM DEX aggregation\nLiFi — Cross-chain + cross-DEX\nKyberSwap — EVM DEX aggregation\n\nRisk notes:\n\nSwap amounts use human-readable numbers (0.1), not bigint. The SDK handles decimal conversion.\nCheck quote.warnings before executing — may contain slippage or liquidity warnings.\nERC-20 token swaps may require a separate approval transaction (approvalPayload).\nCross-chain swaps take longer (minutes, not seconds) and have different failure modes."
      },
      {
        "title": "8. Export / Import vault",
        "body": "// Export to encrypted .vult file\nconst { filename, data } = await vault.export('backup-password');\n// filename: string, data: Base64-encoded vault backup\n\n// Import from .vult file\nconst importedVault = await sdk.importVault(data, 'backup-password');"
      },
      {
        "title": "9. Create vault from seedphrase",
        "body": "// Validate BIP39 seedphrase\nconst validation = await sdk.validateSeedphrase('word1 word2 ...');\n// Returns: { valid: boolean, wordCount: number, error?: string }\n\n// Discover which chains have existing balances\nconst discovery = await sdk.discoverChainsFromSeedphrase('word1 word2 ...');\n// Returns: ChainDiscoveryAggregate\n\n// Create Fast Vault from seedphrase (still needs email verification)\nconst vaultId = await sdk.createFastVaultFromSeedphrase({\n  name: 'imported-vault',\n  email: 'agent@example.com',\n  password: 'secure-password',\n  mnemonic: 'word1 word2 ...',\n});\nconst vault = await sdk.verifyVault(vaultId, 'email-code');\n\nRisk notes:\n\nSeedphrase import creates a new TSS vault from the seed — the original seed-based wallet still exists independently.\nHandle seedphrases with extreme care. Never log, store in plaintext, or transmit unencrypted."
      },
      {
        "title": "10. Vault lifecycle management",
        "body": "// List all vaults\nconst vaults = await sdk.listVaults();\n\n// Set active vault\nawait sdk.setActiveVault(vault);\n\n// Get active vault\nconst active = await sdk.getActiveVault();\n\n// Check vault type\nif (Vultisig.isFastVault(vault)) { /* FastVault methods */ }\nif (Vultisig.isSecureVault(vault)) { /* SecureVault methods */ }\n\n// Delete vault\nawait sdk.deleteVault(vault);"
      },
      {
        "title": "11. Check transaction status",
        "body": "After broadcasting, use the explorer URL or chain-specific methods to confirm transactions:\n\n// Get explorer URL for any chain\nconst explorerUrl = Vultisig.getTxExplorerUrl('Ethereum', txHash);\n// e.g., \"https://etherscan.io/tx/0x...\"\n\nconst addressUrl = Vultisig.getAddressExplorerUrl('Bitcoin', btcAddress);\n// e.g., \"https://mempool.space/address/bc1...\"\n\nFor automated strategies that need to confirm completion before the next action, poll the balance or use an external RPC/indexer to check transaction finality. The SDK does not provide a built-in tx status poller — use vault.updateBalance() to force-refresh after a broadcast and compare before/after.\n\n// Pattern: confirm send completed\nconst balanceBefore = await vault.balance('Ethereum');\n// ... broadcast transaction ...\nawait new Promise(r => setTimeout(r, 15000)); // Wait for block confirmation\nconst balanceAfter = await vault.updateBalance('Ethereum');\n// Compare balanceBefore.amount vs balanceAfter.amount"
      },
      {
        "title": "12. Address book",
        "body": "Manage recurring recipients for automated transfers:\n\n// Get saved addresses (optionally filter by chain)\nconst allContacts = await sdk.getAddressBook();\nconst ethContacts = await sdk.getAddressBook('Ethereum');\n\n// Add entries\nawait sdk.addAddressBookEntry([\n  { chain: 'Ethereum', address: '0x...', name: 'Treasury' },\n  { chain: 'Bitcoin', address: 'bc1...', name: 'Cold Storage' },\n]);\n\n// Update a name\nawait sdk.updateAddressBookEntry('Ethereum', '0x...', 'Main Treasury');\n\n// Remove entries\nawait sdk.removeAddressBookEntry([\n  { chain: 'Ethereum', address: '0x...' },\n]);\n\nSource: Vultisig.ts"
      },
      {
        "title": "13. $VULT discount tiers",
        "body": "Holding $VULT tokens reduces swap fees (up to 50%). The SDK can check and update the agent's discount tier:\n\n// Check current discount tier\nconst tier = await vault.getDiscountTier();\n// Returns: string | null — e.g., \"gold\", \"silver\", or null if no discount\n\n// Update tier (after acquiring more $VULT)\nconst newTier = await vault.updateDiscountTier();\n\nToken contract: 0xb788144DF611029C60b859DF47e79B7726C4DEBa (Ethereum)"
      },
      {
        "title": "14. Listen to events",
        "body": "// SDK-level events\nsdk.on('vaultCreationProgress', (data) => { /* keygen progress */ });\nsdk.on('vaultCreationComplete', (data) => { /* vault ready */ });\nsdk.on('vaultChanged', (data) => { /* active vault switched */ });\n\n// Vault-level events\nvault.on('balanceUpdated', (data) => { /* balance changed */ });\nvault.on('transactionSigned', (data) => { /* signature complete */ });\nvault.on('transactionBroadcast', (data) => { /* tx submitted */ });\nvault.on('signingProgress', (data) => { /* signing steps */ });\nvault.on('swapQuoteReceived', (data) => { /* quote ready */ });\n\n// SecureVault only (multi-device coordination)\nvault.on('qrCodeReady', (data) => { /* show QR for device pairing */ });\nvault.on('deviceJoined', (data) => { /* co-signer connected */ });\nvault.on('allDevicesReady', (data) => { /* threshold met, signing can proceed */ });\n\n// Error handling\nvault.on('error', (error) => { /* handle errors */ });\nsdk.on('error', (error) => { /* handle SDK-level errors */ });\n\nSource: packages/sdk/src/events/"
      },
      {
        "title": "Supported chains",
        "body": "Source: Chain.ts\n\nCategoryChainsSignatureUTXOBitcoin, Litecoin, Dogecoin, Bitcoin Cash, Dash, ZcashECDSAEVMEthereum, BSC, Polygon, Avalanche, Arbitrum, Optimism, Base, Blast, Cronos, zkSync, Hyperliquid, Mantle, SeiECDSACosmos/IBCTHORChain, MayaChain, Cosmos Hub, Osmosis, Dydx, Kujira, Noble, Terra, Terra Classic, AkashECDSAOtherSolana, Sui, Polkadot, TON, Ripple, Tron, CardanoEdDSA / Mixed"
      },
      {
        "title": "Security model",
        "body": "No seed phrases — vault shares replace 12/24 word seeds\nNo single point of failure — no device holds a complete private key\nNo on-chain key registration — unlike multi-sig wallets\nDKLS23 protocol — 3-round TSS, co-developed with Silence Laboratories\nOpen source and audited\nDocs: Security & Technology"
      },
      {
        "title": "CLI alternative",
        "body": "npm install -g @vultisig/sdk\n\nvsig vault create --name agent-vault --type fast\nvsig balance --chain Ethereum\nvsig send --chain Ethereum --to 0x... --amount 0.1\nvsig swap --from ETH --to USDC --amount 0.1\n\nSource: clients/cli/"
      },
      {
        "title": "Progressive disclosure",
        "body": "SDK Users Guide — Complete API walkthrough\nArchitecture — SDK internals, data flow, design patterns\nAgent Integration Guide — Agent-specific patterns and best practices\nFast Vault Docs — How VultiServer co-signing works\nMarketplace Plugin Guide — Build automation plugins\nllms.txt — Concise link index for web-browsing agents\nllms-full.txt — Extended context with examples"
      }
    ],
    "body": "Vultisig SDK Skill (agent-first)\nWhat this Skill is for\nCreating and managing self-custodial crypto vaults (Fast Vault for agents, Secure Vault for multi-device)\nSending transactions across 36+ blockchains (Bitcoin, Ethereum, Solana, Cosmos, and more)\nSwapping tokens cross-chain via THORChain, MayaChain, 1inch, LiFi, KyberSwap\nQuerying balances and gas fees across all supported chains\nImporting/exporting vault backups (.vult files)\nImporting existing wallets via BIP39 seedphrase\nBuilding automated strategies: DCA, rebalancing, conditional swaps, agent-to-agent payments\nDefault stack decisions\n\nFast Vault (2-of-2) for all agent use cases\n\nAgent holds one key share, VultiServer holds the other\nVultiServer auto-co-signs based on policy rules — no human in the loop\nUse Secure Vault only when multi-device human approval is required\n\nTypeScript SDK (@vultisig/sdk) as primary interface\n\nnpm install @vultisig/sdk\nSource: github.com/vultisig/vultisig-sdk\nSDK Users Guide: docs/SDK-USERS-GUIDE.md\n\nMemoryStorage for ephemeral agents, implement Storage interface for persistent agents\n\nMemoryStorage is the only storage exported from the SDK\nFor persistent vaults, implement the Storage interface backed by your preferred store\n\n3-step transaction flow: prepare → sign → broadcast\n\nNever skip steps. Always prepare the keysign payload first, then sign, then broadcast.\nFast Vault signing is automatic (VultiServer co-signs). Secure Vault requires device coordination.\n\nAmounts as bigint (smallest unit) for sends, number (human-readable) for swaps\n\nprepareSendTx takes amount: bigint (e.g., BigInt('100000000000000000') for 0.1 ETH)\ngetSwapQuote takes amount: number (e.g., 0.1 for 0.1 ETH)\nOperating procedure\n1. Initialize SDK\nimport { Vultisig, MemoryStorage } from '@vultisig/sdk';\n\nconst sdk = new Vultisig({ storage: new MemoryStorage() });\nawait sdk.initialize();\n\n\nSource: Vultisig.ts\n\n2. Create a Fast Vault\n\nTwo-step process: create (triggers email verification) then verify.\n\nconst vaultId = await sdk.createFastVault({\n  name: 'my-agent-vault',\n  email: 'agent@example.com',\n  password: 'secure-password',\n});\n\n// Verify with the code sent to the email\nconst vault = await sdk.verifyVault(vaultId, '123456');\n// Returns: FastVault instance — ready for operations\n\n\nRisk notes:\n\nThe password encrypts the vault share. If lost, the vault cannot be recovered.\nThe email verification code is required — agents must have email access or an email relay.\n2b. Create a Secure Vault (human co-signing)\n\nWhen agents need human approval before executing transactions (high-value transfers, treasury ops, compliance flows), use a Secure Vault. The agent holds one share, the human holds the other. The human co-signs via the Vultisig mobile app by scanning a QR code — the transaction only executes when both parties agree.\n\nconst { vault, vaultId, sessionId } = await sdk.createSecureVault({\n  name: 'agent-with-human-approval',\n  onQRCodeReady: (qrPayload) => {\n    // Display QR for the human co-signer to scan with Vultisig app\n    displayQRCode(qrPayload);\n  },\n  onDeviceJoined: (deviceId, total, required) => {\n    console.log(`Device joined: ${total}/${required}`);\n  },\n});\n\n\nSigning requires the human to participate:\n\nconst signature = await vault.sign(payload, {\n  onQRCodeReady: (qr) => {\n    // Human must scan this QR with Vultisig app to co-sign\n    displayQRCode(qr);\n  },\n  onDeviceJoined: (id, total, required) => {\n    console.log(`Signing: ${total}/${required} devices ready`);\n  },\n});\n// Completes only when the human co-signer participates\n\n\nSource: SecureVault.ts\n\nWhen to use Secure Vault over Fast Vault:\n\nTransactions above a risk threshold that need human sign-off\nTreasury or DAO operations requiring human approval\nCompliance workflows where an agent should not act unilaterally\n3. Get addresses\nconst ethAddress = await vault.address('Ethereum');\nconst btcAddress = await vault.address('Bitcoin');\nconst solAddress = await vault.address('Solana');\n\n// All addresses at once\nconst allAddresses = await vault.addresses();\n// Returns: Record<string, string>\n\n\nSource: VaultBase.ts\n\nChain identifiers use PascalCase strings matching the Chain enum: 'Bitcoin', 'Ethereum', 'Solana', 'THORChain', 'Cosmos', 'Polygon', 'Arbitrum', 'Base', 'Optimism', 'Avalanche', 'BSC', etc.\n\nFull chain list: Chain.ts\n\n4. Check balances\n// Native chain balance\nconst ethBalance = await vault.balance('Ethereum');\n// Returns Balance: {\n//   amount: string,      // Raw amount in smallest unit\n//   decimals: number,    // Chain decimals (18 for ETH)\n//   symbol: string,      // \"ETH\"\n//   chainId: string,\n//   fiatValue?: number,  // USD value if available\n// }\n\n// Multiple chains\nconst allBalances = await vault.balances();\n// Returns: Record<string, Balance>\n\n// Force refresh (clears cache)\nconst fresh = await vault.updateBalance('Ethereum');\n\nToken balances (ERC-20, SPL, etc.)\n// Get a specific token balance by contract address\nconst usdcBalance = await vault.balance('Ethereum', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48');\n// Returns Balance: { amount: \"1000000\", decimals: 6, symbol: \"USDC\", ... }\n\n// Get all token balances on a chain\nconst ethTokens = await vault.tokenBalances('Ethereum');\n// Returns: Token[] — all tokens with non-zero balances\n\n// Include tokens when fetching multi-chain balances\nconst everything = await vault.balances(undefined, true); // includeTokens = true\n\n\nRisk notes:\n\nNative balance and token balances are separate queries. vault.balance('Ethereum') returns only ETH, not ERC-20s.\nToken balances require the contract address as the tokenId parameter.\n5. Estimate gas\n// Returns chain-specific gas info\nconst evmGas = await vault.gas('Ethereum');\n// EvmGasInfo: { gasPrice, gasPriceGwei, maxFeePerGas, maxPriorityFeePerGas, gasLimit, estimatedCostUSD }\n\nconst utxoGas = await vault.gas('Bitcoin');\n// UtxoGasInfo: { gasPrice, byteFee, estimatedCostUSD }\n\nconst cosmosGas = await vault.gas('Cosmos');\n// CosmosGasInfo: { gasPrice, gas, estimatedCostUSD }\n\n\nSource: VaultBase.ts — gas<C extends Chain>(chain: C): Promise<GasInfoForChain<C>>\n\n6. Send a transaction\n\n3-step flow: prepareSendTx → sign → broadcastTx\n\n// Step 1: Prepare keysign payload\nconst payload = await vault.prepareSendTx({\n  coin: {\n    chain: 'Ethereum',\n    address: ethAddress,     // Sender address (from vault.address())\n    decimals: 18,\n    ticker: 'ETH',\n  },\n  receiver: '0xRecipientAddress...',\n  amount: BigInt('100000000000000000'), // 0.1 ETH in wei\n  memo: '',                             // Optional\n});\n// Returns: KeysignPayload\n\n// Step 2: Sign (Fast Vault — VultiServer co-signs automatically)\nconst signature = await vault.sign(payload);\n// Returns: Signature { signature: string, recovery?: number, format: 'DER' | 'ECDSA' | 'EdDSA' }\n\n// Step 3: Broadcast\nconst txHash = await vault.broadcastTx({\n  chain: 'Ethereum',\n  keysignPayload: payload,\n  signature: signature,\n});\n// Returns: string (transaction hash)\n\n// Explorer URL\nconst url = Vultisig.getTxExplorerUrl('Ethereum', txHash);\n\n\nSource: VaultBase.prepareSendTx(), FastVault.sign()\n\nRisk notes:\n\namount is in the chain's smallest unit (wei for ETH, satoshi for BTC). Miscalculating decimals will send wrong amounts.\nAlways verify the receiver address. Transactions are irreversible.\nCheck gas estimation before sending to avoid stuck transactions.\nSending ERC-20 / tokens\n\nTo send tokens instead of native currency, add the id field (contract address) to the coin object:\n\n// Send 10 USDC on Ethereum\nconst tokenPayload = await vault.prepareSendTx({\n  coin: {\n    chain: 'Ethereum',\n    address: ethAddress,\n    decimals: 6,            // USDC has 6 decimals\n    ticker: 'USDC',\n    id: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token contract address\n  },\n  receiver: '0xRecipientAddress...',\n  amount: BigInt('10000000'), // 10 USDC (6 decimals)\n});\n\nconst sig = await vault.sign(tokenPayload);\nconst txHash = await vault.broadcastTx({\n  chain: 'Ethereum',\n  keysignPayload: tokenPayload,\n  signature: sig,\n});\n\n\nRisk notes:\n\nThe id field is the token contract address. Without it, the SDK treats it as a native transfer.\nUse the token's decimals, not the chain's. USDC = 6, WETH = 18, WBTC = 8.\nThe sender still needs native ETH/gas token to pay transaction fees.\n7. Swap tokens\n\n4-step flow: getSwapQuote → prepareSwapTx → sign → broadcastTx\n\n// Step 1: Get quote\nconst quote = await vault.getSwapQuote({\n  fromCoin: {\n    chain: 'Ethereum',\n    address: ethAddress,\n    decimals: 18,\n    ticker: 'ETH',\n  },\n  toCoin: {\n    chain: 'Ethereum',\n    address: usdcAddress,\n    decimals: 6,\n    ticker: 'USDC',\n    id: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token contract\n  },\n  amount: 0.1, // Human-readable (NOT bigint)\n});\n// Returns: SwapQuoteResult {\n//   provider: string,\n//   estimatedOutput: bigint,\n//   estimatedOutputFiat?: number,\n//   requiresApproval: boolean,\n//   fees: SwapFees,\n//   warnings: string[],\n// }\n\n// Step 2: Prepare swap transaction\nconst swapResult = await vault.prepareSwapTx({\n  fromCoin: quote.fromCoin,\n  toCoin: quote.toCoin,\n  amount: 0.1,\n  swapQuote: quote,\n});\n// Returns: SwapPrepareResult {\n//   keysignPayload: KeysignPayload,\n//   approvalPayload?: KeysignPayload,  // If token approval needed\n//   quote: SwapQuoteResult,\n// }\n\n// Step 2.5: If approval required, sign and broadcast approval first\nif (swapResult.approvalPayload) {\n  const approvalSig = await vault.sign(swapResult.approvalPayload);\n  await vault.broadcastTx({\n    chain: 'Ethereum',\n    keysignPayload: swapResult.approvalPayload,\n    signature: approvalSig,\n  });\n}\n\n// Step 3: Sign swap\nconst swapSig = await vault.sign(swapResult.keysignPayload);\n\n// Step 4: Broadcast swap\nconst swapTxHash = await vault.broadcastTx({\n  chain: 'Ethereum',\n  keysignPayload: swapResult.keysignPayload,\n  signature: swapSig,\n});\n\n\nSwap providers (auto-routed for best rate):\n\nTHORChain — Native cross-chain (BTC <> ETH, etc.)\nMayaChain — Additional cross-chain pairs\n1inch — EVM DEX aggregation\nLiFi — Cross-chain + cross-DEX\nKyberSwap — EVM DEX aggregation\n\nRisk notes:\n\nSwap amounts use human-readable numbers (0.1), not bigint. The SDK handles decimal conversion.\nCheck quote.warnings before executing — may contain slippage or liquidity warnings.\nERC-20 token swaps may require a separate approval transaction (approvalPayload).\nCross-chain swaps take longer (minutes, not seconds) and have different failure modes.\n8. Export / Import vault\n// Export to encrypted .vult file\nconst { filename, data } = await vault.export('backup-password');\n// filename: string, data: Base64-encoded vault backup\n\n// Import from .vult file\nconst importedVault = await sdk.importVault(data, 'backup-password');\n\n9. Create vault from seedphrase\n// Validate BIP39 seedphrase\nconst validation = await sdk.validateSeedphrase('word1 word2 ...');\n// Returns: { valid: boolean, wordCount: number, error?: string }\n\n// Discover which chains have existing balances\nconst discovery = await sdk.discoverChainsFromSeedphrase('word1 word2 ...');\n// Returns: ChainDiscoveryAggregate\n\n// Create Fast Vault from seedphrase (still needs email verification)\nconst vaultId = await sdk.createFastVaultFromSeedphrase({\n  name: 'imported-vault',\n  email: 'agent@example.com',\n  password: 'secure-password',\n  mnemonic: 'word1 word2 ...',\n});\nconst vault = await sdk.verifyVault(vaultId, 'email-code');\n\n\nRisk notes:\n\nSeedphrase import creates a new TSS vault from the seed — the original seed-based wallet still exists independently.\nHandle seedphrases with extreme care. Never log, store in plaintext, or transmit unencrypted.\n10. Vault lifecycle management\n// List all vaults\nconst vaults = await sdk.listVaults();\n\n// Set active vault\nawait sdk.setActiveVault(vault);\n\n// Get active vault\nconst active = await sdk.getActiveVault();\n\n// Check vault type\nif (Vultisig.isFastVault(vault)) { /* FastVault methods */ }\nif (Vultisig.isSecureVault(vault)) { /* SecureVault methods */ }\n\n// Delete vault\nawait sdk.deleteVault(vault);\n\n11. Check transaction status\n\nAfter broadcasting, use the explorer URL or chain-specific methods to confirm transactions:\n\n// Get explorer URL for any chain\nconst explorerUrl = Vultisig.getTxExplorerUrl('Ethereum', txHash);\n// e.g., \"https://etherscan.io/tx/0x...\"\n\nconst addressUrl = Vultisig.getAddressExplorerUrl('Bitcoin', btcAddress);\n// e.g., \"https://mempool.space/address/bc1...\"\n\n\nFor automated strategies that need to confirm completion before the next action, poll the balance or use an external RPC/indexer to check transaction finality. The SDK does not provide a built-in tx status poller — use vault.updateBalance() to force-refresh after a broadcast and compare before/after.\n\n// Pattern: confirm send completed\nconst balanceBefore = await vault.balance('Ethereum');\n// ... broadcast transaction ...\nawait new Promise(r => setTimeout(r, 15000)); // Wait for block confirmation\nconst balanceAfter = await vault.updateBalance('Ethereum');\n// Compare balanceBefore.amount vs balanceAfter.amount\n\n12. Address book\n\nManage recurring recipients for automated transfers:\n\n// Get saved addresses (optionally filter by chain)\nconst allContacts = await sdk.getAddressBook();\nconst ethContacts = await sdk.getAddressBook('Ethereum');\n\n// Add entries\nawait sdk.addAddressBookEntry([\n  { chain: 'Ethereum', address: '0x...', name: 'Treasury' },\n  { chain: 'Bitcoin', address: 'bc1...', name: 'Cold Storage' },\n]);\n\n// Update a name\nawait sdk.updateAddressBookEntry('Ethereum', '0x...', 'Main Treasury');\n\n// Remove entries\nawait sdk.removeAddressBookEntry([\n  { chain: 'Ethereum', address: '0x...' },\n]);\n\n\nSource: Vultisig.ts\n\n13. $VULT discount tiers\n\nHolding $VULT tokens reduces swap fees (up to 50%). The SDK can check and update the agent's discount tier:\n\n// Check current discount tier\nconst tier = await vault.getDiscountTier();\n// Returns: string | null — e.g., \"gold\", \"silver\", or null if no discount\n\n// Update tier (after acquiring more $VULT)\nconst newTier = await vault.updateDiscountTier();\n\n\nToken contract: 0xb788144DF611029C60b859DF47e79B7726C4DEBa (Ethereum)\n\n14. Listen to events\n// SDK-level events\nsdk.on('vaultCreationProgress', (data) => { /* keygen progress */ });\nsdk.on('vaultCreationComplete', (data) => { /* vault ready */ });\nsdk.on('vaultChanged', (data) => { /* active vault switched */ });\n\n// Vault-level events\nvault.on('balanceUpdated', (data) => { /* balance changed */ });\nvault.on('transactionSigned', (data) => { /* signature complete */ });\nvault.on('transactionBroadcast', (data) => { /* tx submitted */ });\nvault.on('signingProgress', (data) => { /* signing steps */ });\nvault.on('swapQuoteReceived', (data) => { /* quote ready */ });\n\n// SecureVault only (multi-device coordination)\nvault.on('qrCodeReady', (data) => { /* show QR for device pairing */ });\nvault.on('deviceJoined', (data) => { /* co-signer connected */ });\nvault.on('allDevicesReady', (data) => { /* threshold met, signing can proceed */ });\n\n// Error handling\nvault.on('error', (error) => { /* handle errors */ });\nsdk.on('error', (error) => { /* handle SDK-level errors */ });\n\n\nSource: packages/sdk/src/events/\n\nSupported chains\n\nSource: Chain.ts\n\nCategory\tChains\tSignature\nUTXO\tBitcoin, Litecoin, Dogecoin, Bitcoin Cash, Dash, Zcash\tECDSA\nEVM\tEthereum, BSC, Polygon, Avalanche, Arbitrum, Optimism, Base, Blast, Cronos, zkSync, Hyperliquid, Mantle, Sei\tECDSA\nCosmos/IBC\tTHORChain, MayaChain, Cosmos Hub, Osmosis, Dydx, Kujira, Noble, Terra, Terra Classic, Akash\tECDSA\nOther\tSolana, Sui, Polkadot, TON, Ripple, Tron, Cardano\tEdDSA / Mixed\nSecurity model\nNo seed phrases — vault shares replace 12/24 word seeds\nNo single point of failure — no device holds a complete private key\nNo on-chain key registration — unlike multi-sig wallets\nDKLS23 protocol — 3-round TSS, co-developed with Silence Laboratories\nOpen source and audited\nDocs: Security & Technology\nCLI alternative\nnpm install -g @vultisig/sdk\n\nvsig vault create --name agent-vault --type fast\nvsig balance --chain Ethereum\nvsig send --chain Ethereum --to 0x... --amount 0.1\nvsig swap --from ETH --to USDC --amount 0.1\n\n\nSource: clients/cli/\n\nProgressive disclosure\nSDK Users Guide — Complete API walkthrough\nArchitecture — SDK internals, data flow, design patterns\nAgent Integration Guide — Agent-specific patterns and best practices\nFast Vault Docs — How VultiServer co-signing works\nMarketplace Plugin Guide — Build automation plugins\nllms.txt — Concise link index for web-browsing agents\nllms-full.txt — Extended context with examples"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/realpaaao/vultisig-sdk",
    "publisherUrl": "https://clawhub.ai/realpaaao/vultisig-sdk",
    "owner": "realpaaao",
    "version": "0.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/vultisig-sdk",
    "downloadUrl": "https://openagent3.xyz/downloads/vultisig-sdk",
    "agentUrl": "https://openagent3.xyz/skills/vultisig-sdk/agent",
    "manifestUrl": "https://openagent3.xyz/skills/vultisig-sdk/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/vultisig-sdk/agent.md"
  }
}