> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sodax.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> SODAX is mainnet-only (no testnet chains or RPC endpoints exist) with a hub-and-spoke architecture; Sonic is the hub. SODAX is non-custodial protocol/software: it routes and settles; independent solvers on the marketplace fill — never say 'our solver', 'the SODAX solver', that SODAX trades, takes custody, or fills orders. For frontend/React integrations, prefer @sodax/dapp-kit hooks over calling @sodax/sdk directly. SDK operations — the methods that build, submit or await a transaction, and the API/quote calls — return Result<T, E> ({ ok: true, value } or { ok: false, error }): check result.ok, never wrap them in try/catch or branch on error.message; discriminate on the narrow error.code union instead. Synchronous config getters (getPartnerFee, getSupportedSwapTokens, getVault, ...) return their value directly, not a Result.

# Use Base as a lending spoke

> Supply collateral from Base and borrow liquidity delivered to another network, or into Base against collateral held elsewhere, through the SODAX money market. No lending infrastructure to run.

Use this recipe when your Base app wants to offer lending and borrowing without running its own money market. SODAX pools lending liquidity on the hub and lets a user act from any supported network: supply collateral from Base and borrow liquidity delivered to another network, or borrow into Base against collateral held elsewhere.

## What you will build

A position flow that supplies collateral from Base, borrows against it with the borrowed asset delivered to another network, and reads the position back to render a health factor.

> [!NOTE]
>
> The money market list on Base is separate from the swap list: a token can appear in one and not the other. See [Networks & Assets](https://docs.sodax.com/base/networks-and-assets.md).

## Prerequisites

* `@sodax/sdk` and a wallet provider from `@sodax/wallet-sdk-core` or `@sodax/wallet-sdk-react`.
* A Base wallet funded with ETH for gas, and a SODAX API key kept on your server. See [API keys](https://docs.sodax.com/developers/how-to/api-keys.md).

SODAX is mainnet only, so test with small amounts. See [Is SODAX on Testnet?](https://docs.sodax.com/developers/how-to/testnet.md).

## How it works

**1. Supply collateral from Base**

The action is keyed by `srcChainKey: ChainKeys.BASE_MAINNET` and the token comes from the Base money market list. An ERC-20 needs an allowance first, so approve only when it is short, and wait for the approval to confirm before you supply.

**2. Borrow, delivered to another network**

The cross-network part is one parameter. The user still acts from Base, but `dstChainKey` and `dstAddress` decide where the borrowed liquidity lands, and the token comes from the destination network's list. To borrow into Base against collateral held elsewhere, swap the roles. Borrow and withdraw need no approval; repaying an ERC-20 does.

**3. Read the position**

`sodax.moneyMarket.data` returns USD-converted rates per reserve and the user's totals and health factor.

## Code

A small helper finds a token by symbol in a network's list and throws if it isn't there:

```ts theme={null}
export const bySymbol = (tokens: readonly XToken[], symbol: string): XToken => {
  const token = tokens.find(t => t.symbol === symbol);
  if (!token) throw new Error(`${symbol} is not a supported token on this network`);
  return token;
};
```

Supply, borrow and read the position:

```ts theme={null}
import { ChainKeys } from '@sodax/sdk';
import type { IEvmWalletProvider, Sodax, SpokeChainKey } from '@sodax/sdk';

export type SupplyFromBaseParams = {
  sodax: Sodax;
  walletProvider: IEvmWalletProvider;
  userBaseAddress: `0x${string}`;
  symbol: string;
  amount: bigint;
};

/** Supplies collateral from Base, approving first only when the allowance is short. */
export async function supplyFromBase({ sodax, walletProvider, userBaseAddress, symbol, amount }: SupplyFromBaseParams) {
  const token = bySymbol(sodax.moneyMarket.getSupportedTokensByChainId(ChainKeys.BASE_MAINNET), symbol);
  const params = {
    srcChainKey: ChainKeys.BASE_MAINNET,
    srcAddress: userBaseAddress,
    token: token.address,
    amount,
    action: 'supply',
  } as const;

  const allowance = await sodax.moneyMarket.isAllowanceValid({ params });
  if (!allowance.ok) throw allowance.error;
  if (!allowance.value) {
    const approval = await sodax.moneyMarket.approve<typeof ChainKeys.BASE_MAINNET, false>({ params, walletProvider });
    if (!approval.ok) throw approval.error;
    await walletProvider.waitForTransactionReceipt(approval.value);
  }

  const supplied = await sodax.moneyMarket.supply({ params, walletProvider, timeout: 120_000 });
  if (!supplied.ok) throw supplied.error;
  return supplied.value;
}

export type BorrowToNetworkParams = {
  sodax: Sodax;
  walletProvider: IEvmWalletProvider;
  userBaseAddress: `0x${string}`;
  dstChainKey: SpokeChainKey;
  dstAddress: string;
  symbol: string;
  amount: bigint;
};

/** Acts from Base and delivers the borrow on dstChainKey; the token comes from the destination list. */
export async function borrowToNetwork({
  sodax,
  walletProvider,
  userBaseAddress,
  dstChainKey,
  dstAddress,
  symbol,
  amount,
}: BorrowToNetworkParams) {
  const token = bySymbol(sodax.moneyMarket.getSupportedTokensByChainId(dstChainKey), symbol);
  const borrowed = await sodax.moneyMarket.borrow({
    params: {
      srcChainKey: ChainKeys.BASE_MAINNET,
      srcAddress: userBaseAddress,
      token: token.address,
      amount,
      action: 'borrow',
      dstChainKey,
      dstAddress,
    },
    walletProvider,
  });
  if (!borrowed.ok) throw borrowed.error;
  return borrowed.value;
}

/** Rates per reserve plus the user's totals and health factor, from on-chain reads only. */
export async function readPosition(sodax: Sodax, userBaseAddress: `0x${string}`) {
  const { data } = sodax.moneyMarket;
  const reserves = await data.getReservesHumanized();
  const userReserves = await data.getUserReservesHumanized(ChainKeys.BASE_MAINNET, userBaseAddress);
  const formattedReserves = data.formatReservesUSD(data.buildReserveDataWithPrice(reserves));
  const summary = data.formatUserSummary(data.buildUserSummaryRequest(reserves, formattedReserves, userReserves));
  return { formattedReserves, summary };
}
```

## Failures

Each method returns a typed `Result`; the error codes are in [Lend / Borrow (Money Market)](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/money_market.md). Read the position before you borrow, so the amount stays within what the collateral covers.

## Next steps

* [Money Market on Base](https://docs.sodax.com/base/money-market.md): supply, borrow, repay, and withdraw in depth.
* [Networks & Assets](https://docs.sodax.com/base/networks-and-assets.md): the live money market list on Base.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.