UNPKG

@mstable/protocol

Version:
388 lines 20.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable no-console */ require("ts-node/register"); require("tsconfig-paths/register"); const btcConstants_1 = require("@utils/btcConstants"); const constants_1 = require("@utils/constants"); const config_1 = require("hardhat/config"); const utils_1 = require("ethers/lib/utils"); const generated_1 = require("types/generated"); const math_1 = require("@utils/math"); const COEFF = 45; const deployBasset = async (sender, name, symbol, decimals = 18, initialMint = 500000) => { // Implementation const impl = await new generated_1.MockInitializableToken__factory(sender).deploy(); await impl.deployTransaction.wait(); // Initialization Data const data = impl.interface.encodeFunctionData("initialize", [name, symbol, decimals, await sender.getAddress(), initialMint]); // Proxy const proxy = await new generated_1.AssetProxy__factory(sender).deploy(impl.address, constants_1.DEAD_ADDRESS, data); const receipt = await proxy.deployTransaction.wait(); console.log(`Deployed ${name} (${symbol}) to address ${proxy.address}. gas used ${receipt.gasUsed}`); return new generated_1.MockERC20__factory(sender).attach(proxy.address); }; const deployMasset = async (sender, addresses, ethers, bAssetContracts) => { // Invariant Validator console.log(`Deploying Invariant Validator`); const LogicFactory = await ethers.getContractFactory("MassetLogic"); const logicLib = await LogicFactory.deploy(); const receiptForgeVal = await logicLib.deployTransaction.wait(); console.log(`Deployed Invariant Validator to ${logicLib.address}. gas used ${receiptForgeVal.gasUsed}`); // External linked library const Manager = await ethers.getContractFactory("Manager"); const managerLib = await Manager.deploy(); const receiptManager = await managerLib.deployTransaction.wait(); console.log(`Deployed Manager library to ${managerLib.address}. gas used ${receiptManager.gasUsed}`); const linkedAddress = { libraries: { MassetLogic: logicLib.address, MassetManager: managerLib.address, }, }; const massetFactory = await ethers.getContractFactory("Masset", linkedAddress); const size = massetFactory.bytecode.length / 2 / 1000; if (size > 24.576) { console.error(`Masset size is ${size} kb: ${size - 24.576} kb too big`); } else { console.log(`Masset = ${size} kb`); } console.log(`Deploying Masset with ManagerAddr: ${managerLib.address} and nexus ${addresses.nexus}`); const impl = await massetFactory.deploy(addresses.nexus); const receiptImpl = await impl.deployTransaction.wait(); console.log(`Deployed Masset to ${impl.address}. gas used ${receiptImpl.gasUsed}`); // Initialization Data console.log(`Initializing Masset with: ${btcConstants_1.mBtcName}, ${btcConstants_1.mBtcSymbol}, [${bAssetContracts.map( // eslint-disable-next-line (b) => "{" + b.contract.address + ", " + b.integrator + ", " + b.txFee + ", " + 0 + "}")} ] , ${btcConstants_1.config.a.toString()}, ${btcConstants_1.config.limits.min.toString()}, ${btcConstants_1.config.limits.max.toString()}`); const data = impl.interface.encodeFunctionData("initialize", [ btcConstants_1.mBtcName, btcConstants_1.mBtcSymbol, bAssetContracts.map((b) => ({ addr: b.contract.address, integrator: b.integrator, hasTxFee: b.txFee, status: 0, })), btcConstants_1.config, ]); // Proxy console.log(`Deploying mBTC proxy with impl: ${impl.address} and admin ${addresses.proxyAdmin}`); const mBtcProxy = await new generated_1.AssetProxy__factory(sender).deploy(impl.address, addresses.proxyAdmin, data); const receiptProxy = await mBtcProxy.deployTransaction.wait(); console.log(`Deployed mBTC to address ${mBtcProxy.address}. gas used ${receiptProxy.gasUsed}`); if (addresses.renGatewayRegistry !== constants_1.DEAD_ADDRESS) { const gateway = await new generated_1.RenWrapper__factory(sender).deploy(mBtcProxy.address, addresses.renGatewayRegistry); const receiptGateway = await gateway.deployTransaction.wait(); console.log(`Deployed Ren Gateway wrapper to address ${gateway.address}. gas used ${receiptGateway.gasUsed}`); } // Create a Masset contract pointing to the deployed proxy contract return massetFactory.attach(mBtcProxy.address); }; const mint = async (sender, bAssets, mBTC) => { // Mint 3/5 of starting cap const scaledTestQty = btcConstants_1.startingCap.div(5); // Approve spending const approvals = []; // 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(math_1.simpleToExactAmount(1, math_1.BN.from(18).sub(dec))); approvals.push(approval); // eslint-disable-next-line const tx = await bAsset.contract.approve(mBTC.address, approval); // eslint-disable-next-line const receiptApprove = await tx.wait(); console.log( // eslint-disable-next-line `Approved mBTC to transfer ${utils_1.formatEther(scaledTestQty)} ${bAsset.symbol} from ${await sender.getAddress()}. gas used ${receiptApprove.gasUsed}`); console.log( // eslint-disable-next-line `Balance ${(await bAsset.contract.balanceOf(await sender.getAddress())).toString()}`); } // Mint const tx = await mBTC.mintMulti(bAssets.map((b) => b.contract.address), approvals, 1, await sender.getAddress()); const receiptMint = await tx.wait(); // Log minted amount const mAssetAmount = utils_1.formatEther(await mBTC.totalSupply()); console.log(`Minted ${mAssetAmount} mBTC from ${utils_1.formatEther(scaledTestQty)} BTC for each bAsset. gas used ${receiptMint.gasUsed}`); }; const deploySave = async (sender, addresses, mBTC, bAssets, deployVault = true) => { // Save impl console.log(`Deploying Savings Contract nexus: ${addresses.nexus} and underlying ${mBTC.address}`); const unwrapperFactory = await new generated_1.Unwrapper__factory(sender); const unwrapperContract = await unwrapperFactory.deploy(addresses.nexus); const sImpl = await new generated_1.SavingsContract__factory(sender).deploy(addresses.nexus, mBTC.address, unwrapperContract.address); const receiptSaving = await sImpl.deployTransaction.wait(); console.log(`Deployed Savings contract to ${sImpl.address}. gas used ${receiptSaving.gasUsed}`); // Data const sData = sImpl.interface.encodeFunctionData("initialize", [addresses.poker, "Interest bearing mStable BTC", "imBTC"]); // Proxy console.log(`Deploying Savings Contract proxy, impl: ${sImpl.address}, admin: ${addresses.proxyAdmin}`); const sProxy = await new generated_1.AssetProxy__factory(sender).deploy(sImpl.address, addresses.proxyAdmin, sData); const receiptProxy = await sProxy.deployTransaction.wait(); const savingContract = await new generated_1.SavingsContract__factory(sender).attach(sProxy.address); console.log(`Deployed Saving Proxy to ${sProxy.address}. gas used ${receiptProxy.gasUsed}`); // Vault impl if (deployVault) { const vImpl = await new generated_1.BoostedVault__factory(sender).deploy(addresses.nexus, savingContract.address, addresses.boostDirector, math_1.simpleToExactAmount(3000, 18), COEFF, addresses.mta); const receiptVaultImpl = await vImpl.deployTransaction.wait(); console.log(`Deployed Vault Impl to ${vImpl.address}. gas used ${receiptVaultImpl.gasUsed}`); // Data const vData = vImpl.interface.encodeFunctionData("initialize", [addresses.rewardsDistributor, "imBTC Savings Vault", "v-imBTC"]); // Proxy const vProxy = await new generated_1.AssetProxy__factory(sender).deploy(vImpl.address, addresses.proxyAdmin, vData); const receiptVaultProxy = await vProxy.deployTransaction.wait(); const savingsVault = await new generated_1.BoostedVault__factory(sender).attach(vProxy.address); console.log(`Deployed Vault Proxy to ${vProxy.address}. gas used ${receiptVaultProxy.gasUsed}`); // SaveWrapper const wrapper = await new generated_1.SaveWrapper__factory(sender).deploy(addresses.nexus); const receiptSavingWrapper = await wrapper.deployTransaction.wait(); console.log(`Deployed Save Wrapper to address ${wrapper.address}. gas used ${receiptSavingWrapper.gasUsed}`); const bassets = (await mBTC.getBassets())[0].map((p) => p[0]); const approveTx = await wrapper["approve(address,address,address,address[])"](mBTC.address, savingContract.address, savingsVault.address, bassets); const approveTxReceipt = await approveTx.wait(); console.log(`Approve mAsset on SaveWrapper. gas used ${approveTxReceipt.gasUsed}`); return { savingContract, savingsVault }; } // SaveWrapper console.log(`Deploying Wrapper...`); const wrapper = await new generated_1.SaveWrapper__factory(sender).deploy(addresses.nexus); const receiptSavingWrapper = await wrapper.deployTransaction.wait(); console.log(`Deployed Save Wrapper to address ${wrapper.address}. gas used ${receiptSavingWrapper.gasUsed}`); return { savingContract, savingsVault: null }; }; const depositToVault = async (sender, mBTC, save) => { // Mint imBTC const deposit = btcConstants_1.startingCap.div(math_1.BN.from(3)); let tx = await mBTC.approve(save.savingContract.address, deposit); await tx.wait(); tx = await save.savingContract.preDeposit(deposit, await sender.getAddress()); await tx.wait(); const balance = await save.savingContract.balanceOf(await sender.getAddress()); // Deposit to vault tx = await save.savingContract.approve(save.savingsVault.address, balance); await tx.wait(); tx = await save.savingsVault["stake(uint256)"](balance); tx.wait(); console.log(`Minted ${utils_1.formatEther(balance)} imBTC from ${utils_1.formatEther(deposit)} mBTC and deposited to vault`); }; config_1.task("deployMBTC", "Deploys the mBTC contracts").setAction(async (_, hre) => { const { ethers, network } = hre; const [deployer] = await ethers.getSigners(); const addresses = network.name === "ropsten" ? { mta: "0x273bc479E5C21CAA15aA8538DecBF310981d14C0", staking: "0x77f9bf80e0947408f64faa07fd150920e6b52015", nexus: "0xeD04Cd19f50F893792357eA53A549E23Baf3F6cB", proxyAdmin: "0x2d369F83E9DC764a759a74e87a9Bc542a2BbfdF0", rewardsDistributor: "0x99B62B75E3565bEAD786ddBE2642E9c40aA33465", boostDirector: constants_1.DEAD_ADDRESS, uniswap: constants_1.DEAD_ADDRESS, poker: constants_1.DEAD_ADDRESS, renGatewayRegistry: constants_1.DEAD_ADDRESS, } : { mta: constants_1.DEAD_ADDRESS, staking: (await new generated_1.MockERC20__factory(deployer).deploy("Stake", "ST8", 18, constants_1.DEAD_ADDRESS, 1)).address, nexus: constants_1.DEAD_ADDRESS, proxyAdmin: constants_1.DEAD_ADDRESS, rewardsDistributor: constants_1.DEAD_ADDRESS, boostDirector: constants_1.DEAD_ADDRESS, uniswap: constants_1.DEAD_ADDRESS, poker: constants_1.DEAD_ADDRESS, renGatewayRegistry: constants_1.DEAD_ADDRESS, }; const director = await new generated_1.BoostDirector__factory(deployer).deploy(addresses.nexus, addresses.staking); await director.deployTransaction.wait(); addresses.boostDirector = director.address; // 1. Deploy bAssets const bAssets = []; // eslint-disable-next-line for (const btcBasset of btcConstants_1.btcBassets) { // eslint-disable-next-line const contract = await deployBasset(deployer, btcBasset.name, btcBasset.symbol, btcBasset.decimals, btcBasset.initialMint); bAssets.push({ contract, integrator: btcBasset.integrator, txFee: btcBasset.txFee, symbol: btcBasset.symbol, }); } // 2. Deploy mBTC const mBTC = await deployMasset(deployer, addresses, ethers, bAssets); // 3. Mint initial supply await mint(deployer, bAssets, mBTC); // 4. Create savings contract & vault const savingsContracts = await deploySave(deployer, addresses, mBTC, bAssets.map((b) => b.contract.address)); // 5. Mint imBTC and deposit to vault await depositToVault(deployer, mBTC, savingsContracts); // Governance funcs to complete setup: // - Add mBTC savingsContract to SavingsManager to enable interest collection // - Fund the BoostedVault with MTA to enable rewards }); config_1.task("reDeployMBTC", "Re-deploys the mBTC contracts given bAsset addresses").setAction(async (_, hre) => { const { ethers, network } = hre; const [deployer] = await ethers.getSigners(); const addresses = network.name === "ropsten" ? { mta: "0x273bc479E5C21CAA15aA8538DecBF310981d14C0", staking: "0x77f9bf80e0947408f64faa07fd150920e6b52015", nexus: "0xeD04Cd19f50F893792357eA53A549E23Baf3F6cB", proxyAdmin: "0x2d369F83E9DC764a759a74e87a9Bc542a2BbfdF0", rewardsDistributor: "0x99B62B75E3565bEAD786ddBE2642E9c40aA33465", boostDirector: constants_1.DEAD_ADDRESS, uniswap: constants_1.DEAD_ADDRESS, poker: constants_1.DEAD_ADDRESS, renGatewayRegistry: constants_1.DEAD_ADDRESS, } : { mta: constants_1.DEAD_ADDRESS, staking: (await new generated_1.MockERC20__factory(deployer).deploy("Stake", "ST8", 18, constants_1.DEAD_ADDRESS, 1)).address, nexus: constants_1.DEAD_ADDRESS, proxyAdmin: constants_1.DEAD_ADDRESS, rewardsDistributor: constants_1.DEAD_ADDRESS, boostDirector: constants_1.DEAD_ADDRESS, uniswap: constants_1.DEAD_ADDRESS, poker: constants_1.DEAD_ADDRESS, renGatewayRegistry: constants_1.DEAD_ADDRESS, }; const bAssetsRaw = [ { address: "0xd4Da7c3b1C985b8Baec8D2a5709409CCFE809096", integrator: constants_1.ZERO_ADDRESS, txFee: false, }, { address: "0xf08d8Ab65e709B66e77908cc4EDb530113D8d855", integrator: constants_1.ZERO_ADDRESS, txFee: false, }, { address: "0x82e6459D1B9529cC6A8203f1bFE3B04d6CfCbD43", integrator: constants_1.ZERO_ADDRESS, txFee: false, }, ]; const director = await new generated_1.BoostDirector__factory(deployer).deploy(addresses.nexus, addresses.staking); await director.deployTransaction.wait(); addresses.boostDirector = director.address; // 1. Fetch bAssets const erc20Factory = await new generated_1.ERC20__factory(deployer); const bAssets = await Promise.all(bAssetsRaw.map(async (b) => ({ contract: await erc20Factory.attach(b.address), integrator: b.integrator, txFee: b.txFee, symbol: await erc20Factory.attach(b.address).symbol(), }))); // 2. Deploy mBTC const mBTC = await deployMasset(deployer, addresses, ethers, bAssets); // 3. Mint initial supply await mint(deployer, bAssets, mBTC); // 4. Create savings contract & vault const savingsContracts = await deploySave(deployer, addresses, mBTC, bAssets.map((b) => b.contract.address)); // 5. Mint imBTC and deposit to vault await depositToVault(deployer, mBTC, savingsContracts); // Governance funcs to complete setup: // - Add mBTC savingsContract to SavingsManager to enable interest collection // - Fund the BoostedVault with MTA to enable rewards }); config_1.task("deployMBTC-mainnet", "Deploys the mBTC contracts to Mainnet").setAction(async (_, hre) => { const { ethers, network } = hre; if (network.name !== "mainnet") throw Error("Must be mainnet"); const [deployer] = await ethers.getSigners(); const addresses = { mta: "0xa3BeD4E1c75D00fa6f4E5E6922DB7261B5E9AcD2", staking: "0xae8bc96da4f9a9613c323478be181fdb2aa0e1bf", nexus: "0xafce80b19a8ce13dec0739a1aab7a028d6845eb3", proxyAdmin: "0x5c8eb57b44c1c6391fc7a8a0cf44d26896f92386", rewardsDistributor: "0x04dfdfa471b79cc9e6e8c355e6c71f8ec4916c50", boostDirector: constants_1.DEAD_ADDRESS, uniswap: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", poker: "0x0C2eF8a1b3Bc00Bf676053732F31a67ebbA5bD81", renGatewayRegistry: constants_1.DEAD_ADDRESS, }; const bAssetsRaw = [ { address: "0xeb4c2781e4eba804ce9a9803c67d0893436bb27d", integrator: constants_1.ZERO_ADDRESS, txFee: false, }, { address: "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6", integrator: constants_1.ZERO_ADDRESS, txFee: false, }, { address: "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", integrator: constants_1.ZERO_ADDRESS, txFee: false, }, ]; const director = await new generated_1.BoostDirector__factory(deployer).deploy(addresses.nexus, addresses.staking); await director.deployTransaction.wait(); addresses.boostDirector = director.address; // 1. Fetch bAssets const erc20Factory = await new generated_1.ERC20__factory(deployer); const bAssets = await Promise.all(bAssetsRaw.map(async (b) => ({ contract: await erc20Factory.attach(b.address), integrator: b.integrator, txFee: b.txFee, symbol: await erc20Factory.attach(b.address).symbol(), }))); // 2. Deploy mBTC const mBTC = await deployMasset(deployer, addresses, ethers, bAssets); // 3. Create savings contract await deploySave(deployer, addresses, mBTC, bAssets.map((b) => b.contract.address), false); // Governance funcs to complete setup: // - Add mBTC savingsContract to SavingsManager to enable interest collection }); config_1.task("initMBTC", "Initializes the mBTC and imBTC implementations").setAction(async (_, hre) => { const { ethers, network } = hre; const [deployer] = await ethers.getSigners(); console.log(`Connecting using ${await deployer.getAddress()} and url ${network.name}`); const addresses = { mBtcLogic: "0x1E91F826fa8aA4fa4D3F595898AF3A64dd188848", mBtcManager: "0x1E91F826fa8aA4fa4D3F595898AF3A64dd188848", mBtcImpl: "0x69AD1387dA6b2Ab2eA4bF2BEE68246bc042B587f", imBtcImpl: "0x1C728F1bda86CD8d19f56E36eb9e24ED3E572A39", deadToken: "0xB68dEfcA27e80cEb9bCC201fE28edaDc508Ec15b", }; // mBTC Implementation const linkedAddress = { libraries: { MassetLogic: addresses.mBtcLogic, MassetManager: addresses.mBtcManager, }, }; const massetFactory = await ethers.getContractFactory("Masset", linkedAddress); const mBtcImpl = massetFactory.attach(addresses.mBtcImpl); const tx1 = await mBtcImpl.initialize("DEAD", "DEAD", [ { addr: addresses.deadToken, integrator: constants_1.ZERO_ADDRESS, hasTxFee: false, status: 0, }, ], { a: 100, limits: { min: math_1.simpleToExactAmount(100, 16), max: math_1.simpleToExactAmount(100, 16), }, }); console.log(`mBTC impl initialize tx ${tx1.hash}`); const receipt1 = await tx1.wait(); console.log(`mBTC tx mined status ${receipt1.status} used ${receipt1.gasUsed} gas`); // imBTC Savings Contract const imBtcImpl = await new generated_1.SavingsContract__factory(deployer).attach(addresses.imBtcImpl); const tx2 = await imBtcImpl.initialize(constants_1.DEAD_ADDRESS, "DEAD", "DEAD"); console.log(`imBTC impl initialize tx ${tx2.hash}`); const receipt2 = await tx2.wait(); console.log(`imBTC tx mined status ${receipt2.status} used ${receipt2.gasUsed} gas`); }); module.exports = {}; //# sourceMappingURL=deployMbtc.js.map