# Setup Wallet Providers

The SODAX SDK does not force you to use a specific wallet library. Instead, SDK calls accept an `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

1. [Supported provider interfaces](#1-supported-provider-interfaces)
2. [WalletProviderSlot — compile-time enforcement](#2-walletproviderslot--compile-time-enforcement)
3. [wallet-sdk-core: ready-to-use implementations](#3-wallet-sdk-core-ready-to-use-implementations)
   * [BaseWalletProvider](#basewalletprovider)
   * [chainType discriminant](#chaintype-discriminant)
   * [Dual config modes (private-key vs browser-extension)](#dual-config-modes-private-key-vs-browser-extension)
   * [Provider reference](#provider-reference)
4. [Config type reference per chain](#4-config-type-reference-per-chain)
5. [React integration — useWalletProvider](#5-react-integration--usewalletprovider)
6. [Custom implementations](#6-custom-implementations)

***

## 1. Supported provider interfaces

Every chain family has a named interface that `@sodax/sdk` exports:

| Interface                  | `chainType` literal | Chains covered                                                                                                |
| -------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------- |
| `IEvmWalletProvider`       | `'EVM'`             | Sonic (hub), Ethereum, Arbitrum, Base, BSC, Optimism, Polygon, Avalanche, HyperEVM, Lightlink, Redbelly, Kaia |
| `ISolanaWalletProvider`    | `'SOLANA'`          | Solana                                                                                                        |
| `ISuiWalletProvider`       | `'SUI'`             | Sui                                                                                                           |
| `IIconWalletProvider`      | `'ICON'`            | ICON                                                                                                          |
| `IInjectiveWalletProvider` | `'INJECTIVE'`       | Injective                                                                                                     |
| `IStellarWalletProvider`   | `'STELLAR'`         | Stellar                                                                                                       |
| `IStacksWalletProvider`    | `'STACKS'`          | Stacks                                                                                                        |
| `IBitcoinWalletProvider`   | `'BITCOIN'`         | Bitcoin                                                                                                       |
| `INearWalletProvider`      | `'NEAR'`            | NEAR                                                                                                          |

All interfaces extend `WalletAddressProvider` (from `@sodax/sdk`), which requires:

```ts
getWalletAddress(): Promise<string>;
```

The full union of all nine interfaces is `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 uses `WalletProviderSlot<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:

```ts
export type WalletProviderSlot<K extends SpokeChainKey | ChainType, Raw extends boolean = false> =
  Raw extends true
    ? { raw: true; walletProvider?: never }
    : { raw?: false; walletProvider: GetWalletProviderType<K> };
```

Three rules enforced by TypeScript:

1. **`raw: true`** — `walletProvider` is forbidden (`?: never` makes any value a type error). The SDK returns an unsigned transaction payload (`TxReturnType<K, true>`, e.g. `EvmRawTransaction`).
2. **`raw: false` (or omitted)** — `walletProvider` is required and is chain-narrowed to the exact interface for `K` via `GetWalletProviderType<K>`. The SDK signs and broadcasts, returning a transaction hash (`TxReturnType<K, false>`, e.g. `Hash`).
3. **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, resolving `GetWalletProviderType<typeof ChainKeys.ETHEREUM_MAINNET>` to `IEvmWalletProvider` automatically.

```ts
// Raw — walletProvider is a compile error if passed
const rawTx = await sodax.swaps.createIntent({ params, raw: true });

// Signed — walletProvider is required; passing an ISolanaWalletProvider here is a compile error
const result = await sodax.swaps.createIntent({
  params,
  raw: false,
  walletProvider: evmWalletProvider,   // must be IEvmWalletProvider
});
```

***

## 3. wallet-sdk-core: ready-to-use implementations

Install the package:

```bash
npm install @sodax/wallet-sdk-core
# or
yarn add @sodax/wallet-sdk-core
# or
pnpm add @sodax/wallet-sdk-core
```

The package is dependency-free from React and can be used directly in Node.js scripts, bots, and server environments, as well as in browser dApps.

Each chain provider lives under `src/wallet-providers/<chain>/`:

```
wallet-providers/
├── BaseWalletProvider.ts      # Abstract base
├── evm/                       # EvmWalletProvider + types
├── solana/                    # SolanaWalletProvider + types
├── sui/                       # SuiWalletProvider + types
├── icon/                      # IconWalletProvider + types
├── injective/                 # InjectiveWalletProvider + types
├── stellar/                   # StellarWalletProvider + types
├── stacks/                    # StacksWalletProvider + types
├── bitcoin/                   # BitcoinWalletProvider + types
└── near/                      # NearWalletProvider + types
```

### BaseWalletProvider

All nine provider classes extend `BaseWalletProvider<TDefaults>`:

```ts
abstract class BaseWalletProvider<TDefaults extends object> {
  protected readonly defaults: TDefaults;

  abstract getWalletAddress(): Promise<string>;

  // Merge per-call options over defaults[key] (used for per-method defaults groups, e.g. EVM)
  protected mergePolicy<K extends keyof TDefaults>(key: K, options?: …): …

  // Merge per-call options over the entire defaults object (used for flat defaults, e.g. ICON)
  protected mergeDefaults(options?: Partial<TDefaults>): TDefaults
}
```

Subclass constructors call `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

Every `I*WalletProvider` interface declares `readonly chainType` as a string literal. This lets both the SDK and application code discriminate at runtime without `instanceof`:

```ts
// Discriminate without instanceof
if (walletProvider.chainType === 'EVM') {
  // walletProvider is narrowed to IEvmWalletProvider
}
if (walletProvider.chainType === 'SOLANA') {
  // walletProvider is narrowed to ISolanaWalletProvider
}
```

Valid `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:

```ts
isEvmWalletProviderType(wp)      // IEvmWalletProvider
isStellarWalletProviderType(wp)  // IStellarWalletProvider
isBitcoinWalletProviderType(wp)  // IBitcoinWalletProvider
```

### 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:

| Mechanism                                                                             | Chains                                          |
| ------------------------------------------------------------------------------------- | ----------------------------------------------- |
| **Field presence** — `privateKey` field present vs. absent                            | EVM, ICON, Solana, Sui (uses `mnemonics`), NEAR |
| **Explicit `type` field** (`'PRIVATE_KEY'` / `'BROWSER_EXTENSION'`)                   | Bitcoin, Stellar                                |
| **`secret` nested object** (`{ privateKey }` or `{ mnemonics }`) vs. `msgBroadcaster` | Injective                                       |
| **Field presence** — `privateKey` present vs. absent                                  | Stacks                                          |

All config types include an optional `defaults` field for per-method behavioral overrides.

### Provider reference

| Chain           | Provider class            | Native SDK            | `chainType`   |
| --------------- | ------------------------- | --------------------- | ------------- |
| EVM (12 chains) | `EvmWalletProvider`       | viem                  | `'EVM'`       |
| Solana          | `SolanaWalletProvider`    | @solana/web3.js       | `'SOLANA'`    |
| Sui             | `SuiWalletProvider`       | @mysten/sui           | `'SUI'`       |
| ICON            | `IconWalletProvider`      | icon-sdk-js           | `'ICON'`      |
| Injective       | `InjectiveWalletProvider` | @injectivelabs/sdk-ts | `'INJECTIVE'` |
| Stellar         | `StellarWalletProvider`   | @stellar/stellar-sdk  | `'STELLAR'`   |
| Stacks          | `StacksWalletProvider`    | @stacks/transactions  | `'STACKS'`    |
| Bitcoin         | `BitcoinWalletProvider`   | bitcoinjs-lib (PSBT)  | `'BITCOIN'`   |
| NEAR            | `NearWalletProvider`      | near-api-js           | `'NEAR'`      |

***

## 4. Config type reference per chain

### EVM (`EvmWalletProvider`)

```ts
// Private-key mode (scripts / bots)
new EvmWalletProvider({
  privateKey: '0x…',              // hex private key
  chainId: ChainKeys.ARBITRUM_MAINNET,
  rpcUrl: 'https://…',           // optional; falls back to viem default
  defaults?: EvmWalletDefaults,
});

// Browser-extension mode (dApps — wagmi supplies the clients)
new EvmWalletProvider({
  walletClient: viemWalletClient,  // WalletClient<Transport, Chain, Account>
  publicClient: viemPublicClient,
  defaults?: EvmWalletDefaults,
});
```

`EvmWalletDefaults` accepts: `sendTransaction`, `waitForTransactionReceipt`, `publicClient`, `walletClient`, `transport` (all optional; applied per-call via `mergePolicy`).

### Solana (`SolanaWalletProvider`)

```ts
// Private-key mode
new SolanaWalletProvider({
  privateKey: Uint8Array,   // raw keypair bytes
  endpoint: 'https://…',
  defaults?: SolanaWalletDefaults,
});

// Browser-extension mode
new SolanaWalletProvider({
  wallet: walletContextState,  // { publicKey, signTransaction }
  endpoint: 'https://…',
  defaults?: SolanaWalletDefaults,
});
```

`SolanaWalletDefaults` accepts: `connectionCommitment`, `connectionConfig`, `sendOptions`, `confirmCommitment`.

### Sui (`SuiWalletProvider`)

```ts
// Private-key mode (mnemonic-derived)
new SuiWalletProvider({
  rpcUrl: 'https://…',
  mnemonics: 'word1 word2 …',
  defaults?: SuiWalletDefaults,
});

// Browser-extension mode
new SuiWalletProvider({
  client: suiClient,
  wallet: walletWithFeatures,
  account: walletAccount,
  defaults?: SuiWalletDefaults,
});
```

`SuiWalletDefaults` accepts: `signAndExecuteTxn` (dry-run toggle + response options), `getCoins` (pagination limit).

### ICON (`IconWalletProvider`)

```ts
// Private-key mode
new IconWalletProvider({
  privateKey: '0x…',
  rpcUrl: 'https://…',
  defaults?: IconWalletDefaults,
});

// Browser-extension mode (Hana Wallet)
new IconWalletProvider({
  walletAddress?: '0xhx…',   // optional pre-known address
  rpcUrl: 'https://…',
  defaults?: IconWalletDefaults,
});
```

`IconWalletDefaults` accepts: `stepLimit`, `version`, `timestampProvider`, `jsonRpcId`.

> **Note:** `rpcUrl` is typed as `` `http${string}` `` (template literal), not a bare `string`. EVM and Injective `rpcUrl` fields have the same constraint. If you pass a `string` from an environment variable, either narrow it explicitly (e.g. `process.env.RPC_URL as \`http${string}\`\`) or validate at the boundary.

### Injective (`InjectiveWalletProvider`)

```ts
// Private-key / mnemonic mode (credentials nested under `secret`)
new InjectiveWalletProvider({
  secret: { privateKey: '0x…' },   // OR { mnemonics: 'word1 word2 …' }
  chainId: ChainId.Mainnet,
  network: Network.Mainnet,
  defaults?: InjectiveWalletDefaults,
});

// Browser-extension mode
new InjectiveWalletProvider({
  msgBroadcaster: msgBroadcaster,   // MsgBroadcaster from @injectivelabs/wallet-core
  defaults?: InjectiveWalletDefaults,
});
```

`InjectiveWalletDefaults` accepts: `defaultFunds`, `defaultMemo`, `sequence`, `accountNumber`.

### Stellar (`StellarWalletProvider`)

```ts
// Private-key mode (explicit `type` field)
new StellarWalletProvider({
  type: 'PRIVATE_KEY',
  privateKey: 'S…',                // Stellar secret key (S-prefixed), typed as `Hex` string alias
  network: 'PUBLIC',               // or 'TESTNET'
  rpcUrl?: 'https://…',
  defaults?: StellarWalletDefaults,
});

// Browser-extension mode
new StellarWalletProvider({
  type: 'BROWSER_EXTENSION',
  walletsKit: stellarWalletsKit,   // StellarWalletsKit interface
  network: 'PUBLIC',
  rpcUrl?: 'https://…',
  defaults?: StellarWalletDefaults,
});
```

`StellarWalletDefaults` accepts: `pollInterval`, `pollTimeout`, `networkPassphrase`.

### Stacks (`StacksWalletProvider`)

```ts
// Private-key mode
new StacksWalletProvider({
  privateKey: 'string',
  endpoint?: 'https://…',
  defaults?: StacksWalletDefaults,
});

// Browser-extension mode
new StacksWalletProvider({
  address: 'string',
  endpoint?: 'https://…',
  provider?: stacksProvider,   // StacksProvider from @stacks/connect
  defaults?: StacksWalletDefaults,
});
```

`StacksWalletDefaults` accepts: `network` (`'mainnet'` | `'testnet'`), `postConditionMode`.

### Bitcoin (`BitcoinWalletProvider`)

```ts
// Private-key mode (explicit `type` field)
new BitcoinWalletProvider({
  type: 'PRIVATE_KEY',
  privateKey: '0x…',
  network: 'MAINNET',            // or 'TESTNET'
  addressType?: BtcAddressType,  // 'P2PKH' | 'P2SH' | 'P2WPKH' | 'P2TR'
  defaults?: BitcoinWalletDefaults,
});

// Browser-extension mode
new BitcoinWalletProvider({
  type: 'BROWSER_EXTENSION',
  walletsKit: bitcoinWalletsKit,  // BitcoinWalletsKit interface
  network: 'MAINNET',
  defaults?: BitcoinWalletDefaults,
});
```

`BitcoinWalletDefaults` accepts: `defaultFinalize` (whether to finalize PSBTs before returning).

### NEAR (`NearWalletProvider`)

```ts
// Private-key mode
new NearWalletProvider({
  rpcUrl: 'https://…',
  accountId: 'alice.near',
  privateKey: 'ed25519:…',
  defaults?: NearWalletDefaults,
});

// Browser-extension mode
new NearWalletProvider({
  wallet: nearConnector,   // NearConnector from @hot-labs/near-connect
  defaults?: NearWalletDefaults,
});
```

`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.

```ts
import { useWalletProvider } from '@sodax/wallet-sdk-react';
import { ChainKeys } from '@sodax/sdk';

// By chain key — return type is narrowed to IEvmWalletProvider | undefined
const walletProvider = useWalletProvider({ xChainId: ChainKeys.ETHEREUM_MAINNET });

// By chain type — return type is IEvmWalletProvider | undefined
const walletProvider = useWalletProvider({ xChainType: 'EVM' });
```

Pass `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:

```ts
const result = await sodax.swaps.createIntent({
  params: { srcChainKey: ChainKeys.ETHEREUM_MAINNET, … },
  raw: false,
  walletProvider,   // typed as IEvmWalletProvider; compile error if chain mismatch
});
```

Wallet providers are populated into the store by:

* **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 through `ChainActions`.

Configure which chains are active by passing a `config` prop to `SodaxWalletProvider`:

```ts
import { SodaxWalletProvider } from '@sodax/wallet-sdk-react';
import { ChainKeys } from '@sodax/sdk';

<SodaxWalletProvider config={{
  EVM: {
    chains: {
      [ChainKeys.ARBITRUM_MAINNET]: { rpcUrl: 'https://…' },
      [ChainKeys.BASE_MAINNET]:     { rpcUrl: 'https://…' },
    },
    // EVM adapter also supports:
    walletConnect: { projectId: 'YOUR_WC_PROJECT_ID' }, // enables WalletConnect-based wallets (Fireblocks, Ledger Live, etc.)
    ssr: true, // safe SSR hydration when rendering in Next.js
  },
  SOLANA: { chains: { [ChainKeys.SOLANA_MAINNET]: { rpcUrl: 'https://…' } } },
  BITCOIN: {},   // mount with SDK defaults
}}>
  {children}
</SodaxWalletProvider>
```

Omit a chain-type key entirely to skip mounting that adapter. `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`):

```ts
import type { IEvmWalletProvider, EvmRawTransaction, EvmRawTransactionReceipt } from '@sodax/sdk';
import type { Hash } from 'viem';

class MyCustomEvmProvider implements IEvmWalletProvider {
  readonly chainType = 'EVM' as const;   // required literal — used as runtime discriminant

  async getWalletAddress(): Promise<string> { … }
  async sendTransaction(tx: EvmRawTransaction): Promise<Hash> { … }
  async waitForTransactionReceipt(hash: Hash): Promise<EvmRawTransactionReceipt> { … }
}
```

Requirements for a valid custom implementation:

1. **Declare `readonly chainType = '<CHAIN>' as const`** — the SDK and `useWalletProvider` both read this field for runtime dispatch. The value must exactly match the `chainType` literal of the target interface.
2. **Implement every method on the interface** — TypeScript will flag missing methods at compile time.
3. **No base class required** — extending `BaseWalletProvider` is optional; it only provides the `defaults` storage and merge helpers from `@sodax/wallet-sdk-core`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sodax.com/developers/how-to/wallet_providers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
