npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@owney/sdk

v0.7.28

Published

A TypeScript SDK for interacting with DeFi yield agents. Supports multiple agents through a unified interface.

Readme

@owney/sdk

A TypeScript SDK for interacting with DeFi yield agents. Supports multiple agents through a unified interface.

Installation

npm install @owney/sdk

Quick Start

import { OwneySDK } from "@owney/sdk";

// Create the SDK instance
const sdk = new OwneySDK({ apiKey: "your-owney-api-key" });

// Connect with an EIP-1193 wallet provider
await sdk.connect(provider);

// Activate agents on Base (fetches agent keys on first call)
await sdk.activateAgent(8453);

// Get balances across all agents
const balances = await sdk.getBalances();

SDK Functions

new OwneySDK(config)

Create a new SDK instance.

| Param | Type | Description | | --------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------- | | config.apiKey | string | Your Owney API key, used to authenticate with the routing API and fetch agent-specific keys | | config.zyfaiRpcUrls | { 8453?: string; 42161?: string } (optional) | Per-chain RPC URL overrides used by Zyfai SDK network calls |

import { OwneySDK } from "@owney/sdk";

const sdk = new OwneySDK({ apiKey: "your-owney-api-key" });

Custom Zyfai RPC URLs

Use zyfaiRpcUrls to override Zyfai SDK RPC endpoints (for example, to avoid public endpoint rate limits).

const sdk = new OwneySDK({
  apiKey: "your-owney-api-key",
  zyfaiRpcUrls: {
    8453: "https://base-mainnet.g.alchemy.com/v2/<key>",
    42161: "https://arb-mainnet.g.alchemy.com/v2/<key>",
  },
});

Notes:

  • These overrides are used by Zyfai SDK flows only.
  • If omitted, Zyfai SDK uses its default RPC endpoints.
  • Other app-level RPC clients (for example, direct viem calls outside Zyfai) are configured separately.

connect(provider)

Establish connection state. Must be called before any wallet-dependent operation.

| Param | Type | Description | | ---------- | ----------------- | ---------------------------------------------- | | provider | EIP-1193 provider | Wallet provider (e.g. MetaMask, WalletConnect) |

await sdk.connect(window.ethereum);

disconnect()

Disconnect from all agents and clear connection state.

await sdk.disconnect();

isConnected()

Check if the SDK has an active connection.

if (sdk.isConnected()) {
  // safe to call wallet-dependent methods
}

getActiveChainId()

Get the currently active chain ID, set by activateAgent.

Returns: number | null

const chainId = sdk.getActiveChainId();
if (chainId) {
  console.log(`Active on chain ${chainId}`);
}

activateAgent(chainId, agentId?)

Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted. Smart wallets are pre-deployed by the underlying providers, so activation only performs authentication and profile syncing — no deploy or session-key signatures. Saves the chainId for use by all subsequent SDK calls.

| Param | Type | Description | | --------- | ---------------------- | ----------------------------------------------------------------------------- | | chainId | number | Target chain ID (e.g. 8453 for Base, 42161 for Arbitrum) | | agentId | AgentId[] (optional) | Agents to activate. Omit to activate all agents that support the given chain. |

// Activate specific agents on Base
await sdk.activateAgent(8453, ["zyfai"]);

// Activate all agents that support Arbitrum
await sdk.activateAgent(42161);

deposit(options)

Deposit funds into a specific agent, or split equally across all agents if agentId is omitted. Validates that the asset is supported by the target agent(s) on the active chain, and per-agent minimum deposit amounts (defined per chain+asset on agent.supportedAssets[].assets[].minDepositAmount) are taken into account. When splitting across agents, depositCallback is invoked once per final valid agent with that agent's split amount and smart wallet address — expect multiple wallet prompts.

| Param | Type | Description | | ------------------------- | -------------------- | --------------------------------------------------------------- | | options.amount | string | Amount in smallest unit (e.g. "100000000" for 100 USDC) | | options.asset | string | Asset symbol (e.g. "USDC") | | options.depositCallback | DepositCallback | Callback that performs the token transfer and returns a tx hash | | options.agentId | AgentId (optional) | Target agent. Omit to split equally across all agents. |

Zyfai's native transfer path uses sendDeposit(). It returns after the token transfer confirms and the deposit is registered, while balance credit may still be queued. Balance reads reflect subsequent credit and allocation; the deposit call does not wait for waitForDepositCredit(). A successful deposit result confirms the transfer; it does not guarantee that the funds are already credited or earning yield.

Returns: OwneyDepositResult (single agent) or OwneyMultiDepositResult (all agents)

// Deposit to a specific agent
const result = await sdk.deposit({
  agentId: "zyfai",
  amount: "100000000",
  asset: "USDC",
  depositCallback: async (smartWallet, chainId, amount) => {
    const txHash = await transferTokens(smartWallet, amount);
    return txHash;
  },
});
console.log(result.txHash); // "0x..."
console.log(result.smartWallet); // "0x..."
console.log(result.amount); // "100000000"

// Split equally across all agents
const results = await sdk.deposit({
  amount: "100000000",
  asset: "USDC",
  depositCallback: async (smartWallet, chainId, amount) => {
    return await transferTokens(smartWallet, amount);
  },
});
console.log(results.agentResults.zyfai.amount); // "100000000"

withdraw(options)

Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted. Validates that the asset is supported.

When agentId is omitted with a partial amount, the SDK splits the requested amount proportionally across eligible agents based on each agent's per-asset balance. If an agent's withdraw fails, its share is redistributed to remaining not-yet-attempted agents (capped by their headroom).

Full withdrawals (no amount) iterate every eligible agent and continue on per-agent failures — successful agents still return their results. Per-agent failures (e.g. backend returns success: false) surface as WITHDRAW_FAILED from the agent and are caught at the aggregation layer.

Throws:

  • WITHDRAW_INSUFFICIENT_BALANCE — total available across agents is less than amount.
  • WITHDRAW_ALL_FAILED — every agent's withdraw call failed (full or partial). Carries per-agent failure messages via error.details.agentErrors (a Record<agentId, string>).
  • WITHDRAW_PARTIAL_FAILURE — partial withdrawals only: some agents succeeded but total withdrawn is less than amount. Successful txs surfaced via error.details.partialResults; per-agent failures via error.details.agentErrors.
  • WITHDRAW_FAILED — a single agent's underlying withdraw call returned an unsuccessful response. Includes error.agentId and the backend message in error.details.response.

Any error originating from a specific agent also has error.agentId set and a [<code>][agent:<id>] prefix on error.message.

| Param | Type | Description | | ----------------- | -------------------- | --------------------------------------------- | | options.asset | string | Asset symbol (e.g. "USDC") | | options.amount | string (optional) | Amount to withdraw. Omit for full withdrawal. | | options.agentId | AgentId (optional) | Target agent. Omit to withdraw from all. |

Returns: AgentWithdrawResult (single agent) or OwneyWithdrawResult (all agents)

// Partial withdrawal from one agent
const result = await sdk.withdraw({
  asset: "USDC",
  agentId: "zyfai",
  amount: "50000000",
});
console.log(result.type); // "partial"
console.log(result.amount); // "50000000"

// Partial withdrawal split proportionally across all agents
// e.g. zyfai=$5, amount=$4 -> zyfai withdraws $4
const split = await sdk.withdraw({ asset: "USDC", amount: "4000000" });
console.log(split.agentResult.zyfai.amount); // "4000000"

// Full withdrawal from all agents
const results = await sdk.withdraw({ asset: "USDC" });
console.log(results.agentResult.zyfai.type); // "full"

getBalances(agentId?)

Get the user's balances for a specific agent, or aggregated across all agents. Balances are shown after any applicable performance fees have been deducted.

| Param | Type | Description | | --------- | -------------------- | ------------------------------------ | | agentId | "zyfai" (optional) | Agent to query. Omit for all agents. |

Returns: AgentBalance (single agent) or OwneyBalances (all agents)

// Single agent
const balance = await sdk.getBalances("zyfai");
console.log(balance.totalBalance); // "150.25"
console.log(balance.totalBalanceAsset); // "usdc" — unit of totalBalance
console.log(balance.smartWallet); // "0x..."
console.log(balance.tokens); // [{ chain: "BASE", chainId: 8453, asset: "USDC", amount: "150.25" }]

// All agents
const allBalances = await sdk.getBalances();
console.log(allBalances.totalBalance); // "150.25"
console.log(allBalances.totalBalanceAsset); // "usdc" — unit of totalBalance
console.log(allBalances.agentBalances.zyfai.totalBalance); // "150.25"
console.log(allBalances.agentBalances.zyfai.totalBalanceAsset); // "usdc"

getEarnings(agentId?)

Get the user's on-chain earnings for a specific agent, or aggregated across all agents. Earnings are shown after any applicable performance fees have been deducted.

| Param | Type | Description | | --------- | -------------------- | ------------------------------------ | | agentId | "zyfai" (optional) | Agent to query. Omit for all agents. |

Returns: AgentEarnings (single agent) or OwneyEarnings (all agents)

// Single agent
const earnings = await sdk.getEarnings("zyfai");
console.log(earnings.smartWallet); // "0x..."
console.log(earnings.lifetimeEarnings); // 42.5
console.log(earnings.tokens);
// [
//   { chain: "BASE", chainId: 8453, asset: "USDC", amount: "30.0" },
//   { chain: "ARBITRUM", chainId: 42161, asset: "USDC", amount: "12.5" },
// ]

// All agents
const allEarnings = await sdk.getEarnings();
console.log(allEarnings.totalEarnings); // "85.0"
console.log(allEarnings.agentEarnings.zyfai.lifetimeEarnings); // 42.5
console.log(allEarnings.agentEarnings.zyfai.tokens); // per-chain, per-asset breakdown

refreshEarnings(agentId?)

Refresh earnings for agents whose earnings data may be outdated. If the latest snapshot is less than one hour old, the SDK returns it without recalculating.

| Param | Type | Description | | --------- | -------------------- | ------------------------------------ | | agentId | "zyfai" (optional) | Agent to refresh. Omit for all agents. |

Returns: AgentEarnings (single agent) or OwneyEarnings (all agents)

// Single agent
const refreshed = await sdk.refreshEarnings("zyfai");

// All agents
const allRefreshed = await sdk.refreshEarnings();

getAccountApy({ agentId?, days })

Get the weighted APY for the user's account. When querying all agents, the total APY is a balance-weighted average.

| Param | Type | Description | | --------- | ------------------------ | ------------------------------------------------ | | agentId | "zyfai" (optional) | Agent to query. Omit for balance-weighted total. | | days | "7D" \| "14D" \| "30D" | Lookback period |

Returns: AccountAgentApy (single agent) or OwneyAccountApy (all agents)

// Single agent
const apy = await sdk.getAccountApy({ agentId: "zyfai", days: "30D" });
console.log(apy.walletAddress); // "0x..."
console.log(apy.weightedApyAfterFee); // 5.2
// Per chain + token breakdown, when the agent reports it
console.log(apy.weightedApyAfterFeeDetails?.apyPerAsset[8453]?.USDC); // 5.4
// Same per-(chain, asset) breakdown surfaced under a unified key
console.log(apy.apyByChainAndAsset?.[8453]?.USDC); // 5.4

// All agents (balance-weighted)
const allApy = await sdk.getAccountApy({ days: "30D" });
console.log(allApy.totalApy); // "5.6"
console.log(allApy.agentApy.zyfai.weightedApyAfterFee); // 6.0
// Per (chain, asset), balance-weighted across all agents.
// Cells with 0/missing APY for a given agent are excluded from that cell.
console.log(allApy.apyByChainAndAsset[8453]?.USDC); // 5.3
console.log(allApy.apyByChainAndAsset[42161]?.WETH); // 4.7

getHistory({ agentId?, filters? })

Get transaction history for a specific agent, or all agents. When querying all agents, results are merged into a single list sorted by date (newest first). Each entry includes the originating agent and a transactions array with typed on-chain transaction details.

Results are cursor-paginated. The first call (no cursor) anchors a stable snapshot at the current time; subsequent pages within that same snapshot are consistent. Each new cursorless call captures a fresh snapshot — if you need to preserve scroll position while paging, always carry forward the cursor returned by the previous call rather than starting a new cursorless fetch.

Per-chain filtering: The Zyfai backend no longer accepts a chainId filter directly. The SDK performs a bounded internal drain (up to 5 backend round-trips per logical page) to fill the requested limit with entries matching the active chain. This is transparent to callers — the getHistory API is unchanged.

| Param | Type | Description | | ------------------ | -------------------- | ------------------------------------------------------- | | agentId | "zyfai" (optional) | Agent to query. Omit for all agents. | | filters.fromDate | string (optional) | Start date (YYYY-MM-DD) | | filters.toDate | string (optional) | End date (YYYY-MM-DD) | | filters.limit | number (optional) | Max entries returned per call. Defaults to 10. | | filters.cursor | string (optional) | Opaque cursor returned by a previous getHistory call. |

Returns: OwneyAgentHistory

// Single agent with filters
const history = await sdk.getHistory({
  agentId: "zyfai",
  filters: { fromDate: "2025-01-01" },
});
console.log(history.hasMore); // true | false
console.log(history.data[0].agent); // "zyfai"
console.log(history.data[0].action); // "Rebalance"
console.log(history.data[0].date); // "2025-03-15T12:00:00Z"
console.log(history.data[0].transactions[0].txHashes); // ["0x..."]
console.log(history.data[0].transactions[0].amount); // "100.00"
console.log(history.data[0].transactions[0].tokenSymbol); // "USDC"

// Rebalance logs show fund movement between protocols
console.log(history.data[0].rebalanceLog[0].fromProtocol); // "Aave V3"
console.log(history.data[0].rebalanceLog[0].toProtocol); // "Morpho Blue"
console.log(history.data[0].rebalanceLog[0].tokenSymbol); // "USDC"
console.log(history.data[0].rebalanceLog[0].amount); // "100.00"
console.log(history.data[0].rebalanceLog[0].status); // "success"

// All agents (merged and sorted by date)
const allHistory = await sdk.getHistory();
console.log(allHistory.hasMore); // true | false
console.log(allHistory.data[0].agent); // "zyfai" (most recent entry)
console.log(allHistory.data[0].action); // "Rebalance"

// Paginate through all history (per-chain, anchored to a single snapshot)
const allEntries: AgentHistoryEntry[] = [];
let cursor: string | undefined;
do {
  const page = await sdk.getHistory({
    filters: { cursor, limit: 50 },
  });
  allEntries.push(...page.data);
  cursor = page.hasMore ? page.nextCursor : undefined;
} while (cursor);

getUserProfile(agentId?)

Get the user's profile for a specific agent, or all agents.

| Param | Type | Description | | --------- | -------------------- | ------------------------------------ | | agentId | "zyfai" (optional) | Agent to query. Omit for all agents. |

Returns: AgentUserProfile (single agent) or OwneyUserProfile (all agents)

// Single agent
const profile = await sdk.getUserProfile("zyfai");
console.log(profile.address); // "0x..."
console.log(profile.smartWallet); // "0x..."
console.log(profile.chains); // [8453]
console.log(profile.hasActiveSessionKey); // true
console.log(profile.protocols); // ["aave", "compound"]

// All agents
const allProfiles = await sdk.getUserProfile();
console.log(allProfiles.agentUserProfile.zyfai.smartWallet); // "0x..."

getAgentApy({ agentId?, days, tokenSymbol?, chainId? })

Get the agent's average APY performance over a time period. Does not require a wallet connection.

| Param | Type | Description | | ------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------- | | agentId | "zyfai" (optional) | Agent to query. Omit for all agents. | | days | "7D" \| "14D" \| "30D" | Lookback period | | tokenSymbol | string (optional) | Asset symbol (e.g. "USDC"). Scopes the upstream request to a specific asset when the agent's backend supports it. | | chainId | number (optional) | Chain id. Typically paired with tokenSymbol for per-asset+chain APY. |

Returns: AgentApy (single agent) or OwneyAgentApy (all agents)

The agent populates detailedApys.apyPerAsset with a per-chain, per-token breakdown when available. tokenSymbol / chainId only affect whether the upstream query is scoped — the breakdown is built from whatever the agent returns.

// Single agent
const apy = await sdk.getAgentApy({ agentId: "zyfai", days: "30D" });
console.log(apy.averageApy); // 8.5
console.log(apy.detailedApys?.apyPerAsset[8453]?.USDC); // 8.7

// All agents
const allApy = await sdk.getAgentApy({ days: "30D" });
console.log(allApy.agentApy.zyfai.averageApy); // 8.5

// Scope the upstream query to USDC on Base
const usdcBaseApy = await sdk.getAgentApy({
  days: "30D",
  tokenSymbol: "USDC",
  chainId: 8453,
});
console.log(usdcBaseApy.agentApy.zyfai.averageApy); // APY scoped to USDC on Base

Types

Configuration

type AgentId = "zyfai";
type Asset = string;
type DailyApyDays = "7D" | "14D" | "30D";
type OwneySupportedChainId = 8453 | 42161;
type OwneySupportedChains = "BASE" | "ARBITRUM";
type OwneySupportedTokens = "USDC" | "WETH";

type AgentSupportedAsset = {
  readonly symbol: string;
  /** Minimum deposit in the asset's smallest unit (e.g. wei, "0" for none). */
  readonly minDepositAmount: string;
};

type AgentSupportedAssets = {
  readonly chainId: number;
  readonly chain?: string;
  readonly assets: readonly AgentSupportedAsset[];
};

interface OwneySDKConfig {
  apiKey: string;
  zyfaiRpcUrls?: {
    8453?: string;
    42161?: string;
  };
}

interface ConnectionState {
  provider: any;
  walletAddress: `0x${string}`;
  chainId: number | null;
}

type HistoryFilters = {
  fromDate?: string; // YYYY-MM-DD
  toDate?: string; // YYYY-MM-DD
  /** Max entries returned per call. Defaults to 10. */
  limit?: number;
  /** Opaque cursor returned by a previous getHistory call. */
  cursor?: string;
};

type HistoryOptions = {
  agentId?: AgentId;
  filters?: HistoryFilters;
};

type DepositOptions = {
  amount: string;
  asset: Asset;
  depositCallback: DepositCallback;
  agentId?: AgentId;
};

type WithdrawOptions = {
  asset: Asset;
  amount?: string;
  agentId?: AgentId;
};

type AccountApyOptions = {
  agentId?: AgentId;
  days: DailyApyDays;
};

type AgentsApyOptions = {
  agentId?: AgentId;
  days: DailyApyDays;
  tokenSymbol?: string; // e.g. "USDC", "WETH"
  chainId?: number; // typically paired with tokenSymbol
};

Response Types

interface OwneyDepositResult {
  txHash: string;
  smartWallet: string;
  amount: string;
}

interface OwneyMultiDepositResult {
  agentResults: Record<string, OwneyDepositResult>;
}

interface AgentWithdrawResult {
  txHash?: string;
  type: "full" | "partial";
  amount: string;
}

interface OwneyWithdrawResult {
  agentResult: Record<AgentId, AgentWithdrawResult>;
}

interface OwneyToken {
  chain: OwneySupportedChains;
  chainId: OwneySupportedChainId;
  asset: OwneySupportedTokens;
  amount: string;
}

interface AgentBalance {
  smartWallet?: `0x${string}`;
  totalBalance: string;
  totalBalanceAsset: string; // unit of totalBalance, currently always "usdc"
  tokens: OwneyToken[];
}

interface OwneyBalances {
  totalBalance: string;
  totalBalanceAsset: string; // unit of totalBalance, currently always "usdc"
  agentBalances: Record<AgentId, AgentBalance>;
}

interface AgentEarnings {
  smartWallet: `0x${string}`;
  lifetimeEarnings: number;
  tokens: OwneyToken[];
}

interface OwneyEarnings {
  totalEarnings: string;
  agentEarnings: Record<AgentId, AgentEarnings>;
}

type ApyByChainAndAsset = Partial<
  Record<OwneySupportedChainId, Partial<Record<OwneySupportedTokens, number>>>
>;

interface AccountAgentApy {
  walletAddress: string;
  weightedApyAfterFee?: number;
  weightedApyAfterFeeDetails?: AgentApyDetails;
  apyByChainAndAsset?: ApyByChainAndAsset;
}

interface OwneyAccountApy {
  totalApy: string;
  agentApy: Record<AgentId, AccountAgentApy>;
  apyByChainAndAsset: ApyByChainAndAsset;
}

type HistoryAction = "Rebalance" | "Deposit" | "Top up" | "Withdraw" | "Earned";

interface HistoryTransaction {
  txHashes: string[];
  chainId?: number;
  tokenSymbol?: string;
  amount?: string;
}

interface RebalanceLog {
  fromProtocol: string;
  toProtocol: string;
  tokenSymbol: string;
  amount: string;
  status: "success" | "failed";
}

interface AgentHistoryEntry {
  agent: AgentId;
  action: HistoryAction;
  date: string;
  oldApy: string | null;
  newApy: string | null;
  transactions: HistoryTransaction[];
  rebalanceLog: RebalanceLog[];
}

interface OwneyAgentHistory {
  data: AgentHistoryEntry[];
  /** True iff a subsequent page exists; pair with `nextCursor`. */
  hasMore: boolean;
  /** Opaque cursor for the next page. Present iff `hasMore === true`. */
  nextCursor?: string;
}

interface AgentUserProfile {
  address: string;
  smartWallet: string;
  chains: number[];
  strategy?: string;
  hasActiveSessionKey: boolean;
  protocols: string[];
}

interface OwneyUserProfile {
  agentUserProfile: Record<AgentId, AgentUserProfile>;
}

interface AgentApy {
  averageApy: number;
  detailedApys?: AgentApyDetails;
}

interface AgentApyDetails {
  // Per-chain, per-token APY breakdown. Only populated for the chain/token
  // pairs that appear in SupportedAssets — entries may be missing when the
  // upstream agent doesn't report APY for a given chain or token.
  apyPerAsset: Partial<
    Record<OwneySupportedChainId, Partial<Record<OwneySupportedTokens, number>>>
  >;
}

interface OwneyAgentApy {
  agentApy: Record<AgentId, AgentApy>;
}

Callback Types

type DepositCallback = (
  smartWalletAddress: string,
  chainId: number,
  amount: string,
) => Promise<`0x${string}`> | `0x${string}`;

Error Handling

All errors thrown by the SDK are instances of OwneyError (which extends Error), each carrying a stable code string, optional details object, and optional agentId identifying the originating agent. error.message is always prefixed with [<code>] (and [<code>][agent:<id>] when agent-scoped) so the code is visible in browser console logs without inspecting the error object.

import { OwneyError } from "@owney/sdk";

try {
  await sdk.getBalances();
} catch (error) {
  if (error instanceof OwneyError) {
    switch (error.code) {
      case "NOT_CONNECTED":
        // prompt user to connect wallet
        break;
      case "NO_ACTIVE_CHAIN":
        // prompt user to activate an agent
        break;
      case "BALANCE_ALL_FAILED":
        // all agents failed to return balances
        break;
      default:
        console.error(`[${error.code}] ${error.message}`, error.details);
    }
  }
}
type OwneyErrorCode =
  // Connection & wallet
  | "NOT_CONNECTED" // Wallet-dependent method called before connect()
  | "NO_ACTIVE_CHAIN" // Method called before activateAgent()
  | "WALLET_NO_ACCOUNTS" // Provider returned no accounts during connect()
  | "WALLET_ADDRESS_REQUIRED" // Wallet address missing during agent auth
  // Agent resolution
  | "AGENT_NOT_FOUND" // Unknown agent ID passed
  | "AGENT_CHAIN_INCOMPATIBLE" // Agent(s) don't support the given chain
  | "AGENT_EMPTY_LIST" // Empty agentId array passed to activateAgent()
  // Chain
  | "CHAIN_UNSUPPORTED" // Chain ID not in supported list (8453, 42161)
  | "CHAIN_NO_COMPATIBLE_AGENTS" // No agents support the given chain
  // Asset
  | "ASSET_UNSUPPORTED" // Agent doesn't support the asset on the active chain
  | "ASSET_NO_COMPATIBLE_AGENTS" // No agents support the asset on the active chain
  // Deposit
  | "DEPOSIT_AMOUNT_BELOW_MINIMUM" // Amount below an agent's required minimum deposit for the chain+asset
  | "DEPOSIT_CALLBACK_REQUIRED" // Agent requires a depositCallback
  | "DEPOSIT_CALLBACK_INVALID" // depositCallback didn't return a tx hash
  | "DEPOSIT_NO_PERMITTED_TOKENS" // No permitted tokens available for deposit
  // Withdraw
  | "WITHDRAW_NO_PERMITTED_TOKENS" // No permitted tokens available for withdrawal
  | "WITHDRAW_INSUFFICIENT_BALANCE" // Requested amount exceeds total available across agents
  | "WITHDRAW_ALL_FAILED" // Every eligible agent's withdraw call failed
  | "WITHDRAW_PARTIAL_FAILURE" // Some agents succeeded; total withdrawn < requested
  | "WITHDRAW_FAILED" // Agent backend returned an unsuccessful withdraw response
  // API
  | "API_ROUTING_ERROR" // Routing API returned a non-OK HTTP status
  | "API_ROUTING_FAILED" // Routing API returned { success: false }
  | "API_NO_AGENTS" // No supported agents returned by routing API
  // Aggregation
  | "BALANCE_ALL_FAILED" // All agents failed to return balances
  | "ALLOCATION_ALL_FAILED" // All agents failed to return allocation data
  // Validation
  | "VALIDATION_INVALID_DAYS"; // Invalid days value (expected "7D", "14D", or "30D")

class OwneyError extends Error {
  readonly code: OwneyErrorCode;
  readonly details?: Record<string, unknown>;
  readonly agentId?: string;
}

The three convenience subclasses extend OwneyError and remain backwards-compatible:

| Class | Code | Extra properties | | ----------------------------- | -------------------------- | ---------------------------------------- | | NotConnectedError | NOT_CONNECTED | — | | AgentNotFoundError | AGENT_NOT_FOUND | — | | AgentChainIncompatibleError | AGENT_CHAIN_INCOMPATIBLE | incompatibleAgents, connectedChainId |

Cursor errors

InvalidHistoryCursorError is thrown by getHistory when the supplied cursor is invalid. It extends Error directly — not OwneyError — so a catch block that only checks instanceof OwneyError will not catch it. Catch it separately:

import { InvalidHistoryCursorError } from "@owney/sdk";

try {
  const page = await sdk.getHistory({ filters: { cursor: storedCursor } });
} catch (error) {
  if (error instanceof InvalidHistoryCursorError) {
    // Stored cursor is stale or malformed — reset pagination.
    storedCursor = undefined;
    // Refetch first page...
  } else {
    throw error;
  }
}

InvalidHistoryCursorError carries a stable code property (value: "invalid_cursor") and is thrown when:

  • The supplied cursor is an empty string.
  • The cursor is not valid base64 JSON.
  • The cursor payload has the wrong shape (e.g. a cursor from a different pagination context).

Recovery: catch InvalidHistoryCursorError, clear your stored cursor, and refetch from page 1.

| Class | code | Extends | | --------------------------- | ------------------ | ------- | | InvalidHistoryCursorError | "invalid_cursor" | Error |

License

ELv2