Skip to content
Open
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
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,21 @@ On settlement it liquidates the position and exits the seized collateral through
settlement transaction — RedStone's auctioneer does. The solver config owns the RedStone Executor,
LiquidLane adapter, and callback address; the selected strategy owns the callback-specific
`operationData`. Operators can set `maxBidWei` as a per-auction spend ceiling over any strategy; it is
required for the external `webhook` strategy and optional for the built-in `default`. Design, config,
and roadmap:
required for the external `webhook` strategy and optional for the built-in `default`. The common `gas:`
block is optional, and its shared oracle facts are passed to the selected strategy. The built-in strategy
uses them for after-cost economics; without them, it selects gross-profitable bundles while retaining the
signed gas-price cap and native funding checks. When `gas:` is configured, startup requires a feed for the
resolved adapter loan asset and a readable initial oracle snapshot. Design, config, and roadmap:
[`docs/OEV-PLAN.md`](docs/OEV-PLAN.md) · example
[`config/redstone-oev.example.yaml`](config/redstone-oev.example.yaml).

### LI.FI Same-Chain Intents — `lifi-samechain`

A same-chain LI.FI Intents solver for LiquidLane-backed RWA → underlying routes. It publishes gas-aware
standing quotes from current adapter liquidity and receives matched, already-opened escrow orders over the
A same-chain LI.FI Intents solver for LiquidLane-backed RWA → underlying routes. It publishes standing quotes
from current adapter liquidity with optional gas accounting and receives matched, already-opened escrow orders over the
LI.FI WebSocket feed. On startup and reconnect it catches up active matches through `GET /orders` before
publishing quotes; while disconnected it suspends renewal and retries expiry of known curves. Before each fill it
rechecks the canonical order status, adapter state, gas cost, and strategy decision, then atomically claims
rechecks the canonical order status, adapter state, configured gas cost, and strategy decision, then atomically claims
the input, redeems it through LiquidLane, and fills the output via
`LiquidLaneLifiExecutor`. Capacity reserved by already-submitted fills is deducted from both later fill
decisions and standing quotes until those transactions complete. Each token pair advertises the full currently
Expand All @@ -143,9 +146,12 @@ solver greedily rebuilds the best current route plan, and redeemed output above
executor surplus. The default strategy trims an uneconomic range prefix to the first input whose conservative
floor yields a positive output, then prices the published suffix by running the shared LiquidLane exact-input
quote solver at both endpoints. It caps the lower of the two endpoint rates by that floor for interior route
transitions, worst-case route gas, and rounding.
transitions, rounding, and, when configured, worst-case route gas.
`strategy.config.rangeCount` sets the geometric curve resolution (default `8`, maximum `16`).

Omitting LI.FI's `gas:` block disables gas accounting in quote/fill decisions and skips gas-state and
Chainlink reads; the tx manager still prices and pays the actual transaction gas.

The executor contract is the registered LI.FI solver account. It is registered once through EIP-1271 using
a caller signature bound to the executor's EIP-712 domain, appears as `exclusiveFor` in quotes, and calls the
settler's direct finalise path. The framework signer is an authorized executor caller and transaction sender;
Expand All @@ -164,8 +170,8 @@ scheduling are out of scope. Dutch (`0x01`) and exclusive Dutch (`0xe1`) orders
admission and logged as unsupported. `solverMode: external` serves direct filler-authorized adapters.
`solverMode: internal` also enables signed private discounts through the shared backend. `tokensToQuote` uses the same `all`,
`permissioned`, and `permissionless` scopes as RFQ; permissioned inputs must execute through one physical
route. The order-server REST/WS endpoints are explicit required config, and each Chainlink gas feed has
its own required max age. The default strategy evaluates bounded geometric exact-input ranges across
route. The order-server REST/WS endpoints are explicit required config. When `gas:` is configured, each
Chainlink feed has its own required max age. The default strategy evaluates bounded geometric exact-input ranges across
available capacity. See the plan for settlement, pricing, concurrency, and onboarding details:
[`docs/LIFI-PLAN.md`](docs/LIFI-PLAN.md) · example
[`config/lifi.example.yaml`](config/lifi.example.yaml).
Expand Down Expand Up @@ -271,7 +277,7 @@ The solvers split protocol plumbing (reads, signing, submission — fixed) from
- **`webhook`** — delegates each decision to an **external HTTP service you run**: the solver sends it
the raw facts as JSON and executes the validated plan it returns, so your service owns the logic.
LI.FI and UniswapX own separate strategy contracts and independently reject returned fills that exceed
current capacity or do not cover the order plus gas. UniswapX delegates each concrete quote to
current capacity or do not cover the order plus configured gas. UniswapX delegates each concrete quote to
`POST /decide-quote` and each current fill plan to `POST /decide-fill` under the configured webhook URL.

This is the seam for customizing a solver without forking. Contract and trust model:
Expand Down
5 changes: 3 additions & 2 deletions config/lifi.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ solvers:
rangeCount: 8 # geometric ranges per pair (default 8, max 16)
executionDeadlineBuffer: 12s # one Ethereum block left for order and private signatures

# Gas conversion is a solver fact shared by every strategy. Configure one Chainlink USD feed for
# every distinct adapter vault asset (tokenOut); startup fails if any resolved route is uncovered.
# Optional. Omit to use zero economic gas cost and skip gas-state/Chainlink reads; txmanager still
# prices actual transactions under global maxFeeGwei. When present, configure one token/USD feed for
# every distinct adapter vault asset (tokenOut), or startup fails.
gas:
nativeUsdFeed: ${ETH_USD_FEED}
nativeMaxAge: 2h # actual heartbeat plus testnet publication slack
Expand Down
26 changes: 16 additions & 10 deletions config/redstone-oev.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ solvers:
# cross-adapter deallocation-cascade estimate instead of getMaxAssets(). Omit to use the adapter getter.
callback: "0x065B612a182f360D4428cD00a8094049B3c92168" # SymbioticOevSolver — receives Executor callback and pays the bid

# Optional common gas accounting. Omit the entire block to skip Chainlink reads and choose bundles
# by gross loan-token profit. Gas-limit fitting, native Executor-deposit headroom/reservations, the
# fixed callback-funded bid, and the signed maxTxGasPriceWei cap still apply when this is omitted.
gas:
nativeUsdFeed: "0x694AA1769357215DE4FAC081bf1f309aDC325306" # Chainlink Sepolia ETH / USD
nativeMaxAge: 24h # native feed heartbeat plus publication slack
tokenUsdFeeds:
- token: "0x468BB3245BF520a0CD030BDE029c98aCEAF84C9d" # actual adapter vault asset / loan token (TLOAN)
feed: "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E" # Chainlink Sepolia USDC / USD (proxy for TLOAN)
maxAge: 24h # set independently for every token/USD feed

strategy:
name: default
config:
Expand All @@ -46,18 +57,12 @@ solvers:
# # local Morpho math then decides real liquidatability at the auction price
# maxTrackedPositions: 10000 # Morpho API page size + in-memory at-risk position cap (default 10000)

# ETH price feeds used to value gas/bid/profit in USD. loanUsd prices the loan token; on the
# testbed TLOAN is a $1 token, so it reuses Chainlink's Sepolia USDC/USD feed.
loanEthFeed:
ethUsd: "0x694AA1769357215DE4FAC081bf1f309aDC325306" # Chainlink Sepolia ETH / USD
loanUsd: "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E" # Chainlink Sepolia USDC / USD (proxy for TLOAN)
maxAgeMs: 86400000 # max feed staleness before a read fails (default 3600000 = 1h)

bid:
bidEth: "0.0005" # minimum bid in ETH; the final bid is max(this, gross-profit share)
authTtlMs: 60000 # callback-auth replay window (default 60000); independent of the auction timeout
totalBundleProfitBps: 0 # optional bid share of gross bundle profit, in native terms (default 0)
minBundleProfitBidBps: 1000 # required extra bundle margin after gas + bid, as bps of the final bid
totalBundleProfitBps: 0 # optional bid share of gross bundle profit, in native terms (requires gas)
minBundleProfitBidBps: 1000 # extra margin after gas + bid, as bps of the final bid (requires gas)
# omit/set both bps fields to 0 when the top-level gas block is omitted

sizing:
allowFullLiquidation: true # seize full collateral when profitable (default true); false forces fixed 90% partial mode
Expand All @@ -66,7 +71,8 @@ solvers:
monitorPollMs: 10000 # default strategy monitor snapshot poll (API in prod, testMonitor on Sepolia)
maxStateAgeMs: 90000 # max default-strategy cache age before stale_state

maxTxGasPriceWei: "20000000000" # signed tx.gasprice ceiling + solver envelope assumption
maxTxGasPriceWei: "20000000000" # signed tx.gasprice ceiling + native deposit/gas-reservation assumption;
# remains positive and active when gas economics are disabled
# maxBidWei: "1000000000000000" # optional for default; required when strategy.name is webhook

breaker:
Expand Down
Loading