stop or at or above takeProfit, the program sells the Pot’s WETH for USDC on Uniswap V3’s 0.05% pool, down to a floor of the oracle price less maxSlippageBps. Between the thresholds it returns without trading. The cook reverts on a feed answer older than maxAge seconds, a non-positive answer, or an average sale price below the floor.
Target chains: Ethereum. Chainlink.EthUsdFeed is not in Base’s registry, and sauce compile --chain base refuses the file.
This program evaluates conditions only when called. To run it repeatedly, use an external scheduler or caller that submits an authorized transaction.
Prerequisites
Install the Sauce CLI to compile and simulate. To send the transaction, configure a wallet with native coin for gas and the Kitchen fee. Fund the Pot once it is deployed, or use--fund; the program sells WETH the Pot holds.
Program
pot is the Pot the program runs on, available without declaring it; pot.USDC and pot.WETH are its balances (Names).
stop-loss.sauce.ts
How it works
- Chainlink declares
answerasint256, soround.answeris anInt256. The program requires it to be positive, then converts it once withUint256(round.answer). The conversion is checked: a negative value reverts instead of becoming a large unsigned number. Every comparison andMath.mulDivafter it is unsigned. ctx.timestamp() - round.updatedAt <= maxAgerejects a feed answer older thanmaxAge. The program acts on the oracle’s price, not the pool’s, so a pool pushed away from the oracle within one block does not trigger a sale.- The floor is in USDC base units per WETH:
pricehas the feed’s 8 decimals, and dividing by10000 * 100both appliesmaxSlippageBpsand drops 2 decimals to USDC’s 6. - The swap’s price limit is the floor’s sqrt price moved by
sqrt(1 - fee), so the last unit sold still fetches the floor after the pool fee. When the pool is already past that limit, the program returnssold: 0instead of calling the swap. soldandreceivedare the changes in the Pot’s WETH and USDC balances, and the finalrequirechecks the average price from those.
The swap stops at the floor. In a falling market the pool can reach it before all the WETH sells; the rest stays in the Pot until a later run finds a price above the floor.
Run the example
1
Compile
2
Simulate
--assume-balance WETH:1 gives the Pot 1 WETH for this simulation only. A stop of 10,000 USD, above the market, makes this run trigger.3
Send
sauce tx stop-loss.sauce.ts --chain ethereum --owner <your-address> --args 240000000000 320000000000 100 3600 prints the unsigned transactions instead, for your own signer or scheduler.Simulation result
Simulated on a local fork of Ethereum at block 26284400 with the current contracts, using the Simulate command above:stop 10,000 USD, no take-profit, 1% slippage, a one-hour maxAge. Nothing was signed or sent.
maxAge set to 1 second, the feed’s latest answer is too old and the cook reverts:
Next steps
- Dollar-cost averaging: build the WETH position one tranche at a time.
- Buy the dip: buy WETH when the oracle price falls a set percentage.
- Oracle-guarded swap: a single swap held to an oracle price.
- Sweep the Pot: move the USDC from the Pot to a wallet.
sauce simulate, Names, Protocols reference.
