From a99283396725e0a7d3229906efa948e979d77872 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 20 Mar 2024 09:37:54 -0500 Subject: [PATCH 01/25] add codegen skeleton --- codegen/README.md | 68 ++++++++++++++++++++++++++ codegen/hyperdrive_codegen/__init__.py | 0 codegen/hyperdrive_codegen/main.py | 9 ++++ codegen/pyproject.toml | 21 ++++++++ 4 files changed, 98 insertions(+) create mode 100644 codegen/README.md create mode 100644 codegen/hyperdrive_codegen/__init__.py create mode 100644 codegen/hyperdrive_codegen/main.py create mode 100644 codegen/pyproject.toml diff --git a/codegen/README.md b/codegen/README.md new file mode 100644 index 000000000..bf54ab12c --- /dev/null +++ b/codegen/README.md @@ -0,0 +1,68 @@ +# Integrations Codegen Guide +To make integrating hyperdrive with other protocols easier, we've created tooling to generate most of the boilerplate code. This guide walks though how to install and run the codegen tools. + +Here's a quick overview of the directory. +hyperdrive/ +│ +├── codegen/ # Codegen tool directory +│ ├── hyperdrive-codegen/ # Python package for the codegen tool +│ │ ├── __init__.py # Makes hyperdrive-codegen a Python package +│ │ ├── main.py # Entry point of your tool +│ │ └── ... # Other Python modules and package data +│ │ +│ ├── templates/ # Jinja templates directory +│ │ └── ... # Template files +│ │ +│ ├── pyproject.toml # Configuration file for build system and dependencies +│ └── .venv/ # Virtual environment (excluded from version control) +│ +├── contracts/ # Solidity contracts directory +│ └── ... # Solidity files + + +## Install + + +### 0. Install Python + +You'll need to have python installed on your machine to use this tool. Installation varies by operatin system. + +### 1. Install Pyenv + +Follow [Pyenv install instructions](https://github.com/pyenv/pyenv#installation). + +### 2. Set up virtual environment + +You can use any environment, but we recommend [venv](https://docs.python.org/3/library/venv.html), which is part of the standard Python library. + +From hyperdrive's root directory, run: +```bash +pip install --upgrade pip +pyenv install 3.10 +pyenv local 3.10 +python -m venv .venv +source .venv/bin/activate +``` + +### 4. Install dependencies + +To install the dependencies: + +````bash +pip install -e . +```` + + +### 5. Check Installation + +Verify that your package was installed correctly by running something like pip list. You should see hyperdrive-codegen listed as a package. + + +## Usage + +If installation was successful, you should be able to run the command from the terminal: + +```bash +hyperdrive-codegen +``` + diff --git a/codegen/hyperdrive_codegen/__init__.py b/codegen/hyperdrive_codegen/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/hyperdrive_codegen/main.py b/codegen/hyperdrive_codegen/main.py new file mode 100644 index 000000000..f70cc6e77 --- /dev/null +++ b/codegen/hyperdrive_codegen/main.py @@ -0,0 +1,9 @@ +def main(): + print("Welcome to Hyperdrive Codegen!") + # Your code generation logic will go here. + # For now, let's just print a message to the terminal. + print("This tool generates boilerplate code for the Hyperdrive project using Jinja templates.") + + +if __name__ == "__main__": + main() diff --git a/codegen/pyproject.toml b/codegen/pyproject.toml new file mode 100644 index 000000000..15981553b --- /dev/null +++ b/codegen/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +# requires = ["setuptools>=42", "wheel"] +# build-backend = "setuptools.build_meta" +requires = ["flit_core>=3.2"] +build-backend = "flit_core.buildapi" + +[tool.virtualenv] +create = true +env-dir = ".venv" + +[project] +name = "hyperdrive-codegen" +description = "A code generation tool for the Hyperdrive Solidity project." +version = "0.0.1" +readme = "README.md" +requires-python = ">=3.10" +authors = [{ name = "Matthew Brown", email = "matt@delv.tech" }] +dependencies = ["jinja2>=2.11"] + +[project.scripts] +hyperdrive-codegen = "hyperdrive_codegen.main:main" From 2a546a1ca3a139f16b6904779abd5027842c0bbd Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 20 Mar 2024 09:46:17 -0500 Subject: [PATCH 02/25] copy first file contents, add empty files --- .../HyperdriveCoreDeployer.sol.jinja | 55 +++++++++++++++++++ .../HyperdriveDeployerCoordinator.sol.jinja | 0 .../deployers/Target0Deployer.sol.jinja | 0 .../deployers/Target1Deployer.sol.jinja | 0 .../deployers/Target2Deployer.sol.jinja | 0 .../deployers/Target3Deployer.sol.jinja | 0 .../deployers/Target4Deployer.sol.jinja | 0 7 files changed, 55 insertions(+) create mode 100644 codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja create mode 100644 codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja create mode 100644 codegen/templates/deployers/Target0Deployer.sol.jinja create mode 100644 codegen/templates/deployers/Target1Deployer.sol.jinja create mode 100644 codegen/templates/deployers/Target2Deployer.sol.jinja create mode 100644 codegen/templates/deployers/Target3Deployer.sol.jinja create mode 100644 codegen/templates/deployers/Target4Deployer.sol.jinja diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja new file mode 100644 index 000000000..6be40d501 --- /dev/null +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol"; +import { ERC4626Hyperdrive } from "../../instances/erc4626/ERC4626Hyperdrive.sol"; + +/// @author DELV +/// @title ERC4626HyperdriveCoreDeployer +/// @notice The core deployer for the ERC4626Hyperdrive 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 ERC4626HyperdriveCoreDeployer is IHyperdriveCoreDeployer { + /// @notice Deploys a Hyperdrive instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the ERC4626 vault. + /// @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 ERC4626Hyperdrive instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + address _target0, + address _target1, + address _target2, + address _target3, + address _target4, + bytes32 _salt + ) external returns (address) { + address vault = abi.decode(_extraData, (address)); + return ( + address( + // NOTE: We hash the sender with the salt to prevent the + // front-running of deployments. + new ERC4626Hyperdrive{ + salt: keccak256(abi.encode(msg.sender, _salt)) + }( + _config, + _target0, + _target1, + _target2, + _target3, + _target4, + IERC4626(vault) + ) + ) + ); + } +} diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja new file mode 100644 index 000000000..e69de29bb From 48f7037dd27b9466b0c99b50405473b957ed06db Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 20 Mar 2024 12:46:19 -0500 Subject: [PATCH 03/25] add basic example for one file --- codegen/example/config.yaml | 5 ++ codegen/hyperdrive_codegen/main.py | 76 +++++++++++++++++++ codegen/pyproject.toml | 2 +- .../HyperdriveCoreDeployer.sol.jinja | 18 ++--- 4 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 codegen/example/config.yaml diff --git a/codegen/example/config.yaml b/codegen/example/config.yaml new file mode 100644 index 000000000..41d6b83ea --- /dev/null +++ b/codegen/example/config.yaml @@ -0,0 +1,5 @@ +# Template configuration +name: + capitalized: "TestETH" + lowercase: "testeth" + camelcase: "testEth" \ No newline at end of file diff --git a/codegen/hyperdrive_codegen/main.py b/codegen/hyperdrive_codegen/main.py index f70cc6e77..b9f93c611 100644 --- a/codegen/hyperdrive_codegen/main.py +++ b/codegen/hyperdrive_codegen/main.py @@ -1,8 +1,84 @@ +"""Main entrypoint for hyperdrive-codegen tool.""" + +import os +from pathlib import Path + +import yaml +from jinja2 import Environment, FileSystemLoader +from pydantic import BaseModel + + def main(): + """Main entrypoint for the hyperdrive-codegen tool. Handles command-line arguments and calling codegen().""" + print("Welcome to Hyperdrive Codegen!") # Your code generation logic will go here. # For now, let's just print a message to the terminal. print("This tool generates boilerplate code for the Hyperdrive project using Jinja templates.") + codegen() + + +class Name(BaseModel): + """Holds different versions of the instance name.""" + + capitalized: str + lowercase: str + camelcase: str + + +class TemplateConfig(BaseModel): + """Configuration parameters for the codegen templates.""" + + name: Name + + +def codegen(): + """Main script to generate hyperdrive integration boilerplate code.""" + + # load config file + config_file_path = Path("./example/config.yaml") + with open(config_file_path, "r", encoding="utf-8") as file: + config_data = yaml.safe_load(file) + + template_config = TemplateConfig(**config_data) + + # load template files + env = get_jinja_env() + core_deployer_template = env.get_template("deployers/HyperdriveCoreDeployer.sol.jinja") + + # generate the code + rendered_code = core_deployer_template.render(name=template_config.name) + + # write to file + output_path = Path("./example/out/deployers") + contract_file_name = f"{template_config.name.capitalized}HyperdriveCoreDeployer.sol" + contract_file_path = Path(os.path.join(output_path, contract_file_name)) + write_string_to_file(contract_file_path, rendered_code) + + +def get_jinja_env() -> Environment: + """Returns the jinja environment.""" + script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Construct the path to your templates directory. + templates_dir = os.path.join(script_dir, "../templates") + env = Environment(loader=FileSystemLoader(templates_dir)) + + return env + + +def write_string_to_file(path: str | os.PathLike, code: str) -> None: + """Writes a string to a file. + + Parameters + ---------- + path : str | os.PathLike + The location of the output file. + code : str + The code to be written, as a single string. + """ + with open(path, "w", encoding="utf-8") as output_file: + output_file.write(code) if __name__ == "__main__": diff --git a/codegen/pyproject.toml b/codegen/pyproject.toml index 15981553b..0dd3d5950 100644 --- a/codegen/pyproject.toml +++ b/codegen/pyproject.toml @@ -15,7 +15,7 @@ version = "0.0.1" readme = "README.md" requires-python = ">=3.10" authors = [{ name = "Matthew Brown", email = "matt@delv.tech" }] -dependencies = ["jinja2>=2.11"] +dependencies = ["jinja2", "pydantic", "pyyaml"] [project.scripts] hyperdrive-codegen = "hyperdrive_codegen.main:main" diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja index 6be40d501..60a66e1b2 100644 --- a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -1,28 +1,28 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { I{{ name.capitalized }}} from "../../interfaces/{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol"; -import { ERC4626Hyperdrive } from "../../instances/erc4626/ERC4626Hyperdrive.sol"; +import { {{ name.capitalized }}Hyperdrive } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Hyperdrive.sol"; /// @author DELV -/// @title ERC4626HyperdriveCoreDeployer -/// @notice The core deployer for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}HyperdriveCoreDeployer +/// @notice The core deployer for the {{ name.capitalized }}Hyperdrive 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 ERC4626HyperdriveCoreDeployer is IHyperdriveCoreDeployer { +contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer { /// @notice Deploys a Hyperdrive instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the ERC4626 vault. + /// @param _extraData The extra data that contains the vault. /// @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 ERC4626Hyperdrive instance. + /// @return The address of the newly deployed {{ name.capitalized }}Hyperdrive instance. function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, @@ -38,7 +38,7 @@ contract ERC4626HyperdriveCoreDeployer is IHyperdriveCoreDeployer { address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new ERC4626Hyperdrive{ + new {{ name.capitalized }}Hyperdrive{ salt: keccak256(abi.encode(msg.sender, _salt)) }( _config, @@ -47,7 +47,7 @@ contract ERC4626HyperdriveCoreDeployer is IHyperdriveCoreDeployer { _target2, _target3, _target4, - IERC4626(vault) + {{ name.capitalized }}(vault) ) ) ); From cee32c4431db11fc578dffa64777fa1a9835049b Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 20 Mar 2024 14:20:13 -0500 Subject: [PATCH 04/25] move things to their own files --- codegen/example/config.yaml | 2 +- codegen/hyperdrive_codegen/codegen.py | 0 codegen/hyperdrive_codegen/config.py | 17 ++++++ codegen/hyperdrive_codegen/file.py | 17 ++++++ codegen/hyperdrive_codegen/jinja.py | 16 ++++++ codegen/hyperdrive_codegen/main.py | 74 +-------------------------- 6 files changed, 52 insertions(+), 74 deletions(-) create mode 100644 codegen/hyperdrive_codegen/codegen.py create mode 100644 codegen/hyperdrive_codegen/config.py create mode 100644 codegen/hyperdrive_codegen/file.py create mode 100644 codegen/hyperdrive_codegen/jinja.py diff --git a/codegen/example/config.yaml b/codegen/example/config.yaml index 41d6b83ea..58810db17 100644 --- a/codegen/example/config.yaml +++ b/codegen/example/config.yaml @@ -2,4 +2,4 @@ name: capitalized: "TestETH" lowercase: "testeth" - camelcase: "testEth" \ No newline at end of file + camelcase: "testEth" diff --git a/codegen/hyperdrive_codegen/codegen.py b/codegen/hyperdrive_codegen/codegen.py new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/hyperdrive_codegen/config.py b/codegen/hyperdrive_codegen/config.py new file mode 100644 index 000000000..4d9c943e9 --- /dev/null +++ b/codegen/hyperdrive_codegen/config.py @@ -0,0 +1,17 @@ +"""Utilities for working with the template config file.""" + +from pydantic import BaseModel + + +class Name(BaseModel): + """Holds different versions of the instance name.""" + + capitalized: str + lowercase: str + camelcase: str + + +class TemplateConfig(BaseModel): + """Configuration parameters for the codegen templates.""" + + name: Name diff --git a/codegen/hyperdrive_codegen/file.py b/codegen/hyperdrive_codegen/file.py new file mode 100644 index 000000000..e7d963b54 --- /dev/null +++ b/codegen/hyperdrive_codegen/file.py @@ -0,0 +1,17 @@ +"""Utilities for working with files.""" + +import os + + +def write_string_to_file(path: str | os.PathLike, code: str) -> None: + """Writes a string to a file. + + Parameters + ---------- + path : str | os.PathLike + The location of the output file. + code : str + The code to be written, as a single string. + """ + with open(path, "w", encoding="utf-8") as output_file: + output_file.write(code) diff --git a/codegen/hyperdrive_codegen/jinja.py b/codegen/hyperdrive_codegen/jinja.py new file mode 100644 index 000000000..c7553ba93 --- /dev/null +++ b/codegen/hyperdrive_codegen/jinja.py @@ -0,0 +1,16 @@ +"""Utilities for working with jinja.""" + +import os + +from jinja2 import Environment, FileSystemLoader + + +def get_jinja_env() -> Environment: + """Returns the jinja environment.""" + script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Construct the path to your templates directory. + templates_dir = os.path.join(script_dir, "../templates") + env = Environment(loader=FileSystemLoader(templates_dir)) + + return env diff --git a/codegen/hyperdrive_codegen/main.py b/codegen/hyperdrive_codegen/main.py index b9f93c611..6ab8dc379 100644 --- a/codegen/hyperdrive_codegen/main.py +++ b/codegen/hyperdrive_codegen/main.py @@ -1,85 +1,13 @@ """Main entrypoint for hyperdrive-codegen tool.""" -import os -from pathlib import Path - -import yaml -from jinja2 import Environment, FileSystemLoader -from pydantic import BaseModel +from hyperdrive_codegen.codegen import codegen def main(): """Main entrypoint for the hyperdrive-codegen tool. Handles command-line arguments and calling codegen().""" - print("Welcome to Hyperdrive Codegen!") - # Your code generation logic will go here. - # For now, let's just print a message to the terminal. - print("This tool generates boilerplate code for the Hyperdrive project using Jinja templates.") codegen() -class Name(BaseModel): - """Holds different versions of the instance name.""" - - capitalized: str - lowercase: str - camelcase: str - - -class TemplateConfig(BaseModel): - """Configuration parameters for the codegen templates.""" - - name: Name - - -def codegen(): - """Main script to generate hyperdrive integration boilerplate code.""" - - # load config file - config_file_path = Path("./example/config.yaml") - with open(config_file_path, "r", encoding="utf-8") as file: - config_data = yaml.safe_load(file) - - template_config = TemplateConfig(**config_data) - - # load template files - env = get_jinja_env() - core_deployer_template = env.get_template("deployers/HyperdriveCoreDeployer.sol.jinja") - - # generate the code - rendered_code = core_deployer_template.render(name=template_config.name) - - # write to file - output_path = Path("./example/out/deployers") - contract_file_name = f"{template_config.name.capitalized}HyperdriveCoreDeployer.sol" - contract_file_path = Path(os.path.join(output_path, contract_file_name)) - write_string_to_file(contract_file_path, rendered_code) - - -def get_jinja_env() -> Environment: - """Returns the jinja environment.""" - script_dir = os.path.dirname(os.path.abspath(__file__)) - - # Construct the path to your templates directory. - templates_dir = os.path.join(script_dir, "../templates") - env = Environment(loader=FileSystemLoader(templates_dir)) - - return env - - -def write_string_to_file(path: str | os.PathLike, code: str) -> None: - """Writes a string to a file. - - Parameters - ---------- - path : str | os.PathLike - The location of the output file. - code : str - The code to be written, as a single string. - """ - with open(path, "w", encoding="utf-8") as output_file: - output_file.write(code) - - if __name__ == "__main__": main() From 87abbf46b35b4efa8eb9fa35f47ae0548168bd62 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 20 Mar 2024 14:32:02 -0500 Subject: [PATCH 05/25] add ability to parse command line arguments --- codegen/hyperdrive_codegen/codegen.py | 34 ++++++++++++++++ codegen/hyperdrive_codegen/main.py | 57 +++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/codegen/hyperdrive_codegen/codegen.py b/codegen/hyperdrive_codegen/codegen.py index e69de29bb..dd8d7d566 100644 --- a/codegen/hyperdrive_codegen/codegen.py +++ b/codegen/hyperdrive_codegen/codegen.py @@ -0,0 +1,34 @@ +"""The main script to generate hyperdrive integration boilerplate code.""" + +import os +from pathlib import Path + +import yaml + +from hyperdrive_codegen.config import TemplateConfig +from hyperdrive_codegen.file import write_string_to_file +from hyperdrive_codegen.jinja import get_jinja_env + + +def codegen(config_file_path: Path | str, output_dir: Path | str): + """Main script to generate hyperdrive integration boilerplate code.""" + + # load config file + config_file_path = Path(config_file_path) + with open(config_file_path, "r", encoding="utf-8") as file: + config_data = yaml.safe_load(file) + + template_config = TemplateConfig(**config_data) + + # load template files + env = get_jinja_env() + core_deployer_template = env.get_template("deployers/HyperdriveCoreDeployer.sol.jinja") + + # generate the code + rendered_code = core_deployer_template.render(name=template_config.name) + + # write to file + output_path = Path(output_dir) + contract_file_name = f"{template_config.name.capitalized}HyperdriveCoreDeployer.sol" + contract_file_path = Path(os.path.join(output_path, contract_file_name)) + write_string_to_file(contract_file_path, rendered_code) diff --git a/codegen/hyperdrive_codegen/main.py b/codegen/hyperdrive_codegen/main.py index 6ab8dc379..1d4db07f3 100644 --- a/codegen/hyperdrive_codegen/main.py +++ b/codegen/hyperdrive_codegen/main.py @@ -1,12 +1,63 @@ """Main entrypoint for hyperdrive-codegen tool.""" +import argparse +import sys +from typing import NamedTuple, Sequence + from hyperdrive_codegen.codegen import codegen -def main(): - """Main entrypoint for the hyperdrive-codegen tool. Handles command-line arguments and calling codegen().""" +def main(argv: Sequence[str] | None = None) -> None: + """Main entrypoint for the hyperdrive-codegen tool. Handles command-line arguments and calling codegen(). + + Parameters + ---------- + argv : Sequence[str] | None, optional + Command line arguments + """ + config_file_path, output_dir = parse_arguments(argv) + codegen(config_file_path, output_dir) + + +class Args(NamedTuple): + """Command line arguments for pypechain.""" + + config_file_path: str + output_dir: str + + +def namespace_to_args(namespace: argparse.Namespace) -> Args: + """Converts argprase.Namespace to Args.""" + return Args( + config_file_path=namespace.config, + output_dir=namespace.out, + ) + + +def parse_arguments(argv: Sequence[str] | None = None) -> Args: + """Parses input arguments""" + parser = argparse.ArgumentParser(description="Generates class files for a given abi.") + parser.add_argument( + "--config", + help="Path to the config yaml file.", + ) + + parser.add_argument( + "--out", + default="./out", + help="Path to the directory where files will be generated. Defaults to out/.", + ) + + # Use system arguments if none were passed + if argv is None: + argv = sys.argv + + # If no arguments were passed, display the help message and exit + if len(argv) == 1: + parser.print_help(sys.stderr) + sys.exit(1) - codegen() + return namespace_to_args(parser.parse_args()) if __name__ == "__main__": From 1c37a1731621dc73e536b1b36ba8e4f1f594feb8 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 20 Mar 2024 14:41:32 -0500 Subject: [PATCH 06/25] setup the directory --- codegen/hyperdrive_codegen/codegen.py | 6 ++-- codegen/hyperdrive_codegen/file.py | 45 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/codegen/hyperdrive_codegen/codegen.py b/codegen/hyperdrive_codegen/codegen.py index dd8d7d566..09548ff5b 100644 --- a/codegen/hyperdrive_codegen/codegen.py +++ b/codegen/hyperdrive_codegen/codegen.py @@ -6,7 +6,7 @@ import yaml from hyperdrive_codegen.config import TemplateConfig -from hyperdrive_codegen.file import write_string_to_file +from hyperdrive_codegen.file import get_output_folder_structure, setup_directory, write_string_to_file from hyperdrive_codegen.jinja import get_jinja_env @@ -28,7 +28,9 @@ def codegen(config_file_path: Path | str, output_dir: Path | str): rendered_code = core_deployer_template.render(name=template_config.name) # write to file + folder_structure = get_output_folder_structure(template_config.name.lowercase) + setup_directory(output_dir, folder_structure, True) output_path = Path(output_dir) contract_file_name = f"{template_config.name.capitalized}HyperdriveCoreDeployer.sol" - contract_file_path = Path(os.path.join(output_path, contract_file_name)) + contract_file_path = Path(os.path.join(output_path, "deployers", contract_file_name)) write_string_to_file(contract_file_path, rendered_code) diff --git a/codegen/hyperdrive_codegen/file.py b/codegen/hyperdrive_codegen/file.py index e7d963b54..eb4c92519 100644 --- a/codegen/hyperdrive_codegen/file.py +++ b/codegen/hyperdrive_codegen/file.py @@ -1,6 +1,8 @@ """Utilities for working with files.""" import os +import shutil +from pathlib import Path def write_string_to_file(path: str | os.PathLike, code: str) -> None: @@ -15,3 +17,46 @@ def write_string_to_file(path: str | os.PathLike, code: str) -> None: """ with open(path, "w", encoding="utf-8") as output_file: output_file.write(code) + + +def get_output_folder_structure(lowercase_name: str) -> dict: + """Returns a dictionary representation of the output folder structure. + + Parameters + ---------- + lowercase_name: str + The name of the protocol we are generating boilerplate integration code for. Should be in all lowercase letters. + + Returns + ------- + dict + """ + return {"deployers": {lowercase_name: {}}, "instances": {lowercase_name: {}}, "interfaces": {lowercase_name: {}}} + + +def setup_directory(base_path: Path | str, structure: dict, clear_existing: bool = False) -> None: + """Recursively sets up a directory tree based on a given structure. Existing directories can be optionally cleared. + + Parameters + ---------- + base_path : Path + The base path where the directory tree starts. + structure : dict + A nested dictionary representing the directory structure to be created. Each key is a directory name with its value being another dictionary for subdirectories. + clear_existing : bool, optional + Whether to clear existing directories before setting up the new structure. Defaults to False. + """ + base_path = Path(base_path) + if clear_existing and base_path.exists(): + shutil.rmtree(base_path) + base_path.mkdir(parents=True, exist_ok=True) + + for name, sub_structure in structure.items(): + sub_path = base_path / name + if clear_existing and sub_path.exists(): + shutil.rmtree(sub_path) + sub_path.mkdir(exist_ok=True) + + if isinstance(sub_structure, dict): + # Recursively set up subdirectories + setup_directory(sub_path, sub_structure, clear_existing) From 25a7180b46748e16e8c18882060fc18124928039 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Thu, 21 Mar 2024 14:37:02 -0500 Subject: [PATCH 07/25] copy deployer files to templates --- .../HyperdriveDeployerCoordinator.sol.jinja | 134 ++++++++++++++++++ .../deployers/Target0Deployer.sol.jinja | 36 +++++ .../deployers/Target1Deployer.sol.jinja | 36 +++++ .../deployers/Target2Deployer.sol.jinja | 36 +++++ .../deployers/Target3Deployer.sol.jinja | 36 +++++ .../deployers/Target4Deployer.sol.jinja | 36 +++++ 6 files changed, 314 insertions(+) diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index e69de29bb..728da47ec 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IERC4626Hyperdrive } from "../../interfaces/IERC4626Hyperdrive.sol"; +import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol"; +import { ONE } from "../../libraries/FixedPointMath.sol"; +import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol"; + +/// @author DELV +/// @title ERC4626HyperdriveDeployerCoordinator +/// @notice The deployer coordinator for the ERC4626Hyperdrive 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 ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { + using SafeERC20 for ERC20; + + /// @notice Instantiates the deployer coordinator. + /// @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( + address _coreDeployer, + address _target0Deployer, + address _target1Deployer, + address _target2Deployer, + address _target3Deployer, + address _target4Deployer + ) + HyperdriveDeployerCoordinator( + _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 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) { + // If base is the deposit asset, the initialization will be paid in the + // base token. + address token; + if (_options.asBase) { + token = _hyperdrive.baseToken(); + } + // Otherwise, the initialization will be paid in vault shares. + else { + token = address(IERC4626Hyperdrive(address(_hyperdrive)).vault()); + } + + // Take custody of the contribution and approve Hyperdrive to pull the + // tokens. + ERC20(token).safeTransferFrom(_lp, address(this), _contribution); + ERC20(token).forceApprove(address(_hyperdrive), _contribution); + + // NOTE: Return zero since this yield source isn't payable. + return 0; + } + + /// @dev Prevents the contract from receiving ether. + 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. + function _checkPoolConfig( + IHyperdrive.PoolDeployConfig memory _deployConfig + ) internal view override { + // Perform the default checks. + super._checkPoolConfig(_deployConfig); + + // 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. + if ( + _deployConfig.minimumShareReserves < + 10 ** (_deployConfig.baseToken.decimals() - 4) + ) { + 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 ** (_deployConfig.baseToken.decimals() - 4) + ) { + revert IHyperdriveDeployerCoordinator + .InvalidMinimumTransactionAmount(); + } + } + + /// @dev Gets the initial vault share price of the Hyperdrive pool. + /// @param _extraData The extra data passed to the child deployers. + /// @return The initial vault share price of the Hyperdrive pool. + function _getInitialVaultSharePrice( + bytes memory _extraData + ) internal view override returns (uint256) { + // Return the vault's current share price. + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return vault.convertToAssets(ONE); + } +} diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja index e69de29bb..a97b7cf1e 100644 --- a/codegen/templates/deployers/Target0Deployer.sol.jinja +++ b/codegen/templates/deployers/Target0Deployer.sol.jinja @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC4626Target0 } from "../../instances/erc4626/ERC4626Target0.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; + +/// @author DELV +/// @title ERC4626Target0Deployer +/// @notice The target0 deployer for the ERC4626Hyperdrive 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 ERC4626Target0Deployer is IHyperdriveTargetDeployer { + /// @notice Deploys a target0 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed ERC4626Target0 instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return + address( + // NOTE: We hash the sender with the salt to prevent the + // front-running of deployments. + new ERC4626Target0{ + salt: keccak256(abi.encode(msg.sender, _salt)) + }(_config, vault) + ); + } +} diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja index e69de29bb..54f8ac007 100644 --- a/codegen/templates/deployers/Target1Deployer.sol.jinja +++ b/codegen/templates/deployers/Target1Deployer.sol.jinja @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC4626Target1 } from "../../instances/erc4626/ERC4626Target1.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; + +/// @author DELV +/// @title ERC4626Target1Deployer +/// @notice The target1 deployer for the ERC4626Hyperdrive 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 ERC4626Target1Deployer is IHyperdriveTargetDeployer { + /// @notice Deploys a target1 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed ERC4626Target1 instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return + address( + // NOTE: We hash the sender with the salt to prevent the + // front-running of deployments. + new ERC4626Target1{ + salt: keccak256(abi.encode(msg.sender, _salt)) + }(_config, vault) + ); + } +} diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja index e69de29bb..d78f69cb9 100644 --- a/codegen/templates/deployers/Target2Deployer.sol.jinja +++ b/codegen/templates/deployers/Target2Deployer.sol.jinja @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC4626Target2 } from "../../instances/erc4626/ERC4626Target2.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; + +/// @author DELV +/// @title ERC4626Target2Deployer +/// @notice The target2 deployer for the ERC4626Hyperdrive 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 ERC4626Target2Deployer is IHyperdriveTargetDeployer { + /// @notice Deploys a target2 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed ERC4626Target2 instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return + address( + // NOTE: We hash the sender with the salt to prevent the + // front-running of deployments. + new ERC4626Target2{ + salt: keccak256(abi.encode(msg.sender, _salt)) + }(_config, vault) + ); + } +} diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja index e69de29bb..62b9f2c03 100644 --- a/codegen/templates/deployers/Target3Deployer.sol.jinja +++ b/codegen/templates/deployers/Target3Deployer.sol.jinja @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC4626Target3 } from "../../instances/erc4626/ERC4626Target3.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; + +/// @author DELV +/// @title ERC4626Target3Deployer +/// @notice The target3 deployer for the ERC4626Hyperdrive 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 ERC4626Target3Deployer is IHyperdriveTargetDeployer { + /// @notice Deploys a target3 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed ERC4626Target3 instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return + address( + // NOTE: We hash the sender with the salt to prevent the + // front-running of deployments. + new ERC4626Target3{ + salt: keccak256(abi.encode(msg.sender, _salt)) + }(_config, vault) + ); + } +} diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja index e69de29bb..0eb9b1aa8 100644 --- a/codegen/templates/deployers/Target4Deployer.sol.jinja +++ b/codegen/templates/deployers/Target4Deployer.sol.jinja @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC4626Target4 } from "../../instances/erc4626/ERC4626Target4.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; + +/// @author DELV +/// @title ERC4626Target4Deployer +/// @notice The target4 deployer for the ERC4626Hyperdrive 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 ERC4626Target4Deployer is IHyperdriveTargetDeployer { + /// @notice Deploys a target4 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed ERC4626Target4 instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return + address( + // NOTE: We hash the sender with the salt to prevent the + // front-running of deployments. + new ERC4626Target4{ + salt: keccak256(abi.encode(msg.sender, _salt)) + }(_config, vault) + ); + } +} From 57b26dc3855fc8efc2a4e5ef7b7d8f03c8ab91d1 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 08:19:43 -0500 Subject: [PATCH 08/25] add target deployer templates --- codegen/example/config.yaml | 15 +++ .../HyperdriveDeployerCoordinator.sol.jinja | 104 +++++++++++++----- .../deployers/Target0Deployer.sol.jinja | 26 +++-- .../deployers/Target1Deployer.sol.jinja | 26 +++-- .../deployers/Target2Deployer.sol.jinja | 26 +++-- .../deployers/Target3Deployer.sol.jinja | 26 +++-- .../deployers/Target4Deployer.sol.jinja | 26 +++-- 7 files changed, 175 insertions(+), 74 deletions(-) diff --git a/codegen/example/config.yaml b/codegen/example/config.yaml index 58810db17..8beb89b51 100644 --- a/codegen/example/config.yaml +++ b/codegen/example/config.yaml @@ -1,5 +1,20 @@ # Template configuration + +# Vault naming formats. name: capitalized: "TestETH" lowercase: "testeth" camelcase: "testEth" + +# Configuration parameters for the hyperdrive instance. +contract: + + # If the contract is payable in Ether. If it is, then logic should be added + # to accept Ether, and deposit into the vault to obtain vault shares. + payable: false + + # If the contract can accept base to convert to valut shares on behalf of the + # user. + as_base_allowed: false + + diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index 728da47ec..db06476c3 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -3,20 +3,21 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { I{{ name.capitalized }}} from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; -import { IERC4626Hyperdrive } from "../../interfaces/IERC4626Hyperdrive.sol"; +import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/I{{ name.capitalized }}Hyperdrive.sol"; import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol"; import { ONE } from "../../libraries/FixedPointMath.sol"; import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol"; /// @author DELV -/// @title ERC4626HyperdriveDeployerCoordinator -/// @notice The deployer coordinator for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}HyperdriveDeployerCoordinator +/// @notice The deployer coordinator for the {{ name.capitalized }}Hyperdrive +/// 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 ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { +contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { using SafeERC20 for ERC20; /// @notice Instantiates the deployer coordinator. @@ -60,6 +61,38 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { uint256 _contribution, IHyperdrive.Options memory _options ) internal override returns (uint256) { +{% if contract.as_base_allowed && contract.payable %} + // If base is the deposit asset, ensure that enough ether was sent to + // the contract and return the amount of ether that should be sent for + // the contribution. + if (_options.asBase) { + if (msg.value < _contribution) { + revert IHyperdriveDeployerCoordinator.InsufficientValue(); + } + value = _contribution; + } + + // Otherwise, transfer vault shares from the LP and approve the + // Hyperdrive pool. + else { + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. + // Take custody of the contribution and approve Hyperdrive to pull + // the tokens. + token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + ERC20(token).safeTransferFrom(_lp, address(this), _contribution); + ERC20(token).forceApprove(address(_hyperdrive), _contribution); + uint256 approvalAmount = {{ name.camelCase }}.transferSharesFrom( + _lp, + address(this), + _contribution + ); + {{}}.approve(address(_hyperdrive), approvalAmount); + // **************************************************************** + } + + return value; +{% elif contract.as_base_allowed and not contract.payable %} // If base is the deposit asset, the initialization will be paid in the // base token. address token; @@ -68,24 +101,46 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { } // Otherwise, the initialization will be paid in vault shares. else { - token = address(IERC4626Hyperdrive(address(_hyperdrive)).vault()); + token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); } + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. // Take custody of the contribution and approve Hyperdrive to pull the // tokens. ERC20(token).safeTransferFrom(_lp, address(this), _contribution); ERC20(token).forceApprove(address(_hyperdrive), _contribution); + // **************************************************************** +{% elif not contract.as_base_allowed and not contract.payable %} + // Depositing as base is disallowed. + if (_options.asBase) { + revert IHyperdrive.UnsupportedToken(); + } + + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. + // Otherwise, transfer vault shares from the LP and approve the + // Hyperdrive pool. + address token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + ERC20(token).transferFrom(_lp, address(this), _contribution); + ezETH.approve(address(_hyperdrive), _contribution); + // **************************************************************** - // NOTE: Return zero since this yield source isn't payable. - return 0; + return value; +{% endif %} } +{% if contract.payable %} + /// @dev Allows the contract to receive ether. + function _checkMessageValue() internal view override {} +{% else %} /// @dev Prevents the contract from receiving ether. function _checkMessageValue() internal view override { if (msg.value != 0) { revert IHyperdriveDeployerCoordinator.NotPayable(); } } +{% endif %} /// @notice Checks the pool configuration to ensure that it is valid. /// @param _deployConfig The deploy configuration of the Hyperdrive pool. @@ -95,27 +150,17 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { // Perform the default checks. super._checkPoolConfig(_deployConfig); - // 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. - if ( - _deployConfig.minimumShareReserves < - 10 ** (_deployConfig.baseToken.decimals() - 4) - ) { + // Ensure that the minimum share reserves are equal to 1e15. This value + // has been tested to prevent arithmetic overflows in the + // `_updateLiquidity` function when the share reserves are as high as + // 200 million. + if (_deployConfig.minimumShareReserves != 1e15) { 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 ** (_deployConfig.baseToken.decimals() - 4) - ) { + // Ensure that the minimum transaction amount are equal to 1e15. This + // value has been tested to prevent precision issues. + if (_deployConfig.minimumTransactionAmount != 1e15) { revert IHyperdriveDeployerCoordinator .InvalidMinimumTransactionAmount(); } @@ -127,8 +172,9 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { function _getInitialVaultSharePrice( bytes memory _extraData ) internal view override returns (uint256) { - // Return the vault's current share price. - IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); - return vault.convertToAssets(ONE); + // **************************************************************** + // FIXME: Implement this for new instances. + return ONE; + // **************************************************************** } } diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja index a97b7cf1e..81fb7e5f1 100644 --- a/codegen/templates/deployers/Target0Deployer.sol.jinja +++ b/codegen/templates/deployers/Target0Deployer.sol.jinja @@ -1,36 +1,44 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { ERC4626Target0 } from "../../instances/erc4626/ERC4626Target0.sol"; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { {{ name.capitalized }}Target0 } from "../../instances/erc4626/{{ name.capitalized }}Target0.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV -/// @title ERC4626Target0Deployer -/// @notice The target0 deployer for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}Target0Deployer +/// @notice The target0 deployer for the {{ name.capitalized }}Hyperdrive 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 ERC4626Target0Deployer is IHyperdriveTargetDeployer { +contract {{ name.capitalized }}Target0Deployer is IHyperdriveTargetDeployer { + /// @notice The {{ name.capitalized }} contract. + I{{ name.capitalized }} public immutable {{ name.camelcase }}; + + /// @notice Instantiates the core deployer. + /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. + constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { + {{ name.camelcase }} = _{{ name.camelcase }}; + } + /// @notice Deploys a target0 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. - /// @return The address of the newly deployed ERC4626Target0 instance. + /// @return The address of the newly deployed {{ name.capitalized }}Target0 instance. function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, bytes32 _salt ) external returns (address) { - IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); return address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new ERC4626Target0{ + new {{ name.capitalized }}Target0{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, vault) + }(_config, {{ name.camelcase }}) ); } } diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja index 54f8ac007..fdb59bc21 100644 --- a/codegen/templates/deployers/Target1Deployer.sol.jinja +++ b/codegen/templates/deployers/Target1Deployer.sol.jinja @@ -1,36 +1,44 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { ERC4626Target1 } from "../../instances/erc4626/ERC4626Target1.sol"; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { {{ name.capitalized }}Target1 } from "../../instances/erc4626/{{ name.capitalized }}Target1.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV -/// @title ERC4626Target1Deployer -/// @notice The target1 deployer for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}Target1Deployer +/// @notice The target1 deployer for the {{ name.capitalized }}Hyperdrive 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 ERC4626Target1Deployer is IHyperdriveTargetDeployer { +contract {{ name.capitalized }}Target1Deployer is IHyperdriveTargetDeployer { + /// @notice The {{ name.capitalized }} contract. + I{{ name.capitalized }} public immutable {{ name.camelcase }}; + + /// @notice Instantiates the core deployer. + /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. + constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { + {{ name.camelcase }} = _{{ name.camelcase }}; + } + /// @notice Deploys a target1 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. - /// @return The address of the newly deployed ERC4626Target1 instance. + /// @return The address of the newly deployed {{ name.capitalized }}Target1 instance. function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, bytes32 _salt ) external returns (address) { - IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); return address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new ERC4626Target1{ + new {{ name.capitalized }}Target1{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, vault) + }(_config, {{ name.camelcase }}) ); } } diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja index d78f69cb9..20c59e4f5 100644 --- a/codegen/templates/deployers/Target2Deployer.sol.jinja +++ b/codegen/templates/deployers/Target2Deployer.sol.jinja @@ -1,36 +1,44 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { ERC4626Target2 } from "../../instances/erc4626/ERC4626Target2.sol"; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { {{ name.capitalized }}Target2 } from "../../instances/erc4626/{{ name.capitalized }}Target2.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV -/// @title ERC4626Target2Deployer -/// @notice The target2 deployer for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}Target2Deployer +/// @notice The target2 deployer for the {{ name.capitalized }}Hyperdrive 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 ERC4626Target2Deployer is IHyperdriveTargetDeployer { +contract {{ name.capitalized }}Target2Deployer is IHyperdriveTargetDeployer { + /// @notice The {{ name.capitalized }} contract. + I{{ name.capitalized }} public immutable {{ name.camelcase }}; + + /// @notice Instantiates the core deployer. + /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. + constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { + {{ name.camelcase }} = _{{ name.camelcase }}; + } + /// @notice Deploys a target2 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. - /// @return The address of the newly deployed ERC4626Target2 instance. + /// @return The address of the newly deployed {{ name.capitalized }}Target2 instance. function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, bytes32 _salt ) external returns (address) { - IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); return address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new ERC4626Target2{ + new {{ name.capitalized }}Target2{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, vault) + }(_config, {{ name.camelcase }}) ); } } diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja index 62b9f2c03..404f96c28 100644 --- a/codegen/templates/deployers/Target3Deployer.sol.jinja +++ b/codegen/templates/deployers/Target3Deployer.sol.jinja @@ -1,36 +1,44 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { ERC4626Target3 } from "../../instances/erc4626/ERC4626Target3.sol"; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { {{ name.capitalized }}Target3 } from "../../instances/erc4626/{{ name.capitalized }}Target3.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV -/// @title ERC4626Target3Deployer -/// @notice The target3 deployer for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}Target3Deployer +/// @notice The target3 deployer for the {{ name.capitalized }}Hyperdrive 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 ERC4626Target3Deployer is IHyperdriveTargetDeployer { +contract {{ name.capitalized }}Target3Deployer is IHyperdriveTargetDeployer { + /// @notice The {{ name.capitalized }} contract. + I{{ name.capitalized }} public immutable {{ name.camelcase }}; + + /// @notice Instantiates the core deployer. + /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. + constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { + {{ name.camelcase }} = _{{ name.camelcase }}; + } + /// @notice Deploys a target3 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. - /// @return The address of the newly deployed ERC4626Target3 instance. + /// @return The address of the newly deployed {{ name.capitalized }}Target3 instance. function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, bytes32 _salt ) external returns (address) { - IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); return address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new ERC4626Target3{ + new {{ name.capitalized }}Target3{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, vault) + }(_config, {{ name.camelcase }}) ); } } diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja index 0eb9b1aa8..893a1adaf 100644 --- a/codegen/templates/deployers/Target4Deployer.sol.jinja +++ b/codegen/templates/deployers/Target4Deployer.sol.jinja @@ -1,36 +1,44 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { ERC4626Target4 } from "../../instances/erc4626/ERC4626Target4.sol"; -import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { {{ name.capitalized }}Target4 } from "../../instances/erc4626/{{ name.capitalized }}Target4.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV -/// @title ERC4626Target4Deployer -/// @notice The target4 deployer for the ERC4626Hyperdrive implementation. +/// @title {{ name.capitalized }}Target4Deployer +/// @notice The target4 deployer for the {{ name.capitalized }}Hyperdrive 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 ERC4626Target4Deployer is IHyperdriveTargetDeployer { +contract {{ name.capitalized }}Target4Deployer is IHyperdriveTargetDeployer { + /// @notice The {{ name.capitalized }} contract. + I{{ name.capitalized }} public immutable {{ name.camelcase }}; + + /// @notice Instantiates the core deployer. + /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. + constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { + {{ name.camelcase }} = _{{ name.camelcase }}; + } + /// @notice Deploys a target4 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. - /// @return The address of the newly deployed ERC4626Target4 instance. + /// @return The address of the newly deployed {{ name.capitalized }}Target4 instance. function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, bytes32 _salt ) external returns (address) { - IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); return address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new ERC4626Target4{ + new {{ name.capitalized }}Target4{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, vault) + }(_config, {{ name.camelcase }}) ); } } From c3cd85df041c50497e1e29874f47901a5a64d73d Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 08:46:13 -0500 Subject: [PATCH 09/25] add instance templates --- codegen/templates/instances/Base.sol.jinja | 180 ++++++++++++++++++ .../templates/instances/Hyperdrive.sol.jinja | 97 ++++++++++ codegen/templates/instances/Target0.sol.jinja | 39 ++++ codegen/templates/instances/Target1.sol.jinja | 25 +++ codegen/templates/instances/Target2.sol.jinja | 25 +++ codegen/templates/instances/Target3.sol.jinja | 25 +++ codegen/templates/instances/Target4.sol.jinja | 25 +++ 7 files changed, 416 insertions(+) create mode 100644 codegen/templates/instances/Base.sol.jinja create mode 100644 codegen/templates/instances/Hyperdrive.sol.jinja create mode 100644 codegen/templates/instances/Target0.sol.jinja create mode 100644 codegen/templates/instances/Target1.sol.jinja create mode 100644 codegen/templates/instances/Target2.sol.jinja create mode 100644 codegen/templates/instances/Target3.sol.jinja create mode 100644 codegen/templates/instances/Target4.sol.jinja diff --git a/codegen/templates/instances/Base.sol.jinja b/codegen/templates/instances/Base.sol.jinja new file mode 100644 index 000000000..2976a47d1 --- /dev/null +++ b/codegen/templates/instances/Base.sol.jinja @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/I{{ name.capitalized }}Hyperdrive.sol"; +import { HyperdriveBase } from "../../internal/HyperdriveBase.sol"; +import { FixedPointMath, ONE } from "../../libraries/FixedPointMath.sol"; + +/// @author DELV +/// @title {{ name.capitalized }}Base +/// @notice The base contract for the {{ name.capitalized }} Hyperdrive implementation. +/// @dev This Hyperdrive implementation is designed to work with standard +/// {{ name.capitalized }} vaults. Non-standard implementations may not work correctly +/// and should be carefully checked. +/// @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. +abstract contract {{ name.capitalized }}Base is HyperdriveBase { + using FixedPointMath for uint256; + using SafeERC20 for ERC20; + + /// @dev The {{ name.capitalized }} vault that this pool uses as a yield source. + I{{ name.capitalized }} internal immutable _vault; + + /// @notice Instantiates the {{ name.capitalized }} Hyperdrive base contract. + /// @param __vault The {{ name.capitalized }} compatible vault. + constructor(I{{ name.capitalized }} __vault) { + // Initialize the pool immutable. + _vault = __vault; + } + + /// Yield Source /// + + /// @dev Accepts a deposit from the user in base. + /// @param _baseAmount The base amount to deposit. + /// @return The shares that were minted in the deposit. + /// @return The amount of ETH to refund. Since this yield source isn't + /// payable, this is always zero. + function _depositWithBase( + uint256 _baseAmount, + bytes calldata // unused + ) internal override returns (uint256, uint256) { + + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. + // Take custody of the deposit in base. + ERC20(address(_baseToken)).safeTransferFrom( + msg.sender, + address(this), + _baseAmount + ); + + // Deposit the base into the yield source. + // + // NOTE: We increase the required approval amount by 1 wei so that + // the vault ends with an approval of 1 wei. This makes future + // approvals cheaper by keeping the storage slot warm. + ERC20(address(_baseToken)).forceApprove( + address(_vault), + _baseAmount + 1 + ); + uint256 sharesMinted = _vault.deposit(_baseAmount, address(this)); + + return (sharesMinted, 0); + // **************************************************************** + } + + /// @dev Process a deposit in vault shares. + /// @param _shareAmount The vault shares amount to deposit. + function _depositWithShares( + uint256 _shareAmount, + bytes calldata // unused + ) internal override { + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. + // Take custody of the deposit in vault shares. + ERC20(address(_vault)).safeTransferFrom( + msg.sender, + address(this), + _shareAmount + ); + // **************************************************************** + } + + /// @dev Process a withdrawal in base and send the proceeds to the + /// destination. + /// @param _shareAmount The amount of vault shares to withdraw. + /// @param _destination The destination of the withdrawal. + /// @return amountWithdrawn The amount of base withdrawn. + function _withdrawWithBase( + uint256 _shareAmount, + address _destination, + bytes calldata // unused + ) internal override returns (uint256 amountWithdrawn) { + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. + // Redeem from the yield source and transfer the + // resulting base to the destination address. + amountWithdrawn = _vault.redeem( + _shareAmount, + _destination, + address(this) + ); + + return amountWithdrawn; + // **************************************************************** + } + + /// @dev Process a withdrawal in vault shares and send the proceeds to the + /// destination. + /// @param _shareAmount The amount of vault shares to withdraw. + /// @param _destination The destination of the withdrawal. + function _withdrawWithShares( + uint256 _shareAmount, + address _destination, + bytes calldata // unused + ) internal override { + // **************************************************************** + // FIXME: Implement this for new instances. ERC20 example provided. + // Transfer vault shares to the destination. + ERC20(address(_vault)).safeTransfer(_destination, _shareAmount); + // **************************************************************** + } + + /// @dev Ensure that ether wasn't sent because {{ name.capitalized }} vaults don't support + /// deposits of ether. + function _checkMessageValue() internal view override { + // **************************************************************** + // FIXME: Implement this for new instances. + if (msg.value != 0) { + revert IHyperdrive.NotPayable(); + } + // **************************************************************** + } + + /// @dev Convert an amount of vault shares to an amount of base. + /// @param _shareAmount The vault shares amount. + /// @return The base amount. + function _convertToBase( + uint256 _shareAmount + ) internal view override returns (uint256) { + // **************************************************************** + // FIXME: Implement this for new instances. + return _vault.convertToAssets(_shareAmount); + // **************************************************************** + } + + /// @dev Convert an amount of base to an amount of vault shares. + /// @param _baseAmount The base amount. + /// @return The vault shares amount. + function _convertToShares( + uint256 _baseAmount + ) internal view override returns (uint256) { + // **************************************************************** + // FIXME: Implement this for new instances. + return _vault.convertToShares(_baseAmount); + // **************************************************************** + } + + /// @dev Gets the total amount of base held by the pool. + /// @return baseAmount The total amount of base. + function _totalBase() internal view override returns (uint256) { + return _baseToken.balanceOf(address(this)); + } + + /// @dev Gets the total amount of shares held by the pool in the yield + /// source. + /// @return shareAmount The total amount of shares. + function _totalShares() + internal + view + override + returns (uint256 shareAmount) + { + return _vault.balanceOf(address(this)); + } +} diff --git a/codegen/templates/instances/Hyperdrive.sol.jinja b/codegen/templates/instances/Hyperdrive.sol.jinja new file mode 100644 index 000000000..5e21d52cf --- /dev/null +++ b/codegen/templates/instances/Hyperdrive.sol.jinja @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; +import { Hyperdrive } from "../../external/Hyperdrive.sol"; +import { ERC20 } from "../../interfaces/IERC20.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { FixedPointMath } from "../../libraries/FixedPointMath.sol"; +import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; + +/// ______ __ _________ _____ +/// ___ / / /____ ___________________________ /_________(_)__ ______ +/// __ /_/ /__ / / /__ __ \ _ \_ ___/ __ /__ ___/_ /__ | / / _ \ +/// _ __ / _ /_/ /__ /_/ / __/ / / /_/ / _ / _ / __ |/ // __/ +/// /_/ /_/ _\__, / _ ___/\___//_/ \__,_/ /_/ /_/ _____/ \___/ +/// /____/ /_/ +/// XXX ++ ++ XXX +/// ############ XXXXX ++0+ +0++ XXXXX ########### +/// ##////////////######## ++00++ ++00++ ########///////////## +/// ##////////////########## ++000++ ++000++ ##########///////////## +/// ##%%%%%%///// ###### ++0000+ +0000++ ###### /////%%%%%%## +/// %%%%%%%%&& ## ++0000+ +0000++ ## &&%%%%%%%%% +/// %&&& ## +o000+ +000o+ ## &&&% +/// ## ++00+- -+00++ ## +/// #% ++0+ +0++ %# +/// ###-:Oo.++++.oO:-### +/// ##: 00++++++00 :## +/// #S###########* 0++00+++00++0 *##########S# +/// #S % $ 0+++0 $ % S# +/// #S ---------- %+++++:#:+++++%----------- S# +/// #S ------------- %++++: ### :++++%------------ S# +/// S ---------------%++++*\ | /*++++%------------- S +/// #S --------------- %++++ ~W~ ++++%666--o UUUU o- S# +/// #S? --------------- %+++++~+++++%&&&8 o \ / o ?S# +/// ?*????**+++;::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::;+++**????*? +/// #?+////////////////////////////////////////////////////////////////+?# +/// #;;;;;//////////////////////////////////////////////////////////////;;;;;# +/// S;;;;;;;;;//////////////////////////////////////////////////////////;;;;;;;;;S +/// /;;;;;;;;;;;///////////////////////////////////////////////////////;;;;;;;;;;;;\ +/// |||OOOOOOOO||OOOOOOOO=========== __ ___ ===========OOOOOOOO||OOOOOOOO||| +/// |||OOOOOOOO||OOOOOOOO===========| \[__ | \ /===========OOOOOOOO||OOOOOOOO||| +/// |||OOOOOOOO||OOOOOOOO===========|__/[___|___ \/ ===========OOOOOOOO||OOOOOOOO||| +/// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +/// |||////////000000000000\\\\\\\\|:::::::::::::::|////////00000000000\\\\\\\\\\||| +/// SSS\\\\\\\\000000000000////////|:::::0x666:::::|\\\\\\\\00000000000//////////SSS +/// SSS|||||||||||||||||||||||||||||:::::::::::::::||||||||||||||||||||||||||||||SSS +/// SSSSSSSS|_______________|______________||_______________|______________|SSSSSSSS +/// SSSSSSSS SSSSSSSS +/// SSSSSSSS SSSSSSSS +/// +/// @author DELV +/// @title {{ name.capitalized }}Hyperdrive +/// @notice A Hyperdrive instance that uses a {{ name.capitalized }} vault as the yield source. +/// @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 {{ name.capitalized }}Hyperdrive is Hyperdrive, {{ name.capitalized }}Base { + using FixedPointMath for uint256; + using SafeERC20 for ERC20; + + /// @notice Instantiates Hyperdrive with a {{ name.capitalized }} vault as the yield source. + /// @param _config The configuration of the Hyperdrive pool. + /// @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 __vault The {{ name.capitalized }} compatible yield source. + constructor( + IHyperdrive.PoolConfig memory _config, + address _target0, + address _target1, + address _target2, + address _target3, + address _target4, + I{{ name.capitalized }} __vault + ) + Hyperdrive(_config, _target0, _target1, _target2, _target3, _target4) + {{ name.capitalized }}Base(__vault) + { + + // **************************************************************** + // FIXME: Implement this for new instances. ERC4626 example provided. + // Ensure that the base token is the same as the vault's underlying + // asset. + if (address(_config.baseToken) != I{{ name.capitalized }}(_vault).asset()) { + revert IHyperdrive.InvalidBaseToken(); + } + + // Approve the base token with 1 wei. This ensures that all of the + // subsequent approvals will be writing to a dirty storage slot. + ERC20(address(_config.baseToken)).forceApprove(address(_vault), 1); + // **************************************************************** + } +} diff --git a/codegen/templates/instances/Target0.sol.jinja b/codegen/templates/instances/Target0.sol.jinja new file mode 100644 index 000000000..a9d3b955b --- /dev/null +++ b/codegen/templates/instances/Target0.sol.jinja @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; +import { HyperdriveTarget0 } from "../../external/HyperdriveTarget0.sol"; +import { IERC20 } from "../../interfaces/IERC20.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; + +/// @author DELV +/// @title {{ name.capitalized }}Target0 +/// @notice {{ name.capitalized }}Hyperdrive's target0 logic contract. This contract contains +/// all of the getters for Hyperdrive as well as some stateful +/// functions. +/// @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 {{ name.capitalized }}Target0 is HyperdriveTarget0, {{ name.capitalized }}Base { + using SafeERC20 for ERC20; + + /// @notice Initializes the target0 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param __vault The {{ name.capitalized }} compatible vault. + constructor( + IHyperdrive.PoolConfig memory _config, + I{{ name.capitalized }} __vault + ) HyperdriveTarget0(_config) {{ name.capitalized }}Base(__vault) {} + + /// Getters /// + + /// @notice Gets the {{ name.capitalized }} compatible vault used as this pool's yield + /// source. + /// @return The {{ name.capitalized }} compatible yield source. + function vault() external view returns (I{{ name.capitalized }}) { + _revert(abi.encode(_vault)); + } +} diff --git a/codegen/templates/instances/Target1.sol.jinja b/codegen/templates/instances/Target1.sol.jinja new file mode 100644 index 000000000..46bb34450 --- /dev/null +++ b/codegen/templates/instances/Target1.sol.jinja @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { HyperdriveTarget1 } from "../../external/HyperdriveTarget1.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; + +/// @author DELV +/// @title {{ name.capitalized }}Target1 +/// @notice {{ name.capitalized }}Hyperdrive's target1 logic contract. This contract contains +/// several stateful functions that couldn't fit into the Hyperdrive +/// contract. +/// @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 {{ name.capitalized }}Target1 is HyperdriveTarget1, {{ name.capitalized }}Base { + /// @notice Initializes the target1 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param __vault The {{ name.capitalized }} compatible vault. + constructor( + IHyperdrive.PoolConfig memory _config, + I{{ name.capitalized }} __vault + ) HyperdriveTarget1(_config) {{ name.capitalized }}Base(__vault) {} +} diff --git a/codegen/templates/instances/Target2.sol.jinja b/codegen/templates/instances/Target2.sol.jinja new file mode 100644 index 000000000..96a0dbfb8 --- /dev/null +++ b/codegen/templates/instances/Target2.sol.jinja @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { HyperdriveTarget2 } from "../../external/HyperdriveTarget2.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; + +/// @author DELV +/// @title {{ name.capitalized }}Target2 +/// @notice {{ name.capitalized }}Hyperdrive's target2 logic contract. This contract contains +/// several stateful functions that couldn't fit into the Hyperdrive +/// contract. +/// @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 {{ name.capitalized }}Target2 is HyperdriveTarget2, {{ name.capitalized }}Base { + /// @notice Initializes the target2 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param __vault The {{ name.capitalized }} compatible vault. + constructor( + IHyperdrive.PoolConfig memory _config, + I{{ name.capitalized }} __vault + ) HyperdriveTarget2(_config) {{ name.capitalized }}Base(__vault) {} +} diff --git a/codegen/templates/instances/Target3.sol.jinja b/codegen/templates/instances/Target3.sol.jinja new file mode 100644 index 000000000..e388b216a --- /dev/null +++ b/codegen/templates/instances/Target3.sol.jinja @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { HyperdriveTarget3 } from "../../external/HyperdriveTarget3.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; + +/// @author DELV +/// @title {{ name.capitalized }}Target3 +/// @notice {{ name.capitalized }}Hyperdrive's target3 logic contract. This contract contains +/// several stateful functions that couldn't fit into the Hyperdrive +/// contract. +/// @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 {{ name.capitalized }}Target3 is HyperdriveTarget3, {{ name.capitalized }}Base { + /// @notice Initializes the target3 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param __vault The {{ name.capitalized }} compatible vault. + constructor( + IHyperdrive.PoolConfig memory _config, + I{{ name.capitalized }} __vault + ) HyperdriveTarget3(_config) {{ name.capitalized }}Base(__vault) {} +} diff --git a/codegen/templates/instances/Target4.sol.jinja b/codegen/templates/instances/Target4.sol.jinja new file mode 100644 index 000000000..70dd42483 --- /dev/null +++ b/codegen/templates/instances/Target4.sol.jinja @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { HyperdriveTarget4 } from "../../external/HyperdriveTarget4.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; + +/// @author DELV +/// @title {{ name.capitalized }}Target4 +/// @notice {{ name.capitalized }}Hyperdrive's target4 logic contract. This contract contains +/// several stateful functions that couldn't fit into the Hyperdrive +/// contract. +/// @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 {{ name.capitalized }}Target4 is HyperdriveTarget4, {{ name.capitalized }}Base { + /// @notice Initializes the target4 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param __vault The {{ name.capitalized }} compatible vault. + constructor( + IHyperdrive.PoolConfig memory _config, + I{{ name.capitalized }} __vault + ) HyperdriveTarget4(_config) {{ name.capitalized }}Base(__vault) {} +} From 9cabd524ef56c218297f3185d47d6470f8015fd3 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 08:46:19 -0500 Subject: [PATCH 10/25] config comments --- codegen/example/config.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/codegen/example/config.yaml b/codegen/example/config.yaml index 8beb89b51..248881688 100644 --- a/codegen/example/config.yaml +++ b/codegen/example/config.yaml @@ -2,13 +2,18 @@ # Vault naming formats. name: + # Capitalized version of the name to be used i.e. for contract names, file + # names, and comments. capitalized: "TestETH" + + # All lower case name to be used for directories. lowercase: "testeth" + + # Camel case name to be used i.e. for variables. camelcase: "testEth" # Configuration parameters for the hyperdrive instance. contract: - # If the contract is payable in Ether. If it is, then logic should be added # to accept Ether, and deposit into the vault to obtain vault shares. payable: false @@ -16,5 +21,3 @@ contract: # If the contract can accept base to convert to valut shares on behalf of the # user. as_base_allowed: false - - From 64df2bd8c1cee1eaddcfa10b5c470387396b5441 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 10:58:07 -0500 Subject: [PATCH 11/25] render all template files --- codegen/hyperdrive_codegen/codegen.py | 36 +++++------ codegen/hyperdrive_codegen/config.py | 36 +++++++++++ codegen/hyperdrive_codegen/templates.py | 86 +++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 codegen/hyperdrive_codegen/templates.py diff --git a/codegen/hyperdrive_codegen/codegen.py b/codegen/hyperdrive_codegen/codegen.py index 09548ff5b..0e95e2a87 100644 --- a/codegen/hyperdrive_codegen/codegen.py +++ b/codegen/hyperdrive_codegen/codegen.py @@ -1,36 +1,30 @@ """The main script to generate hyperdrive integration boilerplate code.""" -import os from pathlib import Path -import yaml +from jinja2 import Environment -from hyperdrive_codegen.config import TemplateConfig -from hyperdrive_codegen.file import get_output_folder_structure, setup_directory, write_string_to_file +from hyperdrive_codegen.config import get_template_config +from hyperdrive_codegen.file import get_output_folder_structure, setup_directory from hyperdrive_codegen.jinja import get_jinja_env +from hyperdrive_codegen.templates import get_templates, write_templates_to_files def codegen(config_file_path: Path | str, output_dir: Path | str): """Main script to generate hyperdrive integration boilerplate code.""" - # load config file - config_file_path = Path(config_file_path) - with open(config_file_path, "r", encoding="utf-8") as file: - config_data = yaml.safe_load(file) + # Load the configuration file that has all the variables used in the + # template files. + template_config = get_template_config(config_file_path) - template_config = TemplateConfig(**config_data) + # Get the templates to render. + env: Environment = get_jinja_env() + templates = get_templates(env) - # load template files - env = get_jinja_env() - core_deployer_template = env.get_template("deployers/HyperdriveCoreDeployer.sol.jinja") - - # generate the code - rendered_code = core_deployer_template.render(name=template_config.name) - - # write to file + # Setup the output directory. folder_structure = get_output_folder_structure(template_config.name.lowercase) - setup_directory(output_dir, folder_structure, True) output_path = Path(output_dir) - contract_file_name = f"{template_config.name.capitalized}HyperdriveCoreDeployer.sol" - contract_file_path = Path(os.path.join(output_path, "deployers", contract_file_name)) - write_string_to_file(contract_file_path, rendered_code) + setup_directory(output_path, folder_structure, True) + + # Write the templates to files. + write_templates_to_files(templates, output_path, template_config) diff --git a/codegen/hyperdrive_codegen/config.py b/codegen/hyperdrive_codegen/config.py index 4d9c943e9..652f8da22 100644 --- a/codegen/hyperdrive_codegen/config.py +++ b/codegen/hyperdrive_codegen/config.py @@ -1,5 +1,8 @@ """Utilities for working with the template config file.""" +from pathlib import Path + +import yaml from pydantic import BaseModel @@ -11,7 +14,40 @@ class Name(BaseModel): camelcase: str +class Contract(BaseModel): + + payable: bool + as_base_allowed: bool + + class TemplateConfig(BaseModel): """Configuration parameters for the codegen templates.""" name: Name + + contract: Contract + + +def get_template_config(config_file_path: str | Path) -> TemplateConfig: + """Loads a yaml configuation file into a TemplateConfig model. The + TemplateConfig holds all the variables the jinja template files use. + + Parameters + ---------- + config_file_path : str | Path + The path to the yaml config. + + Returns + ------- + TemplateConfig + The template configuration. + """ + + # Load the raw configuration data. + config_file_path = Path(config_file_path) + with open(config_file_path, "r", encoding="utf-8") as file: + config_data = yaml.safe_load(file) + + # Populate the configuration model and return the result. + template_config = TemplateConfig(**config_data) + return template_config diff --git a/codegen/hyperdrive_codegen/templates.py b/codegen/hyperdrive_codegen/templates.py new file mode 100644 index 000000000..5666435bd --- /dev/null +++ b/codegen/hyperdrive_codegen/templates.py @@ -0,0 +1,86 @@ +"""Template helpers.""" + +import os +from dataclasses import dataclass +from pathlib import Path + +from jinja2 import Environment, Template + +from hyperdrive_codegen.config import TemplateConfig +from hyperdrive_codegen.file import write_string_to_file + + +@dataclass +class TemplatePathInfo: + path: str + base_name: str + folder: str + + +@dataclass +class TemplateInfo: + template: Template + path_info: TemplatePathInfo + + +deployer_templates = [ + TemplatePathInfo("deployers/HyperdriveCoreDeployer.sol.jinja", "HyperdriveCoreDeployer.sol", "deployers"), + TemplatePathInfo("deployers/HyperdriveDeployerCoordinator.sol.jinja", "HyperdriveDeployerCoordinator", "deployers"), + TemplatePathInfo("deployers/Target0Deployer.sol.jinja", "Target0Deployer", "deployers"), + TemplatePathInfo("deployers/Target1Deployer.sol.jinja", "Target1Deployer", "deployers"), + TemplatePathInfo("deployers/Target2Deployer.sol.jinja", "Target2Deployer", "deployers"), + TemplatePathInfo("deployers/Target3Deployer.sol.jinja", "Target3Deployer", "deployers"), + TemplatePathInfo("deployers/Target4Deployer.sol.jinja", "Target4Deployer", "deployers"), +] + +instance_templates = [ + TemplatePathInfo("instances/Base.sol.jinja", "Base", "instances"), + TemplatePathInfo("instances/Hyperdrive.sol.jinja", "Hyperdrive", "instances"), + TemplatePathInfo("instances/Target0.sol.jinja", "Target0", "instances"), + TemplatePathInfo("instances/Target1.sol.jinja", "Target1", "instances"), + TemplatePathInfo("instances/Target2.sol.jinja", "Target2", "instances"), + TemplatePathInfo("instances/Target3.sol.jinja", "Target3", "instances"), + TemplatePathInfo("instances/Target4.sol.jinja", "Target4", "instances"), +] + + +def get_templates(env: Environment) -> list[TemplateInfo]: + """Returns a list of template files for generating customized Hyperdrive instances. + + Parameters + ---------- + env : Environment + A jinja2 environment that is informed where the templates/ directory is. + + Returns + ------- + list[Template] + The list of jinja2 templates. + """ + + # Gather the template file strings and return a list of TemplateInfo's. + path_infos = deployer_templates + instance_templates + return [TemplateInfo(template=env.get_template(path_info.path), path_info=path_info) for path_info in path_infos] + + +@dataclass +class FileInfo: + template: TemplateInfo + rendered_code: str + + +def write_templates_to_files(templates: list[TemplateInfo], output_path: Path, template_config: TemplateConfig): + for template in templates: + # Get the file information and rendered code. + file_info = FileInfo(template, rendered_code=template.template.render(template_config.model_dump())) + + # Get the contract file path. + contract_file_name = f"{template_config.name.capitalized}{file_info.template.path_info.base_name}.sol" + contract_file_path = Path( + os.path.join( + output_path, file_info.template.path_info.folder, template_config.name.lowercase, contract_file_name + ) + ) + + # Write the rendered code to file. + write_string_to_file(contract_file_path, file_info.rendered_code) From cb0b23ff99a234b25640c9c5b45f2327724bebec Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 10:58:33 -0500 Subject: [PATCH 12/25] update README --- codegen/README.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/codegen/README.md b/codegen/README.md index bf54ab12c..df6c7284c 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -1,31 +1,38 @@ # Integrations Codegen Guide -To make integrating hyperdrive with other protocols easier, we've created tooling to generate most of the boilerplate code. This guide walks though how to install and run the codegen tools. + +To make integrating hyperdrive with other protocols easier, we've created tooling to generate most of the boilerplate code. This guide walks though how to install and run the codegen tools. Here's a quick overview of the directory. + +``` hyperdrive/ │ ├── codegen/ # Codegen tool directory │ ├── hyperdrive-codegen/ # Python package for the codegen tool │ │ ├── __init__.py # Makes hyperdrive-codegen a Python package -│ │ ├── main.py # Entry point of your tool +│ │ ├── main.py # Entry point of the tool, handles command line arguments, calls codegen.py +| | ├── codegen.py # Main script of the tool │ │ └── ... # Other Python modules and package data │ │ │ ├── templates/ # Jinja templates directory │ │ └── ... # Template files │ │ +│ ├── example/ # An example result of the tool +│ │ └── config.yaml # The template configuration file +│ │ └── out/ # The generated code +│ │ │ ├── pyproject.toml # Configuration file for build system and dependencies │ └── .venv/ # Virtual environment (excluded from version control) │ ├── contracts/ # Solidity contracts directory │ └── ... # Solidity files - +``` ## Install - ### 0. Install Python -You'll need to have python installed on your machine to use this tool. Installation varies by operatin system. +You'll need to have python installed on your machine to use this tool. Installation varies by operatin system. ### 1. Install Pyenv @@ -36,6 +43,7 @@ Follow [Pyenv install instructions](https://github.com/pyenv/pyenv#installation) You can use any environment, but we recommend [venv](https://docs.python.org/3/library/venv.html), which is part of the standard Python library. From hyperdrive's root directory, run: + ```bash pip install --upgrade pip pyenv install 3.10 @@ -48,16 +56,14 @@ source .venv/bin/activate To install the dependencies: -````bash +```bash pip install -e . -```` - +``` ### 5. Check Installation Verify that your package was installed correctly by running something like pip list. You should see hyperdrive-codegen listed as a package. - ## Usage If installation was successful, you should be able to run the command from the terminal: @@ -65,4 +71,3 @@ If installation was successful, you should be able to run the command from the t ```bash hyperdrive-codegen ``` - From 0b73fae2390e2eea95cd1c38bbf88c2d6b0677d7 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 10:58:52 -0500 Subject: [PATCH 13/25] fix deployercoordinator template --- .../deployers/HyperdriveDeployerCoordinator.sol.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index db06476c3..09905c299 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -61,7 +61,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy uint256 _contribution, IHyperdrive.Options memory _options ) internal override returns (uint256) { -{% if contract.as_base_allowed && contract.payable %} +{% if contract.as_base_allowed and contract.payable %} // If base is the deposit asset, ensure that enough ether was sent to // the contract and return the amount of ether that should be sent for // the contribution. @@ -87,7 +87,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy address(this), _contribution ); - {{}}.approve(address(_hyperdrive), approvalAmount); + token.approve(address(_hyperdrive), approvalAmount); // **************************************************************** } From 755d9418040aee8abd7b35d2eab70ebbd2e97cfc Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 11:13:26 -0500 Subject: [PATCH 14/25] cleanup --- codegen/hyperdrive_codegen/templates.py | 28 ++++++++++++++++++++----- codegen/pyproject.toml | 8 +++++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/codegen/hyperdrive_codegen/templates.py b/codegen/hyperdrive_codegen/templates.py index 5666435bd..b58af60c2 100644 --- a/codegen/hyperdrive_codegen/templates.py +++ b/codegen/hyperdrive_codegen/templates.py @@ -12,6 +12,8 @@ @dataclass class TemplatePathInfo: + """Path and name information for the template.""" + path: str base_name: str folder: str @@ -19,10 +21,20 @@ class TemplatePathInfo: @dataclass class TemplateInfo: + """Contains a jinja template and path information.""" + template: Template path_info: TemplatePathInfo +@dataclass +class FileInfo: + """Contains template information and the rendered code.""" + + template: TemplateInfo + rendered_code: str + + deployer_templates = [ TemplatePathInfo("deployers/HyperdriveCoreDeployer.sol.jinja", "HyperdriveCoreDeployer.sol", "deployers"), TemplatePathInfo("deployers/HyperdriveDeployerCoordinator.sol.jinja", "HyperdriveDeployerCoordinator", "deployers"), @@ -63,13 +75,19 @@ def get_templates(env: Environment) -> list[TemplateInfo]: return [TemplateInfo(template=env.get_template(path_info.path), path_info=path_info) for path_info in path_infos] -@dataclass -class FileInfo: - template: TemplateInfo - rendered_code: str +def write_templates_to_files(templates: list[TemplateInfo], output_path: Path, template_config: TemplateConfig): + """Writes a given list of templates to file. + Parameters + ---------- + templates : list[TemplateInfo] + Template information containing path information and the rendered code. + output_path : Path + The directory to write files to. + template_config : TemplateConfig + Template configuration, has all the variables the jinja templates use. + """ -def write_templates_to_files(templates: list[TemplateInfo], output_path: Path, template_config: TemplateConfig): for template in templates: # Get the file information and rendered code. file_info = FileInfo(template, rendered_code=template.template.render(template_config.model_dump())) diff --git a/codegen/pyproject.toml b/codegen/pyproject.toml index 0dd3d5950..708f23f21 100644 --- a/codegen/pyproject.toml +++ b/codegen/pyproject.toml @@ -1,6 +1,4 @@ [build-system] -# requires = ["setuptools>=42", "wheel"] -# build-backend = "setuptools.build_meta" requires = ["flit_core>=3.2"] build-backend = "flit_core.buildapi" @@ -19,3 +17,9 @@ dependencies = ["jinja2", "pydantic", "pyyaml"] [project.scripts] hyperdrive-codegen = "hyperdrive_codegen.main:main" + +[tool.black] +line-length = 120 + +[tool.pylint] +max-line-length = 120 From 355784668484f690ea02e063e19ccdd5f811ba84 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 14:02:50 -0500 Subject: [PATCH 15/25] fixup imports, add interace, fixup README --- codegen/README.md | 29 +++++++++++++++++-- codegen/hyperdrive_codegen/codegen.py | 3 +- codegen/hyperdrive_codegen/templates.py | 16 ++++++++-- .../HyperdriveCoreDeployer.sol.jinja | 2 +- .../HyperdriveDeployerCoordinator.sol.jinja | 4 +-- .../deployers/Target0Deployer.sol.jinja | 4 +-- .../deployers/Target1Deployer.sol.jinja | 4 +-- .../deployers/Target2Deployer.sol.jinja | 4 +-- .../deployers/Target3Deployer.sol.jinja | 4 +-- .../deployers/Target4Deployer.sol.jinja | 4 +-- codegen/templates/instances/Base.sol.jinja | 4 +-- .../templates/instances/Hyperdrive.sol.jinja | 2 +- codegen/templates/instances/Target0.sol.jinja | 2 +- codegen/templates/instances/Target1.sol.jinja | 2 +- codegen/templates/instances/Target2.sol.jinja | 2 +- codegen/templates/instances/Target3.sol.jinja | 2 +- codegen/templates/instances/Target4.sol.jinja | 2 +- .../interfaces/IHyperdrive.sol.jinja | 10 +++++++ .../interfaces/IYieldSource.sol.jinja | 15 ++++++++++ 19 files changed, 88 insertions(+), 27 deletions(-) create mode 100644 codegen/templates/interfaces/IHyperdrive.sol.jinja create mode 100644 codegen/templates/interfaces/IYieldSource.sol.jinja diff --git a/codegen/README.md b/codegen/README.md index df6c7284c..37f600441 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -66,8 +66,33 @@ Verify that your package was installed correctly by running something like pip l ## Usage -If installation was successful, you should be able to run the command from the terminal: +If installation was successful, from the `example/` directory you should be able to run the command: ```bash -hyperdrive-codegen +hyperdrive-codegen --config config.yaml ``` + +Which will output all the generated code in `example/out`. + +### 6. VSCode Debugging + +Add the following VSCode launch configuration, to be able to debug the tool: + +```json +// codegen/.vscode/launch.json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Codegen Debugger", + "type": "debugpy", + "request": "launch", + "program": "./hyperdrive_codegen/main.py", + "console": "integratedTerminal", + "args": "--config ./example/config.yaml --out ./example/out" + } + ] +} +``` + +Note that VSCode should be launched from the codegen/ directory, not the hyperdrive directory. diff --git a/codegen/hyperdrive_codegen/codegen.py b/codegen/hyperdrive_codegen/codegen.py index 0e95e2a87..cd496c872 100644 --- a/codegen/hyperdrive_codegen/codegen.py +++ b/codegen/hyperdrive_codegen/codegen.py @@ -24,7 +24,8 @@ def codegen(config_file_path: Path | str, output_dir: Path | str): # Setup the output directory. folder_structure = get_output_folder_structure(template_config.name.lowercase) output_path = Path(output_dir) - setup_directory(output_path, folder_structure, True) + clear_existing = False + setup_directory(output_path, folder_structure, clear_existing) # Write the templates to files. write_templates_to_files(templates, output_path, template_config) diff --git a/codegen/hyperdrive_codegen/templates.py b/codegen/hyperdrive_codegen/templates.py index b58af60c2..581acc4d1 100644 --- a/codegen/hyperdrive_codegen/templates.py +++ b/codegen/hyperdrive_codegen/templates.py @@ -36,7 +36,7 @@ class FileInfo: deployer_templates = [ - TemplatePathInfo("deployers/HyperdriveCoreDeployer.sol.jinja", "HyperdriveCoreDeployer.sol", "deployers"), + TemplatePathInfo("deployers/HyperdriveCoreDeployer.sol.jinja", "HyperdriveCoreDeployer", "deployers"), TemplatePathInfo("deployers/HyperdriveDeployerCoordinator.sol.jinja", "HyperdriveDeployerCoordinator", "deployers"), TemplatePathInfo("deployers/Target0Deployer.sol.jinja", "Target0Deployer", "deployers"), TemplatePathInfo("deployers/Target1Deployer.sol.jinja", "Target1Deployer", "deployers"), @@ -55,6 +55,11 @@ class FileInfo: TemplatePathInfo("instances/Target4.sol.jinja", "Target4", "instances"), ] +interface_templates = [ + TemplatePathInfo("interfaces/IHyperdrive.sol.jinja", "Hyperdrive", "interfaces"), + TemplatePathInfo("interfaces/IYieldSource.sol.jinja", "", "interfaces"), +] + def get_templates(env: Environment) -> list[TemplateInfo]: """Returns a list of template files for generating customized Hyperdrive instances. @@ -71,7 +76,7 @@ def get_templates(env: Environment) -> list[TemplateInfo]: """ # Gather the template file strings and return a list of TemplateInfo's. - path_infos = deployer_templates + instance_templates + path_infos = deployer_templates + instance_templates + interface_templates return [TemplateInfo(template=env.get_template(path_info.path), path_info=path_info) for path_info in path_infos] @@ -92,8 +97,13 @@ def write_templates_to_files(templates: list[TemplateInfo], output_path: Path, t # Get the file information and rendered code. file_info = FileInfo(template, rendered_code=template.template.render(template_config.model_dump())) - # Get the contract file path. + # Get the contract file name and prepend 'I' if it is an interface file. contract_file_name = f"{template_config.name.capitalized}{file_info.template.path_info.base_name}.sol" + contract_file_name = ( + "I" + contract_file_name if file_info.template.path_info.folder == "interfaces" else contract_file_name + ) + + # Get the path for the file name. contract_file_path = Path( os.path.join( output_path, file_info.template.path_info.folder, template_config.name.lowercase, contract_file_name diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja index 60a66e1b2..f9a4d541f 100644 --- a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { I{{ name.capitalized }}} from "../../interfaces/{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol"; import { {{ name.capitalized }}Hyperdrive } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Hyperdrive.sol"; diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index 09905c299..2161d7ea7 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -3,9 +3,9 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; -import { I{{ name.capitalized }}} from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; -import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/I{{ name.capitalized }}Hyperdrive.sol"; +import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}Hyperdrive.sol"; import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol"; import { ONE } from "../../libraries/FixedPointMath.sol"; import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol"; diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja index 81fb7e5f1..2fdf4d899 100644 --- a/codegen/templates/deployers/Target0Deployer.sol.jinja +++ b/codegen/templates/deployers/Target0Deployer.sol.jinja @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { {{ name.capitalized }}Target0 } from "../../instances/erc4626/{{ name.capitalized }}Target0.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { {{ name.capitalized }}Target0 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target0.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja index fdb59bc21..032b6374b 100644 --- a/codegen/templates/deployers/Target1Deployer.sol.jinja +++ b/codegen/templates/deployers/Target1Deployer.sol.jinja @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { {{ name.capitalized }}Target1 } from "../../instances/erc4626/{{ name.capitalized }}Target1.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { {{ name.capitalized }}Target1 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target1.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja index 20c59e4f5..47eb9ac36 100644 --- a/codegen/templates/deployers/Target2Deployer.sol.jinja +++ b/codegen/templates/deployers/Target2Deployer.sol.jinja @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { {{ name.capitalized }}Target2 } from "../../instances/erc4626/{{ name.capitalized }}Target2.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { {{ name.capitalized }}Target2 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target2.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja index 404f96c28..ad263e721 100644 --- a/codegen/templates/deployers/Target3Deployer.sol.jinja +++ b/codegen/templates/deployers/Target3Deployer.sol.jinja @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { {{ name.capitalized }}Target3 } from "../../instances/erc4626/{{ name.capitalized }}Target3.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { {{ name.capitalized }}Target3 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target3.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja index 893a1adaf..ca4e03289 100644 --- a/codegen/templates/deployers/Target4Deployer.sol.jinja +++ b/codegen/templates/deployers/Target4Deployer.sol.jinja @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { {{ name.capitalized }}Target4 } from "../../instances/erc4626/{{ name.capitalized }}Target4.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { {{ name.capitalized }}Target4 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target4.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/instances/Base.sol.jinja b/codegen/templates/instances/Base.sol.jinja index 2976a47d1..78c8017ab 100644 --- a/codegen/templates/instances/Base.sol.jinja +++ b/codegen/templates/instances/Base.sol.jinja @@ -3,9 +3,9 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; -import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/I{{ name.capitalized }}Hyperdrive.sol"; +import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}Hyperdrive.sol"; import { HyperdriveBase } from "../../internal/HyperdriveBase.sol"; import { FixedPointMath, ONE } from "../../libraries/FixedPointMath.sol"; diff --git a/codegen/templates/instances/Hyperdrive.sol.jinja b/codegen/templates/instances/Hyperdrive.sol.jinja index 5e21d52cf..4e81c8d05 100644 --- a/codegen/templates/instances/Hyperdrive.sol.jinja +++ b/codegen/templates/instances/Hyperdrive.sol.jinja @@ -5,7 +5,7 @@ import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { Hyperdrive } from "../../external/Hyperdrive.sol"; import { ERC20 } from "../../interfaces/IERC20.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { FixedPointMath } from "../../libraries/FixedPointMath.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; diff --git a/codegen/templates/instances/Target0.sol.jinja b/codegen/templates/instances/Target0.sol.jinja index a9d3b955b..9f7af927e 100644 --- a/codegen/templates/instances/Target0.sol.jinja +++ b/codegen/templates/instances/Target0.sol.jinja @@ -5,7 +5,7 @@ import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { HyperdriveTarget0 } from "../../external/HyperdriveTarget0.sol"; import { IERC20 } from "../../interfaces/IERC20.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; diff --git a/codegen/templates/instances/Target1.sol.jinja b/codegen/templates/instances/Target1.sol.jinja index 46bb34450..95f615c6d 100644 --- a/codegen/templates/instances/Target1.sol.jinja +++ b/codegen/templates/instances/Target1.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { HyperdriveTarget1 } from "../../external/HyperdriveTarget1.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; diff --git a/codegen/templates/instances/Target2.sol.jinja b/codegen/templates/instances/Target2.sol.jinja index 96a0dbfb8..11b165a51 100644 --- a/codegen/templates/instances/Target2.sol.jinja +++ b/codegen/templates/instances/Target2.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { HyperdriveTarget2 } from "../../external/HyperdriveTarget2.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; diff --git a/codegen/templates/instances/Target3.sol.jinja b/codegen/templates/instances/Target3.sol.jinja index e388b216a..093169e8d 100644 --- a/codegen/templates/instances/Target3.sol.jinja +++ b/codegen/templates/instances/Target3.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { HyperdriveTarget3 } from "../../external/HyperdriveTarget3.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; diff --git a/codegen/templates/instances/Target4.sol.jinja b/codegen/templates/instances/Target4.sol.jinja index 70dd42483..30ef2d1ba 100644 --- a/codegen/templates/instances/Target4.sol.jinja +++ b/codegen/templates/instances/Target4.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { HyperdriveTarget4 } from "../../external/HyperdriveTarget4.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; diff --git a/codegen/templates/interfaces/IHyperdrive.sol.jinja b/codegen/templates/interfaces/IHyperdrive.sol.jinja new file mode 100644 index 000000000..979097cea --- /dev/null +++ b/codegen/templates/interfaces/IHyperdrive.sol.jinja @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { IHyperdrive } from "../IHyperdrive.sol"; + +// prettier-ignore +interface I{{ name.capitalized }}Hyperdrive is + IHyperdrive +{} + diff --git a/codegen/templates/interfaces/IYieldSource.sol.jinja b/codegen/templates/interfaces/IYieldSource.sol.jinja new file mode 100644 index 000000000..556516a53 --- /dev/null +++ b/codegen/templates/interfaces/IYieldSource.sol.jinja @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// @author is Fei Protocol - https://github.com/fei-protocol/ERC4626/blob/main/src/interfaces/IERC4626.sol +pragma solidity 0.8.20; + +// **************************************************************************** +// FIXME: Fill out this interface as needed. + +/// @author DELV +/// @title I{{ name.capitalized }} +/// @notice The interface file for {{ name.capitalized}} +/// @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. +abstract contract I{{ name.capitalized }} {} +// **************************************************************************** \ No newline at end of file From 12f7a53b8a4b964446f75b0d83f9341b3f5892d1 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 15:17:21 -0500 Subject: [PATCH 16/25] fix build issues --- codegen/example/test_example.py | 0 codegen/hyperdrive_codegen/codegen.py | 3 +-- codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja | 4 ++-- .../deployers/HyperdriveDeployerCoordinator.sol.jinja | 2 +- codegen/templates/instances/Hyperdrive.sol.jinja | 2 +- codegen/templates/interfaces/IYieldSource.sol.jinja | 4 +++- 6 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 codegen/example/test_example.py diff --git a/codegen/example/test_example.py b/codegen/example/test_example.py new file mode 100644 index 000000000..e69de29bb diff --git a/codegen/hyperdrive_codegen/codegen.py b/codegen/hyperdrive_codegen/codegen.py index cd496c872..1446aeee5 100644 --- a/codegen/hyperdrive_codegen/codegen.py +++ b/codegen/hyperdrive_codegen/codegen.py @@ -10,7 +10,7 @@ from hyperdrive_codegen.templates import get_templates, write_templates_to_files -def codegen(config_file_path: Path | str, output_dir: Path | str): +def codegen(config_file_path: Path | str, output_dir: Path | str, clear_existing: bool = False): """Main script to generate hyperdrive integration boilerplate code.""" # Load the configuration file that has all the variables used in the @@ -24,7 +24,6 @@ def codegen(config_file_path: Path | str, output_dir: Path | str): # Setup the output directory. folder_structure = get_output_folder_structure(template_config.name.lowercase) output_path = Path(output_dir) - clear_existing = False setup_directory(output_path, folder_structure, clear_existing) # Write the templates to files. diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja index f9a4d541f..a8cdcb244 100644 --- a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -38,7 +38,7 @@ contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new {{ name.capitalized }}Hyperdrive{ + new I{{ name.capitalized }}Hyperdrive{ salt: keccak256(abi.encode(msg.sender, _salt)) }( _config, @@ -47,7 +47,7 @@ contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer _target2, _target3, _target4, - {{ name.capitalized }}(vault) + I{{ name.capitalized }}(vault) ) ) ); diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index 2161d7ea7..88b98847d 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -123,7 +123,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy // Hyperdrive pool. address token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); ERC20(token).transferFrom(_lp, address(this), _contribution); - ezETH.approve(address(_hyperdrive), _contribution); + ERC20(token).approve(address(_hyperdrive), _contribution); // **************************************************************** return value; diff --git a/codegen/templates/instances/Hyperdrive.sol.jinja b/codegen/templates/instances/Hyperdrive.sol.jinja index 4e81c8d05..5255baa4e 100644 --- a/codegen/templates/instances/Hyperdrive.sol.jinja +++ b/codegen/templates/instances/Hyperdrive.sol.jinja @@ -4,7 +4,7 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { Hyperdrive } from "../../external/Hyperdrive.sol"; -import { ERC20 } from "../../interfaces/IERC20.sol"; +import { IERC20 } from "../../interfaces/IERC20.sol"; import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { FixedPointMath } from "../../libraries/FixedPointMath.sol"; diff --git a/codegen/templates/interfaces/IYieldSource.sol.jinja b/codegen/templates/interfaces/IYieldSource.sol.jinja index 556516a53..a9583e918 100644 --- a/codegen/templates/interfaces/IYieldSource.sol.jinja +++ b/codegen/templates/interfaces/IYieldSource.sol.jinja @@ -2,6 +2,8 @@ // @author is Fei Protocol - https://github.com/fei-protocol/ERC4626/blob/main/src/interfaces/IERC4626.sol pragma solidity 0.8.20; +import { IERC4626 } from "../IERC4626.sol"; + // **************************************************************************** // FIXME: Fill out this interface as needed. @@ -11,5 +13,5 @@ pragma solidity 0.8.20; /// @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. -abstract contract I{{ name.capitalized }} {} +abstract contract I{{ name.capitalized }} is IERC4626 {} // **************************************************************************** \ No newline at end of file From 7980db8b97e8e5b55e3a5931b2f0092b1ac1e5a0 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 16:42:05 -0500 Subject: [PATCH 17/25] lint fixes in solidity --- .../HyperdriveCoreDeployer.sol.jinja | 2 +- .../HyperdriveDeployerCoordinator.sol.jinja | 20 +++++++++---------- .../deployers/Target0Deployer.sol.jinja | 3 +-- .../deployers/Target1Deployer.sol.jinja | 3 +-- .../deployers/Target2Deployer.sol.jinja | 3 +-- .../deployers/Target3Deployer.sol.jinja | 3 +-- .../deployers/Target4Deployer.sol.jinja | 3 +-- .../interfaces/IHyperdrive.sol.jinja | 6 +++++- .../interfaces/IYieldSource.sol.jinja | 2 +- 9 files changed, 21 insertions(+), 24 deletions(-) diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja index a8cdcb244..1217d037c 100644 --- a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -38,7 +38,7 @@ contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. - new I{{ name.capitalized }}Hyperdrive{ + new {{ name.capitalized }}Hyperdrive{ salt: keccak256(abi.encode(msg.sender, _salt)) }( _config, diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index 88b98847d..ea239c5d9 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -54,14 +54,14 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy /// of `_options.asBase`. /// @param _options The options that configure how the initialization is /// settled. - /// @return The value that should be sent in the initialize transaction. + /// @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) { {% if contract.as_base_allowed and contract.payable %} + ) internal override returns (uint256 value) { // If base is the deposit asset, ensure that enough ether was sent to // the contract and return the amount of ether that should be sent for // the contribution. @@ -90,9 +90,8 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy token.approve(address(_hyperdrive), approvalAmount); // **************************************************************** } - - return value; {% elif contract.as_base_allowed and not contract.payable %} + ) internal override returns (uint256 value) { // If base is the deposit asset, the initialization will be paid in the // base token. address token; @@ -101,7 +100,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy } // Otherwise, the initialization will be paid in vault shares. else { - token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + token = address(I{{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); } // **************************************************************** @@ -112,6 +111,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy ERC20(token).forceApprove(address(_hyperdrive), _contribution); // **************************************************************** {% elif not contract.as_base_allowed and not contract.payable %} + ) internal override returns (uint256 value) { // Depositing as base is disallowed. if (_options.asBase) { revert IHyperdrive.UnsupportedToken(); @@ -121,13 +121,12 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy // FIXME: Implement this for new instances. ERC20 example provided. // Otherwise, transfer vault shares from the LP and approve the // Hyperdrive pool. - address token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + address token = address(I{{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); ERC20(token).transferFrom(_lp, address(this), _contribution); ERC20(token).approve(address(_hyperdrive), _contribution); // **************************************************************** - - return value; {% endif %} + return value; } {% if contract.payable %} @@ -167,11 +166,10 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy } /// @dev Gets the initial vault share price of the Hyperdrive pool. - /// @param _extraData The extra data passed to the child deployers. /// @return The initial vault share price of the Hyperdrive pool. function _getInitialVaultSharePrice( - bytes memory _extraData - ) internal view override returns (uint256) { + bytes memory // unused _extraData + ) internal pure override returns (uint256) { // **************************************************************** // FIXME: Implement this for new instances. return ONE; diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja index 2fdf4d899..88add6a0e 100644 --- a/codegen/templates/deployers/Target0Deployer.sol.jinja +++ b/codegen/templates/deployers/Target0Deployer.sol.jinja @@ -24,12 +24,11 @@ contract {{ name.capitalized }}Target0Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target0 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed {{ name.capitalized }}Target0 instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData, + bytes memory, // unused _extraData bytes32 _salt ) external returns (address) { return diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja index 032b6374b..d5d951fc2 100644 --- a/codegen/templates/deployers/Target1Deployer.sol.jinja +++ b/codegen/templates/deployers/Target1Deployer.sol.jinja @@ -24,12 +24,11 @@ contract {{ name.capitalized }}Target1Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target1 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed {{ name.capitalized }}Target1 instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData, + bytes memory, // unused _extraData bytes32 _salt ) external returns (address) { return diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja index 47eb9ac36..53c6a8a4e 100644 --- a/codegen/templates/deployers/Target2Deployer.sol.jinja +++ b/codegen/templates/deployers/Target2Deployer.sol.jinja @@ -24,12 +24,11 @@ contract {{ name.capitalized }}Target2Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target2 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed {{ name.capitalized }}Target2 instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData, + bytes memory, // unused _extraData bytes32 _salt ) external returns (address) { return diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja index ad263e721..1b59a81b0 100644 --- a/codegen/templates/deployers/Target3Deployer.sol.jinja +++ b/codegen/templates/deployers/Target3Deployer.sol.jinja @@ -24,12 +24,11 @@ contract {{ name.capitalized }}Target3Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target3 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed {{ name.capitalized }}Target3 instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData, + bytes memory, // unused _extraData bytes32 _salt ) external returns (address) { return diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja index ca4e03289..29adf6a65 100644 --- a/codegen/templates/deployers/Target4Deployer.sol.jinja +++ b/codegen/templates/deployers/Target4Deployer.sol.jinja @@ -24,12 +24,11 @@ contract {{ name.capitalized }}Target4Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target4 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the pool and sweep targets. /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed {{ name.capitalized }}Target4 instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData, + bytes memory, // unused _extraData bytes32 _salt ) external returns (address) { return diff --git a/codegen/templates/interfaces/IHyperdrive.sol.jinja b/codegen/templates/interfaces/IHyperdrive.sol.jinja index 979097cea..38b457ffd 100644 --- a/codegen/templates/interfaces/IHyperdrive.sol.jinja +++ b/codegen/templates/interfaces/IHyperdrive.sol.jinja @@ -6,5 +6,9 @@ import { IHyperdrive } from "../IHyperdrive.sol"; // prettier-ignore interface I{{ name.capitalized }}Hyperdrive is IHyperdrive -{} +{ + /// @notice Gets the vault used as this pool's yield source. + /// @return The compatible yield source. + function vault() external view returns (address); +} diff --git a/codegen/templates/interfaces/IYieldSource.sol.jinja b/codegen/templates/interfaces/IYieldSource.sol.jinja index a9583e918..f2debda81 100644 --- a/codegen/templates/interfaces/IYieldSource.sol.jinja +++ b/codegen/templates/interfaces/IYieldSource.sol.jinja @@ -5,7 +5,7 @@ pragma solidity 0.8.20; import { IERC4626 } from "../IERC4626.sol"; // **************************************************************************** -// FIXME: Fill out this interface as needed. +// FIXME: Fill out the interface as needed. ERC4626 extended as an example. /// @author DELV /// @title I{{ name.capitalized }} From 918ba5dfdf83426c3bade3c95a10b099e97c7b1e Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 16:58:44 -0500 Subject: [PATCH 18/25] update README --- codegen/README.md | 17 ++++++++++++----- .../HyperdriveDeployerCoordinator.sol.jinja | 11 +++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/codegen/README.md b/codegen/README.md index 37f600441..5852b6f00 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -32,7 +32,7 @@ hyperdrive/ ### 0. Install Python -You'll need to have python installed on your machine to use this tool. Installation varies by operatin system. +You'll need to have python installed on your machine to use this tool. Installation varies by operating system, check the Python homepage for instructions. ### 1. Install Pyenv @@ -57,12 +57,12 @@ source .venv/bin/activate To install the dependencies: ```bash -pip install -e . +pip install -e codegen ``` ### 5. Check Installation -Verify that your package was installed correctly by running something like pip list. You should see hyperdrive-codegen listed as a package. +Verify that your package was installed correctly by running something like `pip list`. You should see hyperdrive-codegen listed as a package. ## Usage @@ -71,9 +71,16 @@ If installation was successful, from the `example/` directory you should be able ```bash hyperdrive-codegen --config config.yaml ``` - Which will output all the generated code in `example/out`. +To actually start a new integration, you would run the following from the hyperdrive root directory: + +```bash +hyperdrive-codegen --config codegen/example/config.yaml --out contracts/src +``` + +Which will populate all the new files into the appropriate folders within `contracts/src/`. + ### 6. VSCode Debugging Add the following VSCode launch configuration, to be able to debug the tool: @@ -95,4 +102,4 @@ Add the following VSCode launch configuration, to be able to debug the tool: } ``` -Note that VSCode should be launched from the codegen/ directory, not the hyperdrive directory. +Note that VSCode should be launched from the `codegen/` directory, not the hyperdrive directory. diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index ea239c5d9..df2809fb5 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -61,7 +61,8 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy uint256 _contribution, IHyperdrive.Options memory _options {% if contract.as_base_allowed and contract.payable %} - ) internal override returns (uint256 value) { + ) internal override returns (uint256) { + uint256 value; // If base is the deposit asset, ensure that enough ether was sent to // the contract and return the amount of ether that should be sent for // the contribution. @@ -79,15 +80,9 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy // FIXME: Implement this for new instances. ERC20 example provided. // Take custody of the contribution and approve Hyperdrive to pull // the tokens. - token = address({{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + address token = address(I{{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); ERC20(token).safeTransferFrom(_lp, address(this), _contribution); ERC20(token).forceApprove(address(_hyperdrive), _contribution); - uint256 approvalAmount = {{ name.camelCase }}.transferSharesFrom( - _lp, - address(this), - _contribution - ); - token.approve(address(_hyperdrive), approvalAmount); // **************************************************************** } {% elif contract.as_base_allowed and not contract.payable %} From 416a50f7f8c737aa4751276a3cef24dfd0ebc1d1 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 18:01:46 -0500 Subject: [PATCH 19/25] add config cases to Base.sol --- codegen/example/config.yaml | 4 +- codegen/templates/instances/Base.sol.jinja | 47 ++++++++++++++++------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/codegen/example/config.yaml b/codegen/example/config.yaml index 248881688..cd2938221 100644 --- a/codegen/example/config.yaml +++ b/codegen/example/config.yaml @@ -16,8 +16,8 @@ name: contract: # If the contract is payable in Ether. If it is, then logic should be added # to accept Ether, and deposit into the vault to obtain vault shares. - payable: false + payable: true # If the contract can accept base to convert to valut shares on behalf of the # user. - as_base_allowed: false + as_base_allowed: true diff --git a/codegen/templates/instances/Base.sol.jinja b/codegen/templates/instances/Base.sol.jinja index 78c8017ab..4b7246cc7 100644 --- a/codegen/templates/instances/Base.sol.jinja +++ b/codegen/templates/instances/Base.sol.jinja @@ -35,6 +35,7 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { /// Yield Source /// /// @dev Accepts a deposit from the user in base. +{%- if contract.as_base_allowed %} /// @param _baseAmount The base amount to deposit. /// @return The shares that were minted in the deposit. /// @return The amount of ETH to refund. Since this yield source isn't @@ -43,7 +44,6 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { uint256 _baseAmount, bytes calldata // unused ) internal override returns (uint256, uint256) { - // **************************************************************** // FIXME: Implement this for new instances. ERC20 example provided. // Take custody of the deposit in base. @@ -66,6 +66,16 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { return (sharesMinted, 0); // **************************************************************** +{% else %} + /// @return The shares that were minted in the deposit. + /// @return The amount of ETH to refund. Since this yield source isn't + /// payable, this is always zero. + function _depositWithBase( + uint256, // unused _baseAmount + bytes calldata // unused _extraData + ) internal pure override returns (uint256, uint256) { + revert IHyperdrive.UnsupportedToken(); +{%- endif %} } /// @dev Process a deposit in vault shares. @@ -87,6 +97,7 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { /// @dev Process a withdrawal in base and send the proceeds to the /// destination. +{% if contract.as_base_allowed %} /// @param _shareAmount The amount of vault shares to withdraw. /// @param _destination The destination of the withdrawal. /// @return amountWithdrawn The amount of base withdrawn. @@ -107,6 +118,15 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { return amountWithdrawn; // **************************************************************** +{% else %} + /// @return amountWithdrawn The amount of base withdrawn. + function _withdrawWithBase( + uint256, // unused _shareAmount + address, // unused _destination + bytes calldata // unused _extraData + ) internal pure override returns (uint256) { + revert IHyperdrive.UnsupportedToken(); +{%- endif %} } /// @dev Process a withdrawal in vault shares and send the proceeds to the @@ -125,17 +145,6 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { // **************************************************************** } - /// @dev Ensure that ether wasn't sent because {{ name.capitalized }} vaults don't support - /// deposits of ether. - function _checkMessageValue() internal view override { - // **************************************************************** - // FIXME: Implement this for new instances. - if (msg.value != 0) { - revert IHyperdrive.NotPayable(); - } - // **************************************************************** - } - /// @dev Convert an amount of vault shares to an amount of base. /// @param _shareAmount The vault shares amount. /// @return The base amount. @@ -177,4 +186,18 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { { return _vault.balanceOf(address(this)); } + +{% if contract.payable %} + /// @dev We override the message value check since this integration is + /// payable. + function _checkMessageValue() internal pure override {} +{% else %} + /// @dev We override the message value check since this integration is + /// not payable. + function _checkMessageValue() internal view override { + if (msg.value > 0) { + revert IHyperdrive.NotPayable(); + } + } +{%- endif %} } From 3147b9c1293c55fc995e63da5029c13ba65d1d91 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 18:17:27 -0500 Subject: [PATCH 20/25] add quick test to make sure things compile --- .github/workflows/codegen_test.yml | 45 +++++++++++++++++++ codegen/test/test.sh | 9 ++++ .../test_not_payable_and_as_base_allowed.yaml | 23 ++++++++++ ...t_not_payable_and_not_as_base_allowed.yaml | 23 ++++++++++ .../test_payable_and_as_base_allowed.yaml | 23 ++++++++++ 5 files changed, 123 insertions(+) create mode 100644 .github/workflows/codegen_test.yml create mode 100755 codegen/test/test.sh create mode 100644 codegen/test/test_not_payable_and_as_base_allowed.yaml create mode 100644 codegen/test/test_not_payable_and_not_as_base_allowed.yaml create mode 100644 codegen/test/test_payable_and_as_base_allowed.yaml diff --git a/.github/workflows/codegen_test.yml b/.github/workflows/codegen_test.yml new file mode 100644 index 000000000..f6a4077ca --- /dev/null +++ b/.github/workflows/codegen_test.yml @@ -0,0 +1,45 @@ +name: Codegen Test + +on: + push: + pull_request: + merge_group: + +jobs: + detect-changes: + uses: ./.github/workflows/check_diff.yaml + with: + pattern: ^codegen/ + + test-core: + name: solidity test core + runs-on: ubuntu-latest-16core + needs: detect-changes + if: needs.detect-changes.outputs.changed == 'true' + env: + GOERLI_RPC_URL: ${{ secrets.GOERLI_RPC_URL }} + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + token: ${{ secrets.GITHUB_TOKEN }} + + - name: install foundry + uses: foundry-rs/foundry-toolchain@v1.0.10 + with: + version: nightly + + - name: set up python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + cache: "pip" + token: ${{github.token}} + + - name: install requirements + run: | + uv pip install -e codegen + + - name: test + run: ./codegen/test/test.sh diff --git a/codegen/test/test.sh b/codegen/test/test.sh new file mode 100755 index 000000000..2a22e9c41 --- /dev/null +++ b/codegen/test/test.sh @@ -0,0 +1,9 @@ + +hyperdrive-codegen --config codegen/test/test_payable_and_as_base_allowed.yaml --out contracts/src +make build-sol + +hyperdrive-codegen --config codegen/test/test_not_payable_and_as_base_allowed.yaml --out contracts/src +make build-sol + +hyperdrive-codegen --config codegen/test/test_not_payable_and_not_as_base_allowed.yaml --out contracts/src +make build-sol \ No newline at end of file diff --git a/codegen/test/test_not_payable_and_as_base_allowed.yaml b/codegen/test/test_not_payable_and_as_base_allowed.yaml new file mode 100644 index 000000000..248881688 --- /dev/null +++ b/codegen/test/test_not_payable_and_as_base_allowed.yaml @@ -0,0 +1,23 @@ +# Template configuration + +# Vault naming formats. +name: + # Capitalized version of the name to be used i.e. for contract names, file + # names, and comments. + capitalized: "TestETH" + + # All lower case name to be used for directories. + lowercase: "testeth" + + # Camel case name to be used i.e. for variables. + camelcase: "testEth" + +# Configuration parameters for the hyperdrive instance. +contract: + # If the contract is payable in Ether. If it is, then logic should be added + # to accept Ether, and deposit into the vault to obtain vault shares. + payable: false + + # If the contract can accept base to convert to valut shares on behalf of the + # user. + as_base_allowed: false diff --git a/codegen/test/test_not_payable_and_not_as_base_allowed.yaml b/codegen/test/test_not_payable_and_not_as_base_allowed.yaml new file mode 100644 index 000000000..bc4518d78 --- /dev/null +++ b/codegen/test/test_not_payable_and_not_as_base_allowed.yaml @@ -0,0 +1,23 @@ +# Template configuration + +# Vault naming formats. +name: + # Capitalized version of the name to be used i.e. for contract names, file + # names, and comments. + capitalized: "TestETH" + + # All lower case name to be used for directories. + lowercase: "testeth" + + # Camel case name to be used i.e. for variables. + camelcase: "testEth" + +# Configuration parameters for the hyperdrive instance. +contract: + # If the contract is payable in Ether. If it is, then logic should be added + # to accept Ether, and deposit into the vault to obtain vault shares. + payable: false + + # If the contract can accept base to convert to valut shares on behalf of the + # user. + as_base_allowed: true diff --git a/codegen/test/test_payable_and_as_base_allowed.yaml b/codegen/test/test_payable_and_as_base_allowed.yaml new file mode 100644 index 000000000..cd2938221 --- /dev/null +++ b/codegen/test/test_payable_and_as_base_allowed.yaml @@ -0,0 +1,23 @@ +# Template configuration + +# Vault naming formats. +name: + # Capitalized version of the name to be used i.e. for contract names, file + # names, and comments. + capitalized: "TestETH" + + # All lower case name to be used for directories. + lowercase: "testeth" + + # Camel case name to be used i.e. for variables. + camelcase: "testEth" + +# Configuration parameters for the hyperdrive instance. +contract: + # If the contract is payable in Ether. If it is, then logic should be added + # to accept Ether, and deposit into the vault to obtain vault shares. + payable: true + + # If the contract can accept base to convert to valut shares on behalf of the + # user. + as_base_allowed: true From 3dbe6ebf955105df23bdcc918aca2368ce20623a Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 18:22:38 -0500 Subject: [PATCH 21/25] fix pattern --- .github/workflows/codegen_test.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codegen_test.yml b/.github/workflows/codegen_test.yml index f6a4077ca..5ef968772 100644 --- a/.github/workflows/codegen_test.yml +++ b/.github/workflows/codegen_test.yml @@ -9,16 +9,13 @@ jobs: detect-changes: uses: ./.github/workflows/check_diff.yaml with: - pattern: ^codegen/ + pattern: ^codegen.* - test-core: - name: solidity test core - runs-on: ubuntu-latest-16core + test: + name: codegen test + runs-on: ubuntu-latest needs: detect-changes if: needs.detect-changes.outputs.changed == 'true' - env: - GOERLI_RPC_URL: ${{ secrets.GOERLI_RPC_URL }} - MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} steps: - uses: actions/checkout@v3 with: @@ -39,7 +36,7 @@ jobs: - name: install requirements run: | - uv pip install -e codegen + pip install -e codegen - name: test run: ./codegen/test/test.sh From 2e370b0d42ac6c41411f80f88a2e8b9a16cb0184 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 26 Mar 2024 18:28:20 -0500 Subject: [PATCH 22/25] add prints --- codegen/test/test.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codegen/test/test.sh b/codegen/test/test.sh index 2a22e9c41..7ffeae8e0 100755 --- a/codegen/test/test.sh +++ b/codegen/test/test.sh @@ -1,9 +1,12 @@ +echo "Testing payable and as_base_allowed" hyperdrive-codegen --config codegen/test/test_payable_and_as_base_allowed.yaml --out contracts/src make build-sol +echo "Testing not payable and as_base_allowed" hyperdrive-codegen --config codegen/test/test_not_payable_and_as_base_allowed.yaml --out contracts/src make build-sol +echo "Testing not payable and not as_base_allowed" hyperdrive-codegen --config codegen/test/test_not_payable_and_not_as_base_allowed.yaml --out contracts/src make build-sol \ No newline at end of file From 306a7ac5ef355df62516f7364c95878295d0b1a6 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 27 Mar 2024 10:30:46 -0500 Subject: [PATCH 23/25] update templates for generalized _vaultSharesPrice --- .../HyperdriveCoreDeployer.sol.jinja | 14 +------ .../HyperdriveDeployerCoordinator.sol.jinja | 7 ++-- .../deployers/Target0Deployer.sol.jinja | 11 +---- .../deployers/Target1Deployer.sol.jinja | 11 +---- .../deployers/Target2Deployer.sol.jinja | 11 +---- .../deployers/Target3Deployer.sol.jinja | 11 +---- .../deployers/Target4Deployer.sol.jinja | 11 +---- codegen/templates/instances/Base.sol.jinja | 41 ++++++++----------- .../templates/instances/Hyperdrive.sol.jinja | 23 +++-------- codegen/templates/instances/Target0.sol.jinja | 20 +-------- codegen/templates/instances/Target1.sol.jinja | 7 +--- codegen/templates/instances/Target2.sol.jinja | 7 +--- codegen/templates/instances/Target3.sol.jinja | 7 +--- codegen/templates/instances/Target4.sol.jinja | 7 +--- 14 files changed, 43 insertions(+), 145 deletions(-) diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja index 1217d037c..a138aefc4 100644 --- a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -15,7 +15,6 @@ import { {{ name.capitalized }}Hyperdrive } from "../../instances/{{ name.lowerc contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer { /// @notice Deploys a Hyperdrive instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the vault. /// @param _target0 The target0 address. /// @param _target1 The target1 address. /// @param _target2 The target2 address. @@ -25,7 +24,7 @@ contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer /// @return The address of the newly deployed {{ name.capitalized }}Hyperdrive instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData, + bytes memory, // unused _extraData, address _target0, address _target1, address _target2, @@ -33,22 +32,13 @@ contract {{ name.capitalized }}HyperdriveCoreDeployer is IHyperdriveCoreDeployer address _target4, bytes32 _salt ) external returns (address) { - address vault = abi.decode(_extraData, (address)); return ( address( // NOTE: We hash the sender with the salt to prevent the // front-running of deployments. new {{ name.capitalized }}Hyperdrive{ salt: keccak256(abi.encode(msg.sender, _salt)) - }( - _config, - _target0, - _target1, - _target2, - _target3, - _target4, - I{{ name.capitalized }}(vault) - ) + }(_config, _target0, _target1, _target2, _target3, _target4) ) ); } diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index df2809fb5..87e169152 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -80,7 +80,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy // FIXME: Implement this for new instances. ERC20 example provided. // Take custody of the contribution and approve Hyperdrive to pull // the tokens. - address token = address(I{{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + address token = _hyperdrive.vaultSharesToken(); ERC20(token).safeTransferFrom(_lp, address(this), _contribution); ERC20(token).forceApprove(address(_hyperdrive), _contribution); // **************************************************************** @@ -95,7 +95,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy } // Otherwise, the initialization will be paid in vault shares. else { - token = address(I{{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + token = _hyperdrive.vaultSharesToken(); } // **************************************************************** @@ -116,7 +116,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy // FIXME: Implement this for new instances. ERC20 example provided. // Otherwise, transfer vault shares from the LP and approve the // Hyperdrive pool. - address token = address(I{{ name.capitalized }}Hyperdrive(address(_hyperdrive)).vault()); + address token = _hyperdrive.vaultSharesToken(); ERC20(token).transferFrom(_lp, address(this), _contribution); ERC20(token).approve(address(_hyperdrive), _contribution); // **************************************************************** @@ -163,6 +163,7 @@ contract {{ name.capitalized }}HyperdriveDeployerCoordinator is HyperdriveDeploy /// @dev Gets the initial vault share price of the Hyperdrive pool. /// @return The initial vault share price of the Hyperdrive pool. function _getInitialVaultSharePrice( + IHyperdrive.PoolDeployConfig memory, // unused _deployConfig bytes memory // unused _extraData ) internal pure override returns (uint256) { // **************************************************************** diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja index 88add6a0e..710e6955c 100644 --- a/codegen/templates/deployers/Target0Deployer.sol.jinja +++ b/codegen/templates/deployers/Target0Deployer.sol.jinja @@ -13,15 +13,6 @@ import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDep /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Target0Deployer is IHyperdriveTargetDeployer { - /// @notice The {{ name.capitalized }} contract. - I{{ name.capitalized }} public immutable {{ name.camelcase }}; - - /// @notice Instantiates the core deployer. - /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. - constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { - {{ name.camelcase }} = _{{ name.camelcase }}; - } - /// @notice Deploys a target0 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _salt The create2 salt used in the deployment. @@ -37,7 +28,7 @@ contract {{ name.capitalized }}Target0Deployer is IHyperdriveTargetDeployer { // front-running of deployments. new {{ name.capitalized }}Target0{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, {{ name.camelcase }}) + }(_config) ); } } diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja index d5d951fc2..42f0af62c 100644 --- a/codegen/templates/deployers/Target1Deployer.sol.jinja +++ b/codegen/templates/deployers/Target1Deployer.sol.jinja @@ -13,15 +13,6 @@ import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDep /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Target1Deployer is IHyperdriveTargetDeployer { - /// @notice The {{ name.capitalized }} contract. - I{{ name.capitalized }} public immutable {{ name.camelcase }}; - - /// @notice Instantiates the core deployer. - /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. - constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { - {{ name.camelcase }} = _{{ name.camelcase }}; - } - /// @notice Deploys a target1 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _salt The create2 salt used in the deployment. @@ -37,7 +28,7 @@ contract {{ name.capitalized }}Target1Deployer is IHyperdriveTargetDeployer { // front-running of deployments. new {{ name.capitalized }}Target1{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, {{ name.camelcase }}) + }(_config) ); } } diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja index 53c6a8a4e..58ad74e7c 100644 --- a/codegen/templates/deployers/Target2Deployer.sol.jinja +++ b/codegen/templates/deployers/Target2Deployer.sol.jinja @@ -13,15 +13,6 @@ import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDep /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Target2Deployer is IHyperdriveTargetDeployer { - /// @notice The {{ name.capitalized }} contract. - I{{ name.capitalized }} public immutable {{ name.camelcase }}; - - /// @notice Instantiates the core deployer. - /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. - constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { - {{ name.camelcase }} = _{{ name.camelcase }}; - } - /// @notice Deploys a target2 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _salt The create2 salt used in the deployment. @@ -37,7 +28,7 @@ contract {{ name.capitalized }}Target2Deployer is IHyperdriveTargetDeployer { // front-running of deployments. new {{ name.capitalized }}Target2{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, {{ name.camelcase }}) + }(_config) ); } } diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja index 1b59a81b0..18ffd2eb5 100644 --- a/codegen/templates/deployers/Target3Deployer.sol.jinja +++ b/codegen/templates/deployers/Target3Deployer.sol.jinja @@ -13,15 +13,6 @@ import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDep /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Target3Deployer is IHyperdriveTargetDeployer { - /// @notice The {{ name.capitalized }} contract. - I{{ name.capitalized }} public immutable {{ name.camelcase }}; - - /// @notice Instantiates the core deployer. - /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. - constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { - {{ name.camelcase }} = _{{ name.camelcase }}; - } - /// @notice Deploys a target3 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _salt The create2 salt used in the deployment. @@ -37,7 +28,7 @@ contract {{ name.capitalized }}Target3Deployer is IHyperdriveTargetDeployer { // front-running of deployments. new {{ name.capitalized }}Target3{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, {{ name.camelcase }}) + }(_config) ); } } diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja index 29adf6a65..beb1df68f 100644 --- a/codegen/templates/deployers/Target4Deployer.sol.jinja +++ b/codegen/templates/deployers/Target4Deployer.sol.jinja @@ -13,15 +13,6 @@ import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDep /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Target4Deployer is IHyperdriveTargetDeployer { - /// @notice The {{ name.capitalized }} contract. - I{{ name.capitalized }} public immutable {{ name.camelcase }}; - - /// @notice Instantiates the core deployer. - /// @param _{{ name.camelcase }} The {{ name.capitalized }} contract. - constructor(I{{ name.capitalized }} _{{ name.camelcase }}) { - {{ name.camelcase }} = _{{ name.camelcase }}; - } - /// @notice Deploys a target4 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _salt The create2 salt used in the deployment. @@ -37,7 +28,7 @@ contract {{ name.capitalized }}Target4Deployer is IHyperdriveTargetDeployer { // front-running of deployments. new {{ name.capitalized }}Target4{ salt: keccak256(abi.encode(msg.sender, _salt)) - }(_config, {{ name.camelcase }}) + }(_config) ); } } diff --git a/codegen/templates/instances/Base.sol.jinja b/codegen/templates/instances/Base.sol.jinja index 4b7246cc7..0d5dac0f0 100644 --- a/codegen/templates/instances/Base.sol.jinja +++ b/codegen/templates/instances/Base.sol.jinja @@ -3,11 +3,10 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; -import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}Hyperdrive.sol"; import { HyperdriveBase } from "../../internal/HyperdriveBase.sol"; -import { FixedPointMath, ONE } from "../../libraries/FixedPointMath.sol"; /// @author DELV /// @title {{ name.capitalized }}Base @@ -19,19 +18,8 @@ import { FixedPointMath, ONE } from "../../libraries/FixedPointMath.sol"; /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. abstract contract {{ name.capitalized }}Base is HyperdriveBase { - using FixedPointMath for uint256; using SafeERC20 for ERC20; - /// @dev The {{ name.capitalized }} vault that this pool uses as a yield source. - I{{ name.capitalized }} internal immutable _vault; - - /// @notice Instantiates the {{ name.capitalized }} Hyperdrive base contract. - /// @param __vault The {{ name.capitalized }} compatible vault. - constructor(I{{ name.capitalized }} __vault) { - // Initialize the pool immutable. - _vault = __vault; - } - /// Yield Source /// /// @dev Accepts a deposit from the user in base. @@ -45,7 +33,7 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { bytes calldata // unused ) internal override returns (uint256, uint256) { // **************************************************************** - // FIXME: Implement this for new instances. ERC20 example provided. + // FIXME: Implement this for new instances. ERC4626 example provided. // Take custody of the deposit in base. ERC20(address(_baseToken)).safeTransferFrom( msg.sender, @@ -59,10 +47,13 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { // the vault ends with an approval of 1 wei. This makes future // approvals cheaper by keeping the storage slot warm. ERC20(address(_baseToken)).forceApprove( - address(_vault), + address(_vaultSharesToken), _baseAmount + 1 ); - uint256 sharesMinted = _vault.deposit(_baseAmount, address(this)); + uint256 sharesMinted = IERC4626(address(_vaultSharesToken)).deposit( + _baseAmount, + address(this) + ); return (sharesMinted, 0); // **************************************************************** @@ -82,12 +73,12 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { /// @param _shareAmount The vault shares amount to deposit. function _depositWithShares( uint256 _shareAmount, - bytes calldata // unused + bytes calldata // unused _extraData ) internal override { // **************************************************************** // FIXME: Implement this for new instances. ERC20 example provided. // Take custody of the deposit in vault shares. - ERC20(address(_vault)).safeTransferFrom( + ERC20(address(_vaultSharesToken)).safeTransferFrom( msg.sender, address(this), _shareAmount @@ -107,10 +98,10 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { bytes calldata // unused ) internal override returns (uint256 amountWithdrawn) { // **************************************************************** - // FIXME: Implement this for new instances. ERC20 example provided. + // FIXME: Implement this for new instances. ERC4626 example provided. // Redeem from the yield source and transfer the // resulting base to the destination address. - amountWithdrawn = _vault.redeem( + amountWithdrawn = IERC4626(address(_vaultSharesToken)).redeem( _shareAmount, _destination, address(this) @@ -141,7 +132,7 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { // **************************************************************** // FIXME: Implement this for new instances. ERC20 example provided. // Transfer vault shares to the destination. - ERC20(address(_vault)).safeTransfer(_destination, _shareAmount); + ERC20(address(_vaultSharesToken)).safeTransfer(_destination, _shareAmount); // **************************************************************** } @@ -153,7 +144,8 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { ) internal view override returns (uint256) { // **************************************************************** // FIXME: Implement this for new instances. - return _vault.convertToAssets(_shareAmount); + return + IERC4626(address(_vaultSharesToken)).convertToAssets(_shareAmount); // **************************************************************** } @@ -165,7 +157,8 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { ) internal view override returns (uint256) { // **************************************************************** // FIXME: Implement this for new instances. - return _vault.convertToShares(_baseAmount); + return + IERC4626(address(_vaultSharesToken)).convertToShares(_baseAmount); // **************************************************************** } @@ -184,7 +177,7 @@ abstract contract {{ name.capitalized }}Base is HyperdriveBase { override returns (uint256 shareAmount) { - return _vault.balanceOf(address(this)); + return _vaultSharesToken.balanceOf(address(this)); } {% if contract.payable %} diff --git a/codegen/templates/instances/Hyperdrive.sol.jinja b/codegen/templates/instances/Hyperdrive.sol.jinja index 5255baa4e..ee1b2f64e 100644 --- a/codegen/templates/instances/Hyperdrive.sol.jinja +++ b/codegen/templates/instances/Hyperdrive.sol.jinja @@ -5,9 +5,7 @@ import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { Hyperdrive } from "../../external/Hyperdrive.sol"; import { IERC20 } from "../../interfaces/IERC20.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; -import { FixedPointMath } from "../../libraries/FixedPointMath.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; /// ______ __ _________ _____ @@ -57,7 +55,6 @@ import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Hyperdrive is Hyperdrive, {{ name.capitalized }}Base { - using FixedPointMath for uint256; using SafeERC20 for ERC20; /// @notice Instantiates Hyperdrive with a {{ name.capitalized }} vault as the yield source. @@ -67,31 +64,21 @@ contract {{ name.capitalized }}Hyperdrive is Hyperdrive, {{ name.capitalized }}B /// @param _target2 The target2 address. /// @param _target3 The target3 address. /// @param _target4 The target4 address. - /// @param __vault The {{ name.capitalized }} compatible yield source. constructor( IHyperdrive.PoolConfig memory _config, address _target0, address _target1, address _target2, address _target3, - address _target4, - I{{ name.capitalized }} __vault + address _target4 ) Hyperdrive(_config, _target0, _target1, _target2, _target3, _target4) - {{ name.capitalized }}Base(__vault) { - - // **************************************************************** - // FIXME: Implement this for new instances. ERC4626 example provided. - // Ensure that the base token is the same as the vault's underlying - // asset. - if (address(_config.baseToken) != I{{ name.capitalized }}(_vault).asset()) { - revert IHyperdrive.InvalidBaseToken(); - } - // Approve the base token with 1 wei. This ensures that all of the // subsequent approvals will be writing to a dirty storage slot. - ERC20(address(_config.baseToken)).forceApprove(address(_vault), 1); - // **************************************************************** + ERC20(address(_config.baseToken)).forceApprove( + address(_config.vaultSharesToken), + 1 + ); } } diff --git a/codegen/templates/instances/Target0.sol.jinja b/codegen/templates/instances/Target0.sol.jinja index 9f7af927e..cc161964a 100644 --- a/codegen/templates/instances/Target0.sol.jinja +++ b/codegen/templates/instances/Target0.sol.jinja @@ -1,11 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; -import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { HyperdriveTarget0 } from "../../external/HyperdriveTarget0.sol"; -import { IERC20 } from "../../interfaces/IERC20.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; @@ -18,22 +14,10 @@ import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract {{ name.capitalized }}Target0 is HyperdriveTarget0, {{ name.capitalized }}Base { - using SafeERC20 for ERC20; - /// @notice Initializes the target0 contract. /// @param _config The configuration of the Hyperdrive pool. - /// @param __vault The {{ name.capitalized }} compatible vault. constructor( - IHyperdrive.PoolConfig memory _config, - I{{ name.capitalized }} __vault - ) HyperdriveTarget0(_config) {{ name.capitalized }}Base(__vault) {} - - /// Getters /// + IHyperdrive.PoolConfig memory _config + ) HyperdriveTarget0(_config) {} - /// @notice Gets the {{ name.capitalized }} compatible vault used as this pool's yield - /// source. - /// @return The {{ name.capitalized }} compatible yield source. - function vault() external view returns (I{{ name.capitalized }}) { - _revert(abi.encode(_vault)); - } } diff --git a/codegen/templates/instances/Target1.sol.jinja b/codegen/templates/instances/Target1.sol.jinja index 95f615c6d..711208bf7 100644 --- a/codegen/templates/instances/Target1.sol.jinja +++ b/codegen/templates/instances/Target1.sol.jinja @@ -2,7 +2,6 @@ pragma solidity 0.8.20; import { HyperdriveTarget1 } from "../../external/HyperdriveTarget1.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; @@ -17,9 +16,7 @@ import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; contract {{ name.capitalized }}Target1 is HyperdriveTarget1, {{ name.capitalized }}Base { /// @notice Initializes the target1 contract. /// @param _config The configuration of the Hyperdrive pool. - /// @param __vault The {{ name.capitalized }} compatible vault. constructor( - IHyperdrive.PoolConfig memory _config, - I{{ name.capitalized }} __vault - ) HyperdriveTarget1(_config) {{ name.capitalized }}Base(__vault) {} + IHyperdrive.PoolConfig memory _config + ) HyperdriveTarget1(_config) {} } diff --git a/codegen/templates/instances/Target2.sol.jinja b/codegen/templates/instances/Target2.sol.jinja index 11b165a51..cf8b4326d 100644 --- a/codegen/templates/instances/Target2.sol.jinja +++ b/codegen/templates/instances/Target2.sol.jinja @@ -2,7 +2,6 @@ pragma solidity 0.8.20; import { HyperdriveTarget2 } from "../../external/HyperdriveTarget2.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; @@ -17,9 +16,7 @@ import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; contract {{ name.capitalized }}Target2 is HyperdriveTarget2, {{ name.capitalized }}Base { /// @notice Initializes the target2 contract. /// @param _config The configuration of the Hyperdrive pool. - /// @param __vault The {{ name.capitalized }} compatible vault. constructor( - IHyperdrive.PoolConfig memory _config, - I{{ name.capitalized }} __vault - ) HyperdriveTarget2(_config) {{ name.capitalized }}Base(__vault) {} + IHyperdrive.PoolConfig memory _config + ) HyperdriveTarget2(_config) {} } diff --git a/codegen/templates/instances/Target3.sol.jinja b/codegen/templates/instances/Target3.sol.jinja index 093169e8d..3942f387a 100644 --- a/codegen/templates/instances/Target3.sol.jinja +++ b/codegen/templates/instances/Target3.sol.jinja @@ -2,7 +2,6 @@ pragma solidity 0.8.20; import { HyperdriveTarget3 } from "../../external/HyperdriveTarget3.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; @@ -17,9 +16,7 @@ import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; contract {{ name.capitalized }}Target3 is HyperdriveTarget3, {{ name.capitalized }}Base { /// @notice Initializes the target3 contract. /// @param _config The configuration of the Hyperdrive pool. - /// @param __vault The {{ name.capitalized }} compatible vault. constructor( - IHyperdrive.PoolConfig memory _config, - I{{ name.capitalized }} __vault - ) HyperdriveTarget3(_config) {{ name.capitalized }}Base(__vault) {} + IHyperdrive.PoolConfig memory _config + ) HyperdriveTarget3(_config) {} } diff --git a/codegen/templates/instances/Target4.sol.jinja b/codegen/templates/instances/Target4.sol.jinja index 30ef2d1ba..ba8736fbf 100644 --- a/codegen/templates/instances/Target4.sol.jinja +++ b/codegen/templates/instances/Target4.sol.jinja @@ -2,7 +2,6 @@ pragma solidity 0.8.20; import { HyperdriveTarget4 } from "../../external/HyperdriveTarget4.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; @@ -17,9 +16,7 @@ import { {{ name.capitalized }}Base } from "./{{ name.capitalized }}Base.sol"; contract {{ name.capitalized }}Target4 is HyperdriveTarget4, {{ name.capitalized }}Base { /// @notice Initializes the target4 contract. /// @param _config The configuration of the Hyperdrive pool. - /// @param __vault The {{ name.capitalized }} compatible vault. constructor( - IHyperdrive.PoolConfig memory _config, - I{{ name.capitalized }} __vault - ) HyperdriveTarget4(_config) {{ name.capitalized }}Base(__vault) {} + IHyperdrive.PoolConfig memory _config + ) HyperdriveTarget4(_config) {} } From 682124e110516cac604f8c37f0fee9e35c359af2 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 27 Mar 2024 13:16:19 -0500 Subject: [PATCH 24/25] flatten interface files and imports --- codegen/hyperdrive_codegen/file.py | 2 +- codegen/hyperdrive_codegen/templates.py | 28 +++++++++++-------- .../HyperdriveCoreDeployer.sol.jinja | 2 +- .../HyperdriveDeployerCoordinator.sol.jinja | 4 +-- .../deployers/Target0Deployer.sol.jinja | 2 +- .../deployers/Target1Deployer.sol.jinja | 2 +- .../deployers/Target2Deployer.sol.jinja | 2 +- .../deployers/Target3Deployer.sol.jinja | 2 +- .../deployers/Target4Deployer.sol.jinja | 2 +- codegen/templates/instances/Base.sol.jinja | 2 +- .../interfaces/IHyperdrive.sol.jinja | 2 +- .../interfaces/IYieldSource.sol.jinja | 5 ++-- 12 files changed, 29 insertions(+), 26 deletions(-) diff --git a/codegen/hyperdrive_codegen/file.py b/codegen/hyperdrive_codegen/file.py index eb4c92519..5c161a7df 100644 --- a/codegen/hyperdrive_codegen/file.py +++ b/codegen/hyperdrive_codegen/file.py @@ -31,7 +31,7 @@ def get_output_folder_structure(lowercase_name: str) -> dict: ------- dict """ - return {"deployers": {lowercase_name: {}}, "instances": {lowercase_name: {}}, "interfaces": {lowercase_name: {}}} + return {"deployers": {lowercase_name: {}}, "instances": {lowercase_name: {}}, "interfaces": {}} def setup_directory(base_path: Path | str, structure: dict, clear_existing: bool = False) -> None: diff --git a/codegen/hyperdrive_codegen/templates.py b/codegen/hyperdrive_codegen/templates.py index 581acc4d1..7df62b65b 100644 --- a/codegen/hyperdrive_codegen/templates.py +++ b/codegen/hyperdrive_codegen/templates.py @@ -4,10 +4,9 @@ from dataclasses import dataclass from pathlib import Path -from jinja2 import Environment, Template - from hyperdrive_codegen.config import TemplateConfig from hyperdrive_codegen.file import write_string_to_file +from jinja2 import Environment, Template @dataclass @@ -97,18 +96,23 @@ def write_templates_to_files(templates: list[TemplateInfo], output_path: Path, t # Get the file information and rendered code. file_info = FileInfo(template, rendered_code=template.template.render(template_config.model_dump())) - # Get the contract file name and prepend 'I' if it is an interface file. + # Get the contract file name contract_file_name = f"{template_config.name.capitalized}{file_info.template.path_info.base_name}.sol" - contract_file_name = ( - "I" + contract_file_name if file_info.template.path_info.folder == "interfaces" else contract_file_name - ) - - # Get the path for the file name. - contract_file_path = Path( - os.path.join( - output_path, file_info.template.path_info.folder, template_config.name.lowercase, contract_file_name + + # Prepend 'I' to the file name if it is an interface file + is_interface_file = file_info.template.path_info.folder == "interfaces" + if is_interface_file: + contract_file_name = "I" + contract_file_name + # NOTE: don't place interface files in a subfolder + contract_file_path = Path( + os.path.join(output_path, file_info.template.path_info.folder, contract_file_name) + ) + else: + contract_file_path = Path( + os.path.join( + output_path, file_info.template.path_info.folder, template_config.name.lowercase, contract_file_name + ) ) - ) # Write the rendered code to file. write_string_to_file(contract_file_path, file_info.rendered_code) diff --git a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja index a138aefc4..d06db0e55 100644 --- a/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja +++ b/codegen/templates/deployers/HyperdriveCoreDeployer.sol.jinja @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol"; import { {{ name.capitalized }}Hyperdrive } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Hyperdrive.sol"; diff --git a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja index 87e169152..9d1aa48e1 100644 --- a/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja +++ b/codegen/templates/deployers/HyperdriveDeployerCoordinator.sol.jinja @@ -3,9 +3,9 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; -import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}Hyperdrive.sol"; +import { I{{ name.capitalized }}Hyperdrive } from "../../interfaces/I{{ name.capitalized }}Hyperdrive.sol"; import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol"; import { ONE } from "../../libraries/FixedPointMath.sol"; import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol"; diff --git a/codegen/templates/deployers/Target0Deployer.sol.jinja b/codegen/templates/deployers/Target0Deployer.sol.jinja index 710e6955c..1b1ad8b99 100644 --- a/codegen/templates/deployers/Target0Deployer.sol.jinja +++ b/codegen/templates/deployers/Target0Deployer.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { {{ name.capitalized }}Target0 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target0.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target1Deployer.sol.jinja b/codegen/templates/deployers/Target1Deployer.sol.jinja index 42f0af62c..559cca208 100644 --- a/codegen/templates/deployers/Target1Deployer.sol.jinja +++ b/codegen/templates/deployers/Target1Deployer.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { {{ name.capitalized }}Target1 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target1.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target2Deployer.sol.jinja b/codegen/templates/deployers/Target2Deployer.sol.jinja index 58ad74e7c..3e7b496e0 100644 --- a/codegen/templates/deployers/Target2Deployer.sol.jinja +++ b/codegen/templates/deployers/Target2Deployer.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { {{ name.capitalized }}Target2 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target2.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target3Deployer.sol.jinja b/codegen/templates/deployers/Target3Deployer.sol.jinja index 18ffd2eb5..d242c868f 100644 --- a/codegen/templates/deployers/Target3Deployer.sol.jinja +++ b/codegen/templates/deployers/Target3Deployer.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { {{ name.capitalized }}Target3 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target3.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/deployers/Target4Deployer.sol.jinja b/codegen/templates/deployers/Target4Deployer.sol.jinja index beb1df68f..ef67191dd 100644 --- a/codegen/templates/deployers/Target4Deployer.sol.jinja +++ b/codegen/templates/deployers/Target4Deployer.sol.jinja @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import { {{ name.capitalized }}Target4 } from "../../instances/{{ name.lowercase }}/{{ name.capitalized }}Target4.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; diff --git a/codegen/templates/instances/Base.sol.jinja b/codegen/templates/instances/Base.sol.jinja index 0d5dac0f0..d1ce1e107 100644 --- a/codegen/templates/instances/Base.sol.jinja +++ b/codegen/templates/instances/Base.sol.jinja @@ -4,7 +4,7 @@ pragma solidity 0.8.20; import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; -import { I{{ name.capitalized }} } from "../../interfaces/{{ name.lowercase }}/I{{ name.capitalized }}.sol"; +import { I{{ name.capitalized }} } from "../../interfaces/I{{ name.capitalized }}.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { HyperdriveBase } from "../../internal/HyperdriveBase.sol"; diff --git a/codegen/templates/interfaces/IHyperdrive.sol.jinja b/codegen/templates/interfaces/IHyperdrive.sol.jinja index 38b457ffd..fde53153a 100644 --- a/codegen/templates/interfaces/IHyperdrive.sol.jinja +++ b/codegen/templates/interfaces/IHyperdrive.sol.jinja @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { IHyperdrive } from "../IHyperdrive.sol"; +import { IHyperdrive } from "./IHyperdrive.sol"; // prettier-ignore interface I{{ name.capitalized }}Hyperdrive is diff --git a/codegen/templates/interfaces/IYieldSource.sol.jinja b/codegen/templates/interfaces/IYieldSource.sol.jinja index f2debda81..ed83dad2b 100644 --- a/codegen/templates/interfaces/IYieldSource.sol.jinja +++ b/codegen/templates/interfaces/IYieldSource.sol.jinja @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// @author is Fei Protocol - https://github.com/fei-protocol/ERC4626/blob/main/src/interfaces/IERC4626.sol +// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; -import { IERC4626 } from "../IERC4626.sol"; +import { IERC4626 } from "./IERC4626.sol"; // **************************************************************************** // FIXME: Fill out the interface as needed. ERC4626 extended as an example. From 70dde7c5b6a435812f116917fdcd33ec597c301c Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Mon, 1 Apr 2024 12:58:05 -0500 Subject: [PATCH 25/25] add CODEOWNERS --- codegen/CODEOWNERS | 3 +++ codegen/templates/interfaces/IHyperdrive.sol.jinja | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 codegen/CODEOWNERS diff --git a/codegen/CODEOWNERS b/codegen/CODEOWNERS new file mode 100644 index 000000000..b742718f4 --- /dev/null +++ b/codegen/CODEOWNERS @@ -0,0 +1,3 @@ +# Codegen codeowners + +- @sentilesdal @cashd diff --git a/codegen/templates/interfaces/IHyperdrive.sol.jinja b/codegen/templates/interfaces/IHyperdrive.sol.jinja index fde53153a..389c462f8 100644 --- a/codegen/templates/interfaces/IHyperdrive.sol.jinja +++ b/codegen/templates/interfaces/IHyperdrive.sol.jinja @@ -3,7 +3,6 @@ pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; -// prettier-ignore interface I{{ name.capitalized }}Hyperdrive is IHyperdrive {