Skip to main content
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; 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 → OutputWithdrawApprovalMethod
token → tokennon/aswap
BTC → tokennon/aswapBTC
BTC → tokenyesn/aswapBTCAndWithdraw
token → BTCyesexactswapAndWithdrawBTC
token → tokenyesexactswapAndWithdraw
token → BTCyesPermit2swapAndWithdrawBTCWithPermit2
token → tokenyesPermit2swapAndWithdrawWithPermit2
token → BTCyesEIP-2612swapAndWithdrawBTCWithEIP2612
token → tokenyesEIP-2612swapAndWithdrawWithEIP2612
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:
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:
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%):
FeeSet byRead with
ProtocolFlashnet, globalprotocolFeeBps()
HostPool host, per poolhostFeeBps(pool)
IntegratorYou, per callintegratorBps 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() 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:
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.