---
# System prepended metadata

title: Casimir Notes
tags: [docs]

---

# Casimir Notes

> Notes on current implementation and upcoming required changes based on [EigenPod Redesign](https://hackmd.io/U36dE9lnQha3tbf7D0GtKw#Changes-from-M2)

## Oracle

Todo outline oracle role and related circumstances. Note, the oracle checks all flow conditions in the order listed below every 5 minutes and calls the corresponding methods as they're required.

### Validator Flow

The oracle updates individual validators throughout their lifecycle from the execution layer to the beacon chain and back again.

1. **Deposit validator**

    - **Summary:**

        The oracle selects `CasimirRegistry.clusterSize` operators for DKG and calls `CasimirManager.depositValidator` with the generated validator deposit info as soon as a new validator is funded and ready for deposit.

    - **Inputs:**
    
    - **Conditions:**

        - The manager has a ready validator (`CasimirManager.readyValidatorIds > 0`)

    - **Effects:**

    - **Implementation:**

2. **Activate validator**

    - **Summary:**

        The oracle generates a validator beacon chain proof and calls `CasimirManager.activateValidator` with the proofs as soon as a pending validator is detectable on the beacon chain.

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

3. **Reshare validator**

    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

4. **Withdraw validator**

    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

### Report Flow

The oracle syncs the sums of execution layer and beacon chain balances daily to prove and update the manager stake balance and related state.

1. **Start report**

    *Current design:*
    
    - **Summary:**

        The oracle calls `CasimirManager.startReport` to capture execution layer timestamp and swept balance snapshot for the report.
        
    - **Inputs:**
    
    - **Conditions:** 

        - The previous report is complete (`ReportStatus.WAITING`)
        - 1 day has passed since the previous report (`REPORT_HEARTBEAT`)

    - **Effects:**

        - Captures the current timestamp to use in the report proofs
        - Captures the total swept balance as a sum of the ambiguous effective balance and rewards in the `EigenPod` and the already-differentiated (withdrawal-delayed) effective balance and rewards
        - Sets the report status for the next step (`ReportStatus.SYNCING_VALIDATORS`)

    - **Implementation:**
    
        ```solidity
        function startReport() external {
            onlyOracle();

            if (reportStatus != ReportStatus.WAITING || block.timestamp < reportTimestamp + REPORT_HEARTBEAT) {
                revert ReportNotNeeded();
            }

            reportStatus = ReportStatus.SYNCING_VALIDATORS;
            reportTimestamp = block.timestamp;
            reportSweptBalance = address(eigenPod).balance - eigenPod.nonBeaconChainETHBalanceWei()
                + delayedEffectiveBalance + delayedRewards;

            emit ReportStarted(reportTimestamp, reportSweptBalance);
        }
        ```
    
    *EigenPod redesign:*
    
    - **Summary:**
    
        The upcoming redesign adds `EigenPod.startCheckpoint` which will be called in `CasimirManager.startReport`, but fits in with minimal changes (some state moves to the `EigenPod`).
        
    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**
    
        ```solidity
        Todo write pseudo code to handle redesign
        ```
    
2. **Sync validators**

    *Current design:*
    
    - **Summary:**

        See the redesign notes below.

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

    *EigenPod redesign:*

    - **Summary:**

        The redesign will allow proving the sum of active validator beacon chain balances, withdrawn validators, and withdrawn rewards using `EigenPod.verifyCheckpointProofs`. The withdrawal proofs in `CasimirManager.withdrawValidator` and `CasimirManager.withdrawRewards` will be removed, and instead the `CasimirManager.syncValidators` will accept an array of validator proofs for the `EigenPod`.

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

3. **Fulfill unstakes**

    *Current design:*
    
    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

    *EigenPod redesign:*
    
    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

4. **Finalize report**

    *Current design:*
    
    - **Summary:**
    
        The oracle calls `CasimirManager.finalizeReport()` to calculate (and disambiguate) the current rewards for a report and update the `CasimirManager.rewardStakeRatioSum` (see the `S` variable described [here](https://batog.info/papers/scalable-reward-distribution.pdf)), effectively rebalancing the user stakes based on the report values.
    
    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**
    
        ```solidity
        function finalizeReport() external {
            onlyOracle();

            if (reportStatus != ReportStatus.FINALIZING) {
                revert ReportNotFinalizing();
            }

            reportStatus = ReportStatus.WAITING;
            uint256 totalStake = getTotalStake();

            uint256 expectedWithdrawnEffectiveBalance = reportWithdrawableValidators * VALIDATOR_CAPACITY;
            uint256 expectedEffectiveBalance = stakedValidatorIds.length * VALIDATOR_CAPACITY;

            int256 rewards = int256(reportActiveBalance + reportSweptBalance)
                - int256(expectedEffectiveBalance + expectedWithdrawnEffectiveBalance);

            int256 change = rewards - latestActiveRewards;

            if (change > 0) {
                uint256 gain = uint256(change);
                if (rewards > 0) {
                    uint256 gainAfterFee = subtractRewardFee(gain);
                    rewardStakeRatioSum += Math.mulDiv(rewardStakeRatioSum, gainAfterFee, totalStake);
                    latestActiveBalanceAfterFee += gainAfterFee;
                } else {
                    rewardStakeRatioSum += Math.mulDiv(rewardStakeRatioSum, gain, totalStake);
                    latestActiveBalanceAfterFee += gain;
                }
            } else if (change < 0) {
                uint256 loss = uint256(-change);
                rewardStakeRatioSum -= Math.mulDiv(rewardStakeRatioSum, loss, totalStake);
                latestActiveBalanceAfterFee -= loss;
            }
            int256 sweptRewards =
                int256(reportSweptBalance + reportRecoveredEffectiveBalance) - int256(reportWithdrawnEffectiveBalance);

            if (sweptRewards > 0) {
                latestActiveBalanceAfterFee -= subtractRewardFee(uint256(sweptRewards));
            }
            latestActiveBalanceAfterFee -= reportWithdrawnEffectiveBalance;
            latestActiveRewards = rewards - sweptRewards;

            reportPeriod++;
            reportRecoveredEffectiveBalance = 0;
            reportWithdrawnEffectiveBalance = 0;
            reportWithdrawnValidators = 0;

            emit ReportFinalized();
        }
        ```
        
    *EigenPod redesign:*
    
    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**
    
### Claim Flow

The oracle claims delayed withdrawals of effective balance and rewards.

1. **Claim effective balance**

    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**

2. **Claim rewards**

    - **Summary:**

    - **Inputs:**
    
    - **Conditions:** 

    - **Effects:**

    - **Implementation:**


## Cyfrin Questions

Todo copy these over.

