Agent-ready decentralized DeFi protocol for non-custodial advanced order types on EVM chains.
Spot provides non-custodial market, limit, TWAP, stop-loss, take-profit, and delayed-start orders on EVM chains, backed by immutable onchain contracts.
🔒 Security Audit Reports: Initial AstraSec audit and updated AstraSec audit
- ✅ Non-custodial: RePermit binds spend authorization to exact order hashes instead of handing custody to the protocol.
- 🔒 Oracle-protected: Trigger checks, slippage caps, freshness windows, and deadlines constrain execution.
- 🛡️ Battle-tested: Contracts are audited and covered by an extensive Foundry test suite.
- 🏗️ Production-ready: Spot is built for multi-chain deployment with repo-shipped config, ABIs, skill files, and a hosted MCP endpoint.
- Market swaps
- Limit orders
- TWAP orders
- Stop-loss orders
- Take-profit orders
- Delayed-start orders
- Chunked recurring execution
Spot supports explicitly included chains with all six core contracts and at least one deployed shared (*) or chain-specific adapter. See config.json for the supported chain configurations and skill/SKILL.md for the matching chain list. Existing deployments do not add a chain to the supported set; Mantle and Manta remain excluded.
Run t before local order QA. npm test includes npm run test:e2e, a read-only live dependency check using chain, cast, jq, curl, and GNU parallel. It fetches the current production offchain oracle config once per run and reports the union of Spot config, skill chains, and oracle chains in a coverage table. npm run test:e2e -- 1 scopes the report to Ethereum.
The E2E table shows core deployment, deployed/known adapter counts, support status, and oracle health separately. Every explicit Spot chain requires all six core contracts and at least one deployed adapter; named solver counts are informational. Shared integrations whose adapters are undeployed are omitted from that chain's active integrations, while missing chain-specific integrations remain failures. Configured chains missing a skill listing also fail. Unlisted chains remain unsupported even when contracts and adapters are deployed.
Oracle checks require a deployed USD oracle and aggregator, deployed and registered oracle adapters, the correct binding, and positive USD quotes for native, wrapped native, and configured oracle connectors. Missing config, contracts, quotes, or RPC access fail with visible details for supported chains. Oracle-only chains show deployment discovery and configured oracle coverage. Discovery covers the selected config/skill/oracle chain set, not every EVM network. SPOT_ORACLE_CONFIG_JSON can supply an explicit snapshot for diagnostics; normal tests fetch production directly.
The same E2E run checks the skill's live relay /health and /status: healthy service, fresh enabled event listeners, and registration of each active Spot integration's adapter address. Takers must be active SAFO instances recently polling that relay, with matching chain/refinery/solver-adapter metadata and fresh, healthy integration loops. Health/polling/listener freshness is 120 seconds; loop freshness is 180 seconds. Set SPOT_TAKER_HEALTH_URLS to the comma-separated production taker health URLs in your private environment. No endpoint is bundled; missing configuration fails the runtime check. These checks use the runtime surfaces exposed by twap-bidder and order-sink; they do not submit orders or prove successful swap execution.
Configure NOTION_API_KEY in your private environment. The integrations database ID is bundled in the check. The board uses the status columns Contracts, Oracle, Takers, and Relay. Tests read every page of the integrations board and check SPOT rows against current configuration and observations. They detect missing, duplicate, and stale integrations; incorrect chain sets or solver labels; and drift in contract, oracle, taker, and relay readiness. For each component, full chain coverage expects Done, partial coverage In progress, and no coverage Not started. Taker comparisons cover observed taker operation. A source outage or chains outside a scoped run leave the corresponding status unchecked rather than inventing a replacement. TWAP/LH rows and other team readiness fields are excluded. Tests never update Notion. Board drift or an unavailable Notion board produces warnings without failing the run; runtime dependency failures still fail. npm run test:runtime checks this logic offline.
Orvex uses Spot's universal integration on Robinhood Chain (4663), with execution routing selected at fill time. No other Orvex mainnet deployment is listed in its official contract directory.
Robinhood's solver adapters cover Kyber, Flytrade (Magpie), OpenOcean, and LI.FI (LiFi).
Each Spot order combines timing, sizing, trigger, and settlement rules in a single signed payload.
input.amountis the per-fill chunk size.input.maxAmountis the total budget across fills.output.limitis the minimum acceptable output per chunk.output.triggerLowerandoutput.triggerUpperdefine stop-loss and take-profit style trigger bands.epochcontrols recurrence:0for one-shot,> 0for recurring fills.startanddeadlinedefine the execution window.
output.limit, triggerLower, and triggerUpper are encoded as per-chunk output-token amounts in the output token's decimals.
A typical order lifecycle is:
- Order creation: The user signs one EIP-712 order with chunk size, total amount, limits, slippage tolerance, epoch interval, and deadline.
- Price attestation: The cosigner signs both trigger-time and current market price data.
- Execution trigger: A whitelisted executor calls
Executor.execute()when the order is eligible. - Validation:
OrderReactorvalidates signatures, checksstart, enforces epoch windows, verifies timestamps, and applies slippage protection. - Settlement: The reactor transfers input tokens, validates the fill result, and enforces minimum output.
- Distribution: Surplus output is distributed between the swapper and optional referrer according to configured shares.
Spot's contracts were professionally audited by AstraSec. See the initial security audit report and updated security audit report. Spot is also oracle-protected: execution depends on cosigned trigger and market price data, freshness windows, and slippage checks.
- WM Allowlist: WM-gated entrypoints restrict privileged admin operations, and order execution honors exclusivity rules.
- Two-Step Ownership:
WMuses OpenZeppelinOwnable2Stepfor secure ownership transfers. - Executor Binding: Orders specify an authorized executor; only that executor can fill the order.
- Non-Exclusive Fillers:
exclusivity = 0locks fills to the designated executor, while values above zero allow third-party fillers that satisfy the higher minimum output requirement.
- Order Validation:
OrderValidationLib.validate()checks all order fields for validity. - Signature Verification: RePermit validates EIP-712 signatures and witness data binding.
- Oracle Price Attestation: The cosigner supplies trigger-time and current market price data used to gate execution.
- Epoch Enforcement:
EpochLib.update()prevents early or duplicate fills within time windows. - Slippage Protection: A maximum 50% slippage cap is enforced in
src/Constants.sol. - Freshness Windows: Current cosignatures expire after configurable time periods.
- Trigger Timestamp Rules: Trigger timestamps must be after
startand no later than the current timestamp.
- Witness-Bound Spending: RePermit ties allowances to exact order hashes, preventing signature reuse.
- Surplus Distribution: Excess tokens are distributed between the swapper and referrer.
- Exact Allowances:
SafeERC20.forceApprove()avoids allowance accumulation attacks.
- Reentrancy Protection:
OrderReactorusesReentrancyGuard;ExecutorandRefineryrely on WM gating and internal invariants. - Safe Token Handling: The system supports USDT-like tokens and ETH handling semantics.
- Emergency Pause:
OrderReactorcan be paused by WM-allowed addresses.
Plain-English examples:
- Sell a fixed amount once, but only if the execution meets a minimum output.
- Split a larger budget into equal chunks and execute one chunk every hour as a TWAP.
- Move into a safer asset if price falls below a stop-loss threshold, or exit on strength if a take-profit threshold is reached.
Order memory order = Order({
// ... standard fields
epoch: 0, // Single execution
input: Input({
amount: 1000e6, // Exact amount to spend
maxAmount: 1000e6 // Same as amount
}),
output: Output({
limit: 950 ether, // Minimum acceptable output
triggerLower: 0, // No lower trigger gate
triggerUpper: 0 // No upper trigger gate
})
});Order memory order = Order({
// ... standard fields
epoch: 3600, // Execute every hour
input: Input({
amount: 100e6, // 100 USDC per chunk
maxAmount: 1000e6 // 1000 USDC total budget
}),
output: Output({
limit: 95 ether, // Minimum per chunk
triggerLower: 0,
triggerUpper: 0
})
});Order memory order = Order({
// ... standard fields
epoch: 0, // Single execution
start: block.timestamp, // Order becomes active immediately
output: Output({
limit: 900 ether, // Minimum per chunk output when executing
triggerLower: 950 ether, // Stop-loss boundary per chunk
triggerUpper: 1200 ether // Take-profit boundary per chunk
})
});- 🧠 OrderReactor (
src/OrderReactor.sol): Validates orders, checks epoch constraints, computes minimum output from cosigned prices, settles via inlined implementation with reentrancy protection, and supports emergency pause via the WM allowlist. - ✍️ RePermit (
src/RePermit.sol): Permit2-style EIP-712 signatures with witness data that bind allowances to exact order hashes, preventing signature reuse. - 🧾 Cosigner (
src/ops/Cosigner.sol): Attests to trigger-time and current market prices with token validation. - 🛠️ Executor (
src/Executor.sol): Whitelisted fillers that execute eligible orders, enforce minimum output, and distribute surplus. - 🔐 WM (
src/ops/WM.sol): Two-step ownership allowlist manager for executors and admin functions with event emission. - 🏭 Refinery (
src/ops/Refinery.sol): Operations utility for batching multicalls and sweeping token balances by basis points.
Based on src/Structs.sol, each order contains:
struct Order {
address reactor; // OrderReactor contract address
address executor; // Authorized executor for this order
Exchange exchange; // Exchange parameters, referrer, and data
address swapper; // Order creator/signer
uint256 nonce; // Unique identifier
uint256 start; // Earliest execution timestamp
uint256 deadline; // Expiration timestamp
uint256 chainid; // Chain ID for cross-chain validation
uint32 exclusivity; // BPS-bounded exclusive execution
uint32 epoch; // Seconds between fills (0 = single-use)
uint32 slippage; // BPS applied to cosigned price
uint32 freshness; // Cosignature validity window in seconds
Input input; // Token to spend
Output output; // Token to receive
}
struct Input {
address token; // Input token address
uint256 amount; // Per-fill chunk amount
uint256 maxAmount; // Total amount across all fills
}
struct Output {
address token; // Output token address
uint256 limit; // Minimum acceptable output, in output-token decimals, per chunk
uint256 triggerLower; // Lower trigger boundary, in output-token decimals, per chunk
uint256 triggerUpper; // Upper trigger boundary, in output-token decimals, per chunk
address recipient; // Where to send output tokens
}- Maximum Slippage: Up to 5,000 BPS, or 50%, inclusive, defined in
src/Constants.sol. - Basis Points: 10,000 BPS equals 100%.
- Freshness Requirements: Must be greater than 0 seconds and less than epoch duration when
epoch != 0. - Epoch Behavior:
0means single execution; values above0mean recurring execution with that interval. - Gas Optimization: Foundry optimizer runs are set to
1,000,000.
The protocol is designed for deployment across EVM-compatible chains with deterministic addresses via CREATE2. Configuration is managed through config.json.
This repository ships these integration surfaces:
- Root package
@orbs-network/spotfor config, build orchestration, contracts, and published metadata inputs. - Self-contained skill package
skill/published as@orbs-network/spot-skill. - Skills-only OpenAI plugin artifact generated with
npm run plugin:buildfor marketplace testing and submission. - Hosted MCP endpoint at
https://agents-sink.orbs.network/mcp. - Hosted raw files at
https://orbs-network.github.io/spot/for direct bundle consumption. - Hosted skill distribution on Clawhub for direct skill discovery.
npm install
npm run build
npm test
npm run fmtNotes:
npm run buildrunsnpm run syncand thenforge build --extra-output-files abi.npm run plugin:buildgenerates the untracked plugin bundle atdist/spot/.- Use
forge testfor the Foundry suite.
- Make the smallest coherent change.
- Keep
skill/, hosted MCP references, and any affected published surfaces in sync. - Run
npm run buildafter changes. - Run tests when behavior changes or when explicitly requested.
- Executor ETH Refunds: Order execution returns the reactor's ETH balance to the filler. Keep executors funded, and treat unexpected reactor ETH as recoverable by WM-allowed addresses.
- Input Tokens: Orders spend ERC-20 tokens; wrap native ETH before creating orders.
- Issues: Use GitHub Issues for bug reports and feature requests.
- Documentation: The repo includes inline code documentation and the canonical skill references.
MIT. See LICENSE.