-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added the skeleton for the Corn integration * Implemented the `CornBase` contract * Wired up the Corn Hyperdrive instance * Added an instance test for the Corn integration * Added deployment scripts for the Corn integration * Addressed review feedback from @jrhea and @mcclurejt * Added a test for the sDAI Corn integration * Added a deploy script for sDAI Corn * Remove FIXMEs * Fixed some small issues with the forknet infrastructure * Addressed review feedback from @mcclurejt
- Loading branch information
1 parent
da3b263
commit 3e07b60
Showing
8 changed files
with
456 additions
and
8 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
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,84 @@ | ||
import { Address, keccak256, parseEther, toBytes, zeroAddress } from "viem"; | ||
import { | ||
HyperdriveInstanceConfig, | ||
getLinkerDetails, | ||
normalizeFee, | ||
parseDuration, | ||
toBytes32, | ||
} from "../../lib"; | ||
import { SDAI_ADDRESS_MAINNET, THREE_MONTHS } from "../../lib/constants"; | ||
import { MAINNET_CORN_COORDINATOR_NAME } from "./corn-coordinator"; | ||
import { MAINNET_FACTORY_NAME } from "./factory"; | ||
|
||
// The name of the pool. | ||
export const MAINNET_CORN_SDAI_91DAY_NAME = | ||
"ElementDAO 91 Day Corn sDAI Hyperdrive"; | ||
|
||
// We use a contribution of 100 sDAI. | ||
const CONTRIBUTION = parseEther("100"); | ||
|
||
export const MAINNET_CORN_SDAI_91DAY: HyperdriveInstanceConfig<"Corn"> = { | ||
name: MAINNET_CORN_SDAI_91DAY_NAME, | ||
prefix: "Corn", | ||
coordinatorAddress: async (hre) => | ||
hre.hyperdriveDeploy.deployments.byName(MAINNET_CORN_COORDINATOR_NAME) | ||
.address, | ||
deploymentId: keccak256(toBytes(MAINNET_CORN_SDAI_91DAY_NAME)), | ||
salt: toBytes32("0x69420"), | ||
extraData: "0x", | ||
contribution: CONTRIBUTION, | ||
fixedAPR: parseEther("0.08"), | ||
timestretchAPR: parseEther("0.075"), | ||
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) => { | ||
let baseToken = await hre.viem.getContractAt( | ||
"contracts/src/interfaces/IERC20.sol:IERC20", | ||
SDAI_ADDRESS_MAINNET, | ||
); | ||
let tx = await baseToken.write.approve([ | ||
hre.hyperdriveDeploy.deployments.byName( | ||
MAINNET_CORN_COORDINATOR_NAME, | ||
).address, | ||
CONTRIBUTION, | ||
]); | ||
let pc = await hre.viem.getPublicClient(); | ||
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: SDAI_ADDRESS_MAINNET, | ||
vaultSharesToken: zeroAddress, | ||
circuitBreakerDelta: parseEther("0.075"), | ||
minimumShareReserves: parseEther("0.001"), // 1e15 | ||
minimumTransactionAmount: parseEther("0.001"), // 1e15 | ||
positionDuration: parseDuration(THREE_MONTHS), | ||
checkpointDuration: parseDuration("1 day"), | ||
timeStretch: 0n, | ||
governance: await factoryContract.read.hyperdriveGovernance(), | ||
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"), THREE_MONTHS), | ||
governanceLP: parseEther("0.15"), | ||
governanceZombie: parseEther("0.03"), | ||
}, | ||
}; | ||
}, | ||
}; |
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,173 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity 0.8.22; | ||
|
||
import { stdStorage, StdStorage } from "forge-std/Test.sol"; | ||
import { CornHyperdriveCoreDeployer } from "../../../contracts/src/deployers/corn/CornHyperdriveCoreDeployer.sol"; | ||
import { CornHyperdriveDeployerCoordinator } from "../../../contracts/src/deployers/corn/CornHyperdriveDeployerCoordinator.sol"; | ||
import { CornTarget0Deployer } from "../../../contracts/src/deployers/corn/CornTarget0Deployer.sol"; | ||
import { CornTarget1Deployer } from "../../../contracts/src/deployers/corn/CornTarget1Deployer.sol"; | ||
import { CornTarget2Deployer } from "../../../contracts/src/deployers/corn/CornTarget2Deployer.sol"; | ||
import { CornTarget3Deployer } from "../../../contracts/src/deployers/corn/CornTarget3Deployer.sol"; | ||
import { CornTarget4Deployer } from "../../../contracts/src/deployers/corn/CornTarget4Deployer.sol"; | ||
import { CornConversions } from "../../../contracts/src/instances/corn/CornConversions.sol"; | ||
import { IERC20 } from "../../../contracts/src/interfaces/IERC20.sol"; | ||
import { ICornHyperdrive } from "../../../contracts/src/interfaces/ICornHyperdrive.sol"; | ||
import { ICornSilo } from "../../../contracts/src/interfaces/ICornSilo.sol"; | ||
import { IHyperdrive } from "../../../contracts/src/interfaces/IHyperdrive.sol"; | ||
import { FixedPointMath } from "../../../contracts/src/libraries/FixedPointMath.sol"; | ||
import { InstanceTest } from "../../utils/InstanceTest.sol"; | ||
import { HyperdriveUtils } from "../../utils/HyperdriveUtils.sol"; | ||
import { Lib } from "../../utils/Lib.sol"; | ||
|
||
contract CornHyperdriveInstanceTest is InstanceTest { | ||
using FixedPointMath for uint256; | ||
using HyperdriveUtils for uint256; | ||
using HyperdriveUtils for IHyperdrive; | ||
using Lib for *; | ||
using stdStorage for StdStorage; | ||
|
||
/// @dev The Corn Silo. | ||
ICornSilo internal immutable silo; | ||
|
||
/// @notice Instantiates the instance testing suite with the configuration. | ||
/// @param _config The instance test configuration. | ||
/// @param _silo The Corn Silo. | ||
constructor( | ||
InstanceTestConfig memory _config, | ||
ICornSilo _silo | ||
) InstanceTest(_config) { | ||
silo = _silo; | ||
} | ||
|
||
/// Overrides /// | ||
|
||
/// @dev Gets the extra data used to deploy the Corn instance. This is empty. | ||
/// @return The empty extra data. | ||
function getExtraData() internal pure override returns (bytes memory) { | ||
return new bytes(0); | ||
} | ||
|
||
/// @dev Converts base amount to the equivalent about in shares. | ||
/// @param baseAmount The base amount. | ||
/// @return The converted share amount. | ||
function convertToShares( | ||
uint256 baseAmount | ||
) internal pure override returns (uint256) { | ||
return CornConversions.convertToShares(baseAmount); | ||
} | ||
|
||
/// @dev Converts share amount to the equivalent amount in base. | ||
/// @param shareAmount The share amount. | ||
/// @return The converted base amount. | ||
function convertToBase( | ||
uint256 shareAmount | ||
) internal pure override returns (uint256) { | ||
return CornConversions.convertToBase(shareAmount); | ||
} | ||
|
||
/// @dev Deploys the Corn Hyperdrive deployer coordinator contract. | ||
/// @param _factory The address of the Hyperdrive factory. | ||
/// @return The coordinator address. | ||
function deployCoordinator( | ||
address _factory | ||
) internal override returns (address) { | ||
vm.startPrank(alice); | ||
return | ||
address( | ||
new CornHyperdriveDeployerCoordinator( | ||
string.concat(config.name, "DeployerCoordinator"), | ||
_factory, | ||
address(new CornHyperdriveCoreDeployer(silo)), | ||
address(new CornTarget0Deployer(silo)), | ||
address(new CornTarget1Deployer(silo)), | ||
address(new CornTarget2Deployer(silo)), | ||
address(new CornTarget3Deployer(silo)), | ||
address(new CornTarget4Deployer(silo)) | ||
) | ||
); | ||
} | ||
|
||
/// @dev Fetches the total supply of the base and share tokens. | ||
/// @return The total supply of base. | ||
/// @return The total supply of vault shares. | ||
function getSupply() internal view override returns (uint256, uint256) { | ||
return ( | ||
config.baseToken.balanceOf(address(silo)), | ||
silo.totalShares(address(config.baseToken)) | ||
); | ||
} | ||
|
||
/// @dev Fetches the token balance information of an account. | ||
/// @param account The account to query. | ||
/// @return The balance of base. | ||
/// @return The balance of vault shares. | ||
function getTokenBalances( | ||
address account | ||
) internal view override returns (uint256, uint256) { | ||
return ( | ||
config.baseToken.balanceOf(account), | ||
silo.sharesOf(account, address(config.baseToken)) | ||
); | ||
} | ||
|
||
/// Getters /// | ||
|
||
/// @dev Test the instances getters. | ||
function test_getters() external view { | ||
assertEq( | ||
address(ICornHyperdrive(address(hyperdrive)).cornSilo()), | ||
address(silo) | ||
); | ||
(, uint256 totalShares) = getTokenBalances(address(hyperdrive)); | ||
assertEq(hyperdrive.totalShares(), totalShares); | ||
} | ||
|
||
/// Price Per Share /// | ||
|
||
/// @dev Fuzz test that verifies that the vault share price is the price | ||
/// that dictates the conversion between base and shares. | ||
/// @param basePaid The fuzz parameter for the base paid. | ||
function test__pricePerVaultShare(uint256 basePaid) external { | ||
// Ensure that the share price is the expected value. | ||
(uint256 totalBase, uint256 totalShares) = getSupply(); | ||
uint256 vaultSharePrice = hyperdrive.getPoolInfo().vaultSharePrice; | ||
assertEq(vaultSharePrice, totalBase.divDown(totalShares)); | ||
|
||
// Ensure that the share price accurately predicts the amount of shares | ||
// that will be minted for depositing a given amount of shares. This will | ||
// be an approximation. | ||
basePaid = basePaid.normalizeToRange( | ||
2 * hyperdrive.getPoolConfig().minimumTransactionAmount, | ||
hyperdrive.calculateMaxLong() | ||
); | ||
(, uint256 hyperdriveSharesBefore) = getTokenBalances( | ||
address(hyperdrive) | ||
); | ||
openLong(bob, basePaid); | ||
(, uint256 hyperdriveSharesAfter) = getTokenBalances( | ||
address(hyperdrive) | ||
); | ||
assertApproxEqAbs( | ||
hyperdriveSharesAfter, | ||
hyperdriveSharesBefore + basePaid.divDown(vaultSharePrice), | ||
config.shareTolerance | ||
); | ||
} | ||
|
||
/// Helpers /// | ||
|
||
/// @dev Advance time and accrue interest. | ||
/// @param timeDelta The time to advance. | ||
/// @param variableRate The variable rate. | ||
function advanceTime( | ||
uint256 timeDelta, | ||
int256 variableRate | ||
) internal override { | ||
// Corn doesn't accrue interest, so we revert if the variable rate isn't | ||
// zero. | ||
require(variableRate == 0, "CornHyperdriveTest: variableRate isn't 0"); | ||
|
||
// Advance the time. | ||
vm.warp(block.timestamp + timeDelta); | ||
} | ||
} |
Oops, something went wrong.