From 893c99d21a2d87c96280f66601a6db8900e5b7d1 Mon Sep 17 00:00:00 2001 From: publius Date: Mon, 7 Aug 2023 01:02:46 +0200 Subject: [PATCH] basin + basin integration deploy script --- protocol/contracts/C.sol | 4 +- protocol/package.json | 2 +- protocol/scripts/basin.js | 158 +++++++++++++++++++++++++++++++ protocol/scripts/contracts.js | 1 + protocol/scripts/price.js | 15 +++ protocol/test/utils/constants.js | 2 +- protocol/utils/well.js | 20 +++- yarn.lock | 10 +- 8 files changed, 198 insertions(+), 14 deletions(-) create mode 100644 protocol/scripts/basin.js create mode 100644 protocol/scripts/price.js diff --git a/protocol/contracts/C.sol b/protocol/contracts/C.sol index 7dad5db2f6..5dc4603b9d 100644 --- a/protocol/contracts/C.sol +++ b/protocol/contracts/C.sol @@ -78,8 +78,8 @@ library C { //////////////////// Well //////////////////// uint256 internal constant WELL_MINIMUM_BEAN_BALANCE = 1000_000_000; // 1,000 Beans - address constant internal BEANSTALK_PUMP = 0xc4AD29ba4B3c580e6D59105FFf484999997675Ff; - address constant BEAN_ETH_WELL = 0x9bAaB117304f7D6517048e371025dB8f89a8DbE5; + address constant internal BEANSTALK_PUMP = 0xBA510f10E3095B83a0F33aa9ad2544E22570a87C; + address constant BEAN_ETH_WELL = 0x23ba274B6Bc6505bca604940B13325D4E3f869b8; function getSeasonPeriod() internal pure returns (uint256) { return CURRENT_SEASON_PERIOD; diff --git a/protocol/package.json b/protocol/package.json index ab5384d4c2..3dec247c6f 100644 --- a/protocol/package.json +++ b/protocol/package.json @@ -43,7 +43,7 @@ "solidity-coverage": "^0.8.2" }, "dependencies": { - "@beanstalk/wells": "0.3.5", + "@beanstalk/wells": "0.4.0", "@ethereum-waffle/chai": "4.0.10", "@nomicfoundation/hardhat-network-helpers": "^1.0.7", "@openzeppelin/contracts": "^3.4.0", diff --git a/protocol/scripts/basin.js b/protocol/scripts/basin.js new file mode 100644 index 0000000000..0d15e525d4 --- /dev/null +++ b/protocol/scripts/basin.js @@ -0,0 +1,158 @@ +const { BEAN, WETH, BEANSTALK_FARMS, ETH_USD_CHAINLINK_AGGREGATOR, PRICE_DEPLOYER } = require("../test/utils/constants"); +const { toX } = require("../test/utils/helpers"); +const { impersonateSigner, toBN, getBean, impersonateBeanstalkOwner } = require("../utils"); +const { deployWellContractAtNonce, encodeWellImmutableData, getWellContractAt } = require("../utils/well"); +const { bipBasinIntegration } = require("./bips"); +const { deployContract } = require("./contracts"); +const { deployPriceContract } = require("./price"); + +const MULTI_FLOW_PUMP_MAX_PERCENT_INCREASE = '0x3ffb9999999999999999999999999999'; // TODO: Set +const MULTI_FLOW_PUMP_MAX_PERCENT_DECREASE = '0x3ffb745d1745cfdaf20b87765b895188'; // TODO: Set +const MULTI_FLOW_PUMP_CAP_INTERVAL = 12; +const MULTI_FLOW_PUMP_ALPHA = '0x3ffecccccccccccccccccccccccccccc'; // TODO: Set + +const AQUIFER_DEPLOYER = '0xc5890Cc9Db6CEb7c5039337582b3b921863C5CD1'; // TODO: Set +const AQUIFER_DEPLOY_NONCE = 9; // TODO: Set + +const CONSTANT_PRODUCT_2_DEPLOYER = '0xe1132AcbA9E2bFEca5EA71822387538053C5716b'; // TODO: Set +const CONSTANT_PRODUCT_2_DEPLOY_NONCE = 5; // TODO: Set + +const MULTI_FLOW_PUMP_DEPLOYER = '0x350dc53714D1741a86A781A48c8E3ef1664803Dc'; // TODO: Set +const MULTI_FLOW_PUMP_DEPLOY_NONCE = 5; // TODO: Set + +const WELL_IMPLEMENTATION_DEPLOYER = '0x15e6e03ddb9682F3ea6458886c7ceA0e07bbb6d9'; // TODO: Set +const WELL_IMPLEMENTATION_DEPLOY_NONCE = 2; // TODO: Set + +const WELL_DEPLOYER = '0x7eaE23DD0f0d8289d38653BCE11b92F7807eFB64'; // TODO: Set +const WELL_DEPLOY_SALT = '0x0000000000000000000000000000000000000000000000000000000000000001'; // TODO: Set +const WELL_NAME = 'BEAN:WETH Constant Product 2 Well' +const WELL_SYMBOL = 'BEANWETHCP2w' + +const ADD_LIQUIDITY_ADDRESS = BEANSTALK_FARMS; // TODO: Set +const INITIAL_BEAN_LIQUIDITY = '2000000000'; // 1000e6 + +async function deployBasinAndIntegrationBip(mock, bipAccount = undefined, basinAccounts = undefined, priceContractAccount = undefined) { + await deployBasin(mock, basinAccounts); + await deployPriceContract(priceContractAccount); + await bipBasinIntegration(mock, bipAccount); +} + +async function deployBasin(mock = true, accounts = undefined) { + + console.log("Deploying Basin...") + + let account = await getAccount(accounts, 'aquifer', AQUIFER_DEPLOYER); + const aquifer = await deployWellContractAtNonce('Aquifer', AQUIFER_DEPLOY_NONCE, [], account, true); + + account = await getAccount(accounts, 'constantProduct2', CONSTANT_PRODUCT_2_DEPLOYER); + const constantProduct2 = await deployWellContractAtNonce('ConstantProduct2', CONSTANT_PRODUCT_2_DEPLOY_NONCE, [], account, true); + + account = await getAccount(accounts, 'multiFlowPump', MULTI_FLOW_PUMP_DEPLOYER); + let multiFlowPump = await deployWellContractAtNonce('MultiFlowPump', MULTI_FLOW_PUMP_DEPLOY_NONCE, [ + MULTI_FLOW_PUMP_MAX_PERCENT_INCREASE, + MULTI_FLOW_PUMP_MAX_PERCENT_DECREASE, + MULTI_FLOW_PUMP_CAP_INTERVAL, + MULTI_FLOW_PUMP_ALPHA + ], account, true); + + account = await getAccount(accounts, 'wellImplementation', WELL_IMPLEMENTATION_DEPLOYER); + const wellImplementation = await deployWellContractAtNonce('Well', WELL_IMPLEMENTATION_DEPLOY_NONCE, [], account, false); + console.log("Well Implementation Deployed at", wellImplementation.address); + + account = await getAccount(accounts, 'well', WELL_DEPLOYER); + const immutableData = encodeWellImmutableData( + aquifer.address, + [BEAN, WETH], + { target: constantProduct2.address, data: '0x', length: 0 }, + [{ target: multiFlowPump.address, data: '0x', length: 0 }] + ); + + const initData = wellImplementation.interface.encodeFunctionData('init', [WELL_NAME, WELL_SYMBOL]); + + const well = await getWellContractAt( + 'Well', + await aquifer.callStatic.boreWell( + wellImplementation.address, + immutableData, + initData, + WELL_DEPLOY_SALT + ) + ); + + await aquifer.boreWell( + wellImplementation.address, + immutableData, + initData, + WELL_DEPLOY_SALT + ); + + console.log("Bean:Eth Well Deployed at:", well.address); + + console.log(""); + + console.log("Adding Liquidity to Well...") + + account = await getAccount(accounts, 'addLiquidity', ADD_LIQUIDITY_ADDRESS); + + const bean = await getBean(); + const weth = await ethers.getContractAt("IWETH", WETH); + + const ethUsdChainlinkAggregator = await ethers.getContractAt('MockChainlinkAggregator', ETH_USD_CHAINLINK_AGGREGATOR) + const beanEthPrice = (await ethUsdChainlinkAggregator.latestRoundData()).answer; + + console.log("Bean:Eth Price:", beanEthPrice.toString()); + + const amounts = [ + toBN(INITIAL_BEAN_LIQUIDITY), + toBN(INITIAL_BEAN_LIQUIDITY).mul(toX('1', 20)).div(beanEthPrice) + ] + + console.log("Bean Amount:", amounts[0].toString()); + console.log("Eth Amount:", amounts[1].toString()); + + console.log(account.address) + + console.log("Approving.."); + await bean.connect(account).approve(well.address, amounts[0]); + await weth.connect(account).approve(well.address, amounts[1]); + + console.log("Wrapping Eth.."); + await weth.connect(account).deposit({ value: amounts[1] }); + + console.log('Adding Liquidity..') + const lpAmountOut = well.getAddLiquidityOut(amounts); + let txn = await well.connect(account).addLiquidity(amounts, lpAmountOut, account.address, ethers.constants.MaxUint256); + await txn.wait(); + txn = await well.connect(account).addLiquidity([toBN('0'), toBN('0')], '0', account.address, ethers.constants.MaxUint256); + await txn.wait(); + + console.log('') + + const reserves = await well.getReserves(); + console.log("Well Statistics:") + console.log("Bean Reserve:", reserves[0].toString()); + console.log("Eth Reserve:", reserves[1].toString()); + console.log("LP Token Total Supply:", (await well.totalSupply()).toString()); + + console.log('') + + console.log("Pump Statistics:") + const instantaneousReserves = await multiFlowPump.readInstantaneousReserves( + well.address, + "0x" + ); + console.log("Instantaneous Bean Reserve:", instantaneousReserves[0].toString()); + console.log("Instantaneous WETH Reserve:", instantaneousReserves[1].toString()); + + console.log('') +} + +async function getAccount(accounts, key, mockAddress) { + if (accounts == undefined) { + return await impersonateSigner(mockAddress, true); + } + return accounts[key]; +} + +exports.deployBasin = deployBasin; +exports.deployBasinAndIntegrationBip = deployBasinAndIntegrationBip; \ No newline at end of file diff --git a/protocol/scripts/contracts.js b/protocol/scripts/contracts.js index 34e098d0ef..bbeec13c62 100644 --- a/protocol/scripts/contracts.js +++ b/protocol/scripts/contracts.js @@ -26,6 +26,7 @@ async function increaseNonce(account, n = 1) { } } +exports.increaseToNonce = increaseToNonce exports.increaseNonce = increaseNonce exports.deployContract = deploy diff --git a/protocol/scripts/price.js b/protocol/scripts/price.js new file mode 100644 index 0000000000..531b6025a5 --- /dev/null +++ b/protocol/scripts/price.js @@ -0,0 +1,15 @@ +const { PRICE_DEPLOYER } = require("../test/utils/constants"); +const { impersonateSigner } = require("../utils"); + +async function deployPriceContract(account = undefined, verbose = true) { + if (account == undefined) { + account = await impersonateSigner(PRICE_DEPLOYER, true); + } + + const contract = await (await ethers.getContractFactory("BeanstalkPrice", account)).deploy(); + await contract.deployed() + if (verbose) console.log(`Price Contract deployed to: ${contract.address}`) + return contract +} + +exports.deployPriceContract = deployPriceContract; \ No newline at end of file diff --git a/protocol/test/utils/constants.js b/protocol/test/utils/constants.js index 614e48a26b..5e41e48798 100644 --- a/protocol/test/utils/constants.js +++ b/protocol/test/utils/constants.js @@ -46,5 +46,5 @@ module.exports = { DEPOT_DEPLOYER: '0x058a783D98cDBB78d403c6B613C17d6b96f20d06', ETH_USDT_UNISWAP_V3: '0x4e68Ccd3E89f51C3074ca5072bbAC773960dFa36', ETH_USD_CHAINLINK_AGGREGATOR: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419', - BEANSTALK_PUMP: '0xc4AD29ba4B3c580e6D59105FFf484999997675Ff' + BEANSTALK_PUMP: '0xBA510f10E3095B83a0F33aa9ad2544E22570a87C' } diff --git a/protocol/utils/well.js b/protocol/utils/well.js index f2298d146c..8d6fce4b9e 100644 --- a/protocol/utils/well.js +++ b/protocol/utils/well.js @@ -4,15 +4,16 @@ const { to6, to18 } = require('../test/utils/helpers'); const { getBeanstalk } = require('./contracts'); const { mintEth } = require('./mint'); const { impersonateBeanstalkOwner } = require('./signer'); +const { increaseToNonce } = require('../scripts/contracts'); const BASE_STRING = './node_modules/@beanstalk/wells/out'; -async function getWellContractFactory(name) { +async function getWellContractFactory(name, account = undefined) { const contractJson = JSON.parse(await fs.readFileSync(`${BASE_STRING}/${name}.sol/${name}.json`)) return await ethers.getContractFactory( contractJson.abi, contractJson.bytecode.object, - await getWellDeployer() + (account == undefined) ? await getWellDeployer() : account ); } @@ -24,10 +25,16 @@ async function getWellContractAt(name, address) { ); } -async function deployWellContract(name, arguments = []) { - const Contract = await getWellContractFactory(name); +async function deployWellContractAtNonce(name, nonce, arguments = [], account = undefined, verbose = false) { + await increaseToNonce(account, nonce) + return await deployWellContract(name, arguments, account, verbose) +} + +async function deployWellContract(name, arguments = [], account = undefined, verbose = false) { + const Contract = await getWellContractFactory(name, account); const contract = await Contract.deploy(...arguments); await contract.deployed(); + if (verbose) console.log(`${name} deployed at ${contract.address}`) return contract; } @@ -244,4 +251,7 @@ exports.setReserves = setReserves; exports.whitelistWell = whitelistWell; exports.getWellContractAt = getWellContractAt exports.deployMockWell = deployMockWell -exports.deployMockPump = deployMockPump \ No newline at end of file +exports.deployMockPump = deployMockPump +exports.deployWellContract = deployWellContract +exports.deployWellContractAtNonce = deployWellContractAtNonce +exports.encodeWellImmutableData = encodeWellImmutableData \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 8bfed8ff45..4520e9eb86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2286,7 +2286,7 @@ __metadata: version: 0.0.0-use.local resolution: "@beanstalk/protocol@workspace:protocol" dependencies: - "@beanstalk/wells": 0.3.5 + "@beanstalk/wells": 0.4.0 "@ethereum-waffle/chai": 4.0.10 "@nomicfoundation/hardhat-network-helpers": ^1.0.7 "@nomiclabs/hardhat-ethers": ^2.2.1 @@ -2407,10 +2407,10 @@ __metadata: languageName: unknown linkType: soft -"@beanstalk/wells@npm:0.3.5": - version: 0.3.5 - resolution: "@beanstalk/wells@npm:0.3.5" - checksum: cf20f1d8d7243ac41518e3fe9fd89c83bad9393912575fc9db872de5dcc797f706c5f32bef7a6550b103ee88e2c99b22c10e7814399337f6e6c4c0e8302965fc +"@beanstalk/wells@npm:0.4.0": + version: 0.4.0 + resolution: "@beanstalk/wells@npm:0.4.0" + checksum: 5919fb2fd048079be9e69159dc091fdbbda4d9021d5c42e94ff16b1d2c4e977272f57530d88aaa58cfaec56813d3ea012acc21a55273fdd28380c4904619ccb4 languageName: node linkType: hard