Skip to content

Commit

Permalink
Merge pull request #1 from yieldnest/feature/upgrade
Browse files Browse the repository at this point in the history
Basic Implementation of Single Asset Vault
  • Loading branch information
xhad authored Aug 28, 2024
2 parents b09972f + 5cf324b commit a0bccc0
Show file tree
Hide file tree
Showing 21 changed files with 1,272 additions and 187 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

- name: Run Forge build
run: |
forge build --sizes
forge build --sizes --skip DeployFactory.sol
id: build

- name: Run Forge tests
Expand Down
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@


account :; cast wallet import $(ACCOUNT_NAME) --interactive

local-factory :; forge script script/Deploy.s.sol:DeployVaultFactory \
--private-key $(PRIVATE_KEY) \
--rpc-url $(RPC_URL) \
--broadcast

deploy-factory :; forge script script/Deploy.s.sol:DeployVaultFactory \
--account $(ACCOUNT_NAME) \
--rpc-url $(RPC_URL) \
--etherscan-api-key $(ETHERSCAN_KEY) \
--verify \
--broadcast




67 changes: 13 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,25 @@
## Foundry
## YieldNest Vault

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**
This is a general purpose starter vault for rapid deployment against new opportunies.

Foundry consists of:
## Overview

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
The initial version is a SingleAsset 4626 Vault with TimelockController to send Admin transactions.
This vault is the Base version used for pre-depositing assets ahead of settled DeFi functionality.

## Documentation
## Test Deployment

https://book.getfoundry.sh/

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```
anvil // --fork-url https://holesky-rpc
### Gas Snapshots
export ACCOUNT_NAME=deployer
make account
```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy
export RPC_URL=
export ETHERSCAN_KEY=
```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
make factory
```

### Cast
This will deploy the factory, from which you can create a new vault.

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
336 changes: 336 additions & 0 deletions broadcast/DeployVaultFactory.sol/17000/run-1724670724.json

Large diffs are not rendered by default.

336 changes: 336 additions & 0 deletions broadcast/DeployVaultFactory.sol/17000/run-latest.json

Large diffs are not rendered by default.

50 changes: 49 additions & 1 deletion script/Actors.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,56 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;
pragma solidity ^0.8.24;

interface IActors {
function ADMIN() external view returns (address);
function OPERATOR() external view returns (address);
function UNAUTHORIZED() external view returns (address);
function PROPOSER_1() external view returns (address);
function PROPOSER_2() external view returns (address);
function EXECUTOR_1() external view returns (address);
function EXECUTOR_2() external view returns (address);
function KERNEL_VAULT() external view returns (address);
}

contract LocalActors {
contract LocalActors is IActors {
address public constant ADMIN = address(1);
address public constant OPERATOR = address(2);
address public constant UNAUTHORIZED = address(3);

address public constant PROPOSER_1 = address(1);
address public constant PROPOSER_2 = address(2);

address public constant EXECUTOR_1 = address(3);
address public constant EXECUTOR_2 = address(4);

address public constant KERNEL_VAULT = address(420);
}

contract AnvilActors is IActors {
address public constant ADMIN = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address public constant OPERATOR = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;
address public constant UNAUTHORIZED = address(0);

address public constant PROPOSER_1 = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address public constant PROPOSER_2 = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;

address public constant EXECUTOR_1 = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address public constant EXECUTOR_2 = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;

address public constant KERNEL_VAULT = address(420);
}

contract HoleskyActors is IActors {
address public constant ADMIN = 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913;
address public constant OPERATOR = 0x9Dd8F69b62ddFd990241530F47dcEd0Dad7f7d39;
address public constant UNAUTHORIZED = address(0);

address public constant PROPOSER_1 = 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913;
address public constant PROPOSER_2 = 0x9Dd8F69b62ddFd990241530F47dcEd0Dad7f7d39;

address public constant EXECUTOR_1 = 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913;
address public constant EXECUTOR_2 = 0x9Dd8F69b62ddFd990241530F47dcEd0Dad7f7d39;

address public constant KERNEL_VAULT = address(420);
}
46 changes: 46 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import "lib/forge-std/src/Script.sol";

import {VaultFactory} from "src/VaultFactory.sol";
import {AnvilActors, HoleskyActors, IActors} from "script/Actors.sol";
import {SingleVault} from "src/SingleVault.sol";

contract DeployVaultFactory is Script {
function run() public {
if (block.chainid == 31337) {
vm.startBroadcast();
AnvilActors actors = new AnvilActors();
uint256 minDelay = 10; // seconds
deployVaultFactory(actors, minDelay);
}

if (block.chainid == 17000) {
vm.startBroadcast();
HoleskyActors actors = new HoleskyActors();
uint256 minDelay = 10; // seconds
deployVaultFactory(actors, minDelay);
}

if (block.chainid == 1) {
// TODO
}
}

function deployVaultFactory(IActors actors, uint256 minDelay) internal {
address singleVaultImpl = address(new SingleVault());

address[] memory proposers = new address[](2);
proposers[0] = actors.PROPOSER_1();
proposers[1] = actors.PROPOSER_2();

address[] memory executors = new address[](2);
executors[0] = actors.EXECUTOR_1();
executors[1] = actors.EXECUTOR_2();

address admin = actors.ADMIN();

new VaultFactory(singleVaultImpl, proposers, executors, minDelay, admin);
}
}
5 changes: 0 additions & 5 deletions solhint.json

This file was deleted.

22 changes: 22 additions & 0 deletions src/Common.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {IERC20} from "lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import {ProxyAdmin} from "lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from
"lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {TimelockControllerUpgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/governance/TimelockControllerUpgradeable.sol";
import {TimelockController} from "lib/openzeppelin-contracts/contracts/governance/TimelockController.sol";
import {AccessControlUpgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol";
import {ERC4626Upgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC4626Upgradeable.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import {IERC4626} from "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {IAccessControl} from "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol";
import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";

contract Common {}
45 changes: 0 additions & 45 deletions src/Factory.sol

This file was deleted.

23 changes: 23 additions & 0 deletions src/ISingleVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {IERC20, IERC4626, IAccessControl} from "src/Common.sol";

interface ISingleVault is IERC20, IERC4626, IAccessControl {
error AssetZeroAddress();
error NameEmpty();
error SymbolEmpty();
error AdminZeroAddress();
error ProposersEmpty();
error ExecutorsEmpty();

function initialize(
IERC20 asset_,
string memory name_,
string memory symbol_,
address admin_,
uint256 minDelay_,
address[] calldata proposers_,
address[] calldata executors_
) external;
}
64 changes: 50 additions & 14 deletions src/SingleVault.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,62 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {ERC4626Upgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC4626Upgradeable.sol";
import {AccessControlUpgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import {
ERC4626Upgradeable,
AccessControlUpgradeable,
ReentrancyGuardUpgradeable,
TimelockControllerUpgradeable,
IERC20
} from "src/Common.sol";

contract SingleVault is ERC4626Upgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable {
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
import {ISingleVault} from "src/ISingleVault.sol";

function initialize(IERC20 asset_, string memory name_, string memory symbol_, address admin_, address operator_)
public
initializer
{
contract SingleVault is ISingleVault, ERC4626Upgradeable, TimelockControllerUpgradeable, ReentrancyGuardUpgradeable {
constructor() {
_disableInitializers();
}

/**
* @dev Initializes the SingleVault contract.
* @param asset_ The address of the ERC20 asset.
* @param name_ The name of the vault.
* @param symbol_ The symbol of the vault.
* @param admin_ The address of the admin.
* @param minDelay_ The minimum delay for timelock.
* @param proposers_ The addresses of the proposers.
* @param executors_ The addresses of the executors.
*/
function initialize(
IERC20 asset_,
string memory name_,
string memory symbol_,
address admin_,
uint256 minDelay_,
address[] calldata proposers_,
address[] calldata executors_
) public initializer {
_verifyParamsAreValid(asset_, name_, symbol_, admin_, proposers_, executors_);
__TimelockController_init(minDelay_, proposers_, executors_, admin_);
__ERC20_init(name_, symbol_);
__ERC4626_init(asset_);
__AccessControl_init();
__ReentrancyGuard_init();
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
_grantRole(OPERATOR_ROLE, operator_);
}

function _verifyParamsAreValid(
IERC20 asset_,
string memory name_,
string memory symbol_,
address admin_,
address[] memory proposers_,
address[] memory executors_
) internal pure {
if (asset_ == IERC20(address(0))) revert AssetZeroAddress();
if (bytes(name_).length == 0) revert NameEmpty();
if (bytes(symbol_).length == 0) revert SymbolEmpty();
if (admin_ == address(0)) revert AdminZeroAddress();
if (proposers_.length == 0) revert ProposersEmpty();
if (executors_.length == 0) revert ExecutorsEmpty();
}
}
Loading

0 comments on commit a0bccc0

Please sign in to comment.