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 before0.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
| Feature | Default | Enables |
|---|---|---|
tracing | off | tracing 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
CoWSwapEthFlowcall-data encoders generated from the upstream Solidity surface via thealloy::sol!macro. Typed ABI bindings for theCoWSwapEthFlowcontract. - onchain
- On-chain order actions and transaction builders.
- order
- Order-construction helpers and
EthFlowadjustments. - 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§
- AppCode
Set - Typestate marker for a builder that has been given an
appCode. - AppCode
Unset - Typestate marker for a builder that has not yet been given an
appCode. - Chain
IdSet - Typestate marker for a builder that has been given a chain id.
- Chain
IdUnset - Typestate marker for a builder that has not yet been given a chain id.
- Limit
Builder - Fluent, typed builder for a limit order, reached through
Trading::limit. - Orderbook
Binding - Runtime binding captured from an orderbook client for quote-derived workflows.
- Quoted
Swap - A fetched swap quote, ready to inspect and submit. Produced by
SwapBuilder::quote. - Set
- Typestate marker: a required swap field has been supplied.
- Swap
Builder - 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.
- Trading
Builder - Builder for
Trading. - Unset
- Typestate marker: a required swap field has not been supplied yet.
Enums§
- Partner
Fee - Typed partner-fee metadata accepted by app-data and trading helpers.
- Partner
FeePolicy - One typed partner-fee policy object.
- Supported
Chain Id - Supported
CoWProtocol chain ids with explicit API configuration.
Traits§
- Orderbook
Client - Minimal orderbook capability required by trading and composable consumers.
Functions§
- unwrap_
transaction - Builds the gas-free transaction that unwraps
amountof 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
amountof 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-traitdependency, mirroring serde’s derive re-export.