UNPKG

@mstable/protocol

Version:
356 lines 18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.deployVault = exports.deployFeederPool = exports.deployFasset = void 0; /* eslint-disable no-restricted-syntax */ /* eslint-disable no-await-in-loop */ const constants_1 = require("@utils/constants"); const math_1 = require("@utils/math"); const utils_1 = require("ethers/lib/utils"); const generated_1 = require("types/generated"); const deploy_utils_1 = require("./deploy-utils"); const etherscan_1 = require("./etherscan"); const networkAddressFactory_1 = require("./networkAddressFactory"); const signerFactory_1 = require("./signerFactory"); const deployFasset = async (sender, name, symbol, decimals = 18, initialMint = math_1.BN.from(500000)) => { // Implementation const impl = await deploy_utils_1.deployContract(new generated_1.MockInitializableToken__factory(sender), `MockInitializableToken with name ${name}, symbol ${symbol} and decimals ${decimals}`); // Initialization Data const data = impl.interface.encodeFunctionData("initialize", [name, symbol, decimals, await sender.getAddress(), initialMint]); // Proxy const proxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(sender), "AssetProxy", [impl.address, constants_1.DEAD_ADDRESS, data]); return new generated_1.MockERC20__factory(sender).attach(proxy.address); }; exports.deployFasset = deployFasset; const deployFeederPool = async (signer, feederData, hre) => { const chain = networkAddressFactory_1.getChain(hre); const feederManagerAddress = networkAddressFactory_1.getChainAddress("FeederManager", chain); const feederLogicAddress = networkAddressFactory_1.getChainAddress("FeederLogic", chain); // Invariant Validator const linkedAddress = { "contracts/feeders/FeederLogic.sol:FeederLogic": feederLogicAddress, "contracts/feeders/FeederManager.sol:FeederManager": feederManagerAddress, }; let impl; let fpConstructorArgs; if (feederData.fAssetRedemptionPriceGetter) { // Update fAssetRedemptionPriceGetter price oracle await generated_1.IRedemptionPriceSnap__factory.connect(feederData.fAssetRedemptionPriceGetter, signer).updateSnappedPrice(); fpConstructorArgs = [networkAddressFactory_1.getChainAddress("Nexus", chain), feederData.mAsset.address, feederData.fAssetRedemptionPriceGetter]; impl = await deploy_utils_1.deployContract(new generated_1.NonPeggedFeederPool__factory(linkedAddress, signer), "NonPeggedFeederPool", fpConstructorArgs); } else { fpConstructorArgs = [networkAddressFactory_1.getChainAddress("Nexus", chain), feederData.mAsset.address]; impl = await deploy_utils_1.deployContract(new generated_1.FeederPool__factory(linkedAddress, signer), "FeederPool", fpConstructorArgs); } await etherscan_1.verifyEtherscan(hre, { address: impl.address, constructorArguments: fpConstructorArgs, libraries: { FeederManager: feederManagerAddress, FeederLogic: feederLogicAddress, }, contract: "contracts/feeders/FeederPool.sol:FeederPool", }); // Initialization Data const mAsset = generated_1.Masset__factory.connect(feederData.mAsset.address, signer); const bAssets = await mAsset.getBassets(); const mpAssets = bAssets.personal.map((bAsset) => bAsset.addr); console.log(`mpAssets. count = ${mpAssets.length}, list: `, mpAssets); console.log(`Initializing FeederPool with: ${feederData.name}, ${feederData.symbol}, mAsset ${feederData.mAsset.address}, fAsset ${feederData.fAsset.address}, A: ${feederData.config.a.toString()}, min: ${utils_1.formatEther(feederData.config.limits.min)}, max: ${utils_1.formatEther(feederData.config.limits.max)}`); const initializeData = impl.interface.encodeFunctionData("initialize", [ feederData.name, feederData.symbol, { addr: feederData.mAsset.address, integrator: feederData.mAsset.integrator || constants_1.ZERO_ADDRESS, hasTxFee: false, status: 0, }, { addr: feederData.fAsset.address, integrator: feederData.fAsset.integrator || constants_1.ZERO_ADDRESS, hasTxFee: false, status: 0, }, mpAssets, feederData.config, ]); const feederPoolProxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(signer), "Feeder Pool Proxy", [ impl.address, networkAddressFactory_1.getChainAddress("DelayedProxyAdmin", chain), initializeData, ]); // Create a FeederPool contract pointing to the deployed proxy contract return new generated_1.FeederPool__factory(linkedAddress, signer).attach(feederPoolProxy.address); }; exports.deployFeederPool = deployFeederPool; const deployVault = async (hre, vaultData) => { const signer = await signerFactory_1.getSigner(hre); const chain = networkAddressFactory_1.getChain(hre); const rewardsDistributorAddress = networkAddressFactory_1.getChainAddress("RewardsDistributor", chain); let vault; // eslint-disable-next-line @typescript-eslint/no-explicit-any let constructorArguments; if (vaultData.boosted) { if (vaultData.dualRewardToken) { constructorArguments = [ networkAddressFactory_1.getChainAddress("Nexus", chain), vaultData.stakingToken, networkAddressFactory_1.getChainAddress("BoostDirector", chain), vaultData.priceCoeff, vaultData.boostCoeff, vaultData.rewardToken, vaultData.dualRewardToken, ]; vault = await deploy_utils_1.deployContract(new generated_1.BoostedDualVault__factory(signer), "BoostedDualVault", constructorArguments); } else { constructorArguments = [ networkAddressFactory_1.getChainAddress("Nexus", chain), vaultData.stakingToken, networkAddressFactory_1.getChainAddress("BoostDirector", chain), vaultData.priceCoeff, vaultData.boostCoeff, vaultData.rewardToken, ]; vault = await deploy_utils_1.deployContract(new generated_1.BoostedVault__factory(signer), "BoostedVault", constructorArguments); } } else if (vaultData.dualRewardToken) { constructorArguments = [networkAddressFactory_1.getChainAddress("Nexus", chain), vaultData.stakingToken, vaultData.rewardToken, vaultData.dualRewardToken]; vault = await deploy_utils_1.deployContract(new generated_1.StakingRewardsWithPlatformToken__factory(signer), "StakingRewardsWithPlatformToken", constructorArguments); } else { constructorArguments = [ networkAddressFactory_1.getChainAddress("Nexus", chain), vaultData.stakingToken, networkAddressFactory_1.getChainAddress("BoostDirector", chain), vaultData.priceCoeff, vaultData.boostCoeff, vaultData.rewardToken, ]; vault = await deploy_utils_1.deployContract(new generated_1.StakingRewards__factory(signer), "StakingRewards", constructorArguments); } await etherscan_1.verifyEtherscan(hre, { address: vault.address, constructorArguments, contract: "contracts/rewards/boosted-staking/BoostedDualVault.sol:BoostedDualVault", }); const initializeData = vault.interface.encodeFunctionData("initialize", [rewardsDistributorAddress, vaultData.name, vaultData.symbol]); const proxyAdminAddress = networkAddressFactory_1.getChainAddress("DelayedProxyAdmin", chain); // Proxy const proxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(signer), "AssetProxy for vault", [ vault.address, proxyAdminAddress, initializeData, ]); return vault.attach(proxy.address); }; exports.deployVault = deployVault; // const mint = async (sender: Signer, bAssets: DeployedFasset[], feederData: FeederData) => { // // e.e. $4e18 * 1e18 / 1e18 = 4e18 // // e.g. 4e18 * 1e18 / 5e22 = 8e13 or 0.00008 // const scaledTestQty = simpleToExactAmount(4).mul(simpleToExactAmount(1)).div(feederData.priceCoeff) // // Approve spending // const approvals: BN[] = [] // // eslint-disable-next-line // for (const bAsset of bAssets) { // // eslint-disable-next-line // const dec = await bAsset.contract.decimals() // const approval = dec === 18 ? scaledTestQty : scaledTestQty.div(simpleToExactAmount(1, BN.from(18).sub(dec))) // approvals.push(approval) // // eslint-disable-next-line // const tx = await bAsset.contract.approve(feederData.pool.address, approval) // // eslint-disable-next-line // const receiptApprove = await tx.wait() // console.log( // // eslint-disable-next-line // `Approved FeederPool to transfer ${formatUnits(approval, dec)} ${bAsset.symbol} from ${await sender.getAddress()}. gas used ${ // receiptApprove.gasUsed // }`, // ) // } // // Mint // console.log( // bAssets.map(() => scaledTestQty.toString()), // await Promise.all( // bAssets.map(async (b) => (await b.contract.allowance(await sender.getAddress(), feederData.pool.address)).toString()), // ), // await Promise.all(bAssets.map(async (b) => (await b.contract.balanceOf(await sender.getAddress())).toString())), // bAssets.map((b) => b.address), // (await feederData.pool.getBassets())[0].map((b) => b[0]), // await feederData.pool.mAsset(), // ) // const tx = await feederData.pool.mintMulti( // bAssets.map((b) => b.address), // approvals, // 1, // await sender.getAddress(), // ) // const receiptMint = await tx.wait() // // Log minted amount // const mAssetAmount = formatEther(await feederData.pool.totalSupply()) // console.log( // `Minted ${mAssetAmount} fpToken from ${formatEther(scaledTestQty)} Units for each [mAsset, fAsset]. gas used ${ // receiptMint.gasUsed // }`, // ) // } // const approveFeederWrapper = async ( // sender: Signer, // feederWrapper: FeederWrapper, // feederPools: FeederPool[], // vaults: BoostedVault[], // ): Promise<void> => { // // Get tokens to approve // const len = feederPools.length // // eslint-disable-next-line // for (let i = 0; i < len; i++) { // const [[{ addr: massetAddr }, { addr: fassetAddr }]] = await feederPools[i].getBassets() // const masset = Masset__factory.connect(massetAddr, sender) // const [bassets] = await masset.getBassets() // const assets = [massetAddr, fassetAddr, ...bassets.map(({ addr }) => addr)] // // Make the approval in one tx // const approveTx = await feederWrapper["approve(address,address,address[])"](feederPools[i].address, vaults[i].address, assets) // await logTxDetails(approveTx, "Approved FeederWrapper tokens") // } // } // export const deployBoostedFeederPools = async (deployer: Signer, addresses: CommonAddresses, pairs: Pair[]): Promise<void> => { // // 1. Deploy boostDirector & Libraries // const start = await deployer.getBalance() // console.log(`\n~~~~~ PHASE 1 - LIBS ~~~~~\n\n`) // let director: BoostDirector // if (!addresses.boostDirector && addresses.boostDirector !== ZERO_ADDRESS) { // director = await deployContract(new BoostDirector__factory(deployer), "BoostDirector", [addresses.nexus, addresses.staking]) // const directorInitTx = await director.initialize([]) // await logTxDetails(directorInitTx, "Initializing BoostDirector") // } else { // director = BoostDirector__factory.connect(addresses.boostDirector, deployer) // } // const feederLibs = { // feederManager: addresses.feederManager, // feederLogic: addresses.feederLogic, // } // if (!addresses.feederManager || !addresses.feederLogic) { // const feederManager = await deployContract(new FeederManager__factory(deployer), "FeederManager") // const feederLogic = await deployContract(new FeederLogic__factory(deployer), "FeederLogic") // feederLibs.feederManager = feederManager.address // feederLibs.feederLogic = feederLogic.address // } // // 2.2 For each fAsset // // - fetch fAsset & mAsset // const data: FeederData[] = [] // // eslint-disable-next-line // for (const pair of pairs) { // const mAssetContract = MV2__factory.connect(pair.mAsset.address, deployer) // const fAssetContract = MockERC20__factory.connect(pair.fAsset.address, deployer) // const deployedMasset: DeployedFasset = { // integrator: ZERO_ADDRESS, // txFee: false, // contract: mAssetContract, // address: pair.mAsset.address, // symbol: pair.mAsset.symbol, // } // const deployedFasset: DeployedFasset = { // integrator: ZERO_ADDRESS, // txFee: false, // contract: fAssetContract, // address: pair.fAsset.address, // symbol: pair.fAsset.symbol, // } // data.push({ // ...feederLibs, // nexus: addresses.nexus, // proxyAdmin: addresses.proxyAdmin, // mAsset: deployedMasset, // fAsset: deployedFasset, // aToken: pair.aToken, // name: `${deployedMasset.symbol}/${deployedFasset.symbol} Feeder Pool`, // symbol: `fP${deployedMasset.symbol}/${deployedFasset.symbol}`, // config: { // a: pair.A, // limits: { // min: simpleToExactAmount(10, 16), // max: simpleToExactAmount(90, 16), // }, // }, // vaultName: `${deployedMasset.symbol}/${deployedFasset.symbol} fPool Vault`, // vaultSymbol: `v-fP${deployedMasset.symbol}/${deployedFasset.symbol}`, // priceCoeff: pair.priceCoeff, // }) // } // // - create fPool (nexus, mAsset, name, integrator, config) // // eslint-disable-next-line // for (const poolData of data) { // console.log(`\n~~~~~ POOL ${poolData.symbol} ~~~~~\n\n`) // console.log("Remaining ETH in deployer: ", formatUnits(await deployer.getBalance())) // // Deploy Feeder Pool // const feederPool = await deployFeederPool(deployer, poolData) // poolData.pool = feederPool // // Mint initial supply // // await mint(deployer, [poolData.mAsset, poolData.fAsset], poolData) // // Rewards Contract // if (addresses.boostDirector) { // const bal = await feederPool.balanceOf(await deployer.getAddress()) // const vault = await deployBoostedVault( // deployer, // addresses, // poolData.pool.address, // poolData.priceCoeff, // poolData.vaultName, // poolData.vaultSymbol, // bal, // ) // poolData.vault = vault // } // } // // 3. Clean // // - initialize boostDirector with pools // console.log(`\n~~~~~ PHASE 3 - ETC ~~~~~\n\n`) // console.log("Remaining ETH in deployer: ", formatUnits(await deployer.getBalance())) // if (!addresses.boostDirector && addresses.boostDirector !== ZERO_ADDRESS) { // const directorInitTx = await director.initialize(data.map((d) => d.vault.address)) // logTxDetails(directorInitTx, `Initializing BoostDirector for vaults: ${data.map((d) => d.vault.address)}`) // } // // - if aToken != 0: deploy Aave integrator & initialize with fPool & aToken addr // for (const poolData of data) { // if (poolData.aToken !== ZERO_ADDRESS) { // const integration = await deployContract( // new AaveV2Integration__factory(deployer), // `integration for ${poolData.symbol} at pool ${poolData.pool.address}`, // [addresses.nexus, poolData.pool.address, addresses.aave, DEAD_ADDRESS], // ) // const initTx = await integration.initialize([poolData.fAsset.address], [poolData.aToken]) // await logTxDetails(initTx, `Initializing pToken ${poolData.aToken} for bAsset ${poolData.fAsset.address}...`) // } // } // // Deploy feederRouter // let feederWrapper: FeederWrapper // if (addresses.boostDirector !== ZERO_ADDRESS) { // if (!addresses.feederRouter) { // // Deploy FeederWrapper // feederWrapper = await deployContract<FeederWrapper>(new FeederWrapper__factory(deployer), "FeederWrapper") // } else { // feederWrapper = FeederWrapper__factory.connect(addresses.feederRouter, deployer) // } // await approveFeederWrapper( // deployer, // feederWrapper, // data.map((d) => d.pool), // data.map((d) => d.vault), // ) // } // // - deploy interestValidator // if (!addresses.interestValidator) { // await deployContract(new InterestValidator__factory(deployer), "InterestValidator", [addresses.nexus]) // } // console.log(`\n~~~~~ 🥳 CONGRATS! Time for Phase 4 🥳 ~~~~~\n\n`) // // 4. Post // // - Fund small amt to vaults // // - Add InterestValidator as a module // // - Fund vaults // console.log("Remaining ETH in deployer: ", formatUnits(await deployer.getBalance())) // const end = await deployer.getBalance() // console.log("Total ETH used: ", formatUnits(end.sub(start))) // } //# sourceMappingURL=feederUtils.js.map