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

Chainlink Integration #1135

Merged
merged 18 commits into from
Aug 21, 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
1 change: 1 addition & 0 deletions .env_template
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
MAINNET_RPC_URL=
SEPOLIA_RPC_URL=
BASE_SEPOLIA_RPC_URL=
GNOSIS_CHAIN_RPC_URL=
DEBUG_RPC_URL=

# private key used for running migration scripts
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
# Install the dependencies.
- uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/solidity_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/solidity_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -41,6 +42,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -63,6 +65,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -85,6 +88,7 @@ jobs:
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
Expand Down
9 changes: 5 additions & 4 deletions contracts/src/deployers/HyperdriveDeployerCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ abstract contract HyperdriveDeployerCoordinator is
// configuration for this instance. This was already done when deploying
// target0, but we check again as a precaution in case the check relies
// on state that can change.
_checkPoolConfig(_deployConfig);
_checkPoolConfig(_deployConfig, _extraData);

// Convert the deploy config into the pool config and set the initial
// vault share price.
Expand Down Expand Up @@ -232,7 +232,7 @@ abstract contract HyperdriveDeployerCoordinator is

// Check the pool configuration to ensure that it's a valid
// configuration for this instance.
_checkPoolConfig(_deployConfig);
_checkPoolConfig(_deployConfig, _extraData);

// Get the initial share price and the hashes of the config and extra
// data.
Expand Down Expand Up @@ -289,7 +289,7 @@ abstract contract HyperdriveDeployerCoordinator is
// configuration for this instance. This was already done when deploying
// target0, but we check again as a precaution in case the check relies
// on state that can change.
_checkPoolConfig(_deployConfig);
_checkPoolConfig(_deployConfig, _extraData);

// Convert the deploy config into the pool config and set the initial
// vault share price.
Expand Down Expand Up @@ -447,7 +447,8 @@ abstract contract HyperdriveDeployerCoordinator is
/// @dev Checks the pool configuration to ensure that it is valid.
/// @param _deployConfig The deploy configuration of the Hyperdrive pool.
function _checkPoolConfig(
IHyperdrive.PoolDeployConfig memory _deployConfig
IHyperdrive.PoolDeployConfig memory _deployConfig,
bytes memory // unused _extraData
) internal view virtual {
// Ensure that the minimum share reserves is at least 1e3. Deployer
// coordinators should override this to be stricter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@ contract AaveHyperdriveDeployerCoordinator is

/// @notice Checks the pool configuration to ensure that it is valid.
/// @param _deployConfig The deploy configuration of the Hyperdrive pool.
/// @param _extraData The empty extra data.
function _checkPoolConfig(
IHyperdrive.PoolDeployConfig memory _deployConfig
IHyperdrive.PoolDeployConfig memory _deployConfig,
bytes memory _extraData
) internal view override {
// Perform the default checks.
super._checkPoolConfig(_deployConfig);
super._checkPoolConfig(_deployConfig, _extraData);

// Ensure that the vault shares token address is non-zero.
if (address(_deployConfig.vaultSharesToken) == address(0)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { IChainlinkAggregatorV3 } from "../../interfaces/IChainlinkAggregatorV3.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol";
import { ChainlinkHyperdrive } from "../../instances/chainlink/ChainlinkHyperdrive.sol";

/// @author DELV
/// @title ChainlinkHyperdriveCoreDeployer
/// @notice The core deployer for the ChainlinkHyperdrive implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract ChainlinkHyperdriveCoreDeployer is IHyperdriveCoreDeployer {
/// @notice Deploys a Hyperdrive instance with the given parameters.
/// @param __name The name of the Hyperdrive pool.
/// @param _config The configuration of the Hyperdrive pool.
/// @param _extraData The extra data containing the Chainlink aggregator.
jalextowle marked this conversation as resolved.
Show resolved Hide resolved
/// @param _target0 The target0 address.
/// @param _target1 The target1 address.
/// @param _target2 The target2 address.
/// @param _target3 The target3 address.
/// @param _target4 The target4 address.
/// @param _salt The create2 salt used in the deployment.
/// @return The address of the newly deployed ChainlinkHyperdrive instance.
function deployHyperdrive(
string memory __name,
IHyperdrive.PoolConfig memory _config,
bytes memory _extraData,
address _target0,
address _target1,
address _target2,
address _target3,
address _target4,
bytes32 _salt
) external returns (address) {
(IChainlinkAggregatorV3 aggregator, uint8 decimals) = abi.decode(
_extraData,
(IChainlinkAggregatorV3, uint8)
);
return (
address(
// NOTE: We hash the sender with the salt to prevent the
// front-running of deployments.
new ChainlinkHyperdrive{
salt: keccak256(abi.encode(msg.sender, _salt))
}(
__name,
_config,
_target0,
_target1,
_target2,
_target3,
_target4,
aggregator,
decimals
)
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol";
import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol";
import { ChainlinkConversions } from "../../instances/chainlink/ChainlinkConversions.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IChainlinkAggregatorV3 } from "../../interfaces/IChainlinkAggregatorV3.sol";
import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol";
import { CHAINLINK_HYPERDRIVE_DEPLOYER_COORDINATOR_KIND } from "../../libraries/Constants.sol";
import { ONE } from "../../libraries/FixedPointMath.sol";
import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol";

/// @author DELV
/// @title ChainlinkHyperdriveDeployerCoordinator
/// @notice The deployer coordinator for the ChainlinkHyperdrive
/// implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract ChainlinkHyperdriveDeployerCoordinator is
HyperdriveDeployerCoordinator
{
using SafeERC20 for ERC20;

/// @notice The deployer coordinator's kind.
string public constant override kind =
CHAINLINK_HYPERDRIVE_DEPLOYER_COORDINATOR_KIND;

/// @notice Instantiates the deployer coordinator.
/// @param _name The deployer coordinator's name.
/// @param _factory The factory that this deployer will be registered with.
/// @param _coreDeployer The core deployer.
/// @param _target0Deployer The target0 deployer.
/// @param _target1Deployer The target1 deployer.
/// @param _target2Deployer The target2 deployer.
/// @param _target3Deployer The target3 deployer.
/// @param _target4Deployer The target4 deployer.
constructor(
string memory _name,
address _factory,
address _coreDeployer,
address _target0Deployer,
address _target1Deployer,
address _target2Deployer,
address _target3Deployer,
address _target4Deployer
)
HyperdriveDeployerCoordinator(
_name,
_factory,
_coreDeployer,
_target0Deployer,
_target1Deployer,
_target2Deployer,
_target3Deployer,
_target4Deployer
)
{}

/// @dev Prepares the coordinator for initialization by drawing funds from
/// the LP, if necessary.
/// @param _hyperdrive The Hyperdrive instance that is being initialized.
/// @param _lp The LP that is initializing the pool.
/// @param _contribution The amount of capital to supply. The units of this
/// quantity are either base or vault shares, depending on the value
/// of `_options.asBase`.
/// @param _options The options that configure how the initialization is
/// settled.
/// @return value The value that should be sent in the initialize transaction.
function _prepareInitialize(
IHyperdrive _hyperdrive,
address _lp,
uint256 _contribution,
IHyperdrive.Options memory _options
) internal override returns (uint256 value) {
// Depositing as base is disallowed.
if (_options.asBase) {
revert IHyperdrive.UnsupportedToken();
}

// Take custody of the contribution and approve Hyperdrive to pull the
// tokens.
address token = _hyperdrive.vaultSharesToken();
ERC20(token).safeTransferFrom(_lp, address(this), _contribution);
ERC20(token).forceApprove(address(_hyperdrive), _contribution);

return value;
}

/// @dev We override the message value check since this integration is
/// not payable.
function _checkMessageValue() internal view override {
if (msg.value != 0) {
revert IHyperdriveDeployerCoordinator.NotPayable();
}
}

/// @notice Checks the pool configuration to ensure that it is valid.
/// @param _deployConfig The deploy configuration of the Hyperdrive pool.
/// @param _extraData The extra data containing the Chainlink aggregator
/// and the instance's decimals.
function _checkPoolConfig(
IHyperdrive.PoolDeployConfig memory _deployConfig,
bytes memory _extraData
) internal view override {
// Perform the default checks.
super._checkPoolConfig(_deployConfig, _extraData);

// Ensure that the base token is zero.
jalextowle marked this conversation as resolved.
Show resolved Hide resolved
if (address(_deployConfig.baseToken) != address(0)) {
revert IHyperdriveDeployerCoordinator.InvalidBaseToken();
}

// Ensure that the vault shares token isn't zero.
if (address(_deployConfig.vaultSharesToken) == address(0)) {
revert IHyperdriveDeployerCoordinator.InvalidVaultSharesToken();
}

// Ensure that the minimum share reserves are large enough to meet the
// minimum requirements for safety.
//
// NOTE: Some pools may require larger minimum share reserves to be
// considered safe. This is just a sanity check.
(, uint8 decimals) = abi.decode(
_extraData,
(IChainlinkAggregatorV3, uint8)
);
if (_deployConfig.minimumShareReserves != 10 ** (decimals - 3)) {
revert IHyperdriveDeployerCoordinator.InvalidMinimumShareReserves();
}

// Ensure that the minimum transaction amount is large enough to meet
// the minimum requirements for safety.
//
// NOTE: Some pools may require larger minimum transaction amounts to be
// considered safe. This is just a sanity check.
if (_deployConfig.minimumTransactionAmount != 10 ** (decimals - 3)) {
revert IHyperdriveDeployerCoordinator
.InvalidMinimumTransactionAmount();
}
}

/// @dev Gets the initial vault share price of the Hyperdrive pool.
/// @param _extraData The extra data containing the Chainlink aggregator
/// and the instance's decimals.
/// @return The initial vault share price of the Hyperdrive pool.
function _getInitialVaultSharePrice(
IHyperdrive.PoolDeployConfig memory, // unused _deployConfig
bytes memory _extraData
) internal view override returns (uint256) {
IChainlinkAggregatorV3 aggregator = abi.decode(
_extraData,
(IChainlinkAggregatorV3)
);
return ChainlinkConversions.convertToBase(aggregator, ONE);
}
}
39 changes: 39 additions & 0 deletions contracts/src/deployers/chainlink/ChainlinkTarget0Deployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { ChainlinkTarget0 } from "../../instances/chainlink/ChainlinkTarget0.sol";
import { IChainlinkAggregatorV3 } from "../../interfaces/IChainlinkAggregatorV3.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol";

/// @author DELV
/// @title ChainlinkTarget0Deployer
/// @notice The target0 deployer for the ChainlinkHyperdrive implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract ChainlinkTarget0Deployer is IHyperdriveTargetDeployer {
/// @notice Deploys a target0 instance with the given parameters.
/// @param _config The configuration of the Hyperdrive pool.
/// @param _extraData The extra data containing the Chainlink aggregator.
/// @param _salt The create2 salt used in the deployment.
/// @return The address of the newly deployed ChainlinkTarget0 instance.
function deployTarget(
IHyperdrive.PoolConfig memory _config,
bytes memory _extraData,
bytes32 _salt
) external returns (address) {
(IChainlinkAggregatorV3 aggregator, uint8 decimals) = abi.decode(
_extraData,
(IChainlinkAggregatorV3, uint8)
);
return
address(
// NOTE: We hash the sender with the salt to prevent the
// front-running of deployments.
new ChainlinkTarget0{
salt: keccak256(abi.encode(msg.sender, _salt))
}(_config, aggregator, decimals)
);
}
}
Loading
Loading