> For the complete documentation index, see [llms.txt](https://docs.osero.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.osero.org/osero-sdk/getting-started/quick-start.md).

# Quick Start

This page walks through three complete examples — one per built-in wallet adapter: viem, ethers v6, and Privy server wallets.

For a deeper explanation of what each piece does, see [Actions](/osero-sdk/core-concepts/actions.md) and [The Execution Plan model](/osero-sdk/core-concepts/execution-plan.md).

## With viem <a href="#with-viem" id="with-viem"></a>

```typescript
import { OseroClient } from '@osero/client';
import { mintSUsds } from '@osero/client/actions';
import { sendWith } from '@osero/client/viem';
import { createWalletClient, http, parseUnits } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const privateKey = process.env.PRIVATE_KEY as `0x${string}` | undefined;
if (!privateKey) throw new Error('Set PRIVATE_KEY before sending transactions');

// 1. Create the OseroClient with a custom transport for Base
const client = OseroClient.create({
  transports: {
    8453: http('https://mainnet.base.org'),
  },
});

// 2. Create a viem WalletClient
const wallet = createWalletClient({
  account: privateKeyToAccount(privateKey),
  chain: base,
  transport: http('https://mainnet.base.org'),
});

// 3. Mint 100 USDC worth of sUSDS on Base
const result = await mintSUsds(client, {
  chainId: 8453,
  amount: parseUnits('100', 6), // USDC has 6 decimals
  sender: wallet.account.address,
}).andThen(sendWith(wallet));

if (result.isErr()) {
  console.error(result.error.name, result.error.message);
  process.exit(1);
}

console.log('sUSDS minted in tx', result.value.txHash);
```

### What this does

1. `OseroClient.create()` initialises the client with a custom RPC transport for Base. For production integrations, always provide custom transports — the default public transports are rate-limited.
2. `mintSUsds(client, request)` builds the `ExecutionPlan` for minting sUSDS from USDC on Base. On L2s this is an `Erc20ApprovalRequired` plan: one approval followed by one PSM3 swap.
3. `.andThen(sendWith(wallet))` pipes the plan through the viem adapter, which broadcasts each transaction in order and waits for confirmation.
4. The result is a `ResultAsync` — check `.isErr()` to handle failures, or access `.value.txHash` on success.

## With ethers v6 <a href="#with-ethers-v6" id="with-ethers-v6"></a>

```typescript
import { OseroClient } from '@osero/client';
import { mintUsds } from '@osero/client/actions';
import { sendWith } from '@osero/client/ethers';
import { JsonRpcProvider, Wallet, parseUnits } from 'ethers';
import { http } from 'viem';

const privateKey = process.env.PRIVATE_KEY;
if (!privateKey) throw new Error('Set PRIVATE_KEY before sending transactions');

const rpcUrl = 'https://arb1.arbitrum.io/rpc';

// 1. Set up an ethers provider and signer for broadcasting.
const provider = new JsonRpcProvider(rpcUrl);
const signer = new Wallet(privateKey, provider);

// 2. Create the OseroClient. Even when broadcasting through ethers, the
//    SDK still uses a viem transport internally for read calls (PSM
//    previews, LitePSM fees, etc.), so transports are configured the
//    same way as with the viem adapter.
const client = OseroClient.create({
  transports: {
    42161: http(rpcUrl),
  },
});

// 3. Mint 1000 USDC worth of USDS on Arbitrum
const result = await mintUsds(client, {
  chainId: 42161,
  amount: parseUnits('1000', 6),
  sender: await signer.getAddress(),
}).andThen(sendWith(signer));

if (result.isOk()) {
  console.log('USDS minted in tx', result.value.txHash);
}
```

### What this does

The pattern is identical to the viem example — the only difference is the wallet adapter. `sendWith` from `@osero/client/ethers` accepts an ethers v6 `Signer` instead of a viem `WalletClient`, and the SDK handles the rest.

## With Privy server wallets

For server-side integrations where keys are custodied by Privy, the Privy adapter submits each transaction to Privy's Wallet API instead of signing locally. It requires the optional `@privy-io/node` peer dependency — see Installation.

```typescript
import { OseroClient } from '@osero/client';
import { mintUsds } from '@osero/client/actions';
import { sendWith, type PrivyWallet } from '@osero/client/privy';
import { PrivyClient } from '@privy-io/node';
import { http, parseUnits } from 'viem';

// 1. Authenticate against Privy and describe the server wallet
const privy = new PrivyClient({
  appId: process.env.PRIVY_APP_ID!,
  appSecret: process.env.PRIVY_APP_SECRET!,
});

const wallet = {
  id: process.env.PRIVY_WALLET_ID!,
  address: process.env.PRIVY_WALLET_ADDRESS as `0x${string}`,
} satisfies PrivyWallet;

// 2. Create the OseroClient — actions still read PSM state through it
const client = OseroClient.create({
  transports: {
    8453: http('https://mainnet.base.org'),
  },
});

// 3. Mint 100 USDC worth of USDS on Base
const result = await mintUsds(client, {
  chainId: 8453,
  amount: parseUnits('100', 6),
  sender: wallet.address,
}).andThen(
  sendWith(privy, wallet, {
    transports: {
      8453: http('https://mainnet.base.org'),
    },
  }),
);

if (result.isErr()) {
  console.error(result.error.name, result.error.message);
  process.exit(1);
}

console.log('USDS minted in tx', result.value.txHash);
```

### What this does

1. `new PrivyClient(...)` authenticates against Privy's Wallet API. The `PrivyWallet` object identifies the signing wallet: `id` is Privy's wallet ID and `address` is its EVM address — the adapter checks it against every transaction's `from` before broadcasting. If your Privy app requires request authorization, add an `authorizationContext` to the wallet object.
2. The action builds the plan exactly as in the other examples; `sender` is the Privy wallet's address.
3. `sendWith(privy, wallet, options)` submits each transaction in the plan to Privy, which selects gas and nonce, signs, and broadcasts server-side. The adapter waits for each receipt through a viem public client before sending the next transaction; the `transports` option controls which RPC is used for that polling.
4. Unlike the viem adapter, the wallet is not bound to one chain — each transaction carries a CAIP-2 chain ID (`eip155:8453` here), so there is no chain to switch.

For the full options reference — including idempotency keys for server-side retries — see Privy Server Wallets.

## Previewing output before minting

Before building or sending any transaction, you can get a quote for the expected output amount using a preview helper:

```typescript
import { previewMintSUsds } from '@osero/client/actions';
import { parseUnits } from 'viem';

const quote = await previewMintSUsds(client, {
  chainId: 8453,
  amount: parseUnits('100', 6),
});

if (quote.isOk()) {
  console.log('Expected sUSDS output:', quote.value); // raw bigint
}
```

Preview helpers only require `chainId` and `amount` — they do not need a sender address or wallet, and they do not build or broadcast any transaction.

## Next steps

* [Actions reference](/osero-sdk/core-concepts/actions.md) — full documentation for all four actions and their preview helpers
* [Balance Helpers](/osero-sdk/core-concepts/balance-helpers.md) — read USDC, USDS, and sUSDS balances
* [Error Handling](/osero-sdk/reference/error-handling.md) — handle typed errors from actions and adapters
* [Configuration](/osero-sdk/reference/configuration.md) — configure custom RPCs, slippage, and confirmation counts


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.osero.org/osero-sdk/getting-started/quick-start.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
