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
- Get a quote with
quote()
- Execute the swap with
execute()
- 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.
| Engine | Supported Networks |
|---|
relay | EVM chains, Solana, Hyperliquid (cross-chain) |
lifi | EVM chains, Solana |
across | EVM chains + Hyperliquid (intent bridge; the Hyperliquid cross-chain fallback to Relay) |
kyberswap | Same-chain swaps on supported EVM chains |
paraswap | Same-chain swaps on supported EVM chains |
jupiter | Same-chain swaps on Solana |
wrap | Same-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",
))