BeanstalkFarms/Beanstalk

RFC: BDV Decrease

Closed this issue · 1 comments

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 (#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 in LibConvert.convert(…).
  • To conform with previous convertData types, have them return 0, and have a check that uses msg.sender instead of address.
  • Replace msg.sender in other places with account.
    • 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.
  • 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 in LibConvertData.sol.
  • Add ANTI_LAMBDA_LAMBDA check in LibConvert.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 as LibLamddaConvert.sol.
  • 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.

#802 addresses this issue.