UNPKG

@mstable/protocol

Version:
383 lines 20.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.mUsdBassets = void 0; /* eslint-disable no-await-in-loop */ /* eslint-disable no-console */ const units_1 = require("@ethersproject/units"); const constants_1 = require("@utils/constants"); const math_1 = require("@utils/math"); const config_1 = require("hardhat/config"); require("ts-node/register"); require("tsconfig-paths/register"); const generated_1 = require("types/generated"); const deploy_utils_1 = require("./utils/deploy-utils"); const networkAddressFactory_1 = require("./utils/networkAddressFactory"); const signerFactory_1 = require("./utils/signerFactory"); const tokens_1 = require("./utils/tokens"); // FIXME: this import does not work for some reason // import { sleep } from "@utils/time" const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const sleepTime = 10000; // milliseconds exports.mUsdBassets = [ { name: "(PoS) USD Coin", symbol: "PoS-USDC", decimals: 6, integrator: constants_1.ZERO_ADDRESS, initialMint: 1000000, }, { name: "(PoS) Dai Stablecoin", symbol: "PoS-DAI", decimals: 18, integrator: constants_1.ZERO_ADDRESS, initialMint: 1000000, }, { name: "(PoS) Tether USD", symbol: "PoS-USDT", decimals: 6, integrator: constants_1.ZERO_ADDRESS, initialMint: 1000000, }, ]; const deployBasset = async (signer, name, symbol, decimals = 18, initialMint = 500000) => { const signerAddress = await signer.getAddress(); // Deploy Implementation const impl = await deploy_utils_1.deployContract(new generated_1.MockInitializableToken__factory(signer), `${symbol} impl`); // Initialization Implementation const data = impl.interface.encodeFunctionData("initialize", [name, symbol, decimals, signerAddress, initialMint]); // Deploy Proxy const proxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(signer), `${symbol} proxy`, [impl.address, constants_1.DEAD_ADDRESS, data]); return new generated_1.MockERC20__factory(signer).attach(proxy.address); }; const deployBassets = async (signer, bAssetsProps) => { const signerAddress = await signer.getAddress(); const bAssets = []; let i = 0; // eslint-disable-next-line for (const basset of bAssetsProps) { const bAssetContract = await deployBasset(signer, basset.name, basset.symbol, basset.decimals, basset.initialMint); await sleep(sleepTime); const pTokenContract = await deploy_utils_1.deployContract(new generated_1.MockERC20__factory(signer), `pToken for ${basset.symbol}`, [ `Aave Matic Market ${basset.name}`, `am${basset.symbol}`, basset.decimals, signerAddress, 0, ]); bAssets.push({ ...bAssetsProps[i], bAssetContract, pTokenContract, }); i += 1; } return bAssets; }; const attachBassets = (deployer, bAssetsProps, bAssetAddresses, pTokenAddresses) => { const bAssets = []; bAssetsProps.forEach((basset, i) => { const bAssetContract = new generated_1.MockERC20__factory(deployer).attach(bAssetAddresses[i]); const pTokenContract = new generated_1.MockERC20__factory(deployer).attach(pTokenAddresses[i]); bAssets.push({ ...bAssetsProps[i], bAssetContract, pTokenContract, }); }); return bAssets; }; const deployMasset = async (deployer, linkedAddress, nexus, delayedProxyAdmin, recolFee = math_1.simpleToExactAmount(5, 13)) => { const mAssetFactory = new generated_1.Masset__factory(linkedAddress, deployer); const impl = await deploy_utils_1.deployContract(mAssetFactory, "Masset Impl", [nexus.address, recolFee]); const proxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(deployer), "Masset Proxy", [ impl.address, delayedProxyAdmin.address, "0x", // Passing zero bytes as we'll initialize the proxy contract later ]); return mAssetFactory.attach(proxy.address); }; const deployInterestBearingMasset = async (deployer, nexus, mUsd, unwrapper, delayedProxyAdmin, poker, symbol, name) => { const impl = await deploy_utils_1.deployContract(new generated_1.SavingsContract__factory(deployer), "SavingsContract Impl", [ nexus.address, mUsd.address, unwrapper.address, ]); const initializeData = impl.interface.encodeFunctionData("initialize", [poker, name, symbol]); const proxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(deployer), "SavingsContract Proxy", [ impl.address, delayedProxyAdmin.address, initializeData, ]); return new generated_1.SavingsContract__factory(deployer).attach(proxy.address); }; const deployAaveIntegration = async (deployer, nexus, mAsset, bAssetAddresses, pTokenAddresses, networkName) => { let platformAddress = constants_1.DEAD_ADDRESS; let rewardTokenAddress = constants_1.DEAD_ADDRESS; let rewardControllerAddress = constants_1.DEAD_ADDRESS; let quickSwapRouter = constants_1.DEAD_ADDRESS; if (networkName === "polygon_mainnet") { platformAddress = "0xd05e3E715d945B59290df0ae8eF85c1BdB684744"; // Aave lendingPoolAddressProvider rewardTokenAddress = "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270"; // wMatic rewardControllerAddress = "0x357D51124f59836DeD84c8a1730D72B749d8BC23"; // Aave AaveIncentivesController quickSwapRouter = "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff"; } const aaveIntegration = await deploy_utils_1.deployContract(new generated_1.PAaveIntegration__factory(deployer), "PAaveIntegration", [ nexus.address, mAsset.address, platformAddress, rewardTokenAddress, rewardControllerAddress, ]); // initialize Aave integration with bAssets and pTokens console.log(`About to initialize Aave integration with bAssets ${bAssetAddresses} and pTokens ${pTokenAddresses}`); const tx = await aaveIntegration.initialize(bAssetAddresses, pTokenAddresses); await tx.wait(); // Deploy Liquidator const liquidator = await deploy_utils_1.deployContract(new generated_1.PLiquidator__factory(deployer), "PLiquidator", [ nexus.address, quickSwapRouter, mAsset.address, ]); return { integrator: aaveIntegration, liquidator, }; }; const mint = async (sender, bAssets, mAsset, scaledMintQty) => { const senderAddress = await sender.getAddress(); // Approve spending const approvals = []; // eslint-disable-next-line for (const bAsset of bAssets) { const dec = bAsset.decimals; const approval = dec === 18 ? scaledMintQty : scaledMintQty.div(math_1.simpleToExactAmount(1, math_1.BN.from(18).sub(dec))); approvals.push(approval); const tx = await bAsset.bAssetContract.approve(mAsset.address, approval); const receiptApprove = await tx.wait(); console.log(`Approved mAsset to transfer ${units_1.formatUnits(scaledMintQty)} ${bAsset.symbol} from ${senderAddress}. gas used ${receiptApprove.gasUsed}`); console.log(`Balance ${(await bAsset.bAssetContract.balanceOf(await sender.getAddress())).toString()}`); } // Mint const tx = await mAsset.mintMulti(bAssets.map((b) => b.bAssetContract.address), approvals, 1, await sender.getAddress(), { gasLimit: 8000000 }); const receiptMint = await tx.wait(); // Log minted amount const mAssetAmount = units_1.formatUnits(await mAsset.totalSupply()); console.log(`Minted ${mAssetAmount} mAssets from ${units_1.formatUnits(scaledMintQty)} units for each bAsset. gas used ${receiptMint.gasUsed}`); }; const save = async (sender, mAsset, imAsset, scaledSaveQty) => { console.log(`About to save ${units_1.formatUnits(scaledSaveQty)} mAssets`); await mAsset.approve(imAsset.address, scaledSaveQty); await imAsset["depositSavings(uint256)"](scaledSaveQty, { gasLimit: 8000000 }); console.log(`Saved ${units_1.formatUnits(scaledSaveQty)} mAssets to interest bearing mAssets`); }; config_1.task("deploy-polly", "Deploys mUSD & System to a Polygon network") .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, hre) => { const { network } = hre; const signer = await signerFactory_1.getSigner(hre, taskArgs.speed); const signerAddress = await signer.getAddress(); // Deploy Nexus const nexus = await deploy_utils_1.deployContract(new generated_1.Nexus__factory(signer), "Nexus", [signerAddress]); // Deploy DelayedProxyAdmin const delayedProxyAdmin = await deploy_utils_1.deployContract(new generated_1.DelayedProxyAdmin__factory(signer), "DelayedProxyAdmin", [ nexus.address, ]); await sleep(sleepTime); let deployedUsdBassets; let multiSigAddress; if (network.name === "hardhat") { multiSigAddress = signerAddress; // Deploy mocked base USD assets deployedUsdBassets = await deployBassets(signer, exports.mUsdBassets); } else if (network.name === "polygon_testnet") { multiSigAddress = "0xE1304aA964C5119C98E8AE554F031Bf3B21eC836"; // 1/3 Multisig // Attach to already deployed mocked bAssets deployedUsdBassets = attachBassets(signer, exports.mUsdBassets, [ "0x4fa81E591dC5dAf1CDA8f21e811BAEc584831673", "0xD84574BFE3294b472C74D7a7e3d3bB2E92894B48", "0x872093ee2BCb9951b1034a4AAC7f489215EDa7C2", // Tether ], [ "0xA2De18B8AE0450D918EA5Bf5890CBA5dD7055A4f", "0x85581E4BDeDB67840876DF20eFeaA6926dfFa11E", "0xAD209ADbCDF8B6917E69E6BcF9D05592388B8ada", ]); } else if (network.name === "polygon_mainnet") { multiSigAddress = "0x4aA2Dd5D5387E4b8dcf9b6Bfa4D9236038c3AD43"; // 4/8 Multisig // Attach to 3rd party bAssets deployedUsdBassets = attachBassets(signer, exports.mUsdBassets, [ "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063", "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", // Tether ], [ "0x1a13F4Ca1d028320A707D99520AbFefca3998b7F", "0x27F8D03b3a2196956ED754baDc28D73be8830A6e", "0x60D55F02A771d515e077c9C2403a1ef324885CeC", ]); } await sleep(sleepTime); // Deploy mAsset dependencies const massetLogic = await deploy_utils_1.deployContract(new generated_1.MassetLogic__factory(signer), "MassetLogic"); const managerLib = await deploy_utils_1.deployContract(new generated_1.MassetManager__factory(signer), "MassetManager"); const linkedAddress = { "contracts/masset/MassetLogic.sol:MassetLogic": massetLogic.address, "contracts/masset/MassetManager.sol:MassetManager": managerLib.address, }; // Deploy mUSD Masset const mUsd = await deployMasset(signer, linkedAddress, nexus, delayedProxyAdmin); await sleep(sleepTime); const { integrator, liquidator } = await deployAaveIntegration(signer, nexus, mUsd, deployedUsdBassets.map((b) => b.bAssetContract.address), deployedUsdBassets.map((b) => b.pTokenContract.address), network.name); const config = { a: 300, limits: { min: math_1.simpleToExactAmount(5, 16), max: math_1.simpleToExactAmount(75, 16), }, }; const txMusd = await mUsd.initialize("mUSD", "mStable USD (Polygon PoS)", deployedUsdBassets.map((b) => ({ addr: b.bAssetContract.address, integrator: network.name === "polygon_mainnet" ? integrator.address : constants_1.ZERO_ADDRESS, hasTxFee: false, status: 0, })), config, { gasLimit: 8000000 }); console.log(`mUSD initialize tx ${txMusd.hash}`); const receiptMusd = await txMusd.wait(); console.log(`mUSD initialize status ${receiptMusd.status} from receipt`); await sleep(sleepTime); const unwrapperFactory = await new generated_1.Unwrapper__factory(signer); const unwrapper = await unwrapperFactory.deploy(nexus.address); await sleep(sleepTime); // Deploy Interest Bearing mUSD const imUsd = await deployInterestBearingMasset(signer, nexus, mUsd, unwrapper, delayedProxyAdmin, constants_1.DEAD_ADDRESS, "imUSD", "Interest bearing mStable USD (Polygon PoS)"); await sleep(sleepTime); // Deploy Save Wrapper const saveWrapper = await deploy_utils_1.deployContract(new generated_1.SaveWrapper__factory(signer), "SaveWrapper"); // Deploy Savings Manager const savingsManager = await deploy_utils_1.deployContract(new generated_1.SavingsManager__factory(signer), "SavingsManager", [ nexus.address, mUsd.address, imUsd.address, math_1.simpleToExactAmount(9, 17), constants_1.ONE_DAY, ]); await sleep(sleepTime); // SaveWrapper contract approves the savings contract (imUSD) to spend its USD mAsset tokens (mUSD) await saveWrapper["approve(address,address)"](mUsd.address, imUsd.address); // SaveWrapper approves the mUSD contract to spend its bAsset tokens const bAssetAddresses = deployedUsdBassets.map((b) => b.bAssetContract.address); await saveWrapper["approve(address[],address)"](bAssetAddresses, mUsd.address); console.log("Successful token approvals from the SaveWrapper"); await sleep(sleepTime); // Initialize Nexus Modules const moduleKeys = [constants_1.KEY_SAVINGS_MANAGER, constants_1.KEY_PROXY_ADMIN, constants_1.KEY_LIQUIDATOR]; const moduleAddresses = [savingsManager.address, delayedProxyAdmin.address, liquidator.address]; const moduleIsLocked = [false, true, false]; const nexusTx = await nexus.connect(signer).initialize(moduleKeys, moduleAddresses, moduleIsLocked, multiSigAddress); const nexusReceipt = await nexusTx.wait(); console.log(`Nexus initialize status ${nexusReceipt.status} from receipt`); await sleep(sleepTime); if (hre.network.name !== "polygon_mainnet") { await mint(signer, deployedUsdBassets, mUsd, math_1.simpleToExactAmount(20)); await save(signer, mUsd, imUsd, math_1.simpleToExactAmount(15)); } else if (hre.network.name === "polygon_mainnet") { // Multimint 2 USD and then save 4 await mint(signer, deployedUsdBassets, mUsd, math_1.simpleToExactAmount(2)); await save(signer, mUsd, imUsd, math_1.simpleToExactAmount(4)); } }); config_1.task("liquidator-snap", "Dumps the config details of the liquidator on Polygon") .addParam("asset", "Symbol of asset to get liquidation details for. eg USDC, PUSDC, DAI, GUSD, alUSD", undefined, config_1.types.string) .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, hre) => { const signer = await signerFactory_1.getSigner(hre, taskArgs.speed); const chain = networkAddressFactory_1.getChain(hre); const asset = tokens_1.tokens.find((t) => t.symbol === taskArgs.asset && t.chain === chain); if (!asset) throw Error(`Could not find asset with symbol ${taskArgs.asset}`); const liquidatorAddress = networkAddressFactory_1.getChainAddress("Liquidator", chain); const liquidator = generated_1.PLiquidator__factory.connect(liquidatorAddress, signer); const liquidationConfig = await liquidator.liquidations(asset.integrator); console.log(liquidationConfig); }); config_1.task("deploy-vimusd", "Deploy Polygon imUSD staking contract v-imUSD") .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, hre) => { const signer = await signerFactory_1.getSigner(hre, taskArgs.speed); const chain = networkAddressFactory_1.getChain(hre); const proxyAdminAddress = networkAddressFactory_1.resolveAddress("DelayedProxyAdmin", chain); const fundManagerAddress = networkAddressFactory_1.getChainAddress("FundManager", chain); const governorAddress = networkAddressFactory_1.getChainAddress("Governor", chain); const nexusAddress = networkAddressFactory_1.getChainAddress("Nexus", chain); const rewardsDistributorAddress = networkAddressFactory_1.getChainAddress("RewardsDistributor", chain); const rewardsDistributor = rewardsDistributorAddress ? generated_1.RewardsDistributor__factory.connect(rewardsDistributorAddress, signer) : await deploy_utils_1.deployContract(new generated_1.RewardsDistributor__factory(signer), "RewardsDistributor", [ nexusAddress, [fundManagerAddress, governorAddress], ]); const stakingRewardsImpl = await deploy_utils_1.deployContract(new generated_1.StakingRewardsWithPlatformToken__factory(signer), "StakingRewardsWithPlatformToken", [ nexusAddress, tokens_1.PmUSD.savings, tokens_1.PMTA.address, tokens_1.PWMATIC.address, constants_1.ONE_DAY.mul(7), // 7 days ]); const initializeData = stakingRewardsImpl.interface.encodeFunctionData("initialize", [ rewardsDistributor.address, "imUSD Vault", "v-imUSD", ]); const proxy = await deploy_utils_1.deployContract(new generated_1.AssetProxy__factory(signer), "Staking Rewards Proxy", [ stakingRewardsImpl.address, proxyAdminAddress, initializeData, ]); const stakingRewards = generated_1.StakingRewardsWithPlatformToken__factory.connect(proxy.address, signer); console.log(`Name ${await stakingRewards.name()}`); console.log(`Symbol ${await stakingRewards.symbol()}`); console.log(`Duration ${await stakingRewards.DURATION()}`); console.log(`Nexus ${await stakingRewards.nexus()}`); console.log(`Staking token ${await stakingRewards.stakingToken()}`); console.log(`Rewards token ${await stakingRewards.rewardsToken()}`); console.log(`Platform token ${await stakingRewards.platformToken()}`); console.log(`Rewards distributor ${await stakingRewards.rewardsDistributor()}`); }); config_1.task("upgrade-vimusd", "Upgrade Polygon imUSD staking contract v-imUSD") .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, hre) => { const signer = await signerFactory_1.getSigner(hre, taskArgs.speed); const chain = networkAddressFactory_1.getChain(hre); const nexusAddress = networkAddressFactory_1.getChainAddress("Nexus", chain); const rewardsDistributorAddress = networkAddressFactory_1.getChainAddress("RewardsDistributor", chain); const rewardsDistributor = generated_1.RewardsDistributor__factory.connect(rewardsDistributorAddress, signer); const stakingRewardsImpl = await deploy_utils_1.deployContract(new generated_1.StakingRewardsWithPlatformToken__factory(signer), "StakingRewardsWithPlatformToken (v-imUSD)", [ nexusAddress, tokens_1.PmUSD.savings, tokens_1.PMTA.address, tokens_1.PWMATIC.address, constants_1.ONE_DAY.mul(91), // 3 months ]); const initializeData = stakingRewardsImpl.interface.encodeFunctionData("initialize", [ rewardsDistributor.address, "imUSD Vault", "v-imUSD", ]); console.log(`Initialize Staking Rewards:\n${initializeData}`); const proxy = generated_1.AssetProxy__factory.connect(tokens_1.PmUSD.vault, signer); const upgradeData = proxy.interface.encodeFunctionData("upgradeToAndCall", [stakingRewardsImpl.address, initializeData]); console.log(`\nupgradeToAndCall data:\n${upgradeData}`); }); config_1.task("exit-vimusd", "Upgrade Polygon imUSD staking contract v-imUSD") .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, hre) => { const signer = await signerFactory_1.getSigner(hre, taskArgs.speed); const vimusd = generated_1.StakingRewardsWithPlatformToken__factory.connect(tokens_1.PmUSD.vault, signer); const tx = await vimusd.exit(); await deploy_utils_1.logTxDetails(tx, "exit from v-imUSD"); }); module.exports = {}; //# sourceMappingURL=deployPolygon.js.map