createApyxClient
The single factory function. Pass a chain and a transport; receive a fully-typed client whose three contract modules know exactly which addresses to call.
import { createApyxClient } from '@koed_jang/apyx-sdk';
import { http } from 'viem';
import { mainnet } from 'viem/chains';
const apyx = createApyxClient({ chain: mainnet, transport: http() });
Signature
function createApyxClient(config: ApyxClientConfig): ApyxClient;
type ApyxClientConfig = {
chain: Chain;
transport: Transport;
walletTransport?: Transport;
account?: Account | Address;
addresses?: Partial<ApyxAddresses>;
};
| Field | Required | Effect |
|---|---|---|
chain | yes | viem Chain object. Drives chainId-based address lookup, gas estimation, and EIP-1559 vs legacy tx defaults. |
transport | yes | viem Transport. Used for reads by the underlying publicClient, and for writes too unless walletTransport is set. Typically http(rpcUrl). |
walletTransport | no | Separate transport for writes. Set this to custom(window.ethereum) in dApps while keeping transport: http(rpc) for reads — gives you a low-latency public RPC for state and the user’s wallet for signing. |
account | no | Either a viem Account (e.g. privateKeyToAccount(...), a hardware-wallet account from a custom toAccount) or a bare Address. When omitted no walletClient is created and write methods throw WalletClientRequiredError. |
addresses | no | Partial<ApyxAddresses> overlay. Useful for forks, custom redeploys, or chains where you want to point the SDK at a non-canonical address. Each field is independently optional and falls back to the built-in registry; see Addresses for the merge semantics. |
Return type
interface ApyxClient {
chain: Chain;
addresses: Readonly<ApyxAddresses>;
publicClient: PublicClient;
walletClient?: WalletClient;
apxUSD: ApxUSD;
apyUSD: ApyUSD;
apyUSDRateView?: ApyUSDRateView;
}
interface ApyxClientCore {
chain: Chain;
addresses: Readonly<ApyxAddresses>;
publicClient: PublicClient;
walletClient?: WalletClient;
}
ApyxClientCore is the subset of ApyxClient that contract modules
receive at construction. It’s exported because consumers occasionally
build their own helpers that take a “client core” — pass it
{ chain, addresses, publicClient, walletClient } and you can
construct your own apxUSD/apyUSD instances against the same fields.
What the factory does
- Resolves addresses. Looks up
chain.idinAPYX_ADDRESSES; throwsUnsupportedChainErrorfor any unknown chainId. - Merges overrides.
{...builtin, ...config.addresses}. - Validates and freezes addresses. Each non-null entry runs through
viem.isAddress(value, { strict: true }). Failure raisesInvalidAddressError. The result isObject.freezed soapyx.addressescannot be mutated post-construction. - Builds clients. A
publicClientis always built. AwalletClientis built only whenaccountis non-null. - Wires modules.
apxUSD(core),apyUSD(core), and (if the chain has aapyUSDRateViewaddress)apyUSDRateView(core, address).
sequenceDiagram
participant U as Caller
participant F as createApyxClient
participant V as viem
U->>F: { chain, transport, account?, addresses? }
F->>F: lookup APYX_ADDRESSES[chain.id]
alt unknown chain
F-->>U: throw UnsupportedChainError
end
F->>F: merge overrides
F->>V: isAddress(strict) for each field
alt malformed
F-->>U: throw InvalidAddressError
end
F->>F: Object.freeze(addresses)
F->>V: createPublicClient(chain, transport)
alt account passed
F->>V: createWalletClient(chain, walletTransport ?? transport, account)
end
F->>F: wire apxUSD / apyUSD / apyUSDRateView modules
F-->>U: ApyxClient
Errors thrown at construction
| Error | When | How to recover |
|---|---|---|
UnsupportedChainError | chain.id is not in the built-in registry | Either pass a supported chain (Ethereum or Base) or override addresses with the redeploy targets. |
InvalidAddressError | A built-in or overridden address fails viem.isAddress({ strict: true }) | Provide a properly checksummed (or all-lowercase) hex address of the right length. |
Errors are thrown synchronously from createApyxClient itself — there
is no async construction path. A successfully returned ApyxClient is
guaranteed to have valid, frozen addresses.
Common patterns
Read-only client for a UI
const apyx = createApyxClient({
chain: mainnet,
transport: http(import.meta.env.VITE_ETH_RPC_URL),
});
Browser dApp — public RPC + injected wallet
const apyx = createApyxClient({
chain: mainnet,
transport: http(rpcUrl), // reads via Alchemy / etc
walletTransport: custom(window.ethereum), // writes via the user's wallet
account: userAddress, // populated after eth_requestAccounts
});
Server-side worker with a private key
const apyx = createApyxClient({
chain: mainnet,
transport: http(process.env.RPC_URL),
account: privateKeyToAccount(process.env.PK as `0x${string}`),
});
Anvil fork test
const apyx = createApyxClient({
chain: mainnet,
transport: http('http://127.0.0.1:8545'),
account: testAccount,
addresses: {
apyUSD: '0xRedeployedFork...', // partial override
},
});