Evolving Past Pure Token Rewards

Evolving Past Pure Token Rewards

We are entering an age of fiscal tightening at the DAO. Rewards are drying up as we batten down the hatches for the winter. Workers are hard at work wrenching closed the spigots and the last drops of chilled YAM slop are dribbling from the mighty Incentivizers.

This slop has kept us nourished, but too often it has made us sick.

As the last sludge drips from the pipes, we look inside and notice that there is another, smaller pipe that has been hidden under the sludge that can be opened both individually or with the main flow. And when we open it, out comes a pure golden YAM puree!

Sweet and pure ambrosia! An unexpected warmth in the cold!

And once Sated on large bowls of pure mashed YAM, without the normal sludge hangover, we realized that we had been doing it wrong all along.

Let the golden YAM puree flow!

Non-Financial Incentives

As we remove the YAM rewards from the ETH/YAM SLP incentivizer, we are limiting the amount of YAM that makes it’s way to the market, but we are also decreasing the financial value of ETH/YAM LP tokens. As we stop the flow of rewards, we should not forget that there is another benefit to the incenitivizers; tokens deposited can be used in governance. You can vote with your deposited $YAM contained in SLP tokens both on snapshot and on-chain. This means we have a secondary incentive avenue: voting power. And this mechanism is a clean and healthy one.

The voting mechanisms in snapshot are quite flexible to allow for experimentation. They can scale voting power without messing with the underlying contract. This is aligned with faster, less binding consensus votes on governance. The voting mechanism for the on chain contracts is less flexible but that’s ok because we don’t want it complicated. We can at least count the baseline amount of YAM in the contract, allowing depositors to vote normally.

:black_nib: **Quick Specification

Same Incentivizer (simple)**
A new snapshot voting strategy can be developed to boost voting power of LP tokens based on community feedback. There would be no change to the way votes are counted for on-chain proposals.

The strategy space is worth exploring more deeply as there is a fair amount of design flexibility that the DAO is not using. Our current strategy simply pulls voting power from the main DAO governance contract. But there is no reason that this should be the default.

Snapshot strategies can add weights to different incentivizers as well as improve the delegation experience (you delegate your vote unless you vote). For example, YAM/ETH LPs who have deposited into the incentivizer could earn voting power for the ETH as well as the YAM (2x voting boost). If that voting power is delegated to someone else then the delegate can vote with it, but if the delegator votes with it, it is removed from the delegate’s total.

More info on snapshot strategies here: https://docs.snapshot.org/strategies/what-is-a-strategy.

With a New Incentivizer
While clearly a more ambitious task, migrating to a new incentivizer would allow the DAO to change the way votes are calculated within the incentivizer and open new options like giving the LP token holders a proportional share of the voting power of the DAO owned liquidity in it, both in snapshot and in on-chain transactions.

While I would not recommend taking this route initially, it speaks to the potential that is possible if we want to get more ambitious.


Taking things a Step Further

Rewarding liquidity providers with added voting power in snapshot votes is the low hanging fruit, But we don’t have to stop there. We could also reward contributors who receive vested YAM (or anyone else who lock their YAM).

If contributors’ YAM payments are deposited into a contributor incentivizer upon payment, they would be able to use the YAM it in governance immediately. There would be an extra step to start the vesting process (withdraw from the incentivizer) but contributors could get added voting power in snapshot governance and 1:1 power in on-chain governance immediately without waiting to vest. when they choose to vest the YAM, they would forego the voting power until the tokens are all vested and claimed (how the current vesting system works). We could provide a choice that contributors can make to either have YAM payments deposited into the contributor incentivizer or directly into a sablier stream.

There is also an option with a receipt token (vYAM) that has different trade-offs.

:black_nib: Quick Specification
Create a vYAM Contract (incentivizer) where you can deposit YAM. The YAM can be re-claimed by calling withdraw, but upon release it goes into a 6 month linear vesting stream created in the transaction.

If we want to use this for compensation, the deposit function would need to allow the input of a separate address that can withdraw from the contract. So if the funds are added by the YAM governance contracts, the msg.sender is not recorded as the party that can withdraw, but instead a second address (the contributor’s) is, and this address is also used to create the sablier stream upon withdrawing.

The same boosts to voting power described in the LP token incentivizer can be applied here, using snapshot strategies.

There is another option where the contract accepts YAM and returns a new token vYAM 1:1. The YAM is deposited and vYAM is minted. The YAM can be re-claimed by redeeming the vYAM in the contract, but upon release it goes into a 6 month linear vesting stream created in the transaction. This is simpler in a way, but it is not how the current YAM incentivizers work (they do internal accounting and don’t return anything) and so the contract would require new deposit logic and also incorporate all the voting logic (probably more complicated in that regard). This is similar to the veCRV model.

A more concrete Specification

I will take a stab here at a more formal specification for how I imagine this would work.

The idea is to build off the vYAM contract mentioned above. This contract is at it’s core an incentivizer contract that accepts X YAM tokens, allows for a separate address that can withdraw, and withdraw is called, it sends a X YAM back to the msg.sender address via a sablier (or other) vesting protocol.

The stake function in the current incentivizer would need to be changed to include another parameter. I have added that parameter here called recipient as a proof of concept (beware that this code if for reference only).

function stake(uint256 amount, address recipient) public {
	// add new deposit to total supply
        _totalSupply = _totalSupply.add(amount);
	// add balance to recipient balance
        uint256 new_bal = _balances[recipient].add(amount);
        _balances[recipent] = new_bal;
	// delegate to recipient
        address delegate = delegates[recipient];
        if (delegate == address(0)) {
          delegates[recipient] = recipient;
          delegate = recipient;
        }
        _moveDelegates(address(0), delegate, amount);
        _writeSupplyCheckpoint();
        // deposit into contract
        yam.safeTransferFrom(msg.sender, address(this), amount);
    }

You can see the original incentivizer code here: https://github.com/yam-finance/yamV3/blob/0f61c94230bf6c44d4d06188a53c45832f84cae7/contracts/incentivizers/YamIncentivizerWithVoting.sol#L709

The Withdraw function would also need to be edited, but not as much since msg.sender is the contributor when they are withdrawing. The final step would be to open a sablier stream instead of sending the tokens directly to the interacting address’ wallet.

function withdraw(uint256 amount) public {
        _totalSupply = _totalSupply.sub(amount);
        uint256 new_bal = _balances[msg.sender].sub(amount);
        _balances[msg.sender] = new_bal;
        _moveDelegates(delegates[msg.sender], address(0), amount);
        _writeSupplyCheckpoint();
        // create sablier stream (
				sablier.createStream(
					msg.sender, 
					amount, 
					address(token), 
					block.timestamp + 900, 
					block.timestamp + 900 + 15778500);
    }

The existing incentivizer calculates voting power based on the percentage of the pool owned by each depositor and most of this code could remain since the account parameter should be the same as the recipient parameter from the stake function.:

    function getCurrentVotes(address account)
        external
        view
        returns (uint256)
    {
        if (!minBlockSet || block.number < minBlockBeforeVoting) {
            return 0;
        }
	// get total votes from incentivizer
        uint256 poolVotes = YAM(address(yam)).getCurrentVotes(address(slp));
	// do checkpoints stuff for account to get the percentage of total pool they own.
        uint32 nCheckpoints = numCheckpoints[account];
        uint256 lpStake = nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].lpStake : 0;
        uint256 percOfVotes = lpStake.mul(BASE).div(_totalSupply);
	// determine how many votes that gets them
        return poolVotes.mul(percOfVotes).div(BASE);
    }

Or course, the variables and whatnot that are specific to the current incentivizer would need to be updated, but you all get the idea. YAM payments could be deposited into this contract and the contributors to whom the payment is given would receive additional voting power using new snapshot strategies.

The Governor contract would need to have this contract added to its incentivizers [] array using the addIncentivizers() function so that the voting power held within would be counted by on-chain governance.

The new snapshot strategies would need to take the voting power from these contracts and the token contract separately so that they could be boosted individually.

Just because we aren’t giving out token rewards any more doesn’t mean we can’t reward our contributors and liquidity providers for their services to the DAO.

Curious to hear your thoughts below.