ySwaps

ySwaps

Glossary

Components

Swappers

Single swapper

Multicall swapper

Swappers Usage

Swapper Contracts (version 0.2.0)

Ethereum

Fantom

Trade Factory

Trade Factory Contracts (version 0.2.0)

Ethereum

Fantom

Solvers Scripts

Dexes Libraries

Execute script

Extra toolings

Procedures

Add new strategy

Remove strategy

Keep3r jobs

Procedures

Add strategy fantom keeper harvest job

A)

# ySwaps

This document contain links to private repositories that might not be publicly available

ySwaps is used to abstract the token trading logic from the strategies harvest method, which means strategies can focus on farming tokens and don't have to handle tokens trading logic and paths. The "swappers" smart contracts allows trading optimizations and new paths to be added since the code is not hardcoded in strategies.

- ySwaps contracts repository (https://github.com/yearn/yswaps)

- ySwaps scripts repository (https://github.com/yearn/yswaps-app)

![yswaps-intro-diagram](https://i.imgur.com/VynhCU4.png)

## Glossary

- `sms`: Strategists multisig

- `tokenIn`: Token we have and we want to trade/swap

- `tokenOut`: Token we want to obtain on the swap

- `hopToken`: Token we use as a middle step between tokenIn and tokenOut

- `tf`: Trade Factory

## Components

- Swappers (https://docs.yearn.fi/developers/v2/yswaps#swappers)

- Trade Factory (https://docs.yearn.fi/developers/v2/yswaps#trade-factory)

- Solvers Scripts (https://docs.yearn.fi/developers/v2/yswaps#solvers-scripts)

- Dexes Libraries (https://docs.yearn.fi/developers/v2/yswaps#dexes-libraries)

- Execute Script (https://docs.yearn.fi/developers/v2/yswaps#execute-script)

- Extra Toolings (https://docs.yearn.fi/developers/v2/yswaps#extra-toolings)

- Procedures (https://docs.yearn.fi/developers/v2/yswaps#procedures)

- Keep3r Jobs (https://docs.yearn.fi/developers/v2/yswaps#keep3r-jobs)

### Swappers

Contracts in charge of making the swaps (uniswap, balancer, sushiswap, solidly and more). We can separated them in two types:

#### Single swapper

Uniswap, balancer, sushiswap, etc. These are straightforward contracts that will make a simple swap on these dexes (`token A` to `token B`). It is also worth to mention that these swappers take care of few extra stuff like: `approval needed to make the swap`, `transfering final tokens to strategy if needed`.

#### Multicall swapper

This contract will receive a bundle of transactions that are required to acquire the wanted token/tokens. This is used in specific cases where trade can not be made in a normal exchange due to liquidity issues, dex not having that token or route, needing extra steps to aquire the token such as depositing or withdrawing, and more. It is important to mention that this swapper does NOT take care of things like approvals, or transfers (important difference with `single swappers`).

#### Swappers Usage

Single swapper example: We have `tokenIn` and `tokenOut` and we know that we can go straight to sushiswap that has enought liquidity to make the trade with good conditions.

Multicall example: We have a `tokenIn` and we want a `tokenOut`. But theres no path on any dex to do the trade directly, so we need to split the swap in two steps:

- Step 1: `tokenIn` for `hopToken`.

- Step 2: `hopToken` for `tokenOut`.

For this example we are gonna assume that we will need to use two different dexes for each step. Since we are gonna split the trade in two different transactions and the main objective is to use TWO DIFFERENT dexes, this is where we use the `Multicall Swapper`.Everything that requires more than just a single swap tx, will use multicall dexes.

#### Swapper Contracts (version 0.2.0)

##### Ethereum

- MultiCallOptimizedSwapper: 0x711d1D8E8B2b468c92c202127A2BBFEFC14bf105 (https://etherscan.io/address/0x711d1D8E8B2b468c92c202127A2BBFEFC14bf105)

- ZRX 0xE32dd1F66365289b7fe14e503CBB336cD5D13F09 (https://etherscan.io/address/0xE32dd1F66365289b7fe14e503CBB336cD5D13F09)

- AsyncBancor 0xf13b8F103690FD74B5F137eC3CF679a9D1B4BA95 (https://etherscan.io/address/0xf13b8F103690FD74B5F137eC3CF679a9D1B4BA95)

- AsyncSushiswap 0x408Ec47533aEF482DC8fA568c36EC0De00593f44 (https://etherscan.io/address/0x408Ec47533aEF482DC8fA568c36EC0De00593f44)

- AsyncUniswapV2 0xA780b6A733D06dFf526A84c4258616b75279C763 (https://etherscan.io/address/0xA780b6A733D06dFf526A84c4258616b75279C763)

- OneInchAggregator 0x934D1c4ba7DF902d6cd0803882876e3C999cb406 (https://etherscan.io/address/0x934D1c4ba7DF902d6cd0803882876e3C999cb406)

##### Fantom

- ZRX: 0x0a94017DF3f8981Da97D79c28b103bAbDa0D67C7 (https://oklink.com/fantom/address/0x0a94017DF3f8981Da97D79c28b103bAbDa0D67C7)

- MultiCallOptimizedSwapper: 0x590B3e12Ded77dE66CBF45050cD07a65d1F51dDD (https://oklink.com/fantom/address/0x590B3e12Ded77dE66CBF45050cD07a65d1F51dDD)

- AsyncSolidly: 0x2cb391afd5180a31d01bE95Bd61A757594C9295a (https://oklink.com/fantom/address/0x2cb391afd5180a31d01bE95Bd61A757594C9295a)

- AsyncSpiritswap: 0x8d2aFF696F14b287a6E759F4bfFB6f08E92DFD20 (https://oklink.com/fantom/address/0x8d2aFF696F14b287a6E759F4bfFB6f08E92DFD20)

- AsyncSpookyswap: 0x86ee473C2eE7eB97Ee0276bE43427a6CF0cC6348 (https://oklink.com/fantom/address/0x86ee473C2eE7eB97Ee0276bE43427a6CF0cC6348)

- SyncSpiritswap: 0x923D22FE66C77E2fea215050F088AE26186F96aE (https://oklink.com/fantom/address/0x923D22FE66C77E2fea215050F088AE26186F96aE)

- SyncSpookyswap: 0xcD00a47D9fB36B0B37D589E20fE4fB7e2D9d9e8A (https://oklink.com/fantom/address/0xcD00a47D9fB36B0B37D589E20fE4fB7e2D9d9e8A)

### Trade Factory

-

This contract has the `enabled trades` that each strategy can make. Enabled trades are just a list of possible swaps that a strategy can make. So it only contains three variables: `strategyAddress`, `tokenIn`, `tokenOut`. We have these enabled trades to know which swaps can/should be made with each strategy.

-

This contract is also in changer of verifying the trades. To do that it will use the different `execute` methods in it and call the `swapper contracts` that needs to use. Remember that `swappers` are the contracts responsible to making the actual swap.

-

When we execute the swap its important to point out that this takes care of: `transfering tokenIn from strat to swapper`, `make final the check if the amount received > minAmountOut`.

#### Trade Factory Contracts (version 0.2.0)

##### Ethereum

- TradeFactory: 0x7BAF843e06095f68F4990Ca50161C2C4E4e01ec6 (https://etherscan.io/address/0x7BAF843e06095f68F4990Ca50161C2C4E4e01ec6)

##### Fantom

- TradeFactory: 0xD3f89C21719Ec5961a3E6B0f9bBf9F9b4180E9e9 (https://oklink.com/fantom/address/0xD3f89C21719Ec5961a3E6B0f9bBf9F9b4180E9e9)

### Solvers Scripts

Scripts in charge of providing the swap transaction that will be used and sent to `Trade Factory contract`.

-

Custom solvers: There are custom solvers for specific cases/strategies that will need to make multiple transactions for a specific swap. Each of these scripts aims to an specific strategy and trade that needs to be made. Some examples (`ThreePoolCrvMulticall.ts`). This is for specific strategies's trades that will need to swap tokens that can not be swaped/resolved on a single dex swap. The tx provided by this solver is gonna be used with the `Multicall swapper`.

-

Dexes solvers: this script is used for situations where the trade can be resolved with a normal swap on an exchange and does NOT require multiple tx to ensure the trade is possible. Different to `Custom Solvers`, this can be used in a generic way for different strategies/swaps. This script checks with every DeX and chooses the best one to make the trade. The tx provided by this solver is gonna be used with the `Single swapper`.

-

Multicall Dexes solvers: This solver is gonna split the trade in different steps using the `hopTokens` provided by us. Each step of the swap will loop between every dexes library and will take the best dex for each step of the trade. This solver generally will be using the `MulticallSwapper` since we are doing 2 steps or tx for the swap. But it is also possible to use the `SingleSwapper` because if both steps of the trade are using the same Dex, we should merge them into one for gas efficiency. We will be transforming `2 tx` into `1 tx` so we can use the `SingleSwapper`.

- All Solvers (https://github.com/yearn/yswaps-app/tree/main/scripts/libraries/solvers)

- Dexes Solver (https://github.com/yearn/yswaps-app/blob/main/scripts/libraries/solvers/Dexes.ts)

- Multicall Dexes Solver (https://github.com/yearn/yswaps-app/blob/main/scripts/libraries/solvers/MulticallDexes.ts)

### Dexes Libraries

There is one dex library per dex (uniswap, bancor, ...). They are in charge of getting the trade information of each Dex and returning all the data needed on the `Solvers`.

NOTE: The libraries contemplate the hopTokens too.

- All Dexes Libraries (https://github.com/yearn/yswaps-app/tree/main/scripts/libraries/dexes)

- Bancor Dex Library (https://github.com/yearn/yswaps-app/blob/main/scripts/libraries/dexes/bancor.ts)

- UniswapV2 Dex Library (https://github.com/yearn/yswaps-app/blob/main/scripts/libraries/dexes/uniswap-v2.ts)

### Execute script

This is where everything starts. Here we will grab all the enabled trades, loop and use logic to determinate if:

- Should the trade by executed?

- If so, what solver should we use?

- Once we have the solver response, execute the swap transaction provided by the solver.

- Execute Mainnet pending trades (https://github.com/yearn/yswaps-app/blob/main/scripts/execute-mainnet-pending-trades.ts)

- Execute Fantom pending trades (https://github.com/yearn/yswaps-app/blob/main/scripts/execute-fantom-pending-trades.ts)

#### Execute pending trades: What exactly happens?

-

Script execute-mainnet-pending-trades
1.1. Identify "pending trades"
1.2. Determinate which solver to use.
1.3. Solver determinates best Dex and returns the swap tx
1.3. Execute swap tx provided by the solver.

-

Call the execute in Trade Factory
2.1. Contract validates the data and that trade in configuration is valid.
2.2 Moves the funds directly from the strategy to the swapper.
2.3 Calls `swapper.swap()` to execute the trade.
2.4 Check that amount received by strategy > minAmountOut provided by us.

-

Swapper executes the trade
3.1. Validates some data.
3.2. Executes the trade
3.3. Send funds directly to the strategy.

### Extra toolings

- Gas service: provides the correct params for gas options for each network

- Price service: we use providers as CoinGecko API to normilize the `tokenInAmount` and `tokenOutAmount` in USD so we can verify that we are not getting a bad price from the Dex we ended up using.

- Link to services scripts (https://github.com/yearn/yswaps-app/tree/main/scripts/libraries/utils)

## Procedures

### Add new strategy

- Add `STRATEGY` role on Trade factory contract. From yMech.

- Add `enable trades` on Trade factory contract. From strategy.

- Add `enable trade` on ySwap repo config (`fantom.ts` `mainnet.ts`)
3.1 To add it to the config we also need to know what solver we are going to use. It would be `Dexes.ts` which is a generic solver or it would have its own `Custom Solver`
3.2 In case of need a `Custom Solver`, we need to code it.

- Once added to config, we are ready to execute the script to swap available trades.

### Remove strategy

- Revoke role from MS.

- Remove from network config file.

- OPTIONAL: remove custom solver if it has one.

## Keep3r jobs

Previous knowledge about how `Keeper Network` works is needed.

### Procedures

#### Add strategy fantom keeper harvest job

##### A)

- Go straight to ftmscan harvest job and add the strategy manually by a yMech.

- Add strategy to v2-ftm-strategies.ts config with `added: true`

##### B) (safest way to have everything added)

- Review and merge pr from strategists to add new strategies.

- On packages/strategies-keep3r Execute script: `npx hardhat run scripts/jobs/detached/01-v2-harvest-ftm-detached-job-add-strategies.ts --network fantom`

- On config file strategies-keep3r/utils/v2-ftm-strategies.ts change once again strategies property added to true

- Push changes.

#### Remove strategy fantom keeper harvest job

- Go to ftmscan `Harvest Job SC` and remove the strategy manually using method `removeStrategies`. Call with a mechanic.

- Remove strategy from `v2-NETWORK-strategies.json` file.


Vault Factory

Vault Factory

Traditional Strategies

Factory Strategies

Calling Harvest

Curve LP Tokens

Curve Strategies

Velodrome LP Tokens

Balancer LP Tokens

Balancer Strategies

Aerodrome LP Tokens

Determine Accumulated Rewards

Curve Strategy

Convex and Convex Frax Strategies

Contracts

Ethereum

Optimism

Base

Create with UI

Create from Contract

# Vault Factory

Yearn's Vault Factory allows anyone to permissionlessly deploy an official Yearn Vault with ready-made yield strategies.

The easiest way to get started using the factory is through the User Interface:

- https://yearn.fi/vaults/factory - Tutorial (https://docs.yearn.fi/developers/v2/vault-factory#create-with-ui)

The current version of the Vault Factory works with the following:

- Curve LP Tokens (https://docs.yearn.fi/developers/v2/vault-factory#curve-lp-tokens)

- Balancer LP Tokens (soon)

The Vault Factory is a massive step forward in automation. We're significantly reducing our operational costs for all vaults deployed with this new method. Here's the fee structure for them:

- 0% management fee (previously 2%)

- 10% performance fee (previously 20%)

Performance fees for every type of yVault go straight to Yearn treasury (treasury.ychad.eth (https://etherscan.io/address/0x93a62da5a14c80f265dabc077fcee437b1a0efde)) and are calculated only on top of harvest profits. The current fee structure for each yVault can be seen directly on the new yearn.fi (https://yearn.fi/vaults) website by clicking on the vault.

![image](https://i.imgur.com/0QIydKb.png)

Only one factory vault can be live for each token, so the Vault Factory will only deploy a new yVault if there is no vault for that token already deployed (excluding "legacy" vaults, though factory versions of these must be deployed from one of Yearn's multisigs).

## Harvests: Traditional vs. Factory Strategies

Factory vaults introduced a key change in the harvest process, enabling permissionless harvests (meaning anyone willing to pay transaction costs can perform them). Here is how harvests work in each case:

### Traditional Strategies

Traditional strategies have the token swap logic directly embedded in them. As a result, a harvest call simultaneously performs debt rebalances and converts them into realized profits in one transaction.

### Factory Strategies

Factory strategies separate swap logic from the strategy, executing it in a different transaction from the harvest. This ensures that swap transactions remain permissioned, safeguarding them from Miner Extractable Value (MEV) attacks.

Harvests in factory strategies still rebalance debt between strategies and allocate idle funds to strategies, pulling accumulated rewards into the strategy contract to be swapped by the ySwaps team. Once swaps are completed, which may take several days, anyone can call harvest a second time to acknowledge the profit generated by the swap and distribute it to the vault, making `pricePerShare` increase.

Although harvests will be permissionless for this specific group of vaults, Yearn will continue utilizing standard keeper automation to call harvests, even if no one else does. These automated harvests are run by keep3r.network and often depend on network congestion and transaction viability. For example, if the network conditions are consistently unfavorable, harvests may have delays.

### Calling Harvest

To call the `harvest()` function on a Yearn strategy, you need to interact with the keeper contract found at keeper.factory.ychad.eth (https://etherscan.io/address/keeper.factory.ychad.eth#writeContract) using the strategy address. Ensure you're calling `harvest()` on the correct contract: You MUST use the strategy address, NOT the vault address.

If you're unsure how to find the strategy address, the best method is to visit the Yearn vault's detail page and look under the "Strategies" section. This section provides information on the debt ratios and the addresses for all strategies attached to the vault.

For example, if you're interested in the vault at address `0xFfA0F0616229eE2aC08FA4C358D23b18D980134B` you can see the list of strategies addresses at yearn.fi/vaults/1/0xFfA0F0616229eE2aC08FA4C358D23b18D980134B?tab=strategies (https://yearn.fi/vaults/1/0xFfA0F0616229eE2aC08FA4C358D23b18D980134B?tab=strategies):

![Strategy Address Location](https://i.imgur.com/LO6E8hw.png)

Once you have the correct strategy address, go to the keeper contract on Etherscan, connect your wallet, enter the strategy address into the `harvest()` function, and execute the transaction by clicking “Write”.

## Curve LP Tokens

The first Vault Factory deployed live on Ethereum is the Curve LP Token Vault Factory. This factory allows users to deploy yVaults for any Curve LP token representing a Curve pool with an active gauge (allowing it to receive CRV emissions).

### Curve Strategies

Factory-deployed yVaults for Curve LP tokens contain up to three ready-made yield strategies:

- StrategyCurveBoostedFactory

- StrategyConvexFactory

- StrategyConvexFraxFactory

StrategyCurveBoostedFactory uses Yearn's veCRV balance (currently 62.8m (https://yearn.fi/ycrv)) to give users the maximum 2.5x boost on their CRV rewards.

StrategyConvexFactory supplies any additional Curve LP tokens (beyond which would receive the maximum 2.5x boost via the Curve strategy) to Convex Finance to earn CRV rewards (boosted by Convex's veCRV balance) and CVX rewards.

StrategyConvexFraxFactory will only be added to the vault if the Curve LP token of the vault can be staked in Convex for Frax (currently available for over 20 Curve LPs). This ConvexFrax strategy will be used instead of the standard Convex strategy to earn additional FXS rewards (on top of the standard CRV and CVX rewards).

![image](https://i.imgur.com/oJdwz6n.png)

In all three strategies, any earned tokens are regularly claimed, sold for more of the underlying Curve LP token, and then deposited back into the strategy to compound the yield.

## Velodrome LP Tokens

On Optimism, we have deployed the Velodrome LP Token Vault Factory. Several vaults have already been deployed and users can now permissionlessly deploy a new vault for any Velodrome V2 pool. The strategy collects VELO emissions from gauge incentives, swaps them for the LP token making auto-compounding effortless! At the moment, harvests for the Velodrome Vault Factory are permissioned and called regularly by keepers.

## Balancer LP Tokens

Balancer is another protocol we have integrated with our Vault Factory. The process is nearly identical to the Curve integration, with a few key differences relating to the unique features of Balancer.

### Balancer Strategies

StrategyAuraFactory is currently the only strategy used for Balancer factory vaults. It leverages the Aura rewards program on Balancer to earn additional yield.

The main difference between Balancer and Curve lies in their respective veTokens. Balancer's veBAL is their LP token (an 80/20 BAL/WETH pair), and their maximum lock duration is 1 year (compared to 4 on Curve). Unlike our Curve strategies where we use our veCRV balance to boost rewards, we currently do not have a large amount of veBAL in the treasury. Therefore, the strategy focuses on earning Aura rewards.

## Aerodrome LP Tokens

On Base, we have deployed the Aerodrome LP Token Vault Factory. Aerodrome is a fork of Velodrome V2 and was deployed by the Velodrome team on Base.

The Aerodrome Vault Factory works identically to the Velodrome Factory. It allows users to deploy new vaults permissionlessly for any Aerodrome V2 pool. The strategy collects AERO emissions from gauge incentives, which are sold for the LP token, making auto-compounding effortless.

Like with the Velodrome Vault Factory, harvests for the Aerodrome Vault Factory are permissioned and regularly called by keepers.

## Determine Accumulated Rewards

This section helps you know how much profit has accumulated, but calling harvest will not recognize profits unless they are sitting in the strategy's contract address. Also if there are reward tokens in the strategy's contract, those values should be added to your calculation in the section below.

### Curve Strategy

For Curve strategies, you can view how much rewards have accumulated for that vault by using Curve.finance's dashboard (https://curve.finance/#/ethereum/dashboard) and putting in Yearn's Curve Voter Proxy address `0xF147b8125d2ef93FB6965Db97D6746952a133934` (curve-voter.ychad.eth). This will show you the dollar amount accumulated in the strategy for all factory vaults.

### Convex and Convex Frax Strategies

For Convex and Convex Frax you can view how much rewards have accumulated in USD by viewing claimableProfitInUsdc() on the strategy under the Read Contract tab.

## Contracts

### Ethereum

- Curve LP Factory Address: 0x21b1FC8A52f179757bf555346130bF27c0C2A17A (https://etherscan.io/address/0x21b1FC8A52f179757bf555346130bF27c0C2A17A#readContract)

- Balancer LP Factory Address: 0x06393857dB733b76DD3ec91F3681cE85db275438 (https://etherscan.io/address/0x06393857db733b76dd3ec91f3681ce85db275438#readContract)

### Optimism

- Velodrome LP Factory Address: 0x8eb53a4fD9D2727a49E9e68a32108C18049bFf86 (https://optimistic.etherscan.io/address/0x8eb53a4fD9D2727a49E9e68a32108C18049bFf86#readContract)

### Base

- Aerodrome LP Factory Address: 0x2d12caFfa46ab3b6c5cEb224620de8b4DE3cDff1 (https://basescan.org/address/0x2d12caffa46ab3b6c5ceb224620de8b4de3cdff1#readContract)

The LP Factory contract provides a few main functions:

- `allDeployedVaults()`: returns an array of all the deployed vaults.

- `numVaults()`: returns the number of vaults deployed.

- `canCreateVaultPermissionlessly()`: takes in an address for a gauge and returns a boolean that indicates whether a vault can be created permissionlessly.

- `createNewVaultsAndStrategies()`: takes in an address for a gauge and a boolean that determines whether duplicate vaults are allowed, and creates a new vault and strategy.

- `latestDefaultOrAutomatedVaultFromGauge()`: takes in an address for a gauge and returns the latest default or automated vault from that gauge.

- `~StrategyImplementation()`: Has the name of the strategy in front of `StrategyImplmentation` and returns the strategy contract template address used in the vault factory each factory will have at least one.

## Create with UI

- User Interface: https://yearn.fi/vaults/factory

Follow these steps to create a new vault with the UI:

- Make sure your wallet is connected

![image](https://i.imgur.com/EKqOla1.png)

- Chose a token to create a vault for

![image](https://i.imgur.com/nIt8h8v.png)

- Review details and click "Create Vault"

![image](https://i.imgur.com/l7Z7oYm.png)

- Sign the transaction and the vault will be created (the signing interface is specific to your wallet provider, this one is Frame (https://frame.sh/))

![image](https://i.imgur.com/uRhX2VB.png)

## Create from Contract

-

Open the contract at etherscan: 0x21b1FC8A52f179757bf555346130bF27c0C2A17A (https://etherscan.io/address/0x21b1FC8A52f179757bf555346130bF27c0C2A17A#writeContract)

-

Call `canCreateVaultPermissionlessly()` function to make sure that a vault does not already exist for the gauge you want to create

![image](https://i.imgur.com/RBS2DIq.png)

- Call `createNewVaultsAndStrategies()` to create a new permissionless vault.

![image](https://i.imgur.com/2bMxjU0.png)

- Now your new Yearn Vault will be deployed and you can sit back while it auto-compounds your rewards into more of your Curve lp position.


Smart Contracts Review Guideline

Smart Contracts Review Guideline

Goals

Considerations

Solidity Version

Formatting & Naming Conventions

Formatting

Naming Conventions

Internal or Private Functions

Use Constants

Best Practices

Reduce Bytecode Size

Use libraries

Use Interfaces

Assert Returns values

Variables - Naming Convention

Multiple Routers

GitHub Issues

Known Issues

Tools

Required Checklists

General

Sources

# Smart Contracts Review Guideline

## Goals

This document specifies some guidelines to develop smart contracts and essential considerations when we do security reviews.

The information described here applies not ONLY to strategies (our main point of risk); if not, the main goal is to help all yDoers that develop or review contracts, especially Solidity.

The main goals are:

- Apply the best practices on developing smart contracts.

- Document our experiences as learning lessons to mitigate risks and new attack vectors.

- Reduce risks to get rekt on mainnet.

- Discover potential issues, bugs, or exploits in the development or review phase.

- Learn about the hacks or exploits that occurred in the DeFi ecosystem during the last months or years.

This document is based on:

- The experience that the Yearn team has reached out to developing smart contracts and helping other protocols to mitigate risks.

- Third sources (website, posts, and others). See more info in the `Sources` section.

## Considerations

### Solidity Version

Most smart contracts are built in Solidity (except the core contracts) and use the `0.6.12` version.

In new Solidity versions, some considerations are not required.

## Formatting & Naming Conventions

All of us are working remotely, and each of us has different ways to develop smart contracts. So, it is extremely important to get a standard formatting and naming convention for developing smart contracts.

### Formatting

The linting or formatting of the smart contract is a very important action to make them more readable, clear and easy to understand.

In our Brownie Strategy Mix repo (https://github.com/yearn/brownie-strategy-mix) we use Pretty Quick (https://www.npmjs.com/package/pretty-quick).

To lint the contracts, you just need to execute the command:

`yarn lint`

Before executing the CLI, you need to install the dependencies using `yarn install`.

### Naming Conventions

#### Internal or Private Functions

To make the contracts more clear, a good practice is to add the `_` prefix to all the internal or private functions.
So, for example for this function

```
function myFunction() internal { ...}
```

We should use:

```
function _myFunction() internal { ...}
```

#### Use Constants

Avoid using magic numbers or values. Instead, use constants with a meaningful name (in uppercase).

Instead of

```
function myFunction() public { ... uint256 value = aValue.mul(1234); ...}
```

use

```
// Add a sentence describing what this constant means.uint256 public constant VALUE_MULTIPLIER = 1234;......function myFunction() public { ... uint256 value = aValue.mul(VALUE_MULTIPLIER); ...}
```

## Best Practices

### Reduce Bytecode Size

#### Use libraries

One option is creating libraries because it encapsulates logic (move logic from the contract itself to the library) and reduces the strategy bytecode size.

References:

#### Use Interfaces

If the contract interacts with multiple protocols, you should use interfaces to interact with them instead of using the contract itself.

### Assert Returns values

We must assert the returned values in any external call to check that the call was successful.

```
uint256 value = externalContract.externalFunction(param1, ...paramN);require(value > 0, "invalid external value");
```

### Variables - Naming Convention

To make the code more clear and readable, we need to identify the unit in the variables that express amounts.

Example:

- `amountInWant`, `balanceInYShares`, etc.

### Multiple Routers

In case we need to use multiple routers to swap tokens, we should use this approach:

- Create constants for the router addresses.

- Create a variable `boolean useUniswap` or similar.

- Create a external/public function to switch the `useUniswap` value.

- To get the router, use:

- `Router router = useUniswap ? uniswapRouter : sushiswapRouter;`

See an example here (https://github.com/therealmonoloco/geist-lender-borrower/blob/master/contracts/Strategy.sol#L158).

## GitHub Issues

Use a new branch for each new strategy. Some old comments have references to lines of codes in branches that were already modified. It is more complicated to follow the comment when it happens.

## Known Issues

- If the strategy uses another vault, we should add the maxLoss setting. See comment here (https://github.com/jmonteer/yearnV2-strat-SNX-staking/pull/9#issuecomment-872376640).

- Strategy.liquidatePosition function: This condition must be true. `amountNeeded == liquidatedAmount + loss`

- Must have the health check address set.

- Example for Fantom (https://github.com/flashfish0x/Strategy0xDAOStaker/blob/ripae/contracts/GenericMasterChefStrategy.sol#L210)

- Example for Ethereum (https://github.com/tonkers-kuma/strategy-ssb/blob/main/contracts/Strategy.sol#L93)

- Must use the `SafeMath` library to do calculations in the Solidity version `0.6.x`.

- The over/underflow issues are fixed in the Solidity version `0.8.x`.

- The `BaseStrategy` already imports and declares the `SafeMath` and `SafeERC20` libraries, so you don't need to use the `using SafeMath for uint` statement. The same with `SafeERC20`.

## Tools

- ETH Security Tools (https://www.ethsecurity.org/research-and-developer-resources/tools)

- Trail of Bits Tools

- Slither (https://github.com/crytic/slither)

- Manticore (https://github.com/trailofbits/manticore)

- Echidna (https://github.com/crytic/echidna)

- Docker Image with all ToB tools (https://github.com/trailofbits/eth-security-toolbox/)

## Required Checklists

Each strategy must pass two checklist verifications, a general checklist and another one depending on its type. Both checklists are required to deploy the strategy on any mainnet network.

### General

These posts describe the most important considerations on security reviews.

- Stackoverflow - Security Review on Smart Contracts (https://ethereum.stackexchange.com/questions/8551/security-review-checklist-for-a-smart-contract)

- Sushiswap - Multiple Checks (https://github.com/sushiswap/bentobox/blob/master/documentation/checks.txt)

- Not Only Owner - Intro Security Hacking Smart Contracts (https://www.notonlyowner.com/learn/intro-security-hacking-smart-contracts-ethereum)

## Sources

- Explained XToken Hack (https://halborn.com/explained-the-xtoken-hack-august-2021/)

- BzX Network Post Mortem (http://web.archive.org/web/20220709131325/https://bzx.network/blog/post-mortem-update)

- Harvest Finance Uninitialized Proxies (https://medium.com/immunefi/harvest-finance-uninitialized-proxies-bug-fix-postmortem-ea5c0f7af96b)

- Uniswap V3: Risk Analysis for TWAP (https://twitter.com/mudit__gupta/status/1459340913751117826?s=21)

- Minimal Proxies - Reasons Why You Should Use EIP1167 (https://medium.com/taipei-ethereum-meetup/reason-why-you-should-use-eip1167-proxy-contract-with-tutorial-cbb776d98e53)

- Origin Protocol - Understanding Minimal Proxies (https://blog.originprotocol.com/a-minimal-proxy-in-the-wild-ae3f7b8da990)

- Open Zeppelin - Understanding Minimal Proxies (https://blog.openzeppelin.com/deep-dive-into-the-minimal-proxy-contract/)

- Open Zeppelin - Creation vs Runtime Code (https://blog.openzeppelin.com/deconstructing-a-solidity-contract-part-ii-creation-vs-runtime-6b9d60ecb44c/)

- Not Only Owner - Spanish & English (https://twitter.com/tinchoabbate/status/1433435829372850180?s=21)

- Twitter Thread - How Your Crypto Fund or Exchange Gets Hacked (https://twitter.com/moo9000/status/1448967076698333192?s=21)


Additional Resources

Additional Resources

Introduction

How To Videos

Start coding

Other reading material

# Additional Resources

This is a collection of resources that aim to be an introduction to how yVaults V2 work.

## Introduction

The best introduction to V2 is the workshop done by Storming0x (https://github.com/storming0x/). It's security-focused but still a great introduction to yVaults V2.

- Video - Part 1 (https://www.youtube.com/watch?v=C0fsYiCI54g)

- Video - Part 2 (https://www.youtube.com/watch?v=Y8y8ALmuLu4)

- Slides (https://docs.google.com/presentation/d/1NsePa_hXV1vsbMixTSRsPKYBHYvmVQf7IvpI_8k4p_k/edit#slide=id.p)

- Yearn State of the Vaults (https://vaults.yearn.fi/)

## How To Videos

- How to become a strategist (https://www.youtube.com/watch?v=NVR3teJw0Y0)

- How to buidl on top of Yearn Vaults (https://www.youtube.com/watch?v=a1TsO62402c)

## Start coding

When you decide to start, this reading material is going to come handy:

- Template for Strategies (https://github.com/yearn/brownie-strategy-mix)

- Vaults V2 Repository (https://github.com/yearn/yearn-vaults)

- How to set up coding environment for Yearn Strategies (https://sambacha.github.io/yearn-vaults/index.html)

- Mint your own DAI (https://medium.com/ethereum-grid/forking-ethereum-mainnet-mint-your-own-dai-d8b62a82b3f7)

- Livecoding: How to write strategies with Foundry and Forge (https://www.youtube.com/watch?v=z48R7dhAGP4)

Once you have the strategy ready. This will guide you further down the road.

- Vault naming standard (https://github.com/yearn/yearn-assets/blob/master/naming-standard.md)

- Release process (https://github.com/yearn/yearn-devdocs/blob/master/docs/developers/v2/OPERATIONS.md)

- Security check (https://docs.google.com/document/d/1hBKB73kJPQM71enrG8xoSFj7wxYmczUlgigyq2KkcTE/edit#heading=h.4ieoeyetfrxm)

## Other reading material

This is a complement to the others but it's not directly related to creating strategies.

- The Keep3r Network (https://macarse.medium.com/the-keep3r-network-experiment-bb1c5182bda3)

- Andre intro to Yearn Vaults (https://medium.com/iearn/yearn-finance-v2-af2c6a6a3613)

- Delegated vaults explanation (https://medium.com/iearn/delegated-vaults-explained-fa81f1c3fce2)


Yearn System Specification

Yearn System Specification

Definitions

Vault Specification

Definitions

Normal Operation

Fees

Profit distribution

Oracle

Emergency Shutdown Mode

Strategy Specification

Definitions

Normal Operation

Emergency Exit Mode

Registry Specification

Normal Operation

Governance Specification

Treasury Specification

# Yearn System Specification

## Definitions

- Governance: YFI token governance system

- Treasury: Yearn rewards mechanism/protocol dev fund

- Vault: Only user touch-point, manages funds

- Strategy: Complex external interactions w/ limited access to Vault

- Strategist: original creator of strategy, is in charge of monitoring its position for adverse effects.

- Registry: On-chain registry of deployed Vaults for tokens, indexed by API version

## Vault Specification

### Definitions

- Management: Trusted with privileged access for limited operations (ensuring performance of Vaults)

- Guardian: Trusted with privileged access for limited operations (ensuring safety of Vaults)

### Normal Operation

NOTE: Users should only withdraw "free" assets as some strategies need to divest "gracefully", and a large withdrawal could incur a loss, which will get passed back to the withdrawer.

NOTE: "free" assets in the Vault means the amount the Vault has freely available (e.g. not invested in Strategies)

NOTE: The strategy can also revoke itself during normal operation of the Vault, but this behavior only occurs during "Emergency Exit" mode.

- A User is able to deposit an amount of the single asset the Vault accepts in exchange for shares of the Vault's underlying assets, depending on the Vault's deposit configuration.

- A User is able to withdraw an amount of tokens represented by their shares up to the total available amount that can be withdrawn from the combination of the Vault's overhead, and what can be forcibly withdrawn from all the strategies with debt to the Vault that have been pre-authorized for withdrawals in the Vault's withdrawal queue.

- A User is able to transfer any amount of their Vault shares to anyone else.

- Only Governance can approve Strategies to interact with Vaults and take on debt.

- Governance can set the Management role to another account, without their permission.

- Either Governance or Management can modify the parameters of a Strategy's borrowing capabilities.

- Either Governance or Management can reconfigure the strategies in the withdrawal queue.

- Only Governance can migrate a Strategy, and their current capital and debt, to a newer version of the Strategy.

- Governance can set the Guardian role to another account, without their permission.

- Either the Guardian or Governance can revoke a Strategy from borrowing any more assets from the Vault and trigger a divestment of that Strategy.

- Either the Guardian or Governance can trigger the Vault to enter Emergency Shutdown Mode and trigger a divestment from all connected Strategies.

### Fees

- The Treasury (which benefits Governance) collects a "management fee" based on the total assets the Vault has over a period of time, assessed each time the Strategy interacts with the Vault, and is provided as newly minted shares to the Treasury.

- The Treasury (which benefits Governance) collects a "performance fee" based on the amount of returns a Strategy produces during Normal Operation, assessed each time the Strategy interacts with the Vault, and is provided as newly minted shares to the Treasury.

- Each Strategist collects a "performance fee" based on the amount of positive returns their Strategy produces during Normal Operation, assessed each time the Strategy interacts with the Vault, and is provided as newly minted shares to the Strategist.

### Profit distribution

Once a strategy is harvested, the gains are distributed during 6 hours.
This is to prevent sandwich attacks of an account depositing tokens right before the harvest and withdrawing right after and getting the profits without staying in the vault.

### Oracle

Yearn vaults aren't using any oracles.
The vault doesn’t rely on oracle because it doesn’t require a price information, it’s not lending, exchanging assets,

### Emergency Shutdown Mode

NOTE: During Emergency Shutdown mode of the Vault, the intention is for the Vault to recall the debt as quickly as reasonable (given on-chain conditions) with minimal losses, and open up deposits to be withdrawn by Users as easily as possible. There is no restrictions on withdrawals above what is expected under Normal Operation.

- During Emergency Shutdown, no Users may deposit into the Vault.

- During Emergency Shutdown, Governance cannot add new Strategies.

- During Emergency Shutdown, the Vault should communicate to each Strategy to return their entire position as quickly as reasonable, with minimal impact to their positions (Normal Operation).

- Only Governance can exit Emergency Shutdown Mode.

## Strategy Specification

### Definitions

- Keeper: a bot which maintains the strategy, by ensuring it regularly generates returns for the Vault during pre-defined intervals or events

### Normal Operation

NOTE: Triggers must be defined for the interval(s) allowable without causing instability to the Strategy's position

NOTE: Updates must not trigger an instability in the Vault, especially when considering other Strategies' update frequencies

- The Strategy can interact with its connected Vault, and obtain capital according to its current borrowing limit.

- The Strategy can interact with any external system required to turn the capital borrowed into returns for the Vault

- The Strategy defines triggers for either Governance, the Strategist, or the Keeper to use as a signal to update or adjust its position(s).

- The Strategy defines triggers for either Governance, the Strategist, or the Keeper to use as a signal to take profits and report to the Vault.

- Either Governance or the Vault can migrate the positions of the Strategy to another Strategy.

- Either Governance or the Strategist can trigger the Strategy to enter into Emergency Exit Mode.

### Emergency Exit Mode

NOTE: In this mode, the Strategy defines a reversionary set of actions that seek to unwind and divest funds back to the Vault as quickly and smoothly as possible, with as minimal losses as possible.

- During Emergency Exit, the Strategy cannot take new debt from the connected Vault.

- During Emergency Exit, the Strategy can still interact with any external system, but must be able to handle any failure(s) of each of those system(s) as well as possible.

- There is no condition that can revert Emergency Exit Mode once it is entered.

## Registry Specification

### Normal Operation

NOTE: The Registry allows an on-chain reference for Vault deployment events, to be used with external integrations. It is also possible to reconstruct the deployment and release history via on-chain calls.

NOTE: The API version of each Vault deployment for a token should increase according to Semantic Versioning (https://semver.org/). However, this is not practically enforced.

- Only Governance can register a new release for future Vaults to use when deploying via proxy deployment.

- Anyone can deploy a proxy deployment Vault, using the latest release, for experimental purposes

- Only Governance can endorse a Vault deployment for a given token with the latest release.

## Governance Specification

NOTE: Governance is expected to manage each deployed Vault and the strategies connected to them in order to maintain the risk and returns that Vault users expect

- Governance must be able to perform the calls expected for it to manage the Vaults and Strategies it maintains.

- Any actions that require the exclusive action by Governance must be able to be accomplished safely within a reasonable timeframe.

## Treasury Specification

NOTE: Rewards are given as shares of each Vault, which are redeemable for the underlying token that the Vault is wrapping.

NOTE: It is up to the design of the Treasury to unwrap and further account for the share of the underlying awarded to governance participants, and the other parties in the Yearn ecosystem (including keeper gas fees, protocol development and maintenance costs, etc.)

NOTE: The Treasury system could leverage the Vault design, with strategies that just market sell the rewards for YFI.

- The Treasury should incentivize proper management of the Vault by Governance, optimizing for stability of returns over long periods of time, minimizing risk, and encouraging growth of deposits.


Definitions

Deployment

Miscellaneous

Running the Vault

Strategy Management

Debt Updates

Reporting

Customization

Accountant

Deposit/Withdraw Limit Modules

Default Queue

Good to Know

What Tokens Not to Use

# Deploying and Managing a V3 Multi Strategy Vault

V3 makes it as simple as possible for anyone to deploy and manage their own Multi Strategy Vaults. No longer will Yearn be the only manager of Vaults, gate-keeping who can be a debt allocator, or what strategies should be added to a vault. Now, anyone can deploy, manage, and earn fees from their vision and preferences on everything from risk profile, fee model, decentralization, etc.

In V3 our multi strategy or "Allocator Vaults" are designed to be efficient 4626 compliant debt allocators that can have many different "strategies" attached to them and will direct funds to these strategies based on the vault's management choice. The vaults are built to be "plug and play" meaning managers can simply deploy, add their strategies, and start the yield generation. But they also hold many customization factors, allowing different managers to differentiate themselves and experiment with different optionality.

Running your vault requires no need to know how to code. Anyone desiring to manage their strategies and allocations can simply deploy and run their vault.

## Definitions

- vault (allocator): ERC-4626 compliant contract that accepts deposits, issues shares, and allocates funds to different strategies to earn yield.

- shares: A tokenized representation of a depositor's share of the underlying balance of a vault.

- strategy: Any ERC-4626 compliant contract that can be added to an allocator vault that earns yield on an underlying asset.

- debt: The amount of the underlying asset that an allocator vault has sent to a strategy to earn yield.

- report: The function where a vault accounts for any profits or losses a strategy has accrued, charges applicable fees, and locks profit to be distributed to depositors.

- role_manager: The position given to an address in a vault that controls what other addresses have rights to call permissioned functions on the vault.

## Deployment

There are multiple ways to handle deployments of vaults. By far the simplest way to deploy your own multi-strategy vaults is by utilizing the pre-built `RoleManager` and `RoleManagerFactory` contracts.

The `RoleManagerFactory` can be used to deploy a full set of V3 periphery contracts including `Accountant`, `DebtAllocator`, `Registry` and `RoleManager` contracts and will configure them all automatically to make deployment and management as simple as possible while still allowing full customization where desired.

You can find the deployed `RoleManagerFactory` contract here (https://etherscan.io/address/0xca12459a931643BF28388c67639b3F352fe9e5Ce).

You will only need three variables.

- `projectName` : The name of your project i.e. "Yearn"

- `governance` : The main address to be in control of the vaults and RoleManager contract. This should be a fully trusted address.

- `management` : Secondary address to manage lower risk more day to day needs of the vault such as debt allocations.

warning

Make sure your `governance` and `management` addresses are NOT the same address as this will prevent you from adding strategies.

```
projectName = "Project Name" // Name of your project.governance = address(0x69) // Address to be in charge of the project.management = address(0x420) // Address to help manage vaults.// Deploy a new RoleManager for your use caseaddress myNewRoleManager = roleManagerFactory.newProject( projectName, governance, management)
```

The `RoleManager` contract deployed will then serve as the `role_manager` position on any multi-strategy vaults deployed for simple and programmatic setup of your vaults.

You can then use your new RoleManager contract to do one step deployments and setups of any new vaults.

```
address newVault = myNewRoleManager.newVault( asset, category, vaultName, vaultSymbol)
```

`category` is used by the RoleManager to classify and store vaults which will allow multiple vault types that use the same underlying address to be deployed. The categorization can be anything a project manager desires or just set to `0` or any other constant for all.

Your new vault will now be deployed, with the Roles given out to each specified address, and Accountant hooked up to charge fees, and endorsed in your registry.

To learn more about how to customize your deployment setups and using the `RoleManager` contract view the full spec (https://docs.yearn.fi/developers/smart-contracts/V3/Periphery/RoleManager)

Alternatively you can manually deploy a vault directly from the factory and do a complete custom setup by following these instructions (https://docs.yearn.fi/developers/v3/vault_deployment)

### Miscellaneous

There are other options that a vault manager can set that are not necessary for the vault to function but may be desired for further customization.

- minimum_total_idle: An amount specified in the underlying asset that the vault will force to remain free in the vault during debt updates to make servicing withdraws cheaper.

- profit_max_unlock_time: The time in which profits reported by the strategies will be distributed to depositors. This can be adjusted to match the current report cycle of the vault's strategies to create a continuous stream of APY paid out to depositors.

## Running the Vault

### Strategy Management

The job of a vault is to manage debt between strategies that do the yield generation. 3 roles control what strategies are added to the vault, ADD_STRATEGY_MANAGER, REVOKE_STRATEGY_MANAGER, and FORCE_REVOKE_MANAGER.

A strategy can be any contract that has the needed 4626 interface (https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultV3.vy#L39) for the vault to interact with it. This includes Tokenized Strategies, 3rd party 4626 vaults, and other allocator vaults.

To add a strategy first call `vault.add_strategy(strategy_address)`.

Each strategy gets added with a default 'max_debt' of 0. This means the MAX_DEBT_MANAGER will need to call `vault.update_max_debt_for_strategy(strategy, max_debt)`.

Once a strategy has been added and given a max_debt, the DEBT_MANAGER role can allocate funds.

To remove a strategy, first remove all the debt from the strategy and then call `vault.revoke_strategy(strategy)`.

If a strategy has issues and cannot pay all of its debt back `vault.force_revoke_strategy(strategy)` can be used to forcefully remove the strategy.

NOTE: Forcefully removing a strategy that still has debt will cause a loss to be recorded and a reduction of Price Per Share.

### Debt Updates

The DEBT_MANAGER role is in charge of allocating funds between the strategies added to a vault.

By default the DEBT_MANAGER role is given to the `DebtAllocator` contract deployed by the `RoleManagerFactory` and is controlled by the `management` address. For a full explanation of the `DebtAllocator` visit the full spec (https://docs.yearn.fi/developers/smart-contracts/V3/Periphery/DebtAllocator)

All debt updates are denominated in the underlying asset and are restricted by the `max_debt` for each strategy and the `minimum_total_idle` for the specific vault.

Debt updates will also respect the strategies specific `maxRedeem` and `maxDeposit`.

To deposit or withdraw vault funds from a strategy simply call `vault.update_debt(strategy, desired_debt)` where desired debt is the end amount denominated in the underlying asset that the strategy should have after the full debt update.

Debt updates also come with an optional `max_loss` parameter that is recommended to be used on debt decreases. It works just like the withdraw/redeem parameter of the same name and assures any losses realized on debt decreases are within the expected bounds.

NOTE: If a strategy has unrealized losses you cannot lower its debt.

NOTE: It is recommended to report a strategy's gain before withdrawing 100% of debt from the strategy.

### Reporting

To properly record any profits/losses from a strategy, charge fees, and lock profits for distribution to depositors, the REPORTING_MANAGER will need to "report" for each strategy via `vault.process_report(strategy)`.

The RoleManager will give the REPORTING_MANAGER role by default to the global permissionless `Keeper`. This means anyone can call `process_report` on your vault unless otherwise set.

This function will trigger all necessary logic to record a strategy's gain since the last report and begin distributing that profit to depositors over the vault's specific `profit_max_unlock_time`.

NOTE: To charge fees you will need first to have added an 'accountant' to your vault that will hold the fee logic and receive the fees that are charged.

NOTE: All profit and loss calculations use the strategies 'convertToAssets' function. If this function can be manipulated it can lead to incorrect profits or losses being recorded by the vault

## Customization

### Accountant

You will need to add a separate contract as the vault's 'accountant' to charge fees.

`vault.set_accountant(accountant)`

*If using the RoleManager/Factory this contract will be automatically deployed and setup during each subsequent vault deployment.

The accountant is called by the vault during every `report` with the strategy that is reporting and the gain or loss it's reporting. The accountant will then return the total fees or refunds that should be charged by the vault during that report and paid to the accountant.

Accountants can hold any logic that vault managers want to dictate fees or simply charge normal performance or management fees. A ready-to-use Accountant can easily be used with any vault for those who wish just to charge standard fees.

See Here: https://github.com/yearn/vault-periphery/blob/master/contracts/accountants/Accountant.sol

#### Deposit/Withdraw Limit Modules

Each vault comes with default deposit and withdraw limits that can be used for out of the box 4626 compliant functionality. However, these limits can also be completely customized for full programmability by adding a deposit_limit_module or withdraw_limit_module respectively.

These modules are stand-alone smart contracts similar to the accountant that if added will be used by the vault to enforce any custom deposit or withdraw limits.

This can be used to enforce a whitelist of depositors, minimum or maximum deposit sizes, liquidity constraints etc.

Note: To set a deposit_limit_module the DEPOSIT_LIMIT_MANAGER will either need to use the optional `override` flag or first need to set the vaults default `deposit_limit` to uint256 max. And will not be able to change the `deposit_limit` without the same flag or unless the deposit_limit_module is removed and set to address(0).

#### Default Queue

Each vault has a `default_queue` based on the strategies added and removed from the vault. The `default_queue` is used to service withdraws when no custom queue is passed. This queue is simply ordered by the time when strategies were added: where the oldest strategy is at the beginning of the queue.

There is an optional parameter in `add_strategy` of `add_to_queue` that defaults to True, but can be set to False if you do not want to add the strategy to the `default_queue`.

If a different ordering is desired or management wants to remove a certain strategy from the default queue, the QUEUE_MANAGER role can set a new queue.

`vault.set_default_queue(new_default_queue)`

Where `new_default_queue` is an array of strategies with a max length of 10, in which all strategies are currently active in the vault.

The vaults QUEUE_MANAGER can also choose to not allow custom queues to be passed into the vault on withdraws at any time by turning on the 'use_default_queue' flag by calling, `vault.set_use_default_queue(True)`.

## Good to Know

### What Tokens Not to Use

There are certain tokens whose native behavior makes them incompatible with being the underlying asset of a vault and should be avoided.

A few examples of this are:

- Rebasing Tokens

- Fee on Transfer

- Reentrancy Tokens (ERC-777)

Any token whose normal functionality breaks the ERC-20 standard may not be compatible with V3 vaults.


Manual Vault Deployment

Manual Vault Deployment

Definitions

Deployment

Setup

Roles

Deposit Limit

# Manual Vault Deployment

tip

if you are looking for the simplest way to deploy your own multi-strategy vaults we recommend first reading about using the Role Manager Factory on this page. (https://docs.yearn.fi/developers/v3/vault_management#deployment)

## Definitions

- vault (allocator): ERC-4626 compliant contract that accepts deposits, issues shares, and allocates funds to different strategies to earn yield.

- shares: A tokenized representation of a depositor's share of the underlying balance of a vault.

- strategy: Any ERC-4626 compliant contract that can be added to an allocator vault that earns yield on an underlying asset.

- debt: The amount of the underlying asset that an allocator vault has sent to a strategy to earn yield.

- report: The function where a vault accounts for any profits or losses a strategy has accrued, charges applicable fees, and locks profit to be distributed to depositors.

- role_manager: The position given to an address in a vault that controls what other addresses have rights to call permissioned functions on the vault.

## Deployment

Each release of the vaults will have its own "Vault Factory" deployed to make it as simple and trustless as possible to deploy your vault. The vault factory allows anyone to trustlessly deploy their own vault which is an exact copy of the previously deployed "original" vault for that specific version.

warning

Vaults not deployed through the factory will not be recognized as part of the Yearn ecosystem and may experience issues during runtime.

To deploy your vault directly from the factory, simply find the factory's address for the most recent release here (https://docs.yearn.fi/developers/addresses/v3-contracts) and call `Factory.deploy_new_vault(params)`.

The needed parameters are:

- asset: The address of an ERC-20 compliant token used as the underlying asset to earn yield for the vault.

- name: The name for your vault that will apply to the token issues to depositors.

- symbol: The symbol the token issued to depositors will use.

- role_manager: The address in charge of giving permissions to other addresses which allow access to certain permissioned functions.

- profit_max_unlock_time: In seconds, profits reported from strategies will be unlocked.

Once deployed, you can get your vault's address from either the Factory function's return value or the `NewVault` event emitted by the factory.

The vault should be automatically verified when deployed. However, if it is not you can follow the verification steps (https://etherscan.io/verifyContract) on Etherscan using the VaultV3.vy (https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultV3.vy) for your specific API Version.

NOTE: The vault factory utilizes create2 (https://eips.ethereum.org/EIPS/eip-1014) opcode to deploy vaults to deterministic addresses. This means the same address can not deploy two vaults with the same default parameters for 'asset', 'name' and 'symbol'.

## Setup

Once deployed, additional setup steps and variables can be configured if desired.

### Roles

The first is to set up the Roles for your specific vault. The vaults use a role-based system for access control to the permissioned functions. The roles are a Vyper Enumerator (https://docs.vyperlang.org/en/stable/types.html#enums) pattern based on Pythons.

Each permissioned function in the Vaults has its own "role" that can call that specific function. For example, to call `add_strategy(new_strategy: address)` the address must have the `ADD_STRATEGY_MANAGER` role. Roles can be held by any number of addresses or by no address.

The same address can hold every role, each role can be held by a different address or any combination desired.

The address sent during deployment as `role_manager` is in charge of assigning roles to different addresses.

A full explanation of python enumerators (https://docs.python.org/3/howto/enum.html) is beyond the scope of this doc, but the corresponding int to each role can be viewed here (https://github.com/yearn/yearn-vaults-v3/blob/master/tests/utils/constants.py#L12)

To give an account a specific role you can simply call `vault.set_role(account, role)` where 'role' is the int representing all the roles you would like the 'account' to hold. This will override all roles previously held by the address.

The role manager can also use `vault.add_role(account, role_to_add)` to only add 1 new role to the existing roles that account already has. Or `vault.remove_role(account, role_to_remove)` to remove just one role without overriding the full bitmap.

Examples

```
# Set `account` to be the ADD_STRATEGY_MANAGERvault.set_role(account, 1)# Set `account` to be both the ADD_STRATEGY_MANAGER and REVOKE_STRATEGY_MANAGERvault.set_role(account, 3)# Add the REPORTING_MANAGER role to the accounts already held roles.vault.add_role(account, 32)# Remove just the REVOKE_STRATEGY_MANAGER role.vault.remove_role(account, 2)# Set `account` to hold every rolevault.set_role(account, 16383)# Set `account` to hold no rolesvault.set_role(account, 0)
```

NOTE: The vault `role_manager` can not call any permissioned function by default, and would have to give itself any roles that it should have.

### Deposit Limit

Each vault will default to have a deposit limit set to 0. Which means all deposits will revert.

Once ready, the address with the DEPOSIT_LIMIT_MANAGER will need to either set a deposit_limit > 0 or add a deposit_limit_module.


Overview

Introduction

Why?

Definitions

Architecture

Getting started

Strategy Writing

Optional Functions

availableDepositLimit(address _owner)

FYI

Periphery

Swappers

APR Oracles

HealthCheck

Report Triggers

Testing

Deployment

Contract Verification

Operating Your strategy

Reporting

Keepers

Setters

Emergencies

# Guide to creating V3 "Tokenized Strategies"

## Overview

So you wanna be a Yearn strategist?

Can you write 3 lines of code?

Well, then you came to the right place.

The strategy creation process has been very simplified in V3, so it is technically possible to write a Tokenized Strategy with only 3 lines of code. However, most strategies will need more than that. This will guide you through the entire strategy development process from getting your local repo set up through deployment and automation to cashing out those sweet sweet strategist fees.

## Introduction

A strategy's job is to hold the logic responsible for generating yield on some underlying asset. It should hold the code to integrate with an external protocol and do any needed asset deployment, withdraw logic, reward selling, reinvesting LTV maintenance etc. to generate the most possible yield from that particular source most efficiently.

The most significant update to Yearn V3 from V2 was the introduction of "Tokenized Strategies". In V2 strategies were stand-alone contracts that were attached to one specific vault. That vault was the only one who could ever deposit or withdraw funds from the strategy and each had a trusted relationship with the other.

In V3 strategies are now fully ERC-4626-compliant stand-alone vaults. Though their job remains the same (i.e., generate yield from one external source), strategies can now be connected to many different vaults simultaneously and deposited directly into by an end user.

This increased functionality not only means strategies have a much larger potential market of depositors but also means anyone (including you) now can build, deploy, market, and maintain your own Yearn strategy without any need for an endorsement or permission from Yearn.

## Why?

- Strategist Fees! - V3 brings back the ability for developers of strategies to earn the fees generated from their strategy. Meaning your earning potential is unlimited.

- Codify Your Yield Farming - Tokenized strategies make it easy for anyone to codify their yield-generating strategies. Wanna keep your alpha private? No problem they come fully customizable to allow for you to be the only one allowed to deposit.

- Simple 4626 Wrappers - Tokenized Strategies make a super easy and cheap way to give any previously deployed protocol an ERC-4626 interface. This opens up any protocol to easily integrate into the rapidly growing 4626 ecosystem (including Yearn Allocator vaults).

## Definitions

- Strategy (https://github.com/yearn/tokenized-strategy) : A strategy or "Tokenized Strategy" in V3 refers to an ERC-4626 compliant contract that utilizes the TokenizedStrategy (https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol) pattern that either allocator vaults or individual users can deposit directly into and receive shares in return. The strategy takes the underlying asset and deploys it in a single source in order to generate yield on that asset.

- Vault: Or "Allocator Vault" is a Yearn ERC4626 compliant Smart contract that receives assets from Depositors to distribute among the different Strategies added to the vault, managing accounting and asset distribution.

- Asset: Any ERC20-compliant token

- Shares: ERC20-compliant token that tracks the asset balance in the strategy for every depositor.

- TokenizedStrategy.sol (https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol): The implementation contract that all strategies delegateCall to for the standard ERC4626 and profit locking functions.

- BaseStrategy.sol (https://github.com/yearn/tokenized-strategy/blob/master/src/BaseStrategy.sol): The abstract contract that a strategy should inherit from that handles all communication with the Tokenized Strategy contract.

- Strategist: The developer of a specific strategy.

- Depositor: Account that deposits the asset and holds Shares

- Management: The owner of the specific strategy that can set fees, profit unlocking time etc.

- Emergency Admin: Address that can call emergency functions on the strategy.

- Keeper: the address of a contract allowed to call report() and tend() on a strategy.

- Factory: The factory that all Allocator Vaults of a specific API version are cloned from that also controls the protocol fee amount and recipient for a strategy.

- Performance Fee: The fee strategies charge during reports based on the yield earned since the last report.

- Performance Fee recipient: The address that receives the shares charged as performance fees.

- Protocol Fee: A fee on the fees charged by strategist sent to the Yearn Treasury.

- Profit Max Unlock Time: Time in seconds over which reported profits will unlock over.

- `report`: Called by management or keepers to accrue all profits or losses, charge fees, and lock profit to be distributed.

- `tend`: Called by management or keepers between reports for any maintenance that should happen that doesn't require a full report.

- API Version: The version that a specific Strategy is using for its logic.

## Architecture

While the complete architecture of the Tokenized Strategy is out of the scope of this document you can read more about how it works here (https://github.com/yearn/tokenized-strategy/blob/master/SPECIFICATION.md)

TLDR: V3 strategies use an immutable proxy pattern to outsource all of its complex, high risk, and redundant code to one TokenizedStrategy.sol (https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol) implementation contract that is used by every strategy of a specific API version. To use this pattern you simply need to inherit the BaseStrategy.sol (https://github.com/yearn/tokenized-strategy/blob/master/src/BaseStrategy.sol) contract, that holds all of the logic to communicate with the implementation contract, and then just override a few simple functions with your specific strategy logic.

## Getting started

Yearn has base templates made to build off of built-in both Ape Worx (https://www.apeworx.io/), a python-based development toolkit, and Foundry (https://book.getfoundry.sh/).

-

Choose your development framework.

- Tokenized Strategy Foundry Mix (https://github.com/yearn/tokenized-strategy-foundry-mix)

- Tokenized Strategy Ape Mix (https://github.com/yearn/tokenized-strategy-ape-mix)

-

Set up the local environment with the selected mix. Each mix has detailed instructions in the "How To Start" section of the README, of specific requirements, cloning instructions, and needed environment variables.

-

Assure tests pass. Each mix comes with a small set of pre-written tests, to serve as examples and can be used to ensure your local repository is set up correctly before adding your logic.

## Strategy Writing

So you have your idea and local environment setup. Now it's time to start writing your actual strategy.

To create your Tokenized Strategy, you must override at least three functions outlined in the `Strategy.sol`.

The only default global variables from the BaseStrategy that can be accessed from storage is `asset` and `TokenizedStrategy`.

If other global variables are needed for your specific strategy, you can use the `TokenizedStrategy` variable to quickly retrieve any other needed variables, such as `totalAssets`, `isShutdown` etc.

Example

```
require(!TokenizedStrategy.isShutdown(), "strategy is shutdown");
```

### _deployFunds(uint256_amount)

Purpose:

- This function is called during every deposit into your strategy to allow it to deploy the underlying asset deposited into the yield source.

Parameters:

- `_amount`: The total amount of underlying assets currently available for deployment, including the amount deposited and previously idle funds.

Returns: NONE.

Good to Know:

- This function is permissionless, so swaps or LP movements can be sandwiched or manipulated.

- This does not need to deploy the full `_amount` if the strategy doesn't want to.

Best Practice:

- Override `availableDepositLimit` with any needed checks like protocol deposit limits or current status. This will alleviate the need to check any of these things during `_deployFunds` since `availableDepositLimit` is called during every deposit to check for restrictions.

_deployFunds() Example

```
function _deployFunds(uint256 _amount) internal override \{ yieldSource.deposit(address(asset), _amount);}
```

### _freeFunds(uint256_amount)

Purpose:

- This function is called during withdraws from your strategy if there is not sufficient idle asset to service the full withdrawal.

Parameters:

- `_amount`: The amount of the underlying asset that needs to be pulled from the yield source.

Returns: NONE.

Good to Know:

- The amount of loose assets has already been accounted for.

- This function is also entirely permissionless, so swaps or lp values can be sandwiched or otherwise manipulated.

- Users have the ability to specify their own `maxLoss` on withdraws.

Best Practice:

- Use the `_amount` parameter passed in rather than relying on .balanceOf(address(this) since idle has already been accounted for.

- Any difference between the `_amount` parameter and the actual amount withdrawn will count as a loss and be passed on to the withdrawer.

- If your strategy is illiquid or can not always service full withdraws, you can limit the amount by overriding `availableWithdrawLimit` outlined below.

_freeFunds() Example

```
function _freeFunds(uint256_amount) internal override { yieldSource.withdraw(address(asset), _amount);}
```

### _harvestAndReport()

Purpose:

- Called during every report. This should harvest and sell any rewards, reinvest any proceeds, perform any position maintenance and return a full accounting of a trusted amount denominated in the underlying asset the strategy holds.

Parameters: NONE

Returns:

- `_totalAssets`: A trusted and accurate account for the total amount of 'asset' the strategy currently holds including loose funds.

Good to Know:

- This can only be called by a permissioned address so if set up correctly, it can be trusted to perform swaps, LP movements etc.

- This should account for both deployed and idle assets.

Best Practice:

- The returned value is used to account for all strategy profits, losses and fees so care should be taken when relying on oracle values, LP prices etc. that have the potential to be manipulated.

- This can still be called after a strategy has been shut down so you may want to check if the strategy is shut down before performing certain functions like re-deploying loose funds.

_harvestAndReport() Example

```
function _harvestAndReport() internal override returns (uint256 _totalAssets) { // Only harvest and redeploy if the strategy is not shutdown. if(!TokenizedStrategy.isShutdown()) { // Claim all rewards and sell to asset. _claimAndSellRewards(); // Check how much we can re-deploy into the yield source. uint256 toDeploy = Math.min( asset.balanceOf(address(this)), availableDepositLimit(address(this)) ); // If greater than 0. if (toDeploy > 0) { // Deposit the sold amount back into the yield source. _deployFunds(toDeploy); } } // Return full balance no matter what. _totalAssets = yieldSource.balanceOf(address(this)) + asset.balanceOf(address(this));}
```

### Optional Functions

Simply overriding those three functions will make your strategy a fully functional, permissionless, 4626-compliant stand-alone vault. It can work independently or seamlessly into any Yearn V3 vault.

While that may be all that's necessary for some of the most straightforward strategies, most strategists may want to add more customization or complexity to their strategy. There are five more optional functions that can be overridden by a strategist if desired to continue to build out their Tokenized Strategy.

### availableDepositLimit(address _owner)

Purpose:

- This is called during any deposits and can be used to enforce any deposit limit or white list that the strategist desires or that the underlying protocol uses.

Parameters:

- `_owner`: The address receiving the shares minted during the deposit.

Returns:

- The limit if any that should be enforced on the deposit.

Good to Know:

- This will default to return uint256 max.

- This does not need to consider any conversion rates from assets to shares. But you should know that any limit under uint256 max may get converted to shares and should not be high enough to overflow on multiplication.

Best Practices:

- Check all values for the protocol you are integrating with that may cause deposits to revert.

- Make sure to implement setter functions for any deposit limit or whitelist that are enforced.

availableDepositLimit() Example

```
function availableDepositLimit( address _owner) public view override returns (uint256) { if (yieldSource.isPaused()) return 0; uint256 totalAssets = TokenizedStrategy.totalAssets(); return totalAssets >= depositLimit ? 0 : depositLimit - totalAssets;}
```

-

availableWithdrawLimit(address _owner)

Purpose:

- This is called during every withdraw and can be used to enforce any withdraw limit the strategist desires.

Parameters:

- `_owner`: The address that owns the shares that would be burnt for the underlying assets.

Returns:

- The limit if any that should be enforced on withdraws.

Good to Know:

- This does not need to consider the balance of the _owner.

- This can be more than the actual amount available to withdraw.

- Recommended use is to have the amount returned not be close to the actual strategies totalAssets to avoid rounding issues.

- Defaults to max uint256.

Best Practices:

- This should be overridden for strategies that have illiquid, or sandwichable positions to prevent reporting incorrect losses on withdraws.

- This should also account for any restrictions the underlying protocol may encounter.

- To just allow the idle funds to be withdrawn use `asset.balanceOf(address(this))`.

- This does not need to consider conversion rates from assets to shares. But you should know that any limit under uint256 max may get converted to shares and should not be high enough to overflow on multiplication.

availableWithdrawLimit() Example

```
function availableWithdrawLimit( address _owner) public view override returns (uint256) { if(positionIsLocked || yieldSource.isPaused()) { return asset.balanceOf(address(this)); } // Return both the loose balance and the current liqudity of the yield source. return asset.balanceOf(address(this)) + asset.balanceOf(address(yieldSource));}
```

-

_tend(uint256 _totalIdle)

Purpose:

- This would get called during a `tend` call and can be used if a strategy needs to perform any maintenance or other actions that don't require a full report. If used the strategy should also implement a `_tendTrigger` that keepers can monitor to know when it should be called.

Parameters:

- `_totalIdle`: The amount of asset currently loose in the strategy.

Returns: NONE

Good to Know:

- The strategies `totalAssets` will be the exact before and after a tend as not to have any effect on PPS.

Best Practices:

- This can only be called by the keeper or management so it should be from a trusted source.

- Can be used to perform LTV adjustments on leveraged strategies.

- Can be used to know a trusted relay has been used to deposit idle funds for a strategy that doesn't deploy funds during deposits.

Example:

_tend() Example

```
function _tend(uint256 _totalIdle) internal override { if (currentLTV() warningLTV()) { _leverDown(_totalIdle); }}
```

-

_tendTrigger()

Purpose:

- Should return whether or not a keeper should call `tend` on the strategy. This should be implemented if tend is needed to be used.

Parameters: NONE.

Returns:

- Boolean representing if a keeper should call `tend`.

Good to Know:

- Default return value is false.

Best Practices:

- Can implement checks on the current base fee of the chain to ensure the gas cost isn't too high.

Example:

_tendTrigger() Example

```
function _tendTrigger() public view override returns (bool) { if (currentLTV() > warningLTV()) { return true; } else if (currentLTV() _emergencyWithdraw(uint256 _amount)
Purpose:

- Allows management to manually pull funds from the yield source once a strategy has been shut down.

Parameters:

- `_amount`: The specific amount to pull from the yield source

Returns: NONE.

Good to Know:

- This can only be called after a strategy is shut down.

- The `_amount` can be more than is available to pull.

- The totalAssets will be the same before and after this call.

Best Practices:

- Keep the withdrawal logic as simple as possible.

- Check `_amount` against the available amount to withdraw.

Example:

_emergencyWithdraw() Example

```
function _emergencyWithdraw(uint256 _amount) internal override { _amount = min(_amount, yieldSource.balanceOf(address(this))); _freeFunds(_amount);}
```

All other functionality, such as reward selling, upgradability, etc., is up to the strategist to determine what best fits their vision. Due to the ability of strategies to stand alone from a Vault, it is expected and encouraged for strategists to experiment with more complex, risky, or previously unfeasible Strategies.

### FYI

The Tokenized Strategy contract manually track totalAssets. Meaning the only way to update the totalAssets for either profits or losses is through a `report` call.

NOTE: Writing to a strategy's default global storage state internally post-deployment is impossible. You must make external calls from the `management` address to configure any desired variables.

To include extra permissioned functions such as setters, there are modifiers for `onlyManagement`, `onlyKeepers` and `onlyEmergencyAuthorized` available by default.

The symbol used for each tokenized Strategy is set automatically with a standardized approach based on the `asset`'s symbol. Strategists should use the `name` parameter in the constructor for a unique and descriptive name that encapsulates their specific Strategy.

## Periphery

To make Strategy writing as simple as possible, a suite of optional 'Periphery' helper contracts can be inherited by your Strategy to provide standardized and tested functionality for things like swaps. A complete list of the periphery contracts can be viewed here (https://github.com/yearn/tokenized-strategy-periphery/tree/master/src)

*All periphery contracts are optional; strategists can choose if they wish to use them.

### Swappers

To make reward swapping as easy and standardized as possible, multiple swapper contracts can be inherited by a strategy to inherit pre-built and tested logic for whichever method of reward swapping is desired. This allows a strategist only to need to set a few global variables and then simply use the default syntax of `_swapFrom(tokenFrom, tokenTo, amountIn, minAmountOut)` to swap any tokens easily during `_harvestAndReport`.

### APR Oracles

For easy integration with Vaults, frontends, debt allocators, etc. There is the option to create an APR oracle (https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/AprOracle/AprOracleBase.sol) contract for your specific strategy that should return the expected APR of the Strategy based on some given `debtChange`.

### HealthCheck

To prevent automated reports from reporting losses/excessive profits that may not be accurate, a strategist can inherit and implement the HealthCheck (https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/Bases/HealthCheck/BaseHealthCheck.sol) contract. This can ensure that a keeper will not call a report that may incorrectly realize incorrect losses or excessive gains. It can cause the report to revert if the gain/loss is outside of the desired bounds and will require manual intervention to ensure the strategy is reporting correctly.

NOTE: It is recommended to implement some checks in `_harvestAndReport` for leveraged or manipulatable strategies that could report incorrect losses due to unforeseen circumstances.

### Report Triggers

The expected behavior is that strategies report profits/losses on a schedule based on their specific `profitMaxUnlockTime` that management can customize. If a custom trigger cycle is desired or extra checks should be added a strategist can create their own customReportTrigger (https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/ReportTrigger/CustomStrategyTriggerBase.sol) that can be added to the default contract for a specific strategy.

*More information can be found below in the "Reporting" section.

## Testing

Due to the nature of the BaseStrategy utilizing an external contract for most of its logic, the default interface for any strategy will not allow proper testing of all functions. Testing of your Strategy should utilize the pre-built IStrategyInterface (https://github.com/yearn/tokenized-strategy-foundry-mix/blob/master/src/interfaces/IStrategyInterface.sol) to cast any deployed strategy through for testing, as seen in the testing setups in each mix. You can add any external functions you add for your specific strategy to this interface to test all functions with one variable.

Foundry Example

```
Strategy _strategy = new Strategy(asset, name);IStrategyInterface strategy = IStrategyInterface(address(_strategy));
```

Ape Example

```
strategy = management.deploy(project.Strategy, asset, name)strategy = project.IStrategyInterface.at(strategy.address)
```

Due to the permissionless nature of the Tokenized Strategies, all tests are written without integration with any allocator vault funding it. While those tests can be added, all V3 vaults utilize the ERC-4626 standard for deposit/withdraw and accounting, so they can be plugged in easily to any number of different vaults with the same `asset.`

## Deployment

Building a factory that can be deployed once is recommended for strategies that will be used with multiple different assets. Then, all strategies can be deployed on the chain using the factory.

Cloning is not recommended for Tokenized Strategies.

### Contract Verification

Once the Strategy is deployed and verified, you must also verify the TokenizedStrategy functions. To do this, navigate to the /#code page on Etherscan.

- Click on the `More Options` drop-down menu.

- Click "is this a proxy?".

- Click the "Verify" button.

- Click "Save".

This should add all of the external `TokenizedStrategy` functions to the contract interface on Etherscan.

## Operating Your strategy

Once deployed your strategy should be able to be interacted with as any other ERC-4626 vault.

In addition to the normal 4626 interface, Tokenized Strategies come built-in with some simple functions for management to properly maintain the strategy.

### Reporting

The main operational procedure strategists need to take care of is the reporting of a strategy. Calling `report` on a strategy must be done by either the 'management' or 'keeper' address.

Reporting causes the strategy to accrue rewards, and record any gains or losses, as well as charge and pay fees. It is needed for the depositors of a vault to earn yield and for the strategist to earn fees.

It is recommended to build strategies on the assumption that reports will happen based on the strategies specific `profitMaxUnlockTime`.

Since reports are the only time _harvestAndReport will be called any strategies that need more frequent checks or updates should override the_tend and tendTrigger functions for any needed mid-report maintenance.

### Keepers

The easiest way to ensure regular reports and tends on your strategy is to hook it up with a 3rd party keeper.

There are 2 keeper networks that integrate well with Yearn Vaults:

- TKS (The Keeper Service) is Yearn's in-house automation solution for vaults and strategies.

- Gelato Network (https://www.gelato.network/) is a large 3rd party automation solution for different EVM networks.

### Setters

The strategy comes with some default variables that the management of a strategy can set and update.

- Changing management: Changing the strategies management is a two-step process. First, the current management must call `setPendingManagement(address)` with the desired address to transfer the management to. Then, that address must call `acceptManagement()` for the change to go into effect.

- Keeper. A strategy manager can set a new address to be the keeper at any time with `setKeeper(address)`.

- Emergency Admin. This will default to address(0) and can be set by the management with `setEmergencyAdmin(address)`.

- Performance Fee. Management can adjust the amount of the gain realized during a report that gets charged as a performance fee with `setPerformanceFee(uint16)`.
**Subject to min and max.

- Performance Fee Recipient. Set the address to receive the performance fees charged during a report with `setPerformanceFeeRecipient(address)`.

- Profit Unlocking Period. Profits recorded during reports are slowly unlocked to depositors of a strategy over the strategy-specific 'profitMaxUnlockTime'. This defaults to 10 days and can be changed at any time by the strategist with `setProfitMaxUnlockTime(uint256)`.

### Emergencies

There are two default emergency functions built in. The first of which is `shutdownStrategy()`. This can only ever be called by the management or emergencyAdmin and is non-reversible.

Once this is called it will stop any further deposits or mints but will not affect any other functionality including withdraw, redeem, report and tend. This allows management to continue recording profits or losses and users to withdraw even post-shutdown.

This can be used in an emergency or simply to retire a vault.

Once a strategy is shut down management or the emergencyAdmin can also call `emergencyWithdraw(_amount)`, which will tell the strategy to withdraw a specified `_amount` from the yield source and keep it idle in the vault.

All other emergency functionality is left up to the individual strategist.


Protocol Fees

Protocol Fees

# Protocol Fees

V3 introduces a protocol fee that is applied by the vault on each strategy
`report()`. This fee is a percentage of the total fees returned by the
Accountant (management/performance fees), not a direct percentage of profit.

The protocol fee is configured in the VaultFactory (default + optional per‑vault
custom overrides). Governance controls the allowed values, which can be set anywhere
from 0% to 50%. The protocol fee recipient is stored in the VaultFactory and is the
default recipient even when a custom protocol fee is set for a specific vault.

Example

```
profit = 100performance_fee = 20%protocol_fee = 10%total_fees = profit * performance_fee = 20protocol_fees = total_fees * protocol_fee = 2performance_fees = total_fees - protocol_fees = 1818 would get paid to the vault managers performance_fee_recipient.2 would get paid to the Yearn Treasury.
```

You can retrieve both the default protocol fee and a vault‑specific override using
the VaultFactory that corresponds to that vault’s API.

Examples

```
# Retrieve the default config.vaultFactory.protocol_fee_config()# Check a specific vault current config to be usedvaultFactory.protocol_fee_config(vault_address)# Check whether a custom override is active for a vaultvaultFactory.use_custom_protocol_fee(vault_address)
```


Periphery

Periphery

Vault Periphery

Release Registry

Registry

Accountant

Debt Allocator

Role Manager

# Periphery

Yearn V3 is built to be modular and customizable by anyone wishing to run their own vault. In order to do this the core code has been left as un-opinionated as possible while allowing it to be customized through the use of optional "Periphery" contracts or "modules".

This is a non-exhaustive list of the current periphery contracts developed or deployed in order to assist those wishing to deploy/manage their own V3 vaults.

For the most updated contracts visit:

- Vault Periphery Repo: https://github.com/yearn/vault-periphery

- TokenizedStrategy Periphery: https://github.com/yearn/tokenized-strategy-periphery

The deployed address of most periphery contracts or their corresponding factories can be found on chain from the Protocol Address provider: `0x775F09d6f3c8D2182DFA8bce8628acf51105653c`

The Yearn-specific periphery contracts can be retrieved from the relevant chain's Role Manager (https://docs.yearn.fi/developers/smart-contracts/V3/Periphery/RoleManager)

## Vault Periphery

The contracts in the 'Vault Periphery' are meant to be used alongside a V3 multi strategy vault in order to help add additional functionality.

### Release Registry

https://github.com/yearn/vault-periphery/blob/master/contracts/registry/ReleaseRegistry.sol

Yearn controlled registry to track any new versions of V3 released on that specific chain.

Each time a new Version of the Vault Factory (https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultFactory.vy) is deployed it will get added to the Release Registry.

### Registry

https://github.com/yearn/vault-periphery/blob/master/contracts/registry/Registry.sol

Stores the endorsed multi strategy and single strategy vaults. Can also deploy new multi strategy vaults based on the most recent Vault Factory added to the Release Registry.

- `newEndorsedVault(...)` Deploy and endorse a new multi strategy vault.

Deploy a custom Registry using the RegistryFactory (https://docs.yearn.fi/developers/smart-contracts/V3/Periphery/RegistryFactory)

### Accountant

https://github.com/yearn/vault-periphery/tree/master/contracts/accountants

By default V3 multi strategy vaults have fees set to 0 and will need an `accountant` set to charge fees.

If set an accountant is called during each process_report (https://github.com/yearn/yearn-vaults-v3/blob/9fbc614bbce9d7cbad42e284a15f0f43cf1a673f/contracts/VaultV3.vy#L1202) with the relevant information for the strategies report. The accountant can hold any logic desired to charge performance fees, management fees, issue refunds, perform healthchecks etc.

Some possible non-standard uses of an accountant could be:

- Auto compounding rewards back into the vault

- Setting up a Junior Tranche

- Tiered fees based on % returns or TVL

To deploy a generic account use the Accountant Factory (https://docs.yearn.fi/developers/smart-contracts/V3/Periphery/AccountantFactory) and then call set_accountant (https://github.com/yearn/yearn-vaults-v3/blob/9fbc614bbce9d7cbad42e284a15f0f43cf1a673f/contracts/VaultV3.vy#L1342) on the vault.

### Debt Allocator

https://github.com/yearn/vault-periphery/tree/master/contracts/debtAllocators

To manager the allocation of debt between multiple strategies in a multi strategy vault some generic Debt Allocators have been developed. These contracts are meant to be given the `DEBT_MANAGER` and `REPORTING_MANAGER` roles for a specific vault and then monitored by a keeper to manage the allocations based on set 'target ratios'.

The owner of the Debt allocator can set multiple parameters that will dictate when a keeper should call the `update_debt` function on the allocator based on the return value of the `shouldUpdateDebt` view function.

- `targetDebtRatio` A percent (in basis points) for the allocator to target a specific strategy to have. EX: 5_000 == 50% of the vaults funds.

- `maxDebtRatio` The max percent (in basis points) for the allocator to allow a strategy to have.

- `minimumChange` The minimum amount in terms of the underlying asset to be moved to trigger a debt update.

- `maxAcceptableBaseFee` The maximum the block.basefee is allowed to be during debt updates to save gas.

- `maxDebtUpdateLoss` The value to send as maxLoss (https://docs.yearn.fi/developers/v3/Integrating_v3#maxloss) for a debt update. Default is 1 (0.01%).

- `keeper` Allow an address to call the `update_debt` function.

- `manager` Non-governance address that is allowed to update the strategies target and max debt ratios.

You can deploy a single generic Debt Allocator using the Debt Allocator Factory (https://docs.yearn.fi/developers/addresses/v3-contracts#protocol-addresses) for any V3 vault.

### Role Manager

https://github.com/yearn/vault-periphery/blob/master/contracts/Managers/RoleManager.sol

The Role Manager is used to hold the `role_manager` position in Yearns multi strategy vaults and make deployments simpler. All role configuration and periphery contracts are set up during the vaults deployment.

Yearn specific periphery contracts can also all be retrieved on chain from the Role Manager on that chain.

For Yearn specific implementation addresses check Contract Addresses (https://docs.yearn.fi/developers/addresses/)


yVaults v3

yVaults v3

Definitions

Periphery Contracts

Get started

Additional Links

# yVaults v3

Yearn's V3 system is a decentralized suite of yield-generating products built to fit any need. It is designed to be un-opinionated and customizable infrastructure for the world to build on, making yield generation as safe, efficient, and easy as possible for all parties. Anyone can deploy a strategy or manage a vault. So whether you are a gas golfing expert, a degen looking to codify your personal yield farming strategy, or just an average crypto user looking to earn passive yield on your magical internet tokens, V3 is for you.

V3 is a drastically more modular design than V2. Meaning that the core vaults will serve as generic contracts that handle the base vault functionality. Then there are many optional "periphery" contracts such as Accountants (https://docs.yearn.fi/developers/v3/periphery#accountant) that charge fees, or Debt Allocators (https://docs.yearn.fi/developers/v3/periphery#debt-allocator) that manage debt allocations that can be added on or customized for complete freedom and customization of the vaults functionality.

The most significant update to Yearn V3 from V2 was the introduction of "Tokenized Strategies". In V2, strategies are stand-alone contracts that are attached to one specific vault. Only that vault can deposit or withdraw funds from the strategy and there is a trusted relationship between them. In V3, strategies are now fully ERC-4626 compliant, stand-alone vaults. Though their job remains the same (generate yield from one external source), strategies can now be connected to many different vaults simultaneously and can also be deposited into directly by an end user.

## Definitions

-

Vault (https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultV3.vy): A vault or "Allocator Vault" in V3 refers to an ERC-4626 compliant contract that takes in user deposits, mints shares corresponding to the user's share of the underlying assets held in that vault, and then allocates the underlying asset to an array of different "strategies" that earn yield on that asset.

-

Strategy: A strategy in V3 refers to a yield-generating contract added to a vault that has the needed ERC-4626 interface (https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultV3.vy#L40). The strategy takes the underlying asset and deploys it to a single source, generating yield on that asset.

-

TokenizedStrategy (https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol) A technical implementation of a Strategy that is also a stand-alone ERC-4626 compliant Vault. These are the yield generators in the V3 ecosystem. This pattern can be used so that either Allocator Vaults or individual users can deposit directly into and receive shares in return.

-

Vault Factory (https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultFactory.vy): A factory contract deployed by Yearn Governance that anyone can use to easily and trustlessly deploy new Allocator Vaults. Each Allocator Vault release will have its own factory.

![image](https://docs.yearn.fi/assets/images/yvaults-v3-more-detail-fe81f3237d78cfa8da477bb310d65da2.png)

## Periphery Contracts

V3 incorporates periphery contracts, which are extensible code blocks that can be attached to a yVault or work alongside it to extend functionality over and beyond core base logic. They are not required but can facilitate building around yVaults.

A few examples of periphery contracts used in V3 are:

- 4626 Router: Wrapper that handles deposits and withdrawals to/from all vaults and strategies.

- Registry: Handles adding and tracking strategies and vaults.

- Debt Allocator: Can efficiently allocate debt to different strategies. Added to an Allocator Vault for the best yield opportunities.

- Accountant: Handles changing fees for vault operations.

- Deposit/Withdraw Limit Modules: Allows dynamic control over a vaults deposit or withdraw limits for full customization.

- Swappers: Pre-built contracts for strategies to inherit to easily implement their desired swap logic.

- APR Oracles: Retrieve the expected current APY on-chain for different vaults or strategies to properly allocate debt.

- And any others you can come up with!

To read more about the periphery contracts or where to find the current versions click here (https://docs.yearn.fi/developers/v3/periphery)

## Get started

- Integrating V3 (https://docs.yearn.fi/developers/v3/Integrating_v3)

- Building your own V3 Strategy (https://docs.yearn.fi/developers/v3/strategy_writing_guide)

- Deploying and managing a V3 Vault (https://docs.yearn.fi/developers/v3/vault_management)

- Periphery Contracts (https://docs.yearn.fi/developers/v3/periphery)

- Protocol Fees (https://docs.yearn.fi/developers/v3/protocol_fees)

To find deployed contracts see Contract Addresses (https://docs.yearn.fi/developers/addresses/v3-contracts)

If a contract has not been deployed on a specific chain it can be done permissionlessly using the scripts in the relevant GitHub repo. Or reach out to a Yearn contributor for help.

## Additional Links

yVaults v3 GitHub Repo (https://github.com/yearn/yearn-vaults-v3)

VaultV3 Specification (https://github.com/yearn/yearn-vaults-v3/blob/master/TECH_SPEC.md)

Tokenized Strategy GitHub Repo (https://github.com/yearn/tokenized-strategy)

Tokenized Strategy Specification (https://github.com/yearn/tokenized-strategy/blob/master/SPECIFICATION.md)

V3 Design Article (https://medium.com/iearn/yearnv3-motivation-and-design-107840cb4844)

ERC4626 Info (https://erc4626.info/)

ERC4626 EIP (https://eips.ethereum.org/EIPS/eip-4626)