diff --git a/protocol/.env-sample b/protocol/.env-sample index 92d10da0f..83883916c 100644 --- a/protocol/.env-sample +++ b/protocol/.env-sample @@ -3,4 +3,4 @@ BLOCK_NUMBER= MAINNET_RPC= ARBITRUM_RPC= ETHERSCAN_KEY= -DIAMOND_DEPLOYER_PRIVATE_KEY= \ No newline at end of file +ETHERSCAN_KEY_ARBITRUM= \ No newline at end of file diff --git a/protocol/contracts/beanstalk/init/reseed/L2/ReseedAccountStatus.sol b/protocol/contracts/beanstalk/init/reseed/L2/ReseedAccountStatus.sol index 08a8c658c..0fbcd5bd7 100644 --- a/protocol/contracts/beanstalk/init/reseed/L2/ReseedAccountStatus.sol +++ b/protocol/contracts/beanstalk/init/reseed/L2/ReseedAccountStatus.sol @@ -27,16 +27,16 @@ contract ReseedAccountStatus { uint128 germinatingStalkEven; } - // emitted when a status is migrated. - event MigratedAccountStatus( + event MigratedAccountTokenStatus( address indexed account, address indexed token, - uint256 stalk, - uint256 roots, uint256 bdv, int96 lastStem ); + // emitted when a status is migrated. + event MigratedAccountStatus(address indexed account, uint256 stalk, uint256 roots); + function init(AccountStatus[] calldata accountStatuses) external { // for each account for (uint i = 0; i < accountStatuses.length; i++) { @@ -51,6 +51,14 @@ contract ReseedAccountStatus { .accts[accountStatuses[i].account] .mowStatuses[accountStatuses[i].tokens[j]] .lastStem = accountStatuses[i].mowStatuses[j].lastStem; + + // emit event on a per account per token basis. + emit MigratedAccountTokenStatus( + accountStatuses[i].account, + accountStatuses[i].tokens[j], + accountStatuses[i].mowStatuses[j].bdv, + accountStatuses[i].mowStatuses[j].lastStem + ); } // set stalk and roots for account. s.accts[accountStatuses[i].account].stalk = accountStatuses[i].stalk; @@ -64,6 +72,13 @@ contract ReseedAccountStatus { s.accts[accountStatuses[i].account].germinatingStalk[ GerminationSide.EVEN ] = accountStatuses[i].germinatingStalkEven; + + // emit event on a per account basis. + emit MigratedAccountStatus( + accountStatuses[i].account, + accountStatuses[i].stalk, + accountStatuses[i].stalk * 1e12 // roots + ); } } } diff --git a/protocol/contracts/beanstalk/init/reseed/L2/ReseedSun.sol b/protocol/contracts/beanstalk/init/reseed/L2/ReseedSun.sol deleted file mode 100644 index d4c21e110..000000000 --- a/protocol/contracts/beanstalk/init/reseed/L2/ReseedSun.sol +++ /dev/null @@ -1,57 +0,0 @@ -/* - SPDX-License-Identifier: MIT -*/ - -pragma solidity ^0.8.20; -pragma experimental ABIEncoderV2; - -import {AppStorage} from "contracts/beanstalk/storage/AppStorage.sol"; -import {LibCases} from "contracts/libraries/LibCases.sol"; -import {C} from "contracts/C.sol"; - -/** - * @author Brean - * @notice ReseedSun re-initializes the Sun. - * @dev Cases are re-initialized. Season is set to L1 state. - */ -contract ReseedSun { - uint256 constant PERIOD = 3600; - uint256 constant TIMESTAMP = 0; - /** - * @notice Emitted when the AverageGrownStalkPerBdvPerSeason Updates. - */ - event UpdateAverageStalkPerBdvPerSeason(uint256 newStalkPerBdvPerSeason); - - /** - * @notice Emitted when the grownStalkToLP changes. - * @param season The current Season - * @param caseId The Weather case, which determines how the BeanToMaxLPGpPerBDVRatio is adjusted. - * @param absChange The absolute change in the BeanToMaxLPGpPerBDVRatio. - * @dev formula: L_n = L_n-1 +/- bL - */ - event BeanToMaxLpGpPerBdvRatioChange(uint256 indexed season, uint256 caseId, int80 absChange); - - AppStorage internal s; - - function init( - uint32 season, - uint32 temperature, - uint128 averageGrownStalkPerBdvPerSeason, - uint128 beanToMaxLpGpPerBdvRatio - ) external { - s.sys.season.current = season; - s.sys.season.period = PERIOD; - s.sys.season.timestamp = TIMESTAMP; - s.sys.weather.temp = temperature; - s.sys.seedGauge.averageGrownStalkPerBdvPerSeason = averageGrownStalkPerBdvPerSeason; - emit BeanToMaxLpGpPerBdvRatioChange( - s.sys.season.current, - type(uint256).max, - int80(int128(beanToMaxLpGpPerBdvRatio)) - ); - - s.sys.seedGauge.beanToMaxLpGpPerBdvRatio = beanToMaxLpGpPerBdvRatio; - emit UpdateAverageStalkPerBdvPerSeason(averageGrownStalkPerBdvPerSeason); - LibCases.setCasesV2(); - } -} diff --git a/protocol/contracts/beanstalk/silo/WhitelistFacet/WhitelistFacet.sol b/protocol/contracts/beanstalk/silo/WhitelistFacet/WhitelistFacet.sol index 64f6481f0..d85f94b54 100644 --- a/protocol/contracts/beanstalk/silo/WhitelistFacet/WhitelistFacet.sol +++ b/protocol/contracts/beanstalk/silo/WhitelistFacet/WhitelistFacet.sol @@ -141,12 +141,12 @@ contract WhitelistFacet is Invariable, WhitelistedTokens, ReentrancyGuard { /** * @notice Updates the Liquidity Weight Implementation for a given Token. */ - function updateLiqudityWeightImplementationForToken( + function updateLiquidityWeightImplementationForToken( address token, Implementation memory impl ) external payable { LibDiamond.enforceIsOwnerOrContract(); - LibWhitelist.updateLiqudityWeightImplementationForToken(token, impl); + LibWhitelist.updateLiquidityWeightImplementationForToken(token, impl); } /** diff --git a/protocol/contracts/interfaces/IMockFBeanstalk.sol b/protocol/contracts/interfaces/IMockFBeanstalk.sol index 953c22927..a35cd1c7e 100644 --- a/protocol/contracts/interfaces/IMockFBeanstalk.sol +++ b/protocol/contracts/interfaces/IMockFBeanstalk.sol @@ -509,7 +509,7 @@ interface IMockFBeanstalk { address indexed token, Implementation gaugePointImplementation ); - event UpdatedLiqudityWeightImplementationForToken( + event UpdatedLiquidityWeightImplementationForToken( address indexed token, Implementation liquidityWeightImplementation ); @@ -2048,7 +2048,7 @@ interface IMockFBeanstalk { Implementation memory impl ) external payable; - function updateLiqudityWeightImplementationForToken( + function updateLiquidityWeightImplementationForToken( address token, Implementation memory impl ) external payable; diff --git a/protocol/contracts/libraries/Convert/LibPipelineConvert.sol b/protocol/contracts/libraries/Convert/LibPipelineConvert.sol index 280c900d6..473e42421 100644 --- a/protocol/contracts/libraries/Convert/LibPipelineConvert.sol +++ b/protocol/contracts/libraries/Convert/LibPipelineConvert.sol @@ -200,10 +200,7 @@ library LibPipelineConvert { pipeData.initialLpSupply ); - require( - pipeData.stalkPenaltyBdv == 0, - "Convert: Penalty would be applied to this convert, use pipeline convert" - ); + require(pipeData.stalkPenaltyBdv == 0, "Convert: Non-zero Stalk Penalty"); } } } diff --git a/protocol/contracts/libraries/Silo/LibWhitelist.sol b/protocol/contracts/libraries/Silo/LibWhitelist.sol index c77eafdf3..e0d0e9062 100644 --- a/protocol/contracts/libraries/Silo/LibWhitelist.sol +++ b/protocol/contracts/libraries/Silo/LibWhitelist.sol @@ -180,7 +180,7 @@ library LibWhitelist { Implementation memory lwImplementation ) internal { updateGaugePointImplementationForToken(token, gpImplementation); - updateLiqudityWeightImplementationForToken(token, lwImplementation); + updateLiquidityWeightImplementationForToken(token, lwImplementation); updateOptimalPercentDepositedBdvForToken(token, optimalPercentDepositedBdv); } @@ -261,7 +261,7 @@ library LibWhitelist { /** * @notice updates the gauge point implementation for a token. */ - function updateLiqudityWeightImplementationForToken( + function updateLiquidityWeightImplementationForToken( address token, Implementation memory lwImplementation ) internal { diff --git a/protocol/hardhat.config.js b/protocol/hardhat.config.js index ef419ebd1..28e35ff9a 100644 --- a/protocol/hardhat.config.js +++ b/protocol/hardhat.config.js @@ -31,7 +31,7 @@ const { INTERNAL_EXTERNAL, INTERNAL_TOLERANT } = require("./test/hardhat/utils/balances.js"); -const { BEANSTALK, PUBLIUS, BEAN_ETH_WELL, BCM } = require("./test/hardhat/utils/constants.js"); +const { BEANSTALK, PUBLIUS, BEAN_ETH_WELL, BCM, L2_BCM } = require("./test/hardhat/utils/constants.js"); const { to6 } = require("./test/hardhat/utils/helpers.js"); //const { replant } = require("./replant/replant.js") const { reseedL2 } = require("./reseed/reseedL2.js"); @@ -120,32 +120,6 @@ task("sunriseArb", async function () { ); }); -task("addReseedFacets", async function () { - let l2bcm = await impersonateSigner("0xDd5b31E73dB1c566Ca09e1F1f74Df34913DaaF69"); - const l2BeanstalkAddress = "0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70"; - let beanstalkDeployer = await impersonateSigner("0xe26367ca850da09a478076481535d7c1c67d62f9"); - await mintEth(l2bcm.address); - await mintEth(beanstalkDeployer.address); - // transfer ownership to the l2bcm. - await upgradeWithNewFacets({ - diamondAddress: l2BeanstalkAddress, - facetNames: ["OwnershipFacet"], - initFacetName: "ReseedTransferOwnership", - initArgs: [l2bcm.address], - bip: false, - verbose: false, - account: beanstalkDeployer, - checkGas: true, - initFacetNameInfo: "ReseedTransferOwnership" - }); - // claim ownership of the l2 beanstalk. - await (await getBeanstalk(l2BeanstalkAddress)).connect(l2bcm).claimOwnership(); - // perform the diamond cut. - await reseed10(l2bcm, l2BeanstalkAddress, false, true); - console.log("-----------------------------------"); - console.log("\nDiamond cut complete: Facets added to L2 Beanstalk."); -}); - task("getTime", async function () { beanstalk = await ethers.getContractAt("SeasonFacet", BEANSTALK); console.log("Current time: ", await this.seasonGetter.time()); @@ -167,7 +141,7 @@ task("reseedL2", async () => { // the account that deploys the new diamond address at nonce 0. let beanstalkDeployer = await impersonateSigner("0xe26367ca850da09a478076481535d7c1c67d62f9"); // the l2 bcm safe account address. - let l2bcm = await impersonateSigner("0xDd5b31E73dB1c566Ca09e1F1f74Df34913DaaF69"); + let l2bcm = await impersonateSigner(L2_BCM); await mintEth(beanstalkDeployer.address); await mintEth(l2bcm.address); await reseedL2({ @@ -533,7 +507,10 @@ module.exports = { } }, etherscan: { - apiKey: process.env.ETHERSCAN_KEY + apiKey: { + arbitrumOne: process.env.ETHERSCAN_KEY_ARBITRUM, + mainnet: process.env.ETHERSCAN_KEY + } }, solidity: { compilers: [ diff --git a/protocol/reseed/reseed10.js b/protocol/reseed/reseed10.js index f850f5a34..214c95335 100644 --- a/protocol/reseed/reseed10.js +++ b/protocol/reseed/reseed10.js @@ -1,13 +1,17 @@ -const { upgradeWithNewFacets } = require("../scripts/diamond.js"); +const { upgradeWithDeployedFacets } = require("../scripts/diamond.js"); const fs = require("fs"); const { retryOperation } = require("../utils/read.js"); /** * @notice reseed9 (final step) adds all facets to beanstalk, and unpauses beanstalk. + * note: All facets will be deployed prior to running the reseed. */ async function reseed10(account, L2Beanstalk, mock, verbose = true) { - // get list of facets to deploy: - let facets = [ + console.log("-----------------------------------"); + console.log("reseed10: add all facets to L2 Beanstalk.\n"); + + // get list of facet names to link + let facetNames = [ "SeasonFacet", // SUN "SeasonGettersFacet", "GaugeGettersFacet", @@ -38,67 +42,50 @@ async function reseed10(account, L2Beanstalk, mock, verbose = true) { "L1RecieverFacet" // MIGRATION ]; - // A list of public libraries that need to be deployed separately. - libraryNames = [ - "LibGauge", - "LibIncentive", - "LibConvert", - "LibLockedUnderlying", - "LibWellMinting", - "LibGerminate", - "LibPipelineConvert", - "LibSilo", - "LibShipping", - "LibFlood", - "LibTokenSilo", - "LibEvaluate", - "LibSiloPermit" + // get list of facet addresses to link + const facetAddresses = [ + "0x552322CD960FFB809d91012CE05d6FBB86BaE290", + "0xdf522AC66735CB506D15236CF35938588f29e34B", + "0x16b6B2Deb4b19DDb664167CF8cBE601DFA9a87e5", + "0x043a11704A9e508a2b03c4Dc38Ae60dEE369EAEC", + "0x837B2DB3ea3092E9452fCB118027aeBA1d9FfbD3", + "0xA89Fbf550A453f0eD9D75DAac706fa41eE7F9A1d", + "0xD14b7AB5fd36C770e3339A94F3763cAeC046DDCc", + "0x51757F6c0A662B4fB57E96a903b199d9D0fCd312", + "0x7eF1D0449dD48189AF968586b2F91c8294ADDC07", + "0x0D6dF5E737EF25913F6f2fA1649D0F9530c83D59", + "0xa7D49dC04ab8530509A03f9B8669ac6Bc026711f", + "0x320AaEBB1a644BEd2B86038eDE49B81072D02be0", + "0xd7a7Ec3B2EC70EdFFfB969f94436908fB53B3B85", + "0x3D5Cd5A7C7312bF005de78B09e125b34165a69Ec", + "0x35f6977D9236C0734520878799598eA0FE692965", + "0x958679Ab3CC0961F4339FaeCcbf36a1d5906cbF5", + "0x6464446d74C27961396A126b2d449aBdDea354cd", + "0xE6f9cE8737fa856e2aEeD2925DB39Fcac25c6513", + "0x47422eEEcd1cE855dcf59eE7EaEb23c6A4666699", + "0xd4A0797D7700bbA801d2DeD34e5d44480D0061Fe", + "0x4D26Caf0778D651922e89c546f09Ae852cc4933a", + "0xcC0f8117B6c0c45C15D4d306Cdb14454263f33Ba", + "0xD61E6F775dE1B0C3aC8A4b2516FEb7A935DC85Bb", + "0x6f252Ecf79aF1bd57c48047a8B109001FFB4c1DB", + "0x0b980ab39F9fDf3226b98Bc32d96EC180fd61687", + "0xD9171D21C414AE676946a60cd226b3EDa5aC3a2A", + "0x7ee24734b97902E6081D702514776416F11F971b", + "0x53106dc7D78dF1EeD36947cf0536d7eCcCa7e0b1" ]; - // A mapping of facet to public library names that will be linked to it. - // MockFacets will be deployed with the same public libraries. - facetLibraries = { - SeasonFacet: [ - "LibGauge", - "LibIncentive", - "LibWellMinting", - "LibGerminate", - "LibShipping", - "LibFlood", - "LibEvaluate" - ], - ConvertFacet: ["LibConvert", "LibPipelineConvert", "LibSilo", "LibTokenSilo"], - PipelineConvertFacet: ["LibPipelineConvert", "LibSilo", "LibTokenSilo"], - UnripeFacet: ["LibLockedUnderlying"], - SeasonGettersFacet: ["LibLockedUnderlying", "LibWellMinting"], - SiloFacet: ["LibSilo", "LibTokenSilo", "LibSiloPermit"], - EnrootFacet: ["LibSilo", "LibTokenSilo"], - ClaimFacet: ["LibSilo", "LibTokenSilo"], - GaugeGettersFacet: ["LibLockedUnderlying"], - L1RecieverFacet: ["LibSilo", "LibTokenSilo"] - }; - - // A mapping of external libraries to external libraries that need to be linked. - // note: if a library depends on another library, the dependency will need to come - // before itself in `libraryNames` - libraryLinks = { - LibEvaluate: ["LibLockedUnderlying"] - }; - - // upgrade beanstalk with all facets. calls `InitReseed` + // link all facets to beanstalk diamond: await retryOperation(async () => { - await upgradeWithNewFacets({ + await upgradeWithDeployedFacets({ diamondAddress: L2Beanstalk, - facetNames: facets, - facetLibraries: facetLibraries, - libraryNames: libraryNames, - linkedLibraries: libraryLinks, - initFacetName: "InitReseed", - initArgs: [], - bip: false, - verbose: verbose, - account: account + facetNames: facetNames, + facetAddresses: facetAddresses, + verbose: true, + account: account, + checkGas: true }); }); + + console.log("\nFacets added to L2 Beanstalk."); } exports.reseed10 = reseed10; diff --git a/protocol/reseed/reseedAddLiquidityAndTransfer.js b/protocol/reseed/reseedAddLiquidityAndTransfer.js index 0ca01a3f0..e3af44daa 100644 --- a/protocol/reseed/reseedAddLiquidityAndTransfer.js +++ b/protocol/reseed/reseedAddLiquidityAndTransfer.js @@ -139,7 +139,7 @@ async function reseedAddLiquidityAndTransfer(account, L2Beanstalk, mock = true, to6("0") // to6("1000000") // BEAN/USDT ]; console.log("-----------------------------------"); - console.log("add liquidity to wells and transfers to l2 beanstalk.\n"); + console.log("Add liquidity to wells and transfer LP tokens to L2 beanstalk.\n"); const beanAddress = "0xBEA0005B8599265D41256905A9B3073D397812E4"; await impersonateToken(beanAddress, 6); const bean = await ethers.getContractAt("MockToken", beanAddress); diff --git a/protocol/reseed/reseedL2.js b/protocol/reseed/reseedL2.js index d7afa2375..f7402ef13 100644 --- a/protocol/reseed/reseedL2.js +++ b/protocol/reseed/reseedL2.js @@ -8,7 +8,6 @@ const { parsePodMarketplace } = require("./dataConverts/convertPodMarketplace.js const { parseGlobals } = require("./dataConverts/convertGlobal.js"); const { parseExternalHolders } = require("./dataConverts/convertExternalHolders.js"); const { parseTokens } = require("./dataConverts/convertTokens.js"); -const { reseedDeployL2Beanstalk } = require("./reseedDeployL2Beanstalk.js"); const { reseed2 } = require("./reseed2.js"); const { reseed3 } = require("./reseed3.js"); const { reseed4 } = require("./reseed4.js"); @@ -23,6 +22,7 @@ const { reseedAddLiquidityAndTransfer } = require("./reseedAddLiquidityAndTransf const fs = require("fs"); const { upgradeWithNewFacets } = require("../scripts/diamond.js"); const { getBeanstalk } = require("../utils/contracts.js"); +const { L2_BEANSTALK } = require("../test/hardhat/utils/constants.js"); let reseeds; async function reseedL2({ @@ -42,7 +42,6 @@ async function reseedL2({ // delete prev gas report if (fs.existsSync("./reseed/data/gas-report.csv")) fs.unlinkSync("./reseed/data/gas-report.csv"); reseeds = [ - reseedDeployL2Beanstalk, // deploy l2 beanstalk diamond reseed2, // reseedbean + deploy wells and fertilizer proxy on l2 reseedGlobal, // reseed global variables reseed3, // reseed field @@ -54,51 +53,31 @@ async function reseedL2({ reseed9, // reseed whitelist reseed10 // add selectors to l2 ]; - let l2BeanstalkAddress; - console.clear(); await printBeanstalk(); for (let i = start; i < reseeds.length; i++) { await printStage(i, end, mock, log); - console.log("L2 Beanstalk:", l2BeanstalkAddress); - - if (i == 0) { - // first step on the l2 is to deploy the L2 beanstalk diamond with predetermined address. - l2BeanstalkAddress = await reseedDeployL2Beanstalk(beanstalkDeployer, log, mock); - continue; - } + console.log("L2 Beanstalk:", L2_BEANSTALK); if (setState == true) { - await reseeds[i](beanstalkDeployer, l2BeanstalkAddress, mock, verbose); + await reseeds[i](beanstalkDeployer, L2_BEANSTALK, mock, verbose); continue; } - if (i == reseeds.length - 2) { - // prior to the last reseed (i.e, adding facets to L2 beanstalk), - // the Beanstalk deployer needs to transfer ownership to the beanstalk owner. - console.log("Transferring ownership to the beanstalk owner."); - await upgradeWithNewFacets({ - diamondAddress: l2BeanstalkAddress, - facetNames: ["OwnershipFacet"], - initFacetName: "ReseedTransferOwnership", - initArgs: [l2owner.address], - bip: false, - verbose: false, - account: beanstalkDeployer, - checkGas: true, - initFacetNameInfo: "ReseedTransferOwnership" - }); - } + // Prior to the last reseed (i.e, adding facets to L2 beanstalk), + // the beanstalk owner needs to accept ownership of beanstalk. + // The ownership facet will already be added to the diamond + // and the deployer will have already proposed the l2 owner as the new owner. if (i == reseeds.length - 1) { // claim ownership of beanstalk: console.log("Claiming ownership of beanstalk."); - await (await getBeanstalk(l2BeanstalkAddress)).connect(l2owner).claimOwnership(); - // initialize beanstalk state add selectors to L2 beanstalk. - await reseed10(l2owner, l2BeanstalkAddress, mock); + await (await getBeanstalk(L2_BEANSTALK)).connect(l2owner).claimOwnership(); + // add selectors to l2 beanstalk from the already deployed facets + await reseed10(l2owner, L2_BEANSTALK, mock); } } // adds liquidity to wells and transfer well LP tokens to l2 beanstalk: - if (addLiquidity) await reseedAddLiquidityAndTransfer(l2owner, l2BeanstalkAddress, true); + if (addLiquidity) await reseedAddLiquidityAndTransfer(l2owner, L2_BEANSTALK, true); console.log("Reseed successful."); } diff --git a/protocol/scripts/diamond.js b/protocol/scripts/diamond.js index 17aa1266c..022751f21 100644 --- a/protocol/scripts/diamond.js +++ b/protocol/scripts/diamond.js @@ -84,12 +84,6 @@ async function deployDiamond({ throw Error(`Requires only 1 map argument. ${arguments.length} arguments used.`); } const diamondFactory = await ethers.getContractFactory("Diamond"); - const diamondCut = []; - if (verbose) { - console.log("--"); - console.log("Setting up diamondCut args"); - console.log("--"); - } let result; if (typeof initDiamond === "string") { const initDiamondName = initDiamond; @@ -409,6 +403,165 @@ async function upgrade({ return result; } +// Deploys a list of facets along with their linked libraries +async function deployFacetsAndLibraries({ + facets, + libraryNames, + facetLibraries, + libraryLinks, + account, + verify = false, + verbose = true +}) { + const deployedLibraries = {}; + const deployedFacets = {}; + + // Helper function to deploy a contract + async function deployContract(name, libraries = {}) { + if (verbose) console.log(`Deploying: ${name}`); + const factory = await ethers.getContractFactory(name, { + libraries: libraries, + signer: account + }); + const contract = await factory.deploy(); + await contract.deployed(); + + if (verify) { + await run("verify", { + address: contract.address, + constructorArguments: [] + }); + } + + const receipt = await contract.deployTransaction.wait(); + if (verbose) console.log(`${name} deployed at ${contract.address}`); + if (verbose) console.log(`${name} deploy gas used: ${receipt.gasUsed.toString()}`); + + return contract; + } + + // Deploy libraries + for (const libName of libraryNames) { + const linkedLibs = {}; + if (libraryLinks[libName]) { + for (const linkLib of libraryLinks[libName]) { + if (!deployedLibraries[linkLib]) { + throw new Error(`Linked library ${linkLib} not deployed yet for ${libName}`); + } + linkedLibs[linkLib] = deployedLibraries[linkLib].address; + } + } + deployedLibraries[libName] = await deployContract(libName, linkedLibs); + } + + // Deploy facets + for (const facetName of facets) { + const facetLibs = {}; + if (facetLibraries[facetName]) { + for (const libName of facetLibraries[facetName]) { + if (!deployedLibraries[libName]) { + throw new Error(`Required library ${libName} not deployed for facet ${facetName}`); + } + facetLibs[libName] = deployedLibraries[libName].address; + } + } + deployedFacets[facetName] = await deployContract(facetName, facetLibs); + } + return { deployedLibraries, deployedFacets }; +} + +// upgrade diamond with already deployed facets +async function upgradeWithDeployedFacets({ + diamondAddress, + facetNames = [], + facetAddresses = [], + selectorsToRemove = [], + selectorsToAdd = {}, + initFacetAddress = ethers.constants.AddressZero, + initArgs = [], + account = null, + verbose = false, +}) { + let totalGasUsed = ethers.BigNumber.from("0"); + let initFacetCallGas = ethers.BigNumber.from("0"); + + if (arguments.length !== 1) { + throw Error(`Requires only 1 map argument. ${arguments.length} arguments used.`); + } + const diamondCutFacet = await ethers.getContractAt("DiamondCutFacet", diamondAddress); + const diamondLoupeFacet = await ethers.getContractAt("DiamondLoupeFacet", diamondAddress); + + const diamondCut = []; + const existingFacets = await diamondLoupeFacet.facets(); + + if (verbose && facetAddresses.length > 0) console.log("\nProcessing Facets"); + + if (selectorsToRemove.length > 0) { + // check if any selectorsToRemove are already gone + for (const selector of selectorsToRemove) { + if (!inFacets(selector, existingFacets)) { + throw Error("Function selector to remove is already gone."); + } + } + diamondCut.push([ethers.constants.AddressZero, FacetCutAction.Remove, selectorsToRemove]); + } + + for (let i = 0; i < facetAddresses.length; i++) { + const facetAddress = facetAddresses[i]; + const facetContract = await ethers.getContractAt(facetNames[i], facetAddress); + const add = []; + const replace = []; + const selectors = + selectorsToAdd[facetAddress] !== undefined + ? selectorsToAdd[facetAddress] + : await getSelectors(facetContract); + + for (const selector of selectors) { + if (!inFacets(selector, existingFacets)) { + add.push(selector); + } else { + replace.push(selector); + } + } + if (add.length > 0) { + diamondCut.push([facetAddress, FacetCutAction.Add, add]); + } + if (replace.length > 0) { + diamondCut.push([facetAddress, FacetCutAction.Replace, replace]); + } + if (verbose) console.log(`Processed ${facetNames[i]} at ${facetAddress}`); + } + + if (verbose) { + console.log("diamondCut arg:"); + console.log(diamondCut); + console.log("------"); + } + + let functionCall = "0x"; + if (initFacetAddress !== ethers.constants.AddressZero) { + const initFacet = await ethers.getContractAt("IDiamondCut", initFacetAddress); + functionCall = await initFacet.interface.encodeFunctionData("init", initArgs); + if (verbose) console.log(`Function call: ${functionCall.toString().substring(0, 100)}`); + } + + let result = await diamondCutFacet + .connect(account) + .diamondCut(diamondCut, initFacetAddress, functionCall); + + const receipt = await result.wait(); + initFacetCallGas = receipt.gasUsed; + totalGasUsed = totalGasUsed.add(receipt.gasUsed); + + if (verbose) { + console.log("------"); + console.log("Upgrade transaction hash: " + result.hash); + console.log(`Diamond Cut Gas Used: ` + strDisplay(receipt.gasUsed)); + console.log("Total gas used: " + strDisplay(totalGasUsed)); + } + return result; +} + async function upgradeWithNewFacets({ diamondAddress, facetNames = [], @@ -652,3 +805,5 @@ exports.deploy = deploy; exports.inFacets = inFacets; exports.upgrade = upgrade; exports.deployDiamond = deployDiamond; +exports.deployFacetsAndLibraries = deployFacetsAndLibraries; +exports.upgradeWithDeployedFacets = upgradeWithDeployedFacets; diff --git a/protocol/test/foundry/sun/Gauge.t.sol b/protocol/test/foundry/sun/Gauge.t.sol index 132e4e301..c6db54e1c 100644 --- a/protocol/test/foundry/sun/Gauge.t.sol +++ b/protocol/test/foundry/sun/Gauge.t.sol @@ -334,7 +334,7 @@ contract GaugeTest is TestHelper { uint256 initialLockedBeans = bs.getLockedBeansUnderlyingUnripeLP(); // add liquidity to unripeLP well. - // Note: {addLiqudityToWell} is not used as sync() is called to manipulate the reserves. + // Note: {addLiquidityToWell} is not used as sync() is called to manipulate the reserves. // Additionally, calling sync() multiple times to update reserves only works for the MockPump and should // not work for the multiFlowPump. diff --git a/protocol/test/hardhat/utils/constants.js b/protocol/test/hardhat/utils/constants.js index 2ce4ae9ee..a2dee0797 100644 --- a/protocol/test/hardhat/utils/constants.js +++ b/protocol/test/hardhat/utils/constants.js @@ -59,7 +59,9 @@ module.exports = { L2_USDC: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", L2_USDT: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + L2_BEANSTALK: "0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70", L2_FERTILIZER: "0xFEFEFE2cfb089aEF0b0578573eF3CFAbC15f1490", + L2_BCM: "0xDd5b31E73dB1c566Ca09e1F1f74Df34913DaaF69", ZERO_BYTES: "0x0000000000000000000000000000000000000000000000000000000000000000" };