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
- Supported Chains — the address book and chainId table.
- Approve and deposit recipe — the full apxUSD → apyUSD round-trip end-to-end.
- SDK Reference: createApyxClient — every option, every error.
- CLI Reference: REPL — interactive shell with the
exact same
apyxclient constructed for you.