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
2 changes: 1 addition & 1 deletion benchmarks/bridge-execution-latency.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ abstract: |
from the latency distribution and counted against the success rate.

methodology:
- "Route: a self-conserving USDC triangle. Solana USDC to Base USDC, Base USDC to Arbitrum USDT, Arbitrum USDT to Solana USDC. Each executing bridge completes the full triangle before the next starts, so inventory returns to its origin and only fees burn."
- "Route: a self-conserving all-USDC triangle. Solana USDC to Base USDC, Base USDC to Arbitrum USDC, Arbitrum USDC to Solana USDC. Each executing bridge completes the full triangle before the next starts, so inventory returns to its origin and only fees burn."
- "Ticket sizes: $3 daily and $30 twice weekly, on fixed UTC schedules. Amounts are deliberately small: this measures settlement reliability, not large-ticket cost."
- "Latency: execution latency is wall-clock from broadcast to the destination credit; end-to-end latency adds the quote round-trip. Histogram buckets 1s, 5s, 10s, 30s, 60s, 120s, 300s, 600s; p50, p90 and p99 via histogram_quantile over 24h."
- "Outcome classification: settled (funds received), reverted or refunded (capital returned to source), or errored (never broadcast). Only settled transactions contribute to the latency distribution; reverts and refunds count against the success rate."
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/bridge-fee.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ methodology:
- "Reference notional: $300 USDC. Smaller sizes ($5, $50) are captured by the harness but excluded from this report."
- "Cost: `bridge_cost_percent{amount_usd=\"300\"}`, in percent of notional. Includes fees + slippage + destination gas."
- "Cadence: full sweep every 5 minutes for 24 hours."
- "Aggregation: the headline number is the average of per-corridor 24h medians over the corridors a provider actually quotes. The TRUMP to BRETT calibration route is excluded. Near Intents has no USDT legs, so its aggregate covers the Solana to Base and Arbitrum to HyperCore corridors only. deBridge does not quote the Arbitrum to HyperCore corridor, so its aggregate covers the remaining three. Across also skips Arbitrum to HyperCore, so its aggregate covers the same three corridors as deBridge."
- "Aggregation: the headline number is the average of per-corridor 24h medians over the corridors a provider actually quotes. The TRUMP to BRETT calibration route is excluded. deBridge does not quote the Arbitrum to HyperCore corridor, so its aggregate covers the remaining three. Across also skips Arbitrum to HyperCore, so its aggregate covers the same three corridors as deBridge."
- "Normalization: cost is quoted USD in minus quoted USD delivered, the same all-in definition for every provider. Near Intents bundles the destination chain withdrawal fee into its quoted amountOut (the 1Click API documents withdrawFee as already deducted), so no extra gas term is added on top."
- "Regions: eu-west only at present. The us-east and sgp probes are temporarily paused, so the live figures reflect the EU-West (Paris) origin; the other two tabs return when those probes resume."
- "Failures (quote_failed, unsupported route) excluded from cost aggregates and counted toward success rate."
Expand All @@ -85,7 +85,7 @@ findings:
- "{{name:mobula}} returns {{p50:mobula}} (p50, 24 h). Intent layers compress fees, slippage and destination gas into a single spread, so the effective number reads lower than aggregators that route through a paid underlying bridge."
- "{{name:lifi}} sits at {{p50:lifi}} (p50, 24 h). Aggregators pay the underlying bridge plus a thin markup, so their effective cost trails intent layers on liquid corridors where multiple solvers compete on the same route."
- "{{name:debridge}} clocks {{p50:debridge}} (p50, 24 h). Direct protocols front-load cost into a native-token fee, which dominates on $300 trades because the fixed component does not scale with notional."
- "{{name:across}} posts {{p50:across}} (p50, 24 h). Optimistic relayer fills price mostly relayer capital plus destination gas, so the number stays tight on same-asset USDC corridors and widens on the cross-asset USDT legs, where the quote wraps a DEX swap around the bridge and swap impact enters the all-in cost."
- "{{name:across}} posts {{p50:across}} (p50, 24 h). Optimistic relayer fills price mostly relayer capital plus destination gas, so the number stays tight across the same-asset USDC corridors of the triangle."
- "{{worst_name}} trails the cross-corridor aggregate at {{worst_p50}} (p50, 24 h). On a $300 trade the gap between leader and laggard is mostly the fixed-fee floor of the slower path, not relative spread efficiency, and the laggard on one corridor can be the leader on another once corridor dimensions are surfaced."

faq:
Expand Down
10 changes: 6 additions & 4 deletions harnesses/bridge-monitor/cmd/monitor/across_bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (

// Live response captured 2026-07-08 from
// GET https://app.across.to/api/swap/approval?tradeType=exactInput&amount=300000000
// &inputToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&originChainId=8453
// &outputToken=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9&destinationChainId=42161
//
// &inputToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&originChainId=8453
// &outputToken=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9&destinationChainId=42161
//
// (Base USDC to Arbitrum USDT, the cross-asset corridor). Trimmed to the
// fields the harness decodes; values are verbatim.
const acrossLiveSwapResponse = `{"crossSwapType":"anyToBridgeable","fees":{"total":{"amount":"1099243","amountUsd":"1.099199999999999955","token":{"decimals":6,"symbol":"USDC","address":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","name":"USD Coin","chainId":8453},"pct":"3664146565862634","details":{"type":"total-breakdown","swapImpact":{"amount":"-158088","amountUsd":"-0.15808239547799996","token":{"decimals":6,"symbol":"USDC","address":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","name":"USD Coin","chainId":8453},"pct":"-526962396755870"},"app":{"amount":"0","amountUsd":"0.0","token":{"decimals":6,"symbol":"USDT","address":"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9","name":"Tether USD","chainId":42161},"pct":"0"},"bridge":{"amount":"1258386","amountUsd":"1.257282395477999914","token":{"address":"0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2","decimals":6,"symbol":"USDT","chainId":8453},"pct":"4191108962618505","details":{"type":"across","lp":{"amount":"498437","amountUsd":"0.497999870750999996","token":{"address":"0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2","decimals":6,"symbol":"USDT","chainId":8453},"pct":"1660065971808872"},"relayerCapital":{"amount":"749162","amountUsd":"0.748504984925999928","token":{"address":"0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2","decimals":6,"symbol":"USDT","chainId":8453},"pct":"2495116421076843"},"destinationGas":{"amount":"6210800385526","amountUsd":"0.010777539801","token":{"chainId":42161,"address":"0x0000000000000000000000000000000000000000","decimals":18,"symbol":"ETH"},"pct":"35926569732789"}}}}}},"inputAmount":"300000000","expectedOutputAmount":"299156590","minOutputAmount":"298410564","expectedFillTime":2}`
Expand Down Expand Up @@ -65,8 +67,8 @@ func TestAcrossRouteSupport(t *testing.T) {
}
for name, want := range map[string]bool{
"USDC_SOL_BASE": true, // Sol USDC to Base USDC
"USDC_BASE_USDT_ARB": true, // cross-asset via Swap API
"USDT_ARB_USDC_SOL": true, // cross-asset via Swap API
"USDC_BASE_ARB": true, // same-asset USDC via Swap API
"USDC_ARB_SOL": true, // same-asset USDC via Swap API
"TRUMP_SOL_BRETT_BASE": false, // calibration route, excluded
"USDC_ARB_HYPERCORE": false, // Across 999 is HyperEVM, not a HyperCore credit
} {
Expand Down
6 changes: 3 additions & 3 deletions harnesses/bridge-monitor/cmd/monitor/balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ func (bc *BalanceChecker) fillEVMFromChain(result map[string]map[string]float64,
case "Base":
reads = []tokenRead{{baseUSDCAddr, []string{"USDC"}}}
case "Arbitrum":
// Both USDT0 and USDT symbols: cycle_sim reads "USDT0" (Mobula naming)
// while route helpers fall back to "USDT".
// Triangle is all-USDC now; USDC is the home leg. USDT0 kept as a
// read only to monitor any leftover after the USDT->USDC migration.
reads = []tokenRead{
{arbUSDTAddr, []string{"USDT0", "USDT"}},
{arbUSDCAddr, []string{"USDC"}},
{arbUSDTAddr, []string{"USDT0", "USDT"}},
}
default:
return false
Expand Down
12 changes: 6 additions & 6 deletions harnesses/bridge-monitor/cmd/monitor/cycle_sim.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func SimulateTriangleCycle(balances map[string]map[string]float64, tier float64)

solUSDC := balances["Solana"]["USDC"]
baseUSDC := balances["Base"]["USDC"]
arbUSDT := balances["Arbitrum"]["USDT0"]
arbUSDC := balances["Arbitrum"]["USDC"]

// Per-bridge leg requirement is 1×tier (not 3×): one TX at a time, settlement
// replenishes the next leg before it has to source.
Expand Down Expand Up @@ -60,15 +60,15 @@ func SimulateTriangleCycle(balances map[string]map[string]float64, tier float64)
return sim
}

// R3: Arb USDT → Sol USDC. R2 of current bridge deposited ~tier × 0.98 on Arb.
arbEff := arbUSDT + need*netFactor
// R3: Arb USDC → Sol USDC. R2 of current bridge deposited ~tier × 0.98 on Arb.
arbEff := arbUSDC + need*netFactor
if arbEff < need {
sim.BlockLeg = "R3 Arb USDT"
sim.BlockLeg = "R3 Arb USDC"
sim.Needed = need
sim.Available = arbEff
sim.Reason = fmt.Sprintf("R3 Arb→Sol blocked: need $%.2f USDT on Arbitrum (incl. R2 inflow ≈$%.2f), effective $%.2f",
sim.Reason = fmt.Sprintf("R3 Arb→Sol blocked: need $%.2f USDC on Arbitrum (incl. R2 inflow ≈$%.2f), effective $%.2f",
need, need*netFactor, arbEff)
sim.RefillChain, sim.RefillToken, sim.RefillUSD = "Arbitrum", "USDT", need-arbEff
sim.RefillChain, sim.RefillToken, sim.RefillUSD = "Arbitrum", "USDC", need-arbEff
return sim
}

Expand Down
11 changes: 6 additions & 5 deletions harnesses/bridge-monitor/cmd/monitor/debridge_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ func debridgeChainID(chain string) int64 {
// Debridge protocol charges a fixed amount in native tokens that we convert to USD
// using live spot prices (5min cache). Hardcoded fallbacks are intentionally
// conservative so an API outage doesn't make Debridge look artificially cheap.
// Solana: 0.015 SOL native fix fee
// EVM: 0.001 ETH native fix fee
//
// Solana: 0.015 SOL native fix fee
// EVM: 0.001 ETH native fix fee
func debridgeFixFeeUSD(fromChain string) float64 {
switch strings.ToLower(fromChain) {
case "solana":
Expand All @@ -56,9 +57,9 @@ type DebridgeQuoteResponse struct {
ApproximateUsdValue float64 `json:"approximateUsdValue"`
} `json:"dstChainTokenOut"`
} `json:"estimation"`
FixFee string `json:"fixFee"`
ProtocolFeeApproximateUsdValue float64 `json:"protocolFeeApproximateUsdValue"`
Order struct {
FixFee string `json:"fixFee"`
ProtocolFeeApproximateUsdValue float64 `json:"protocolFeeApproximateUsdValue"`
Order struct {
ApproximateFulfillmentDelay int64 `json:"approximateFulfillmentDelay"`
} `json:"order"`
ErrorMessage string `json:"errorMessage,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion harnesses/bridge-monitor/cmd/monitor/gas_topup.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const gasTierSafeBuffer = 1.20
const gasMinMeaningfulUSD = 5.0

type gasChain struct {
Chain string
Chain string
NativeSym string
// PrimaryStable is the stablecoin sold first for gas (contract address).
PrimaryStable string
Expand Down
2 changes: 1 addition & 1 deletion harnesses/bridge-monitor/cmd/monitor/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func initSelfHealingMetrics() {
bridgeTierDowngraded.WithLabelValues("30", "3").Set(0)
bridgeStrandedHours.WithLabelValues("Solana", "USDC").Set(0)
bridgeStrandedHours.WithLabelValues("Base", "USDC").Set(0)
bridgeStrandedHours.WithLabelValues("Arbitrum", "USDT0").Set(0)
bridgeStrandedHours.WithLabelValues("Arbitrum", "USDC").Set(0)
for _, chain := range []string{"Solana", "Base", "Arbitrum"} {
for _, outcome := range []string{"attempted", "succeeded", "failed", "capped", "gated"} {
bridgeGasTopup.WithLabelValues(chain, outcome).Add(0)
Expand Down
14 changes: 7 additions & 7 deletions harnesses/bridge-monitor/cmd/monitor/mobula_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func GetTestRoutes() []TestRoute {
// USDC Triangle (self-balancing):
// R1: Solana USDC → Base USDC
// R2: Base USDC → Arbitrum USDT
// R3: Arbitrum USDT → Solana USDC
// R3: Arbitrum USDC → Solana USDC
//
// Meme Route (separate, weekly only):
// R4: TRUMP (Solana) → BRETT (Base)
Expand All @@ -363,23 +363,23 @@ func GetTestRoutes() []TestRoute {
IsSolanaSrc: true,
WeeklyOnly: false,
},
// R2: Base USDC → Arbitrum USDT
// R2: Base USDC → Arbitrum USDC (all-USDC triangle)
{
Name: "USDC_BASE_USDT_ARB",
Name: "USDC_BASE_ARB",
FromChain: "Base", FromChainAPI: "evm:8453",
FromToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
ToChain: "Arbitrum", ToChainAPI: "evm:42161",
ToToken: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
ToToken: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
Amounts: []float64{5, 50, 300},
UsdAmounts: []float64{5, 50, 300},
IsSolanaSrc: false,
WeeklyOnly: false,
},
// R3: Arbitrum USDT → Solana USDC (completes the triangle)
// R3: Arbitrum USDC → Solana USDC (completes the all-USDC triangle)
{
Name: "USDT_ARB_USDC_SOL",
Name: "USDC_ARB_SOL",
FromChain: "Arbitrum", FromChainAPI: "evm:42161",
FromToken: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
FromToken: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
ToChain: "Solana", ToChainAPI: "solana:solana",
ToToken: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
Amounts: []float64{5, 50, 300},
Expand Down
10 changes: 5 additions & 5 deletions harnesses/bridge-monitor/cmd/monitor/nearintents_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ type NearIntentsQuoteRequest struct {

type NearIntentsQuoteResponse struct {
Quote struct {
AmountIn string `json:"amountIn"`
AmountInFormatted string `json:"amountInFormatted"`
AmountInUsd string `json:"amountInUsd"`
AmountOut string `json:"amountOut"`
AmountIn string `json:"amountIn"`
AmountInFormatted string `json:"amountInFormatted"`
AmountInUsd string `json:"amountInUsd"`
AmountOut string `json:"amountOut"`
AmountOutFormatted string `json:"amountOutFormatted"`
AmountOutUsd string `json:"amountOutUsd"`
AmountOutUsd string `json:"amountOutUsd"`
// timeEstimate is the solver-reported settlement ETA in seconds.
TimeEstimate float64 `json:"timeEstimate"`
} `json:"quote"`
Expand Down
8 changes: 2 additions & 6 deletions harnesses/bridge-monitor/cmd/monitor/reaper.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const reaperMaxTransferUSD = 30 * rebalanceBufferFactor
var homeTokens = map[string]map[string]bool{
"Solana": {"USDC": true, "SOL": true, "TRUMP": true},
"Base": {"USDC": true, "ETH": true, "BRETT": true},
"Arbitrum": {"USDT0": true, "USDT": true, "USDC": true, "ETH": true},
"Arbitrum": {"USDC": true, "ETH": true},
}

// Stranded tokens we know how to route home. Anything else is alert-only:
Expand Down Expand Up @@ -156,11 +156,7 @@ func reaperTick(fetch func() (map[string]map[string]float64, bool, error), rebal

// Home legs always report 0 so alert expressions have a baseline series.
for _, leg := range triangleLegs {
sym := leg.Token
if leg.Chain == "Arbitrum" {
sym = "USDT0"
}
bridgeStrandedHours.WithLabelValues(leg.Chain, sym).Set(0)
bridgeStrandedHours.WithLabelValues(leg.Chain, leg.Token).Set(0)
}
for k, h := range hours {
bridgeStrandedHours.WithLabelValues(k.Chain, k.Token).Set(h)
Expand Down
2 changes: 1 addition & 1 deletion harnesses/bridge-monitor/cmd/monitor/rebalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ type legSpec struct {
var triangleLegs = []legSpec{
{Chain: "Solana", ChainAPI: "solana:solana", Token: "USDC", TokenAddr: solanaUSDCMint},
{Chain: "Base", ChainAPI: "evm:8453", Token: "USDC", TokenAddr: baseUSDCAddr},
{Chain: "Arbitrum", ChainAPI: "evm:42161", Token: "USDT", TokenAddr: arbUSDTAddr},
{Chain: "Arbitrum", ChainAPI: "evm:42161", Token: "USDC", TokenAddr: arbUSDCAddr},
}

func findLeg(chain string) (legSpec, bool) {
Expand Down
16 changes: 11 additions & 5 deletions harnesses/bridge-monitor/cmd/monitor/relay_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ type RelayStepData struct {
Data string `json:"data"`
Value string `json:"value"`
// Solana fields
Instructions []RelaySolanaInstruction `json:"instructions"`
AddressLookupTableAddresses []string `json:"addressLookupTableAddresses"`
Instructions []RelaySolanaInstruction `json:"instructions"`
AddressLookupTableAddresses []string `json:"addressLookupTableAddresses"`
}

type RelayQuoteResponse struct {
Expand All @@ -96,9 +96,15 @@ type RelayQuoteResponse struct {
TimeEstimate float64 `json:"timeEstimate"`
} `json:"details"`
Fees struct {
Gas struct{ AmountUsd string `json:"amountUsd"` } `json:"gas"`
RelayerGas struct{ AmountUsd string `json:"amountUsd"` } `json:"relayerGas"`
RelayerService struct{ AmountUsd string `json:"amountUsd"` } `json:"relayerService"`
Gas struct {
AmountUsd string `json:"amountUsd"`
} `json:"gas"`
RelayerGas struct {
AmountUsd string `json:"amountUsd"`
} `json:"relayerGas"`
RelayerService struct {
AmountUsd string `json:"amountUsd"`
} `json:"relayerService"`
} `json:"fees"`
// Transaction steps for execution (EVM or Solana)
Steps []struct {
Expand Down
6 changes: 3 additions & 3 deletions harnesses/bridge-monitor/cmd/monitor/selfheal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func balancesSnapshot(sol, base, arb float64) map[string]map[string]float64 {
return map[string]map[string]float64{
"Solana": {"USDC": sol, "SOL": 30},
"Base": {"USDC": base, "ETH": 40},
"Arbitrum": {"USDT0": arb, "ETH": 25},
"Arbitrum": {"USDC": arb, "ETH": 25},
}
}

Expand Down Expand Up @@ -225,8 +225,8 @@ func TestStrandedHoursComputation(t *testing.T) {
if _, ok := hours[strandKey{"Solana", "USDC"}]; ok {
t.Error("home leg Solana/USDC reported as stranded")
}
if _, ok := hours[strandKey{"Arbitrum", "USDT0"}]; ok {
t.Error("home leg Arbitrum/USDT0 reported as stranded")
if _, ok := hours[strandKey{"Arbitrum", "USDC"}]; ok {
t.Error("home leg Arbitrum/USDC reported as stranded")
}

// 7 hours later the same balance is still there: above the 6h default.
Expand Down
10 changes: 5 additions & 5 deletions harnesses/bridge-monitor/cmd/monitor/socket_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ func socketChainID(chain string) string {
}

type socketRoute struct {
OutputValueInUsd float64 `json:"outputValueInUsd"`
InputValueInUsd float64 `json:"inputValueInUsd"`
TotalGasFeesInUsd float64 `json:"totalGasFeesInUsd"`
ServiceTime int `json:"serviceTime"`
BridgeRoute struct {
OutputValueInUsd float64 `json:"outputValueInUsd"`
InputValueInUsd float64 `json:"inputValueInUsd"`
TotalGasFeesInUsd float64 `json:"totalGasFeesInUsd"`
ServiceTime int `json:"serviceTime"`
BridgeRoute struct {
BridgeFeeAmount string `json:"bridgeFeeAmount"`
} `json:"bridgeRoute"`
}
Expand Down
8 changes: 4 additions & 4 deletions harnesses/bridge-monitor/cmd/monitor/squid_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ type squidGasCost struct {
type squidRouteResponse struct {
Route struct {
Estimate struct {
FromAmountUSD string `json:"fromAmountUSD"`
ToAmountUSD string `json:"toAmountUSD"`
FeeCosts []squidFeeCost `json:"feeCosts"`
GasCosts []squidGasCost `json:"gasCosts"`
FromAmountUSD string `json:"fromAmountUSD"`
ToAmountUSD string `json:"toAmountUSD"`
FeeCosts []squidFeeCost `json:"feeCosts"`
GasCosts []squidGasCost `json:"gasCosts"`
EstimatedRouteDuration int `json:"estimatedRouteDuration"`
} `json:"estimate"`
} `json:"route"`
Expand Down
Loading
Loading