Skip to content

Commit

Permalink
feat: script to setup Morpho markets
Browse files Browse the repository at this point in the history
  • Loading branch information
sogipec committed Apr 3, 2024
1 parent f3e53e6 commit 2bdc35c
Show file tree
Hide file tree
Showing 9 changed files with 693 additions and 12 deletions.
362 changes: 362 additions & 0 deletions contracts/interfaces/external/morpho/IMorpho.sol

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions contracts/interfaces/external/morpho/IMorphoChainlinkOracleV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title IMorphoChainlinkOracleV2Factory
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Interface for MorphoChainlinkOracleV2Factory
interface IMorphoChainlinkOracleV2Factory {
/// @notice Emitted when a new Chainlink oracle is created.
/// @param oracle The address of the Chainlink oracle.
/// @param caller The caller of the function.
event CreateMorphoChainlinkOracleV2(address caller, address oracle);

/// @notice Whether a Chainlink oracle vault was created with the factory.
function isMorphoChainlinkOracleV2(address target) external view returns (bool);

/// @dev Here is the list of assumptions that guarantees the oracle behaves as expected:
/// - The vaults, if set, are ERC4626-compliant.
/// - The feeds, if set, are Chainlink-interface-compliant.
/// - Decimals passed as argument are correct.
/// - The base vaults's sample shares quoted as assets and the base feed prices don't overflow when multiplied.
/// - The quote vault's sample shares quoted as assets and the quote feed prices don't overflow when multiplied.
/// @param baseVault Base vault. Pass address zero to omit this parameter.
/// @param baseVaultConversionSample The sample amount of base vault shares used to convert to underlying.
/// Pass 1 if the base asset is not a vault. Should be chosen such that converting `baseVaultConversionSample` to
/// assets has enough precision.
/// @param baseFeed1 First base feed. Pass address zero if the price = 1.
/// @param baseFeed2 Second base feed. Pass address zero if the price = 1.
/// @param baseTokenDecimals Base token decimals.
/// @param quoteVault Quote vault. Pass address zero to omit this parameter.
/// @param quoteVaultConversionSample The sample amount of quote vault shares used to convert to underlying.
/// Pass 1 if the quote asset is not a vault. Should be chosen such that converting `quoteVaultConversionSample` to
/// assets has enough precision.
/// @param quoteFeed1 First quote feed. Pass address zero if the price = 1.
/// @param quoteFeed2 Second quote feed. Pass address zero if the price = 1.
/// @param quoteTokenDecimals Quote token decimals.
/// @param salt The salt to use for the CREATE2.
/// @dev The base asset should be the collateral token and the quote asset the loan token.
function createMorphoChainlinkOracleV2(
address baseVault,
uint256 baseVaultConversionSample,
address baseFeed1,
address baseFeed2,
uint256 baseTokenDecimals,
address quoteVault,
uint256 quoteVaultConversionSample,
address quoteFeed1,
address quoteFeed2,
uint256 quoteTokenDecimals,
bytes32 salt
) external returns (address oracle);
}

interface IMorphoOracle {
/// @notice Returns the price of 1 asset of collateral token quoted in 1 asset of loan token, scaled by 1e36.
/// @dev It corresponds to the price of 10**(collateral token decimals) assets of collateral token quoted in
/// 10**(loan token decimals) assets of loan token with `36 + loan token decimals - collateral token decimals`
/// decimals of precision.
function price() external view returns (uint256);
}
46 changes: 46 additions & 0 deletions helpers/fork.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#! /bin/bash

source lib/utils/helpers/common.sh

function main {
if [ ! -f .env ]; then
echo ".env not found!"
exit 1
fi
source .env

echo "Which chain would you like to fork ?"
echo "- 1: Ethereum Mainnet"
echo "- 2: Arbitrum"
echo "- 3: Polygon"
echo "- 4: Gnosis"
echo "- 5: Avalanche"
echo "- 6: Base"
echo "- 7: Binance Smart Chain"
echo "- 8: Celo"
echo "- 9: Polygon ZkEvm"
echo "- 10: Optimism"
echo "- 11: Linea"

read option

uri=$(chain_to_uri $option)
if [ -z "$uri" ]; then
echo "Unknown network"
exit 1
fi

echo "What block do you want to fork ? (Can leave empty for instant)"

read block

if [ -z "$block" ]; then
echo "Forking $uri"
anvil --fork-url $uri
else
echo "Forking $uri at block $block"
anvil --fork-url $uri --fork-block-number $block
fi
}

main
1 change: 1 addition & 0 deletions lib/pendle-core-v2-public
Submodule pendle-core-v2-public added at fb0fcc
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"coverage": "hardhat coverage",
"coverage:foundry": "forge coverage --report lcov",
"deploy": "hardhat deploy --tags newOracle --network ",
"fork": "bash helpers/fork.sh",
"script:fork": "FOUNDRY_PROFILE=dev forge script --skip test --fork-url fork --broadcast -vvvv",
"etherscan": "hardhat etherscan-verify --network",
"foundry:deploy": "forge script --broadcast --verify -vvvv --rpc-url",
"generate-types-from-abis": "typechain --target ethers-v5 --out-dir typechain './export/abi/*.json'",
Expand Down
20 changes: 20 additions & 0 deletions scripts/addGovernor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ChainId, registry } from '@angleprotocol/sdk';
import { deployments, ethers, network } from 'hardhat';

import { CoreBorrow, CoreBorrow__factory } from '../typechain';

async function main() {
const { deployer } = await ethers.getNamedSigners();
const coreBorrowAddress = (await deployments.get('CoreBorrowTest')).address
const newGovernor = registry(network.config.chainId as ChainId)?.Governor!

const coreBorrow = new ethers.Contract(coreBorrowAddress, CoreBorrow__factory.createInterface(), deployer) as CoreBorrow;
console.log("Adding governor")
console.log(newGovernor,coreBorrowAddress);
await coreBorrow.connect(deployer).addGovernor(newGovernor)
}

main().catch(error => {
console.error(error);
process.exit(1);
});
136 changes: 136 additions & 0 deletions scripts/foundry/mainnet/CreateMorphoMarkets.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { IMorpho, MarketParams } from "../../../contracts/interfaces/external/morpho/IMorpho.sol";
import { IMorphoChainlinkOracleV2Factory, IMorphoOracle } from "../../../contracts/interfaces/external/morpho/IMorphoChainlinkOracleV2.sol";
import "./MainnetConstants.s.sol";
import { StdCheats } from "forge-std/Test.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Before running this script, ensure that the deployer has the necessary balance in all tokens to seed the markets
contract CreateMorphoMarkets is Script, MainnetConstants, StdCheats {
error ZeroAdress();

function run() external {
uint256 deployerPrivateKey = vm.deriveKey(vm.envString("MNEMONIC_MAINNET"), "m/44'/60'/0'/0/", 0);
address deployer = vm.addr(deployerPrivateKey);
console.log("Address: %s", deployer);
console.log(deployer.balance);
vm.startBroadcast(deployerPrivateKey);

MarketParams memory params;
bytes memory emptyData;

// TODO: comment when testing in prod
deal(EZETH, deployer, 10 ** 16);
deal(RSETH, deployer, 10 ** 16);
deal(PTETHFI, deployer, 10 ** 16);
deal(USDA, deployer, 3 ether);

IERC20(USDA).approve(MORPHO_BLUE, type(uint256).max);

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SETUP EZETH
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
{
bytes32 salt;
address ezETHOracle = IMorphoChainlinkOracleV2Factory(MORPHO_ORACLE_FACTORY).createMorphoChainlinkOracleV2(
address(0),
1,
EZETH_ETH_ORACLE,
CHAINLINK_ETH_USD_ORACLE,
18,
address(0),
1,
address(0),
address(0),
18,
salt
);
console.log(IMorphoOracle(ezETHOracle).price());
params.collateralToken = EZETH;
params.irm = IRM_MODEL;
params.lltv = LLTV_77;
params.oracle = ezETHOracle;
params.loanToken = USDA;
IMorpho(MORPHO_BLUE).createMarket(params);
IMorpho(MORPHO_BLUE).supply(params, 1 ether, 0, deployer, emptyData);
// 0.01 ezETH
IERC20(EZETH).approve(MORPHO_BLUE, 10 ** 16);
IMorpho(MORPHO_BLUE).supplyCollateral(params, 10 ** 16, deployer, emptyData);
IMorpho(MORPHO_BLUE).borrow(params, (1 ether * 9) / 10, 0, deployer, deployer);
}

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SETUP RSETH
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

{
bytes32 salt;
address rsETHOracle = IMorphoChainlinkOracleV2Factory(MORPHO_ORACLE_FACTORY).createMorphoChainlinkOracleV2(
address(0),
1,
RSETH_ETH_ORACLE,
CHAINLINK_ETH_USD_ORACLE,
18,
address(0),
1,
address(0),
address(0),
18,
salt
);

console.log(IMorphoOracle(rsETHOracle).price());

params.collateralToken = RSETH;
params.irm = IRM_MODEL;
params.lltv = LLTV_77;
params.oracle = rsETHOracle;
params.loanToken = USDA;
IMorpho(MORPHO_BLUE).createMarket(params);
IMorpho(MORPHO_BLUE).supply(params, 1 ether, 0, deployer, emptyData);
IERC20(RSETH).approve(MORPHO_BLUE, 10 ** 16);
IMorpho(MORPHO_BLUE).supplyCollateral(params, 10 ** 16, deployer, emptyData);
IMorpho(MORPHO_BLUE).borrow(params, (1 ether * 9) / 10, 0, deployer, deployer);
}

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SETUP PT WEETH
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

{
bytes32 salt;
address ptETHFIOracle = IMorphoChainlinkOracleV2Factory(MORPHO_ORACLE_FACTORY)
.createMorphoChainlinkOracleV2(
address(0),
1,
// TODO: make sure it's been updated
PTEETH_WEETH_ORACLE,
WEETH_USD_ORACLE,
18,
address(0),
1,
address(0),
address(0),
18,
salt
);
console.log(IMorphoOracle(ptETHFIOracle).price());
params.collateralToken = PTETHFI;
params.irm = IRM_MODEL;
params.lltv = LLTV_62;
params.oracle = ptETHFIOracle;
params.loanToken = USDA;
IMorpho(MORPHO_BLUE).createMarket(params);
IMorpho(MORPHO_BLUE).supply(params, 1 ether, 0, deployer, emptyData);
IERC20(PTETHFI).approve(MORPHO_BLUE, 10 ** 16);
IMorpho(MORPHO_BLUE).supplyCollateral(params, 10 ** 16, deployer, emptyData);
IMorpho(MORPHO_BLUE).borrow(params, (1 ether * 9) / 10, 0, deployer, deployer);
}

vm.stopBroadcast();
}
}
49 changes: 37 additions & 12 deletions scripts/foundry/mainnet/MainnetConstants.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,47 @@ import "../../../contracts/external/ProxyAdmin.sol";
import "../../../contracts/external/TransparentUpgradeableProxy.sol";

contract MainnetConstants {
address public constant GOVERNOR = 0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8;
address public constant GUARDIAN = 0x0C2553e4B9dFA9f83b1A6D3EAB96c4bAaB42d430;
address public constant PROXY_ADMIN = 0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b;
address public constant PROXY_ADMIN_GUARDIAN = 0xD9F1A8e00b0EEbeDddd9aFEaB55019D55fcec017;
address public constant CORE_BORROW = 0x5bc6BEf80DA563EBf6Df6D6913513fa9A7ec89BE;
address constant GOVERNOR = 0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8;
address constant GUARDIAN = 0x0C2553e4B9dFA9f83b1A6D3EAB96c4bAaB42d430;
address constant PROXY_ADMIN = 0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b;
address constant PROXY_ADMIN_GUARDIAN = 0xD9F1A8e00b0EEbeDddd9aFEaB55019D55fcec017;
address constant CORE_BORROW = 0x5bc6BEf80DA563EBf6Df6D6913513fa9A7ec89BE;

address public constant ANGLE_ROUTER = 0x4579709627CA36BCe92f51ac975746f431890930;
address public constant ONE_INCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;
address public constant UNI_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address constant ANGLE_ROUTER = 0x4579709627CA36BCe92f51ac975746f431890930;
address constant ONE_INCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;
address constant UNI_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;

// AGEUR Mainnet treasury
address public constant AGEUR_TREASURY = 0x8667DBEBf68B0BFa6Db54f550f41Be16c4067d60;
address public constant AGGOLD_TREASURY = address(0);
address constant AGEUR_TREASURY = 0x8667DBEBf68B0BFa6Db54f550f41Be16c4067d60;
address constant AGGOLD_TREASURY = address(0);

uint256 public constant BASE_TOKENS = 10 ** 18;
uint64 public constant BASE_PARAMS = 10 ** 9;
uint256 constant BASE_TOKENS = 10 ** 18;
uint64 constant BASE_PARAMS = 10 ** 9;

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MORPHO DATA
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

address constant USDA = 0x0000206329b97DB379d5E1Bf586BbDB969C63274;
address constant EZETH = 0xbf5495Efe5DB9ce00f80364C8B423567e58d2110;
address constant PTETHFI = 0xc69Ad9baB1dEE23F4605a82b3354F8E40d1E5966;
address constant RSETH = 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7;

address constant EZETH_ETH_ORACLE = 0xF4a3e183F59D2599ee3DF213ff78b1B3b1923696;
address constant RSETH_ETH_ORACLE = 0xA736eAe8805dDeFFba40cAB8c99bCB309dEaBd9B;
// TODO: this one needs to be updated and changed
address constant PTEETH_WEETH_ORACLE = 0xdDb6F90fFb4d3257dd666b69178e5B3c5Bf41136;
address constant WEETH_USD_ORACLE = 0xdDb6F90fFb4d3257dd666b69178e5B3c5Bf41136;

address constant CHAINLINK_ETH_USD_ORACLE = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419;

address constant MORPHO_ORACLE_FACTORY = 0x3A7bB36Ee3f3eE32A60e9f2b33c1e5f2E83ad766;
address constant MORPHO_BLUE = 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb;
address constant IRM_MODEL = 0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC;

uint256 constant LLTV_86 = 860000000000000000;
uint256 constant LLTV_77 = 770000000000000000;
uint256 constant LLTV_62 = 625000000000000000;

function deployUpgradeable(address implementation, bytes memory data) public returns (address) {
return address(new TransparentUpgradeableProxy(implementation, PROXY_ADMIN, data));
Expand Down
29 changes: 29 additions & 0 deletions scripts/mainnet-fork/name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ChainId, registry } from '@angleprotocol/sdk/dist';
import { BigNumber, Contract } from 'ethers';
import { deployments, ethers, network } from 'hardhat';
import yargs from 'yargs';

import {
AgTokenSideChainMultiBridgeNameable,
AgTokenSideChainMultiBridgeNameable__factory,
} from '../../typechain';

const argv = yargs.env('').boolean('ci').parseSync();

async function main() {
const { deployer } = await ethers.getNamedSigners();
const chainId = ChainId.MAINNET;
const stablecoinAddress = registry(chainId)?.agEUR?.AgToken!;
const stableContract = new Contract(
stablecoinAddress,
AgTokenSideChainMultiBridgeNameable__factory.abi,
deployer,
) as AgTokenSideChainMultiBridgeNameable;

console.log(await stableContract.name())
}

main().catch(error => {
console.error(error);
process.exit(1);
});

0 comments on commit 2bdc35c

Please sign in to comment.