Beanstalk
Beanstalk copied to clipboard
BIP-X: Misc Improvements
BIP-X: Misc. Improvements
Proposer
Beanstalk Farms, Brendan Sanderson, Ben Weintraub
Proposer Wallet: TBD
Summary
- Migrate the Fertilizer metadata hosted at fert.bean.money on-chain;
- When $\Delta B_{\overline{t-1}} < 0$, change Soil issued at
gm
to be the minimum of (1) $-\Delta B$ calculated using the instantaneous reserves from Multi Flow and (2) $-\Delta B_{\overline{t-1}}$; - Implement an Anti λ → λ Convert type that allows any user to decrease a Deposit's BDV if the Recorded BDV (the BDV stored on-chain with the Deposit) is greater than the Current BDV (the number of tokens in the Deposit × the current BDV of the token);
- Change the Chop Rate calculation from the [% recapitalized × % of Sprouts that have become Rinsable] to the [% recapitalized]^2;
- Update the Locked Beans calculation to account for the change to the Chop Rate; and
- Decrease the recapitalization amount upon Chop per BIR-14.
Links
- BIP-X GitHub PR
- GitHub Commit Hash: TBD
- Safe Transaction TBD
Problem
Currently, Fertilizer metadata is currently hosted on centralized infrastructure. This includes the SVG, the traits, etc. Any data hosted on centralized infrastructure requires maintenance and is subject to downtime.
Beanstalk is prone to overissuing Soil at gm
call because Soil issuance below peg is solely based on $-\Delta B_{\overline{t-1}}$.
Currently, the Recorded BDV of a Deposit is not necessarily equal to its Current BDV. For example, if a user Deposits BEANETH into the Silo and the USD price of ETH falls significantly (and thus the BDV of BEANETH decreases), the Recorded BDV does not decrease, i.e., the user “locked in” the higher BDV at the time of Deposit. In practice, this may mean Beanstalk is over crediting BDV to Deposits relative to their value to the system. Beanstalk only supports Convert types that do not decrease the BDV of the Deposit.
Currently, Beanstalk offers a conservative Chop Rate of ~1.03% (22.49% recapitalization * 4.5627% of debt repaid to Fertilizer) to Unripe holders. Although the current model is likely to result in the least volatility as Beanstalk is recapitalized (as a result of Unripe holders Chopping later on average), Beanstalk can be more aggressive given its healthy position in terms of liquidity. Chopping is healthy for Beanstalk as its obligations and the amount needed to fully recapitalize Unripe assets decreases.
Locked Beans are conservatively calculated under the assumption that all Unripe LP is Chopped within a single Season.
Currently, when Unripe LP holders Chop, s.recapitalized
is unchanged as demonstrated in BIR-14. As a result, the Barn Raise ends earlier than intended, i.e., Beanstalk will not sell enough Fertilizer to fully recapitalize all Unripe LP.
Proposed Solution
On-Chain Fert Metadata
We propose to migrate the Fertilizer metadata hosted at fert.bean.money on-chain.
Specification
- Create a new contract called
FertilizerImage.sol
to dynamically and efficiently assemble the SVG image for Active, Used and Available fertilizer; and - Modify
uri
inInternalizer.sol
to (1) assemble the required on-chain data, (2) generate the correct Fertilizer image URI usingimageUri
fromFertilizerImage.sol
and (3) return the final metadata URI to be consumed.
Soil Issuance Update
We propose to change Soil issued at gm
when $\Delta B_{\overline{t-1}} < 0$ to be the minimum of (1) $-\Delta B$ calculated using the instantaneous reserves from Multi Flow and (2) $-\Delta B_{\overline{t-1}}$.
Specification
In SeasonFacet/Sun.sol
:
- Implement
setSoilBelowPeg
, which calculates the cumulative deltaB across all whitelisted Wells using the instantaneous reserves in Multi Flow, compares it to its time weighted counterpart and picks the minimum of those two values; and - Update the P < 1 case in
stepSun
to usesetSoilBelowPeg
.
BDV Decrease
Implement a new ANTI_LAMBDA_LAMBDA
Convert type, callable by anyone, that Converts on behalf of a user and can decrease a Deposit's BDV.
Specification
- Add an additional parameter
account
inLibConvert.convert(…)
; - Add to the return parameters a
decreaseBDV
boolean representing whether the Convert type should decrease BDV or not; - Add the
ANTI_LAMBDA_LAMBDA
Convert case to the convert ladder inLibConvert
; - Reorder the Convert ladder in
LibConvert
so that more frequenly used Converts appear first; - To conform with previous
convertData
types, update them return 0, and add a check that usesmsg.sender
instead ofaccount
when applicable; - In
ConvertFacet.convert()
, replacemsg.sender
in other Convert helper functions withaccount
; - Check if the
ANTI_LAMBDA_LAMBDA
convert is called inConvertFacet.convert()
, and when it is, update the input Deposit with the current BDV; and - Pack all convert properties in a struct called
convertParams
inLibConvert
for code readability and extensibility.
Chop Changes
We propose to:
- Change the Chop Rate calculation from the [% recapitalized × % of Sprouts that have become Rinsable] to the [% recapitalized]^2;
- Update the Locked Beans calculation to account for the change to the Chop Rate; and
- Decrease the recapitalization amount upon Chop per BIR-14.
Specification
Chop rate change:
- Remove
LibUnripe.getRecapPaidPercentAmount()
(the percentage paid back to Fertilizer holders) from the Chop Rate calculation; - Update
LibUnripe.getPenalizedUnderlying()
to calculate the Unripe λ → λ Conversion using the new formula; - Isolate the calculation to get the dollar amount needed for recapitalization to a new function called
LibFertilizer.getTotalRecapDollarsNeeded()
; - Implement
getTotalRecapitalizedPercent()
to get the US dollar percentage recapitalized by Beanstalk; - Update
getLockedBeansUnderlyingUnripeBean()
to account for the percent recapitalized percentage instead of the amount paid back to Fertilizer; - Refactor
LibChop.chop()
to useLibUnripe.removeUnderlying()
instead ofLibUnripe.decrementUnderlying()
when decreasing the available Ripe underlying amount for the Unripe token after a Chop.
Technical Rationale
The Fertilizer Facet must be updated due to changes to the ERC-1155 token metadata. Hosting the metadata on-chain instead of on centralized infrastructure eliminates any risks associated with uptime.
The Unripe Facet must be updated due to changes to the chop
function.
The Convert Facet must be updated due to the introduction of ANTI_LAMBDA_LAMBDA
.
The Season Facet must be updated due to changes to the deltaB calculation introduced by the Soil issuance change below peg.
Economic Rationale
Soil Issuance Update
Consider an example where Beanstalk is at -300k deltaB for the first 58 minutes of a Season. At the 58th minute, i.e., 10 blocks before the next gm
call, a Farmer buys and Sows 200k Beans, bringing the current deltaB to -100k.
Assuming no other trades in the final 2 minutes of the Season, the Soil issued at gm
will be slightly less than 300k, despite Beanstalk only needing 100k Beans to be bought to return to peg. Before Multi Flow, this was necessary for sufficient manipulation resistance.
In general, Beanstalk does not need to be particularly aggressive when issuing Soil—it does not want to issue debt if it doesn't have to.
Thus, using the inter-block MEV manipulation resistant instantaneous reserves in Multi Flow to calculate deltaB below peg is ideal.
BDV Decrease
The ability to decrease a Deposit's BDV is necessary to prevent Beanstalk from over crediting BDV to Deposits relative to their value to the system. There is no incentive for a Farmer to decrease their own BDV. Thus, the Anti λ → λ Convert is callable by any user. There may be sufficient incentive for someone to call Anti λ → λ Convert on a Farmer's Deposit to increase their own Stalk ownership.
Chop Changes
Beanstalk can be more aggressive given its healthy position in terms of liquidity. Chopping is healthy for Beanstalk as its obligations and the amount needed to fully recapitalize Unripe assets decreases.
The Locked Beans calculation must be updated to account for the new Chop Rate calculation.
Ensuring the chop
function is implemented as intended is essential to the structure of the Barn approved by the DAO.
Contract Changes
Initialization Contract
The init
function on the following TBD
contract is called:
Fertilizer Facet
The following FertilizerFacet
is removed from Beanstalk:
The following FertilizerFacet
is added to Beanstalk:
FertilizerFacet
Function Changes
Name | Selector | Action | Type | New Functionality |
---|---|---|---|---|
balanceOfBatchFertilizer |
0x304ec65d |
Replace | View | |
balanceOfFertilized |
0xb6f42085 |
Replace | View | |
balanceOfFertilizer |
0x1799b3b2 |
Replace | View | |
balanceOfUnfertilized |
0x1edb6be1 |
Replace | View | |
beansPerFertilizer |
0x9bb4e35a |
Replace | View | |
getActiveFertilizer |
0xdc6ba285 |
Replace | View | |
getBarnRaiseWell |
TBD |
Replace | View | |
getBarnRaiseToken |
TBD |
Replace | View | |
getCurrentHumidity |
0x39448802 |
Replace | View | |
getEndBpf |
0xc85951a1 |
Replace | View | |
getFertilizer |
0x9c45a1d5 |
Replace | View | |
getFertilizers |
0x34af5416 |
Replace | View | |
getFirst |
0x1e223143 |
Replace | View | |
getHumidity |
0x29130a66 |
Replace | View | |
getLast |
0x4d622831 |
Replace | View | |
getMintFertilizerOut |
0x69744dd0 |
Replace | View | |
getNext |
0xf4a057e2 |
Replace | View | |
getTotalRecapDollarsNeeded |
TBD |
Add | View | ✓ |
isFertilizing |
0x6ae1c014 |
Replace | View | |
remainingRecapitalization |
0x4a16607c |
Replace | View | |
totalFertilizedBeans |
0x4f9a9678 |
Replace | View | |
totalFertilizerBeans |
0xf9c4ebde |
Replace | View | |
totalUnfertilizedBeans |
0xa3ef48c9 |
Replace | View | |
beginBarnRaiseMigration |
TBD |
Replace | Call | |
claimFertilized |
0x83e08888 |
Replace | Call | |
mintFertilizer |
0xbb02e10b |
Replace | Call | |
payFertilizer |
0xd47aee59 |
Replace | Call |
Unripe Facet
The following UnripeFacet
is removed from Beanstalk:
The following UnripeFacet
is added to Beanstalk:
UnripeFacet
Function Changes
Name | Selector | Action | Type | New Functionality |
---|---|---|---|---|
_getPenalizedUnderlying |
0xa84643e4 |
Remove | View | |
balanceOfPenalizedUnderlying |
0x1acc0a47 |
Replace | View | |
balanceOfUnderlying |
0x1be655e8 |
Replace | View | |
getLockedBeans |
0x087d78b4 |
Replace | View | |
getLockedBeansFromTwaReserves |
0x7caa025f |
Replace | View | |
getLockedBeansUnderlyingUnripeBean |
0xbfe2f3be |
Replace | View | ✓ |
getLockedBeansUnderlyingUnripeLP |
TBD |
Replace | View | |
getPenalizedUnderlying |
0x6de45df2 |
Replace | View | |
getPenalty |
0x014a8a49 |
Replace | View | |
getPercentPenalty |
0xbb7de478 |
Replace | View | ✓ |
getRecapFundedPercent |
0x43cc4ee0 |
Replace | View | |
getRecapitalized |
TBD |
Add | View | ✓ |
getRecapPaidPercent |
0xab434eb7 |
Replace | View | |
getTotalUnderlying |
0xadef4533 |
Replace | View | |
getUnderlying |
0x9f06b3fa |
Replace | View | |
getUnderlyingPerUnripeToken |
0xb8a04d1b |
Replace | View | |
getUnderlyingToken |
0x691bcc88 |
Replace | View | |
isUnripe |
0xfc6a19df |
Replace | View | |
picked |
0xd3c73ec8 |
Replace | View | |
addMigratedUnderlying |
0x787cee99 |
Replace | Call | |
addUnripeToken |
0xfa345569 |
Replace | Call | |
chop |
0x9a516cad |
Replace | Call | |
pick |
0x13ed3cea |
Replace | Call | |
switchUnderlyingToken |
0xa33fa99f |
Replace | Call |
Convert Facet
The following ConvertFacet
is removed from Beanstalk:
The following ConvertFacet
is added to Beanstalk:
ConvertFacet
Function Changes
Name | Selector | Action | Type | New Functionality |
---|---|---|---|---|
convert |
0xb362a6e8 |
Replace | Call | ✓ |
Season Facet
The following SeasonFacet
is removed from Beanstalk:
The following SeasonFacet
is added to Beanstalk:
SeasonFacet
Function Changes
Name | Selector | Action | Type | New Functionality |
---|---|---|---|---|
seasonTime |
0xca7b7d7b |
Replace | View | |
gm |
0x64ee4b80 |
Replace | Call | ✓ |
sunrise |
0xfc06d2a6 |
Replace | Call |
Beans Minted
None.
Audit
The commit hash of this BIP is TBD.
An audit competition of this upgrade was held via Codehawks using commit hash 662d26f12ee219ee92dc485c06e01a4cb5ee8dfb. The final report can be read here TBD.
Audit remediations were committed and documented in PR #TBD.
Post Audit Changes
The following changes have been made to the BIP code, but have not been audited.
PR #TBD, which does TBD.
Effective
Immediate upon commitment.