IWalletProvider implementation that you supply — either by using the ready-made implementations
in @sodax/wallet-sdk-core, or by writing your own against the interface contracts in
@sodax/sdk.
Table of Contents
- Supported provider interfaces
- WalletProviderSlot: compile-time enforcement
- wallet-sdk-core: ready-to-use implementations
- Config type reference per chain
- React integration: useWalletProvider
- Custom implementations
1. Supported provider interfaces
Every chain family has a named interface that@sodax/sdk exports:
All interfaces extend
WalletAddressProvider (from @sodax/sdk), which requires:
IWalletProvider. GetWalletProviderType<K> maps a
chain key or ChainType literal to the appropriate specific interface.
2. WalletProviderSlot: compile-time enforcement
Every SDK method that executes a transaction usesWalletProviderSlot<K, Raw> (defined in
packages/types/src/common/common.ts) to enforce the pairing between raw mode and the presence
of a wallet provider at compile time:
-
raw: true—walletProvideris forbidden (?: nevermakes any value a type error). The SDK returns an unsigned transaction payload (TxReturnType<K, true>, e.g.EvmRawTransaction). -
raw: false(or omitted) —walletProvideris required and is chain-narrowed to the exact interface forKviaGetWalletProviderType<K>. The SDK signs and broadcasts, returning a transaction hash (TxReturnType<K, false>, e.g.Hash). -
Chain narrowing flows from the chain key — when the caller passes a literal chain key such
as
ChainKeys.ETHEREUM_MAINNET, TypeScript preserves that as a value type, resolvingGetWalletProviderType<typeof ChainKeys.ETHEREUM_MAINNET>toIEvmWalletProviderautomatically.
3. wallet-sdk-core: ready-to-use implementations
Install the package:src/wallet-providers/<chain>/:
BaseWalletProvider
All nine provider classes extendBaseWalletProvider<TDefaults>:
super(config.defaults). Per-call overrides shallow-merge over the
stored defaults at invocation time — nested objects replace wholesale rather than deep-merging.
chainType discriminant
EveryI*WalletProvider interface declares readonly chainType as a string literal. This lets
both the SDK and application code discriminate at runtime without instanceof:
chainType values: 'EVM', 'BITCOIN', 'SOLANA', 'STELLAR', 'SUI', 'ICON',
'INJECTIVE', 'STACKS', 'NEAR'.
packages/sdk/src/shared/guards.ts also exposes named guards for the most common cases:
Dual config modes (private-key vs browser-extension)
Every provider accepts a discriminated-union config: one variant for server-side/script usage (private key) and one for dApp usage (pre-built client from a browser wallet). Discriminant mechanism varies by chain:
All config types include an optional
defaults field for per-method behavioral overrides.
Provider reference
4. Config type reference per chain
EVM (EvmWalletProvider)
EvmWalletDefaults accepts: sendTransaction, waitForTransactionReceipt, publicClient,
walletClient, transport (all optional; applied per-call via mergePolicy).
Solana (SolanaWalletProvider)
SolanaWalletDefaults accepts: connectionCommitment, connectionConfig, sendOptions,
confirmCommitment.
Sui (SuiWalletProvider)
rpcUrl still works as a deprecated alias for grpcUrl, and
the two are mutually exclusive. signTransaction takes the transaction positionally, so an
options-shaped signer such as dAppKit.signTransaction needs the wrapper above rather than a
direct assignment; walletAccount is dApp Kit’s UiWalletAccount, and naming it stops the wallet
signing with whichever account happens to be connected.
SuiWalletDefaults accepts: signAndExecuteTxn (dry-run toggle), getCoins (pagination limit).
ICON (IconWalletProvider)
IconWalletDefaults accepts: stepLimit, version, timestampProvider, jsonRpcId.
Note:rpcUrlis typed as`http${string}`(template literal), not a barestring. EVM and InjectiverpcUrlfields have the same constraint. If you pass astringfrom an environment variable, either narrow it explicitly (e.g.process.env.RPC_URL as \http$“) or validate at the boundary.
Injective (InjectiveWalletProvider)
InjectiveWalletDefaults accepts: defaultFunds, defaultMemo, sequence, accountNumber.
Stellar (StellarWalletProvider)
StellarWalletDefaults accepts: pollInterval, pollTimeout, networkPassphrase.
Stacks (StacksWalletProvider)
StacksWalletDefaults accepts: network ('mainnet' | 'testnet'), postConditionMode.
Bitcoin (BitcoinWalletProvider)
BitcoinWalletDefaults accepts: defaultFinalize (whether to finalize PSBTs before returning).
NEAR (NearWalletProvider)
NearWalletDefaults accepts: throwOnFailure, waitUntil, gasDefault, depositDefault.
5. React integration: useWalletProvider
packages/wallet-sdk-react provides useWalletProvider — a hook that reads the chain-appropriate
provider from the Zustand store and returns it typed to the correct I*WalletProvider interface.
xChainId or xChainType, never both — the hook asserts this at runtime and the
overloads enforce it at compile time.
The returned provider is ready to pass directly into any SDK call’s walletProvider slot:
- Provider-managed chains (EVM, Solana, Sui) — Hydrator components (
EvmHydrator,SolanaHydrator,SuiHydrator) sync the native SDK state into the store as the sole writers. - Non-provider chains (Bitcoin, ICON, Injective, Stellar, NEAR, Stacks) — providers are
created as a side-effect of
setXConnection()in the store, triggered when a user connects a wallet throughChainActions.
config prop to SodaxWalletProvider:
useWalletProvider will return
undefined for disabled chains and emit a one-time console warning.
6. Custom implementations
You can implement the SDK interfaces directly without using@sodax/wallet-sdk-core. Each
interface is defined in @sodax/sdk (e.g. IEvmWalletProvider in @sodax/sdk):
- Declare
readonly chainType = '<CHAIN>' as const— the SDK anduseWalletProviderboth read this field for runtime dispatch. The value must exactly match thechainTypeliteral of the target interface. - Implement every method on the interface — TypeScript will flag missing methods at compile time.
- No base class required — extending
BaseWalletProvideris optional; it only provides thedefaultsstorage and merge helpers from@sodax/wallet-sdk-core. - EVM providers must honor
options.expectedChainId— refuse to broadcast when the wallet’s active chain id differs; ignoring it silently disables the SDK’s wrong-chain protection. A provider that already declares its own second options parameter must widen it toYourOptions & EvmSendTransactionOptionsto keep satisfying the interface.