Skip to content

Commit

Permalink
feat: version 3.0.2 (#188)
Browse files Browse the repository at this point in the history
* feat: update api and ape version

* chore: removals (#189)

* chore: remove increase and decrease allowances

* chore: remove open roles

* feat: add max loss to debt updates (#190)

* feat: use cloning for vaults (#191)

* feat: use cloning for vaults

* fix: scripts

* chore: fix interfaces

* chore: lower case factory

* fix: update to strategy changes

* feat: add to queue flag (#195)

* fix: updated strategy branch

* feat: minor fixes (#194)

* fix: redeem corrections

* chore: dont burn zero shares

* fix: use updated strategy storage

* fix: rebase

* chore: bump oz version

* fix: oz 4626 fix

* fix: lossy test

* fix: round down in max redeem

* fix: comment

* chore: ignore snapshot

* test: add foundry tests (#196)

* chore: setup foundry test

* chore: add remappings

* forge install: erc4626-tests

* test: add foundry fuzzing tests

* fix: max uint deposit limit

* fix: test strategy

* fix: foundry runner

* fix: clamp overflow

* fix: default tests

* chore: clean up linting

* fix: new strategy version

* fix: reporting costs (#192)

* test: for no locking

* chore: cheaper reports

* chore: track current debt

* chore: lower unlocked gas

* fix: set to 0

* build: only burn or mint (#193)

* build: only burn or mint

* build: target end supply

* chore: comments

* fix: comments

* fix: strategy changes

* chore: rebase

* fix: decimal type

* chore: deployment and interfaces

* fix: black

* chore: updated strategy branch

* fix: foundry remapping
  • Loading branch information
Schlagonia authored Feb 5, 2024
1 parent 9a25833 commit f869f7e
Show file tree
Hide file tree
Showing 38 changed files with 999 additions and 1,431 deletions.
65 changes: 65 additions & 0 deletions .github/workflows/foundry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Foundry tests

on:
push:
branches:
- master
pull_request:

concurrency:
group: ${{github.workflow}}-${{github.ref}}
cancel-in-progress: true

jobs:
unit:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
architecture:
- "x64"
python-version:
- "3.10"
node_version:
- 16

steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: recursive

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture }}

- name: Install Ape
uses: ApeWorX/[email protected]
with:
python-version: '3.10'

- name: install vyper
run: pip install git+https://github.com/vyperlang/vyper

- name: Compile contracts
# Compile Ape contracts to get dependencies
run: ape compile --force --size

- name: Install Vyper
run: pip install vyper==0.3.7

- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node_version }}

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Foundry tests
run: forge test -vvv
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ jobs:
run: pip install -r requirements.txt

- name: Run black
run: black --check --include "(tests|scripts)" .
run: black --check .
2 changes: 0 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ jobs:
- uses: ApeWorX/[email protected]
with:
python-version: '3.10'
ape-version-pin: "==0.6.3"
ape-plugins-list: 'solidity==0.6.0 vyper==0.6.1 hardhat==0.6.0'

- name: install vyper
run: pip install git+https://github.com/vyperlang/vyper
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pyenv.cfg
vyper_git_commithash.txt
bin/
lib/
cache/
out/
share/
build/
include/
Expand All @@ -17,3 +18,6 @@ venv/
.vscode
yarn.lock
env
cache/
out/
.gas-snapshot
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/erc4626-tests"]
path = lib/erc4626-tests
url = https://github.com/a16z/erc4626-tests
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
"not-rely-on-time": "off",
"private-vars-leading-underscore": "warn",
"reason-string": ["warn", { "maxLength": 64 }],
"yearn/underscore-function-args": "error"
"yearn/underscore-function-args": "off"
}
}
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ This repository runs on [ApeWorx](https://www.apeworx.io/). A python based devel

You will need:
- Python 3.8 or later
- Vyper 0.3.7
- [Vyper 0.3.7](https://docs.vyperlang.org/en/stable/installing-vyper.html)
- [Foundry](https://book.getfoundry.sh/getting-started/installation)
- Linux or macOS
- Windows: Install Windows Subsystem Linux (WSL) with Python 3.8 or later
- [Hardhat](https://hardhat.org/) installed globally
Expand All @@ -24,7 +25,7 @@ You will need:
Fork the repository and clone onto your local device

```
git clone https://github.com/user/yearn-vaults-v3
git clone --recursive https://github.com/user/yearn-vaults-v3
cd yearn-vaults-v3
```

Expand Down Expand Up @@ -60,6 +61,24 @@ and test smart contracts with:
ape test
```

To run the Foundry tests

NOTE: You will need to first compile with Ape before running foundry tests.
```
forge test
```

## Deployment

Deployments of the Vault Factory are done using create2 to be at a deterministic address on any EVM chain.

Check the [docs](https://docs.yearn.fi/developers/v3/overview) for the most updated deployment address.

Deployments on new chains can be done permissionlessly by anyone using the included script.
```
ape run scripts/deploy.py --network YOUR_RPC_URL
```

### To make a contribution please follow the [guidelines](https://github.com/yearn/yearn-vaults-v3/bloc/master/CONTRIBUTING.md)

See the ApeWorx [documentation](https://docs.apeworx.io/ape/stable/) and [github](https://github.com/ApeWorX/ape) for more information.
Expand Down
6 changes: 3 additions & 3 deletions TECH_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ This responsibility is taken by callers with DEBT_MANAGER role

This role can increase or decrease strategies specific debt.

The vault sends and receives funds to/from strategies. The function updateDebt(strategy, target_debt) will set the current_debt of the strategy to target_debt (if possible)
The vault sends and receives funds to/from strategies. The function update_debt(strategy, target_debt, max_loss) (max_loss defaults to 100%) will set the current_debt of the strategy to target_debt (if possible)

If the strategy currently has less debt than the target_debt, the vault will send funds to it.

Expand Down Expand Up @@ -224,15 +224,15 @@ Strategies are completely independent smart contracts that can be implemented fo

In any case, to be compatible with the vault, they need to implement the following functions, which are a subset of ERC4626 vaults:
- asset(): view returning underlying asset
- totalAssets(): view returning current amount of assets. It can include rewards valued in `asset` ¡
- maxDeposit(address): view returning the amount max that the strategy can take safely
- deposit(assets, receiver): deposits `assets` amount of tokens into the strategy. it can be restricted to vault only or be open
- maxRedeem(owner): return the max amount of shares that `owner` can redeem.
- redeem(shares, receiver, owner): redeems `shares` of the strategy for the underlying asset.
- balanceOf(address): return the number of shares of the strategy that the address has
- convertToAssets(shares): Converts `shares` into the corresponding amount of asset.
- convertToShares(assets): Converts `assets` into the corresponding amount of shares.
- previewWithdraw(assets): Converts `assets` into the corresponding amount of shares rounding up.
- maxRedeem(owner): return the max amount of shares that `owner` can redeem.


This means that the vault can deposit into any ERC4626 vault but also that a non-compliant strategy can be implemented provided that these functions have been implemented (even in a non ERC4626 compliant way).

Expand Down
9 changes: 3 additions & 6 deletions ape-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,22 @@ name: yearn-v3

plugins:
- name: solidity
version: 0.6.0
- name: vyper
version: 0.6.1
- name: hardhat
version: 0.6.0

default_ecosystem: ethereum
dependencies:
- name: openzeppelin
github: OpenZeppelin/openzeppelin-contracts
version: 4.7.3
ref: 4.9.5
- name: tokenized-strategy
github: yearn/tokenized-strategy
branch: master
ref: master
contracts_folder: src

solidity:
import_remapping:
- "@openzeppelin/contracts=openzeppelin/v4.7.3"
- "@openzeppelin/contracts=openzeppelin/v4.9.5"
- "@tokenized-strategy=tokenized-strategy/master"

ethereum:
Expand Down
62 changes: 36 additions & 26 deletions contracts/VaultFactory.vy
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
This vault Factory can be used by anyone wishing to deploy their own
ERC4626 compliant Yearn V3 Vault of the same API version.
The factory uses the Blueprint (ERC-5202) standard to handle the
deployment of any new vaults off of the immutable address stored
at `VAULT_BLUEPRINT`. This allows the vaults to be deployed and
initialized fully on-chain with their init byte code, thus not
requiring any delegatecall patterns or post deployment initialization.
The factory clones new vaults from its specific `VAULT_ORIGINAL`
immutable address set on creation of the factory.
The deployments are done through create2 with a specific `salt`
that is derived from a combination of the deployer's address,
the underlying asset used, as well as the name and symbol specified.
Expand All @@ -33,6 +31,15 @@

from vyper.interfaces import ERC20

interface IVault:
def initialize(
asset: address,
name: String[64],
symbol: String[32],
role_manager: address,
profit_max_unlock_time: uint256
): nonpayable

event NewVault:
vault_address: indexed(address)
asset: indexed(address)
Expand Down Expand Up @@ -68,13 +75,13 @@ struct PFConfig:
fee_recipient: address

# Identifier for this version of the vault.
API_VERSION: constant(String[28]) = "3.0.1"
API_VERSION: constant(String[28]) = "3.0.2"

# The max amount the protocol fee can be set to.
MAX_FEE_BPS: constant(uint16) = 5_000 # 50%

# The address that all newly deployed vaults are based from.
VAULT_BLUEPRINT: immutable(address)
VAULT_ORIGINAL: immutable(address)

# State of the Factory. If True no new vaults can be deployed.
shutdown: public(bool)
Expand All @@ -95,21 +102,21 @@ custom_protocol_fee: public(HashMap[address, uint16])
use_custom_protocol_fee: public(HashMap[address, bool])

@external
def __init__(name: String[64], vault_blueprint: address, governance: address):
def __init__(name: String[64], vault_original: address, governance: address):
self.name = name
VAULT_BLUEPRINT = vault_blueprint
VAULT_ORIGINAL = vault_original
self.governance = governance

@external
def deploy_new_vault(
asset: ERC20,
asset: address,
name: String[64],
symbol: String[32],
role_manager: address,
profit_max_unlock_time: uint256
) -> address:
"""
@notice Deploys a new vault base on the bLueprint.
@notice Deploys a new clone of the original vault.
@param asset The asset to be used for the vault.
@param name The name of the new vault.
@param symbol The symbol of the new vault.
Expand All @@ -120,29 +127,32 @@ def deploy_new_vault(
# Make sure the factory is not shutdown.
assert not self.shutdown, "shutdown"

# Deploy the new vault using the blueprint.
vault_address: address = create_from_blueprint(
VAULT_BLUEPRINT,
asset,
name,
symbol,
role_manager,
profit_max_unlock_time,
code_offset=3,
salt=keccak256(_abi_encode(msg.sender, asset.address, name, symbol))
# Clone a new version of the vault using create2.
vault_address: address = create_minimal_proxy_to(
VAULT_ORIGINAL,
value=0,
salt=keccak256(_abi_encode(msg.sender, asset, name, symbol))
)

IVault(vault_address).initialize(
asset,
name,
symbol,
role_manager,
profit_max_unlock_time,
)

log NewVault(vault_address, asset.address)
log NewVault(vault_address, asset)
return vault_address

@view
@external
def vault_blueprint()-> address:
def vault_original()-> address:
"""
@notice Get the address of the vault blueprint
@return The address of the vault blueprint
@notice Get the address of the vault to clone from
@return The address of the original vault.
"""
return VAULT_BLUEPRINT
return VAULT_ORIGINAL

@view
@external
Expand Down
Loading

0 comments on commit f869f7e

Please sign in to comment.