-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Meta morpho scripts #1098
Merged
Merged
Meta morpho scripts #1098
Changes from 10 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
566bcce
meta-morpho/README.md
tbrent 87e34a9
initial USDC/ETH/WBTC-supporting implementations
tbrent 1a8cbce
new structure for better inheritance
tbrent c6fb3a5
refine approach and get tests for 4 vaults passing
tbrent 11357bf
deploy scripts
tbrent 861c89c
verification scripts
tbrent 36a7981
adjust maxTradeVolume for smaller vaults
tbrent ed1f34f
add comment
tbrent 6ccf0dc
fix test
tbrent 8da89a2
Merge branch 'meta-morpho' into meta-morpho-scripts
tbrent 2775287
Merge branch '3.4.0' into meta-morpho-scripts
tbrent 86ace8a
decrease maxTradeVolume for bbUSDT and steakPYUSD
tbrent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,41 @@ | ||
// SPDX-License-Identifier: BlueOak-1.0.0 | ||
pragma solidity 0.8.19; | ||
|
||
// solhint-disable-next-line max-line-length | ||
import { Asset, AppreciatingFiatCollateral, CollateralConfig, IRewardable } from "./AppreciatingFiatCollateral.sol"; | ||
import { OracleLib } from "./OracleLib.sol"; | ||
// solhint-disable-next-line max-line-length | ||
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | ||
import { IERC4626 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; | ||
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; | ||
import { shiftl_toFix } from "../../libraries/Fixed.sol"; | ||
|
||
/** | ||
* @title ERC4626FiatCollateral | ||
* @notice Collateral plugin for a ERC4626 vault | ||
* | ||
* Warning: Only valid for linear ERC4626 vaults | ||
*/ | ||
contract ERC4626FiatCollateral is AppreciatingFiatCollateral { | ||
uint256 private immutable oneShare; | ||
int8 private immutable refDecimals; | ||
|
||
/// config.erc20 must be a MetaMorpho ERC4626 vault | ||
/// @param config.chainlinkFeed Feed units: {UoA/ref} | ||
/// @param revenueHiding {1} A value like 1e-6 that represents the maximum refPerTok to hide | ||
constructor(CollateralConfig memory config, uint192 revenueHiding) | ||
AppreciatingFiatCollateral(config, revenueHiding) | ||
{ | ||
require(address(config.erc20) != address(0), "missing erc20"); | ||
// require(config.defaultThreshold > 0, "defaultThreshold zero"); | ||
IERC4626 vault = IERC4626(address(config.erc20)); | ||
oneShare = 10**vault.decimals(); | ||
refDecimals = int8(uint8(IERC20Metadata(vault.asset()).decimals())); | ||
} | ||
|
||
/// @return {ref/tok} Actual quantity of whole reference units per whole collateral tokens | ||
function underlyingRefPerTok() public view override returns (uint192) { | ||
// already accounts for fees to be taken out | ||
return shiftl_toFix(IERC4626(address(erc20)).convertToAssets(oneShare), -refDecimals); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
contracts/plugins/assets/meta-morpho/MetaMorphoFiatCollateral.sol
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,23 @@ | ||
// SPDX-License-Identifier: BlueOak-1.0.0 | ||
pragma solidity 0.8.19; | ||
|
||
import { CollateralConfig } from "../AppreciatingFiatCollateral.sol"; | ||
import { ERC4626FiatCollateral } from "../ERC4626FiatCollateral.sol"; | ||
|
||
/** | ||
* @title MetaMorphoFiatCollateral | ||
* @notice Collateral plugin for a MetaMorpho vault with fiat collateral, like USDC or USDT | ||
* Expected: {tok} != {ref}, {ref} is pegged to {target} unless defaulting, {target} == {UoA} | ||
* | ||
* For example: steakUSDC, steakPYUSD, bbUSDT | ||
*/ | ||
contract MetaMorphoFiatCollateral is ERC4626FiatCollateral { | ||
/// config.erc20 must be a MetaMorpho ERC4626 vault | ||
/// @param config.chainlinkFeed Feed units: {UoA/ref} | ||
/// @param revenueHiding {1} A value like 1e-6 that represents the maximum refPerTok to hide | ||
constructor(CollateralConfig memory config, uint192 revenueHiding) | ||
ERC4626FiatCollateral(config, revenueHiding) | ||
{ | ||
require(config.defaultThreshold > 0, "defaultThreshold zero"); | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
contracts/plugins/assets/meta-morpho/MetaMorphoSelfReferentialCollateral.sol
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,55 @@ | ||
// SPDX-License-Identifier: BlueOak-1.0.0 | ||
pragma solidity 0.8.19; | ||
|
||
// solhint-disable-next-line max-line-length | ||
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | ||
import { CollateralConfig } from "../AppreciatingFiatCollateral.sol"; | ||
import { FixLib, CEIL } from "../../../libraries/Fixed.sol"; | ||
import { OracleLib } from "../OracleLib.sol"; | ||
import { ERC4626FiatCollateral } from "../ERC4626FiatCollateral.sol"; | ||
|
||
/** | ||
* @title MetaMorphoSelfReferentialCollateral | ||
* @notice Collateral plugin for a MetaMorpho vault with self referential collateral, like WETH | ||
* Expected: {tok} == {ref}, {ref} == {target}, {target} != {UoA} | ||
* | ||
* For example: Re7WETH | ||
*/ | ||
contract MetaMorphoSelfReferentialCollateral is ERC4626FiatCollateral { | ||
using FixLib for uint192; | ||
using OracleLib for AggregatorV3Interface; | ||
|
||
/// config.erc20 must be a MetaMorpho ERC4626 vault | ||
/// @param config.chainlinkFeed Feed units: {UoA/ref} | ||
/// @param revenueHiding {1} A value like 1e-6 that represents the maximum refPerTok to hide | ||
constructor(CollateralConfig memory config, uint192 revenueHiding) | ||
ERC4626FiatCollateral(config, revenueHiding) | ||
{ | ||
// require(config.defaultThreshold > 0, "defaultThreshold zero"); | ||
} | ||
|
||
/// Can revert, used by other contract functions in order to catch errors | ||
/// @return low {UoA/tok} The low price estimate | ||
/// @return high {UoA/tok} The high price estimate | ||
/// @return pegPrice {target/ref} | ||
function tryPrice() | ||
external | ||
view | ||
override | ||
returns ( | ||
uint192 low, | ||
uint192 high, | ||
uint192 pegPrice | ||
) | ||
{ | ||
// {UoA/tok} = {UoA/ref} * {ref/tok} | ||
uint192 p = chainlinkFeed.price(oracleTimeout).mul(underlyingRefPerTok()); | ||
uint192 err = p.mul(oracleError, CEIL); | ||
|
||
low = p - err; | ||
high = p + err; | ||
// assert(low <= high); obviously true just by inspection | ||
|
||
pegPrice = targetPerRef(); | ||
} | ||
} |
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,27 @@ | ||
# MetaMorpho | ||
|
||
Morpho Blue is a permisionless lending protocol. At the time of this writing (March 19th, 2024), the only way to deposit is through something called **MetaMorpho**: (somewhat) managed ERC4626 vaults. Our integration with these tokens is straightforward with the exception of reward claiming, which occurs via supplying a merkle proof. This can be done permisionlessly and without interacting with any of our contracts, so any interaction with rewards is omitted here. The expectation is -- _and this is important to emphasize_ -- **any MORPHO reward claiming is left up to the RToken community to cause**. | ||
|
||
## Up-only-ness | ||
|
||
MetaMorpho suffers from a similar to that of the Curve volatile pools which can lose assets on admin fee claim. | ||
|
||
## Target tokens | ||
|
||
**USD** | ||
| Name | Symbol | Address | Reward Tokens | | ||
| -- | -- | -- | -- | | ||
| Steakhouse USDC | steakUSDC| 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB | wstETH, MORPHO | | ||
| Steakhouse PYSUD | steakPYUSD | 0xbEEF02e5E13584ab96848af90261f0C8Ee04722a | MORPHO | | ||
| Flagship USDT | bbUSDT| 0x2C25f6C25770fFEC5959D34B94Bf898865e5D6b1 | MORPHO | | ||
|
||
**ETH** | ||
|
||
| Name | Symbol | Address | Reward Tokens | | ||
| -------- | ------- | ------------------------------------------ | --------------------------- | | ||
| Re7 WETH | Re7WETH | 0x78Fc2c2eD1A4cDb5402365934aE5648aDAd094d0 | USDC, SWISE, BTRFLY, MORPHO | | ||
|
||
## Future Work | ||
|
||
- Assets need to exist for each of the Reward Tokens, which requires oracles. Only USDC meets this bar; SWISE, BTRFLY, and MORPHO do not have oracles yet. | ||
- The right reward token assets need to be registered for an RToken as a function of their collateral. This can be done using the above table. |
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,47 @@ | ||
// SPDX-License-Identifier: BlueOak-1.0.0 | ||
pragma solidity 0.8.19; | ||
|
||
import { IERC4626 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; | ||
import "@openzeppelin/contracts/utils/Address.sol"; | ||
import "../../libraries/Fixed.sol"; | ||
|
||
// Simple pass-through wrapper for real MetaMorpho ERC4626 vaults | ||
// Allows settable asset count for testing | ||
contract MockMetaMorpho4626 { | ||
using FixLib for uint192; | ||
|
||
IERC4626 public immutable actual; // the real ERC4626 vault | ||
|
||
uint192 public multiplier = FIX_ONE; | ||
|
||
// solhint-disable-next-line no-empty-blocks | ||
constructor(IERC4626 _actual) { | ||
actual = _actual; | ||
} | ||
|
||
function applyMultiple(uint192 multiple) external { | ||
multiplier = multiplier.mul(multiple); | ||
} | ||
|
||
// === Pass-throughs === | ||
|
||
function balanceOf(address account) external view returns (uint256) { | ||
return actual.balanceOf(account); | ||
} | ||
|
||
function asset() external view returns (address) { | ||
return actual.asset(); | ||
} | ||
|
||
function decimals() external view returns (uint8) { | ||
return actual.decimals(); | ||
} | ||
|
||
function convertToAssets(uint256 amount) external view returns (uint256) { | ||
return multiplier.mulu_toUint(actual.convertToAssets(amount), CEIL); | ||
} | ||
|
||
function totalAssets() public view returns (uint256) { | ||
return multiplier.mulu_toUint(actual.totalAssets(), CEIL); | ||
} | ||
} |
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
91 changes: 91 additions & 0 deletions
91
scripts/deployment/phase2-assets/collaterals/deploy_bbusdt.ts
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,91 @@ | ||
import fs from 'fs' | ||
import hre from 'hardhat' | ||
import { getChainId } from '../../../../common/blockchain-utils' | ||
import { networkConfig } from '../../../../common/configuration' | ||
import { fp } from '../../../../common/numbers' | ||
import { expect } from 'chai' | ||
import { CollateralStatus } from '../../../../common/constants' | ||
import { | ||
getDeploymentFile, | ||
getAssetCollDeploymentFilename, | ||
IAssetCollDeployments, | ||
getDeploymentFilename, | ||
fileExists, | ||
} from '../../common' | ||
import { | ||
USDT_ORACLE_TIMEOUT, | ||
USDT_ORACLE_ERROR, | ||
USDT_USD_FEED, | ||
PRICE_TIMEOUT, | ||
DELAY_UNTIL_DEFAULT, | ||
} from '../../../../test/plugins/individual-collateral/meta-morpho/constants' | ||
import { MetaMorphoFiatCollateral } from '../../../../typechain' | ||
import { ContractFactory } from 'ethers' | ||
|
||
async function main() { | ||
// ==== Read Configuration ==== | ||
const [deployer] = await hre.ethers.getSigners() | ||
|
||
const chainId = await getChainId(hre) | ||
|
||
console.log(`Deploying Collateral to network ${hre.network.name} (${chainId}) | ||
with burner account: ${deployer.address}`) | ||
|
||
if (!networkConfig[chainId]) { | ||
throw new Error(`Missing network configuration for ${hre.network.name}`) | ||
} | ||
|
||
// Get phase1 deployment | ||
const phase1File = getDeploymentFilename(chainId) | ||
if (!fileExists(phase1File)) { | ||
throw new Error(`${phase1File} doesn't exist yet. Run phase 1`) | ||
} | ||
// Check previous step completed | ||
const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) | ||
const assetCollDeployments = <IAssetCollDeployments>getDeploymentFile(assetCollDeploymentFilename) | ||
|
||
const deployedCollateral: string[] = [] | ||
|
||
/******** Deploy MetaMorpho Flagship USDT - bbUSDT **************************/ | ||
|
||
const MetaMorphoFiatCollateralFactory: ContractFactory = await hre.ethers.getContractFactory( | ||
'MetaMorphoFiatCollateral' | ||
) | ||
|
||
const collateral = <MetaMorphoFiatCollateral>await MetaMorphoFiatCollateralFactory.connect( | ||
deployer | ||
).deploy( | ||
{ | ||
priceTimeout: PRICE_TIMEOUT.toString(), | ||
chainlinkFeed: USDT_USD_FEED, | ||
oracleError: USDT_ORACLE_ERROR.toString(), | ||
erc20: networkConfig[chainId].tokens.bbUSDT, | ||
maxTradeVolume: fp('1e6').toString(), // $7.5m vault | ||
oracleTimeout: USDT_ORACLE_TIMEOUT.toString(), | ||
targetName: hre.ethers.utils.formatBytes32String('USD'), | ||
defaultThreshold: USDT_ORACLE_ERROR.add(fp('0.01')).toString(), // +1% buffer rule | ||
delayUntilDefault: DELAY_UNTIL_DEFAULT.toString(), | ||
}, | ||
fp('1e-6') // small admin fee uncertainty | ||
) | ||
await collateral.deployed() | ||
|
||
console.log(`Deployed bbUSDT to ${hre.network.name} (${chainId}): ${collateral.address}`) | ||
await (await collateral.refresh()).wait() | ||
expect(await collateral.status()).to.equal(CollateralStatus.SOUND) | ||
|
||
assetCollDeployments.collateral.bbUSDT = collateral.address | ||
assetCollDeployments.erc20s.bbUSDT = networkConfig[chainId].tokens.bbUSDT | ||
deployedCollateral.push(collateral.address.toString()) | ||
|
||
fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2)) | ||
|
||
console.log(`Deployed collateral to ${hre.network.name} (${chainId}) | ||
New deployments: ${deployedCollateral} | ||
Deployment file: ${assetCollDeploymentFilename}`) | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error) | ||
process.exitCode = 1 | ||
}) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should be using much smaller numbers for this. The vaults are currently too small to sustain these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I think $500k can make sense, but much lower and things become unusable on mainnet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And <$500k for pyUSD, since it has $1.7m vault
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good to me. Probably $250k for smaller vaults and $500k for every other.