diff --git a/benchmarks/bridge-quote-latency-solana.yml b/benchmarks/bridge-quote-latency-solana.yml index 7284a2b97..ab5eb37c7 100644 --- a/benchmarks/bridge-quote-latency-solana.yml +++ b/benchmarks/bridge-quote-latency-solana.yml @@ -53,18 +53,18 @@ abstract: | methodology: - "Origin: Solana only. Every corridor in this bench starts from Solana USDC; the destination is the per-tab chain." - "Destinations: Base, Arbitrum, BNB, Ethereum and Robinhood Chain. A provider that does not quote a given destination simply does not appear on that tab." - - "Robinhood Chain (Arbitrum Orbit, chainId 4663) has no native USDC, so it is a cross-asset USDC to USDG (Global Dollar) corridor. On the live probe only Mobula returns a usable SOL to Robinhood quote; Relay, LI.FI and deBridge reject the USDC-to-USDG pair on this chain (invalid input/output currency), so they do not appear on the Robinhood tab." - - "Latency: wall-clock from request to a usable quote, in milliseconds. p50, p90 and p99 over a rolling 24h window via histogram_quantile on a from_chain=Solana-scoped recording rule." + - "Robinhood Chain (Arbitrum Orbit, chainId 4663) has no native USDC, so it is a cross-asset USDC to USDG (Global Dollar) corridor. Mobula, Relay, LI.FI and deBridge all quote it today (the pair was rejected by three of them at launch); Across and Near Intents are not attempted on this destination." + - "Latency: wall-clock from request to a fully read quote response, in milliseconds. p50, p90 and p99 over a rolling 24h window via histogram_quantile on a from_chain=Solana-scoped recording rule, summed over the destinations and notionals of the tab (the All tab pools every destination). Near Intents' dry quotes carry a fixed 3 s solver wait (quoteWaitingTimeMs: 3000), so its figures sit at about 3 s by construction; the histogram has 500 ms buckets between 1 and 5 s to resolve it." - "Cadence: every five minutes, at $5, $50 and $300 notional." - - "Region: EU-West only at present. The us-east and sgp probes are paused, so the figures reflect the EU-West (Paris) origin." - - "Cohort: Mobula, Relay, LI.FI, deBridge, Across and Near Intents. Squid and Socket are EVM-only aggregators with no Solana-source route and are excluded here (they remain in the general bridge-quote-latency bench)." + - "Region: every figure on this page is pinned to the EU-West (Paris) origin. A us-east probe also runs and its cells are kept in Prometheus, but they are not pooled into the headline; the sgp probe is down." + - "Cohort: Mobula, Relay, LI.FI, deBridge, Across and Near Intents. Squid and Socket are EVM-only aggregators with no Solana-source route and are excluded here (they remain in the general bridge-quote-latency bench). Across and Near Intents are probed on Base and Arbitrum only: the harness maps no BNB, Ethereum or Robinhood asset for them yet, so their absence from those tabs is ours, not theirs. The R4 meme route (TRUMP to BRETT) quoted by the same loop is excluded from every cell." findings: - "{{best_name}} returns the fastest Solana-origin quote at {{best_p50}} (p50, 24 h) across {{count}} providers, on the destinations it covers." - "{{name:mobula}} returns {{p50:mobula}} (p50, 24 h). A thin price-discovery call against pre-quoted solvers keeps Solana-origin latency low even though the SPL resolution adds work the EVM-only corridors avoid." - "{{name:relay}} sits at {{p50:relay}} (p50, 24 h)." - - "{{name:near-intents}} clocks {{p50:near-intents}} (p50, 24 h); its 1Click flow is bimodal, sub-100ms on solver-cached corridors and up to the full auction window otherwise." - - "{{worst_name}} trails at {{worst_p50}} (p50, 24 h), the cost of a heavier route search on the Solana-origin path." + - "{{name:near-intents}} clocks {{p50:near-intents}} (p50, 24 h): its dry quote waits a fixed 3 s solver window by design, so this row measures that wait, not route search." + - "{{worst_name}} trails at {{worst_p50}} (p50, 24 h)." faq: - q: "What is the fastest bridge to leave Solana?" @@ -93,12 +93,12 @@ providers: tag: Aggregator + intent layer formula: "p50 over 24h of Solana-origin quote latency (ms) from Mobula, at the selected destination and notional, sampled every 5 minutes from EU-West." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="mobula"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="mobula"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="mobula"}) - mean: ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="mobula"} / clamp_min(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="mobula"}, 1) - success: ocb:bridge_quote_success:sol_avg24h{bridge="mobula"} - sample_size: ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="mobula"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:sol_avg24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="mobula", from_chain="Solana"}[1h]))) - slug: relay @@ -106,12 +106,12 @@ providers: tag: Cross-chain relay formula: "p50 over 24h of Solana-origin quote latency (ms) from Relay, at the selected destination and notional, sampled every 5 minutes from EU-West." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="relay"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="relay"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="relay"}) - mean: ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="relay"} / clamp_min(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="relay"}, 1) - success: ocb:bridge_quote_success:sol_avg24h{bridge="relay"} - sample_size: ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="relay"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:sol_avg24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="relay", from_chain="Solana"}[1h]))) - slug: lifi @@ -119,12 +119,12 @@ providers: tag: Aggregator formula: "p50 over 24h of Solana-origin quote latency (ms) from LI.FI, at the selected destination and notional, sampled every 5 minutes from EU-West." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="lifi"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="lifi"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="lifi"}) - mean: ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="lifi"} / clamp_min(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="lifi"}, 1) - success: ocb:bridge_quote_success:sol_avg24h{bridge="lifi"} - sample_size: ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="lifi"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:sol_avg24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="lifi", from_chain="Solana"}[1h]))) - slug: debridge @@ -132,12 +132,12 @@ providers: tag: Native-token fees formula: "p50 over 24h of Solana-origin quote latency (ms) from deBridge, at the selected destination and notional, sampled every 5 minutes from EU-West." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="debridge"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="debridge"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="debridge"}) - mean: ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="debridge"} / clamp_min(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="debridge"}, 1) - success: ocb:bridge_quote_success:sol_avg24h{bridge="debridge"} - sample_size: ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="debridge"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:sol_avg24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="debridge", from_chain="Solana"}[1h]))) - slug: across @@ -145,12 +145,12 @@ providers: tag: Optimistic relay formula: "p50 over 24h of Solana-origin quote latency (ms) from Across, at the selected destination and notional, sampled every 5 minutes from EU-West." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="across"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="across"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="across"}) - mean: ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="across"} / clamp_min(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="across"}, 1) - success: ocb:bridge_quote_success:sol_avg24h{bridge="across"} - sample_size: ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="across"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:sol_avg24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="across", from_chain="Solana"}[1h]))) - slug: near-intents @@ -158,10 +158,10 @@ providers: tag: Intent layer (NEAR) formula: "p50 over 24h of Solana-origin quote latency (ms) from the Near Intents 1Click API, at the selected destination and notional, sampled every 5 minutes from EU-West." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="near-intents"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="near-intents"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="near-intents"}) - mean: ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="near-intents"} / clamp_min(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="near-intents"}, 1) - success: ocb:bridge_quote_success:sol_avg24h{bridge="near-intents"} - sample_size: ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="near-intents"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:sol_rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:sol_rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:sol_rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:sol_avg24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:sol_increase24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="near-intents", from_chain="Solana"}[1h]))) diff --git a/benchmarks/bridge-quote-latency.yml b/benchmarks/bridge-quote-latency.yml index 9de6245f3..a177381be 100644 --- a/benchmarks/bridge-quote-latency.yml +++ b/benchmarks/bridge-quote-latency.yml @@ -43,9 +43,9 @@ seo_intro: | number every public roundup ignores. how many milliseconds the API burns before the user sees a price. We hammer the same USDC routes (Solana, Base, Arbitrum) against every bridge from the EU-West (Paris) - origin, every five minutes, on three notional sizes. The US-East and - Singapore origins are temporarily paused, so the live numbers reflect - EU-West only. p50, p90 and p99 are computed via Prometheus + origin, every five minutes, on three notional sizes. The headline is + pinned to EU-West (a US-East probe also runs and feeds the region + breakdown; Singapore is down). p50, p90 and p99 are computed via Prometheus `histogram_quantile` over the 24-hour window, so the leaderboard reflects sustained API performance, not a lucky cold-start. The same harness records failure mode for every request (quote_failed, @@ -65,7 +65,7 @@ methodology: - "Routes: USDC pairs spanning Solana, Base and Arbitrum." - "Notional sizes: $5, $50, $300 per quote." - "Cadence: full sweep (4 routes × 3 amounts × N bridges) every 5 minutes for 24 hours." - - "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 harness is built to probe three origins simultaneously and the other two tabs return when those probes resume." + - "Regions: every figure on this page is pinned to the EU-West (Paris) origin. A us-east probe also runs and its cells stay in Prometheus for the region breakdown, but they are not pooled into the headline; the sgp probe is down. Execution-path quotes ($3 and $30 tickets) and the R4 meme route quoted by the same loop are excluded from every cell." - "Histogram buckets: 10, 25, 50, 100, 200, 500, 1000, 2000, 5000, 10000 ms. Sub-50ms buckets added 2026-07-13 so solver-cached fast paths (Near Intents on HyperCore in particular) surface their true p50 instead of being floored at the interpolation of the (0, 50] bucket." - "Failures (quote_failed, execution_failed, unsupported route) excluded from latency aggregates and counted toward success rate." @@ -122,22 +122,22 @@ providers: tag: Aggregator + intent layer formula: "Median wall-clock ms over 24h for Mobula's quote API to return a usable USDC route, sampled every 5 minutes across 4 routes and 3 notionals from the EU-West (Paris) origin." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="mobula"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="mobula"} - success: ocb:bridge_quote_success:avg24h{bridge="mobula"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="mobula"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="mobula"}[1h]))) regions: - region: eu-west - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="eu-west"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="mobula", region="eu-west"}[1h]))) - region: us-east - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="us-east"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="us-east", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="mobula", region="us-east"}[1h]))) - region: sgp - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="sgp"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="mobula", region="sgp", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="mobula", region="sgp"}[1h]))) - slug: relay @@ -145,22 +145,22 @@ providers: tag: Cross-chain relay formula: "Median wall-clock ms over 24h for Relay's solver-quote API to return a usable USDC route, sampled every 5 minutes across 4 routes and 3 notionals from the EU-West (Paris) origin." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="relay"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="relay"} - success: ocb:bridge_quote_success:avg24h{bridge="relay"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="relay"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="relay"}[1h]))) regions: - region: eu-west - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="eu-west"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="relay", region="eu-west"}[1h]))) - region: us-east - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="us-east"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="us-east", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="relay", region="us-east"}[1h]))) - region: sgp - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="sgp"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="relay", region="sgp", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="relay", region="sgp"}[1h]))) - slug: lifi @@ -168,22 +168,22 @@ providers: tag: Aggregator formula: "Median wall-clock ms over 24h for LI.FI's route-search API to return a usable USDC route across underlying bridges, sampled every 5 minutes across 4 routes and 3 notionals from the EU-West (Paris) origin." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="lifi"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="lifi"} - success: ocb:bridge_quote_success:avg24h{bridge="lifi"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="lifi"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="lifi"}[1h]))) regions: - region: eu-west - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="eu-west"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="lifi", region="eu-west"}[1h]))) - region: us-east - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="us-east"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="us-east", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="lifi", region="us-east"}[1h]))) - region: sgp - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="sgp"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="lifi", region="sgp", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="lifi", region="sgp"}[1h]))) - slug: debridge @@ -191,22 +191,22 @@ providers: tag: Native-token fees formula: "Median wall-clock ms over 24h for deBridge's direct-protocol quote API to return a single-route USDC quote, sampled every 5 minutes across 4 routes and 3 notionals from the EU-West (Paris) origin." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="debridge"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="debridge"} - success: ocb:bridge_quote_success:avg24h{bridge="debridge"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="debridge"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="debridge"}[1h]))) regions: - region: eu-west - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="eu-west"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="debridge", region="eu-west"}[1h]))) - region: us-east - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="us-east"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="us-east", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="debridge", region="us-east"}[1h]))) - region: sgp - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="sgp"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="debridge", region="sgp", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="debridge", region="sgp"}[1h]))) - slug: near-intents @@ -214,22 +214,22 @@ providers: tag: Intent layer (NEAR) formula: "Median wall-clock ms over 24h for Near Intents 1Click API to return a usable USDC quote via the solver auction bus, sampled every 5 minutes across the supported routes and 3 notionals from the EU-West (Paris) origin." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="near-intents"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="near-intents"} - success: ocb:bridge_quote_success:avg24h{bridge="near-intents"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="near-intents"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="near-intents"}[1h]))) regions: - region: eu-west - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="eu-west"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="near-intents", region="eu-west"}[1h]))) - region: us-east - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="us-east"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="us-east", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="near-intents", region="us-east"}[1h]))) - region: sgp - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="sgp"}) + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="near-intents", region="sgp", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="near-intents", region="sgp"}[1h]))) - slug: across @@ -237,12 +237,12 @@ providers: tag: Intent layer formula: "Median wall-clock ms over 24h for Across's Swap API to return a usable USDC quote across supported corridors (Sol to Base, Base to Arb) from the EU-West origin. Arb to Sol excluded: no destination swaps to Solana." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="across"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="across"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="across"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="across"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="across"} - success: ocb:bridge_quote_success:avg24h{bridge="across"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="across"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="across", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="across"}[1h]))) - slug: squid @@ -250,12 +250,12 @@ providers: tag: Aggregator (Axelar) formula: "Median wall-clock ms for Squid Router's v2 API to return a best-output USDC route, p50 over 24h, EVM corridors only (Base to Arb). Solana source excluded: API returns server error." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="squid"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="squid"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="squid"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="squid"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="squid"} - success: ocb:bridge_quote_success:avg24h{bridge="squid"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="squid"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="squid", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="squid"}[1h]))) - slug: socket @@ -263,10 +263,10 @@ providers: tag: Aggregator formula: "Median wall-clock ms for Socket Protocol's v2 API to return a best-output USDC route (via Across, Stargate, CCTP), p50 over 24h, EVM corridors only (Base to Arb)." queries: - p50: histogram_quantile(0.50, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="socket"}) - p90: histogram_quantile(0.90, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="socket"}) - p99: histogram_quantile(0.99, ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="socket"}) - mean: ocb:bridge_quote_latency_ms_sum:rate24h{bridge="socket"} / ocb:bridge_quote_latency_ms_count:rate24h{bridge="socket"} - success: ocb:bridge_quote_success:avg24h{bridge="socket"} - sample_size: ocb:bridge_quote_latency_ms_count:increase24h{bridge="socket"} + p50: histogram_quantile(0.50, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"})) + p90: histogram_quantile(0.90, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"})) + p99: histogram_quantile(0.99, sum by (le) (ocb:bridge_quote_latency_ms_bucket:rate24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"})) + mean: sum(ocb:bridge_quote_latency_ms_sum:rate24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"}) / clamp_min(sum(ocb:bridge_quote_latency_ms_count:rate24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"}), 1e-9) + success: avg(ocb:bridge_quote_success:avg24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"}) + sample_size: round(sum(ocb:bridge_quote_latency_ms_count:increase24h{bridge="socket", region="eu-west", amount_usd=~"5|50|300"})) series: histogram_quantile(0.50, sum by (le) (rate(bridge_quote_latency_ms_bucket{bridge="socket"}[1h]))) diff --git a/harnesses/bridge-monitor/cmd/monitor/executor.go b/harnesses/bridge-monitor/cmd/monitor/executor.go index 9f01c03dc..bfd7587c0 100644 --- a/harnesses/bridge-monitor/cmd/monitor/executor.go +++ b/harnesses/bridge-monitor/cmd/monitor/executor.go @@ -956,7 +956,7 @@ func (e *Executor) recordExecutionMetrics(result *ExecutionResult) { } // Record latencies - bridgeQuoteLatency.WithLabelValues(labels...).Observe(float64(result.QuoteLatencyMs)) + bridgeExecQuoteLatency.WithLabelValues(labels...).Observe(float64(result.QuoteLatencyMs)) bridgeExecutionLatency.WithLabelValues(labels...).Observe(float64(result.ExecutionLatencyMs)) bridgeE2ELatency.WithLabelValues(labels...).Observe(float64(result.E2ELatencyMs)) // Exact latency gauge (only on a real fill): lets the bench read the true diff --git a/harnesses/bridge-monitor/cmd/monitor/metrics.go b/harnesses/bridge-monitor/cmd/monitor/metrics.go index 2beb60316..0b7e17fcb 100644 --- a/harnesses/bridge-monitor/cmd/monitor/metrics.go +++ b/harnesses/bridge-monitor/cmd/monitor/metrics.go @@ -14,8 +14,20 @@ var ( // bucket. histogram_quantile then linearly interpolated to ~25ms // regardless of the true value, hiding the real bimodality. bridgeQuoteLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "bridge_quote_latency_ms", - Help: "Latency to get bridge quote in milliseconds", + Name: "bridge_quote_latency_ms", + Help: "Latency to get bridge quote in milliseconds (quote loop only; execution-path quotes go to bridge_exec_quote_latency_ms)", + // Finer between 1 s and 5 s: Near Intents' dry quotes wait a fixed + // 3 s solver window, and with one bucket over (2000, 5000] every + // quantile was an interpolation of that edge. + Buckets: []float64{10, 25, 50, 100, 200, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 5000, 7500, 10000}, + }, []string{"bridge", "from_chain", "to_chain", "from_token", "to_token", "amount_usd", "region", "chain"}) + + // Quote latency measured on the execution path (a different call, with + // signing payloads, at the execution tickets). Kept out of the quote + // benches' histogram so it does not create undeclared $3 / $30 cells. + bridgeExecQuoteLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ + Name: "bridge_exec_quote_latency_ms", + Help: "Quote latency on the execution path in milliseconds", Buckets: []float64{10, 25, 50, 100, 200, 500, 1000, 2000, 5000, 10000}, }, []string{"bridge", "from_chain", "to_chain", "from_token", "to_token", "amount_usd", "region", "chain"}) diff --git a/harnesses/bridge-monitor/cmd/monitor/mobula_bridge.go b/harnesses/bridge-monitor/cmd/monitor/mobula_bridge.go index 47d4da6aa..c2e862a29 100644 --- a/harnesses/bridge-monitor/cmd/monitor/mobula_bridge.go +++ b/harnesses/bridge-monitor/cmd/monitor/mobula_bridge.go @@ -215,11 +215,14 @@ func signBridgeIntent(typedDataJSON json.RawMessage, key *ecdsa.PrivateKey) (str func (m *MobulaBridge) quote(originChain, originToken, destChain, destToken, senderAddress, walletAddress string, amount float64, extraParams string) (*MobulaQuoteResponse, time.Duration, error) { start := time.Now() + // The key travels in the Authorization header, not the query string: a + // transport error wraps *url.Error, whose text carries the full URL and + // used to reach the log and Slack. url := fmt.Sprintf( - mobulaAPIBase()+"/api/2/bridge/quote?originChainId=%s&originToken=%s&destinationChainId=%s&destinationToken=%s&amount=%s&walletAddress=%s&apiKey=%s", + mobulaAPIBase()+"/api/2/bridge/quote?originChainId=%s&originToken=%s&destinationChainId=%s&destinationToken=%s&amount=%s&walletAddress=%s", originChain, originToken, destChain, destToken, strconv.FormatFloat(amount, 'f', -1, 64), - walletAddress, m.apiKey, + walletAddress, ) if senderAddress != "" { url += "&senderAddress=" + senderAddress @@ -230,6 +233,7 @@ func (m *MobulaBridge) quote(originChain, originToken, destChain, destToken, sen if err != nil { return nil, 0, fmt.Errorf("failed to create request: %w", err) } + req.Header.Set("Authorization", m.apiKey) resp, err := m.client.Do(req) if err != nil { @@ -237,9 +241,11 @@ func (m *MobulaBridge) quote(originChain, originToken, destChain, destToken, sen } defer resp.Body.Close() - latency := time.Since(start) - + // Stopwatch stops after the body is read, like every other provider in + // this harness (it stopped at the response headers before, timing the + // operator's product to an earlier event than its competitors). body, _ := io.ReadAll(resp.Body) + latency := time.Since(start) if resp.StatusCode != http.StatusOK { return nil, latency, fmt.Errorf("API error %d: %s", resp.StatusCode, string(body)) } diff --git a/infrastructure/monitoring/prometheus/ocb_bridge_quote_solana.yml b/infrastructure/monitoring/prometheus/ocb_bridge_quote_solana.yml index 470283427..afea1a60f 100644 --- a/infrastructure/monitoring/prometheus/ocb_bridge_quote_solana.yml +++ b/infrastructure/monitoring/prometheus/ocb_bridge_quote_solana.yml @@ -7,12 +7,12 @@ groups: interval: 30s rules: - record: ocb:bridge_quote_latency_ms_bucket:sol_rate24h - expr: sum by (bridge, region, chain, amount_usd, le) (rate(bridge_quote_latency_ms_bucket{from_chain="Solana"}[24h])) + expr: sum by (bridge, region, chain, amount_usd, le) (rate(bridge_quote_latency_ms_bucket{from_chain="Solana", from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) - record: ocb:bridge_quote_success:sol_avg24h - expr: avg by (bridge, region, chain, amount_usd) (avg_over_time(bridge_quote_success{from_chain="Solana"}[24h])) + expr: avg by (bridge, region, chain, amount_usd) (avg_over_time(bridge_quote_success{from_chain="Solana", from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) - record: ocb:bridge_quote_latency_ms_count:sol_increase24h - expr: sum by (bridge, region, chain, amount_usd) (increase(bridge_quote_latency_ms_count{from_chain="Solana"}[24h])) + expr: sum by (bridge, region, chain, amount_usd) (increase(bridge_quote_latency_ms_count{from_chain="Solana", from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) - record: ocb:bridge_quote_latency_ms_sum:sol_rate24h - expr: sum by (bridge, region, chain, amount_usd) (rate(bridge_quote_latency_ms_sum{from_chain="Solana"}[24h])) + expr: sum by (bridge, region, chain, amount_usd) (rate(bridge_quote_latency_ms_sum{from_chain="Solana", from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) - record: ocb:bridge_quote_latency_ms_count:sol_rate24h - expr: sum by (bridge, region, chain, amount_usd) (rate(bridge_quote_latency_ms_count{from_chain="Solana"}[24h])) + expr: sum by (bridge, region, chain, amount_usd) (rate(bridge_quote_latency_ms_count{from_chain="Solana", from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) diff --git a/infrastructure/monitoring/prometheus/recording_rules/ocb_bridge_quote.yml b/infrastructure/monitoring/prometheus/recording_rules/ocb_bridge_quote.yml new file mode 100644 index 000000000..e16df402f --- /dev/null +++ b/infrastructure/monitoring/prometheus/recording_rules/ocb_bridge_quote.yml @@ -0,0 +1,32 @@ +# Recording rules for the bridge QUOTE benches (002 bridge-quote-latency, +# 003 bridge-fee reads raw gauges). Deployed on the VPS Prometheus as +# /opt/ocb/prom-rules/histogram_recording_rules.yml (the file was VPS-only +# until 2026-09-19; this is the source of truth now). +# +# The rules keep (bridge, region, chain, amount_usd) so the chain tabs can +# filter; the SPEC queries must aggregate with sum by (le) / sum() / avg() +# over what is left, or prom.scalar takes result[0] and the headline is a +# random cell (audit 2026-09-19: p99 below p50 on the live page). +# +# Excluded at the source: +# - the R4 meme route (TRUMP on Solana to BRETT on Base) quoted by the +# same loop, which pooled a cross-asset swap into the USDC corridors; +# - execution-path quotes, which the harness now observes in +# bridge_exec_quote_latency_ms (amount_usd 3 and 30 kept out here for +# the samples recorded before that change). +groups: + - name: bridge_quote_recording + interval: 15m + rules: + - record: ocb:bridge_quote_latency_ms_bucket:rate24h + expr: sum by (bridge, region, chain, amount_usd, le) (rate(bridge_quote_latency_ms_bucket{from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) + - record: ocb:bridge_quote_latency_ms_sum:rate24h + expr: sum by (bridge, region, chain, amount_usd) (rate(bridge_quote_latency_ms_sum{from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) + - record: ocb:bridge_quote_latency_ms_count:rate24h + expr: sum by (bridge, region, chain, amount_usd) (rate(bridge_quote_latency_ms_count{from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) + - record: ocb:bridge_quote_latency_ms_count:increase24h + expr: sum by (bridge, region, chain, amount_usd) (increase(bridge_quote_latency_ms_count{from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) + - record: ocb:bridge_quote_success:avg24h + expr: avg by (bridge, region, chain, amount_usd) (avg_over_time(bridge_quote_success{from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h])) + - record: ocb:bridge_quote_latency_ms_bucket:rate24h_provider + expr: sum by (provider, region, chain, amount_usd, le) (label_replace(rate(bridge_quote_latency_ms_bucket{from_token!="6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", amount_usd!~"3|30"}[24h]), "provider", "$1", "bridge", "(.+)"))