[BIP-225] Amendment to [BIP-146] Incentivize 8020 BPT Staking (ve8020)

Authors: Aura Contributors, Balancer Contributors

Background

BIP-146 was introduced to incentivize adoption of the 80/20 model across DeFI. The proposal was approved earlier this year. As noted by Solarcurve, some specifications within BIP-146 were purposefully left as soft requirements to allow for future flexibility. This current proposal, based on extensive feedback from Balancer and Aura Contributors, seeks to finalize those provisions, so that projects adopting the 80/20 model have a working framework to follow during their grant application process.

Specifications

A. BIP-146 suggested the following milestones for grant qualification:

  • 25k BAL
    • TVL exceeds value of 25k BAL by 30x
    • TVL exceeds $4.125M
    • Lifetime total revenue earned exceeds $45.8k
  • 50K BAL
    • TVL exceeds value of 50k BAL by 30x
    • TVL exceeds $8.25M
    • Lifetime total revenue earned exceeds $275k

This proposal increases requirements in BAL terms to make them closer to the revenue added to the system. At a market price of $7.00 USD, this amendment revises the first two milestones to the following, with no changes to the latter two milestones in BIP-146:

  • 25k BAL
    • TVL exceeds value of 50K BAL by 25x
    • TVL exceeds $8.75M
    • Lifetime total revenue earned exceeds $280K
  • 50K BAL
    • TVL exceeds value of 50K BAL by 60x
    • TVL exceeds $21M
    • Lifetime total revenue earned exceeds $630K

B. BIP-146 stated that “All BAL granted through this program must be locked in veBAL and ideally the project will provide the necessary 20% of ETH so that no BAL is sold.”

This proposal amends this provision by requiring projects to provide the necessary ETH against any BAL granted, so that no BAL is indirectly sold.

C. BIP-146 did not provide guidance as to how granted BAL would be managed by grantee. As stated by Fernando, “My biggest fear with the way this proposal is stated is that [BAL granted goes directly to grantee’s possession] and then not much can be done to guarantee its intended use…In other words nothing prevents you from stopping unlocking and then withdrawing the underlying BAL and WETH in a year to your treasury….It’s also possible that both [parties] agree for whatever reason it makes sense for you to stop re-locking, in this case I firmly think you should keep the ETH you added (it will be constantly rebalanced to 20% of the pool so it might be more or less than you added depending on how the pool evolved) and Balancer DAO should keep the BAL.”

This proposal establishes a trustless non-custodial relationship for the granted BAL, accessible by both grantor and grantee. Aura Contributors have developed a VeBalGrant contract with the following specifications to meet this requirement:

  • Project Functions:
    • Increase locked amount in veBAL using BPT balance
    • Increase veBAL lock time
    • Claim fees from distributor
    • Create initial lock for the grant
  • Balancer Functions:
    • Change the active state of the grant should the grantee break rules of the grant or both parties decide to end it, winding down the lock and giving Balancer control over gauge voting
  • Shared Functions:
    • Release veBAL lock when the grant is inactive
    • Redeem BPT position for WETH and BAL when the grant is inactive
    • Withdraw and distribute WETH and BAL balances to project and balancer when inactive
  • Conditionally Shared Functions. If grant state is active they are only callable by the project, once inactive they are only callable by Balancer.
    • Vote for a gauge with specified weight
    • Execute contract calls with restricted access to some

We strongly encourage each party to review the contract code and associated tests thoroughly. The links to the contract and tests can be found below:

Contract Link
Fork Test Link

D. BIP-146 notes “that only TVL and revenue from locked liquidity [i.e. ve8020 pools] will be counted towards the milestones.” Further, Solarcurve states, “We only want BAL emissions going to locked liquidity…If you open this up to include systems where BAL emissions go to unlocked liquidity there’s little reason to have this program imo, since you’re now competing with basically every pool we have earning emissions. The key here is getting a lot of locked liquidity on Balancer that is predominantly paid for by other mechanisms besides BAL emissions.”

This proposal clarifies that protocol owned liquidity owned by a protocol qualifies as “locked liquidity,” and expands the definition of this term for the purposes of this grant to be only those pools used in the ve8020 pool. See the discussion here, for further context.

Voting

This forum post will be open for discussion approximately three days before the Snapshot proposal goes live. We appreciate and encourage an open discussion on the subject. This vote will be a single-choice vote. You may vote “For” or “Against” this proposal, or choose to abstain from the vote. By voting “For” this proposal, you are voting in favor of adopting the amendment to BIP-146 in accordance with the specifications set out in this proposal and assuming that both parties have had sufficient time to peer review the contract.

@McFly, ping me anytime if you have questions.

1 Like

I think these are fine changes overall, though I’d like to present an alternative approach.

Repeal 146 and treat ve8020’s as core pools with regular gauges. This does mean emissions won’t go to lockers but no one is locking tokens for single digit BAL emission APR. It’s likely net TVL of these pools will go up with this approach as we’ll attract farmers & speculators who are bullish on the token but don’t want a long lockup. There is no need to send BAL from treasury - as a core pool, fees earned by the pool will be returned as bribes. This way if the pool is contributing a high amount of protocol revenue like RDNT/WETH is lately it will receive a commensurate amount of emissions via the bribe market.

No need to send BAL from treasury, bribe market gets more bribes, net TVL of the pool will be higher, Aura benefits from the unlocked TVL being deposited there. Sole downside is lockers don’t get their single digit BAL APR.

2 Likes

Hey @Franklin the links to the contract & fork test aren’t working.

Gm, Zefram, here you go:

1 Like

I have taken a look at the VeBalGrant contract, and here are a few comments:

  1. withdrawBalances() does not fairly compensate the project for impermanent loss, making it quite risky for a project to participate in the grant program.
    • Currently, the contract returns min(ethContributed, wethBalance) to the project at the end of the grant program.
    • If BAL’s price goes up (against ETH), the project doesn’t benefit, since the ETH returned to the project is at most how much it originally put in, which is fine. However, if BAL’s price goes down, the project suffers losses, since it receives less ETH than it originally put in. Therefore, the project suffers downside risk but no upside benefit from LPing, which is probably not the intent of the grants program.
    • In the case where BAL’s price has gone down, the contract should instead return all ETH + an amount of BAL that’s equal in value to ethContributed - wethBalance. The TWAP of BAL can be easily fetched from the BAL BPT contract, which has the built-in TWAP oracle enabled.
  2. In createLock(), it’s extremely likely that there will be WETH/BAL left over after adding liquidity. There’s no point in keeping the leftover tokens in the contract, so at the end of the function, the contract should return the leftover WETH/BAL balance to the project/Balancer.
  3. claimFees() can only be called when the grant program is active, meaning if there are unclaimed fees when the grant program is deactivated, then those fees would be stuck there. To prevent this, claimFees() should be callable regardless of whether the grant program is active, and if the program is inactive, then instead of adding BAL & ETH to LP and increasing the lock, the contract should simply transfer the claimed tokens out like in the else branch.
  4. Currently, it’s possible to deactivate the grant program while the veBAL lock is active, which doesn’t quite make sense since deactivation before the lock expiry just forces the funds to be locked up for no reason. Therefore, deactivating the grant program should be restricted to after the existing lock has expired. To prevent the project from evading deactivation by increasing the lock time in perpetuity, Balancer should have the additional ability to disable increasing the lock time.
  5. execute() allows calls to the Balancer vault regardless of whether the grant program is active, which means the project & Balancer can add/withdraw liquidity or swap tokens at any time. It’s probably harmless, but I just wanted to double check if it’s desired behavior or a bug.
3 Likes

Thanks, brother, these are great comments. I’ll forward them to @phijifry and Heph–we’ll get back to you shortly.

1 Like

Hi @boredGenius! I appreciate your feedback:

  1. Thanks for bringing this up, it’s a fair point. I’m looking forward to hearing Balancer’s perspective on this.
  2. No worries, createLock uses EXACT_TOKENS_IN_FOR_BPT_OUT, so there won’t be any tokens remaining.
  3. Good catch! We’ll update the modifier to be onlyCurrentParty.
  4. That’s intentional - “deactivate” is meant to do just that. The initial thinking is that once deactivated is called that is the “end” of the grant program. I can see the reason why Balancer might want to have more flexibility here like you are suggesting. I would look forward to hearing their comments on this.
  5. Great idea, we can include the vault as a blacklisted address to execute.

Thanks again for your input! Let me know if there is anything else :vulcan_salute:

3 Likes

Thanks for your points @boredGenius and your reply @phijifry.

Let me comment on 1) and 4) as per your request phijifry:

    1. I’d change it. I agree with @boredGenius and think the risks should be the same for both Balancer and the project which is not the current state of the code. IMO Balancer should only get all the BAL and the project all the WETH, regardless of how the price ratio BAL/ETH moved over time. This will ensure that Balancer will always get back 80% (and the project 20%) of the value when the ve balance can be unlocked.
    1. I would keep this as is. IIUC this basically comes down to: who should be allowed to vote on gauges while the lock is being unwound. IMO, if the lock is being unwound this could mean the project has broken the rules of the program and in this case I think the project should not have a full year in control of the gauge votes. If the unwinding is done in a friendly way (because both agreed it was the best outcome) I don’t think Balancer DAO will have any interest in not voting for what the project wants while the lock is being unwound. So not much the project is losing IMO.
2 Likes

Sounds good, agree with you on both points.

2 Likes

We have updated our PR based on the comments that have been discussed. Please see here.

We have also added a bunch of unit tests to accompany the original fork test. Would be great if both teams could review before proceeding. :vulcan_salute::wine_glass:

3 Likes

https://snapshot.org/#/balancer.eth/proposal/0x8215d47c8e5505d32e8a9bbf93bf887f9767b901a4248cb2873679d45ce7a421

2 Likes

Hey, I have went over the updated grant contract, here are some comments:

  • totalEthContributed can be removed I think, it doesn’t seem to serve a purpose in the contract but uses storage.
  • Why do release() and redeem() now use the onlyBalancer modifier? Doesn’t it make more sense to use onlyAuth instead so that both the project and Balancer can execute the withdrawal of funds?
  • In claimFees(), if (_token == address(BAL) || _token == address(WETH)) should instead be if ((_token == address(BAL) || _token == address(WETH)) && active), since if the grant is deactivated it no longer makes sense to increase the lock.

Looks good otherwise!

3 Likes

Hey @boredGenius, thanks for this feedback. A few final notes:

  • Release/redeem are using the onlyBalancer modifier so balancer msig can ensure the pool exit doesn’t get sandwiched.
  • totalEthContributed is just there as a view fn for quick reference
  • This is the intended behaviour of claimFees.

Thanks again for your help reviewing this!

1 Like