I believe we need a solution based on following requirements:
- Ability to incentivize existing and new Comets with 2 or more tokens at the same time;
- Seamless transition: users shall not perform any actions to start receiving rewards in additional tokens;
- Do not upgrade existing smart contracts, as @allthecolors mentioned.
- Ability to relaunch incentivization program with the same token (for example: distribute 100K USDC in Q1 2024, then stop distribution and redistribute another 200K USDC in Q3 2024);
- Reusable code: the solution shall be reusable for future EVM Comets and applicable to existing EVM Comets.
Multi-rewards state that flows out after the described requirements
Let’s imitate that 1 accrued = 1 token. Inc = incentivize.
State 1: - accrued +100
- Date X
- Accured 1000
- Claimed 900
- Owned 1000 - 900 = 100
- The user does not claim a reward
State 2: - accrued +100
- Date X1
- Accrued(COMP) 1100
- Claimed(COMP) 900
- Owned 1100 - 900 = 200(COMP)
- Adding new inc reward (USDC)
- Accrued(USDC) 0
- Claimed(USDC) 0
- Owned 0 - 0 = 0 USDC
State 3: - accrued +100
- Date X2
- Accrued(COMP) 1200
- Claimed(COMP) 900
- Owned 1200 - 900 = 300(COMP)
- Accrued(USDC) 100
- Claimed(USDC) 0
- Owned 100 - 0 = 100 USDC
- Stop USDC inc reward
State 4: - accrued +100
- Date X4
- Accrued(COMP) 1300
- Claimed(COMP) 900
- Owned 1300 - 900 = 400(COMP)
- Accrued(USDC) 100
- Claimed(USDC) 0
- Owned 100 - 0 = 100 USDC
- Start a new USDC’ inc reward
- Accrued(USDC’) 0
- Claimed(USDC’) 0
- Owned 0 - 0 = 0 USDC’
State 5: - accrued +100
- Date X4
- Accrued(COMP) 1400
- Claimed(COMP) 900
- Owned 1400 - 900 = 500(COMP)
- Accrued(USDC) 100
- Claimed(USDC) 0
- Owned 100 - 0 = 100 USDC
- Accrued(USDC’) 100
- Claimed(USDC’) 0
- Owned 100 - 0 = 100 USDC’
Finally, claim: 500 COMP, 100 USDC, 100 USDC’
Overall - important not to receive more rewards than should be received and not to lose rewards for finished campaigns.
Challenge
@kevin shared some great ideas here. However this approach affect existing(deployed) smart contracts.
Firstly, I thought about some wrapper over the existing CometRewards.sol. The flow could look like this: User → CometRewardsV2.sol → CometRewards.sol → Comet. All the deployed contracts stayed untouched and new multi-token logic is implemented in CometRewardsV2 which has a similar interface to CometRewards.
However, from my perspective, It is not possible to create such state flow only on the smart contract side. It requires storing all periodical rewards on a contract, which is not possible without some trigger.
Most possible solutions
- Service that automatically triggers a new additional method to set the currently accrued amount for each user into the rewards storage in CometRewardsV2 - e.g. getInMomentRewardAccrued() - so we can store the accrued amount by the moment the campaign starts and finishes (for each user). But that will require indexing all current Comet users and paying for gas for such txs.
- Service that periodically stores a storage snapshot (some own or 3rd party one used for on-chain state forking) and use the timestamp to get the accrued amount at the moment - and integrate such call to the frontend. So when the user tries to claim rewards from the closed pool - UI will pass the accrued amount by the moment of campaign closing.
These are the only options for fulfilling requirements above, including keeping both multiple rewards and preventing rewards losing (or overcompensation) when the campaign is over: service to trigger accrue status update for each user for campaign start and finish (with expanses for backend service and gas payments), or 3rd party indexer for such info fetching (but with ugly frontend integration).
All other cases will require additional actions from users, as for now there is no info in Comet to use to bind to the start/end of the rewards campaign for each user.
Feedback is much appreciated!