How It Works
A Stop Loss order monitors the price ratio between two tokens using oracle feeds. When the ratio falls to or below your strike price, the order becomes executable. This provides automated risk management without manual monitoring.(sellTokenPrice / buyTokenPrice) <= strike
Data Structure
Parameters
The token to sell when the stop loss is triggered
The token to receive in exchange
For sell orders: the exact amount of
sellToken to sellFor buy orders: the maximum amount of sellToken willing to sellFor sell orders: the minimum amount of
buyToken to receiveFor buy orders: the exact amount of buyToken to receiveThe IPFS hash of the appData associated with the order
The address that will receive the proceeds of the trade
Whether this is a sell order (
true) or buy order (false)Whether solvers can partially fill the order. Useful when the exact amount isn’t known at placement time.
The UNIX timestamp until which the order is valid. Provides replay protection - the order will only execute once before this time.
A Chainlink-compatible oracle returning the sell token price in a specific numeraire (e.g., USD or ETH)Important: Must use the same numeraire as
buyTokenPriceOracleA Chainlink-compatible oracle returning the buy token price in the same numeraire as
sellTokenPriceOracleImportant: Must use the same numeraire as sellTokenPriceOracleThe exchange rate (denominated in sellToken/buyToken) that triggers the stop loss. Specified with 18 decimals.The order triggers when:
(sellTokenPrice * 10^18) / buyTokenPrice <= strikeExample: For a strike of $200, set strike = 200 * 10^18 = 200000000000000000000Maximum staleness allowed for oracle data in seconds. If either oracle hasn’t updated within this time, the order polls for the next block.Should exceed both oracles’ update intervals. Common values:
- Ethereum mainnet: 3600 (1 hour)
- Gnosis Chain: 600 (10 minutes)
Oracle Requirements
Price Validation
The contract performs several oracle validations:- Positive Prices: Both oracle prices must be greater than 0
- Freshness Check: Both oracles must have updated within
maxTimeSinceLastOracleUpdateseconds - Decimal Normalization: Prices are scaled to 18 decimals for comparison
Behavior
Strike Price Check
The order calculates the current exchange rate and compares it to the strike:SCALING_FACTOR = 10^18
Replay Protection
ThevalidTo parameter ensures the order only executes once. After execution or expiration, the order becomes permanently invalid.
Order Type
Stop loss orders:- Use zero fees (limit orders)
- Support both sell and buy order kinds
- Can be partially fillable
- Use ERC20 balance for both sell and buy tokens
Error Messages
The current time exceeds
validTo. The order has expired and will not execute.One or both oracles returned a price less than or equal to 0. The order will not execute.
One or both oracles have not updated within
maxTimeSinceLastOracleUpdate seconds. The order will poll again in the next block.The current price is above the strike price. The order will poll again in the next block.
Example Usage
Example 1: Protect GNO Position
Sell 100 GNO if the price falls below $200:Example 2: Stop Loss with Partial Fill
Sell up to 50 ETH if price falls below $2000, allowing partial fills:Example 3: Cross-Asset Stop Loss
Sell WBTC for ETH if BTC/ETH ratio falls below 15:Implementation Details
Contract Address
The Stop Loss conditional order type is deployed at/src/types/StopLoss.sol.
Key Function
Stop loss orders provide one-time protection. After execution, you’ll need to create a new order for continued protection.