Skip to content

Latest commit

 

History

History
270 lines (201 loc) · 10.5 KB

File metadata and controls

270 lines (201 loc) · 10.5 KB
title description
Simplex
Simplex is an automated binary that monitors Intent Gateway orders and fills them profitably, earning fees by providing liquidity and execution services.

Simplex

Simplex is an automated binary that monitors Intent Gateway orders and fills them profitably. It watches configured chains for OrderPlaced events, waits for sufficient confirmations based on the order's value, evaluates profitability across all configured strategies, and executes the best fill. Fillers earn the difference between order inputs and outputs.

Quick Start

Docker (Recommended)

docker pull polytopelabs/simplex:latest

docker run -d \
  --name simplex \
  --restart unless-stopped \
  -v $(pwd):/app:ro \
  polytopelabs/simplex:latest \
  --config /app/config.toml \
  --data-dir /app

Strategies

Simplex ships with two built-in strategies configured as [[strategies]] entries in your TOML config. For every order, Simplex evaluates all configured strategies and executes whichever returns the highest profit.

Basic

Basic strategy fills cross-chain orders where the input and output token are the same — USDC→USDC or USDT→USDT across chains. It checks your balance on the destination chain, estimates order fees - (gas + protocol fees + relayer fees), and fills directly if profitable.

The bpsCurve sets the minimum basis-point margin required at each order size. Points are interpolated, so you can model tighter spreads for larger orders:

[[strategies]]
type = "basic"
bpsCurve = [
    { amount = "100",    value = 100 },   # $100 orders: 1% minimum margin
    { amount = "1000",   value = 50  },   # $1000 orders: 0.5%
    { amount = "10000",  value = 25  },   # $10k orders: 0.25%
    { amount = "100000", value = 10  },   # $100k orders: 0.1%
]

BasicFiller requires pre-positioned stablecoins on each destination chain.


HyperFX

HyperFX fills swaps between USD-pegged stablecoins (USDC/USDT) and a single configurable exotic token — for example, cNGN (a Nigerian naira stablecoin). It supports both same-chain and cross-chain orders.

Same-chain orders (source == destination) are filled immediately without waiting for additional confirmations. Cross-chain orders use the configured confirmation policy for HyperFX to determine how many confirmations to wait for before bidding.

Profit comes from two sources: the bid/ask spread on the exotic token, and order fees minus gas. The filler holds both stablecoins and the exotic token. When a user swaps stable→exotic the filler sells exotic at the ask price; when the user swaps exotic→stable the filler buys at the bid price. The spread between the two curves is the filler's margin per trade.

Both curves are expressed in exotic tokens per USD. A higher bid means the filler acknowledges fewer stables are owed per exotic received (the filler profits more on the exotic→stable leg). A lower ask means the filler sends fewer exotic tokens per stable received (the filler profits more on the stable→exotic leg).

maxOrderUsd caps the filler's exposure per order. Orders larger than the cap are partially filled up to that amount — the IntentGateway releases inputs proportionally to the fraction of outputs provided, so partial fills work without any extra on-chain logic.

HyperFX always uses the solver selection path: it submits a signed bid to Hyperbridge via IntentsCoprocessor rather than calling fillOrder directly. This requires substratePrivateKey and hyperbridgeWsUrl in [simplex], and a bundlerUrl on each [[chains]] entry where HyperFX will operate. Simplex automatically monitors and tops up the ERC-4337 EntryPoint deposit as a background task — depositing 10% of the solver account's native balance when it falls low.

[[strategies]]
type = "hyperfx"
maxOrderUsd = "5000"

# Bid price curve: exotic per USD when *buying* exotic from a user (exotic→stable leg).
bidPriceCurve = [
    { amount = "100",  price = "1580" },
    { amount = "1000", price = "1575" },
    { amount = "5000", price = "1570" },
]

# Ask price curve: exotic per USD when *selling* exotic to a user (stable→exotic leg).
askPriceCurve = [
    { amount = "100",  price = "1560" },
    { amount = "1000", price = "1555" },
    { amount = "5000", price = "1550" },
]

[strategies.exoticTokenAddresses]
"EVM-56"  = "0xExoticTokenAddressOnBsc"
"EVM-137" = "0xExoticTokenAddressOnPolygon"

Example profit calculation

For a $1000 USDC → cNGN order, the curve interpolates to bid 1575, ask 1555 at the $1000 size:

User sends:       $1000 USDC
Filler delivers:  1,555,000 cNGN      (1000 × ask 1555)
Filler's cost:    1,555,000 / 1575    = $987.30  (valued at bid)
Spread profit:    $1000 − $987.30     = $12.70
Fee profit:       $2.80 − $1.30 costs = $1.50
Total profit:     ~$14.20

Configuration

[simplex]

[simplex]
privateKey          = "0x..."  # EVM private key
maxConcurrentOrders = 5

# Required for HyperFX / solver selection
substratePrivateKey = "0x.."       # Hex seed or mnemonic for Hyperbridge extrinsics
hyperbridgeWsUrl    = "wss://nexus.ibp.network"       # Hyperbridge WebSocket endpoint

[simplex.logging]
level = "info"                 # trace | debug | info | warn | error

[simplex.pendingQueue]
maxRechecks    = 10
recheckDelayMs = 30000

Each chain where HyperFX operates needs a bundlerUrl in its [[chains]] entry:

[[chains]]
chainId   = 8453
rpcUrl    = "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY"
bundlerUrl = "https://api.pimlico.io/v2/8453/rpc?apikey=YOUR_KEY"

[[chains]]
chainId   = 56
rpcUrl    = "https://bsc-dataseed.binance.org/"
bundlerUrl = "https://api.pimlico.io/v2/56/rpc?apikey=YOUR_KEY"

Confirmation Policy

Confirmation policies are configured per strategy. Both BasicFiller and HyperFX can use confirmation policies for cross-chain orders.

Before processing a cross-chain order, Simplex waits for enough block confirmations to guard against chain reorganizations. The number of confirmations scales with order value using a curve — small orders are processed quickly, large orders wait longer. Same-chain orders always proceed without additional confirmation delay.

[confirmationPolicies."1"]     # Ethereum Mainnet (~12s blocks)
points = [
    { amount = "5",    value = 3  },   # $5 → 3 blocks (~36s)
    { amount = "500",  value = 6  },   # $500 → 6 blocks (~72s)
    { amount = "5000", value = 12 },   # $5000 → 12 blocks (~2.5m)
]

[confirmationPolicies."56"]    # BSC (~1s blocks)
points = [
    { amount = "1",    value = 3  },
    { amount = "500",  value = 6  },
    { amount = "5000", value = 15 },
]

[confirmationPolicies."42161"] # Arbitrum (~0.25s blocks)
points = [
    { amount = "2",    value = 2  },
    { amount = "1000", value = 5  },
    { amount = "8000", value = 10 },
]

For HyperFX, you can configure confirmation policies in the same way. For example:

[[strategies]]
type = "hyperfx"
maxOrderUsd = "5000"

[strategies.exoticTokenAddresses]
"EVM-56"  = "0xExoticTokenAddressOnBsc"
"EVM-137" = "0xExoticTokenAddressOnPolygon"

[strategies.confirmationPolicies]
# Chain IDs for HyperFX confirmation policy (same schema as BasicFiller)
[strategies.confirmationPolicies."56"]    # BSC (~1s blocks)
points = [
    { amount = "1",   value = 3  },
    { amount = "500", value = 6  },
    { amount = "5000", value = 15 },
]

[strategies.confirmationPolicies."42161"] # Arbitrum (~0.25s blocks)
points = [
    { amount = "2",    value = 2  },
    { amount = "1000", value = 5  },
    { amount = "8000", value = 10 },
]
If HyperFX is configured without [strategies.confirmationPolicies], Simplex logs a warning at startup and skips cross-chain orders for that strategy. Only same-chain HyperFX orders will be processed in that case.

Auto-Rebalancing

Auto-rebalancing only applies to BasicFiller. HyperFX manages its own exotic token inventory separately.

When a chain's stablecoin balance drops below a threshold, the rebalancer bridges tokens from another chain to restore it. triggerPercentage = 0.5 means rebalancing triggers when the balance falls to 50% of the configured base:

[rebalancing]
triggerPercentage = 0.5

[rebalancing.baseBalances."USDC"]
"1"     = "10000"
"56"    = "10000"
"42161" = "10000"
"8453"  = "10000"

[rebalancing.baseBalances."USDT"]
"1"     = "10000"
"56"    = "10000"
"42161" = "10000"
"8453"  = "10000"

Docker

version: "3.8"

services:
    simplex:
        image: polytopelabs/simplex:latest
        container_name: simplex
        restart: unless-stopped
        volumes:
            - ./config.toml:/app/config.toml:ro
        logging:
            driver: "json-file"
            options:
                max-size: "10m"
                max-file: "3"

Requirements

You need an EVM private key funded with native tokens for gas and stablecoins to fill orders with — minimum $10,000 equivalent per chain is a reasonable starting point. For HyperFX, also hold the exotic token on each chain, plus a Substrate account with BRIDGE tokens for Hyperbridge extrinsic fees. These extrinsic fees are claimable — Simplex claims them automatically after each batch of bids is executed on-chain or when the filler stops.

RPC endpoints must be from a premium provider (Alchemy Pro, Infura Growth+, QuickNode Pro). Archive node access is required for storage slot queries and gas simulation. Free-tier RPCs will not work reliably.

Troubleshooting

No profitable strategy found

Gas prices may be too high relative to the order fee, or your bpsCurve thresholds are set too conservatively. Check balances on the destination chain and review current gas prices.

Insufficient token balances

Deposit more stablecoins (and exotic tokens for HyperFX) on the destination chains.

RPC rate limiting (429 errors)

Switch to a premium RPC provider or reduce maxConcurrentOrders.

HyperFX bid submission fails

Confirm substratePrivateKey and hyperbridgeWsUrl are set in [simplex], that each relevant chain has a bundlerUrl, and that your Substrate account has BRIDGE tokens. Ensure the solver account has sufficient native balance — Simplex automatically tops up the ERC-4337 EntryPoint deposit as a background task (10% of native balance per top-up).

For verbose output, set level = "debug" in [simplex.logging]. Report bugs to the Hyperbridge GitHub with full logs (redact private keys).