Skip to main content
Trade Above Threshold orders automatically trigger when your token balance exceeds a specified amount. When triggered, the order sells your entire balance at the current market price, making it useful for automated conversions and yield harvesting.

How It Works

The contract continuously monitors your balance of a specific token. When your balance reaches or exceeds the threshold, it creates a sell order for your entire balance.
if (sellToken.balanceOf(owner) >= threshold) {
    // Sell entire balance at market price
}
This order type sells at market price (buyAmount = 1) without price limits. Ensure you trust the CoW Protocol solvers to provide fair execution.

Data Structure

struct Data {
    IERC20 sellToken;
    IERC20 buyToken;
    address receiver;
    uint32 validityBucketSeconds;
    uint256 threshold;
    bytes32 appData;
}

Parameters

sellToken
IERC20
required
The token to monitor and sell when the threshold is reached
buyToken
IERC20
required
The token to receive in exchange
receiver
address
required
The address that will receive the bought tokens
validityBucketSeconds
uint32
required
The width of the validity bucket in seconds. Orders queried within the same bucket will have the same validTo timestamp (and thus the same orderUid).The validTo timestamp is calculated as:
validTo = ((currentTime / validityBucketSeconds) * validityBucketSeconds) + validityBucketSeconds
Recommended values:
  • 300 (5 minutes)
  • 900 (15 minutes)
  • 3600 (1 hour)
Shorter periods update the order more frequently, longer periods reduce orderbook spam.
threshold
uint256
required
The minimum balance of sellToken required to trigger the order. When balance >= threshold, the order becomes valid.Example: Set to 1000e18 to trigger when you have at least 1000 tokens (assuming 18 decimals)
appData
bytes32
required
The IPFS hash of the appData associated with the order

Behavior

Threshold Check

The order checks your current balance:
uint256 balance = data.sellToken.balanceOf(owner);

if (balance >= data.threshold) {
    // Order is valid, sell entire balance
} else {
    // Order not valid, poll next block
}

Sell Amount

The order always sells your entire current balance, not just the threshold amount:
sellAmount = balance  // Entire balance
buyAmount = 1         // Market order (no price limit)
The order sells your complete balance, not just the excess above the threshold. If you have 2000 tokens and threshold is 1000, it will sell all 2000 tokens.

Market Execution

The order sets buyAmount = 1 (the minimum non-zero value), which effectively makes it a market order. The actual received amount depends on the solver’s execution.
CoW Protocol solvers compete to provide the best execution. While there’s no explicit limit price, solvers are incentivized to maximize your output to win the batch.

Validity Bucketing

The order uses validity buckets to prevent orderbook spam. Orders queried within the same bucket have identical orderUid values:
validTo = ((block.timestamp / validityBucketSeconds) * validityBucketSeconds) + validityBucketSeconds
Example with 15-minute buckets:
  • At 10:07 → validTo = 10:15
  • At 10:12 → validTo = 10:15 (same orderUid)
  • At 10:16 → validTo = 10:30 (new orderUid)

Order Properties

  • Kind: Always sell orders (KIND_SELL)
  • Partially fillable: No (false)
  • Fee: 0 (limit order)
  • Balance: ERC20 balances for both tokens

Validation

BALANCE_INSUFFICIENT
error
The owner’s balance is below the threshold. The order will poll again in the next block.

Example Usage

Example 1: Yield Harvesting

Automatically sell staking rewards when they accumulate:
TradeAboveThreshold.Data memory order = TradeAboveThreshold.Data({
    sellToken: IERC20(REWARD_TOKEN_ADDRESS),
    buyToken: IERC20(USDC_ADDRESS),
    receiver: msg.sender,
    validityBucketSeconds: 3600,      // 1 hour buckets
    threshold: 100e18,                // Sell when >= 100 rewards
    appData: bytes32(0)
});

bytes memory staticInput = abi.encode(order);
Scenario:
  • You earn 10 REWARD tokens per day from staking
  • When balance reaches 100 tokens (after ~10 days), order triggers
  • Automatically converts all rewards to USDC
  • Repeats when balance reaches 100 again

Example 2: DCA Out of Position

Automatically sell tokens as you acquire them:
TradeAboveThreshold.Data memory order = TradeAboveThreshold.Data({
    sellToken: IERC20(TOKEN_ADDRESS),
    buyToken: IERC20(WETH_ADDRESS),
    receiver: msg.sender,
    validityBucketSeconds: 900,       // 15 minute buckets
    threshold: 50e18,                 // Sell when >= 50 tokens
    appData: bytes32(0)
});

bytes memory staticInput = abi.encode(order);

Example 3: Fee Collection

Automatically convert protocol fees to treasury token:
TradeAboveThreshold.Data memory order = TradeAboveThreshold.Data({
    sellToken: IERC20(FEE_TOKEN_ADDRESS),
    buyToken: IERC20(TREASURY_TOKEN_ADDRESS),
    receiver: TREASURY_ADDRESS,
    validityBucketSeconds: 86400,     // 1 day buckets
    threshold: 1000e6,                // Sell when >= 1000 USDC fees
    appData: bytes32(0)
});

bytes memory staticInput = abi.encode(order);

Example 4: Low Threshold for Frequent Conversions

Convert tokens frequently with low threshold:
TradeAboveThreshold.Data memory order = TradeAboveThreshold.Data({
    sellToken: IERC20(USDC_ADDRESS),
    buyToken: IERC20(DAI_ADDRESS),
    receiver: msg.sender,
    validityBucketSeconds: 300,       // 5 minute buckets
    threshold: 10e6,                  // Sell when >= 10 USDC
    appData: bytes32(0)
});

bytes memory staticInput = abi.encode(order);

Use Cases

Automated Yield Harvesting

  • Stake tokens and earn rewards
  • Automatically sell rewards when they accumulate
  • Convert to stablecoins or other tokens
  • No manual intervention needed

Regular Conversions

  • Receive payments in one token
  • Automatically convert to preferred token
  • Maintain desired portfolio composition
  • Dollar-cost average out of positions

Fee Management

  • Collect protocol fees in various tokens
  • Automatically convert to treasury token
  • Reduce operational overhead
  • Optimize gas costs with threshold-based execution

Stream Liquidation

  • Receive token streams (e.g., from Sablier)
  • Automatically liquidate streamed tokens
  • Convert to desired asset
  • Minimize manual transactions

Implementation Details

Contract Address

The Trade Above Threshold conditional order type is deployed at /src/types/TradeAboveThreshold.sol.

Key Function

function getTradeableOrder(
    address owner,
    address,
    bytes32,
    bytes calldata staticInput,
    bytes calldata
) public view override returns (GPv2Order.Data memory order) {
    TradeAboveThreshold.Data memory data = abi.decode(staticInput, (Data));
    
    uint256 balance = data.sellToken.balanceOf(owner);
    
    // Check if balance meets threshold
    if (!(balance >= data.threshold)) {
        revert IConditionalOrder.PollTryNextBlock(BALANCE_INSUFFICIENT);
    }
    
    // Create order selling entire balance
    order = GPv2Order.Data(
        data.sellToken,
        data.buyToken,
        data.receiver,
        balance,  // Sell entire balance
        1,        // Market order (no limit)
        Utils.validToBucket(data.validityBucketSeconds),
        data.appData,
        0,
        GPv2Order.KIND_SELL,
        false,
        GPv2Order.BALANCE_ERC20,
        GPv2Order.BALANCE_ERC20
    );
}

Validity Bucket Utility

function validToBucket(uint32 validity) internal view returns (uint32 validTo) {
    validTo = ((uint32(block.timestamp) / validity) * validity) + validity;
}

Considerations

No Price Protection: This order type uses market execution without price limits. While CoW Protocol’s batch auction mechanism and solver competition provide some protection, there’s no guaranteed minimum output.
Balance Monitoring: The order continuously polls your balance. Once your balance falls below the threshold (e.g., after execution), the order becomes invalid until your balance increases again.
Gas Efficiency: By using a threshold, you avoid creating orders for small amounts. Set your threshold based on gas costs and desired trade frequency.

Build docs developers (and LLMs) love