Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
The current rewards calculation is snapshot based. With a single snapshot taken each week at ~08:00 UTC on Wednesday. The percentage of the global debt represented by each wallet is recorded and rewards are allocated proportionately. This mechanism presents an attack vector on the system as a free rider could potentially mint just before each snapshot, then burn immediately after, receiving rewards without risk. In practice this has not been a common strategy, though it has been observed. The main reasons for this are that most wallets do not retain sufficient Synths to fully clear their debt before each snapshot making this strategy less effective. In addition there are incentives to keeping sUSD or sETH in the depot and/or Uniswap, due to potential liquidity in the case of the depot or LP rewards for the sETH pool.
However, if there is one pattern we have observed this year it is that any attack vector in the system will eventually be exploited, so rather than accept this latent risk and assume the current friction will not be automated away we have spent time on R&D to close the attack preemptively. This issue will outline a SIP that will change the mechanism for calculating rewards to rely on not only debt at the time of the snapshot but the average debt over the course of the period for each wallet.
To understand how this mechanism works I will first provide an overview of the current debt register.
To calculate rewards on-chain we must compress the information about the debt distribution to a few operations. With thousands of wallets minting and burning each week, storing the state of each wallet and calculating rewards would not be viable on-chain. Instead we use the fact that a mint or burn event has an equal impact on every other wallet in the system. To illustrate this, we will consider a three player game.
At T0 Alice and Bob have 50% of the debt.
The key is that the starting debt is irrelevant for either Alice or Bob, they will both be equally impacted by this change or debt delta. It also holds that no matter how many players are in the game any increase or decrease in the global debt by any player will impact each other player equally.
Once we identify this property of the system we can then compress all mint and burn events debt deltas by tracking the cumulative debt delta, CDD which is the product of each debt delta.
For any wallet we can determine their current debt by storing three values, the initial debt percentage of the global debt they represented, the CDD index number they entered the system at and the CDD index number now. Take the simple case of Alice:
At T0 Alice enters the system as the only player with 100% of the debt.
T1: 100 | 0
Alice was 100% of the debt, and the CDD at T3 is
This now allows us to only store the CDD and the opening debt percentage for each wallet and from this information alone we can determine the debt of every wallet at any given time, specifically at the close of the period for the purpose of calculating rewards.
This calculation also allows us to provide each wallet with an exact amount of debt that must be burned to exit the system at any time without tracking every event for every wallet individually.
When it comes to calculating rewards we take the snapshot for all wallets at the close of the period as if they had requested to exit the system and we then calculate the percentage of the debt each wallet represents and its proportion of the rewards for that period. As mentioned above this is suboptimal as it means that a wallet that has minted since the start of the period will get the same rewards as one that mints in the block immediately before the snapshot.
Increasing the number snapshots does not resolve this, as even with a high number of snapshots a system could be constructed to automate the minting and burning around each snapshot with the only cost being gas and some infrastructure.
To close this attack vector we need to track the debt of each wallet over time throughout the period. But as mentioned above we need to be able to compress this information into a few operations to make the calculation viable on-chain.
We need to record the time interval between each mint and burn in order to capture the impact of the changes to the debt register over time. This is a change to the current system where we discard the previous debt register information if a user mints of burns multiple times within a period, because currently we only care about the last mint/burn event.
The calculations can be found here: https://docs.google.com/spreadsheets/d/12FLqU_q4vn57qm9ZwDyBUjrWZOBDagX00YRTOV5n-DM/edit#gid=0
The table above shows a simple case of three events, in the case of Alice we can determine her average debt position over time with the following formula:
Which can be factored to:
Which allows us to create a new value that we increment with each mint/burn event to capture the impact that mint/burn had on all other wallets and for how long, allowing us to determine their average debt percentage over the period.
We already store the debt register entry where the wallet last minted/burned and the debt percentage at that time. So now by combining this information with the time based CDD value from when they entered and the close of the period we can track all wallets.
The issue is this calculation requires that the entry debt percentage remains static during the period, so if someone mints or burns their starting debt percentage will change. In order to resolve this we need to have a new variable where we can capture the accrued fee pool percentage for a wallet when it mints or burns and then we can begin to track the fee accruals from that point forward. This also handles the case where a wallet joins for the first time or exits the system completely. Because in both cases we simply write the accrued fees to this variable and then wait for their next mint/burn or the close of the fee period whichever comes first.
So at the end of the fee period when a wallet claims fees we first read the accrued fee percentage variable, if this is zero then we calculate the fee percentage by looking at the entry debt percentage and multiplying that by the time based cumulative debt delta to work out the average percentage of the debt pool for that wallet during the fee period.
We now have a system that more fairly distributes rewards but that allows a wallet to exit or enter the debt pool during the fee period and only lose the fees during the time that they have no debt.
Once this proposal has been discussed and validated by the community I will write a SIP and the engineering team will determine the specific implementation within the system.
your analysis is well done and very interesting. However, in my understanding the little inaccuracy of the CDD is not an issue in real life and even has a positive implication.
If in your example Bob loses 6$ instead of gaining 6$ the CDD method gives Alice a 94% average share of the debt instead of the "true average" of 92%.
This means that it can go both ways. Bob has to win with his synths in order to "game the system". But that means he needs to have an active position on the market which in turn means he has to speculate.
There are 2 positive side effects of the CDD calculation method.
Second, because of the first effect, LPs are incentivized to hold sUSD in their wallets instead of other synths, making the whole system more stable.
As long as the system can not technically be exploited, like frontrunning and snapshotting, we can safely assume that LPs are there for the passive returns instead of speculating. (They already have to speculate somewhat because they hold and lock the volatile SNX)
Hi @gloc90 ,