This is the repository for the governance system of Gyroscope.
The Gyroscope governance system is designed to bring many different stakeholder groups into governance. Voting power is split between a number of different voting vaults, which allocate voting power to different stakeholder groups. Furthermore, the quorum, time delay, and other parameters are set depending on the impact of the proposed changes.
The voting power of a user is computed by the VotingPowerAggregator
contract.
This contract loops over all the vaults of the system and sums up the voting power of the user in each vault weighted with the vault's weight.
Each vote has different rules for how voting power is computed.
In most vaults, the voting power can be delegated, which decreases the voting power of the account delegating and increases the voting power of the one delegated.
The following vaults are currently implemented:
FoundingMemberVault
: Every owner of a Gyro founding member (NFT distributed on Ethereum) starts with a prescribed voting power. To claim the voting power, a user must submit a Merkle proof that it owns a founding member NFT by signing a message. The Merkle proof is generated from a snapshot of founding member NFT holders. Governance can later decide to increase the voting power of some users by callingNFTVault.updateMultiplier
CouncillorNFTVault
: This vault is similar to theFoundingMemberVault
but the voting power is assigned when minting aCouncillorNFT
AssociatedDAOVault
: This vault allows governance to arbitrarily assign voting power to any address by callingAssociatedDAOVault.updateDAOAndTotalWeight
. In practice, this will be used to give voting power to other DAOs that are part of the Gyroscope ecosystem.- Locking vaults: The
LPVault
allows a user to lock a given token (such as LP tokens or GYFI) to earn voting power. There can be as manyLPVault
in existence as we decide to support different tokens. An locking vault for LP assets could be incentivised through a liquidity mining scheme implemented in its parentLiquidityMining
contract AggregateLPVault
: This aggregates the voting power across a set of registeredLPVault
s (e.g., all vaults that lock are set up for LP shares). TheLPVault
s are weighted through governance.
The weights of different voting vaults should sum to 1 (representing 100% of total voting power) and change over time according to a schedule set in VotingPowerAggregator
. A schedule starts from initial weights at the starting time and arrives at final weights at the ending time with weights changing linearly over time. A new schedule can be set by governance by calling VotingPowerAggregator.setSchedule
.
Every function that can be called through governance is assigned a tier. A tier contains the following information:
proposalThreshold
: the minimum voting power required to create a proposalquorum
: the quorum to be reached for the proposal to passvoteThreshold
: the minimum ratio offor
votes for the vote to passtimeLockDuration
: the length of the time lockproposalLength
: the length of the proposalactionLevel
: how "impactful" the given action is
Assigning a tier is done using an ITierStrategy
implementation and varies depending on the function called.
The following strategies are implemented:
StaticTierStrategy
: always returns the same tier regardless of the argumentsSimpleThresholdStrategy
: returns a tier based on whether one of the parameters is above a given thresholdSetVaultFeesStrategy
: Same asSimpleThresholdStrategy
but compares two arguments to the thresholdSetSystemParamsStrategy
: Similar toSimpleThresholdStrategy
but compares a several fields of astruct
to multiple thresholdsSetKeyStrategy
: Has a different tier per key argument. This is used for theGyroConfig.setAddress
that has the power to replace parts of the system.
- Proposal creation: A proposal, which is a list of calls to execute, is created by a participant using
GovernanceManager.createProposal
- The tier (containing quorum and other metadata, see
DataTypes.Tier
) is set to the highest tier of any of the calls to execute - The proposer votes are computed and checked against the proposal threshold (part of the tier information)
- If the proposer has enough voting power, the proposal is started
- The tier (containing quorum and other metadata, see
- Voting phase
- Any participant with voting power is allowed to vote "for", "against", or "abstain" using
GovernanceManager.vote
- A participant can change his vote at any time
- Any participant with voting power is allowed to vote "for", "against", or "abstain" using
- Proposal conclusion: a vote can be concluded by anyone using
GovernanceManager.tallyVote
- If the quorum is reached and the vote threshold is reached, the proposal is queued for execution
- If not, the proposal is marked as rejected
- Proposal execution: a proposal can be executed by anyone using
GovernanceManager.executeProposal
once the time lock for the tallied proposal has passed
An emergency recovery mechanism for the governance contract is included as a fallback in case something goes wrong with the governance contracts and they are no longer usable (e.g, if they are bricked because of a smart contract bug or incorrect parameterization change). The emergency recovery mechanism is composed of a backup multisig combined with an optimistic approval mechanism and various safeguards as implemented in EmergencyRecovery
.
The emergency recovery mechanism has the following properties:
- Multisig signers are assigned by governance and can be changed at any time
- The multisig can initiate an upgrade to the governance contract subject to a timelock
- (Optimistic approval) during the timelock, governance can vote to override the upgrade
- Emergency recovery has a sunset built in, which can optionally be extended by governance
On top of the basic voting structure, the governance system includes several checks and balances and safety mechanisms.
A special form of optimistic approval is used to give end users of the protocol (GYD stablecoin holders) power over governance regarding how upgradeable the protocol should be. This takes the form of an alternative 'bounded' form of GYD that can affect governance settings.
As implemented in BoundedERC20WithEMA
, at any time, a user can choose between holding GYD or the bounded wGYD and can freely convert between them. Choosing to hold wGYD signifies a vote for more limited upgradeability of the protocol. When a user converts between GYD and wGYD, a moving average is updated in the wGYD contract. When the moving average exceeds a threshold in addition to the total wGYD supply exceeding another threshold, upgradeability of core Gyroscope contracts through governance becomes more difficult. This takes the form of increased difficulty in action tiering.
The main idea is to let the user market decide when the system should be more upgradeable and when core infrastructure should be considered more settled based on the market choice of whether to adopt GYD or wGYD.
We track the moving average of the share of wGYD to GYD in terms of an irregularly-spaced exponential moving average (EMA) as follows. Index the points in time where the EMA is updated by
Here,
Note that we only track the EMA at the previously updated block, not the current block. This is to prevent manipulation of the EMA by, e.g., using a flash loan. The values
The variables in _updateEMA()
match the variables from the formulas above as follows:
Math | Code |
---|---|
expMovingAverage.value |
|
previousBoundedPctOfSupply.value |
|
expMovingAverage.blockNb |
|
previousBoundedPctOfSupply.blockNb |
|
windowWidth |
An important ability of governance is to be a good steward of the GYD reserve structure, adapting it as the DeFi space changes. This requires safeguards against governance misincentives. This mechanism imposes conditions on cash flows being realized by governance to help keep incentives of governance aligned with the best interest of the longterm system.
This mechanism is implemented in ReserveStewardshipIncentives
in the Protocol
repository as it requires integration with the protocol code.
Governance can initiate an incentive initiative by calling startInitiative
. To start an initiative, it is required that the system has excessive health properties (e.g., that the reserve ratio is above an excess threshold). Specifying an initiative includes specifying a rewardPercentage
.
Once an initiative is active, several health properties of the system are tracked over a long period of time, as performed via _checkpoint
. This includes tracking the average GYD supply and the number of days that reserve health violations are observed over this time period.
At the end of the time period, governance can call completeInitiative
, which verifies whether health properties were achieved over the term of the initiative and, if so, calculates an incentive reward based on rewardPercentage
and the average GYD supply over the term. The size of the reward is limited by a condition on the health of the system that would follow any reward. If rewardPercentage
is too high considering the end health of the system, the reward calculation also imposes a penalty, reducing the size of the end reward.
The end result is intended to be a structure in which incentive rewards are only given to governance after their stewardship has proven successful over a long time period.
This module is a tool available to governance to incentivize a backstop to the protocol. It is implemented in GydRecovery
in the Protocol
repository as it requires integration with the protocol code.
Any user can deposit GYD to the recovery module to backstop the system. A user can initiate a withdrawal of their staked GYD subject to an unstaking period. The contract tracks an adjusted form of balances that accounts for any recovery operations that are performed.
If the reserve ratio falls below a trigger ratio, a burn of GYD in the recovery module is performed. The amount of the burn is the amount, if possible, to bring the system back to a target reserve ratio. A partial burn is when not all GYD in the module is burned and is performed by modifying the adjustmentFactor
affecting adjusted balances. A full burn is when all GYD in the module is burned and is handled separately.
The GYD recovery module is set up with liquidity mining infrastructure. Governance can choose to allocate incentive assets in the form of GYFI tokens to the recovery module and can start or stop the mining of these incentives by participants who have staked GYD in the module.
The environment can be setup using the following steps
- Create a virtual environment with
make init
- Activate the virtual environment with
source .venv/bin/activate
- Install dependencies with
make setup
The tests can then be run using:
brownie test