-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
post launch and mBTC snap task (#125)
- Loading branch information
1 parent
7b29b58
commit cabb395
Showing
8 changed files
with
379 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
pragma solidity 0.8.0; | ||
|
||
contract DeadToken { | ||
uint8 private _decimals = 18; | ||
|
||
function decimals() public view returns (uint8) { | ||
return _decimals; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { hardhatConfig } from "./hardhat.config" | ||
import "./tasks/deployMbtc" | ||
import "./tasks/mBTC" | ||
|
||
export default hardhatConfig |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
/* eslint-disable no-await-in-loop */ | ||
/* eslint-disable no-restricted-syntax */ | ||
/* eslint-disable no-console */ | ||
import { btcBassets, capFactor, contracts, getBassetFromAddress, startingCap } from "@utils/btcConstants" | ||
import { fullScale, ONE_DAY } from "@utils/constants" | ||
import { applyDecimals, applyRatio, BN, simpleToExactAmount } from "@utils/math" | ||
import { Signer } from "ethers" | ||
import { formatUnits } from "ethers/lib/utils" | ||
import { task } from "hardhat/config" | ||
import { InvariantValidator__factory, Masset, Masset__factory } from "types/generated" | ||
|
||
interface TxSummary { | ||
total: BN | ||
fees: BN | ||
} | ||
|
||
const getTvlCap = async (signer: Signer): Promise<BN> => { | ||
const validator = await new InvariantValidator__factory(signer).attach(contracts.mainnet.InvariantValidator) | ||
const tvlStartTime = await validator.startTime() | ||
const weeksSinceLaunch = BN.from(Date.now()).div(1000).sub(tvlStartTime).mul(fullScale).div(604800) | ||
// // e.g. 1e19 + (15e18 * 2.04e36) = 1e19 + 3.06e55 | ||
// // startingCap + (capFactor * weeksSinceLaunch**2 / 1e36); | ||
return startingCap.add(capFactor.mul(weeksSinceLaunch.pow(2)).div(fullScale.pow(2))) | ||
} | ||
|
||
const getBasket = async (mBtc: Masset, signer: Signer) => { | ||
const tvlCap = await getTvlCap(signer) | ||
|
||
const bAssets = await mBtc.getBassets() | ||
const bAssetTotals: BN[] = [] | ||
let totalBassets = BN.from(0) | ||
btcBassets.forEach((_, i) => { | ||
const scaledBassetQuantity = applyRatio(bAssets[1][i].vaultBalance, bAssets[1][i].ratio) | ||
bAssetTotals.push(scaledBassetQuantity) | ||
totalBassets = totalBassets.add(scaledBassetQuantity) | ||
}) | ||
|
||
console.log("\nmBTC basket") | ||
btcBassets.forEach((bAsset, i) => { | ||
const percentage = bAssetTotals[i].mul(100).div(totalBassets) | ||
console.log(`${bAsset.symbol.padEnd(7)} ${formatUnits(bAssetTotals[i]).padEnd(20)} ${percentage.toString().padStart(2)}%`) | ||
}) | ||
const surplus = await mBtc.surplus() | ||
console.log(`Surplus ${formatUnits(surplus)}`) | ||
const tvlCapPercentage = totalBassets.mul(100).div(tvlCap) | ||
console.log(`Total ${formatUnits(totalBassets).padStart(21)}`) | ||
console.log(`TVL cap ${formatUnits(tvlCap).padStart(21)} ${tvlCapPercentage}%`) | ||
} | ||
|
||
const getSwapRates = async (mBTC: Masset) => { | ||
console.log("\nSwap rates") | ||
for (const inputToken of btcBassets) { | ||
for (const outputToken of btcBassets) { | ||
if (inputToken.symbol !== outputToken.symbol) { | ||
const inputAddress = contracts.mainnet[inputToken.symbol] | ||
const outputAddress = contracts.mainnet[outputToken.symbol] | ||
try { | ||
const inputStr = "0.1" | ||
const input = simpleToExactAmount(inputStr, inputToken.decimals) | ||
const output = await mBTC.getSwapOutput(inputAddress, outputAddress, input) | ||
const scaledInput = applyDecimals(input, inputToken.decimals) | ||
const scaledOutput = applyDecimals(output, outputToken.decimals) | ||
const percent = scaledOutput.sub(scaledInput).mul(1000).div(scaledInput) | ||
console.log( | ||
`${inputStr} ${inputToken.symbol.padEnd(6)} -> ${outputToken.symbol.padEnd(6)} ${formatUnits( | ||
output, | ||
outputToken.decimals, | ||
).padEnd(21)} ${percent.toString().padStart(4)}bps`, | ||
) | ||
} catch (err) { | ||
console.error(`${inputToken.symbol} -> ${outputToken.symbol} ${err.message}`) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
const getBalances = async (mBTC: Masset) => { | ||
const mBtcBalance = await mBTC.totalSupply() | ||
const savingBalance = await mBTC.balanceOf(contracts.mainnet.imBTC) | ||
const sushiPoolBalance = await mBTC.balanceOf(contracts.mainnet.sushiPool) | ||
const mStableFundManagerBalance = await mBTC.balanceOf(contracts.mainnet.fundManager) | ||
const otherBalances = mBtcBalance.sub(savingBalance).sub(sushiPoolBalance).sub(mStableFundManagerBalance) | ||
|
||
console.log("\nmBTC Holders") | ||
console.log(`imBTC ${formatUnits(savingBalance).padEnd(20)} ${savingBalance.mul(100).div(mBtcBalance)}%`) | ||
console.log(`Sushi Pool ${formatUnits(sushiPoolBalance).padEnd(20)} ${sushiPoolBalance.mul(100).div(mBtcBalance)}%`) | ||
console.log( | ||
`mStable Fund Manager ${formatUnits(mStableFundManagerBalance).padEnd(20)} ${mStableFundManagerBalance.mul(100).div(mBtcBalance)}%`, | ||
) | ||
console.log(`Others ${formatUnits(otherBalances).padEnd(20)} ${otherBalances.mul(100).div(mBtcBalance)}%`) | ||
} | ||
|
||
const getMints = async (mBTC: Masset, currentBlock: number): Promise<TxSummary> => { | ||
const filter = await mBTC.filters.Minted(null, null, null, null, null) | ||
const logs = await mBTC.queryFilter(filter, currentBlock - ONE_DAY.toNumber()) | ||
|
||
console.log("\nMints in last 24 hours") | ||
console.log("Block#\t Minter\t\t\t\t\t bAsset Masset Quantity") | ||
let total = BN.from(0) | ||
let count = 0 | ||
logs.forEach((log) => { | ||
const inputBasset = getBassetFromAddress(log.args.input) | ||
console.log(`${log.blockNumber} ${log.args.minter} ${inputBasset.symbol.padEnd(6)} ${formatUnits(log.args.mAssetQuantity)}`) | ||
total = total.add(log.args.mAssetQuantity) | ||
count += 1 | ||
}) | ||
console.log(`Count ${count}, Total ${formatUnits(total)}`) | ||
return { | ||
total, | ||
fees: BN.from(0), | ||
} | ||
} | ||
|
||
const getRedemptions = async (mBTC: Masset, currentBlock: number): Promise<TxSummary> => { | ||
const filter = await mBTC.filters.Redeemed(null, null, null, null, null, null) | ||
const logs = await mBTC.queryFilter(filter, currentBlock - ONE_DAY.toNumber()) | ||
|
||
console.log("\nRedemptions in last 24 hours") | ||
console.log("Block#\t Redeemer\t\t\t\t bAsset Masset Quantity\tFee") | ||
let total = BN.from(0) | ||
let fees = BN.from(0) | ||
let count = 0 | ||
logs.forEach((log) => { | ||
const outputBasset = getBassetFromAddress(log.args.output) | ||
console.log( | ||
`${log.blockNumber} ${log.args.redeemer} ${outputBasset.symbol.padEnd(6)} ${formatUnits(log.args.mAssetQuantity)} ${formatUnits( | ||
log.args.scaledFee, | ||
)}`, | ||
) | ||
total = total.add(log.args.mAssetQuantity) | ||
fees = fees.add(log.args.scaledFee) | ||
count += 1 | ||
}) | ||
console.log(`Count ${count}, Total ${formatUnits(total)}`) | ||
|
||
return { | ||
total, | ||
fees, | ||
} | ||
} | ||
|
||
const getSwaps = async (mBTC: Masset, currentBlock: number): Promise<TxSummary> => { | ||
const filter = await mBTC.filters.Swapped(null, null, null, null, null, null) | ||
const logs = await mBTC.queryFilter(filter, currentBlock - ONE_DAY.toNumber()) | ||
|
||
console.log("\nSwaps in last 24 hours") | ||
console.log("Block#\t Swapper\t\t\t\t Input Output Output Quantity\tFee") | ||
// Scaled bAsset quantities | ||
let total = BN.from(0) | ||
let fees = BN.from(0) | ||
let count = 0 | ||
logs.forEach((log) => { | ||
const inputBasset = getBassetFromAddress(log.args.input) | ||
const outputBasset = getBassetFromAddress(log.args.output) | ||
console.log( | ||
`${log.blockNumber} ${log.args.swapper} ${inputBasset.symbol.padEnd(6)} ${outputBasset.symbol.padEnd(6)} ${formatUnits( | ||
log.args.outputAmount, | ||
outputBasset.decimals, | ||
).padEnd(21)} ${formatUnits(log.args.scaledFee)}`, | ||
) | ||
total = total.add(applyDecimals(log.args.outputAmount, outputBasset.decimals)) | ||
fees = fees.add(log.args.scaledFee) | ||
count += 1 | ||
}) | ||
console.log(`Count ${count}, Total ${formatUnits(total)}`) | ||
|
||
return { | ||
total, | ||
fees, | ||
} | ||
} | ||
|
||
const outputFees = (mints: TxSummary, swaps: TxSummary, redeems: TxSummary, totalSupply: BN) => { | ||
const totalFees = redeems.fees.add(swaps.fees) | ||
const totalTotals = mints.total.add(redeems.total).add(swaps.total) | ||
console.log("\nFees in the last 24 hours") | ||
console.log(" mBTC Volume\t Fees\t\t Fee %") | ||
console.log( | ||
`Mints ${formatUnits(mints.total).padEnd(22)} ${formatUnits(mints.fees).padEnd(20)} ${mints.fees.mul(100).div(totalFees)}%`, | ||
) | ||
console.log( | ||
`Redeem ${formatUnits(redeems.total).padEnd(22)} ${formatUnits(redeems.fees).padEnd(20)} ${redeems.fees.mul(100).div(totalFees)}%`, | ||
) | ||
console.log( | ||
`Swap ${formatUnits(swaps.total).padEnd(22)} ${formatUnits(swaps.fees).padEnd(20)} ${swaps.fees.mul(100).div(totalFees)}%`, | ||
) | ||
const totalApy = totalFees.mul(36500).div(totalSupply) | ||
console.log(`Total ${formatUnits(totalTotals).padEnd(22)} ${formatUnits(totalFees).padEnd(20)} APY ${totalApy}%`) | ||
} | ||
|
||
task("mBTC-snap", "Get the latest data from the mBTC contracts").setAction(async (_, hre) => { | ||
const { ethers } = hre | ||
|
||
const [signer] = await ethers.getSigners() | ||
|
||
const linkedAddress = { | ||
__$1a38b0db2bd175b310a9a3f8697d44eb75$__: contracts.mainnet.Manager, | ||
} | ||
const mBtc = await new Masset__factory(linkedAddress, signer).attach(contracts.mainnet.mBTC) | ||
|
||
const currentBlock = await hre.ethers.provider.getBlockNumber() | ||
console.log(`Latest block ${currentBlock}, ${new Date().toUTCString()}`) | ||
|
||
await getBasket(mBtc, signer) | ||
await getBalances(mBtc) | ||
await getSwapRates(mBtc) | ||
|
||
const mintSummary = await getMints(mBtc, currentBlock) | ||
const redeemSummary = await getRedemptions(mBtc, currentBlock) | ||
const swapSummary = await getSwaps(mBtc, currentBlock) | ||
|
||
const totalSupply = await mBtc.totalSupply() | ||
outputFees(mintSummary, swapSummary, redeemSummary, totalSupply) | ||
}) | ||
|
||
module.exports = {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.