Proposal #4 - Polygon Staking Rewards Bug Fix ============================================= Summary ------- This proposal describes a bug fix to the new staking program on Polygon, to ensure fair distribution of rewards in accordance with [DAO proposal #3][proposal-3], which was [previously approved by 98.74% of voters][snapshot-3]. [proposal-3]: https://docs.pantherprotocol.io/dao/governance/proposal-3-polygon-extension [snapshot-3]: https://snapshot.org/#/pantherprotocol.eth/proposal/0x969138dfe31faeb2cde3b10fe4e3fe40d3ad571974d1e566b5257229488a937b **The Panther team strongly recommends voting in favor of this proposed fix to anyone who wants the Polygon staking rewards to be distributed fairly as previously approved.** With the fix applied, **stakers will receive the same high APYs which were previously displayed on the staking app.** For example, for the first 30 minutes, APY was over 1,320%, and for the first 6 hours, it was over 290%. It is also important to note that **all staked tokens are completely safe and unaffected.** The bug only affects distribution of *rewards* on Polygon. Nothing on the Ethereum mainnet is affected. Background ---------- The recent deployment of Panther’s staking program on the Polygon network was quickly followed by discovery of an unfortunate bug where the [`MaticRewardPool`][MaticRewardPool] contract incorrectly computes the rewards to vest at any given moment, acting as if no rewards have ever been vested. This is problematic as it causes the contract to accrue rewards at a much higher and faster rate than initially planned, exhausting almost all of the 2 million ZKP pool by Thursday, March 10th. [MaticRewardPool]: https://polygonscan.com/address/0x773d49309c4E9fc2e9254E7250F157D99eFe2d75 Of course this goes against [DAO proposal #3][proposal-3], whereby rewards should vest linearly over 56 days. The bug unfairly denies all ZKP holders the opportunity they should have had to accrue rewards at any time during the 56 day period. As such, the Panther development team is proposing the below fix to ensure rewards are vested and redeemable at the schedule originally approved by the DAO. Participation ------------- Please review the proposed actions detailed below, and vote to accept or reject them. To participate in voting, you need to have [staked $ZKP][how-to-stake] in [Panther's "Traditional" staking solution][staking], and/or had staked $ZKP delegated to you. [how-to-stake]: https://docs.pantherprotocol.io/dao/token/staking/how-to-stake [staking]: https://docs.pantherprotocol.io/dao/token/staking/ As per the existing DAO governance structure, voting power is calculated by snapshot.org taking a snapshot of the total number of ZKP tokens staked (and/or received via delegation) on both Ethereum and Polygon [at the time when the proposal was created][snapshot-voting]. [snapshot-voting]: https://docs.snapshot.org/proposals/vote Proposed actions ---------------- The Panther team proposes a solution rescuing existing rewards, and "upgrading" the existing contracts to correct the bug, with the following actions: 1. Disable the existing `StakeRewardAdviser` contract for the `unstake` action, to prepare for a corrective contract and to ensure that [the previously approved terms of DAO proposal #3][proposal-3-staking] are not violated. 2. Create a fresh vesting pool of 2M ZKP tokens on the Ethereum Mainnet, minted from the total 450M $ZKP allocated for protocol rewards. 3. Bridge the newly minted 2M $ZKP to a new `RewardTreasury` contract on Polygon. 4. Configure `RewardTreasury` to allow its tokens to be spent by a new `StakeRewardController` contract. 5. Replace the existing `StakeRewardAdviser` contract for both `stake` / `unstake` actions with this new `StakeRewardController` contract, which automatically reclaims prematurely vested rewards, and distributes fairly accrued rewards to both existing and future stakers as specified by [the previously approved terms of DAO proposal #3][proposal-3-staking]. There will be a period for the switchover from the old contract to the new one. It ends if / when the proposal is executed, at which point any stakes newly created during this period will lose their accrued rewards. This will *not* affect stakes created before the switchover period commenced. 6. Reinstate display of (corrected) reward figures in the staking app UI. [proposal-3-staking]: https://docs.pantherprotocol.io/dao/governance/proposal-3-polygon-extension/staking Fallback safety mechanisms -------------------------- Since the fix is both time-critical and complex to implement, it may prove impossible to reliably achieve the above via the Reality.eth mechanism used to execute previous proposals. Therefore two fallback actions are proposed, to ensure the safety of the allocated reward tokens: 1. If necessary, add a temporary guard to the DAO multisig which would prevent execution of some or all of the steps above. 2. If necessary, execute some or all of the steps above via signers of the DAO multisig, rather than via Reality.eth, in accordance with point 8 of the [DAO launch proposal][launch], which states: > "To protect, take corrective actions, and minimize the risks > caused by smart contract bugs, etc. This proposal will allow a > set of signers of the DAO multisig to have an overrule power." [launch]: https://docs.pantherprotocol.io/launchdao/voting-proposals/3-launch However, it is considered highly undesirable to invoke this overrule power without first seeking DAO approval via a democratic process. Therefore this proposal solicits the DAO's authorization to implement the above actions utilizing DAO multisig signers rather than an executable proposal, if that should be necessary. Technical details ----------------- ### Smart contracts It is proposed to use the following new smart contracts on the Polygon PoS chain: | Contract | Address | | --------------------- | ------------------------------------------ | | RewardTreasury | 0x20AD9300BdE78a24798b1Ee2e14858E5581585Bc | | StakeRewardController | 0xdCd54b9355F60A7B596D1B7A9Ac10E6477d6f1bb | All other contracts remain as documented in previous proposals. As mentioned in the previous section, due to the time-critical nature of the fix, if any issues are discovered by further auditing during the voting period, it may be necessary to deploy amended versions of the above two contracts, and invoke the fallback mechanisms in order to activate those instead. If so, amendments will be kept to a minimum as much as possible, to preserve the original intention of the above contracts as described below. ### `StakeRewardAdviser` replacement The previous `StakeRewardAdviser`, which is tightly coupled with the buggy `MaticRewardPool` contract, will be replaced by calling the `removeRewardAdviser` function of the existing `RewardMaster` contract, followed by `addRewardAdviser` to configure its replacement. Removal and addition needs to be done for both the `stake` and `unstake` actions. ### New `StakeRewardController` For "old" stakes created before the replacement, this contract returns modified advice with "old" amounts of rewards (shares of the reward pool), but with the address of the `RewardTreasury` contract as the recipient of rewards. This allows reclamation of the incorrectly vested rewards, which it can then use to distribute in the corrected manner. To achieve this, `StakeRewardController` is preprogrammed with sufficient historical data of all previous staking activity to be able to calculate the corrected distribution of previously accrued rewards. For "new" stakes created, it returns advice to `RewardMaster` with zero rewards (zero "shares"), preventing `RewardMaster` from distributing incorrect amounts, and instead assumes responsibility for reward distribution. ### New Polygon Staking Rewards vesting pool `vestingPools::addVestingPools([wallet], [poolParams])` will be called on the existing `VestingPool` contract on the Ethereum Mainnet, where: * `wallet` is the address of the DAO Multisig address on Ethereum (0x505796f5Bc290269D2522cf19135aD7Aa60dfd77). * Final `poolParams` will be: { isPreMinted: true, isAdjustable: true, start: 2022-03-15T00:00:00Z, vestingDays: 1, sAllocation: 2e12, // 2M tokens sUnlocked: 2e12, // 2M tokens vested: 0 } This will result in a `poolId` of 14 (since 0--12 were created during TGE, and 13 in the previous proposal). This new pool is required to serve as a temporary "advance loan" from one part of the protocol to another, since the prematurely vested rewards from the previous 2M pool can only be recovered as the final part of execution of an `unstake` operation, *after* the corrected rewards are distributed by `StakeRewardController` to the account performing the unstaking. Bridging of these 2M tokens will be performed in a similar manner to [DAO proposal #3](proposal-3), except that the final recipient will be the `RewardTreasury` contract instead of the buggy `MaticRewardPool`. [proposal-3]: https://docs.pantherprotocol.io/dao/governance/proposal-3-polygon-extension ### Activation of `StakeRewardController` When other contracts are configured correctly as described above, `StakeRewardController` will be activated, allowing further staking and unstaking with the fully corrected reward calculations. Compensation ------------ The Panther Foundation will compensate for the cost of "gas" on the Ethereum network to any person who executes the Reality.eth transactions which fulfill this proposal, by sending a number of ZKP tokens with the equivalent market value to the Ethereum address(es) from which the transactions were sent. To clarify, this only applies to transactions directly associated with this DAO proposal listed at [https://snapshot.org/#/pantherprotocol.eth](https://snapshot.org/#/pantherprotocol.eth). It does *not* promise any compensation for normal staking / unstaking transactions, or other interactions with the smart contracts. Acceptance Criteria ------------------- In order for "Zodiac Reality Module" (further referred to as the "Module") to execute a transaction, any corresponding proposal must have passed, as reported by Reality.eth. The Reality.eth question should conform to this template (the required template ID is defined by the installed Module): ```json { "title": "Did the Snapshot proposal with the id %s in the PantherProtocol.eth space pass the execution of the array of Module transactions that have the hash 0x%s and does it meet the requirements of the document referenced in the daorequirements record at PantherProtocol.eth? The hash is the keccak of the concatenation of the individual EIP-712 hashes of the Module transactions. If this question was asked before the corresponding Snapshot proposal was resolved, it should ALWAYS be resolved to INVALID!", "lang": "en", "type": "bool", "category": "DAO proposal" } ``` Reality.eth should resolve the question to “yes” only for proposals that: * were initiated as a Snapshot proposal in the PantherProtocol.eth space (at [https://snapshot.org/#/pantherprotocol.eth](https://snapshot.org/#/pantherprotocol.eth)); * had a minimum quorum of 4% of the $ZKP token total supply, returned by the $ZKP smart contract deployed on Ethereum network at the address stated by the `zkpaddress` record at PantherProtocol.eth ([https://app.ens.domains/name/pantherprotocol.eth/details](https://app.ens.domains/name/pantherprotocol.eth/details)), having cast votes to approve execution of the transactions; * had a voting period of at least 3 days; * had no significant service outages or availability issues that could have reasonably restricted $ZKP token holders from casting their votes in the proposal; * have a minimum bond on the Reality question of at least 0.5ETH; * the module transaction hash in the Reality.eth question is the keccak hash of the concatenation of the individual EIP-712 hashes of the module transactions defined in the Snapshot proposal; * the plain description of the transactions, and their intended result, in the proposal is complete and accurate; * do not occur during, in, or as a result of any unauthorized or malicious changes to the PantherProtocol.eth Snapshot space; * were not filtered from the default view in the PantherProtocol.eth Snapshot space during the voting period. Reality.eth should resolve the question to “invalid” if: * the Reality.eth question meets the above requirements but was created prior to the end of the proposal vote period and/or the snapshot block for the vote (i.e. the final results of the vote are not yet known). In all other cases, the Reality.eth question should be resolved to “no”.