ebtc-protocol/ebtc

View synced collShares, debt, ICR, TCR

Closed this issue · 1 comments

Problem

The TCR and ICR, when read from the contract at a point-in-time, are always incorrect if the accounting (stEth rebases, debt redistributions) are not synced globally (and for the case of the ICR, the Cdp as well)

the following functions all used cached values of the total system and cdp values

getTCR()
getICR()
getCdpCollShares()
getCdpDebt()

the only case where the collateral is indeed updated in a view function is the getDebtAndCollShares() (renamed) function
this acts as-if the local stEthFeeIndex of the Cdp was updated

  • however, this is also potentially incorrect if the global stEth index is not synced to the real stEth index
  • the pending debt, is calculated and I believe incorporated correctly here
    • it is also returned as a separate value (and this value is never used anymore)

this function applying this pending accounting is the only reason NICR order survives some scenarios with the invariant intact

The Solution

@GalloDaSballo put together a separate lens contract that you'd use callStatic with this to simulate and return the value of the values after pending accounting.

However, we need to fix this in order for the reInserts() to be correct
when we compare NICR, it needs to be against what the value would be if updated for each Cdp

Solution Details

  • separate the accounting calculations from the accounting updating storage
  • for debt, we already have getPendingDebt, so this should be simple
function syncGlobalAccounting() {
(returns stuff like new stEthIndex, perUintStaked, error, etc.. all the values that will be updated from the process)  _calcSyncedGlobalAccounting():
  _applyPendingGlobalAccounting(variables to update);
}
function syncAccounting(cdpId) {
([globalVariables])  _calcSyncedGlobalAccounting():
([cdpVariables (indexes, collShares, debt, etc)])  _calcSycnedAccounting(cdpId, [globalVariables]):

  _applyPendingGlobalAccounting([globalVariables]);
  _applyPendingAccounting(cdpId, [globalVariables], [cdpVariables]);
}

and then this should hopefully look the same, but the getAccumulatedFeeSplitApplied should incorporate any global accounting updates that should also happen.

function getDebtAndCollShares(
        bytes32 _cdpId
    ) public view returns (uint256 debt, uint256 coll) {
        debt = Cdps[_cdpId].debt;
        (, uint256 _newColl) = getAccumulatedFeeSplitApplied(_cdpId, systemStEthFeePerUnitIndex);
        coll = _newColl;

        pendingEBTCDebtReward = getPendingRedistributedDebt(_cdpId);

        debt = debt + pendingEBTCDebtReward;
    }

modified functions

getDebtAndCollShares() renamed to getSyncedCdpCollSharesAndDebt()

Net-new functions

With this new ability to calculate the new accounting variables separately from their application, we can just calculate them and return them to get a proper view into what the system really is with it's virtual accounting applied:

getScynedCdpDebt()
getScynedCdpCollShares()
getScynedTCR()
getScynedICR()

PR is here #636