🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

vultisig-sdk

by @realpaaao

Use this skill when an agent needs to create crypto wallets, send transactions, swap tokens, check balances, or perform any on-chain operation across 36+ blockchains using threshold signatures (TSS). Vultisig SDK provides self-custodial MPC vaults β€” no seed phrases, no single point of failure. Fast Vaults (2-of-2 with VultiServer) enable fully autonomous agent operations without human approval.

Versionv0.1.0
Downloads2,402
Stars⭐ 2
TERMINAL
clawhub install vultisig-sdk

πŸ“– About This Skill


name: vultisig description: Use this skill when an agent needs to create crypto wallets, send transactions, swap tokens, check balances, or perform any on-chain operation across 36+ blockchains using threshold signatures (TSS). Vultisig SDK provides self-custodial MPC vaults β€” no seed phrases, no single point of failure. Fast Vaults (2-of-2 with VultiServer) enable fully autonomous agent operations without human approval. user-invocable: true

Vultisig SDK Skill (agent-first)

What this Skill is for

  • Creating and managing self-custodial crypto vaults (Fast Vault for agents, Secure Vault for multi-device)
  • Sending transactions across 36+ blockchains (Bitcoin, Ethereum, Solana, Cosmos, and more)
  • Swapping tokens cross-chain via THORChain, MayaChain, 1inch, LiFi, KyberSwap
  • Querying balances and gas fees across all supported chains
  • Importing/exporting vault backups (.vult files)
  • Importing existing wallets via BIP39 seedphrase
  • Building automated strategies: DCA, rebalancing, conditional swaps, agent-to-agent payments
  • Default stack decisions

    1) Fast Vault (2-of-2) for all agent use cases - Agent holds one key share, VultiServer holds the other - VultiServer auto-co-signs based on policy rules β€” no human in the loop - Use Secure Vault only when multi-device human approval is required

    2) TypeScript SDK (@vultisig/sdk) as primary interface - npm install @vultisig/sdk - Source: github.com/vultisig/vultisig-sdk - SDK Users Guide: docs/SDK-USERS-GUIDE.md

    3) MemoryStorage for ephemeral agents, implement Storage interface for persistent agents - MemoryStorage is the only storage exported from the SDK - For persistent vaults, implement the Storage interface backed by your preferred store

    4) 3-step transaction flow: prepare β†’ sign β†’ broadcast - Never skip steps. Always prepare the keysign payload first, then sign, then broadcast. - Fast Vault signing is automatic (VultiServer co-signs). Secure Vault requires device coordination.

    5) Amounts as bigint (smallest unit) for sends, number (human-readable) for swaps - prepareSendTx takes amount: bigint (e.g., BigInt('100000000000000000') for 0.1 ETH) - getSwapQuote takes amount: number (e.g., 0.1 for 0.1 ETH)

    Operating procedure

    1. Initialize SDK

    import { Vultisig, MemoryStorage } from '@vultisig/sdk';

    const sdk = new Vultisig({ storage: new MemoryStorage() }); await sdk.initialize();

    > Source: Vultisig.ts

    2. Create a Fast Vault

    Two-step process: create (triggers email verification) then verify.

    const vaultId = await sdk.createFastVault({
      name: 'my-agent-vault',
      email: 'agent@example.com',
      password: 'secure-password',
    });

    // Verify with the code sent to the email const vault = await sdk.verifyVault(vaultId, '123456'); // Returns: FastVault instance β€” ready for operations

    Risk notes:

  • The password encrypts the vault share. If lost, the vault cannot be recovered.
  • The email verification code is required β€” agents must have email access or an email relay.
  • 2b. Create a Secure Vault (human co-signing)

    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.

    const { vault, vaultId, sessionId } = await sdk.createSecureVault({
      name: 'agent-with-human-approval',
      onQRCodeReady: (qrPayload) => {
        // Display QR for the human co-signer to scan with Vultisig app
        displayQRCode(qrPayload);
      },
      onDeviceJoined: (deviceId, total, required) => {
        console.log(Device joined: ${total}/${required});
      },
    });
    

    Signing requires the human to participate:

    const signature = await vault.sign(payload, {
      onQRCodeReady: (qr) => {
        // Human must scan this QR with Vultisig app to co-sign
        displayQRCode(qr);
      },
      onDeviceJoined: (id, total, required) => {
        console.log(Signing: ${total}/${required} devices ready);
      },
    });
    // Completes only when the human co-signer participates
    

    > Source: SecureVault.ts

    When to use Secure Vault over Fast Vault:

  • Transactions above a risk threshold that need human sign-off
  • Treasury or DAO operations requiring human approval
  • Compliance workflows where an agent should not act unilaterally
  • 3. Get addresses

    const ethAddress = await vault.address('Ethereum');
    const btcAddress = await vault.address('Bitcoin');
    const solAddress = await vault.address('Solana');

    // All addresses at once const allAddresses = await vault.addresses(); // Returns: Record

    > Source: VaultBase.ts

    Chain identifiers use PascalCase strings matching the Chain enum: 'Bitcoin', 'Ethereum', 'Solana', 'THORChain', 'Cosmos', 'Polygon', 'Arbitrum', 'Base', 'Optimism', 'Avalanche', 'BSC', etc.

    > Full chain list: Chain.ts

    4. Check balances

    // Native chain balance
    const ethBalance = await vault.balance('Ethereum');
    // Returns Balance: {
    //   amount: string,      // Raw amount in smallest unit
    //   decimals: number,    // Chain decimals (18 for ETH)
    //   symbol: string,      // "ETH"
    //   chainId: string,
    //   fiatValue?: number,  // USD value if available
    // }

    // Multiple chains const allBalances = await vault.balances(); // Returns: Record

    // Force refresh (clears cache) const fresh = await vault.updateBalance('Ethereum');

    #### Token balances (ERC-20, SPL, etc.)

    // Get a specific token balance by contract address
    const usdcBalance = await vault.balance('Ethereum', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48');
    // Returns Balance: { amount: "1000000", decimals: 6, symbol: "USDC", ... }

    // Get all token balances on a chain const ethTokens = await vault.tokenBalances('Ethereum'); // Returns: Token[] β€” all tokens with non-zero balances

    // Include tokens when fetching multi-chain balances const everything = await vault.balances(undefined, true); // includeTokens = true

    Risk notes:

  • Native balance and token balances are separate queries. vault.balance('Ethereum') returns only ETH, not ERC-20s.
  • Token balances require the contract address as the tokenId parameter.
  • 5. Estimate gas

    // Returns chain-specific gas info
    const evmGas = await vault.gas('Ethereum');
    // EvmGasInfo: { gasPrice, gasPriceGwei, maxFeePerGas, maxPriorityFeePerGas, gasLimit, estimatedCostUSD }

    const utxoGas = await vault.gas('Bitcoin'); // UtxoGasInfo: { gasPrice, byteFee, estimatedCostUSD }

    const cosmosGas = await vault.gas('Cosmos'); // CosmosGasInfo: { gasPrice, gas, estimatedCostUSD }

    > Source: VaultBase.ts β€” gas(chain: C): Promise>

    6. Send a transaction

    3-step flow: prepareSendTx β†’ sign β†’ broadcastTx

    // Step 1: Prepare keysign payload
    const payload = await vault.prepareSendTx({
      coin: {
        chain: 'Ethereum',
        address: ethAddress,     // Sender address (from vault.address())
        decimals: 18,
        ticker: 'ETH',
      },
      receiver: '0xRecipientAddress...',
      amount: BigInt('100000000000000000'), // 0.1 ETH in wei
      memo: '',                             // Optional
    });
    // Returns: KeysignPayload

    // Step 2: Sign (Fast Vault β€” VultiServer co-signs automatically) const signature = await vault.sign(payload); // Returns: Signature { signature: string, recovery?: number, format: 'DER' | 'ECDSA' | 'EdDSA' }

    // Step 3: Broadcast const txHash = await vault.broadcastTx({ chain: 'Ethereum', keysignPayload: payload, signature: signature, }); // Returns: string (transaction hash)

    // Explorer URL const url = Vultisig.getTxExplorerUrl('Ethereum', txHash);

    > Source: VaultBase.prepareSendTx(), FastVault.sign()

    Risk notes:

  • amount is in the chain's smallest unit (wei for ETH, satoshi for BTC). Miscalculating decimals will send wrong amounts.
  • Always verify the receiver address. Transactions are irreversible.
  • Check gas estimation before sending to avoid stuck transactions.
  • #### Sending ERC-20 / tokens

    To send tokens instead of native currency, add the id field (contract address) to the coin object:

    // Send 10 USDC on Ethereum
    const tokenPayload = await vault.prepareSendTx({
      coin: {
        chain: 'Ethereum',
        address: ethAddress,
        decimals: 6,            // USDC has 6 decimals
        ticker: 'USDC',
        id: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token contract address
      },
      receiver: '0xRecipientAddress...',
      amount: BigInt('10000000'), // 10 USDC (6 decimals)
    });

    const sig = await vault.sign(tokenPayload); const txHash = await vault.broadcastTx({ chain: 'Ethereum', keysignPayload: tokenPayload, signature: sig, });

    Risk notes:

  • The id field is the token contract address. Without it, the SDK treats it as a native transfer.
  • Use the token's decimals, not the chain's. USDC = 6, WETH = 18, WBTC = 8.
  • The sender still needs native ETH/gas token to pay transaction fees.
  • 7. Swap tokens

    4-step flow: getSwapQuote β†’ prepareSwapTx β†’ sign β†’ broadcastTx

    // Step 1: Get quote
    const quote = await vault.getSwapQuote({
      fromCoin: {
        chain: 'Ethereum',
        address: ethAddress,
        decimals: 18,
        ticker: 'ETH',
      },
      toCoin: {
        chain: 'Ethereum',
        address: usdcAddress,
        decimals: 6,
        ticker: 'USDC',
        id: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token contract
      },
      amount: 0.1, // Human-readable (NOT bigint)
    });
    // Returns: SwapQuoteResult {
    //   provider: string,
    //   estimatedOutput: bigint,
    //   estimatedOutputFiat?: number,
    //   requiresApproval: boolean,
    //   fees: SwapFees,
    //   warnings: string[],
    // }

    // Step 2: Prepare swap transaction const swapResult = await vault.prepareSwapTx({ fromCoin: quote.fromCoin, toCoin: quote.toCoin, amount: 0.1, swapQuote: quote, }); // Returns: SwapPrepareResult { // keysignPayload: KeysignPayload, // approvalPayload?: KeysignPayload, // If token approval needed // quote: SwapQuoteResult, // }

    // Step 2.5: If approval required, sign and broadcast approval first if (swapResult.approvalPayload) { const approvalSig = await vault.sign(swapResult.approvalPayload); await vault.broadcastTx({ chain: 'Ethereum', keysignPayload: swapResult.approvalPayload, signature: approvalSig, }); }

    // Step 3: Sign swap const swapSig = await vault.sign(swapResult.keysignPayload);

    // Step 4: Broadcast swap const swapTxHash = await vault.broadcastTx({ chain: 'Ethereum', keysignPayload: swapResult.keysignPayload, signature: swapSig, });

    Swap providers (auto-routed for best rate):

  • THORChain β€” Native cross-chain (BTC <> ETH, etc.)
  • MayaChain β€” Additional cross-chain pairs
  • 1inch β€” EVM DEX aggregation
  • LiFi β€” Cross-chain + cross-DEX
  • KyberSwap β€” EVM DEX aggregation
  • Risk notes:

  • Swap amounts use human-readable numbers (0.1), not bigint. The SDK handles decimal conversion.
  • Check quote.warnings before executing β€” may contain slippage or liquidity warnings.
  • ERC-20 token swaps may require a separate approval transaction (approvalPayload).
  • Cross-chain swaps take longer (minutes, not seconds) and have different failure modes.
  • 8. Export / Import vault

    // Export to encrypted .vult file
    const { filename, data } = await vault.export('backup-password');
    // filename: string, data: Base64-encoded vault backup

    // Import from .vult file const importedVault = await sdk.importVault(data, 'backup-password');

    9. Create vault from seedphrase

    // Validate BIP39 seedphrase
    const validation = await sdk.validateSeedphrase('word1 word2 ...');
    // Returns: { valid: boolean, wordCount: number, error?: string }

    // Discover which chains have existing balances const discovery = await sdk.discoverChainsFromSeedphrase('word1 word2 ...'); // Returns: ChainDiscoveryAggregate

    // Create Fast Vault from seedphrase (still needs email verification) const vaultId = await sdk.createFastVaultFromSeedphrase({ name: 'imported-vault', email: 'agent@example.com', password: 'secure-password', mnemonic: 'word1 word2 ...', }); const vault = await sdk.verifyVault(vaultId, 'email-code');

    Risk notes:

  • Seedphrase import creates a new TSS vault from the seed β€” the original seed-based wallet still exists independently.
  • Handle seedphrases with extreme care. Never log, store in plaintext, or transmit unencrypted.
  • 10. Vault lifecycle management

    // List all vaults
    const vaults = await sdk.listVaults();

    // Set active vault await sdk.setActiveVault(vault);

    // Get active vault const active = await sdk.getActiveVault();

    // Check vault type if (Vultisig.isFastVault(vault)) { /* FastVault methods */ } if (Vultisig.isSecureVault(vault)) { /* SecureVault methods */ }

    // Delete vault await sdk.deleteVault(vault);

    11. Check transaction status

    After broadcasting, use the explorer URL or chain-specific methods to confirm transactions:

    // Get explorer URL for any chain
    const explorerUrl = Vultisig.getTxExplorerUrl('Ethereum', txHash);
    // e.g., "https://etherscan.io/tx/0x..."

    const addressUrl = Vultisig.getAddressExplorerUrl('Bitcoin', btcAddress); // e.g., "https://mempool.space/address/bc1..."

    For 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.

    // Pattern: confirm send completed
    const balanceBefore = await vault.balance('Ethereum');
    // ... broadcast transaction ...
    await new Promise(r => setTimeout(r, 15000)); // Wait for block confirmation
    const balanceAfter = await vault.updateBalance('Ethereum');
    // Compare balanceBefore.amount vs balanceAfter.amount
    

    12. Address book

    Manage recurring recipients for automated transfers:

    // Get saved addresses (optionally filter by chain)
    const allContacts = await sdk.getAddressBook();
    const ethContacts = await sdk.getAddressBook('Ethereum');

    // Add entries await sdk.addAddressBookEntry([ { chain: 'Ethereum', address: '0x...', name: 'Treasury' }, { chain: 'Bitcoin', address: 'bc1...', name: 'Cold Storage' }, ]);

    // Update a name await sdk.updateAddressBookEntry('Ethereum', '0x...', 'Main Treasury');

    // Remove entries await sdk.removeAddressBookEntry([ { chain: 'Ethereum', address: '0x...' }, ]);

    > Source: Vultisig.ts

    13. $VULT discount tiers

    Holding $VULT tokens reduces swap fees (up to 50%). The SDK can check and update the agent's discount tier:

    // Check current discount tier
    const tier = await vault.getDiscountTier();
    // Returns: string | null β€” e.g., "gold", "silver", or null if no discount

    // Update tier (after acquiring more $VULT) const newTier = await vault.updateDiscountTier();

    > Token contract: 0xb788144DF611029C60b859DF47e79B7726C4DEBa (Ethereum)

    14. Listen to events

    // SDK-level events
    sdk.on('vaultCreationProgress', (data) => { /* keygen progress */ });
    sdk.on('vaultCreationComplete', (data) => { /* vault ready */ });
    sdk.on('vaultChanged', (data) => { /* active vault switched */ });

    // Vault-level events vault.on('balanceUpdated', (data) => { /* balance changed */ }); vault.on('transactionSigned', (data) => { /* signature complete */ }); vault.on('transactionBroadcast', (data) => { /* tx submitted */ }); vault.on('signingProgress', (data) => { /* signing steps */ }); vault.on('swapQuoteReceived', (data) => { /* quote ready */ });

    // SecureVault only (multi-device coordination) vault.on('qrCodeReady', (data) => { /* show QR for device pairing */ }); vault.on('deviceJoined', (data) => { /* co-signer connected */ }); vault.on('allDevicesReady', (data) => { /* threshold met, signing can proceed */ });

    // Error handling vault.on('error', (error) => { /* handle errors */ }); sdk.on('error', (error) => { /* handle SDK-level errors */ });

    > Source: packages/sdk/src/events/

    Supported chains

    > Source: Chain.ts

    | Category | Chains | Signature | |----------|--------|-----------| | UTXO | Bitcoin, Litecoin, Dogecoin, Bitcoin Cash, Dash, Zcash | ECDSA | | EVM | Ethereum, BSC, Polygon, Avalanche, Arbitrum, Optimism, Base, Blast, Cronos, zkSync, Hyperliquid, Mantle, Sei | ECDSA | | Cosmos/IBC | THORChain, MayaChain, Cosmos Hub, Osmosis, Dydx, Kujira, Noble, Terra, Terra Classic, Akash | ECDSA | | Other | Solana, Sui, Polkadot, TON, Ripple, Tron, Cardano | EdDSA / Mixed |

    Security model

  • No seed phrases β€” vault shares replace 12/24 word seeds
  • No single point of failure β€” no device holds a complete private key
  • No on-chain key registration β€” unlike multi-sig wallets
  • DKLS23 protocol β€” 3-round TSS, co-developed with Silence Laboratories
  • Open source and audited
  • Docs: Security & Technology
  • CLI alternative

    npm install -g @vultisig/sdk

    vsig vault create --name agent-vault --type fast vsig balance --chain Ethereum vsig send --chain Ethereum --to 0x... --amount 0.1 vsig swap --from ETH --to USDC --amount 0.1

    > Source: clients/cli/

    Progressive disclosure

  • SDK Users Guide β€” Complete API walkthrough
  • Architecture β€” SDK internals, data flow, design patterns
  • Agent Integration Guide β€” Agent-specific patterns and best practices
  • Fast Vault Docs β€” How VultiServer co-signing works
  • Marketplace Plugin Guide β€” Build automation plugins
  • llms.txt β€” Concise link index for web-browsing agents
  • llms-full.txt β€” Extended context with examples