UNPKG

@mstable/protocol

Version:
233 lines 15.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); require("ts-node/register"); require("tsconfig-paths/register"); const config_1 = require("hardhat/config"); const generated_1 = require("types/generated"); const math_1 = require("@utils/math"); const utils_1 = require("ethers/lib/utils"); const storage_utils_1 = require("./utils/storage-utils"); const snap_utils_1 = require("./utils/snap-utils"); const tokens_1 = require("./utils/tokens"); const quantity_formatters_1 = require("./utils/quantity-formatters"); const rates_utils_1 = require("./utils/rates-utils"); const defender_utils_1 = require("./utils/defender-utils"); const utils_2 = require("./utils"); const networkAddressFactory_1 = require("./utils/networkAddressFactory"); const getBalances = async (feederPool, block, asset, quantityFormatter) => { const feederPoolBalance = await feederPool.totalSupply({ blockTag: block, }); const vaultBalance = await feederPool.balanceOf(asset.vault, { blockTag: block, }); const otherBalances = feederPoolBalance.sub(vaultBalance); console.log("\nHolders"); console.log(`Vault ${quantityFormatter(vaultBalance)} ${vaultBalance.mul(100).div(feederPoolBalance)}%`); console.log(`Others ${quantityFormatter(otherBalances)} ${otherBalances.mul(100).div(feederPoolBalance)}%`); console.log(`Total ${quantityFormatter(feederPoolBalance)}`); return { total: feederPoolBalance, save: vaultBalance, earn: math_1.BN.from(0), }; }; const getFeederPool = (signer, contractAddress, chain = tokens_1.Chain.mainnet) => { const linkedAddress = { __$60670dd84d06e10bb8a5ac6f99a1c0890c$__: networkAddressFactory_1.getChainAddress("FeederManager", chain), __$7791d1d5b7ea16da359ce352a2ac3a881c$__: networkAddressFactory_1.getChainAddress("FeederLogic", chain), }; const feederPoolFactory = new generated_1.FeederPool__factory(linkedAddress, signer); return feederPoolFactory.attach(contractAddress); }; const getQuantities = (fAsset, _swapSize) => { let quantityFormatter; let swapSize; if (fAsset.quantityFormatter === "USD") { quantityFormatter = quantity_formatters_1.usdFormatter; swapSize = _swapSize || 10000; } else if (fAsset.quantityFormatter === "BTC") { quantityFormatter = quantity_formatters_1.btcFormatter; swapSize = _swapSize || 1; } return { quantityFormatter, swapSize, }; }; config_1.task("feeder-storage", "Dumps feeder contract storage data") .addOptionalParam("block", "Block number to get storage from. (default: current block)", 0, config_1.types.int) .addParam("fasset", "Token symbol of the feeder pool asset. eg HBTC, TBTC, GUSD or BUSD", undefined, config_1.types.string, false) .setAction(async (taskArgs, { ethers, network, hardhatArguments }) => { const chain = networkAddressFactory_1.getChain(network.name, hardhatArguments.config); const fAsset = tokens_1.tokens.find((t) => t.symbol === taskArgs.fasset); if (!fAsset) { console.error(`Failed to find feeder pool asset with token symbol ${taskArgs.fasset}`); process.exit(1); } const { blockNumber } = await snap_utils_1.getBlock(ethers, taskArgs.block); const signer = await defender_utils_1.getSigner(ethers); const pool = getFeederPool(signer, fAsset.feederPool, chain); await storage_utils_1.dumpTokenStorage(pool, blockNumber); await storage_utils_1.dumpFassetStorage(pool, blockNumber); await storage_utils_1.dumpConfigStorage(pool, blockNumber); }); config_1.task("feeder-snap", "Gets feeder transactions over a period of time") .addOptionalParam("from", "Block to query transaction events from. (default: deployment block)", 12146627, config_1.types.int) .addOptionalParam("to", "Block to query transaction events to. (default: current block)", 0, config_1.types.int) .addParam("fasset", "Token symbol of the feeder pool asset. eg HBTC, TBTC, GUSD or BUSD", undefined, config_1.types.string, false) .setAction(async (taskArgs, { ethers, network, hardhatArguments }) => { const chain = networkAddressFactory_1.getChain(network.name, hardhatArguments.config); const signer = await defender_utils_1.getSigner(ethers); const { fromBlock, toBlock } = await snap_utils_1.getBlockRange(ethers, taskArgs.from, taskArgs.to); const fAsset = tokens_1.tokens.find((t) => t.symbol === taskArgs.fasset); if (!fAsset) { console.error(`Failed to find feeder pool asset with token symbol ${taskArgs.fasset}`); process.exit(1); } console.log(`\nGetting snap for feeder pool ${fAsset.symbol} from block ${fromBlock.blockNumber}, to ${toBlock.blockNumber}`); const mAsset = tokens_1.tokens.find((t) => t.symbol === fAsset.parent); const fpAssets = [mAsset, fAsset]; const feederPool = getFeederPool(signer, fAsset.feederPool); const savingsManagerAddress = networkAddressFactory_1.getChainAddress("SavingsManager", chain); const savingsManager = generated_1.SavingsManager__factory.connect(savingsManagerAddress, signer); const { quantityFormatter } = getQuantities(fAsset, taskArgs.swapSize); const mintSummary = await snap_utils_1.getMints(tokens_1.tokens, feederPool, fromBlock.blockNumber, toBlock.blockNumber, quantityFormatter); const mintMultiSummary = await snap_utils_1.getMultiMints(tokens_1.tokens, feederPool, fromBlock.blockNumber, toBlock.blockNumber, quantityFormatter); const swapSummary = await snap_utils_1.getSwaps(tokens_1.tokens, feederPool, fromBlock.blockNumber, toBlock.blockNumber, quantityFormatter); const redeemSummary = await snap_utils_1.getRedemptions(tokens_1.tokens, feederPool, fromBlock.blockNumber, toBlock.blockNumber, quantityFormatter); const redeemMultiSummary = await snap_utils_1.getMultiRedemptions(tokens_1.tokens, feederPool, fromBlock.blockNumber, toBlock.blockNumber, quantityFormatter); await snap_utils_1.snapConfig(feederPool, toBlock.blockNumber); await snap_utils_1.getBasket(feederPool, fpAssets.map((b) => b.symbol), mAsset.symbol, quantity_formatters_1.usdFormatter, toBlock.blockNumber); const balances = await getBalances(feederPool, toBlock.blockNumber, fAsset, quantityFormatter); const collectedInterestSummary = await snap_utils_1.getCollectedInterest(fpAssets, feederPool, savingsManager, fromBlock, toBlock, quantityFormatter, balances.save); const data = await feederPool.data(); console.log(`\nPending gov fees ${quantityFormatter(data.pendingFees)}`); snap_utils_1.outputFees(mintSummary, mintMultiSummary, swapSummary, redeemSummary, redeemMultiSummary, balances, fromBlock.blockTime, toBlock.blockTime, quantityFormatter); }); config_1.task("feeder-rates", "Feeder rate comparison to Curve") .addOptionalParam("block", "Block number to compare rates at. (default: current block)", 0, config_1.types.int) .addOptionalParam("swapSize", "Swap size to compare rates with Curve", undefined, config_1.types.float) .addParam("fasset", "Token symbol of the feeder pool asset. eg HBTC, TBTC, GUSD or BUSD", undefined, config_1.types.string, false) .setAction(async (taskArgs, { ethers, network }) => { const signer = await defender_utils_1.getSigner(ethers); const block = await snap_utils_1.getBlock(ethers, taskArgs.block); const fAsset = tokens_1.tokens.find((t) => t.symbol === taskArgs.fasset); if (!fAsset) { console.error(`Failed to find feeder pool asset with token symbol ${taskArgs.fasset}`); process.exit(1); } console.log(`\nGetting rates for feeder pool ${fAsset.symbol} at block ${block.blockNumber}, ${block.blockTime.toUTCString()}`); const feederPool = getFeederPool(signer, fAsset.feederPool); const mAsset = tokens_1.tokens.find((t) => t.symbol === fAsset.parent); const fpAssets = [mAsset, fAsset]; // Get the bAssets for the main pool. eg bAssets in mUSD or mBTC // These are the assets that are not feeder pools and parent matches the fAsset's parent const mpAssets = tokens_1.tokens.filter((t) => t.parent === fAsset.parent && !t.feederPool); const { quantityFormatter, swapSize } = getQuantities(fAsset, taskArgs.swapSize); console.log(" Qty Input Output Qty Out Rate Output Rate Diff Arb$"); await rates_utils_1.getSwapRates(fpAssets, fpAssets, feederPool, block.blockNumber, quantityFormatter, network.name, swapSize); await rates_utils_1.getSwapRates([fAsset], mpAssets, feederPool, block.blockNumber, quantityFormatter, network.name, swapSize); await rates_utils_1.getSwapRates(mpAssets, [fAsset], feederPool, block.blockNumber, quantityFormatter, network.name, swapSize); await snap_utils_1.snapConfig(feederPool, block.blockNumber); }); config_1.task("frax-post-deploy", "Mint FRAX Feeder Pool").setAction(async (_, { ethers }) => { const signer = await defender_utils_1.getSigner(ethers); const frax = generated_1.ERC20__factory.connect(tokens_1.PFRAX.address, signer); const fraxFp = generated_1.FeederPool__factory.connect(tokens_1.PFRAX.feederPool, signer); const musd = await generated_1.IERC20__factory.connect(tokens_1.PmUSD.address, signer); const approveAmount = math_1.simpleToExactAmount(100); const bAssetAmount = math_1.simpleToExactAmount(10); const minAmount = math_1.simpleToExactAmount(9); let tx = await frax.approve(tokens_1.PFRAX.feederPool, approveAmount); await utils_2.logTxDetails(tx, "approve FRAX"); tx = await musd.approve(tokens_1.PFRAX.feederPool, approveAmount); await utils_2.logTxDetails(tx, "approve mUSD"); tx = await fraxFp.mintMulti([tokens_1.PFRAX.address, tokens_1.PmUSD.address], [bAssetAmount, bAssetAmount], minAmount, await signer.getAddress()); await utils_2.logTxDetails(tx, "mint FRAX FP"); }); config_1.task("feeder-mint", "Mint some Feeder Pool tokens") .addOptionalParam("amount", "Amount of the mAsset and fAsset to deposit", undefined, config_1.types.int) .addParam("fasset", "Token symbol of the feeder pool asset. eg HBTC, GUSD, PFRAX or alUSD", undefined, config_1.types.string) .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, { ethers, network }) => { const chain = networkAddressFactory_1.getChain(network.name); const signer = await defender_utils_1.getSigner(ethers, taskArgs.speed); const signerAddress = await signer.getAddress(); const fAssetSymbol = taskArgs.fasset; const feederPoolToken = tokens_1.tokens.find((t) => t.symbol === fAssetSymbol && t.chain === chain); if (!feederPoolToken) throw Error(`Could not find feeder pool asset token with symbol ${fAssetSymbol}`); if (!feederPoolToken.feederPool) throw Error(`No feeder pool configured for token ${fAssetSymbol}`); const mAssetSymbol = feederPoolToken.parent; if (!mAssetSymbol) throw Error(`No parent mAsset configured for feeder pool asset ${mAssetSymbol}`); const mAssetToken = tokens_1.tokens.find((t) => t.symbol === mAssetSymbol && t.chain === chain); if (!mAssetToken) throw Error(`Could not find mAsset token with symbol ${mAssetToken}`); const fp = generated_1.FeederPool__factory.connect(feederPoolToken.feederPool, signer); const fpSymbol = await fp.symbol(); const mintAmount = math_1.simpleToExactAmount(taskArgs.amount); // mint Feeder Pool tokens const tx = await fp.mintMulti([mAssetToken.address, feederPoolToken.address], [mintAmount, mintAmount], 0, signerAddress); await utils_2.logTxDetails(tx, `Mint ${fpSymbol} from ${utils_1.formatUnits(mintAmount)} ${mAssetSymbol} and ${utils_1.formatUnits(mintAmount)} ${fAssetSymbol}`); }); config_1.task("feeder-redeem", "Redeem some Feeder Pool tokens") .addParam("fasset", "Token symbol of the feeder pool asset. eg HBTC, GUSD, PFRAX or alUSD", undefined, config_1.types.string) .addParam("amount", "Amount of the feeder pool liquidity tokens to proportionately redeem", undefined, config_1.types.int) .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, { ethers, network }) => { const chain = networkAddressFactory_1.getChain(network.name); const signer = await defender_utils_1.getSigner(ethers, taskArgs.speed); const signerAddress = await signer.getAddress(); const fAssetSymbol = taskArgs.fasset; const feederPoolToken = tokens_1.tokens.find((t) => t.symbol === fAssetSymbol && t.chain === chain); if (!feederPoolToken) throw Error(`Could not find feeder pool asset token with symbol ${fAssetSymbol}`); if (!feederPoolToken.feederPool) throw Error(`No feeder pool configured for token ${fAssetSymbol}`); const fp = generated_1.FeederPool__factory.connect(feederPoolToken.feederPool, signer); const fpSymbol = await fp.symbol(); const fpAmount = math_1.simpleToExactAmount(taskArgs.amount); const minBassetAmount = fpAmount.mul(40).div(100); // min 40% for each bAsset // redeem Feeder Pool tokens const tx = await fp.redeemProportionately(fpAmount, [minBassetAmount, minBassetAmount], signerAddress); await utils_2.logTxDetails(tx, `Redeem ${fpSymbol} from ${utils_1.formatUnits(fpAmount)}`); }); config_1.task("feeder-swap", "Swap some Feeder Pool tokens") .addParam("input", "Token symbol of the input token to the swap. eg mUSD, PmUSD, mBTC, HBTC, GUSD, PFRAX or alUSD", undefined, config_1.types.string) .addParam("output", "Token symbol of the output token from the swap. eg mUSD, PmUSD, mBTC, HBTC, GUSD, PFRAX or alUSD", undefined, config_1.types.string) .addParam("amount", "Amount of input tokens to swap", undefined, config_1.types.int) .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", config_1.types.string) .setAction(async (taskArgs, { ethers, network }) => { const chain = networkAddressFactory_1.getChain(network.name); const signer = await defender_utils_1.getSigner(ethers, taskArgs.speed); const signerAddress = await signer.getAddress(); const inputSymbol = taskArgs.input; const inputToken = tokens_1.tokens.find((t) => t.symbol === inputSymbol && t.chain === chain); if (!inputToken) throw Error(`Could not find input asset token with symbol ${inputSymbol}`); const outputSymbol = taskArgs.output; const outputToken = tokens_1.tokens.find((t) => t.symbol === outputSymbol && t.chain === chain); if (!outputToken) throw Error(`Could not find output asset token with symbol ${outputSymbol}`); let fp; if (inputToken.feederPool && !outputToken.feederPool) { fp = generated_1.FeederPool__factory.connect(inputToken.feederPool, signer); } else if (!inputToken.feederPool && outputToken.feederPool) { fp = generated_1.FeederPool__factory.connect(outputToken.feederPool, signer); } else { throw Error(`Could not find Feeder Pool for input ${inputSymbol} and output ${outputSymbol}`); } const fpSymbol = await fp.symbol(); const inputAmount = math_1.simpleToExactAmount(taskArgs.amount); const minOutputAmount = inputAmount.mul(90).div(100); // min 90% of the input const tx = await fp.swap(inputToken.address, outputToken.address, inputAmount, minOutputAmount, signerAddress); await utils_2.logTxDetails(tx, `swap ${utils_1.formatUnits(inputAmount)} ${inputSymbol} for ${outputSymbol} using ${fpSymbol} Feeder Pool`); }); module.exports = {}; //# sourceMappingURL=feeder.js.map