Supported Chains
Two chains ship as built-in: Ethereum mainnet (chainId 1) and
Base mainnet (chainId 8453). Every other chainId throws
UnsupportedChainError at createApyxClient time —
the SDK fails fast rather than constructing a half-broken client.
- Address book
- Address checksumming and immutability
apyUSDRateViewis optional per chain- Overriding addresses (forks, testnets, custom deployments)
- Adding a new chain
Address book
| Chain | chainId | apxUSD | apyUSD | apyUSDRateView |
|---|---|---|---|---|
| Ethereum mainnet | 1 | 0x98A878b1Cd98131B271883B390f68D2c90674665 | 0x38EEb52F0771140d10c4E9A9a72349A329Fe8a6A | 0xab3Aa53D942cbFb58773856BdE4F3c3EFbaf0fDc |
| Base mainnet | 8453 | 0xD993935E13851dd7517af10687EC7e5022127228 | 0x2c271ddF484aC0386d216eB7eB9Ff02D4Dc0F6AA | — |
The same table lives in code at src/addresses.ts — that file is
the source of truth and the registry the SDK reads at runtime. If a
chain ever goes missing here but exists in the source, file an issue.
Address checksumming and immutability
createApyxClient runs every address — built-in and overridden alike —
through getAddress from viem. That serves two purposes:
- Validation. A malformed address (non-hex, wrong length, bad
case-checksum) raises
InvalidAddressErrorat construction. Failure is loud and immediate, not at first call. - Normalization. The returned
apyx.addressesobject always holds EIP-55 checksummed strings, regardless of the case you pass in.
The result is also Object.freezed — apyx.addresses cannot be mutated
in place after construction, even by accident.
apyUSDRateView is optional per chain
The on-chain rate view contract is deployed on Ethereum but not on
Base. The SDK reflects that in the type system: apyx.apyUSDRateView
is typed as RateViewModule | undefined. Always guard with ?.:
const apy = await apyx.apyUSDRateView?.apy();
// ^^^^^^^^
// undefined on chains where the rate view isn't deployed
Calling without the optional chain on Base would be a compile-time error.
If you need to compute the same value off-chain (e.g. to compare),
combine apyUSD.exchangeRate() with a historical reference rate; see
the APY recipe.
Overriding addresses (forks, testnets, custom deployments)
The built-in registry covers the live mainnet deployments. To target a
fork or a custom redeploy, pass addresses at construction:
const apyx = createApyxClient({
chain: mainnet,
transport: http('http://127.0.0.1:8545'),
addresses: {
apyUSD: '0xYourFork...',
// apxUSD + apyUSDRateView fall back to the built-in mainnet values
},
});
A partial override is merged onto the built-in registry — you only need
to specify the fields you’re moving. Each override goes through the
same getAddress validation and freezes into apyx.addresses like any
other entry.
This is the path used by every e2e test that runs against an anvil mainnet fork (see E2E testing).
Adding a new chain
The matrix above is short on purpose: more deployments lands as the
protocol expands. Track the add list in
src/addresses.ts — a new chainId entry there ripples through
to the SDK and CLI without code changes elsewhere.
If you’re consuming the SDK on a chain we haven’t listed and the
contract is already deployed there, override addresses and tell us —
we’d rather generalise the registry than have every consumer hand-roll
the same mapping.