# Money Market — `@sodax/dapp-kit`

Cross-chain lending and borrowing.

Pair: [`../../migration/features/money-market.md`](../../migration/features/money-market.md).

## Hook surface

```ts
// @ai-snippets-skip
// User mutations (4 actions)
useSupply({ mutationOptions });
useWithdraw({ mutationOptions });
useBorrow({ mutationOptions });
useRepay({ mutationOptions });

// Allowance + approve — useMMAllowance wraps the MM params under `params.payload`
useMMAllowance({ params: { payload: MoneyMarketParams<K> }, queryOptions });   // disabled for borrow/withdraw (data is undefined)
useMMApprove({ mutationOptions });

// Reserves data (read-only)
useReservesData({ queryOptions });                     // All reserve data
useReservesHumanized({ queryOptions });                // Decimal-normalized
useReservesList({ queryOptions });                     // List of reserve asset addresses
useReservesUsdFormat({ queryOptions });                // With USD values

// User position
useUserFormattedSummary({ params, queryOptions });     // Health factor, collateral, debt
useUserReservesData({ params, queryOptions });         // Per-reserve user position

// aTokens
useAToken({ params, queryOptions });                   // aToken metadata
useATokensBalances({ params, queryOptions });          // aToken balances
```

## Mutation params

All four user mutations share the same TVars shape (only the `action` literal differs):

```ts
// @ai-snippets-skip
type UseSupplyVars<K extends SpokeChainKey = SpokeChainKey> = {
  params: MoneyMarketSupplyParams<K>;
  walletProvider: GetWalletProviderType<K>;
};

// MoneyMarketSupplyParams<K>:
// {
//   srcChainKey: K;
//   srcAddress: GetAddressType<K>;
//   token: string;
//   amount: bigint;
//   action: 'supply';
//   dstChainKey?: SpokeChainKey;  // optional cross-chain delivery
//   dstAddress?: string;
// }
```

`borrow`, `withdraw`, `repay` follow the same shape with their respective `action` literals (`'borrow'` / `'withdraw'` / `'repay'`). **All four actions** accept optional `dstChainKey`/`dstAddress` for cross-chain delivery — supply on chain A and credit collateral on chain B, withdraw from chain A into a wallet on chain B, etc.

```ts
// @ai-snippets-skip
const { mutateAsyncSafe: supply } = useSupply();
const result = await supply({
  params: { srcChainKey: ChainKeys.BASE_MAINNET, srcAddress: '0x...', token: '0x...', amount: 1_000_000n, action: 'supply' },
  walletProvider,
});
if (!result.ok) return;
const { srcChainTxHash, dstChainTxHash } = result.value;   // TxHashPair
```

## Approve / allowance

```ts
// @ai-snippets-skip
// useMMAllowance reads `params.payload` (the MM params); no walletProvider — the read calls
// `isAllowanceValid` with `raw: true` internally. For borrow/withdraw, returns true automatically.
const { data: isApproved } = useMMAllowance({ params: { payload: supplyParams } });
const { mutateAsync: approve } = useMMApprove();
if (!isApproved) await approve({ params: supplyParams, walletProvider });
```

`useMMAllowance` skips the on-chain check entirely for `'borrow'` / `'withdraw'` actions — the query is `enabled: false` for those, so `data` stays `undefined`. Treat "absent allowance for borrow/withdraw" as "approval not required" at the call site (these actions never need ERC-20 approval).

## Reserves data hooks

| Hook | Returns | When to use |
|---|---|---|
| `useReservesData` | `[ReserveData[], ...]` | Raw data for custom rendering |
| `useReservesHumanized` | `ReserveDataHumanized[]` | Decimal-normalized (most common for UI) |
| `useReservesList` | `Address[]` | Just the reserve addresses |
| `useReservesUsdFormat` | `ReserveDataWithUsd[]` | With USD price overlays |
| `useUserFormattedSummary` | `{ totalCollateralUSD, totalBorrowsUSD, healthFactor, ... }` | Dashboard-ready summary |
| `useUserReservesData` | `UserReserveData[]` | Per-reserve user position |

## Return shapes

| Hook | Returns |
|---|---|
| `useSupply` / `useBorrow` / `useWithdraw` / `useRepay` | `SafeUseMutationResult<TxHashPair, Error, ...>` (`{ srcChainTxHash, dstChainTxHash }`) |
| `useMMApprove` | `SafeUseMutationResult<TxReturnType<K, false>, Error, ...>` — chain-keyed receipt union |
| `useMMAllowance` | `UseQueryResult<boolean, Error>` — already unwrapped; for `borrow`/`withdraw` actions the query is `enabled: false` and `data` is `undefined` |
| Reserve / position hooks | `UseQueryResult<TData, Error>` — already unwrapped; queries throw on SDK `!ok` |

## Gotchas

1. **Health factor < 1.0 is liquidation territory.** Always render a warning when `useUserFormattedSummary().healthFactor < 1.05` or whatever margin your UX uses.
2. **Cross-chain delivery via `dstChainKey`/`dstAddress`** — supported on all four actions (supply / withdraw / borrow / repay). Omit for same-chain operations; don't pass `dstChainKey === srcChainKey` (let the default kick in).
3. **`useMMAllowance` is `enabled: false` for borrow/withdraw** — `data` stays `undefined` (not `true`). Treat "no allowance result for borrow/withdraw" as "approval not required" — those actions never need ERC-20 approval.
4. **Position queries take `{ spokeChainKey, userAddress }`** (NOT `srcChainKey`/`srcAddress` — those are mutation-side names). The hub wallet derivation is automatic.

## Cross-references

- [`../recipes/money-market.md`](../recipes/money-market.md) — full worked examples.
- [`../../migration/features/money-market.md`](../../migration/features/money-market.md) — v1 → v2 porting.
- [`../../../../sdk/ai-exported/integration/features/money-market.md`](../../../../sdk/ai-exported/integration/features/money-market.md) — underlying SDK MM surface.
