Beanstalk
Beanstalk copied to clipboard
RFC: BDV Decrease
RFC: BDV Decrease
Authors
Brean, Ben Weintraub, Brendan Sanderson, Guy, deadmanwalking
Summary
Implement a new 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 that token).
Problem:
Currently, the Recorded BDV of a given Deposit is asynchronous with 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 greater 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.
Solution
Implement a new Convert type ANTI_LAMBDA_LAMBDA
, callable by anyone, that Converts on behalf of a user.
Context
This functionality becomes particularly impactful once Generalized Convert (https://github.com/BeanstalkFarms/Beanstalk/issues/716) is live and a stable pair (for example, BEAN:USDT) is whitelisted in the Silo. For example, if a Depositor “locks in” a high Recorded BDV in a BEANETH Deposit and the USD price of ETH begins dropping, they should be compelled to consider that if they don’t Convert out of BEANETH, their BDV may decrease. This is not something that any Depositor in the system currently has to consider — they’ll be credited with the BDV (and thus, base Stalk) they “locked in”, regardless of how the BDV of the underlying tokens change.
Specification
ConvertFacet.sol
- Add an additional parameter
account
inLibConvert.convert(…)
. - To conform with previous
convertData
types, have them return 0, and have a check that usesmsg.sender
instead of address. - Replace
msg.sender
in other places withaccount
.- Note: This is additionally developed with the Tractor specification in mind; if this is developed after Tractor, we can replace
msg.sender
with the input parameter of_convert
.
- Note: This is additionally developed with the Tractor specification in mind; if this is developed after Tractor, we can replace
- Add to the return parameters a boolean representing whether the Convert type should decrease BDV or not.
Example Implementation
....
address toToken; address fromToken;
uint256 grownStalk; address account;
(toToken, fromToken, toAmount, fromAmount, account, decreaseBDV) = LibConvert.convert(
convertData
);
...
if(account == address(0)) account = msg.sender;
LibSilo._mow(account, fromToken);
LibSilo._mow(account, toToken);
...
uint256 newBdv = LibTokenSilo.beanDenominatedValue(toToken, toAmount);
if(decreaseBDV) {
toBdv = newBdv;
} else {
toBdv = newBdv > fromBdv ? newBdv : fromBdv;
}
Libraries
- Add a new Convert type
ANTI_LAMBDA_LAMBDA
inLibConvertData.sol
. - Add
ANTI_LAMBDA_LAMBDA
check inLibConvert.sol
. - Update return parameters to return account.
- For non
ANTI_LAMBDA_LAMBDA
converts, return 0. - the
ANTI_LAMBDA_LAMBDA
convert can use the same library/function asLibLamddaConvert.sol
.
- For non
- Add to the return parameter a boolean representing whether the Convert type should decrease BDV or not:
Example Implementation
// LibConvert:
...
} else if (kind == LibConvertData.ConvertKind.UNRIPE_TO_RIPE) {
(tokenOut, tokenIn, amountOut, amountIn) = LibChopConvert
.convertUnripeToRipe(convertData);
// DecreaseBDV = false;
// account = address(0);
// new code
} else if (kind == LibConvertData.ConvertKind.ANTI_LAMDA_LAMDA) {
(tokenOut, tokenIn, amountOut, amountIn, account) = LibLambdaConvert
.convert(convertData);
DecreaseBDV = true;
} else {
revert("Convert: Invalid payload");
}
Note: the boolean DecreaseBDV
and address account
are initialized to 0, and thus previous Convert types do not need to be updated.