Getting Started with Core
@symmio/trading-core is the framework-agnostic SDK. Every call is a plain function that takes a Config as its first argument — no hooks, no providers, no framework. Reach for it in a Node script (deposit bot, indexer), a non-React framework layer (Vue, Solid), or a React app that wants to bypass the hook layer.
Building a React UI? Use Getting Started with React instead — it wraps every one of these functions in a hook with caching and invalidation. Come back here when you need the raw calls.
1. Install
pnpm add @symmio/trading-core viemviem is the only peer dependency — bring your own copy.
2. Create a config
Every action and query-options factory receives a Config as its first argument. Create it once with createConfig and share it. The config never owns viem clients itself — you inject them through resolver callbacks, so you stay in control of the RPC and the wallet.
import { createConfig, SymmioSupportedChainId } from "@symmio/trading-core";
import { createPublicClient, http, zeroAddress } from "viem";
import { hyperEvm } from "viem/chains";
const publicClient = createPublicClient({ chain: hyperEvm, transport: http() });
const config = createConfig({
getClient: () => publicClient,
symmioConfig: {
// `affiliatesAddress` is required per chain. `zeroAddress` is fine for testing —
// trades open, but you earn no fee share. Register to collect fees (see below).
[SymmioSupportedChainId.HYPER_EVM]: { addresses: { affiliatesAddress: zeroAddress } },
},
});getClient is all a read-only config needs. Add getWalletClient when you want to send transactions — see step 4.
affiliatesAddress is required per chain — your frontend’s on-chain identity. For testing you can pass the zero
address (as above): trades still open, you just earn no fee share. For production, registration lets your
affiliate collect a share of trading fees. Then set the registered address. See
Register an Affiliate .
3. Read on-chain data
Every read is getXyz(config, params):
import { getUserSubAccounts } from "@symmio/trading-core";
const subs = await getUserSubAccounts(config, { user: "0xabc..." });
console.log(subs.map((sub) => sub.name));Want a cache? Every read also ships a matching getXyzQueryOptions(config, options) factory that returns a ready-made TanStack Query options bag — feed it into queryClient.fetchQuery or any framework’s query layer. See Query Options.
4. Send a transaction
Writes sign through the wallet client your config resolves. Add getWalletClient to createConfig, then call xyz(config, params):
import { createConfig, editAccountName, SymmioSupportedChainId } from "@symmio/trading-core";
import { createPublicClient, createWalletClient, http, zeroAddress } from "viem";
import { hyperEvm } from "viem/chains";
const config = createConfig({
getClient: () => createPublicClient({ chain: hyperEvm, transport: http() }),
getWalletClient: async () => createWalletClient({ account, chain: hyperEvm, transport: http() }),
// required per chain — zeroAddress for testing, a registered affiliate to earn fees
symmioConfig: { [SymmioSupportedChainId.HYPER_EVM]: { addresses: { affiliatesAddress: zeroAddress } } },
});
const hash = await editAccountName(config, {
account: "0xSubAccount...",
name: "Trading bot",
});A config with no getWalletClient is read-only; write actions throw NO_WALLET_CLIENT. Writes are also dry-run with simulateContract first by default — see simulateBeforeWrite.
Next steps
- Overview — the full catalog: contracts, unified quotes, price service, subgraph, Muon.
- Config — client resolvers, chain overrides, and the WebSocket constructor in full.
- Balance Model — which balance funds trading (deposit → trade; no allocate), and the two decimal scales.
- Errors — the
SymmError/SymmApiErrorcatalogue every action can throw.