Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quickstart

Read the live exchange rate of apyUSD on Ethereum mainnet in five lines. Then layer in writes (approve + deposit) once you’ve signed in with an account.

A read-only client

createApyxClient is the single entry point. With just a chain and a transport, you get every read method on apxUSD, apyUSD, and apyUSDRateView:

import { createApyxClient } from '@koed_jang/apyx-sdk';
import { http } from 'viem';
import { mainnet } from 'viem/chains';

const apyx = createApyxClient({
  chain: mainnet,
  transport: http(process.env.ETH_RPC_URL),
});

// apyUSD (ERC-4626 vault) reads
const exchangeRate = await apyx.apyUSD.exchangeRate();   // 1e18-scaled: 1 share -> assets
const totalAssets  = await apyx.apyUSD.totalAssets();
const shares       = await apyx.apyUSD.convertToShares(1_000_000n);

// On-chain rate view
const apy        = await apyx.apyUSDRateView?.apy();           // 18-dec fraction
const annualized = await apyx.apyUSDRateView?.annualizedYield();

// apxUSD (ERC-20) reads
const balance = await apyx.apxUSD.balanceOf('0x...');

apyUSDRateView is optional-by-chain — it exists on Ethereum but not on Base — so it’s typed apyUSDRateView?: and you guard with ?.. See Supported Chains for the full address matrix.

If process.env.ETH_RPC_URL is unset, the default public RPC kicks in. For real workloads pass an Alchemy / Infura / private endpoint — see the Custom RPC recipe.

Adding writes

To send transactions, pass an account at construction. Only then are approve, transfer, deposit, redeem, and permit exposed:

import { privateKeyToAccount } from 'viem/accounts';

const apyx = createApyxClient({
  chain: mainnet,
  transport: http(process.env.ETH_RPC_URL),
  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
});

const approve = await apyx.apxUSD.approve({
  spender: apyx.addresses.apyUSD,
  amount: 1_000_000n,
});
await approve.wait();

const deposit = await apyx.apyUSD.deposit({
  assets: 1_000_000n,
  receiver: apyx.walletClient!.account!.address,
});
await deposit.wait();

Calling a write without account throws WalletClientRequiredError. Construct the client once, fork it for read vs write contexts:

const reader = createApyxClient({ chain: mainnet, transport: http() });
const writer = createApyxClient({ chain: mainnet, transport: http(), account });

The two clients hit the same RPC; only the wallet-side primitives differ.

What returns what

Read methods resolve directly to a value. Write methods resolve to an intermediate “tx handle” you can .wait() on:

const tx = await apyx.apyUSD.deposit({ assets, receiver });
//    ^^^^ TxHandle: { hash, wait, transactionHash }
const receipt = await tx.wait();
//    ^^^^^^^ viem's TransactionReceipt

This avoids hidden round-trips: you can fan out multiple submissions and await receipts in parallel, log the hash to a UI immediately, etc.

Where to next