YIP-4 Commitment Pool and new DAO

Authors: Florin Avram @florin, Markus @m.laeng
First publication date: 2024/04/29

This proposal replaces the earlier draft: RETRACTED: Migrating to a new YOU Staking Pool contract and a new DAO contract

Summary

YIP-4 aims to transition to a new pool for staking YOU tokens and the preparation to adopt a new DAO. The YOU Staking Pool V3, henceforth referred to as the Commitment Pool, will replace the YOU Staking Pool V2, also known as the Unified Staking Pool. The Commitment Pool represents the initial step in advancing the Youves platform, as outlined in the Strategic Vision blog post.

The Youves vision involves transitioning to a trading-oriented platform where users will have access to additional tools to leverage their collateral. This shift introduces greater rewards and risks for users who engage in long or short directional bets. Consequently, a bailout mechanism is necessary to prevent the accumulation of bad debt on the platform.

The functionality of the Commitment Pool will largely remain the same, allowing YOU stakers to receive rewards based on platform activity, along with the following additional changes:

  • Stakers will receive rewards according to their selected commitment period (a detailed explanation of this will be provided later in the post).
  • A percentage of the rewards will be reserved for bailouts and used to cover accumulating bad debt on the platform. The community will have the opportunity to vote on these bailouts through YIPs.

Rationale

The Commitment Pool aims to reward users who commit to staking YOUs for extended periods by distributing rewards equitably among YOU stakers. Additionally, users committed for longer durations will have greater voting weight in YIP decisions compared to those with shorter commitments.

Users are free to diversify their stakes as desired. For example, they could allocate 50% of their YOU holdings to stakes with the longest cooldown period, 25% to a medium-term cooldown period, and 25% to a short-term cooldown, all based on their liquidity preferences.

Functionality

The Commitment Pool allows users to stake their YOUs, earn rewards based on platform activity, and participate in voting on future platform developments through YIPs, using their stake’s voting power.

Each new stake must be associated with a user-selected cooldown period, representing the minimum time the user agrees to wait before they can withdraw their stake. Withdrawal must be manually initiated by the user.

For example, the Commitment Pool has a maximum cooldown period of four years and a user creates a stake with a two-year cooldown period, they must manually trigger this by calling the enter_cooldown entrypoint. After this call, the user must wait the specified two years before they can withdraw their stake.

Distribution of Rewards

Each stake has a weight calculated based on the selected cooldown period and its state. A stake can be in one of two states:

  1. Fully commited - the stake will receive all the rewards it is entitled to.
  2. In cooldown - the stake will receive only half of the rewards it is entitled to.

The formula to compute a stake’s weight is:
weight = amount * cooldown * state / max_cooldown where state=1 for fully commited stakes and state=1/2 for stakes in cooldown. This results in a linear distribution of rewards according to the selected cooldown period.

For example, a stake of 100 YOUs with a cooldown period half of the maximum will have a weight of 50 if fully committed. If the same stake is in cooldown, its weight will be 25.

Rewards are then distributed based on each stake’s percentage of the total weight in the pool. In a scenario where one stake has a weight of 50 and the sum of all stake weights in the pool is 500, this stake will receive 10% of the rewards, reflecting its 10% share of the total stake weights in the pool.

Voting power

As previously mentioned, stakes can be used to vote on proposals, with voting power distributed in a step logarithmic fashion. This is achieved by dividing the maximum cooldown period into 32 epochs, each lasting 28 days (4 weeks). Each epoch is associated with a specific percentage of voting power, detailed in the voting_scale_map within the contract’s storage. This percentage determines the voting power of a stake based on which epoch it falls into and the amount of YOU tokens it holds and accumulated.

The epoch applicable to a particular stake is calculated using the formula: epoch = cooldown / epoch_length. For instance, a stake with a cooldown period of 16 weeks would fall into epoch = 16 / 4 = 4.

To better understand how the voting power works, consider the following example:

  • A commitment pool with a maximum cooldown period of 896 days, divided into 32 epochs, each 28 days long.
  • A stake consisting of 100 YOUs (deposited amount + received rewards) with a selected cooldown period of 448 days (half of the maximum cooldown period).
  • The epoch into which this stake falls is calculated as: 448 / 28 = 16.
  • Upon reviewing the voting scale map, we find that epoch 16 corresponds to a ratio of (8000, 10000), which is 80%.
  • Therefore, the voting weight of this stake is 80% of 100, equaling 80.

The graph below describes the voting power and reward weight based on the selected cooldown period.

Commit

The commit entrypoint is used by a user to create or update a stake. When committing, the user selects:

  • the amount of YOU tokens to stake,
  • the cooldown period, which can range from 0 to the maximum cooldown period,
  • the stake_id (optional), in case the user wishes to update an existing stake instead of creating a new one.

Enter cooldown

The enter_cooldown entrypoint enables a user to place their stake into cooldown, which is a prerequisite for withdrawal. The user must wait for the designated cooldown period to elapse before they can withdraw their stake.

Note 1: This step is essential for withdrawing the stake and must be manually initiated by the user.

Note 2: A stake in cooldown will have half the weight of an identical stake that is not in cooldown, and consequently, it will receive half of the rewards during cooldown.

Recommit

If a user changes their mind about having a stake in cooldown and would like to gain all the rewards, they can recommit to the pool. The stake will then carry full reward weight again and receive all the rewards to which it is entitled.

Note: After recommitting, the cooldown period is reset to its previous value, and the user will need to enter_cooldown again if they wish to withdraw the stake.

Withdraw

A user can withdraw their stake once the cooldown period has passed. Upon withdrawal, the user will receive back the initially staked amount plus accumulated rewards earned while the stake was in the pool. Once executed, the stake is then removed from the contract storage.

Kickout

The kickout mechanism is necessary to prevent a user from remaining in the pool and collecting rewards indefinitely after their stake’s cooldown period has expired. To implement this feature without unduly penalizing such stakes, we allow a max_withdraw_delay for a stake to be withdrawn. If the cooldown_period + max_withdraw_delay has elapsed, a stake can be kicked out, and the user who kicks out the stake is entitled to a percentage of the rewards accumulated on that stake. This percentage is adjustable and is specified in the kicker_reward_ratio parameter.

For example, let’s assume that the kicker_reward_ratio is 20%. If a stake initially comprising 100 YOUs has accumulated 50 YOUs in rewards while in the pool and the conditions for kicking out the stake are met, the kicker (the user who kicks out the stake) will receive 20% of 50 YOUs = 10 YOUs, while the original owner will receive the remaining 140 YOUs.

Methodology

The transition to the new commitment pool has to be done in multiple steps and it will involve multiple YIPs. This is the first YIP of that series that proposes to change the admin of those contracts which do not support more than one admin and where the current admin is the current DAO KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab to a new DAO. The new DAO contract needs to be deployed in order to accept the new commitment pool as the originator of the stakes.

This YIP will also unlock all stakes of the old Unified Staking Pool KT1UZcNDxTdkn33Xx5HRkqQoZedc3mEs11yV in order to migrate the stakes to the new Commitment Pool.

Once this YIP succeeds, all contracts where the Youves keyholders are admin, will be set to have the new DAO as an admin by the Youves keyholders and the old DAO KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab will be removed from being admin.

For this YIP the following steps will be done:

Step Description Effect Result Status
1. Deployment of Commitment pool A new pool to commit and stake YOU tokens KT1EN…Ao2 :white_check_mark:
2. Deployment of new DAO A DAO contract to support the implementation of the Commitment Pool KT1Cq…QAx :white_check_mark:
3. Deployment of a new reward collector/buy back swapper contract Collects the token and either swaps them to YOU or sends them to the bailout fund :soon:
4. Deployment of a bailout fund contract Holds tokens to pay bad debt accumulated on the platform and will be controlled by the new DAO :soon:
5. Voting on YIP-4 Will unlock the funds on the old Unified Staking Pool and will propose the new DAO as admin where it is necessary A new DAO will come into effect, users can withraw the old stakes and commit to the new pool :soon:
6. Updating additional contracts with the new DAO through multisig Completely remove the old DAO as an admin from almost all Youves contracts (except flat curves) The new DAO will overtake as admin on almost all Youves contracts (except flat curves) :soon:
7. Voting on YIP-5 YIP-5 will set the new DAO as an admin on all remaining Youves contracts The new DAO completely takes over :soon:

Proposal

In this proposal we will have the new DAO prepared to be set as admin on all contracts of the platform.
In the table below you can see what effect this proposal will have on youves contracts.

Contract Name Contract Address Entrypoint called Effect
uUSD/USDt flat curve KT1UJBvm4hv11Uvu6r4c8zE5K2EfmwiRVgsm proposeNewAdmin Set the new DAO as a proposed admin
USDC.e/uUSD flat curve KT1NgbaaYhtXh3MwJoYYxrrKUwG3RX5LYVL6 proposeNewAdmin Set the new DAO as a proposed admin
wUSDC/uUSD flat curve KT1JeWiS8j1kic4PHx7aTnEr9p4xVtJNzk5b proposeNewAdmin Set the new DAO as a proposed admin
uBTC/uUSD flat curve KT1STLQKxiRtAh1e7DZhu1xUTAJ7KLpV9Rru proposeNewAdmin Set the new DAO as a proposed admin
tzBTC/wwBTC flat curve KT1T974a8qau4xP3RAAWPYCZM9xtwU9FLjPS proposeNewAdmin Set the new DAO as a proposed admin
tzBTC/uBTC flat curve KT1XvH5f2ja2jzdDbv6rxPmecZFU7s3obquN proposeNewAdmin Set the new DAO as a proposed admin
wBTC.e/uBTC flat curve KT1CkpDuwCFrnoqTam6upYiPBiFNsSEVbBei proposeNewAdmin Set the new DAO as a proposed admin
kUSD/uUSD flat curve KT1AVbWyM8E7DptyBCu4B5J5B7Nswkq7Skc6 proposeNewAdmin Set the new DAO as a proposed admin
USDtz/uUSD flat curve KT1Xbx9pykNd38zag4yZvnmdSNBknmCETvQV proposeNewAdmin Set the new DAO as a proposed admin
uXTZ/xtz flat curve KT1SPUvH5khHtirTEVeECiKrnh4FFXxWZ6ui proposeNewAdmin Set the new DAO as a proposed admin
uXTZ/xtz legacy flat curve KT1WgguedKZWucrdRKQXaRECEPMZennaVPck proposeNewAdmin Set the new DAO as a proposed admin
uUSD/uXAU flat curve KT1Ad5yJzoiRRdMJPvhJiPJ7Cq8WbJnCS7bg proposeNewAdmin Set the new DAO as a proposed admin
uXTZ/xtz legacy flat curve KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS proposeNewAdmin Set the new DAO as a proposed admin
checker engine KT1LrEJsaTR5vMdwjvASTtFPUbk2wnX3P166 set_admin Sets the new DAO as an admin
Unified staking pool KT1UZcNDxTdkn33Xx5HRkqQoZedc3mEs11yV update_max_release_period Updates the max release period to 1 second

Code

Source code in SmartPy

GitHub repo with the source code

def YIP4(unit):
    sp.set_type(unit, sp.TUnit)
    NEW_YOUVES_DAO = sp.address("KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN")
    sp.result(sp.list([
        execute_propose_flat_swap_administrator(sp.address("KT1UJBvm4hv11Uvu6r4c8zE5K2EfmwiRVgsm"), NEW_YOUVES_DAO), # UUSD/USDT
        execute_propose_flat_swap_administrator(sp.address("KT1NgbaaYhtXh3MwJoYYxrrKUwG3RX5LYVL6"), NEW_YOUVES_DAO), # USDCE/UUSD
        execute_propose_flat_swap_administrator(sp.address("KT1JeWiS8j1kic4PHx7aTnEr9p4xVtJNzk5b"), NEW_YOUVES_DAO), # WUSDC/UUSD
        execute_propose_flat_swap_administrator(sp.address("KT1STLQKxiRtAh1e7DZhu1xUTAJ7KLpV9Rru"), NEW_YOUVES_DAO), # UUSD/UBTC
        execute_propose_flat_swap_administrator(sp.address("KT1T974a8qau4xP3RAAWPYCZM9xtwU9FLjPS"), NEW_YOUVES_DAO), # tzbtc/wwbtc
        execute_propose_flat_swap_administrator(sp.address("KT1XvH5f2ja2jzdDbv6rxPmecZFU7s3obquN"), NEW_YOUVES_DAO), # tzbtc/ubtc
        execute_propose_flat_swap_administrator(sp.address("KT1CkpDuwCFrnoqTam6upYiPBiFNsSEVbBei"), NEW_YOUVES_DAO), # wbtc.e/ubtc
        execute_propose_flat_swap_administrator(sp.address("KT1AVbWyM8E7DptyBCu4B5J5B7Nswkq7Skc6"), NEW_YOUVES_DAO), # kusd/usd
        execute_propose_flat_swap_administrator(sp.address("KT1Xbx9pykNd38zag4yZvnmdSNBknmCETvQV"), NEW_YOUVES_DAO), # usdtz/uusd
        execute_propose_flat_swap_administrator(sp.address("KT1SPUvH5khHtirTEVeECiKrnh4FFXxWZ6ui"), NEW_YOUVES_DAO), # xtz/uxtz v2
        execute_propose_flat_swap_administrator(sp.address("KT1WgguedKZWucrdRKQXaRECEPMZennaVPck"), NEW_YOUVES_DAO), # xxtz/uxtz
        execute_propose_flat_swap_administrator(sp.address("KT1Ad5yJzoiRRdMJPvhJiPJ7Cq8WbJnCS7bg"), NEW_YOUVES_DAO), # uusd/uxau
        execute_propose_flat_swap_administrator(sp.address("KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS"), NEW_YOUVES_DAO), # uxtz/xtz legacy

        execute_set_checker_admin(sp.address("KT1LrEJsaTR5vMdwjvASTtFPUbk2wnX3P166"), NEW_YOUVES_DAO),
        execute_update_max_release_period(sp.address("KT1UZcNDxTdkn33Xx5HRkqQoZedc3mEs11yV"), sp.nat(1)), 
    ]))

Compiled Michelson code

{ DROP; NIL operation; PUSH address "KT1UZcNDxTdkn33Xx5HRkqQoZedc3mEs11yV"; CONTRACT %update_max_release_period nat; IF_NONE { PUSH int 205; FAILWITH } {}; PUSH mutez 0; PUSH nat 1; TRANSFER_TOKENS; CONS; PUSH address "KT1LrEJsaTR5vMdwjvASTtFPUbk2wnX3P166"; CONTRACT %set_admin address; IF_NONE { PUSH int 788; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1Ad5yJzoiRRdMJPvhJiPJ7Cq8WbJnCS7bg"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1WgguedKZWucrdRKQXaRECEPMZennaVPck"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1SPUvH5khHtirTEVeECiKrnh4FFXxWZ6ui"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1Xbx9pykNd38zag4yZvnmdSNBknmCETvQV"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1AVbWyM8E7DptyBCu4B5J5B7Nswkq7Skc6"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1CkpDuwCFrnoqTam6upYiPBiFNsSEVbBei"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1XvH5f2ja2jzdDbv6rxPmecZFU7s3obquN"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1T974a8qau4xP3RAAWPYCZM9xtwU9FLjPS"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1STLQKxiRtAh1e7DZhu1xUTAJ7KLpV9Rru"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1JeWiS8j1kic4PHx7aTnEr9p4xVtJNzk5b"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1NgbaaYhtXh3MwJoYYxrrKUwG3RX5LYVL6"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS; PUSH address "KT1UJBvm4hv11Uvu6r4c8zE5K2EfmwiRVgsm"; CONTRACT %proposeNewAdmin address; IF_NONE { PUSH int 244; FAILWITH } {}; PUSH mutez 0; PUSH address "KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN"; TRANSFER_TOKENS; CONS }

SHA256 Hash of the Michelson code

780addbd201ee98954b2d97d56c56746891aa3fa36d13ed2952fc8a70f1a1f7b

UPDATE: There was a wrong contract mentioned in the text of the proposal. In the text it said KT1Cq…QAx was the new DAO contract, but the link below went to KT1T3BFE..ptJ3NN on tzkt.io, which is the correct DAO.

KT1T3BFEu9WSQyRuV9Fyd7SqTU4rW3ptJ3NN is also the contract mentioned in the lambda which will be executed. The issue was only in the proposal text, not in the involved contracts or lambdas.