Skip to main content

Crate cow_sdk_trading

Crate cow_sdk_trading 

Source
Expand description

§cow-sdk-trading

High-level CoW Protocol trading orchestration surface covering quoting, signing, posting, allowance management, native-asset wrapping, and on-chain order actions.

⚠️ Alpha — 0.1.0-alpha. Pre-release and not security-audited; the public API may change before 0.1.0. It is published as a pre-release, so Cargo selects it only when you opt in (cow-sdk-trading = "0.1.0-alpha.10"). Review it yourself before relying on it with real funds.

This is the orchestration layer that turns configured signers, providers, and orderbook clients into a single ready-state trading facade. The primary entry point is Trading. Most end-user code reaches this crate through cow-sdk; depend on it directly when you want the trading entry points without the rest of the facade surface.

§Install

[dependencies]
cow-sdk-trading = "0.1.0-alpha.10"

§Minimal example

The TradingBuilder::ready one-call shortcut accepts a complete total TraderParams and returns a ready-state Trading with the default per-chain orderbook client:

use cow_sdk_core::SupportedChainId;
use cow_sdk_trading::{TraderParams, TradingBuilder};

let _trading = TradingBuilder::ready(
    TraderParams::new(SupportedChainId::Sepolia, "your-app-code")
        .expect("app code validates"),
);

For fluent control over env, settlement-contract overrides, or orderbook injection, use the full builder:

use cow_sdk_core::{CowEnv, SupportedChainId};
use cow_sdk_trading::Trading;

let _trading = Trading::builder()
    .chain_id(SupportedChainId::Sepolia)
    .app_code("your-app-code")
    .env(CowEnv::Prod)
    .build()
    .expect("ready-state construction");

Allowance reads, approval submission, pre-sign transaction construction, and on-chain cancellation need chain authority but no app code, so they are the crate’s free functions — cow_protocol_allowance, approval_transaction, pre_sign_transaction, and onchain_cancel_order — and need no trading client. wrap_transaction and unwrap_transaction build the native-asset wrap and unwrap transactions, resolving the chain’s wrapped-native token from the chain id, and need neither a client nor a provider. Quote, post, order lookup, and off-chain cancellation flows use the ready Trading client.

Owner attribution lives on the per-trade TradeParams (or LimitTradeParams); the Trading client does not store a default owner. For signer-backed flows the signer’s address fills the slot when TradeParams.owner is None.

§Swap in one call

Trading::swap() opens a typed builder with named token setters, so the sell and buy tokens cannot be transposed. execute quotes, signs, and posts in one call; quote returns a result you can inspect before submit. The same chain works with any signer — a local key, a remote signer, a host-supplied EIP-1193 wallet, or a smart account:

use cow_sdk_core::{Amount, Signer, UserRejection, address};
use cow_sdk_trading::Trading;

let weth = address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2");
let usdc = address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48");

// Quote, sign, and post in one call.
let posted = trading
    .swap()
    .sell_token(weth)
    .buy_token(usdc)
    .sell_amount(Amount::from_units(1, 18)?)
    .slippage_bps(50)
    .execute(signer)
    .await?;
println!("posted order {}", posted.order_id.to_hex_string());

// Or inspect the quote first, then submit the exact quoted order.
let quoted = trading
    .swap()
    .sell_token(weth)
    .buy_token(usdc)
    .sell_amount(Amount::from_units(1, 18)?)
    .quote(signer)
    .await?;
println!("suggested slippage (bps): {}", quoted.results().suggested_slippage_bps);
let _posted = quoted.submit(signer).await?;

§Limit order in one call

A limit order sets an explicit price — both amounts — so no quote is fetched. Trading::limit() opens the same kind of typed builder as swap(): named setters that cannot be transposed, then post to sign and post, or post_presign for the smart-account path that needs no signer:

use cow_sdk_core::{Amount, Signer, UserRejection, address};
use cow_sdk_trading::Trading;

let weth = address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2");
let usdc = address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48");

// Sell exactly 1 WETH, want at least 3000 USDC.
let posted = trading
    .limit()
    .sell_token(weth)
    .buy_token(usdc)
    .sell_amount(Amount::from_units(1, 18)?)
    .buy_amount(Amount::from_units(3000, 6)?)
    .post(signer)
    .await?;
println!("posted order {}", posted.order_id.to_hex_string());

§Placing an order from a Safe

place_swap and place_limit take the authorization mode as one Authorization value, so a smart-contract-wallet order is the same call shape as an EOA order:

  • Authorization::Ecdsa(signer) — EOA / EIP-712 signing.
  • Authorization::Eip1271(provider) — Safe off-chain contract signature.
  • Authorization::PreSign — Safe on-chain pre-sign, no signer.

The mode selects the typed OrderPlacement result. The signing arms resolve to OrderPlacement::Live { order_uid }; PreSign resolves to OrderPlacement::PendingActivation { order_uid, activation }, where activation is the ordered approve-then-set-pre-signature SafeActivation bundle the owner sends or proposes from the smart account to make the order fillable. build_presign_activation builds the same bundle for an already-posted pre-sign order.

§Quoting a swap

Quoting is the lowest-friction action and needs no signer — the owner comes from TradeParams:

use cow_sdk_core::{Address, Amount, OrderKind, SupportedChainId, address};
use cow_sdk_trading::{TradeParams, TradingBuilder};

let trading = TradingBuilder::ready(
    cow_sdk_trading::TraderParams::new(SupportedChainId::Mainnet, "your-app-code")?,
);

// Sell 1 WETH for USDC.
let weth = address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2");
let usdc = address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48");
let params = TradeParams::new(
    OrderKind::Sell,
    weth,
    usdc,
    Amount::from_units(1, 18)?,
)
.with_owner(Address::new("0x76b0340e50BD9883D8B2CA5fd9f52439a9e7Cf58")?);

let quote = trading.quote_only(params, None).await?;
println!("suggested slippage (bps): {}", quote.suggested_slippage_bps);

§Waiting for mined receipts

For workflows that need to observe mined success or revert status before continuing, use submit_and_wait_for_receipt. This is the common shape for approve-then-settle flows:

use cow_sdk_trading::{WaitError, WaitOptions, submit_and_wait_for_receipt};

let receipt = match submit_and_wait_for_receipt(
    signer,
    provider,
    approve_tx,
    WaitOptions::approve_default(),
)
.await
{
    Ok(receipt) => receipt,
    Err(WaitError::Reverted { receipt }) => {
        return Err(format!(
            "approval reverted: gas_used={:?}",
            receipt.gas_used
        )
        .into());
    }
    Err(WaitError::Timeout {
        transaction_hash,
        elapsed,
    }) => {
        return Err(format!(
            "approval receipt {} was not observed after {:?}",
            transaction_hash.to_hex_string(),
            elapsed
        )
        .into());
    }
    Err(other) => return Err(Box::new(other)),
};

assert_eq!(receipt.status, Some(TransactionStatus::Success));

The companion poll_for_receipt helper is available when a workflow already has a transaction hash from a separate broadcast path. Both helpers are generic over Signer and Provider, so they work with the native Alloy client, separate Alloy provider and signer adapters, host-supplied EIP-1193 wallets, and custom integrations.

When only the revert verdict matters, WaitError::reverted() returns the reverted receipt for a mined on-chain failure and None for the transient broadcast, lookup, timeout, and cancellation variants — a coarse alternative to matching each variant.

§Feature flags

FeatureDefaultEnables
tracingofftracing spans on every Trading method and the broadcast/receipt path, and enables tracing across the core, contracts, signing, orderbook, and app-data crates.

§Where this fits

Trading orchestrates; it carries no transport or signing crypto of its own. Orderbook I/O is delegated to an injected or default cow-sdk-orderbook client (which owns retry and rate-limit policy), and signing goes through a caller-supplied cow_sdk_core::Signer. OrderBoundsValidator enforces only operator-independent invariants client-side; the services backend remains authoritative for deny-lists, balances, exact validity windows, and price checks. No alloy_* type appears in the public API. Most consumers reach this crate through the cow-sdk facade as cow_sdk::trading.

§Examples

The workspace ships runnable, deterministic scenarios for the trading workflows — quoting, posting, EthFlow, receipt waiting, and the advanced seam traits — cataloged by goal in Examples. Getting Started walks the recommended first session.

§Where to next

§License

Licensed under GPL-3.0-or-later. See the workspace LICENSE file for the full text. High-level CoW Protocol trading workflows for quoting, signing, posting, allowance management, native-asset wrapping, and on-chain order actions.

§Async-first entry points

Every public free function and Trading method in this crate is pub async fn and accepts any signer implementing cow_sdk_core::Signer. The crate ships one canonical async entry per operation; callers in non-async contexts thread an executor at the call site.

Cooperative cancellation through cow_sdk_core::Cancellable::cancel_with composes on every public async entry. Each entry lifts a fired cancellation token into the crate-level TradingError::Cancelled variant.

Narrow async signer capability traits (cow_sdk_core::TypedDataSigner, cow_sdk_core::DigestSigner) remain available for callback-shaped adapters that expose only one signing operation; owner resolution is served by cow_sdk_core::Signer::address.

§Fluent swap lifecycle

Trading::swap opens a typed SwapBuilder for the common swap path: named sell/buy/amount setters that cannot be transposed, then a single asynchronous terminal — SwapBuilder::execute for one-call quote-sign-post, or SwapBuilder::quote to inspect a QuotedSwap before QuotedSwap::submit. The flat free functions and Trading methods remain the full surface; the builder is an additive ergonomic entry over them.

§Placement by authorization

place_swap and place_limit take the authorization mode as one Authorization value — Authorization::Ecdsa, Authorization::Eip1271, or Authorization::PreSign — so a smart-contract-wallet order is the same call shape as an EOA order. The mode statically selects the typed OrderPlacement result: the signing arms resolve to OrderPlacement::Live, while Authorization::PreSign resolves to OrderPlacement::PendingActivation, whose SafeActivation carries the on-chain approve-then-set-pre-signature bundle the owner must still send or propose from the smart account (build_presign_activation builds the same bundle for an already-posted order).

Re-exports§

pub use allowance::approval_transaction;
pub use allowance::approve_cow_protocol;
pub use allowance::cow_protocol_allowance;
pub use app_data::build_app_data;
pub use app_data::build_app_data_doc;
pub use app_data::merge_and_seal_app_data;
pub use app_data::params_from_doc;
pub use cancel::offchain_cancel_order;
pub use error::OrderbookContextValue;
pub use error::TradingError;
pub use onchain::EthFlowTransaction;
pub use onchain::PreparedTransaction;
pub use onchain::eth_flow_transaction;
pub use onchain::onchain_cancel_order;
pub use onchain::onchain_cancellation_transaction;
pub use onchain::pre_sign_transaction;
pub use order::OrderToSignParams;
pub use order::calculate_unique_order_id;
pub use order::order_to_sign;
pub use order::swap_params_to_limit_order_params;
pub use placement::Authorization;
pub use placement::NoSigner;
pub use placement::OrderPlacement;
pub use placement::SafeActivation;
pub use placement::build_presign_activation;
pub use placement::place_limit;
pub use placement::place_swap;
pub use post::build_limit_order_to_sign;
pub use post::post_cow_protocol_trade;
pub use post::post_limit_order;
pub use post::post_limit_order_presign;
pub use post::post_sell_native_currency_order;
pub use post::post_swap_order;
pub use post::post_swap_order_from_quote;
pub use post::post_swap_order_presign;
pub use quote::quote_only;
pub use quote::quote_results;
pub use slippage::DEFAULT_GAS_LIMIT;
pub use slippage::DEFAULT_QUOTE_VALIDITY;
pub use slippage::DEFAULT_SLIPPAGE_BPS;
pub use slippage::GAS_MARGIN_PERCENT;
pub use slippage::MAX_SLIPPAGE_BPS;
pub use slippage::calculate_quote_amounts_and_costs;
pub use slippage::default_slippage_bps;
pub use slippage::partner_fee_bps;
pub use slippage::resolve_slippage_suggestion;
pub use slippage::sanitize_protocol_fee_bps;
pub use slippage::suggest_slippage_bps;
pub use slippage::suggest_slippage_from_fee;
pub use slippage::suggest_slippage_from_volume;
pub use types::AllowanceParams;
pub use types::ApprovalParams;
pub use types::EthFlowOrderExistsChecker;
pub use types::LimitTradeParams;
pub use types::LimitTradeParamsFromQuote;
pub use types::OrderPostingResult;
pub use types::OrderTraderParams;
pub use types::PostTradeAdditionalParams;
pub use types::QuoteRequestOverride;
pub use types::QuoteResults;
pub use types::QuoterParams;
pub use types::SlippageSuggester;
pub use types::SlippageToleranceRequest;
pub use types::SlippageToleranceResponse;
pub use types::TradeAdvancedSettings;
pub use types::TradeParams;
pub use types::TraderParams;
pub use types::TradingAppDataInfo;
pub use validation::AmountSide;
pub use validation::ClientRejection;
pub use validation::OrderBoundsValidator;
pub use verify::preflight_eip1271;
pub use verify::presign_activation_status;
pub use wait::WaitError;
pub use wait::WaitOptions;
pub use wait::poll_for_receipt;
pub use wait::submit_and_wait_for_receipt;

Modules§

allowance
Allowance reads, approval transactions, and approval submission helpers.
app_data
Trading app-data generation and quote-to-post merge helpers.
cancel
Off-chain cancellation helpers.
error
Trading crate error types.
eth_flow
Typed CoWSwapEthFlow call-data encoders generated from the upstream Solidity surface via the alloy::sol! macro. Typed ABI bindings for the CoWSwapEthFlow contract.
onchain
On-chain order actions and transaction builders.
order
Order-construction helpers and EthFlow adjustments.
params
Offline helper validation entry points on trade-parameter builders. Offline-helper validation entry points on the public trade-parameter builders.
placement
Authorization-as-a-value placement and bundled pre-sign activation. Authorization-as-a-value order placement (ADR 0073).
post
Quote-to-post orchestration helpers. Quote-to-post orchestration helpers grouped by order family.
quote
Quote construction and quote-request precedence helpers.
slippage
Slippage and fee calculation helpers. Slippage and fee calculation helpers.
types
Shared trading DTOs, trait seams, and settings types. Shared trading DTOs, trait seams, and settings types.
validation
Typed client-side validator enforcing the reviewed services protocol-invariant matrix on every submission seam. Typed client-side validator for every public trading submission seam.
verify
Honest EIP-1271 preflight and pre-sign lifecycle status helpers. Honest EIP-1271 preflight and pre-sign lifecycle status helpers (ADR 0073).
wait
Broadcast-then-poll helpers for mined transaction receipts. Broadcast-then-poll helpers for workflows that need mined receipts.

Structs§

AppCodeSet
Typestate marker for a builder that has been given an appCode.
AppCodeUnset
Typestate marker for a builder that has not yet been given an appCode.
ChainIdSet
Typestate marker for a builder that has been given a chain id.
ChainIdUnset
Typestate marker for a builder that has not yet been given a chain id.
LimitBuilder
Fluent, typed builder for a limit order, reached through Trading::limit.
OrderbookBinding
Runtime binding captured from an orderbook client for quote-derived workflows.
QuotedSwap
A fetched swap quote, ready to inspect and submit. Produced by SwapBuilder::quote.
Set
Typestate marker: a required swap field has been supplied.
SwapBuilder
Fluent, typed builder for a swap order, reached through Trading::swap.
Trading
High-level trading facade that stores trader defaults plus an optional injected orderbook client.
TradingBuilder
Builder for Trading.
Unset
Typestate marker: a required swap field has not been supplied yet.

Enums§

PartnerFee
Typed partner-fee metadata accepted by app-data and trading helpers.
PartnerFeePolicy
One typed partner-fee policy object.
SupportedChainId
Supported CoW Protocol chain ids with explicit API configuration.

Traits§

OrderbookClient
Minimal orderbook capability required by trading and composable consumers.

Functions§

unwrap_transaction
Builds the gas-free transaction that unwraps amount of the wrapped-native token back into the chain’s native asset (for example WETH into ETH).
wrap_transaction
Builds the gas-free transaction that wraps amount of the chain’s native asset into its wrapped-native token (for example ETH into WETH).

Attribute Macros§

async_trait
Re-exported so seam-trait implementors need no direct async-trait dependency, mirroring serde’s derive re-export.