# Restaking Risk API > Calculate collateral reuse and modeled slash losses, and check whether caller-supplied slashing stages fit in an available window. No network calls are made. Each POST has a fixed USDC price on Base, paid with the x402 exact scheme. The request is validated first, and payment settles only after a successful (2xx) result. Failed calls are not charged. 1. POST JSON matching the requestBody. Invalid input returns 400 with no payment challenge. 2. A valid unpaid call returns 402 with the exact amount and payTo. 3. Pay and retry with payment-signature. Payment settles only if the operation returns 2xx. A 4xx/5xx is not charged. - Product: https://www.brainiac.software/api/restaking-risk - Docs: https://www.brainiac.software/api/restaking-risk/docs - OpenAPI: https://www.brainiac.software/api/restaking-risk/openapi.json - Contact: support@brainiac.software (https://www.brainiac.software/contact) ## Operations ### POST /api/v1/restaking-risk/cross-network-slashing-exposure $0.05 USDC. Calculate unique collateral, gross exposure, and overlap when caller-supplied vault collateral is reused across networks. Simultaneous scenarios slash the starting balance and cap the combined percent at 100%. Sequential scenarios reduce the remaining balance after each event. audit_status is calculated, warnings, incomplete, or invalid. Amounts are integers in the caller-supplied unit. Prices and conversion rates are used only when supplied. No balance or price is fetched. Inputs: vaults, allocations, reuse?, slashing, scenarios, prices?, rates? Docs: https://www.brainiac.software/api/restaking-risk/docs#restaking-risk-cross-network-slashing-exposure Example request: ```json { "vaults": [ { "id": "vault-a", "collateral": [ { "asset": "stETH", "amount": "1000" }, { "asset": "ETH", "amount": "500" } ] }, { "id": "vault-b", "collateral": [ { "asset": "stETH", "amount": "1000" } ] } ], "allocations": [ { "id": "a1", "vault": "vault-a", "network": "eigenlayer", "operator": "op-1", "asset": "stETH", "amount": "1000" }, { "id": "a2", "vault": "vault-b", "network": "symbiotic", "operator": "op-2", "asset": "stETH", "amount": "1000" }, { "id": "a3", "vault": "vault-a", "network": "eigenlayer", "operator": "op-1", "asset": "ETH", "amount": "200" } ], "reuse": [ { "id": "shared-steth", "asset": "stETH", "amount": "1000", "allocations": [ "a1", "a2" ] } ], "slashing": [ { "network": "eigenlayer", "operator": "op-1", "percent": "50" }, { "network": "symbiotic", "operator": "op-2", "percent": "40" } ], "scenarios": [ { "id": "both-at-once", "ordering": "simultaneous", "events": [ { "network": "eigenlayer", "operator": "op-1" }, { "network": "symbiotic", "operator": "op-2" } ] }, { "id": "eigen-then-symbiotic", "ordering": "sequential", "events": [ { "network": "eigenlayer", "operator": "op-1" }, { "network": "symbiotic", "operator": "op-2" } ] } ], "prices": [ { "asset": "ETH", "quote": "USD", "price": "3000" } ], "rates": [ { "base": "stETH", "quote": "ETH", "rate": "1" } ] } ``` Example response: ```json { "audit_status": "warnings", "total_collateral": [ { "asset": "stETH", "amount": "2000", "detail": "Stated stETH is vault-a 1000 plus vault-b 1000. A vault line is the balance that vault reports, before reuse is removed." }, { "asset": "ETH", "amount": "500", "detail": "Stated ETH is vault-a 500. A vault line is the balance that vault reports, before reuse is removed." } ], "unique_collateral": [ { "asset": "stETH", "amount": "1000", "detail": "Unique stETH is stated 2000 minus 1000. shared-steth removes 1000 because vault-a and vault-b list the same 1000." }, { "asset": "ETH", "amount": "500", "detail": "Unique ETH is 500. No reuse group spans more than one vault for this asset." } ], "unique_collateral_value": { "quote": "USD", "amount": "4500000", "detail": "Unique collateral is 4500000 USD using the supplied price or one conversion." }, "total_gross_exposure": [ { "asset": "stETH", "amount": "2000", "detail": "Gross stETH exposure adds a1 1000 plus a2 1000. Each allocation is counted in full." }, { "asset": "ETH", "amount": "200", "detail": "Gross ETH exposure adds a3 200. Each allocation is counted in full." } ], "total_gross_exposure_value": { "quote": "USD", "amount": "6600000", "detail": "Gross exposure is 6600000 USD using the supplied price or one conversion." }, "overlapping_exposure": [ { "asset": "stETH", "amount": "1000", "reuse_id": "shared-steth", "detail": "2 allocations list the same 1000 stETH. Overlap is 1000 times 1 extra listing." } ], "network_exposure": [ { "network": "eigenlayer", "asset": "stETH", "gross_amount": "1000", "unique_amount": "1000", "detail": "eigenlayer gross stETH is 1000 from allocations. Unique units exposed on this network are 1000. A unit reused on another network is included here once and may also be included there." }, { "network": "symbiotic", "asset": "stETH", "gross_amount": "1000", "unique_amount": "1000", "detail": "symbiotic gross stETH is 1000 from allocations. Unique units exposed on this network are 1000. A unit reused on another network is included here once and may also be included there." }, { "network": "eigenlayer", "asset": "ETH", "gross_amount": "200", "unique_amount": "200", "detail": "eigenlayer gross ETH is 200 from allocations. Unique units exposed on this network are 200. A unit reused on another network is included here once and may also be included there." } ], "vault_exposure": [ { "vault": "vault-a", "asset": "stETH", "collateral_amount": "1000", "gross_amount": "1000", "unique_amount": "1000", "shared_amount": "1000", "detail": "vault-a reports 1000 stETH. Allocations list 1000. 1000 unique units of this vault are allocated, of which 1000 also appear in a reuse group." }, { "vault": "vault-a", "asset": "ETH", "collateral_amount": "500", "gross_amount": "200", "unique_amount": "200", "shared_amount": "0", "detail": "vault-a reports 500 ETH. Allocations list 200. 200 unique units of this vault are allocated, of which 0 also appear in a reuse group." }, { "vault": "vault-b", "asset": "stETH", "collateral_amount": "1000", "gross_amount": "1000", "unique_amount": "1000", "shared_amount": "1000", "detail": "vault-b reports 1000 stETH. Allocations list 1000. 1000 unique units of this vault are allocated, of which 1000 also appear in a reuse group." } ], "scenarios": [ { "id": "both-at-once", "ordering": "simultaneous", "losses": [ { "asset": "stETH", "amount": "900", "detail": "simultaneous loss of stETH is 900 unique units. Gross exposure is not this loss." }, { "asset": "ETH", "amount": "100", "detail": "simultaneous loss of ETH is 100 unique units. Gross exposure is not this loss." } ], "loss_value": { "quote": "USD", "amount": "3000000", "detail": "both-at-once modeled loss is 3000000 USD using the supplied price or one conversion." }, "remaining": [ { "asset": "stETH", "amount": "100", "detail": "both-at-once leaves 100 stETH. Starting unique collateral was 1000." }, { "asset": "ETH", "amount": "400", "detail": "both-at-once leaves 400 ETH. Starting unique collateral was 500." } ], "events": [ { "index": 1, "network": "eigenlayer", "operator": "op-1", "percent": "50", "asset_losses": [ { "asset": "stETH", "amount": "500", "detail": "eigenlayer operator op-1 is attributed 500 stETH from the starting balance at 50%. Simultaneous losses are capped so the combined percent does not pass 100%." }, { "asset": "ETH", "amount": "100", "detail": "eigenlayer operator op-1 is attributed 100 ETH from the starting balance at 50%. Simultaneous losses are capped so the combined percent does not pass 100%." } ], "remaining": [ { "asset": "stETH", "amount": "500", "detail": "Simultaneous events share the starting balance. 500 stETH remains after the loss attributed through event 1." }, { "asset": "ETH", "amount": "400", "detail": "Simultaneous events share the starting balance. 400 ETH remains after the loss attributed through event 1." } ], "detail": "simultaneous event 1 uses 50% from the operator slashing rule." }, { "index": 2, "network": "symbiotic", "operator": "op-2", "percent": "40", "asset_losses": [ { "asset": "stETH", "amount": "400", "detail": "symbiotic operator op-2 is attributed 400 stETH from the starting balance at 40%. Simultaneous losses are capped so the combined percent does not pass 100%." } ], "remaining": [ { "asset": "stETH", "amount": "100", "detail": "Simultaneous events share the starting balance. 100 stETH remains after the loss attributed through event 2." }, { "asset": "ETH", "amount": "400", "detail": "Simultaneous events share the starting balance. 400 ETH remains after the loss attributed through event 2." } ], "detail": "simultaneous event 2 uses 40% from the operator slashing rule." } ] }, { "id": "eigen-then-symbiotic", "ordering": "sequential", "losses": [ { "asset": "stETH", "amount": "700", "detail": "sequential loss of stETH is 700 unique units. Gross exposure is not this loss." }, { "asset": "ETH", "amount": "100", "detail": "sequential loss of ETH is 100 unique units. Gross exposure is not this loss." } ], "loss_value": { "quote": "USD", "amount": "2400000", "detail": "eigen-then-symbiotic modeled loss is 2400000 USD using the supplied price or one conversion." }, "remaining": [ { "asset": "stETH", "amount": "300", "detail": "eigen-then-symbiotic leaves 300 stETH. Starting unique collateral was 1000." }, { "asset": "ETH", "amount": "400", "detail": "eigen-then-symbiotic leaves 400 ETH. Starting unique collateral was 500." } ], "events": [ { "index": 1, "network": "eigenlayer", "operator": "op-1", "percent": "50", "asset_losses": [ { "asset": "stETH", "amount": "500", "detail": "eigenlayer operator op-1 slashes 50% of the stETH remaining before this event. The floor loss is 500." }, { "asset": "ETH", "amount": "100", "detail": "eigenlayer operator op-1 slashes 50% of the ETH remaining before this event. The floor loss is 100." } ], "remaining": [ { "asset": "stETH", "amount": "500", "detail": "After event 1, 500 stETH of unique collateral remains." }, { "asset": "ETH", "amount": "400", "detail": "After event 1, 400 ETH of unique collateral remains." } ], "detail": "sequential event 1 uses 50% from the operator slashing rule." }, { "index": 2, "network": "symbiotic", "operator": "op-2", "percent": "40", "asset_losses": [ { "asset": "stETH", "amount": "200", "detail": "symbiotic operator op-2 slashes 40% of the stETH remaining before this event. The floor loss is 200." } ], "remaining": [ { "asset": "stETH", "amount": "300", "detail": "After event 2, 300 stETH of unique collateral remains." }, { "asset": "ETH", "amount": "400", "detail": "After event 2, 400 ETH of unique collateral remains." } ], "detail": "sequential event 2 uses 40% from the operator slashing rule." } ] } ], "maximum_modeled_loss": [ { "asset": "stETH", "amount": "900", "scenario_id": "both-at-once", "ordering": "simultaneous", "detail": "The largest modeled stETH loss is 900 in both-at-once (simultaneous). This is unique units lost, not gross exposure." }, { "asset": "ETH", "amount": "100", "scenario_id": "both-at-once", "ordering": "simultaneous", "detail": "The largest modeled ETH loss is 100 in both-at-once (simultaneous). This is unique units lost, not gross exposure." } ], "maximum_modeled_loss_value": { "quote": "USD", "amount": "3000000", "scenario_id": "both-at-once", "detail": "The largest valued modeled loss is 3000000 USD in both-at-once. Each asset is valued once from the supplied price or one conversion." }, "concentration": [ { "kind": "network", "id": "eigenlayer", "asset": "stETH", "share": "50.0000", "gross_amount": "1000", "total_gross": "2000", "detail": "network eigenlayer lists 1000 of 2000 gross stETH. The share is 50.0000%. Reused units are counted in every allocation." }, { "kind": "vault", "id": "vault-a", "asset": "stETH", "share": "50.0000", "gross_amount": "1000", "total_gross": "2000", "detail": "vault vault-a lists 1000 of 2000 gross stETH. The share is 50.0000%. Reused units are counted in every allocation." }, { "kind": "network", "id": "symbiotic", "asset": "stETH", "share": "50.0000", "gross_amount": "1000", "total_gross": "2000", "detail": "network symbiotic lists 1000 of 2000 gross stETH. The share is 50.0000%. Reused units are counted in every allocation." }, { "kind": "vault", "id": "vault-b", "asset": "stETH", "share": "50.0000", "gross_amount": "1000", "total_gross": "2000", "detail": "vault vault-b lists 1000 of 2000 gross stETH. The share is 50.0000%. Reused units are counted in every allocation." }, { "kind": "network", "id": "eigenlayer", "asset": "ETH", "share": "100.0000", "gross_amount": "200", "total_gross": "200", "detail": "network eigenlayer lists 200 of 200 gross ETH. The share is 100.0000%. Reused units are counted in every allocation." }, { "kind": "vault", "id": "vault-a", "asset": "ETH", "share": "100.0000", "gross_amount": "200", "total_gross": "200", "detail": "vault vault-a lists 200 of 200 gross ETH. The share is 100.0000%. Reused units are counted in every allocation." } ], "cascading_paths": [ { "reuse_id": "shared-steth", "asset": "stETH", "amount": "1000", "vaults": [ "vault-a", "vault-b" ], "networks": [ "eigenlayer", "symbiotic" ], "operators": [ "op-1", "op-2" ], "detail": "The same 1000 stETH is listed by a1 and a2. Those units can be slashed by every listed network. Later sequential events see the reduced balance." } ], "warnings": [ { "code": "cascading_exposure", "severity": "medium", "detail": "Reuse shared-steth shares 1000 stETH across eigenlayer and symbiotic. A sequential slash on one exposure reduces the collateral left for the later exposure." }, { "code": "concentration", "severity": "medium", "detail": "network eigenlayer has 100.0000% of gross ETH exposure. The highlight threshold is more than half." }, { "code": "concentration", "severity": "medium", "detail": "vault vault-a has 100.0000% of gross ETH exposure. The highlight threshold is more than half." } ], "assumptions": [ "Amounts are integers in the caller-supplied unit. Each slash uses floor division, so a remainder stays with the collateral.", "A reuse group is one quantity of underlying collateral named by more than one allocation. Unique collateral counts that quantity once.", "Gross exposure adds every allocation. Reused collateral is counted once for each allocation that lists it.", "Overlapping exposure is the extra times reused collateral is listed. It is not an additional balance.", "A simultaneous scenario applies every matching percent to the starting amount of a shared slice and caps the combined percent at 100%.", "A sequential scenario subtracts each matching loss before the next event is applied to that slice.", "An event percent replaces the slashing table for that event. Otherwise the operator rule is used, then a network rule with no operator.", "Collateral that is not allocated is not slashed.", "A supplied price values an asset. A supplied rate converts that asset once into another asset that has a price. No price or rate is invented.", "A concentration figure above 50% means one network or vault holds more than half of that asset's gross exposure.", "A modeled loss is the slash of unique units. Gross exposure is the larger figure and is not the loss." ] } ``` ### POST /api/v1/restaking-risk/slashing-correlation $0.04 USDC. Cap each operator's network weights at 100 percent of its stake, then weight that exposure by stake. The correlation score is the share of stake that sits on more than one network. Weights are the caller's risk weights. No stake is fetched. Inputs: operators Docs: https://www.brainiac.software/api/restaking-risk/docs#restaking-risk-slashing-correlation Example request: ```json { "operators": [ { "id": "op-a", "stake": 1000, "networks": [ { "id": "eigenlayer", "weight": 60 }, { "id": "symbiotic", "weight": 50 } ] }, { "id": "op-b", "stake": 1000, "networks": [ { "id": "eigenlayer", "weight": 20 } ] } ] } ``` Example response: ```json { "maximum_slashing_exposure_percentage": 60, "correlation_risk_score": 50 } ``` ### POST /api/v1/restaking-risk/slashing-window-feasibility $0.05 USDC. Compare caller-supplied slashing stages with an available window. Each duration is an integer in seconds, or in epochs when its unit is epochs. Epoch length is seconds. Stages run in detection, evidence, submission, veto, execution, and finality order. Consecutive stages listed in parallel start together and the timeline uses the longest. A missing stage is incomplete and is not treated as zero. feasibility_status is feasible, margin_exceeded, infeasible, incomplete, or invalid. A fit is arithmetic only. No protocol parameters are fetched. Inputs: epoch, window, detection?, evidence?, submission?, veto?, execution?, finality?, margin?, parallel?, alternatives? Docs: https://www.brainiac.software/api/restaking-risk/docs#restaking-risk-slashing-window-feasibility Example request: ```json { "epoch": { "value": "12", "unit": "seconds" }, "window": { "value": "10", "unit": "epochs" }, "detection": { "value": "2", "unit": "epochs" }, "evidence": { "value": "30", "unit": "seconds" }, "submission": { "value": "1", "unit": "epochs" }, "veto": { "value": "2", "unit": "epochs" }, "execution": { "value": "18", "unit": "seconds" }, "finality": { "value": "1", "unit": "epochs" }, "margin": { "value": "12", "unit": "seconds" }, "alternatives": [ { "id": "shorter-evidence", "epoch": { "value": "12", "unit": "seconds" }, "window": { "value": "10", "unit": "epochs" }, "detection": { "value": "2", "unit": "epochs" }, "evidence": { "value": "18", "unit": "seconds" }, "submission": { "value": "1", "unit": "epochs" }, "veto": { "value": "2", "unit": "epochs" }, "execution": { "value": "18", "unit": "seconds" }, "finality": { "value": "1", "unit": "epochs" }, "margin": { "value": "12", "unit": "seconds" } } ] } ``` Example response: ```json { "feasibility_status": "margin_exceeded", "available_window": { "seconds": "120", "epochs": "10", "remainder_seconds": "0", "detail": "The available window is 120 seconds, which is 10 epochs of 12 seconds." }, "total_required": { "seconds": "132", "epochs": "11", "remainder_seconds": "0", "includes_margin": true, "detail": "The stages take 120 seconds. The safety margin adds 12 seconds, so the required duration is 132 seconds." }, "slack": { "kind": "overrun", "seconds": "12", "detail": "Required 132 seconds exceeds the 120 second window by 12 seconds." }, "stages": [ { "stage": "detection", "seconds": "24", "epochs": "2", "remainder_seconds": "0", "supplied_value": "2", "supplied_unit": "epochs", "start_seconds": "0", "end_seconds": "24", "share": "20.0000", "parallel": false, "detail": "2 epochs of 12 seconds is 24 seconds. It starts at 0 seconds and ends at 24 seconds. It is 20.0000% of the 120 second window." }, { "stage": "evidence", "seconds": "30", "epochs": "2", "remainder_seconds": "6", "supplied_value": "30", "supplied_unit": "seconds", "start_seconds": "24", "end_seconds": "54", "share": "25.0000", "parallel": false, "detail": "30 seconds. It starts at 24 seconds and ends at 54 seconds. It is 25.0000% of the 120 second window." }, { "stage": "submission", "seconds": "12", "epochs": "1", "remainder_seconds": "0", "supplied_value": "1", "supplied_unit": "epochs", "start_seconds": "54", "end_seconds": "66", "share": "10.0000", "parallel": false, "detail": "1 epoch of 12 seconds is 12 seconds. It starts at 54 seconds and ends at 66 seconds. It is 10.0000% of the 120 second window." }, { "stage": "veto", "seconds": "24", "epochs": "2", "remainder_seconds": "0", "supplied_value": "2", "supplied_unit": "epochs", "start_seconds": "66", "end_seconds": "90", "share": "20.0000", "parallel": false, "detail": "2 epochs of 12 seconds is 24 seconds. It starts at 66 seconds and ends at 90 seconds. It is 20.0000% of the 120 second window." }, { "stage": "execution", "seconds": "18", "epochs": "1", "remainder_seconds": "6", "supplied_value": "18", "supplied_unit": "seconds", "start_seconds": "90", "end_seconds": "108", "share": "15.0000", "parallel": false, "detail": "18 seconds. It starts at 90 seconds and ends at 108 seconds. It is 15.0000% of the 120 second window." }, { "stage": "finality", "seconds": "12", "epochs": "1", "remainder_seconds": "0", "supplied_value": "1", "supplied_unit": "epochs", "start_seconds": "108", "end_seconds": "120", "share": "10.0000", "parallel": false, "detail": "1 epoch of 12 seconds is 12 seconds. It starts at 108 seconds and ends at 120 seconds. It is 10.0000% of the 120 second window." } ], "bottlenecks": [ { "stage": "evidence", "seconds": "30", "share": "25.0000", "detail": "evidence is the longest supplied stage at 30 seconds, 25.0000% of the window." } ], "infeasibility": [ { "parameter": "margin", "seconds": "12", "detail": "The stages take 120 seconds and fit in the 120 second window. The 12 second safety margin makes the required duration 132 seconds, which overruns by 12 seconds." } ], "missing_stages": [], "safety_margin": { "supplied": true, "seconds": "12", "ideal_seconds": "120", "with_margin_seconds": "132", "ideal_fits": true, "with_margin_fits": false, "detail": "The stages fit and the 12 second safety margin does not." }, "alternatives": [ { "id": "shorter-evidence", "feasibility_status": "feasible", "available_window_seconds": "120", "total_required_seconds": "120", "slack_kind": "remaining", "slack_seconds": "0", "ideal_fits": true, "with_margin_fits": true, "detail": "Required 120 seconds leaves 0 seconds of the 120 second window." } ], "assumptions": [ "Every duration is an integer. A value in epochs is that integer times the supplied epoch length. The epoch length is seconds.", "The calculated unit is seconds. Epoch counts use integer division, and a remainder is the leftover seconds.", "Stages run in detection, evidence, submission, veto, execution, and finality order. A parallel group of consecutive stages starts together, and the next stage waits for the longest member.", "Parallel durations are not added. Each stage is still listed with its own duration.", "A missing stage is omitted from the sum. It is not treated as zero, and the result is incomplete.", "Veto, execution, and finality are required stages. When they are supplied, their full duration is included.", "The safety margin is added after the last stage. It is not a second copy of any stage.", "Remaining time is the window minus the required duration. Overrun is the required duration minus the window.", "A fit is arithmetic on the supplied numbers. It does not show that a network will detect, submit, veto, or finalize in that time.", "No protocol parameters were fetched." ] } ``` ### POST /api/v1/restaking-risk/exit-window $0.04 USDC. Subtract the unbonding time and the withdrawal delay from the soonest caller-supplied slash horizon. The buffer is that remainder in hours. The feasibility score is the buffer divided by the soonest horizon, and it is zero when the buffer is negative. No queue is read from a network. Inputs: unbonding_hours, withdrawal_delay_hours, events Docs: https://www.brainiac.software/api/restaking-risk/docs#restaking-risk-exit-window Example request: ```json { "unbonding_hours": 24, "withdrawal_delay_hours": 18, "events": [ { "network": "eigenlayer", "hours_until_slash": 72 }, { "network": "symbiotic", "hours_until_slash": 96 } ] } ``` Example response: ```json { "exit_feasibility_score": 42, "time_buffer_hours": 30 } ```