Skip to main content
Use swap to move tokens between chains or swap between assets on the same chain. This is the primary way most agents rebalance portfolios, enter/exit positions, or convert between tokens.

Workflow

  1. Get a quote with quote()
  2. Execute the swap with execute()
  3. Check data.status in the response

Get Quote

Get pricing and routing information for a swap.
def quote(request: SwapQuoteRequest | SwapQuoteRequestInput) -> SwapQuoteResponse
Request Parameters:
  • from (object): Source wallet { network, address }
  • to (object): Destination wallet { network, address }
  • amount (string): Amount in smallest unit (wei, lamports, etc.)
  • fromToken (string | null, optional): Source token address (omit for native tokens)
  • toToken (string | null, optional): Destination token address (omit for native tokens)
  • slippage (string, optional): Slippage tolerance % as string (default: “0.5”)
  • engines (string[], optional): Restrict routing to specific engines — route providers ("relay", "lifi", "across", "kyberswap", "paraswap", "jupiter") and/or action adapters ("pusd", "erc4626", "hypercore-deposit")
Response:
  • success (boolean): Whether the quote was retrieved
  • data (object): Quote data (on success)
    • engine (string): Routing engine used (e.g., "relay", "lifi", "across", "kyberswap", "paraswap", "jupiter", "pusd", "erc4626")
    • engines (string[], optional): Original routing engine filter when one was requested
    • assetSend (object): Source asset details
      • network (string): Network identifier
      • address (string): On-chain token contract address (or the chain’s native-asset sentinel)
      • token (string): Token identifier
      • name (string): Token name
      • symbol (string): Token symbol
      • decimals (number): Token decimals
      • amount (string): Amount in smallest units
      • amountFormatted (string): Human-readable amount
      • amountUsd (string, optional): Approximate value in USD
    • assetReceive (object): Destination asset details (same shape as assetSend, plus an optional minimumAmount — the slippage floor in smallest units)
    • priceImpact (object): Price impact info
      • percentage (string): Price impact as a percentage
      • usd (string, optional): Price impact in USD
    • fees (array): Fee breakdown
      • name (string): Fee label
      • amount (string, optional): Fee amount in smallest units
      • amountFormatted (string, optional): Human-readable fee
      • amountUsd (string, optional): Fee value in USD
    • steps (array): Transaction steps to execute
    • quoteFreshness (object, optional): Quote expiry metadata
      • issuedAtMs (number): Quote issue time in milliseconds
      • ttlMs (number): Quote time-to-live in milliseconds
      • resolvedSlippage (string): Slippage value applied to this quote
      • minimumOutputAtIssue (string): Minimum output amount captured at quote time
      • signature (string, optional): Server signature used to reject tampered freshness metadata
  • error (string | null): Error message if quote failed
Example:
quote = agent.swap.quote({
    "from": {
        "network": "ethereum:137",
        "address": agent.sessionWalletAddress,
    },
    "to": {
        "network": "ethereum:137",
        "address": agent.sessionWalletAddress,
    },
    "amount": "1000000",  # 1 USDC.e (6 decimals)
    "fromToken": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",  # USDC.e
    "toToken": "0xd93f7e271cb87c23aaa73edc008a79646d1f9912",  # wSOL
    "slippage": "10.0",
})

if quote.success and quote.data:
    if quote.data.asset_receive.amount_formatted:
        agent.log(f"You'll receive: {quote.data.asset_receive.amount_formatted}")
    if quote.data.price_impact.percentage:
        agent.log(f"Price impact: {quote.data.price_impact.percentage}%")

        # Validate price impact
        if abs(float(quote.data.price_impact.percentage)) > 10:
            agent.log("Price impact too high", error=True)
            return

Execute Quote

Execute a swap using a quote.
def execute(quote_data: SwapData | list[SwapData]) -> SwapExecuteResponse | list[SwapExecuteResponse]
Parameters:
  • quoteData: Complete quote object from quote(), or array of quotes for bulk execution
  • expiresAt (string | null, optional): ISO 8601 timestamp. In manual mode, the suggestion is discarded if not approved by this time. If omitted, no time-based expiry is set (all suggestions are auto-cleared at the start of each run cycle regardless).
Response:
  • success (boolean): Whether execution started
  • data.status (string): Execution status (“success”, “failure”, “refund”, “delayed”)
  • data.in.txs (string[]): Input transaction hashes (on success)
  • data.out.txs (string[]): Output transaction hashes (on success)
  • error (string | null): Error message (on failure)
Example:
if quote.success and quote.data:
    result = agent.swap.execute(quote.data)

    if result.success and result.data:
        agent.log(f"Swap status: {result.data.status}")
        if result.data.status == "success":
            agent.log("Swap completed")
            if result.data.in_ and result.data.in_.txs:
                agent.log(f"In tx: {result.data.in_.txs[0]}")
            if result.data.out and result.data.out.txs:
                agent.log(f"Out tx: {result.data.out.txs[0]}")
        elif result.data.status == "failure":
            agent.log("Swap failed", error=True)
    else:
        agent.log(result.error or "Execute failed", error=True)

Bulk Execution

Execute multiple swaps in parallel by passing an array of quotes:
results = agent.swap.execute([quote1.data, quote2.data])
for index, result in enumerate(results):
    if result.success and result.data:
        agent.log(f"Swap {index + 1} status: {result.data.status}")

Routing Engines

Circuit queries all compatible routing engines and selects the quote with the highest net output amount. Selection is a pure quote competition — there is no static engine preference.
EngineSupported Networks
relayEVM chains, Solana, Hyperliquid (cross-chain)
lifiEVM chains, Solana
acrossEVM chains + Hyperliquid (intent bridge; the Hyperliquid cross-chain fallback to Relay)
kyberswapSame-chain swaps on supported EVM chains
paraswapSame-chain swaps on supported EVM chains
jupiterSame-chain swaps on Solana
wrapSame-chain wrap/unwrap on supported EVM chains (vault share ↔ underlying, pUSD ↔ USDC.e)

Notes

  • Always validate quotes before executing. Check price impact and slippage.
  • Execute quotes promptly. Expired quotes are rejected with QUOTE_STALE; request a fresh quote and retry.
  • Circuit filters quotes with price impact exceeding 100%. Agents should validate returned quotes based on their own parameters.
  • Amounts are in smallest units (wei for ETH, lamports for SOL, etc.).
  • Omit fromToken/toToken for native tokens (ETH, SOL).
  • Execution status is final for same-chain swaps. For cross-chain bridges, the data.status field in the execute response indicates the final status: "success", "failure", "refund", or "delayed".

Manual Mode

In manual mode, execute() returns a suggestion instead of executing. The response will have data.suggested = true and data.suggestionId.

See Also

Python: from Parameter

from is a reserved keyword in Python. Use the string key "from" in dicts (recommended), or from_ if using the Pydantic model directly.
from is a reserved keyword in Python. When passing a dict to quote(), use the string key "from" — it works because dict keys are strings. If using the Pydantic model directly, the field is from_:
# Using a dict (recommended) — "from" works as a string key
quote = agent.swap.quote({
    "from": {"network": "ethereum:137", "address": agent.sessionWalletAddress},
    "to": {"network": "ethereum:137", "address": agent.sessionWalletAddress},
    "amount": "1000000",
})

# Using the Pydantic model — use from_ (with underscore)
from circuit_sdk.types.swap import SwapQuoteRequest, SwapWallet
quote = agent.swap.quote(SwapQuoteRequest(
    from_=SwapWallet(network="ethereum:137", address=agent.sessionWalletAddress),
    to=SwapWallet(network="ethereum:137", address=agent.sessionWalletAddress),
    amount="1000000",
))