Skip to main content
Package: @blend-money/sdk-actionsGitHub · npm · Monorepo: sdks

Install

  • pnpm
  • npm
  • yarn
pnpm add @blend-money/sdk-core @blend-money/sdk-actions

Quick start

import { BlendClientWithActions } from "@blend-money/sdk-actions";
import { Integrations } from "@blend-money/sdk-types";

const client = new BlendClientWithActions({
  baseUrl: "https://api.blend.money",
  userAddress: "0x1234567890abcdef1234567890abcdef12345678",
  integratorId: "example-app",
}, { gardenAppId: "YOUR_GARDEN_APP_ID" });

// Get available strategies for USX integration
const strategies = await client.strategy.getAvailableStrategies(Integrations.USX);

// Create a deposit plan
const plan = await client.actions.deposit(
  { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", decimals: 6, chainId: 8453 },
  strategies[0],
  1_000_000n, // 1 USDC
  50, // 0.5% slippage
);

console.log("Required approvals:", plan.requiredApprovals.length);
console.log("Required transactions:", plan.requiredTxns.length);

What it adds

  • actions.deposit(...) → Direct transfer or cross-chain route to the Safe
  • actions.withdraw(...) → Vault withdrawal with optional cross-chain swap
  • actions.rebalance(...) → Manual rebalance using /safe/rebalance/manual
  • actions.getManualRebalanceCall(...) → Low-level rebalance calldata helper

Configuration

The Actions SDK requires configuration for cross-chain adapters:
const client = new BlendClientWithActions({
  baseUrl: "https://api.blend.money",
  userAddress: "0x1234567890abcdef1234567890abcdef12345678",
  integratorId: "example-app",
}, {
  gardenAppId: "YOUR_GARDEN_APP_ID", // Optional: for Garden cross-chain routes
  lifiIntegratorId: "YOUR_LIFI_ID"   // Optional: for LiFi cross-chain routes
});

Cross-chain Routing

The Actions SDK automatically selects the appropriate cross-chain adapter:
  • LiFi: Used for EVM-to-EVM routes (Ethereum, Base, Polygon, etc.)
  • Garden: Used for Botanix routes and native Bitcoin operations
// This will use LiFi (EVM to EVM)
const plan = await client.actions.deposit(
  { address: "0x...", symbol: "USDC", decimals: 6, chainId: 1 },      // Ethereum
  { vaultId: "0x...", chainId: 8453, token: {...}, name: "...", symbol: "..." }, // Base
  1_000_000n,
  50,
);

// This will use Garden (Botanix route)
const plan2 = await client.actions.deposit(
  { address: "0x...", symbol: "USDC", decimals: 6, chainId: 1 },      // Ethereum
  { vaultId: "0x...", chainId: 3637, token: {...}, name: "...", symbol: "..." }, // Botanix
  1_000_000n,
  50,
);

API

deposit(inputToken, strategy, amount, slippageBps?)

Returns an ActionPlan with approvals and transactions for a deposit. Cross‑chain routes are automatically built via LiFi (EVM) or Garden (Botanix/native BTC). Parameters:
  • inputToken: Token to deposit (address, symbol, decimals, chainId)
  • strategy: Target vault configuration from strategy.getAvailableStrategies()
  • amount: Amount in smallest units (e.g., 1 USDC = 1_000_000n)
  • slippageBps: Optional slippage tolerance in basis points (default: 50 = 0.5%)
Examples:
// Same-chain deposit (direct transfer)
const plan = await client.actions.deposit(
  { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", decimals: 6, chainId: 8453 },
  { vaultId: "0x1234...", chainId: 8453, token: { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", decimals: 6, chainId: 8453 }, name: "USDC Vault", symbol: "vUSDC" },
  1_000_000n, // 1 USDC
  50, // 0.5% slippage
);

// Cross-chain deposit (uses LiFi)
const crossChainPlan = await client.actions.deposit(
  { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", symbol: "USDC", decimals: 6, chainId: 1 }, // Ethereum USDC
  { vaultId: "0x1234...", chainId: 8453, token: { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", decimals: 6, chainId: 8453 }, name: "USDC Vault", symbol: "vUSDC" }, // Base vault
  1_000_000n,
  100, // 1% slippage for cross-chain
);

withdraw(rpcClient, strategy, amount, outputToken, isMaxWithdraw?, slippageBps?)

Returns a tuple where the second item may be a function to build a follow‑up cross‑chain plan after on‑chain state updates. Parameters:
  • rpcClient: Viem public client for the vault’s chain
  • strategy: Vault configuration to withdraw from
  • amount: Amount to withdraw in smallest units (ignored if isMaxWithdraw is true)
  • outputToken: Desired output token (address, symbol, decimals, chainId)
  • isMaxWithdraw: Whether to withdraw all available shares (default: false)
  • slippageBps: Optional slippage tolerance for cross-chain swaps (default: 50)
Examples:
import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

// Create RPC client for the vault chain
const publicClient = createPublicClient({
  chain: base,
  transport: http('https://mainnet.base.org')
});

// Partial withdrawal to same token
const [withdrawPlan] = await client.actions.withdraw(
  publicClient,
  strategy,
  1_000_000n, // 1 USDC
  { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", decimals: 6, chainId: 8453 },
  false,
  50,
);

// Max withdrawal with cross-chain swap
const [withdrawPlan, swapPlanBuilder] = await client.actions.withdraw(
  publicClient,
  strategy,
  0n, // Amount ignored when isMaxWithdraw = true
  { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", symbol: "USDC", decimals: 6, chainId: 1 }, // Ethereum USDC
  true, // Max withdrawal
  100, // 1% slippage for cross-chain
);

// Execute the withdrawal, then build cross-chain plan if needed
if (swapPlanBuilder) {
  const swapPlan = await swapPlanBuilder();
  console.log("Cross-chain swap plan:", swapPlan);
}

rebalance(strategy, amountVaultToken)

Builds a multisend ActionPlan that calls the controller using the manual rebalance calldata. Parameters:
  • strategy: Vault configuration to rebalance
  • amountVaultToken: Amount of vault tokens to rebalance in smallest units
Example:
// Rebalance 100 vault tokens
const plan = await client.actions.rebalance(strategy, 100_000_000n);

console.log("Deploy type:", plan.deployType); // "multisend"
console.log("Required transactions:", plan.requiredTxns.length); // 1
console.log("Is delegate call:", plan.requiredTxns[0].isDelegateCall); // true

getManualRebalanceCall(userAddress, chainId, vaultId, amount)

Low‑level helper to fetch the target + calldata for manual rebalances. Useful when you need to build custom transaction flows. Parameters:
  • userAddress: User’s EOA address
  • chainId: Chain ID of the vault
  • vaultId: Vault contract address
  • amount: Amount to rebalance (string or bigint)
Example:
const { target, data } = await client.actions.getManualRebalanceCall(
  client.getConfig().userAddress,
  8453,
  strategy.vaultId,
  1_000_000n,
);

// Use the calldata in your custom transaction
const customTx = {
  to: target,
  data: data,
  value: 0n,
  chainId: 8453,
  account: client.getConfig().userAddress,
};

Execution helpers

TransactionHandler

For executing ActionPlans from a Safe, use the TransactionHandler to submit multisend/UserOps with a paymaster.
import { TransactionHandler } from "@blend-money/sdk-actions";
import { createWalletClient, createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

// Create clients
const walletClient = createWalletClient({
  chain: base,
  transport: http('https://mainnet.base.org')
});

const publicClient = createPublicClient({
  chain: base,
  transport: http('https://mainnet.base.org')
});

// Create transaction handler
const handler = new TransactionHandler("YOUR_PIMLICO_API_KEY");

// Execute action plan
const { receipts } = await handler.submitActionPlan(
  walletClient,
  publicClient,
  safeAddress,
  [plan] // Array of ActionPlans
);

console.log("Transaction receipts:", receipts);

Manual Execution

References

  • Repo: https://github.com/BlendMoney/sdkspackages/sdk-actions
  • Readme: packages/sdk-actions/README.md