Skip to content
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

Morpho cbBTC/USDC Mainnet Integration. #1209

Merged
merged 5 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions hardhat.config.mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
MAINNET_EZETH_182DAY,
MAINNET_EZETH_COORDINATOR,
MAINNET_FACTORY,
MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY,
MAINNET_MORPHO_BLUE_COORDINATOR,
MAINNET_MORPHO_BLUE_SUSDE_DAI_182DAY,
MAINNET_MORPHO_BLUE_USDE_DAI_182DAY,
Expand Down Expand Up @@ -44,6 +45,7 @@ const config: HardhatUserConfig = {
MAINNET_MORPHO_BLUE_SUSDE_DAI_182DAY,
MAINNET_MORPHO_BLUE_USDE_DAI_182DAY,
MAINNET_MORPHO_BLUE_WSTETH_USDA_182DAY,
MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY,
MAINNET_STUSD_182DAY,
MAINNET_SUSDE_182DAY,
],
Expand Down
1 change: 1 addition & 0 deletions tasks/deploy/config/mainnet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from "./erc4626-coordinator";
export * from "./ezeth-182day";
export * from "./ezeth-coordinator";
export * from "./factory";
export * from "./morpho-blue-cbbtc-usdc-182day";
export * from "./morpho-blue-coordinator";
export * from "./morpho-blue-susde-dai-182day";
export * from "./morpho-blue-usde-dai-182day";
Expand Down
140 changes: 140 additions & 0 deletions tasks/deploy/config/mainnet/morpho-blue-cbbtc-usdc-182day.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import {
Address,
encodeAbiParameters,
keccak256,
parseEther,
toHex,
zeroAddress,
} from "viem";
import {
CBBTC_ADDRESS_MAINNET,
HyperdriveInstanceConfig,
SIX_MONTHS,
USDC_ADDRESS_MAINNET,
getLinkerDetails,
normalizeFee,
parseDuration,
toBytes32,
} from "../../lib";
import { MAINNET_FACTORY_NAME } from "./factory";
import { MAINNET_MORPHO_BLUE_COORDINATOR_NAME } from "./morpho-blue-coordinator";

export const MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY_NAME =
"ElementDAO 182 Day Morpho Blue cbBTC/USDC Hyperdrive";

// USDC only has 6 decimals.
const CONTRIBUTION = 100_000_000n;

const morphoBlueParameters = encodeAbiParameters(
[
{
components: [
{
name: "morpho",
type: "address",
},
{
name: "collateralToken",
type: "address",
},
{
name: "oracle",
type: "address",
},
{
name: "irm",
type: "address",
},
{
name: "lltv",
type: "uint256",
},
],
name: "MorphoBlueParams",
type: "tuple",
},
],
[
{
morpho: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb" as `0x${string}`,
collateralToken: CBBTC_ADDRESS_MAINNET,
oracle: "0xA6D6950c9F177F1De7f7757FB33539e3Ec60182a" as `0x${string}`,
irm: "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC" as `0x${string}`,
lltv: BigInt("860000000000000000"),
},
],
);

export const MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY: HyperdriveInstanceConfig<"MorphoBlue"> =
{
name: MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY_NAME,
prefix: "MorphoBlue",
coordinatorAddress: async (hre) =>
hre.hyperdriveDeploy.deployments.byName(
MAINNET_MORPHO_BLUE_COORDINATOR_NAME,
).address,
deploymentId: keccak256(
toHex(MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY_NAME),
),
salt: toBytes32("0x42080085"),
extraData: morphoBlueParameters,
contribution: CONTRIBUTION,
// NOTE: The latest variable rate on the Morpho Blue market is 2.93% APY:
// https://app.morpho.org/market?id=0x64d65c9a2d91c36d56fbc42d69e979335320169b3df63bf92789e2c8883fcc64&network=mainnet&morphoPrice=0.75
fixedAPR: parseEther("0.0293"),
timestretchAPR: parseEther("0.05"),
options: async (hre) => ({
extraData: "0x",
asBase: true,
destination: (await hre.getNamedAccounts())["deployer"] as Address,
}),
// Prepare to deploy the contract by setting approvals.
prepare: async (hre, options) => {
let pc = await hre.viem.getPublicClient();
let baseToken = await hre.viem.getContractAt(
"contracts/src/interfaces/IERC20.sol:IERC20",
USDC_ADDRESS_MAINNET,
);
let tx = await baseToken.write.approve([
hre.hyperdriveDeploy.deployments.byName(
MAINNET_MORPHO_BLUE_COORDINATOR_NAME,
).address,
CONTRIBUTION,
]);
await pc.waitForTransactionReceipt({ hash: tx });
},
poolDeployConfig: async (hre) => {
let factoryContract = await hre.viem.getContractAt(
"HyperdriveFactory",
hre.hyperdriveDeploy.deployments.byName(MAINNET_FACTORY_NAME)
.address,
);
return {
baseToken: USDC_ADDRESS_MAINNET,
vaultSharesToken: zeroAddress,
circuitBreakerDelta: parseEther("0.05"),
minimumShareReserves: 1_000_000n,
minimumTransactionAmount: 1_000_000n,
positionDuration: parseDuration(SIX_MONTHS),
checkpointDuration: parseDuration("1 day"),
timeStretch: 0n,
governance: await factoryContract.read.governance(),
feeCollector: await factoryContract.read.feeCollector(),
sweepCollector: await factoryContract.read.sweepCollector(),
checkpointRewarder:
await factoryContract.read.checkpointRewarder(),
...(await getLinkerDetails(
hre,
hre.hyperdriveDeploy.deployments.byName(
MAINNET_FACTORY_NAME,
).address,
)),
fees: {
curve: parseEther("0.01"),
flat: normalizeFee(parseEther("0.0005"), SIX_MONTHS),
governanceLP: parseEther("0.15"),
governanceZombie: parseEther("0.03"),
},
};
},
};
2 changes: 2 additions & 0 deletions tasks/deploy/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export const RSETH_POOL_LINEA =
// │ Mainnet Addresses │
// ╰─────────────────────────────────────────────────────────╯

export const CBBTC_ADDRESS_MAINNET =
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf" as Address;
export const CORN_SILO_ADDRESS_MAINNET =
"0x8bc93498b861fd98277c3b51d240e7E56E48F23c" as Address;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { stdStorage, StdStorage } from "forge-std/Test.sol";
import { IMorpho } from "morpho-blue/src/interfaces/IMorpho.sol";
import { IERC20 } from "../../../contracts/src/interfaces/IERC20.sol";
import { IFiatTokenProxy } from "../../../contracts/src/interfaces/IFiatTokenProxy.sol";
import { IHyperdrive } from "../../../contracts/src/interfaces/IHyperdrive.sol";
import { IMorphoBlueHyperdrive } from "../../../contracts/src/interfaces/IMorphoBlueHyperdrive.sol";
import { Lib } from "../../utils/Lib.sol";
import { MorphoBlueHyperdriveInstanceTest } from "./MorphoBlueHyperdriveInstanceTest.t.sol";

contract MorphoBlue_cbBTC_USDC_Mainnet_HyperdriveTest is
MorphoBlueHyperdriveInstanceTest
{
using Lib for *;
using stdStorage for StdStorage;

/// @dev The address of the loan token. This is just the USDC token.
address internal constant LOAN_TOKEN =
address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);

/// @dev Whale accounts.
address internal LOAN_TOKEN_WHALE =
address(0x51eDF02152EBfb338e03E30d65C15fBf06cc9ECC);
address[] internal baseTokenWhaleAccounts = [LOAN_TOKEN_WHALE];

/// @notice Instantiates the instance testing suite with the configuration.
constructor()
MorphoBlueHyperdriveInstanceTest(
InstanceTestConfig({
name: "Hyperdrive",
kind: "MorphoBlueHyperdrive",
decimals: 6,
baseTokenWhaleAccounts: baseTokenWhaleAccounts,
vaultSharesTokenWhaleAccounts: new address[](0),
baseToken: IERC20(LOAN_TOKEN),
vaultSharesToken: IERC20(address(0)),
// NOTE: The share tolerance is quite high for this integration
// because the vault share price is ~1e12, which means that just
// multiplying or dividing by the vault is an imprecise way of
// converting between base and vault shares. We included more
// assertions than normal to the round trip tests to verify that
// the calculations satisfy our expectations of accuracy.
shareTolerance: 1e3,
minimumShareReserves: 1e6,
minimumTransactionAmount: 1e6,
positionDuration: POSITION_DURATION,
fees: IHyperdrive.Fees({
curve: 0.001e18,
flat: 0.0001e18,
governanceLP: 0,
governanceZombie: 0
}),
enableBaseDeposits: true,
enableShareDeposits: false,
enableBaseWithdraws: true,
enableShareWithdraws: false,
baseWithdrawError: abi.encodeWithSelector(
IHyperdrive.UnsupportedToken.selector
),
isRebasing: false,
shouldAccrueInterest: true,
// The base test tolerances.
closeLongWithBaseTolerance: 2,
roundTripLpInstantaneousWithBaseTolerance: 1e3,
roundTripLpWithdrawalSharesWithBaseTolerance: 1e5,
roundTripLongInstantaneousWithBaseUpperBoundTolerance: 100,
// NOTE: Since the curve fee isn't zero, this check is ignored.
roundTripLongInstantaneousWithBaseTolerance: 0,
roundTripLongMaturityWithBaseUpperBoundTolerance: 100,
roundTripLongMaturityWithBaseTolerance: 1e3,
roundTripShortInstantaneousWithBaseUpperBoundTolerance: 100,
// NOTE: Since the curve fee isn't zero, this check is ignored.
roundTripShortInstantaneousWithBaseTolerance: 0,
roundTripShortMaturityWithBaseTolerance: 1e3,
// NOTE: Share deposits and withdrawals are disabled, so these are
// 0.
//
// The share test tolerances.
closeLongWithSharesTolerance: 0,
closeShortWithSharesTolerance: 0,
roundTripLpInstantaneousWithSharesTolerance: 0,
roundTripLpWithdrawalSharesWithSharesTolerance: 0,
roundTripLongInstantaneousWithSharesUpperBoundTolerance: 0,
roundTripLongInstantaneousWithSharesTolerance: 0,
roundTripLongMaturityWithSharesUpperBoundTolerance: 0,
roundTripLongMaturityWithSharesTolerance: 0,
roundTripShortInstantaneousWithSharesUpperBoundTolerance: 0,
roundTripShortInstantaneousWithSharesTolerance: 0,
roundTripShortMaturityWithSharesTolerance: 0,
// The verification tolerances.
verifyDepositTolerance: 2,
verifyWithdrawalTolerance: 3
}),
IMorphoBlueHyperdrive.MorphoBlueParams({
// The mainnet Morpho Blue pool
morpho: IMorpho(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb),
// The address of the collateral token. This is cbBTC.
collateralToken: address(
0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf
),
// The address of the oracle.
oracle: address(0xA6D6950c9F177F1De7f7757FB33539e3Ec60182a),
// The address of the interest rate model.
irm: address(0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC),
// The liquidation loan to value ratio.
lltv: 860000000000000000
})
)
{}

/// @notice Forge function that is invoked to setup the testing environment.
function setUp() public override __mainnet_fork(21_092_084) {
// Invoke the instance testing suite setup.
super.setUp();
}

/// Helpers ///

/// @dev Mints base tokens to a specified account.
/// @param _recipient The recipient of the minted tokens.
/// @param _amount The amount of tokens to mint.
function mintBaseTokens(
address _recipient,
uint256 _amount
) internal override {
bytes32 balanceLocation = keccak256(abi.encode(address(_recipient), 9));
vm.store(LOAN_TOKEN, balanceLocation, bytes32(_amount));
}
}
Loading