Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EBIP-19: Misc Bug Fixes 2 #1148

Merged
merged 13 commits into from
Oct 14, 2024
56 changes: 56 additions & 0 deletions protocol/abi/Beanstalk.json
Original file line number Diff line number Diff line change
Expand Up @@ -5060,6 +5060,49 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
}
],
"name": "getUsedConvertCapacity",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "overallConvertCapacityUsed",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "well",
"type": "address"
},
{
"internalType": "uint256",
"name": "wellConvertCapacityUsed",
"type": "uint256"
}
],
"internalType": "struct ConvertGettersFacet.WellConvertCapacityUsed[]",
"name": "wellConvertCapacityUsed",
"type": "tuple[]"
}
],
"internalType": "struct ConvertGettersFacet.ConvertCapacityUsed",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -10228,6 +10271,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "l2BlockNumber",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "paused",
Expand Down
13 changes: 13 additions & 0 deletions protocol/abi/MockBeanstalk.json
Original file line number Diff line number Diff line change
Expand Up @@ -9566,6 +9566,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "l2BlockNumber",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "paused",
Expand Down
72 changes: 72 additions & 0 deletions protocol/contracts/beanstalk/init/InitMultFlowPumpUpgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
SPDX-License-Identifier: MIT
*/

pragma solidity ^0.8.20;

import {IAquifer} from "contracts/interfaces/basin/IAquifer.sol";
import {IWell, Call, IERC20} from "contracts/interfaces/basin/IWell.sol";
import {LibWhitelistedTokens} from "contracts/libraries/Silo/LibWhitelistedTokens.sol";
import {LibWellDeployer} from "contracts/libraries/Basin/LibWellDeployer.sol";
import {AppStorage} from "contracts/beanstalk/storage/AppStorage.sol";

interface IWellUpgradeable {
function upgradeTo(address implementation) external;
}

/**
* @author Brean
* @title InitMultiFlowPumpUpgrade upgrades the Whitelisted Wells to use the new MultiFlowPump.
**/
contract InitMultiFlowPumpUpgrade {
address internal constant MULTI_FLOW_PUMP_V1_2_1 = 0xBA150002660BbCA20675D1C1535Cd76C98A95b13;
address internal constant U_WELL_IMPLEMENTATION =
address(0xBA510995783111be5301d93CCfD5dE4e3B28e50B);
address internal constant AQUIFER = address(0xBA51AAAa8C2f911AE672e783707Ceb2dA6E97521);
address internal constant CP2_WELL_FUNCTION =
address(0xBA15000450Bf6d48ec50BD6327A9403E401b72b4);
address internal constant BEAN_USDC = address(0xBea00ee04D8289aEd04f92EA122a96dC76A91bd7);
address internal constant BEAN_USDT = address(0xbEA00fF437ca7E8354B174339643B4d1814bED33);

AppStorage internal s;

function init() external {
address[] memory wells = LibWhitelistedTokens.getWhitelistedWellLpTokens();

for (uint256 i; i < wells.length; i++) {
IWell well = IWell(wells[i]);
// fetch the well's immutable and init data
IERC20[] memory tokens = well.tokens();
Call memory wellFunction = well.wellFunction();
Call[] memory pumps = well.pumps();

// replace the pump addresses with the new MultiFlowPump address
pumps[0].target = MULTI_FLOW_PUMP_V1_2_1;

// if the well is not USDC or USDT, set the well function to CP2_WELL_FUNCTION
if (wells[i] != BEAN_USDC && wells[i] != BEAN_USDT) {
wellFunction.target = CP2_WELL_FUNCTION;
}

// encode the immutable and init data
(bytes memory immutableData, bytes memory initData) = LibWellDeployer
.encodeWellDeploymentData(AQUIFER, tokens, wellFunction, pumps);

// deploy the new well:
address minimalProxyWell = IAquifer(AQUIFER).boreWell(
U_WELL_IMPLEMENTATION,
immutableData,
initData,
bytes32("1")
);

// upgrade the well to the new implementation
IWellUpgradeable(wells[i]).upgradeTo(minimalProxyWell);
// call add liquidity to start the pump.
well.sync(address(this), 0);

// delete the well Oracle snapshot.
delete s.sys.wellOracleSnapshots[wells[i]];
}
}
}
45 changes: 43 additions & 2 deletions protocol/contracts/beanstalk/silo/ConvertGettersFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {LibConvert} from "contracts/libraries/Convert/LibConvert.sol";
import {LibWellMinting} from "contracts/libraries/Minting/LibWellMinting.sol";
import {LibDeltaB} from "contracts/libraries/Oracle/LibDeltaB.sol";
import {LibArbitrum} from "contracts/libraries/LibArbitrum.sol";
import {LibWhitelistedTokens} from "contracts/libraries/Silo/LibWhitelistedTokens.sol";

/**
* @author Publius
* @title ConvertGettersFacet contains view functions related to converting Deposited assets.
**/
contract ConvertGettersFacet {
using LibRedundantMath256 for uint256;
struct WellConvertCapacityUsed {
address well;
uint256 wellConvertCapacityUsed;
}

struct ConvertCapacityUsed {
uint256 overallConvertCapacityUsed;
WellConvertCapacityUsed[] wellConvertCapacityUsed;
}

/**
* @notice Returns the maximum amount that can be converted of `tokenIn` to `tokenOut`.
Expand Down Expand Up @@ -93,7 +104,7 @@ contract ConvertGettersFacet {
uint256 _overallCappedDeltaB = LibConvert.abs(LibDeltaB.overallCappedDeltaB());
uint256 overallConvertCapacityUsed = s
.sys
.convertCapacity[block.number]
.convertCapacity[LibArbitrum.blockNumber()]
.overallConvertCapacityUsed;
return
overallConvertCapacityUsed > _overallCappedDeltaB
Expand All @@ -110,10 +121,40 @@ contract ConvertGettersFacet {
AppStorage storage s = LibAppStorage.diamondStorage();
return
LibConvert.abs(LibDeltaB.cappedReservesDeltaB(well)).sub(
s.sys.convertCapacity[block.number].wellConvertCapacityUsed[well]
s.sys.convertCapacity[LibArbitrum.blockNumber()].wellConvertCapacityUsed[well]
);
}

/**
* @notice Returns the used convert capacity information at a specific block number.
* @param blockNumber the block number to get the used convert capacity for
*/
function getUsedConvertCapacity(
uint256 blockNumber
) external view returns (ConvertCapacityUsed memory) {
AppStorage storage s = LibAppStorage.diamondStorage();
address[] memory tokens = LibWhitelistedTokens.getWhitelistedWellLpTokens();
ConvertCapacityUsed memory usedConvertCapacity;
usedConvertCapacity.wellConvertCapacityUsed = new WellConvertCapacityUsed[](tokens.length);
for (uint i; i < tokens.length; i++) {
address well = tokens[i];
uint256 wellConvertCapacityUsed = s
.sys
.convertCapacity[blockNumber]
.wellConvertCapacityUsed[well];

WellConvertCapacityUsed memory wellConvertCapacityUsedStruct;
wellConvertCapacityUsedStruct.well = well;
wellConvertCapacityUsedStruct.wellConvertCapacityUsed = wellConvertCapacityUsed;
usedConvertCapacity.wellConvertCapacityUsed[i] = wellConvertCapacityUsedStruct;
}
usedConvertCapacity.overallConvertCapacityUsed = s
.sys
.convertCapacity[blockNumber]
.overallConvertCapacityUsed;
return usedConvertCapacity;
}

/**
* @notice Calculates the bdv penalized by a convert.
* @dev See {LibConvert.calculateStalkPenalty}.
Expand Down
3 changes: 2 additions & 1 deletion protocol/contracts/beanstalk/sun/SeasonFacet/SeasonFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {Invariable} from "contracts/beanstalk/Invariable.sol";
import {LibTractor} from "contracts/libraries/LibTractor.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {IBean} from "contracts/interfaces/IBean.sol";
import {LibArbitrum} from "contracts/libraries/LibArbitrum.sol";

/**
* @title SeasonFacet
Expand Down Expand Up @@ -102,7 +103,7 @@ contract SeasonFacet is Invariable, Weather {
function stepSeason() private returns (uint32 season) {
s.sys.season.current += 1;
season = s.sys.season.current;
s.sys.season.sunriseBlock = uint64(block.number); // Note: will overflow after 2^64 blocks.
s.sys.season.sunriseBlock = uint64(LibArbitrum.blockNumber()); // Note: will overflow after 2^64 blocks.
emit Sunrise(season);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {LibDeltaB} from "contracts/libraries/Oracle/LibDeltaB.sol";
import {LibFlood} from "contracts/libraries/Silo/LibFlood.sol";
import {BeanstalkERC20} from "contracts/tokens/ERC20/BeanstalkERC20.sol";
import {LibArbitrum} from "contracts/libraries/LibArbitrum.sol";

/**
* @title SeasonGettersFacet
Expand Down Expand Up @@ -297,4 +298,8 @@ contract SeasonGettersFacet {
{
return LibFlood.getWellsByDeltaB();
}

function l2BlockNumber() external view returns (uint256) {
return LibArbitrum.blockNumber();
}
}
16 changes: 16 additions & 0 deletions protocol/contracts/ecosystem/arbitrum/ArbSys.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {LibArbitrum} from "contracts/libraries/LibArbitrum.sol";

/**
* @title ArbSys
* @author Brean
* @notice ArbSys is a precompile for the Arbitrum network that provides the current block number.
*/
contract ArbSys {
function arbBlockNumber() external view returns (uint256) {
return LibArbitrum.blockNumber();
}
}
2 changes: 2 additions & 0 deletions protocol/contracts/interfaces/IMockFBeanstalk.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2166,4 +2166,6 @@ interface IMockFBeanstalk {
function woohoo() external pure returns (uint256);

function wrapEth(uint256 amount, uint8 mode) external payable;

function l2BlockNumber() external view returns (uint256);
}
22 changes: 22 additions & 0 deletions protocol/contracts/interfaces/basin/IWellUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IWell} from "contracts/interfaces/basin/IWell.sol";

/**
* @title IWell is the interface for the Well contract.
*
* In order for a Well to be verified using a permissionless on-chain registry, a Well Implementation should:
* - Not be able to self-destruct (Aquifer's registry would be vulnerable to a metamorphic contract attack)
* - Not be able to change its tokens, Well Function, Pumps and Well Data
*/
interface IWellUpgradeable is IWell {
function init(string memory name, string memory symbol) external;

function initNoWellToken() external;

function upgradeTo(address newImplementation) external;

function upgradeToAndCall(address newImplementation, bytes memory data) external;
}
51 changes: 51 additions & 0 deletions protocol/contracts/libraries/Basin/LibWellDeployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IWell, Call, IERC20} from "contracts/interfaces/basin/IWell.sol";
import {IWellUpgradeable} from "contracts/interfaces/basin/IWellUpgradeable.sol";

/**
* @title LibWellDeployer
* @author Brean
* @notice LibWellDeployer provides helper functions for deploying Wells with Aquifers.
*/
library LibWellDeployer {
/**
* @notice Encode the Well's immutable data.
*/
function encodeWellDeploymentData(
address _aquifer,
IERC20[] memory _tokens,
Call memory _wellFunction,
Call[] memory _pumps
) internal pure returns (bytes memory immutableData, bytes memory initData) {
immutableData = encodeWellImmutableData(_aquifer, _tokens, _wellFunction, _pumps);
initData = abi.encodeWithSelector(IWellUpgradeable.initNoWellToken.selector);
}

function encodeWellImmutableData(
address _aquifer,
IERC20[] memory _tokens,
Call memory _wellFunction,
Call[] memory _pumps
) internal pure returns (bytes memory immutableData) {
immutableData = abi.encodePacked(
_aquifer, // aquifer address
_tokens.length, // number of tokens
_wellFunction.target, // well function address
_wellFunction.data.length, // well function data length
_pumps.length, // number of pumps
_tokens, // tokens array
_wellFunction.data // well function data (bytes)
);
for (uint256 i; i < _pumps.length; ++i) {
immutableData = abi.encodePacked(
immutableData, // previously packed pumps
_pumps[i].target, // pump address
_pumps[i].data.length, // pump data length
_pumps[i].data // pump data (bytes)
);
}
}
}
5 changes: 3 additions & 2 deletions protocol/contracts/libraries/Convert/LibConvert.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {LibTokenSilo} from "contracts/libraries/Silo/LibTokenSilo.sol";
import {GerminationSide} from "contracts/beanstalk/storage/System.sol";
import {LibBytes} from "contracts/libraries/LibBytes.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {LibArbitrum} from "contracts/libraries/LibArbitrum.sol";

/**
* @title LibConvert
Expand Down Expand Up @@ -235,7 +236,7 @@ library LibConvert {
);

// Update penalties in storage.
ConvertCapacity storage convertCap = s.sys.convertCapacity[block.number];
ConvertCapacity storage convertCap = s.sys.convertCapacity[LibArbitrum.blockNumber()];
convertCap.overallConvertCapacityUsed = convertCap.overallConvertCapacityUsed.add(
overallConvertCapacityUsed
);
Expand Down Expand Up @@ -318,7 +319,7 @@ library LibConvert {
) internal view returns (uint256 cumulativePenalty, PenaltyData memory pdCapacity) {
AppStorage storage s = LibAppStorage.diamondStorage();

ConvertCapacity storage convertCap = s.sys.convertCapacity[block.number];
ConvertCapacity storage convertCap = s.sys.convertCapacity[LibArbitrum.blockNumber()];

// first check overall convert capacity, if none remaining then full penalty for amount in direction of peg
if (convertCap.overallConvertCapacityUsed >= overallCappedDeltaB) {
Expand Down
Loading
Loading