---
## /integrate/curators/deploy-vault
---
description: "This guide explains how to deploy a Symbiotic V2 vault using the DeployVaultV2 script."
---
import { Tabs, TabItem } from "../../../components/Tabs";
# Deploy Vault V2
This guide explains how to deploy a Symbiotic V2 vault using the `DeployVaultV2` script.
Vault V2 is an ERC-20 tokenized vault where shares are represented by an ERC-20 token. The vault stores a single asset, manages deposits and withdrawals, and uses a Universal Delegator to allocate assets across supported adapters.
## Deployment overview
To deploy a Vault V2, configure and run:
```bash
script/DeployVaultV2.s.sol
```
The script deploys:
- a Vault V2 contract
- an ERC-20 vault share token
- a Universal Delegator linked to the vault
- optional deposit limits
- optional depositor whitelisting
- role holders for vault administration, fee management, deposit controls, allocation, deallocation, and adapter management
The deployment flow uses the Vault Factory from Symbiotic core constants:
```solidity
SymbioticCoreConstants.core().vaultFactory.create(
VAULT_V2_VERSION,
owner,
abi.encode(vaultParams)
);
```
After deployment, the script reads the deployed vault's Universal Delegator via:
```solidity
address delegator = IVaultV2(vault).delegator();
```
## 1. Clone the core repository
```bash
git clone --recurse-submodules https://github.com/symbioticfi/core.git
cd core
git checkout delegator-simplify
```
## 2. Configure the deployment script
Open:
```bash
script/DeployVaultV2.s.sol
```
Update the required fields before deployment:
```solidity
// Name of the ERC20 representing shares in the vault
string NAME = "SymVault";
// Symbol of the ERC20 representing shares in the vault
string SYMBOL = "SV";
// Address of the owner of the vault who can migrate the vault to new versions whitelisted by Symbiotic
address OWNER = 0x0000000000000000000000000000000000000000;
// Address of the vault asset token
address ASSET = 0x0000000000000000000000000000000000000000;
```
| Parameter | Description |
| --------- | -------------------------------------------------------------------------------------------------------------- |
| `NAME` | Name of the ERC-20 token representing vault shares. |
| `SYMBOL` | Symbol of the ERC-20 token representing vault shares. |
| `OWNER` | Owner of the vault. In the default script, this address also receives all vault and Universal Delegator roles. |
| `ASSET` | ERC-20 asset deposited into the vault. |
## 3. Optional configuration
The script also supports deposit limits and depositor whitelisting.
```solidity
// Deposit limit (maximum amount of assets allowed in the vault)
uint256 DEPOSIT_LIMIT = 0;
// Whether deposits are restricted to whitelisted depositors
bool DEPOSIT_WHITELIST = false;
// Initial whitelisted depositor (used only when DEPOSIT_WHITELIST is true)
address DEPOSITOR_TO_WHITELIST = 0x0000000000000000000000000000000000000000;
```
| Parameter | Description |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| `DEPOSIT_LIMIT` | Maximum amount of assets allowed in the vault. If set to `0`, deposit limits are disabled. |
| `DEPOSIT_WHITELIST` | Whether deposits are restricted to whitelisted depositors. |
| `DEPOSITOR_TO_WHITELIST` | Initial depositor to whitelist. Used only when `DEPOSIT_WHITELIST` is `true`. |
The script enables the deposit limit automatically when `DEPOSIT_LIMIT != 0`:
```solidity
isDepositLimit: DEPOSIT_LIMIT != 0
```
## 4. Vault V2 roles
The default script assigns all Vault V2 roles to `OWNER`.
```solidity
defaultAdminRoleHolder: OWNER,
managementFeeRoleHolder: OWNER,
performanceFeeRoleHolder: OWNER,
depositLimitSetRoleHolder: OWNER,
depositorWhitelistRoleHolder: OWNER,
isDepositLimitSetRoleHolder: OWNER,
depositWhitelistSetRoleHolder: OWNER,
```
| Role holder | Description |
| ------------------------------- | ------------------------------------------------------------ |
| `defaultAdminRoleHolder` | Address with admin permissions over vault roles. |
| `managementFeeRoleHolder` | Address allowed to manage the vault management fee. |
| `performanceFeeRoleHolder` | Address allowed to manage the vault performance fee. |
| `depositLimitSetRoleHolder` | Address allowed to set the deposit limit. |
| `depositorWhitelistRoleHolder` | Address allowed to whitelist depositors. |
| `isDepositLimitSetRoleHolder` | Address allowed to enable or disable deposit limits. |
| `depositWhitelistSetRoleHolder` | Address allowed to enable or disable depositor whitelisting. |
:::note
The default script assigns all roles to `OWNER`. For production deployments, consider whether these roles should be assigned to a multisig, automation contract, or separate operational addresses.
:::
## 5. Universal Delegator
Vault V2 deploys with a Universal Delegator. The Universal Delegator is encoded in the vault initialization params through `delegatorParams`.
```solidity
delegatorParams: abi.encode(
IUniversalDelegator.InitParams({
allocateRoleHolder: OWNER,
deallocateRoleHolder: OWNER,
forceDeallocateRoleHolder: OWNER,
addAdapterRoleHolder: OWNER,
swapAdaptersRoleHolder: OWNER,
defaultAdminRoleHolder: OWNER,
removeAdapterRoleHolder: OWNER,
setAdapterLimitsRoleHolder: OWNER,
setAutoAllocateAdaptersRoleHolder: OWNER
})
)
```
The deployment base validates that the vault and delegator are correctly linked:
```solidity
assert(IVaultV2(vault).delegator() == delegator);
assert(IUniversalDelegator(delegator).vault() == vault);
```
| Role holder | Description |
| ----------------------------------- | -------------------------------------------------------------------- |
| `allocateRoleHolder` | Address allowed to allocate vault assets through supported adapters. |
| `deallocateRoleHolder` | Address allowed to deallocate assets from adapters. |
| `forceDeallocateRoleHolder` | Address allowed to force deallocation from adapters. |
| `addAdapterRoleHolder` | Address allowed to add new adapters. |
| `removeAdapterRoleHolder` | Address allowed to remove adapters. |
| `swapAdaptersRoleHolder` | Address allowed to swap or reorder adapters. |
| `setAdapterLimitsRoleHolder` | Address allowed to set adapter limits. |
| `setAutoAllocateAdaptersRoleHolder` | Address allowed to configure auto-allocation adapters. |
| `defaultAdminRoleHolder` | Address with admin permissions over Universal Delegator roles. |
## 6. Deploy the vault
Run the deployment script with Foundry:
```bash
forge script script/DeployVaultV2.s.sol:DeployVaultV2Script \
--rpc-url=RPC \
--account=ACCOUNT \
--sender=SENDER \
--broadcast
```
Replace:
| Placeholder | Description |
| ----------- | ------------------------------------ |
| `RPC` | RPC endpoint for the target network. |
| `ACCOUNT` | Foundry account used for signing. |
| `SENDER` | Sender address used for deployment. |
Example:
```bash
forge script script/DeployVaultV2.s.sol:DeployVaultV2Script \
--rpc-url=https://ethereum-rpc.publicnode.com \
--account=deployer \
--sender=0x0000000000000000000000000000000000000000 \
--broadcast
```
:::note
This is an example command. Replace the RPC URL, account, sender, owner, and asset values with your own deployment configuration.
:::
## 7. Deployment output
After deployment, the script logs the deployed Vault V2 and Universal Delegator addresses:
```solidity
Logs.log(
string.concat(
"Deployed VaultV2",
"\n vault:",
vm.toString(vault_),
"\n delegator:",
vm.toString(delegator_)
)
);
```
## 8. Complete deployment script
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import "./base/DeployVaultV2Base.sol";
// forge script script/DeployVaultV2.s.sol:DeployVaultV2Script --rpc-url=RPC --account=ACCOUNT --sender=SENDER --broadcast
contract DeployVaultV2Script is DeployVaultV2Base {
// Configurations - UPDATE THESE BEFORE DEPLOYMENT
// Name of the ERC20 representing shares in the vault
string NAME = "SymVault";
// Symbol of the ERC20 representing shares in the vault
string SYMBOL = "SV";
// Address of the owner of the vault who can migrate the vault to new versions whitelisted by Symbiotic
address OWNER = 0x0000000000000000000000000000000000000000;
// Address of the vault asset token
address ASSET = 0x0000000000000000000000000000000000000000;
// Optional
// Deposit limit (maximum amount of assets allowed in the vault)
uint256 DEPOSIT_LIMIT = 0;
// Whether deposits are restricted to whitelisted depositors
bool DEPOSIT_WHITELIST = false;
// Initial whitelisted depositor (used only when DEPOSIT_WHITELIST is true)
address DEPOSITOR_TO_WHITELIST = 0x0000000000000000000000000000000000000000;
function run() public {
runBase(
DeployVaultV2Params({
owner: OWNER,
vaultParams: VaultV2Params({
baseParams: IVaultV2.InitParams({
name: NAME,
symbol: SYMBOL,
asset: ASSET,
depositWhitelist: DEPOSIT_WHITELIST,
depositorToWhitelist: DEPOSITOR_TO_WHITELIST,
depositLimit: DEPOSIT_LIMIT,
isDepositLimit: DEPOSIT_LIMIT != 0,
defaultAdminRoleHolder: OWNER,
managementFeeRoleHolder: OWNER,
performanceFeeRoleHolder: OWNER,
depositLimitSetRoleHolder: OWNER,
depositorWhitelistRoleHolder: OWNER,
isDepositLimitSetRoleHolder: OWNER,
depositWhitelistSetRoleHolder: OWNER,
delegatorParams: abi.encode(
IUniversalDelegator.InitParams({
allocateRoleHolder: OWNER,
deallocateRoleHolder: OWNER,
forceDeallocateRoleHolder: OWNER,
addAdapterRoleHolder: OWNER,
swapAdaptersRoleHolder: OWNER,
defaultAdminRoleHolder: OWNER,
removeAdapterRoleHolder: OWNER,
setAdapterLimitsRoleHolder: OWNER,
setAutoAllocateAdaptersRoleHolder: OWNER
})
)
})
})
})
);
}
}
```
## 9. Complete base script
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {Script} from "forge-std/Script.sol";
import {IUniversalDelegator} from "../../src/interfaces/delegator/IUniversalDelegator.sol";
import {IVaultV2, VAULT_V2_VERSION} from "../../src/interfaces/vault/IVaultV2.sol";
import {Logs} from "../utils/Logs.sol";
import {SymbioticCoreConstants} from "../../test/integration/SymbioticCoreConstants.sol";
contract DeployVaultV2Base is Script {
struct VaultV2Params {
IVaultV2.InitParams baseParams;
}
struct DeployVaultV2Params {
address owner;
VaultV2Params vaultParams;
}
function runBase(DeployVaultV2Params memory params) public returns (address, address) {
vm.startBroadcast();
address vault_ = address(
SymbioticCoreConstants.core().vaultFactory
.create(_getVaultVersion(), params.owner, _getVaultParamsEncoded(params))
);
address delegator_ = IVaultV2(vault_).delegator();
Logs.log(
string.concat(
"Deployed VaultV2", "\n vault:", vm.toString(vault_), "\n delegator:", vm.toString(delegator_)
)
);
_validateDeployment(vault_, delegator_);
vm.stopBroadcast();
return (vault_, delegator_);
}
function _getVaultVersion() internal virtual returns (uint64) {
return VAULT_V2_VERSION;
}
function _getVaultParamsEncoded(DeployVaultV2Params memory params) internal pure virtual returns (bytes memory) {
return abi.encode(params.vaultParams.baseParams);
}
function _validateDeployment(address vault, address delegator) internal view {
assert(IVaultV2(vault).delegator() == delegator);
assert(IUniversalDelegator(delegator).vault() == vault);
}
}
```
## Next steps
After deployment, the vault owner can configure the vault by:
- setting or updating deposit limits
- enabling or disabling depositor whitelisting
- whitelisting depositors
- adding adapters
- removing adapters
- swapping adapters
- configuring adapter limits
- configuring auto-allocation adapters
- allocating and deallocating assets through the Universal Delegator
:::warning
Before using the vault in production, review the role configuration carefully. The default script assigns all permissions to `OWNER`, which may be appropriate for testing but should be assessed for production deployments.
:::
---
## /integrate/curators/helpful-core-contracts-endpoints
---
description: "This page lists useful functions for curators across Symbiotic Core contracts."
---
# Helpful Core Contracts' Endpoints
This page lists useful functions for curators across Symbiotic Core contracts.
:::note
The delegator setter methods below (`setNetworkLimit()`, `setOperatorNetworkShares()`, …) apply to Vault V1 and older delegator-based vaults. For **Vault V2**, allocation is performed through the Universal Delegator — see [Manage Allocations](/integrate/curators/manage-allocations).
:::
| Function | Use-case |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| [`create(InitParams params) -> address, address, address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/IVaultConfigurator.sol#L52) | Create a new Vault |
| [`Vault.delegator() → address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/vault/IVaultStorage.sol#L60) | Get the Vault's delegator |
| [`Vault.slasher() → address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/vault/IVaultStorage.sol#L72) | Get the Vault's slasher |
| [`BaseDelegator.TYPE() → uint64`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/common/IEntity.sol#L17) | Get the delegator's type (0 - NetworkRestake, 1 - FullRestake, etc.) |
| [`BaseDelegator.stake(bytes32 subnetwork, address operator) → uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IBaseDelegator.sol#L150) | Get the operator-network's stake |
| [`NetworkRestakeDelegator.setNetworkLimit(bytes32 subnetwork, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L136) | Set an amount of collateral to allocate to the network |
| [`NetworkRestakeDelegator.networkLimit(bytes32 subnetwork) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L84) | Check the network's allocation |
| [`NetworkRestakeDelegator.setOperatorNetworkShares(bytes32 subnetwork, address operator, uint256 shares) `](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L147) | Set the operator's share from the network's allocation |
| [`NetworkRestakeDelegator.operatorNetworkShares(bytes32 subnetwork, address operator) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L128) | Check the operator-network's shares |
| [`FullRestakeDelegator.setNetworkLimit(bytes32 subnetwork, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L112) | Set an amount of collateral to allocate to the network |
| [`FullRestakeDelegator.networkLimit(bytes32 subnetwork) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L81) | Check the network's allocation |
| [`FullRestakeDelegator.setOperatorNetworkLimit(bytes32 subnetwork, address operator, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L122) | Set the operator's limit over the network's allocation |
| [`FullRestakeDelegator.operatorNetworkLimit(bytes32 subnetwork, address operator) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L104) | Check the operator-network's limit |
| [`OperatorSpecificDelegator.setNetworkLimit(bytes32 subnetwork, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorSpecificDelegator.sol#L85) | Set an amount of collateral to allocate to the network |
| [`OperatorSpecificDelegator.networkLimit(bytes32 subnetwork) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorSpecificDelegator.sol#L77) | Check the network's allocation |
| [`OperatorSpecificDelegator.operator() -> address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorSpecificDelegator.sol#L60) | Check the operator who receive all the allocations |
| [`OperatorNetworkSpecificDelegator.network() -> address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorNetworkSpecificDelegator.sol#L44) | Check the network who receive all the allocations |
| [`OperatorNetworkSpecificDelegator.operator() -> address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorNetworkSpecificDelegator.sol#L50) | Check the operator who receive all the allocations |
| [`BaseSlasher.TYPE() → uint64`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/common/IEntity.sol#L17) | Get the slasher's type (0 - Slasher, 1 - VetoSlasher) |
---
## /integrate/curators
---
description: "This guide walks you through the curator lifecycle in Symbiotic. You'll deploy a vault, manage allocations, and earn fees from managing depositors' funds."
---
import { Card1 } from "../../../components/Card1";
# Get Started
This guide walks you through the curator lifecycle in Symbiotic. You'll deploy a vault, manage allocations, and earn fees from managing depositors' funds.
:::steps
## Deploy Vault
Deploy a vault that matches your curation needs.
}
href="/integrate/curators/deploy-vault"
/>
## Configure Curator & Operator Fees
Register the curator in `CuratorRegistry` and configure curator and operator fees.
}
href="/integrate/curators/registry-and-fees"
/>
## Submit Metadata
Make your curator and vault visible on the Symbiotic UI.
}
href="/integrate/curators/submit-metadata"
/>
## Manage Allocations
Configure how your vault allocates stake to networks and operators.
:::
---
## /integrate/curators/manage-adapters
---
description: "Learn how to add adapters to a Vault V2 Universal Delegator."
---
# Adapter Management
Before capital can be allocated, the desired adapter must first be added to the vault's Universal Delegator.
Each Vault V2 has its own Universal Delegator responsible for managing the set of available adapters. Once added, adapters can be configured, allocated to, and removed by accounts with the appropriate permissions.
## Add an Adapter
The helper script calls the Universal Delegator's `addAdapter()` function.
```solidity title="AddAdapterBase.s.sol"
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IVaultV2} from "../../../../src/interfaces/vault/IVaultV2.sol";
import {IUniversalDelegator} from "../../../../src/interfaces/delegator/IUniversalDelegator.sol";
import {Logs} from "../../../utils/Logs.sol";
import {ScriptBase} from "../../../utils/ScriptBase.s.sol";
contract AddAdapterBaseScript is ScriptBase {
function runBase(address vault, address adapter) public virtual returns (bytes memory data, address target) {
target = IVaultV2(vault).delegator();
data = abi.encodeCall(IUniversalDelegator.addAdapter, (adapter));
sendTransaction(target, data);
Logs.log(
string.concat("Add adapter", "\n vault:", vm.toString(vault), "\n adapter:", vm.toString(adapter))
);
Logs.logSimulationLink(target, data);
}
}
```
The deployment script specifies the vault and adapter addresses:
```solidity title="AddAdapter.s.sol"
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./base/AddAdapterBase.s.sol";
contract AddAdapterScript is AddAdapterBaseScript {
address constant VAULT = 0x0000000000000000000000000000000000000000;
address constant ADAPTER = 0x0000000000000000000000000000000000000000;
function run() public {
runBase(VAULT, ADAPTER);
}
}
```
## Parameters
| Parameter | Description |
| --------- | --------------------------------------------------------- |
| `VAULT` | Address of the Vault V2. |
| `ADAPTER` | Address of the adapter to add to the Universal Delegator. |
## Deploy
Run:
```bash
forge script script/delegator/AddAdapter.s.sol:AddAdapterScript \
--rpc-url=RPC \
--account=ACCOUNT \
--sender=SENDER \
--broadcast
```
Replace:
| Placeholder | Description |
| ----------- | ------------------------------------------------ |
| `RPC` | RPC endpoint. |
| `ACCOUNT` | Foundry account. |
| `SENDER` | Address holding the `addAdapterRoleHolder` role. |
## Verify
1. Open the Vault V2 contract.
2. Read `delegator()` to obtain the Universal Delegator address.
3. Open the Universal Delegator contract.
4. Verify the adapter was successfully added using the available read methods or emitted events.
:::note
Only addresses with the `addAdapterRoleHolder` permission can add adapters. By default, this role is assigned to the vault `OWNER` during deployment.
:::
---
## /integrate/curators/manage-allocations
---
description: "Learn how curators allocate Vault V2 assets across adapters through the Universal Delegator."
---
# Manage Allocations
In Vault V2, curators no longer manage allocations by setting network limits and operator shares directly. Instead, vault assets are allocated through the vault's **Universal Delegator**, which routes capital across the vault's configured adapters.
As a curator, the main allocation flow is:
- Get the vault's delegator address
- Make sure the relevant adapters have been added and configured
- Allocate assets across adapters using the Universal Delegator
- Deallocate assets from adapters when needed
:::note
This page describes the Vault V2 allocation flow. The previous `setNetworkLimit()` and `setOperatorNetworkShares()` flow applies to older delegator-based vaults and is deprecated for Vault V2.
:::
## Allocate to Adapters
The Universal Delegator exposes an `allocateAll(uint256 amount)` method that allocates vault assets across configured adapters.
The default allocation helper script calls:
```solidity
IUniversalDelegator.allocateAll(amount)
```
on the delegator associated with a given Vault V2.
### Allocation Script
```solidity [AllocateAdaptersBaseScript.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IVaultV2} from "../../../../src/interfaces/vault/IVaultV2.sol";
import {IUniversalDelegator} from "../../../../src/interfaces/delegator/IUniversalDelegator.sol";
import {Logs} from "../../../utils/Logs.sol";
import {ScriptBase} from "../../../utils/ScriptBase.s.sol";
contract AllocateAdaptersBaseScript is ScriptBase {
function runBase(address vault, uint256 amount) public virtual returns (bytes memory data, address target) {
target = IVaultV2(vault).delegator();
data = abi.encodeCall(IUniversalDelegator.allocateAll, (amount));
sendTransaction(target, data);
Logs.log(
string.concat("Allocate adapters", "\n vault:", vm.toString(vault), "\n amount:", vm.toString(amount))
);
Logs.logSimulationLink(target, data);
}
}
```
This script:
1. Receives the Vault V2 address and the amount to allocate
2. Fetches the Universal Delegator address from the vault
3. Encodes a call to `allocateAll(amount)`
4. Sends the transaction to the delegator
## Allocation Parameters
| Parameter | Description |
| --------- | -------------------------------------------------------------------------- |
| `vault` | Address of the Vault V2 whose assets should be allocated. |
| `amount` | Amount of the vault asset to allocate across adapters. |
| `target` | The Universal Delegator address returned by `IVaultV2(vault).delegator()`. |
| `data` | Encoded calldata for `IUniversalDelegator.allocateAll(amount)`. |
## Using Safe
To allocate assets through Safe:
1. Open [Safe](https://app.safe.global/)
2. Open **Transaction Builder**
3. Get the Vault V2 address
4. Read the vault's `delegator()` address using the UI, CLI, Etherscan, or another block explorer
5. Enter the delegator address as the contract address
6. Click **Use Implementation ABI**
7. Choose the `allocateAll(uint256 amount)` method
8. Enter the amount of assets to allocate
9. Sign and execute the transaction
:::note
The `amount` should be denominated in the vault asset's smallest unit. For example, for a 6-decimal asset such as USDC, `1000000` represents `1 USDC`.
:::
## Verify Allocation
To verify allocation state, use the Universal Delegator read methods and the relevant adapter read methods.
At a high level, you should verify:
1. The vault's `delegator()` points to the Universal Delegator used for the transaction
2. The relevant adapters are configured on the delegator
3. The allocation transaction was executed successfully
4. The target adapters received or accounted for the allocated assets
### Verify the Delegator
1. Open the Vault V2 contract in a block explorer
2. Open the **Read Contract** tab
3. Query `delegator()`
4. Confirm that the returned address matches the delegator used for the allocation transaction
### Verify the Allocation Transaction
1. Open the allocation transaction in a block explorer
2. Confirm that the transaction target is the Universal Delegator
3. Confirm that the calldata corresponds to `allocateAll(uint256 amount)`
4. Confirm that the transaction succeeded
## Deallocations
Deallocations are also handled through the Universal Delegator. The exact method depends on the desired deallocation flow and adapter configuration.
Common deallocation-related permissions are assigned during Vault V2 deployment:
| Role holder | Description |
| --------------------------- | ---------------------------------------------------- |
| `deallocateRoleHolder` | Address allowed to deallocate assets from adapters. |
| `forceDeallocateRoleHolder` | Address allowed to force deallocation from adapters. |
:::warning
Use force deallocation carefully. It is intended for situations where normal deallocation is not sufficient or where an adapter-specific flow requires it.
:::
## Adapter Management
Before assets can be allocated, the relevant adapters must be added and configured on the Universal Delegator.
Vault V2 deployment assigns the following adapter-management roles:
| Role holder | Description |
| ----------------------------------- | ------------------------------------------------------ |
| `addAdapterRoleHolder` | Address allowed to add new adapters. |
| `removeAdapterRoleHolder` | Address allowed to remove adapters. |
| `swapAdaptersRoleHolder` | Address allowed to reorder or swap adapters. |
| `setAdapterLimitsRoleHolder` | Address allowed to configure adapter limits. |
| `setAutoAllocateAdaptersRoleHolder` | Address allowed to configure auto-allocation adapters. |
:::note
The default Vault V2 deployment script assigns these roles to the vault `OWNER`. For production deployments, these permissions should be reviewed and may be assigned to a multisig or automation contract depending on the vault's operational setup.
:::
## Example Flow
A typical Vault V2 allocation flow looks like this:
1. Deploy the Vault V2
2. Add the required adapters to the Universal Delegator
3. Configure adapter limits
4. Configure auto-allocation adapters if applicable
5. Deposit assets into the vault
6. Call `allocateAll(amount)` on the Universal Delegator
7. Verify that assets were allocated as expected
## Deprecated Flow
The previous curator allocation flow used network and operator allocation methods such as:
```solidity
setNetworkLimit(...)
setOperatorNetworkShares(...)
```
These methods are part of the older delegator model. For Vault V2, allocation is performed through the Universal Delegator and its configured adapters.
If you are using Vault V2, use the adapter allocation flow described above instead.
---
## /integrate/curators/registry-and-fees
---
description: "Vault V2 supports management and performance fees configured directly on the vault. Fees accrue automatically as newly minted vault shares to the configured fee receivers."
---
# Manage Fees
Vault V2 supports two fee types that are configured directly on the vault:
- **Management fee:** a continuous fee charged on vault assets over time.
- **Performance fee:** a fee charged on the vault's positive performance.
Unlike previous versions, there is no external rewards registry or curator registration. Fees are managed directly by the vault and accrue automatically as newly minted vault shares.
Since vault shares represent ownership of a yield-bearing vault, fee receivers are compensated in vault shares rather than the underlying collateral.
## Management Fee
The management fee can be configured through `setManagementFee`.
```solidity
vault.setManagementFee(fee, receiver);
```
Where:
- `fee` is the management fee rate.
- `receiver` is the address receiving the newly minted vault shares.
Only addresses with the appropriate permission can update the management fee.
## Performance Fee
The performance fee can be configured through `setPerformanceFee`.
```solidity
vault.setPerformanceFee(fee, receiver);
```
Where:
- `fee` is the performance fee rate.
- `receiver` is the address receiving the newly minted vault shares.
Only addresses with the appropriate permission can update the performance fee.
## Fee Accrual
Fees accrue automatically through the vault's accounting logic. Whenever the vault updates its accounting, it calculates any accrued management and performance fees and mints the corresponding amount of vault shares to the configured fee receivers.
Because fees are paid in vault shares, the vault does not need to withdraw collateral from adapters or other yield-generating strategies. Instead, the fee receiver becomes a shareholder of the vault, while the ownership of existing depositors is diluted proportionally.
## Realizing Fees
There is no separate fee claiming process in Vault V2.
Fee receivers obtain vault shares automatically as fees accrue. These shares behave like any other vault shares and can be redeemed or withdrawn through the standard vault withdrawal flow, subject to the vault's withdrawal conditions and available liquidity.
---
## /integrate/curators/submit-metadata
---
description: "The Symbiotic UI displays TVL, allocations, and relationships between curators, vaults, operators, and networks. To make your entity visible on the UI, submit..."
---
# Submit Metadata
The [Symbiotic UI](https://app.symbiotic.fi/deposit) displays TVL, allocations, and relationships between curators, vaults, operators, and applications. To make your entity visible on the UI, submit its metadata to the corresponding repository.
After you submit metadata, the Symbiotic team reviews and merges it. Once merged, your data appears on the UI.
## Add a New Entity Template
### Choose a Repository
| Chain | URL |
| ------- | -------------------------------------------------------------------------------------------------- |
| Mainnet | [https://github.com/symbioticfi/metadata-mainnet](https://github.com/symbioticfi/metadata-mainnet) |
| Hoodi | [https://github.com/symbioticfi/metadata-hoodi](https://github.com/symbioticfi/metadata-hoodi) |
### Repository Structure
The repository is organized as follows:
```
repository/
├── vaults/
│ ├── 0x/
│ │ ├── info.json
│ │ └── logo.png (optional)
├── networks/
├── operators/
├── tokens/
```
Each entity is identified by its Ethereum address (`0x...`), and its data is stored in a folder named after the address. Inside this folder, include a file `info.json` containing metadata, and optionally, an icon file `logo.png`.
***
### Steps to Add a New Entity
**Note: After your PR is submitted, email your PR link to [verify@symbiotic.fi](mailto\:verify@symbiotic.fi) from your official business email (domain must match that of your entity website) to allow us to confirm your identity ahead of merging your PR.**
1. **Determine the entity type**:
- Decide whether the entity belongs to `vaults`, `networks`, `operators`, `tokens` or `points`.
- If the entity is a `vault`, ensure its collateral token entity is registered in the `tokens` folder before adding the vault metadata. If not, add the token first.
2. **Register the entity in the registry**:
- Before adding metadata for vaults, networks, or operators, ensure that they are registered in their respective registries. You can find the current registry contract addresses in the [Addresses page](/get-started/resources/addresses). Unregistered entities will not be accepted.
3. **Create a new folder**:
- Navigate to the appropriate directory for the entity type.
- Create a folder named after the Ethereum address (e.g., `0x1234567890abcdef1234567890abcdef12345678`).
4. **Add the `info.json` file**:
- Include metadata in the specified format (see below).
5. **(Optional) Add an icon file**:
- If available, include a `logo.png` file with the entity’s logo.
The Symbiotic team reviews your PR after automated checks pass. If approved, it will be merged into the repository.
***
### File Format: `info.json`
The `info.json` file must follow this structure:
#### Required Fields
- `name` (string): The name of the entity.
- `description` (string): A brief description of the entity.
- `tags` (array of strings): Tags categorizing the entity.
- `links` (array of objects): External links related to the entity.
#### Fields for Tokens
- `cmcId` (string): The CoinMarketCap ID for the token. Used to fetch price of the token in USD.
- `permitName` (string): The `name` field for EIP-2612 support.
- `permitVersion` (string): The `version` field for EIP-2612 support.
#### Fields for Vaults
- `curatorId` (string): The ID of the curator of the vault.
- `vaultType` (string): The type of the vault. Can be one of:
- `eth-restaking`: Vaults with ETH-flavored collateral restaked across multiple networks
- `btc-restaking`: Vaults with BTC-flavored collateral restaked across multiple networks
- `network-exclusive`: Vaults exclusive to a single network
#### Supported `links` Types
Each link should include:
- `type`: The type of the link. Supported values are:
- `website`: The official website of the entity.
- `explorer`: A blockchain explorer link for the entity's Ethereum address or contract.
- `docs`: Documentation related to the entity.
- `example`: Example use cases or tutorials.
- `externalLink`: A link to be shown below the entity's name.
- `name`: A user-friendly name for the link.
- `url`: The URL of the resource.
### Icon File: `logo.png` (Optional)
If you want to include an icon for the entity, follow these guidelines:
- **File Name**: `logo.png`
- **Dimensions**: 256x256 pixels
- **Format**: PNG
Place the `logo.png` file in the same folder as the `info.json` file.
***
### Validation
Before submitting your PR, ensure the following:
1. The Ethereum address is valid:
- It must start with `0x` and be exactly 42 characters long.
2. The `info.json` file is valid:
- Use a JSON validator, such as [https://jsonlint.com/](https://jsonlint.com/).
3. The `logo.png` file (if included) meets the size requirement of **256x256 pixels**.
***
### Submitting the Pull Request
Once your files are added to the repository, create a Pull Request with the following details:
1. **Entity Type**: Specify the type (vault, network, operator, token).
2. **Ethereum Address**: Provide the address of the entity.
3. **Description**: Summarize the entity’s purpose and data.
#### Example PR Description
```
Added new token entity: 0x1234567890abcdef1234567890abcdef12345678
- **Name**: USDT
- **Description**: USDT is a stablecoin pegged to the US Dollar, widely used for trading and liquidity in cryptocurrency markets.
- **Tags**: stablecoin, usdt
- **Links**:
- [Website](https://tether.to/)
- [Etherscan](https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7)
- [Tether Documentation](https://docs.tether.to/)
- **CMC ID**: 825
- **Permit Name**: USDT Permit Token
- **Permit Version**: 1
- **Icon**: Included (256x256 px)
```
***
### Review and Approval
Your PR will be reviewed to ensure:
- The `info.json` file has all required fields and valid data.
- The `logo.png` file (if included) meets the requirements.
- The metadata is accurate and well-structured.
- The submitter of the PR is from the entity in question (verified via an email with your PR link to [verify@symbiotic.fi](mailto\:verify@symbiotic.fi) from your official business email)
After approval, your changes will be merged into the repository.
## Add a Curator
:::steps
##### Create a new folder in the `/curators` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "My Curator",
"description": "My Curator is a curator that allows you to manage your vaults.",
"tags": ["curator", "staking"],
"links": [
{ "type": "website", "name": "Website", "url": "https://mycurator.com" },
{ "type": "twitter", "name": "Twitter", "url": "https://x.com/mycurator" },
{
"type": "explorer",
"name": "Explorer",
"url": "https://etherscan.io/address/0x1234567890abcdef1234567890abcdef12345678"
}
]
}
```
##### Save a logo of the Curator to `logo.png` of 256x256 pixels size
:::
## Add a Token
::::steps
##### Create a new folder in the `/tokens` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "My Token",
"description": "My Token is a token that allows you to earn rewards.",
"tags": ["token", "staking"],
"cmcId": "1234567890",
"links": [{ "type": "website", "name": "Website", "url": "https://mytoken.com" }]
}
```
:::warning
If the CMC ID is missing:
- The token’s price cannot be displayed
- TVL (Total Value Locked) in USD won’t be calculated
- Symbiotic Points cannot be calculated or distributed
- Points will be calculated from the date the CMC ID is added; retrospective recalculation for points accrued before this date will not occur.
:::
##### Save a logo of the Token to `logo.png` of 256x256 pixels size
::::
## Add a Vault
:::warning
If the Vault's collateral is not yet supported by Symbiotic, a separate **Token PR** must be submitted before the **Vault PR**.
:::
::::steps
##### Create a new folder in the `/vaults` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "DeFi Vault",
"description": "A secure vault for decentralized finance.",
"tags": ["vault", "DeFi"],
"curatorName": "My Curator",
"links": [
{
"type": "website",
"name": "Website",
"url": "https://example-vault.com/"
},
{
"type": "docs",
"name": "Vault Documentation",
"url": "https://example-vault.com/docs"
}
]
}
```
:::warning
If the CMC ID is missing:
- The token’s price cannot be displayed
- TVL (Total Value Locked) in USD won’t be calculated
- Symbiotic Points cannot be calculated or distributed
- Points will be calculated from the date the CMC ID is added; retrospective recalculation for points accrued before this date will not occur.
:::
##### Save a logo of the Vault to `logo.png` of 256x256 pixels size
::::
---
## /integrate/curators/vault-wrapping
---
description: "Sometimes, due to design choices for security guarantees or interaction flow optimization, you can't implement your ideas in a standard way. In these cases,..."
---
# Vault Wrapping
Sometimes, due to design choices for security guarantees or interaction flow optimization, you can't implement your ideas in a standard way. In these cases, you can wrap the Symbiotic Vault for deposits, slashing, opt-ins, etc. This page presents example cases:
## Mortgage-backed Security Example
A **mortgage-backed security (MBS)** is a financial instrument created by pooling together many individual home loans (mortgages) and selling them as a single tradable security. Instead of a bank holding a mortgage and collecting monthly payments, the cash flows (interest and principal) from thousands of mortgages are bundled, then redistributed to investors in the MBS.
- **Tranching**: To cater to different investor risk appetites, the pool is divided into **tranches**.
- Senior tranches: Get paid first, lower risk, lower yield.
- Junior tranches: Get paid later and absorb defaults first, higher risk, higher yield.
- **Risk distribution**: This structure spreads default risk across different investor groups and creates a market for varying levels of risk exposure.
Mortgage Backed Securities Structuring and Value Chain
### Slashing Tranche-Based Vault Wrapper
In Symbiotic, **slashing vaults** are pools where collateral is staked to secure external networks or services. Just like mortgages carry **default risk**, staking carries **slashing risk** (collateral may be cut if operators misbehave).
Here’s how the analogy works:
- **Mortgages = Operator Collateral Positions**
Each mortgage in an MBS corresponds to an individual operator’s staked collateral in Symbiotic. Just as homeowners may default, operators may be slashed.
- **MBS Pool = Slashing Vault**
The pooled mortgages in an MBS map to the **vault of collateral** in Symbiotic. Both aggregate risk into a collective structure.
- **Tranches = Vault Risk Segmentation**
Symbiotic vaults could be designed with **tranches** similar to MBS:
- Senior tranche: Investors who want safer exposure get priority in withdrawals and protection against small slashes (absorbed by junior tranches first).
- Mezzanine tranche: Medium-risk exposure, takes losses only after juniors are hit.
- Junior tranche: Risk-seeking investors absorb slashing losses first but get higher yield (greater share of staking rewards).
- **Cash Flows = Staking Rewards**
Just as mortgages generate interest payments, collateral in slashing vaults generates staking rewards or fees. These flows are redistributed to participants, depending on their tranche.
- **Risk Transformation**
MBS transform mortgage default risk into tiered securities with different profiles. Symbiotic vaults could similarly transform **slashing risk** into structured exposure, letting risk-averse and risk-seeking participants coexist in the same vault.
Tranche-Based (or Slashing Insurance) Vault Segmentation + Redistribution
### Implementation
A user (staker) would have 3 choices to deposit a single ERC20 asset (collateral) into a Symbiotic vault. They can either deposit into the junior, mezzanine or senior tranche, according to their risk-profile or portfolio fit. The vault wrapper contract would then deposit the collateral to the Symbiotic vault, and the user would receive (or not, depending on the curator choice) an LST.
From our understanding, there may be 2 possibilities to issue the receipt token:
**Model A — 3 Separate ERC20s (most common in structured products)**
- When a user deposits, they **choose the tranche** (junior, mezzanine, senior).
- The wrapper mints them **only that tranche token (LST)**.
- Example:
- Alice deposits 100 USDC → gets **100 tJNR**.
- Bob deposits 100 USDC → gets **100 tSNR**.
**Model B — 1 ERC20 + internal “tranche shares” accounting**
- Users deposit into the wrapper without selecting a tranche.
- The wrapper automatically allocates the deposit across junior, mezz, and senior according to some fixed ratio (e.g., 20/30/50).
- The user receives **one unified wrapper-LST** (e.g., `tWRAP`).
Tranche-Based Vault Proposed Implementation
The entire paper, co-authored with ReSquared can be found here: [https://github.com/dias-henrique/Slashing-Insurance-Vaults/blob/main/CESIV.pdf](https://github.com/dias-henrique/Slashing-Insurance-Vaults/blob/main/CESIV.pdf)