Skip to content

Commit

Permalink
Morpho cbBTC/USDC Mainnet Integration. (#1209)
Browse files Browse the repository at this point in the history
* copy test file

* update test

* copy deploy script

* update deploy script

---------

Co-authored-by: Jonny Rhea <[email protected]>
  • Loading branch information
sentilesdal and jrhea authored Nov 14, 2024
1 parent 7cfaaf0 commit ba3fde9
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 0 deletions.
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));
}
}

0 comments on commit ba3fde9

Please sign in to comment.