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

# Conductor

Conductor is the contract `TradingClient` calls to run a swap: it pulls the input in, routes through Uniswap V3, takes fees, and sweeps the output back to Spark in one call. Most integrators never touch it. Use [`TradingClient.swap`](/products/execution/swaps); it picks the right Conductor method, signs, and submits for you.

This page documents the contract surface for callers who bypass the SDK: wiring a swap into a contract you wrote, building a UI that constructs intents by hand, or batching several swaps into one signed transaction.

## Swap methods

`TradingClient.swap` selects one of nine Conductor methods from the input asset, output asset, `withdraw` flag, and approval mode:

| Input → Output | Withdraw | Approval | Method                          |
| -------------- | -------- | -------- | ------------------------------- |
| token → token  | no       | n/a      | `swap`                          |
| BTC → token    | no       | n/a      | `swapBTC`                       |
| BTC → token    | yes      | n/a      | `swapBTCAndWithdraw`            |
| token → BTC    | yes      | exact    | `swapAndWithdrawBTC`            |
| token → token  | yes      | exact    | `swapAndWithdraw`               |
| token → BTC    | yes      | Permit2  | `swapAndWithdrawBTCWithPermit2` |
| token → token  | yes      | Permit2  | `swapAndWithdrawWithPermit2`    |
| token → BTC    | yes      | EIP-2612 | `swapAndWithdrawBTCWithEIP2612` |
| token → token  | yes      | EIP-2612 | `swapAndWithdrawWithEIP2612`    |

Permit2 and EIP-2612 are distinct. Permit2 is Uniswap's standalone transfer contract, authorized with one signed `PermitTransferFrom`. EIP-2612 is per-token, implemented by `SparkToken`, and is the path `useAvailableBalance` takes. BTC inputs carry their amount in `msg.value`, so they never need a token permit, which is why the matrix has no BTC-input permit rows.

## The swap call

`swap` is the base method. Its on-chain signature:

```solidity theme={null}
function swap(
    address tokenIn,
    address tokenOut,
    uint24  fee,
    uint256 amountIn,
    uint256 minAmountOut,
    address integrator,
    uint16  integratorBps,
    uint256 deadline
) external returns (uint256 amountOut);
```

`integrator` is the Spark-routed fee recipient (zero address for none), `integratorBps` its cut (0 to 1000), and `deadline` a unix-seconds expiry. The `*AndWithdraw*` variants insert a `bytes sparkRecipient` before `integrator`. The Permit2 and EIP-2612 variants drop `deadline`, since the signature carries its own, and append the permit struct.

Encode calldata with viem and the Conductor ABI:

```typescript theme={null}
import { conductorAbi } from "@flashnet/sdk/execution";
import { encodeFunctionData } from "viem";

const calldata = encodeFunctionData({
  abi: conductorAbi,
  functionName: "swap",
  args: [
    tokenIn,                                       // 0x..., sorted against tokenOut
    tokenOut,                                      // 0x...
    3000,                                          // fee tier
    amountIn,                                      // bigint, base units
    minAmountOut,                                  // bigint
    integrator,                                    // 0x... or zero address
    0,                                             // integratorBps
    BigInt(Math.floor(Date.now() / 1000) + 1800),  // deadline: now + 30 min
  ],
});
```

`encodeFunctionData` returns 0x-prefixed calldata. Wrap it in an EIP-1559 transaction, sign it, and submit through `ExecutionClient.execute`, which expects the RLP-hex of the signed transaction, not the calldata. For `swapBTC` and the BTC-input variants, set the transaction `value` to the input in wei (sats × `WEI_PER_SAT`, where `WEI_PER_SAT = 10^10`); for token inputs, set `value: 0n`.

## Fees

The Conductor skims up to three fees on each swap, each a separate basis-point rate capped at 1000 (10%):

| Fee        | Set by              | Read with                |
| ---------- | ------------------- | ------------------------ |
| Protocol   | Flashnet, global    | `protocolFeeBps()`       |
| Host       | Pool host, per pool | `hostFeeBps(pool)`       |
| Integrator | You, per call       | `integratorBps` argument |

The fee is taken in a single asset, chosen by priority: WBTC if either leg is WBTC, otherwise USDB if either leg is USDB, otherwise the output token. It accrues to each recipient's balance and is withdrawn with `claim(address token)`. [`quote()`](/products/execution/swaps#quoting) returns the combined rate as `conductorFeeBps` and reports `amountOut` already net of it.

## Custom errors

A reverted swap puts the selector in the intent's `statusMessage`. `decodeRevertReason` maps it back to the error name using the built-in `CONDUCTOR_REVERT_ERRORS` table:

```typescript theme={null}
import { decodeRevertReason } from "@flashnet/sdk";

const decoded = decodeRevertReason(intent.statusMessage);
// e.g. { name: "SlippageExceeded()", selector: "0x8199f5f3", raw: "..." }
```

What a swap reverts with:

* `SlippageExceeded()`: output fell below `minAmountOut`.
* `DeadlineExpired(uint256)`: submitted after `deadline`.
* `InvalidIntegrator()` / `FeeRateTooHigh(uint16,uint16)`: `integratorBps` over 1000, or a non-zero bps with a zero recipient.
* `ZeroAmountIn()`: a BTC swap sent with no `value`.

A missing pool (wrong fee tier, or no pool for the pair) reverts inside the Uniswap router, not the Conductor, so it surfaces as a generic `Error(string)` rather than a Conductor selector. `TokensNotSorted()`, `WBTCNotInPair()`, and `InsufficientBTCValue()` are pool-creation and liquidity errors, not swap errors.
