Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Yo Protocol SDK — Complete Reference
- ERC-4626 yield vault protocol on Ethereum, Base, and Arbitrum. All deposits/redeems route through a single Gateway contract. The SDK (`@yo-protocol/core`) wraps on-chain reads, write actions, prepared transactions, REST API queries, and Merkl reward claims.
- ## Table of Contents
- 1. [Installation & Initialization](#installation--initialization)
- 2. [Contract Addresses](#contract-addresses)
- 3. [Supported Chains](#supported-chains)
- 4. [Vault Registry](#vault-registry)
- 5. [API Reference — Vault Reads](#vault-reads-on-chain)
- 6. [API Reference — User Reads](#user-reads-on-chain)
- 7. [API Reference — Write Actions](#write-actions-require-wallet)
- 8. [API Reference — Prepared Transactions](#prepared-transactions-calldata-mode)
- 9. [API Reference — Gateway Quotes](#gateway-quote-helpers)
- 10. [API Reference — REST API](#rest-api-methods)
- 11. [API Reference — Merkl Rewards](#merkl-reward-methods)
- 12. [API Reference — Transaction Helpers](#transaction-helpers)
- 13. [TypeScript Interfaces](#typescript-interfaces)
- 14. [Utilities](#utilities)
- 15. [Workflow Examples](#workflow-examples)
- 16. [CLI Reference](#cli-yo-protocolcli)
- 17. [Important Gotchas](#important-gotchas)
- ---
- ## Installation & Initialization
- ```bash
- npm install @yo-protocol/core viem
- ```
- ```ts
- import { createYoClient } from '@yo-protocol/core'
- // Read-only (no wallet needed)
- const client = createYoClient({ chainId: 1 })
- // With wallet
- const client = createYoClient({ chainId: 8453, walletClient })
- // Custom RPC
- import { createPublicClient, http } from 'viem'
- import { mainnet } from 'viem/chains'
- const publicClient = createPublicClient({ chain: mainnet, transport: http('https://...') })
- const client = createYoClient({ chainId: 1, publicClient })
- ```
- `YoClientConfig`: `{ chainId: SupportedChainId, publicClient?: PublicClient, walletClient?: WalletClient, partnerId?: number }`
- ---
- ## Contract Addresses
- | Contract | Address |
- |----------|---------|
- | **Gateway** | `0xF1EeE0957267b1A474323Ff9CfF7719E964969FA` |
- | **Vault Registry** | `0x56c3119DC3B1a75763C87D5B0A2C55E489502232` |
- | **Oracle** | `0x6E879d0CcC85085A709eBf5539224f53d0D396B0` |
- | **Redeemer** | `0x0439e941841f97dc1334d1a433379c6fcdcc2162` |
- | **Merkl Distributor** (Base) | `0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae` |
- | **Merkl Creator** | `0x8C9200d94Cf7A1B201068c4deDa6239F15FED480` |
- | **YO Token** (Base) | `0x3C1a1c9C2D073E5bC4e7AF97f0d7caC7a82E2262` |
- Merkl API base: `https://api.merkl.xyz/v4`
- REST API base: `https://api.yo.xyz`
- ---
- ## Supported Chains
- | Chain | ID | Network Name |
- |-------|-----|-------------|
- | Ethereum | `1` | `ethereum` |
- | Base | `8453` | `base` |
- | Arbitrum | `42161` | `arbitrum` |
- Type: `SupportedChainId = 1 | 8453 | 42161`
- ---
- ## Vault Registry
- ### yoETH
- - **Address**: `0x3a43aec53490cb9fa922847385d82fe25d0e9de7`
- - **Underlying**: WETH (18 decimals)
- - **Chains**: Ethereum, Base
- - **Token addresses**:
- - Ethereum (1): `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`
- - Base (8453): `0x4200000000000000000000000000000000000006`
- ### yoBTC
- - **Address**: `0xbcbc8cb4d1e8ed048a6276a5e94a3e952660bcbc`
- - **Underlying**: cbBTC (8 decimals)
- - **Chains**: Ethereum, Base
- - **Token addresses**:
- - Ethereum (1): `0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf`
- - Base (8453): `0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf`
- ### yoUSD
- - **Address**: `0x0000000f2eb9f69274678c76222b35eec7588a65`
- - **Underlying**: USDC (6 decimals)
- - **Chains**: Ethereum, Base, Arbitrum
- - **Token addresses**:
- - Ethereum (1): `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`
- - Base (8453): `0x833589fcd6edb6e08f4c7c32d4f71b54bda02913`
- - Arbitrum (42161): `0xaf88d065e77c8cC2239327C5EDb3A432268e5831`
- ### yoEUR
- - **Address**: `0x50c749ae210d3977adc824ae11f3c7fd10c871e9`
- - **Underlying**: EURC (6 decimals)
- - **Chains**: Ethereum, Base
- - **Token addresses**:
- - Ethereum (1): `0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c`
- - Base (8453): `0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42`
- ### yoGOLD
- - **Address**: `0x586675A3a46B008d8408933cf42d8ff6c9CC61a1`
- - **Underlying**: XAUt (6 decimals)
- - **Chains**: Ethereum only
- - **Token addresses**:
- - Ethereum (1): `0x68749665FF8D2d112Fa859AA293F07A622782F38`
- ### yoUSDT
- - **Address**: `0xb9a7da9e90d3b428083bae04b860faa6325b721e`
- - **Underlying**: USDT (6 decimals)
- - **Chains**: Ethereum only
- - **Token addresses**:
- - Ethereum (1): `0xdac17f958d2ee523a2206206994597c13d831ec7`
- ### Programmatic Access
- ```ts
- import { VAULTS, getVaultsForChain, getVaultByAddress, YO_GATEWAY_ADDRESS } from '@yo-protocol/core'
- // Get all vaults for a chain
- const baseVaults = getVaultsForChain(8453)
- // Look up by address
- const vault = getVaultByAddress('0x0000000f2eb9f69274678c76222b35eec7588a65')
- // Get underlying token address for a specific chain
- const usdcOnBase = VAULTS.yoUSD.underlying.address[8453]
- ```
- ---
- ## Vault Reads (on-chain)
- ### `getVaults(): VaultConfig[]`
- Return known vault configs for the client's chain. No RPC call.
- ### `getVaultState(vault: Address): Promise<VaultState>`
- Full on-chain vault state: name, symbol, decimals, totalAssets, totalSupply, asset address, exchangeRate.
- ### `previewDeposit(vault: Address, assets: bigint): Promise<bigint>`
- ERC-4626 `previewDeposit` — how many shares for a given asset amount.
- ### `previewRedeem(vault: Address, shares: bigint): Promise<bigint>`
- ERC-4626 `previewRedeem` — how many assets for a given share amount.
- ### `convertToAssets(vault: Address, shares: bigint): Promise<bigint>`
- ERC-4626 `convertToAssets` — share-to-asset conversion without fees.
- ### `convertToShares(vault: Address, assets: bigint): Promise<bigint>`
- ERC-4626 `convertToShares` — asset-to-share conversion without fees.
- ### `isPaused(vault: Address): Promise<boolean>`
- Check if vault deposits are paused.
- ### `getIdleBalance(vault: Address): Promise<bigint>`
- Get vault's idle (uninvested) balance.
- ---
- ## User Reads (on-chain)
- ### `getTokenBalance(token: Address, account: Address): Promise<TokenBalance>`
- ERC-20 balance. Returns `{ token, balance, decimals }`.
- ### `getShareBalance(vault: Address, account: Address): Promise<bigint>`
- User's vault share balance (raw bigint).
- ### `getUserPosition(vault: Address, account: Address): Promise<UserVaultPosition>`
- User's position as `{ shares, assets }` — shares held and their asset value.
- ### `getAllowance(token: Address, owner: Address, spender: Address): Promise<TokenAllowance>`
- ERC-20 allowance. Returns `{ token, owner, spender, allowance }`.
- ### `hasEnoughAllowance(token: Address, owner: Address, spender: Address, amount: bigint): Promise<boolean>`
- Check if allowance >= amount.
- ---
- ## Write Actions (require wallet)
- All write methods require `walletClient` set via constructor or `setWalletClient()`.
- ### `approve(token: Address, amount: bigint, spender?: Address): Promise<ApproveResult>`
- ERC-20 approve. Spender defaults to Gateway. Returns `{ hash }`.
- ### `approveMax(token: Address, spender?: Address): Promise<ApproveResult>`
- Approve max uint256. Spender defaults to Gateway. Returns `{ hash }`.
- ### `deposit(params): Promise<DepositResult>`
- Deposit assets via Gateway. Returns `{ hash, shares }`.
- ```ts
- params: {
- vault: Address
- amount: bigint // asset amount to deposit
- recipient?: Address // defaults to wallet account
- slippageBps?: number // default 50 (0.5%)
- partnerId?: number // default from client config
- }
- ```
- ### `depositWithApproval(params): Promise<DepositWithApprovalResult>`
- Approve (if needed) + deposit in one call. Returns `{ approveHash?, depositHash, shares }`.
- ```ts
- params: {
- vault: Address
- token: Address // token to approve
- amount: bigint
- recipient?: Address
- slippageBps?: number
- partnerId?: number
- }
- ```
- ### `redeem(params): Promise<RedeemResult>`
- Redeem shares via Gateway. Returns `{ hash, assets }`.
- ```ts
- params: {
- vault: Address
- shares: bigint // shares to redeem
- recipient?: Address // defaults to wallet account
- slippageBps?: number // default 50
- minAssetsOut?: bigint // override slippage calc
- partnerId?: number
- }
- ```
- ---
- ## Prepared Transactions (calldata mode)
- For Safe multisig, Account Abstraction, or batched transactions. Returns `PreparedTransaction { to, data, value }`.
- ### `prepareApprove(params: { token, amount, spender? }): PreparedTransaction`
- Synchronous. No RPC call.
- ### `prepareDeposit(params): Promise<PreparedTransaction>`
- **Requires `recipient`** (unlike `deposit()`). Queries gateway for minShares.
- ### `prepareRedeem(params): Promise<PreparedTransaction>`
- **Requires `recipient`**. Queries gateway for minAssetsOut.
- ### `prepareDepositWithApproval(params): Promise<PreparedTransaction[]>`
- Returns array: `[approveTx?, depositTx]`. Checks on-chain allowance.
- ```ts
- params: {
- vault: Address
- token: Address
- owner: Address // token owner for allowance check
- amount: bigint
- recipient?: Address
- slippageBps?: number
- partnerId?: number
- }
- ```
- ---
- ## Gateway Quote Helpers
- On-chain reads against the Gateway contract (may differ from direct vault reads due to fees).
- ### `quotePreviewDeposit(vault: Address, assets: bigint): Promise<bigint>`
- ### `quotePreviewRedeem(vault: Address, shares: bigint): Promise<bigint>`
- ### `quotePreviewWithdraw(vault: Address, assets: bigint): Promise<bigint>`
- ### `quoteConvertToAssets(vault: Address, shares: bigint): Promise<bigint>`
- ### `quoteConvertToShares(vault: Address, assets: bigint): Promise<bigint>`
- ---
- ## Gateway Allowance Helpers
- ### `getShareAllowance(vault: Address, owner: Address): Promise<bigint>`
- Share allowance granted to the Gateway.
- ### `getAssetAllowance(vault: Address, owner: Address): Promise<bigint>`
- Asset allowance granted to the Gateway.
- ---
- ## REST API Methods
- Off-chain queries to `https://api.yo.xyz`. No RPC needed.
- ### `getVaultSnapshot(vault: Address): Promise<VaultSnapshot>`
- Comprehensive vault data: TVL, yield (1d/7d/30d), protocols, share price, idle balances.
- ### `getVaultYieldHistory(vault: Address): Promise<TimeseriesPoint[]>`
- Historical yield data. Returns `{ timestamp, value }[]`.
- ### `getVaultTvlHistory(vault: Address): Promise<TimeseriesPoint[]>`
- Historical TVL data. Returns `{ timestamp, value }[]`.
- ### `getUserHistory(vault: Address, user: Address, limit?: number): Promise<UserHistoryItem[]>`
- User transaction history (deposits, withdraws, redeems).
- ### `getUserPerformance(vault: Address, user: Address): Promise<UserPerformance>`
- User realized/unrealized P&L. Returns `{ realized: FormattedValue, unrealized: FormattedValue }`.
- ### `getUserPoints(user: Address): Promise<UserPoints | null>` *(deprecated)*
- Use `getUserPerformance` instead.
- ### `getPendingRedemptions(vault: Address, user: Address): Promise<PendingRedeem>`
- User's pending redeem requests.
- ### `getVaultPendingRedeems(vault: Address): Promise<PendingRedeem>`
- Total pending redeems for a vault.
- ---
- ## Merkl Reward Methods
- ### `getMerklCampaigns(options?: { status?: 'LIVE' | 'PAST' }): Promise<MerklCampaign[]>`
- List Yo-related Merkl campaigns.
- ### `getMerklRewards(user: Address): Promise<MerklChainRewards | null>`
- Raw API rewards for user on client's chain.
- ### `getMerklClaimedAmount(user: Address, token: Address): Promise<bigint>`
- On-chain claimed amount for a specific reward token.
- ### `getClaimableRewards(user: Address): Promise<MerklChainRewards | null>`
- **Preferred method.** Merges API rewards with on-chain claimed amounts for accurate claimable data.
- ### `claimMerklRewards(chainRewards: MerklChainRewards): Promise<ClaimMerklRewardsResult>`
- Claim rewards on-chain. Pass the result of `getClaimableRewards()`. Returns `{ hash }`.
- ### Utility methods (static-like)
- - `getMerklClaimableAmount(reward: MerklTokenReward): bigint` — claimable for single reward
- - `hasMerklClaimableRewards(chainRewards: MerklChainRewards): boolean` — any claimable?
- - `getMerklTotalClaimable(chainRewards: MerklChainRewards): Map<string, bigint>` — all claimable by token
- ---
- ## Transaction Helpers
- ### `waitForTransaction(hash): Promise<TransactionReceipt>`
- Wait for any tx confirmation. Returns `{ hash, status, blockNumber, gasUsed }`.
- ### `waitForRedeemReceipt(hash): Promise<RedeemReceipt>`
- Wait for redeem tx and decode the `YoGatewayRedeem` event. Returns `{ hash, status, instant, assetsOrRequestId, shares, blockNumber }`.
- ### `setWalletClient(walletClient: WalletClient): void`
- Set or change the wallet client after construction.
- ---
- ## TypeScript Interfaces
- ### Core Types
- ```ts
- type SupportedChainId = 1 | 8453 | 42161
- type VaultId = 'yoETH' | 'yoBTC' | 'yoUSD' | 'yoEUR' | 'yoGOLD' | 'yoUSDT'
- interface YoClientConfig {
- chainId: SupportedChainId
- publicClient?: PublicClient
- walletClient?: WalletClient
- partnerId?: number // default: 9999
- }
- ```
- ### Vault Types
- ```ts
- interface VaultState {
- address: Address
- name: string
- symbol: string
- decimals: number
- totalAssets: bigint
- totalSupply: bigint
- asset: Address
- assetDecimals: number
- exchangeRate: bigint
- }
- interface VaultConfig {
- address: Address
- name: string
- symbol: VaultId
- underlying: {
- symbol: string
- decimals: number
- address: Record<number, Address> // chainId -> token address
- }
- chains: readonly number[]
- }
- ```
- ### User Types
- ```ts
- interface UserVaultPosition {
- shares: bigint
- assets: bigint
- }
- interface TokenBalance {
- token: Address
- balance: bigint
- decimals: number
- }
- interface TokenAllowance {
- token: Address
- owner: Address
- spender: Address
- allowance: bigint
- }
- ```
- ### Action Results
- ```ts
- interface DepositResult {
- hash: Hash
- shares: bigint
- }
- interface DepositWithApprovalResult {
- approveHash?: Hash
- depositHash: Hash
- shares: bigint
- }
- interface RedeemResult {
- hash: Hash
- assets: bigint
- }
- interface ApproveResult {
- hash: Hash
- }
- interface TransactionReceipt {
- hash: Hash
- status: 'success' | 'reverted'
- blockNumber: bigint
- gasUsed: bigint
- }
- interface RedeemReceipt {
- hash: Hash
- status: 'success' | 'reverted'
- instant: boolean // true = assets received, false = queued
- assetsOrRequestId: bigint // assets if instant, request ID if queued
- shares: bigint
- blockNumber: bigint
- }
- interface PreparedTransaction {
- to: Address
- data: Hex
- value: bigint
- }
- ```
- ### API Types
- ```ts
- interface FormattedValue {
- raw: number | string
- formatted: string
- }
- interface VaultSnapshot {
- id: string
- name: string
- type?: string
- asset: { name, symbol, decimals, address, coingeckoId? }
- shareAsset: { name, symbol, decimals, address }
- chain: { id, name, nativeAsset?, explorer?, blockTime? }
- contracts: { vaultAddress, authorityAddress? }
- deployment?: { blockNumber, timestamp, txHash }
- protocols?: { name, allocation? }[]
- stats: {
- tvl: FormattedValue
- totalSupply?: FormattedValue
- maxCap?: FormattedValue
- yield: { '1d': string|null, '7d': string|null, '30d': string|null }
- rewardYield?: string|null
- sharePrice?: FormattedValue
- idleBalance?: FormattedValue
- investedBalance?: FormattedValue
- protocolStats?: ProtocolStat[]
- }
- lastUpdated?: number
- }
- interface TimeseriesPoint {
- timestamp: number
- value: number
- }
- interface UserHistoryItem {
- type: 'deposit' | 'withdraw' | 'redeem'
- timestamp: number
- assets: FormattedValue
- shares: FormattedValue
- txHash: string
- }
- interface UserPerformance {
- realized: FormattedValue
- unrealized: FormattedValue
- }
- interface PendingRedeem {
- assets?: FormattedValue
- shares?: FormattedValue
- }
- type Network = 'base' | 'ethereum' | 'arbitrum' | 'unichain' | 'tac' | 'plasma' | 'hyperevm'
- ```
- ### Merkl Types
- ```ts
- interface MerklToken {
- address: Address
- chainId: number
- decimals: number
- symbol: string
- name: string
- icon?: string
- }
- interface MerklCampaign {
- id: string
- computeChainId: number
- distributionChainId: number
- startTimestamp: number
- endTimestamp: number
- creatorAddress: string
- rewardToken: MerklToken
- amount: string
- Opportunity?: MerklOpportunity
- }
- interface MerklTokenReward {
- token: MerklToken
- amount: string // total earned (cumulative)
- claimed: string // already claimed
- proofs: string[] // merkle proofs for claiming
- }
- interface MerklChainRewards {
- chainId: number
- rewards: MerklTokenReward[]
- }
- interface ClaimMerklRewardsResult {
- hash: Hash
- }
- type MerklCampaignStatus = 'LIVE' | 'PAST'
- ```
- ---
- ## Utilities
- ### Formatting
- ```ts
- import { formatTokenAmount, parseTokenAmount, formatUsd, formatPercent, formatCompactNumber } from '@yo-protocol/core'
- formatTokenAmount(1000000n, 6) // "1"
- formatTokenAmount(1000000n, 6, { maxDecimals: 2 }) // "1"
- parseTokenAmount("1.5", 18) // 1500000000000000000n
- formatUsd(1234.5) // "$1,234.50"
- formatPercent(0.0534) // "5.34%"
- formatCompactNumber(1234567) // "1.23M"
- ```
- ### Math Helpers (big.js-based)
- All accept `string | number | bigint | Big`:
- `mul`, `div`, `add`, `sub`, `mulDiv`, `gt`, `gte`, `lt`, `lte`, `eq`, `toFixed`, `toNumber`, `abs`, `pow`, `sqrt`, `toBigInt`, `toStr`
- `applySlippage(value: bigint, slippageBps: number): bigint` — `value - (value * bps) / 10000`
- ### Validation
- ```ts
- import { validateAddress, validateAmount } from '@yo-protocol/core'
- validateAddress('0x...', 'vault') // throws if invalid
- validateAmount(100n, 'amount') // throws if <= 0
- ```
- ---
- ## Workflow Examples
- ### Deposit into a Vault
- ```ts
- import { createYoClient, VAULTS, parseTokenAmount } from '@yo-protocol/core'
- const client = createYoClient({ chainId: 1, walletClient })
- // 1. Check vault state
- const vault = VAULTS.yoUSD
- const state = await client.getVaultState(vault.address)
- const paused = await client.isPaused(vault.address)
- if (paused) throw new Error('Vault is paused')
- // 2. Parse amount (100 USDC)
- const amount = parseTokenAmount('100', vault.underlying.decimals) // 100_000_000n
- // 3. Deposit with auto-approval
- const result = await client.depositWithApproval({
- vault: vault.address,
- token: vault.underlying.address[1], // USDC on Ethereum
- amount,
- })
- console.log('Approve tx:', result.approveHash) // undefined if already approved
- console.log('Deposit tx:', result.depositHash)
- console.log('Shares received:', result.shares)
- ```
- ### Deposit (manual approve)
- ```ts
- import { YO_GATEWAY_ADDRESS } from '@yo-protocol/core'
- const token = VAULTS.yoUSD.underlying.address[1]
- const amount = parseTokenAmount('100', 6)
- // Check allowance first
- const hasAllowance = await client.hasEnoughAllowance(
- token, walletClient.account.address, YO_GATEWAY_ADDRESS, amount
- )
- if (!hasAllowance) {
- await client.approve(token, amount)
- }
- const result = await client.deposit({ vault: VAULTS.yoUSD.address, amount })
- ```
- ### Redeem from a Vault
- ```ts
- const vault = VAULTS.yoETH
- // Get user's share balance
- const shares = await client.getShareBalance(vault.address, userAddress)
- // Redeem all shares
- const result = await client.redeem({ vault: vault.address, shares })
- // Wait for receipt to check if instant or queued
- const receipt = await client.waitForRedeemReceipt(result.hash)
- if (receipt.instant) {
- console.log('Received assets:', receipt.assetsOrRequestId)
- } else {
- console.log('Queued. Request ID:', receipt.assetsOrRequestId)
- // Check pending redemptions via API
- const pending = await client.getPendingRedemptions(vault.address, userAddress)
- console.log('Pending:', pending)
- }
- ```
- ### Check All User Positions
- ```ts
- import { formatTokenAmount } from '@yo-protocol/core'
- const client = createYoClient({ chainId: 8453 })
- const vaults = client.getVaults() // vaults available on Base
- for (const vault of vaults) {
- const position = await client.getUserPosition(vault.address, userAddress)
- if (position.shares > 0n) {
- console.log(`${vault.symbol}: ${formatTokenAmount(position.assets, vault.underlying.decimals)} ${vault.underlying.symbol}`)
- }
- }
- ```
- ### Query Vault Performance (API)
- ```ts
- const client = createYoClient({ chainId: 1 })
- const snapshot = await client.getVaultSnapshot(VAULTS.yoUSD.address)
- console.log('TVL:', snapshot.stats.tvl.formatted)
- console.log('7d yield:', snapshot.stats.yield['7d'])
- const yieldHistory = await client.getVaultYieldHistory(VAULTS.yoUSD.address)
- const tvlHistory = await client.getVaultTvlHistory(VAULTS.yoUSD.address)
- ```
- ### User Performance & History
- ```ts
- const perf = await client.getUserPerformance(VAULTS.yoUSD.address, userAddress)
- console.log('Realized P&L:', perf.realized.formatted)
- console.log('Unrealized P&L:', perf.unrealized.formatted)
- const history = await client.getUserHistory(VAULTS.yoUSD.address, userAddress, 10)
- for (const item of history) {
- console.log(`${item.type} | ${item.assets.formatted} | ${item.txHash}`)
- }
- ```
- ### Claim Merkl Rewards (Base only)
- ```ts
- const client = createYoClient({ chainId: 8453, walletClient })
- // 1. Check for claimable rewards (merges API + on-chain data)
- const rewards = await client.getClaimableRewards(userAddress)
- if (!rewards || !client.hasMerklClaimableRewards(rewards)) {
- console.log('No claimable rewards')
- return
- }
- // 2. Inspect claimable amounts
- const claimable = client.getMerklTotalClaimable(rewards)
- for (const [token, amount] of claimable) {
- console.log(`Claimable: ${token} = ${amount}`)
- }
- // 3. Claim
- const result = await client.claimMerklRewards(rewards)
- console.log('Claim tx:', result.hash)
- ```
- ### Prepared Transactions (Safe / Account Abstraction)
- For multisig or batched execution — get raw calldata without sending.
- ```ts
- import { createYoClient, VAULTS, parseTokenAmount, YO_GATEWAY_ADDRESS } from '@yo-protocol/core'
- const client = createYoClient({ chainId: 1 })
- const vault = VAULTS.yoUSD
- const amount = parseTokenAmount('1000', 6)
- // Option A: Separate approve + deposit
- const approveTx = client.prepareApprove({
- token: vault.underlying.address[1],
- amount,
- })
- const depositTx = await client.prepareDeposit({
- vault: vault.address,
- amount,
- recipient: safeAddress, // required for prepare methods
- })
- // Submit both to Safe
- await safeSdk.createTransaction({ safeTransactionData: [approveTx, depositTx] })
- // Option B: Auto-check allowance + deposit
- const txs = await client.prepareDepositWithApproval({
- vault: vault.address,
- token: vault.underlying.address[1],
- owner: safeAddress,
- amount,
- recipient: safeAddress,
- })
- // txs = [approveTx, depositTx] or just [depositTx] if already approved
- // Prepare redeem
- const redeemTx = await client.prepareRedeem({
- vault: vault.address,
- shares: 1000000n,
- recipient: safeAddress,
- })
- ```
- Each `PreparedTransaction` has: `{ to: Address, data: Hex, value: bigint }`.
- ### Multi-Chain Setup
- ```ts
- // Create clients for each chain
- const ethClient = createYoClient({ chainId: 1 })
- const baseClient = createYoClient({ chainId: 8453 })
- const arbClient = createYoClient({ chainId: 42161 })
- // yoUSD is available on all three chains
- const ethSnapshot = await ethClient.getVaultSnapshot(VAULTS.yoUSD.address)
- const baseSnapshot = await baseClient.getVaultSnapshot(VAULTS.yoUSD.address)
- const arbSnapshot = await arbClient.getVaultSnapshot(VAULTS.yoUSD.address)
- // Note: underlying token addresses differ per chain!
- // Ethereum USDC: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
- // Base USDC: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
- // Arbitrum USDC: 0xaf88d065e77c8cC2239327C5EDb3A432268e5831
- ```
- ---
- ## CLI (`@yo-protocol/cli`)
- Alternative for shell-based agents. Install: `npm install -g @yo-protocol/cli`
- Global options: `--chain <1|8453|42161>`, `--rpc-url <url>`, `--raw` (treat amounts as raw bigint)
- | Command | Description |
- |---------|-------------|
- | `yo info vaults` | List all vaults |
- | `yo info chains` | List supported chains |
- | `yo info resolve <id>` | Resolve vault ID or address |
- | `yo read vault-state --vault yoUSD` | On-chain vault state |
- | `yo read token-balance --token <addr> --account <addr>` | ERC-20 balance |
- | `yo read share-balance --vault yoETH --account <addr>` | Vault share balance |
- | `yo read position --vault yoUSD --account <addr>` | User position (shares + assets) |
- | `yo read allowance --token <addr> --owner <addr>` | ERC-20 allowance |
- | `yo read preview-deposit --vault yoUSD --amount 100` | Preview deposit |
- | `yo read preview-redeem --vault yoUSD --shares 100` | Preview redeem |
- | `yo read max-deposit --vault yoUSD --receiver <addr>` | Max depositable |
- | `yo read max-redeem --vault yoUSD --owner <addr>` | Max redeemable |
- | `yo prepare approve --token <addr> --amount 100` | Build approve tx calldata |
- | `yo prepare deposit --vault yoUSD --amount 100 --recipient <addr>` | Build deposit tx |
- | `yo prepare redeem --vault yoUSD --shares 100 --recipient <addr>` | Build redeem tx |
- | `yo prepare deposit-with-approval --vault yoUSD --token <addr> --owner <addr> --amount 100` | Build approve+deposit txs |
- | `yo api vault-snapshot --vault yoUSD` | Vault snapshot from API |
- | `yo api vault-yield --vault yoUSD` | Yield timeseries |
- | `yo api vault-tvl --vault yoUSD` | TVL timeseries |
- | `yo api user-history --vault yoUSD --user <addr>` | User tx history |
- | `yo api user-pending --vault yoUSD --user <addr>` | Pending redemptions |
- ---
- ## Important Gotchas
- 1. **Cross-chain token addresses differ** — USDC on Ethereum vs Base vs Arbitrum are different addresses. Use `VAULTS[vaultId].underlying.address[chainId]` to get the correct one.
- 2. **Default slippage is 50 bps (0.5%)** — Override with `slippageBps` param.
- 3. **Redeems can be instant or queued** — Check `RedeemReceipt.instant`. If `false`, `assetsOrRequestId` is a request ID, not an asset amount.
- 4. **Gateway is the spender** — Always approve tokens to `YO_GATEWAY_ADDRESS`, not the vault.
- 5. **`getUserPoints` is deprecated** — Use `getUserPerformance(vault, user)` instead.
- 6. **Prepared transactions need a `recipient`** — Unlike direct calls, `prepareDeposit`/`prepareRedeem` require an explicit `recipient` address.
- 7. **Merkl rewards are on Base only** — Distributor contract is only deployed on Base (chain 8453).
- 8. **`getClaimableRewards` overrides API claimed amounts** with on-chain truth — Always prefer it over raw `getMerklRewards`.
Advertisement