Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

Solidity interface library for the Rain Protocol order book. Defines interfaces and types for an onchain order book where orders are strategies expressed as Rainlang interpreter bytecode. Part of the Rain Protocol ecosystem.
Solidity interface library for Raindex (Rain Protocol's onchain order book). Defines interfaces and types for an order book where orders are strategies expressed as Rainlang interpreter bytecode. Part of the Rain Protocol ecosystem.

License: DecentraLicense 1.0 (DCL-1.0). REUSE 3.2 compliant — all files need SPDX headers:
```solidity
Expand All @@ -30,8 +30,8 @@ Compiler: Solidity 0.8.25, EVM target: cancun, optimizer enabled (1M runs). Fuzz

### Interfaces (`src/interface/`)

- **IOrderBookV6** — Current stable interface. Vault-based order book with deposit/withdraw, add/remove orders, take orders (market buy), and clear (match two orders with bounty). IERC3156 flash loan compliant. Supports vaultless orders (vault ID `0` means tokens move directly from wallet) and input/output-based take order limits via `IOIsInput` flag.
- **IOrderBookV6OrderTaker / IOrderBookV6ArbOrderTaker** — Callback interfaces for takers receiving tokens during `takeOrders`.
- **IRaindexV6** — Current stable interface. Vault-based order book with deposit/withdraw, add/remove orders, take orders (market buy), and clear (match two orders with bounty). IERC3156 flash loan compliant. Supports vaultless orders (vault ID `0` means tokens move directly from wallet) and input/output-based take order limits via `IOIsInput` flag.
- **IRaindexV6OrderTaker / IRaindexV6ArbOrderTaker** — Callback interfaces for takers receiving tokens during `takeOrders`.
- **ierc3156/** — Flash loan interfaces (IERC3156FlashLender, IERC3156FlashBorrower).
- **deprecated/** (v1-v5) — Old interface versions. Do not modify unless undeprecating.

Expand Down Expand Up @@ -61,7 +61,7 @@ rain.math.float/=lib/rain.interpreter.interface/lib/rain.math.float/src/

- All reverts use custom errors — no `revert("string")` or `require()` with string messages.
- Interfaces use `pragma solidity ^0.8.18` (note: differs from interpreter interface which uses `^0.8.25`).
- Versioned naming: interfaces (`IOrderBookV6`), structs (`OrderV4`, `ClearConfigV2`), events (`AddOrderV3`), functions (`deposit4`, `withdraw4`).
- Versioned naming: interfaces (`IRaindexV6`), structs (`OrderV4`, `ClearConfigV2`), events (`AddOrderV3`), functions (`deposit4`, `withdraw4`).
- Use `//forge-lint: disable-next-line(...)` comments for lint suppressions: `unused-import`, `mixed-case-variable`, `pascal-case-struct`.
- Use `//forge-lint: disable-start(...)`/`disable-end(...)` for multi-line suppressions.
- Branch naming: `YYYY-MM-DD-description`.
Expand Down
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,47 @@
# Raindex

Raindex is a programmable, dynamic onchain order book. Orders are not static
limit orders — they are strategies written as Rain interpreter expressions that
evaluate at match time. This means order amounts and ratios can change based on
onchain state, time, oracle prices, or any other logic the expression author
encodes. Two orders clear when their evaluated ratios overlap, with any surplus
going to the clearer as a bounty.

## Raindex vs. traditional order books

Traditional onchain order books (e.g. dYdX, Serum) replicate the familiar
limit-order model: users place fixed-price bids and asks, a matching engine
pairs them, and fills execute at the stated price. This works, but each
repricing requires a new transaction, making active market-making expensive
and slow.

Raindex replaces static prices with executable expressions. An order's ratio
and maximum amount are computed fresh every time someone attempts to match it.
The expression can read any onchain state — block number, oracle feeds, vault
balances, its own persistent storage — so a single order can implement
strategies that would otherwise require off-chain bots continuously cancelling
and reposting.

## Raindex vs. AMMs

AMMs (Uniswap, Curve, Balancer) achieve always-on liquidity by pooling tokens
into a shared reserve governed by a bonding curve. Liquidity providers deposit
tokens and receive pool shares; the curve mechanically sets the price. This
removes the need for active order management but introduces impermanent loss,
pool-level MEV extraction, and limited strategic control for individual LPs.

Raindex keeps individual ownership of tokens in per-user vaults — there is no
shared pool. Each order owner defines their own pricing logic, so there is no
bonding curve imposing a single price on all participants. Because orders
evaluate independently, one user's strategy cannot dilute or override another's.
Clearers (analogous to AMM arbitrageurs) match overlapping orders and keep the
surplus, providing the same "always available" clearing incentive that
arbitrageurs provide to AMMs, but without requiring passive LPs to share a
pool.

This repo defines the Solidity interfaces and types for Raindex. It does not
contain the implementation.

## Dev stuff

### Local environment & CI
Expand Down
22 changes: 0 additions & 22 deletions src/interface/IOrderBookV6ArbOrderTaker.sol

This file was deleted.

65 changes: 32 additions & 33 deletions src/interface/IOrderBookV6.sol → src/interface/IRaindexV6.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
IInterpreterStoreV3
} from "../../lib/rain.interpreter.interface/src/interface/IInterpreterCallerV4.sol";

/// Import unmodified structures from older versions of `IOrderBook`.
/// Import unmodified structures from older versions of the Raindex interface.
import {
ClearStateChangeV2,
ClearConfigV2,
Expand Down Expand Up @@ -61,9 +61,9 @@ struct TakeOrdersConfigV5 {
bytes data;
}

/// @title IOrderBookV6
/// @notice An orderbook that deploys _strategies_ represented as interpreter
/// expressions rather than individual orders. The order book contract itself
/// @title IRaindexV6
/// @notice A Raindex that deploys _strategies_ represented as interpreter
/// expressions rather than individual orders. The Raindex contract itself
/// behaves similarly to an `ERC4626` vault but with much more fine grained
/// control over how tokens are allocated and moved internally by their owners,
/// and without any concept of "shares". Token owners MAY deposit and withdraw
Expand Down Expand Up @@ -91,7 +91,7 @@ struct TakeOrdersConfigV5 {
/// move from order B to order A and 10 TKNA will move to the clearer's vault and
/// 1 TKNB will move from order A to order B. In the case of fixed prices this is
/// not very interesting as order B could more simply take order A directly for
/// cheaper rather than involving a third party. Indeed, Orderbook supports a
/// cheaper rather than involving a third party. Indeed, Raindex supports a
/// direct "take orders" method that works similar to a "market buy". In the case
/// of dynamic expression based ratios, it allows both order A and order B to
/// clear non-interactively according to their strategy, trading off active
Expand All @@ -110,13 +110,12 @@ struct TakeOrdersConfigV5 {
/// ∴ ratioA * ratioB <= 1
/// ```
///
/// Orderbook is `IERC3156FlashLender` compliant with a 0 fee flash loan
/// Raindex is `IERC3156FlashLender` compliant with a 0 fee flash loan
/// implementation to allow external liquidity from other onchain DEXes to match
/// against orderbook expressions. All deposited tokens across all vaults are
/// against Raindex expressions. All deposited tokens across all vaults are
/// available for flashloan, the flashloan MAY BE REPAID BY CALLING TAKE ORDER
/// such that Orderbook's liability to its vaults is decreased by an incoming
/// trade from the flashloan borrower. See `ZeroExOrderBookFlashBorrower` for
/// an example of how this works in practise.
/// such that Raindex's liability to its vaults is decreased by an incoming
/// trade from the flashloan borrower.
///
/// Token amounts and ratios returned by calculate order MUST be rain floating
/// point values. Handle IO will receive these values as floating point values.
Expand All @@ -125,32 +124,32 @@ struct TakeOrdersConfigV5 {
/// at 37 decimals generally because when packed the floats are normalized to
/// int128 values for the coefficients. Generally this means that the precision
/// is larger than the entire minted supply of almost all tokens in existence.
/// In the rare case of a token that has token balances in the orderbook larger
/// In the rare case of a token that has token balances in the Raindex larger
/// than 10^38, some truncation will occur after the 37th decimal place
/// internally, on the _least_ significant digits, so should not be an issue
/// even in extreme edge cases.
///
/// Internal float values are converted to absolute token values according to the
/// token's own `decimals` call only when tokens are moved by the orderbook. This
/// token's own `decimals` call only when tokens are moved by the Raindex. This
/// means that some tokens MAY NOT be supported:
/// - If the token does not implement `decimals` then the orderbook will revert
/// - If the token does not implement `decimals` then the Raindex will revert
/// when trying to move tokens.
/// - If the token has a `decimals` value that is not a constant value then the
/// internal accounting will be incorrect and the orderbook will either be
/// internal accounting will be incorrect and the Raindex will either be
/// drained of or lock up that token. (other tokens will not be impacted).
///
/// When two orders clear there are NO TOKEN MOVEMENTS, only internal vault
/// balances are updated from the input and output vaults. Typically this results
/// in less gas per clear than calling external token transfers and also avoids
/// issues with reentrancy, allowances, external balances etc. This also means
/// that REBASING TOKENS AND TOKENS WITH DYNAMIC BALANCE ARE NOT SUPPORTED.
/// Orderbook ONLY WORKS IF TOKEN BALANCES ARE 1:1 WITH ADDITION/SUBTRACTION PER
/// Raindex ONLY WORKS IF TOKEN BALANCES ARE 1:1 WITH ADDITION/SUBTRACTION PER
/// VAULT MOVEMENT.
///
/// Dust due to rounding errors always favours the order. Output max is rounded
/// down and IO ratios are rounded up. Input and output amounts are always
/// converted to absolute values before applying to vault balances such that
/// orderbook always retains fully collateralised inventory of underlying token
/// Raindex always retains fully collateralised inventory of underlying token
/// balances to support withdrawals, with the caveat that dynamic token balances
/// are not supported.
///
Expand All @@ -173,18 +172,18 @@ struct TakeOrdersConfigV5 {
///
/// Note that each order specifies its own interpreter and deployer so the
/// owner is responsible for not corrupting their own calculations with bad
/// interpreters. This also means the Orderbook MUST assume the interpreter, and
/// interpreters. This also means the Raindex MUST assume the interpreter, and
/// notably the interpreter's store, is malicious and guard against reentrancy
/// etc.
///
/// As Orderbook supports any expression that can run on any `IInterpreterV4` and
/// As Raindex supports any expression that can run on any `IInterpreterV4` and
/// counterparties are available to the order, order strategies are free to
/// implement KYC/membership, tracking, distributions, stock, buybacks, etc. etc.
///
/// Main differences between `IOrderBookV5` and `IOrderBookV6`:
/// Main differences between `IOrderBookV5` and `IRaindexV6`:
/// - Supports vaultless orders.
/// - Supports take order configuration based on taker output rather than input.
interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {
interface IRaindexV6 is IERC3156FlashLender, IInterpreterCallerV4 {
/// MUST be thrown by `deposit` and `withdraw` if the vault ID is zero.
/// @param sender `msg.sender` depositing or withdrawing tokens.
/// @param token The token being deposited or withdrawn.
Expand Down Expand Up @@ -251,18 +250,18 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {
uint256 withdrawAmountUint256
);

/// An order has been added to the orderbook. The order is permanently and
/// An order has been added to the Raindex. The order is permanently and
/// always active according to its expression until/unless it is removed.
/// @param sender `msg.sender` adding the order and is owner of the order.
/// @param orderHash The hash of the order as it is recorded onchain. Only
/// the hash is stored in Orderbook storage to avoid paying gas to store the
/// the hash is stored in Raindex storage to avoid paying gas to store the
/// entire order.
/// @param order The newly added order. MUST be handed back as-is when
/// clearing orders and contains derived information in addition to the order
/// config that was provided by the order owner.
event AddOrderV3(address sender, bytes32 orderHash, OrderV4 order);

/// An order has been removed from the orderbook. This effectively
/// An order has been removed from the Raindex. This effectively
/// deactivates it. Orders can be added again after removal.
/// @param sender `msg.sender` removing the order and is owner of the order.
/// @param orderHash The hash of the removed order.
Expand Down Expand Up @@ -345,7 +344,7 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {
///
/// At the same time, allowing vault IDs to be specified by the depositor
/// allows much more granular and direct control over token movements within
/// Orderbook than either ERC4626 vault shares or mere contract-level ERC20
/// Raindex than either ERC4626 vault shares or mere contract-level ERC20
/// allowances can facilitate.
///
/// Vault IDs are namespaced by the token address so there is no risk of
Expand All @@ -354,11 +353,11 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {
///
/// `0` amount deposits are unsupported as underlying token contracts
/// handle `0` value transfers differently and this would be a source of
/// confusion. The order book MUST revert with `ZeroDepositAmount` if the
/// confusion. The Raindex MUST revert with `ZeroDepositAmount` if the
/// amount is zero.
///
/// Vault ID `0` is disallowed for deposits to avoid collision with vaultless
/// orders. The order book MUST revert with `ZeroVaultId` if the vault ID is
/// orders. The Raindex MUST revert with `ZeroVaultId` if the vault ID is
/// zero.
///
/// @param token The token to deposit.
Expand All @@ -371,7 +370,7 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {

/// Allows the sender to withdraw any tokens from their own vaults. If the
/// withdrawer has an active flash loan debt denominated in the same token
/// being withdrawn then Orderbook will merely reduce the debt and NOT send
/// being withdrawn then Raindex will merely reduce the debt and NOT send
/// the amount of tokens repaid to the flashloan debt.
///
/// MUST revert if the amount _requested_ to withdraw is zero. The withdrawal
Expand All @@ -380,13 +379,13 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {
/// other internal accounting.
///
/// Vault ID `0` is NOT supported due to collision with vaultless orders.
/// The order book MUST revert with `ZeroVaultId` if the vault ID is zero.
/// The Raindex MUST revert with `ZeroVaultId` if the vault ID is zero.
///
/// @param token The token to withdraw.
/// @param vaultId The vault ID to withdraw from.
/// @param targetAmount The amount of tokens to attempt to withdraw. MAY
/// result in fewer tokens withdrawn if the vault balance is lower than the
/// target amount. MAY NOT be zero, the order book MUST revert with
/// target amount. MAY NOT be zero, the Raindex MUST revert with
/// `ZeroWithdrawTargetAmount` if the amount is zero.
/// @param tasks Additional tasks to run after the withdraw. Withdraw
/// information SHOULD be made available during evaluation in context.
Expand Down Expand Up @@ -430,9 +429,9 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {
/// MUST revert with `OrderNoInputs` if the order has no inputs.
/// MUST revert with `OrderNoOutputs` if the order has no outputs.
///
/// If the order already exists, the order book MUST NOT change state, which
/// If the order already exists, the Raindex MUST NOT change state, which
/// includes not emitting an event. Instead it MUST return false. If the
/// order book modifies state it MUST emit an `AddOrder` event and return
/// Raindex modifies state it MUST emit an `AddOrderV3` event and return
/// true.
///
/// If vault ID is `0` for any input or output, this indicates a vaultless
Expand Down Expand Up @@ -508,9 +507,9 @@ interface IOrderBookV6 is IERC3156FlashLender, IInterpreterCallerV4 {

/// Allows `msg.sender` to match two live orders placed earlier by
/// non-interactive parties and claim a bounty in the process. The clearer is
/// free to select any two live orders on the order book for matching and as
/// free to select any two live orders on the Raindex for matching and as
/// long as they have compatible tokens, ratios and amounts, the orders will
/// clear. Clearing the orders DOES NOT remove them from the orderbook, they
/// clear. Clearing the orders DOES NOT remove them from the Raindex, they
/// remain live until explicitly removed by their owner. Even if the input
/// vault balances are completely emptied, the orders remain live until
/// removed. This allows order owners to deploy a strategy over a long period
Expand Down
20 changes: 20 additions & 0 deletions src/interface/IRaindexV6ArbOrderTaker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 thedavidmeister
pragma solidity ^0.8.18;

import {IRaindexV6OrderTaker} from "./IRaindexV6OrderTaker.sol";
import {TakeOrdersConfigV5, IRaindexV6, TaskV2} from "./IRaindexV6.sol";

/// @title IRaindexV6ArbOrderTaker
/// @notice Interface for contracts that execute arbitrage against an
/// `IRaindexV6` Raindex by taking orders and executing a post-arb task.
interface IRaindexV6ArbOrderTaker is IRaindexV6OrderTaker {
/// Executes an arbitrage against the given Raindex. The `msg.value` MAY
/// be used by the implementation to wrap native tokens or interact with
/// external liquidity sources. Implementations MUST validate that
/// `raindex` is a trusted contract.
/// @param raindex The Raindex to arb against.
/// @param takeOrders Config for the orders to take.
/// @param task Post-arb task to evaluate.
function arb5(IRaindexV6 raindex, TakeOrdersConfigV5 calldata takeOrders, TaskV2 calldata task) external payable;
}
Loading