TLDR: This post proposes a mechanism to slash operators who fail to meet the job specifications after the assignment.
Kalypso enables users to specify a deadlines when a job is submitted. A match is only made against an operator who can provide the proof within the deadline. If the operator fails to submit the proof for the job within the specified time period, then the operator can be slashed.
There are two components to an operator stake:
- Self stake - Tokens staked by an operator itself
- Delegations - Tokens delegated to an operator either from the native staking or Symbiotic module
The self stake portion of the stake of a slashed job is provided to the slasher who submits the slashing request while the rest of the stake assigned for the job through delegations is burnt once all phases of slashing are completed.
Slashing proceeds in 4 phases:
- Job enters the slashing phase
- The slash request is bridged to Ethereum where it is submitted to all Symbiotic vaults that delegate towards the operator
- Unless the slash request is vetoed, the slash request is executed once veto period is over and before the execution period is over
- The result of the slash request (vetoed or executed) is submitted back on Arbitrum
Phase 1: Job enters the slashing phase on Arbitrum
When the ZK proof for a job isn’t submitted within the specified time, the job enters the slashing phase. This blocks the stake assigned to the job from being reused for any other job till a proof that the Symbiotic contract on Ethereum either vetoed or executed the slashing isn’t received.
Phase 2: Slashing Request is submitted to the vaults on Ethereum
The enclave code to read data for a given jobId from Arbitrum and generate a signed message to prove that the job has met the conditions to be slashed is predefined and published.
-
Anyone acting as a Slasher can deploy the above enclave image and verify its signing key on Ethereum.
-
The Slasher can then send a request to the enclave by sending the following parameters:
-
API keys for the RPC endpoints used for both Arbitrum and Ethereum
-
jobId of the job that entered the slashing phase
-
The response from the enclave has the following format:
{ jobId: <number> operator: <address>, captureTimestamp: <number>, signedData: { <vault address>: { slashedAmount: <number>, signature: <Sig on jobId, vault, operator, captureTimestamp, stakedAmount> }, … } }
-
All the vaults staked towards the operator during captureTimestamp are subject to being slashed. A Slash Request per vault is submitted to the
initiateVaultSlash
method of the Slash Verifier contract on Ethereum.function initiateVaultSlash ( uint256 jobId, address operator, address vault, uint256 captureTimestamp, uint256 amount, address feeAddress )
-
Multiple Slash Requests for different vaults for the same job can be submitted together using an aggregator function.
Phase 3: Slash Request Resolution
Depending on the slashing mechanism used by the vaults, the slash request might result in instant slashing or there can be a veto period. Slasher needs to execute slashing once the veto period is complete in case of veto slashing.
Phase 4: Slash Response is submitted on Arbitrum
-
The enclave image used to transfer data from Ethereum to Arbitrum also contains logic which reads data from Ethereum regarding the execution or veto of Slashing Requests finalized between the lastCaptureTimestamp to the latestCaptureTimestamp for which data is being bridged.
-
The Transmitter can send a request to the server in enclave image with the following parameters:
-
API keys necessary for enclave to read data from Ethereum
-
lastCaptureTimestamp to be used for querying executions and vetoes
-
Number of entries to divide executions and vetoes into so that the transaction fits within Arbitrum’s gas limit
-
All the data about executions/vetoes of slashing requests are read from Ethereum and the response consolidates the amount vetoed or slashed per job. The response format is as follows:
{ lastCaptureTimestamp: <Timestamp>, captureTimestamp: <Timestamp>, slashResolutions: [ <length: noOfTxs> { slashData: <RLP encoded array of (jobId, amount, feeAddress)> signature: <signature on index, noOfTxs, slashData, lastCaptureTimestamp, captureTimestamp> }, … ] }
-
In case there’s no veto or execution, a signature with noOfTxs as 0 and all other data as null values is produced which can be submitted on-chain as proof.
-
The response data (veto or execution) is to be submitted to the following function:
function submitSlashes ( uint256 index, uint256 noOfTxs, uint256 captureTimestamp, bytes data, bytes signature )
-
A snapshot is complete only if delegation data and slash responses are submitted and if lastCaptureTimestamp matches the captureTimestamp of the last snapshot and captureTimestamp for all the txs are the same and submitted by the same Transmitter.
-
If no slash response for a job is submitted within
MEL
(max vault epoch length) time from the captureTimestamp that was used for the job, then the self stake/delegation blocked for the job can be released by the operator.