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

# Swap USDC for WSOL at an Orca whirlpool on Solana

> A Solana cook that buys WSOL with the Pot's USDC at the Orca whirlpool of tick spacing 4, within a price limit, and sends the WSOL to a recipient.

The program buys WSOL with `amountIn` of the Pot's USDC at the pool `Orca.Whirlpool.pool(USDC, WSOL, 4)` finds and transfers what the swap returned to `to`. The cook reverts when the Pot holds less than `amountIn`, the pool's price is already past `priceLimit`, the swap returns less than `minOut`, or the recipient's WSOL balance does not rise by what the swap returned.

**Target chains:** Solana. Use `--chain solana`. The program does not compile for EVM chains because it uses the Solana-only `Orca` namespace.

## Prerequisites

You need the `sauce` command (`npm install -g @eco-incorp/sauce`), a Solana key to send from (a keypair file, or `sauce wallet new <name> --solana`), and the USDC in the Pot's USDC token account. `--fund` is EVM only: transfer the USDC to that token account before running the cook, not to the Pot's address. `sauce pot --chain solana --owner <your-pubkey>` prints the Pot's address; use it as the token account's owner. See [Installation](https://docs.eco.com/sauce-sdk/installation.md).

## Program

`pot` is the Pot the program runs on, available without declaring it; `pot.USDC` reads its USDC token account ([Names](https://docs.eco.com/sauce/names.md#balances)).

```ts solana-swap.sauce.ts theme={null}
// Buys WSOL with `amountIn` of the Pot's USDC at Orca's USDC/WSOL whirlpool of tick spacing 4,
// never paying more than `priceLimit` for any unit, and forwards the WSOL to `to`. The pool is
// found by its key, as an EVM program finds a Uniswap pool by its fee. The cook reverts, and
// nothing moves, when the pool is past `priceLimit`, the swap returns less than `minOut`, or the
// recipient's WSOL balance does not rise by what the swap returned.
//
//   sauce simulate solana-swap.sauce.ts --chain solana --owner <pubkey> \
//     --assume-balance USDC:<amountIn>n --args <to> <amountIn> <priceLimit> <minOut>
//   sauce run solana-swap.sauce.ts --chain solana --keypair <keypair> \
//     --args <to> <amountIn> <priceLimit> <minOut>
//
//   to: Address          who receives the WSOL: a wallet's base58 public key
//   amountIn: Uint256    the USDC to pay, in USDC's base units (6 decimals): 100000000 is 100 USDC
//   priceLimit: Uint256  the most one WSOL may cost, fee included: USDC base units per WSOL base
//                        unit, times 1e18; `sauce pools --chain solana USDC WSOL` prints it
//   minOut: Uint256      the least WSOL to receive, in lamports (9 decimals): 900000000 is 0.9 SOL
//
// Pay 100 USDC for at least 0.9 SOL at no more than 110 USDC per SOL:
//
//   sauce simulate solana-swap.sauce.ts --chain solana --owner <pubkey> \
//     --assume-balance USDC:100 --args <to> 100000000 110000000000000000 900000000
function main(
  to: Address,
  amountIn: Uint256,
  priceLimit: Uint256,
  minOut: Uint256,
): { spent: Uint256; received: Uint256 } {
  require(amountIn > 0, "amountIn is zero");
  require(pot.USDC >= amountIn, "not enough USDC in the Pot");

  const usdcBefore = pot.USDC;
  const wsolBefore = to.WSOL;
  const got = Orca.Whirlpool.swap(
    Orca.Whirlpool.pool(USDC, WSOL, 4),
    USDC,
    WSOL,
    amountIn,
    priceLimit,
    minOut,
  );
  require(got > 0, "pool skipped: its price is past priceLimit");
  WSOL.transfer(to, got);

  const received = to.WSOL - wsolBefore;
  require(received == got, "recipient received a different amount");
  return { spent: usdcBefore - pot.USDC, received };
}
```

## How it works

* `Orca.Whirlpool.pool(USDC, WSOL, 4)` names the pool by its key, the tick spacing, as an EVM program asks a factory for a pool by its fee. Compiling adds the nine accounts a swap at the pool takes (program, pool, config, two vaults, one more account, three tick arrays) to `main`, and the command reads them from the pool when it builds the cook, so no account is passed on the command line.
* `priceLimit` is USDC base units per WSOL base unit, times 10^18: 110 USDC per SOL is `110 × 10^(18 + 6 − 9)`, `110000000000000000`. `sauce pools --chain solana USDC WSOL` prints each pool's current price with its fee and as a `priceLimit`.
* `swap` returns 0 and moves nothing when the pool's price is already past `priceLimit`; `require(got > 0, …)` turns that into a revert with a reason. `spent` is measured from the Pot's USDC balance, because a swap the limit stops early leaves the rest of `amountIn` in the Pot.
* `sauce compile --json` measures the cook at 4,032 bytes against Solana's 1,232-byte transaction limit, so `sauce run` writes the 3,063-byte program and arguments into a code buffer first and cooks from it.

## Run the example

**1. Read the pool**

```bash theme={null}
sauce pools --chain solana USDC WSOL
```

The listing names each pool's key (`found by key: Orca.Whirlpool.pool(USDC, WSOL, 4)`), its fee, its liquidity and its price paying USDC, with the fee and as a `priceLimit`. Set `priceLimit` above that price by the slippage you accept.

**2. Compile**

```bash theme={null}
sauce compile solana-swap.sauce.ts --chain solana
sauce compile solana-swap.sauce.ts --chain solana --json \
  --args <recipient> 100000000 110000000000000000 900000000
```

`--json` adds the program's size, the payload with the arguments, and `cook`: the cook's size against Solana's 1,232-byte limit, 4,032 bytes here, with `"fits": false`.

**3. Simulate**

```bash theme={null}
sauce simulate solana-swap.sauce.ts --chain solana --owner <your-pubkey> \
  --assume-balance USDC:100 --args <recipient> 100000000 110000000000000000 900000000
```

`--assume-balance USDC:100` gives the Pot's USDC account 100 USDC in a local LiteSVM copy of the accounts the cook names, read from the cluster; the cook is past one transaction, so the simulation runs there in any case. `--owner` must be a wallet's address.

**4. Send**

```bash theme={null}
sauce run solana-swap.sauce.ts --chain solana --keypair <keypair> \
  --args <recipient> 100000000 110000000000000000 900000000
```

`sauce run` creates the Pot and its missing token accounts (asking first, or with `--yes`; the owner pays their rent), stages the program in a code buffer, sends the cook and closes the buffer. `--wallet <name>` signs with a Solana wallet instead of `--keypair`. `sauce tx` with `--owner <your-pubkey>` in place of `--keypair <keypair>` prints the same run as a plan of unsigned transactions for another signer.

> [!WARNING]
>
> `to` is a wallet's public key. A token account given there is taken as a wallet, and the cook pays an associated token account it holds, which no one can spend from.

## Simulation result

Simulated on Solana at slot 460260659 with the command above, in a local LiteSVM copy. Nothing was signed or sent; values change with the slot. Lines that name the owner are left out.

```text theme={null}
...
main returns { spent: Uint256, received: Uint256 }: { spent: 100000000, received: 961044220 }
Simulated in a local copy (LiteSVM) of the 16 accounts the cook names, read from solana at slot 460260659, with the released engine and Kitchen: the cook does not fit one transaction, and no cluster can stage a program without sending. Nothing was signed or sent:
  Kitchen create_pot: Pot BjFSkVpfmbX19SuADFxTsfzWdTErjdELMyd4Nd4iXo9T is not created on solana yet, so the copy creates it first
  the 3063-byte program staged into a code buffer in 6 transactions, as `sauce run` stages it
...
Token balance changes:
  6Cz6ZMnQAE4D9UFUyxpsdWYHtkJ5h315eBAFvq8gRSGs (potUSDC, the Pot's USDC account), owned by BjFSkVpfmbX19SuADFxTsfzWdTErjdELMyd4Nd4iXo9T (the Pot): -100 USDC
  CDpxuy4Liae8HPUKA788gLi3QRgnH17PEEip2zem8hHw (toWSOL, main's argument to's WSOL account), owned by H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS: +0.96104422 WSOL
  EUuUbDcafPrmVTD5M6qoJAoyyNbihBhugADAxRMn5he9 (orcaWhirlpool4VaultA, pool Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE's vaultA, paying USDC), owned by Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE (orcaWhirlpool4Account, pool Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE's pool, paying USDC): -0.96104422 WSOL
  2WLWEuKDgkDUccTpbwYp1GToYktiSB1cXvreHUwiSUVP (orcaWhirlpool4VaultB, pool Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE's vaultB, paying USDC), owned by Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE (orcaWhirlpool4Account, pool Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE's pool, paying USDC): +100 USDC
...
```

The swap spent all 100 USDC and the recipient's WSOL account received 0.96104422 WSOL, about 104.05 USDC per SOL, inside the 110 limit. The full output also lists what a first run on a new Pot costs the owner: 0.073099792 SOL in all, of which the code buffer's 0.0173228 SOL comes back when `sauce run` closes it.

With `priceLimit` at 100 USDC per SOL (`100000000000000000`), below the pool's price, and `--expect-revert "pool skipped"`:

```text theme={null}
As expected, the cook reverts: the program threw "pool skipped: its price is past priceLimit"
The cook reverts: the program threw "pool skipped: its price is past priceLimit"
Simulated in a local copy (LiteSVM) of the 16 accounts the cook names, read from solana at slot 460260715, with the released engine and Kitchen: the cook does not fit one transaction, and no cluster can stage a program without sending. Nothing was signed or sent:
...
```

## Next steps

* [Distributed swap on Solana](https://docs.eco.com/quickstarts/sauce/solana-distributed-swap.md): one order over several pools at one price limit
* [Quote, swap and supply](https://docs.eco.com/quickstarts/sauce/quote-swap-supply.md): the EVM version of choosing a pool before swapping
* [`sauce pools`](https://docs.eco.com/sauce-sdk/cli/pools), [`sauce simulate`](https://docs.eco.com/sauce-sdk/cli/simulate), [`sauce run`](https://docs.eco.com/sauce-sdk/cli/run), [Names](https://docs.eco.com/sauce/names.md)


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