What chains and assets are supported?
Zipper is Polyester's deposit/withdraw bridge. Its public configuration lists every supported chain, unified asset, and per-chain route — including network fees and minimums:
const config = await client.zipper.getDepositWithdrawConfig();The same data is easier to consume through the catalog's zipper reader, which adds lookups and conversions:
await client.catalog.ensureReady();
const chains = client.catalog.zipper.listChains();
const usdc = client.catalog.zipper.requireAssetBySymbol("USDC");
const route = client.catalog.zipper.requireAssetChain("USDC", "ethereum");Deposits
Create (or fetch) a deposit address for an account on a given chain, then send funds to it:
const address = await client.deposit.createAddress({ chainId });
const addresses = await client.deposit.listAddresses();Deposit addresses are per-account — pass account to get a subaccount's address.
Tracking with lifecycle flows
Cross-chain operations (deposits, withdrawals) progress through multi-step lifecycle flows. The lifecycle service reads and streams their state, so you can show users exactly where their funds are:
const { flows } = await client.lifecycle.listFlows({
/* kind/state/account filters */
});
const flow = await client.lifecycle.getFlow({ flowId });
// find the flow for a transaction hash
const byTx = await client.lifecycle.listFlowsByTx({ txHash });
// live progress
const unsubscribe = client.lifecycle.subscribeFlowDetail({
flowId,
onEvent: (detail) => updateProgress(detail),
});subscribeOpenFlows streams summaries of all open flows for an account.
Ledger transfers
Every balance movement is a ledger transfer. List and stream them:
const { transfers, nextPageToken } = await client.transfers.list({ limit: 50 });
const unsubscribe = client.transfers.subscribe({
accountId,
onEvent: (transfer) => console.log(transfer),
});Internal transfers
Move funds between Polyester accounts (root ↔ subaccount, or to another user) without touching a chain:
const result = await client.internalTransfers.create({
/* destination (root / subaccount / smart account), asset, decimal amount */
});Destinations can be resolved from user input with client.accounts.resolve(...), and saved ones
come from the address book (client.addressBook.listTransferDestinations()). Internal transfer
requests are idempotent.
Withdrawals from Trading
Withdrawals out of the Trading venue are signed intents. Two destinations:
// Trading → Funding (stays on Polyester)
await client.tradingWithdraws.createToFunding({
/* asset, decimal amount, destination, signature or walletSigner */
});
// Trading → an external chain
await client.tradingWithdraws.createToExternalChain({
/* asset, gross decimal amount, destination network + address, signature or walletSigner */
});Each intent includes a short deadline (~5 minutes), a nonce, and an idempotency key, and must be
signed — either pass a walletSigner for an EIP-712 wallet signature, or a precomputed payloadSignature when signing with API-key infrastructure.
client.guardSigner to co-sign protected actions: signProtectedAction / batchSignProtectedActions produce the approval
signatures, and createWallet / rotateWallet / exportWallet manage the backend guard wallet itself.On-chain actions with the smart account
For operations that require sending an actual chain transaction from the user's smart account
(rather than an API request), the @polyester/sdk/smart-account subpath wires viem +
account-abstraction against the environment's bundler and paymaster:
import {
createPolyesterSmartAccount,
createPolyesterSmartAccountClient,
sendPolyesterUserOperation,
} from "@polyester/sdk/smart-account";
const account = await createPolyesterSmartAccount({ environment, owner });
const smartAccountClient = createPolyesterSmartAccountClient(account, { environment });
await sendPolyesterUserOperation(smartAccountClient, {
calls: [
/* ... */
],
});sendPolyesterUserOperation estimates gas and applies a safety buffer before submitting. predictPolyesterSmartAccountAddress computes the account address without any RPC calls.