Sym ERC20 Vault
ERC20-based SymByzVaults let you restake approved ERC20 tokens and use all Symbiotic features like delegation, slashing, and configuration routing.
1. Choose the ERC20 token
Ensure it is whitelisted or accepted in the context where you’re deploying.
2. Construct ByzVaultParams
Follow the 2. Construct the ByzVaultParams struct guide to set all vault settings (roles, token, fees, limit).
3. Construct SymParams
SymParams
is composed of four substructures:
BurnerParams
owner
: The address with permission to modify the Burner's configuration, including changing the delay and receivers. If set toaddress(0)
, the BurnerRouter becomes immutable.delay
: The waiting period (in seconds) required before any new configuration becomes active. This delay gives stakers a chance to withdraw in case they disagree with the upcoming changes.globalReceiver
: Default destination address for all burned assets if no specific receiver rule is triggered.networkReceivers
: List of fallback receivers mapped to specific networks. Used ifoperatorNetworkReceivers
is not configured for a given slashing event.operatorNetworkReceivers
: The most specific routing layer. If a slash involves a particular operator on a specific network, this route takes precedence.
VaultParams
version
: The version ID of the vault implementation to deploy.epochDuration
: Time duration (in seconds) of each vault epoch.
DelegatorParams
delegatorType
: Enum specifying the strategy for delegating stake. Types include: NETWORK_RESTAKE, FULL_RESTAKE, OPERATOR_SPECIFIC, OPERATOR_NETWORK_SPECIFIC.hook
: Optional contract that implements theonSlash()
interface. If configured, it will be called whenever a slash is processed. Can be used to implement automated delegation adjustments or additional accounting logic.hookSetRoleHolder
: Address with the right to update thehook
. Must be carefully controlled.networkLimitSetRoleHolders
: List of addresses that can modify the delegation strategy at the network level. Applicable only to certain delegator types (e.g. NETWORK_RESTAKE).operatorNetworkLimitOrSharesSetRoleHolders
: Role holders that configure operator-level delegation. Relevant for delegator types that allow fine-grained allocation per operator-network pair.operator
: Required only for fixed-operator delegator types. This operator will receive all delegations.network
: Required only for fixed-network delegator types. This network will receive all delegated stake.
SlasherParams
slasherType
: Determines the logic for executing slash requests. Values include:INSTANT
: Slash is executed immediately when conditions are met.VETO
: Allows the configured resolver to veto slashing events during a specific veto window.
vetoDuration
: Duration (in seconds) of the veto period. This is the window during which a resolver may block a slash request. Only applicable forVETO
slashers.resolverSetEpochsDelay
: Delay in vault epochs before a network’s updated resolver configuration becomes active. Used for safety and coordination. Only relevant forVETO
slasher types.
4. Call the Factory
Prerequisites
An Ethereum account (EOA) or smart contract that will act as the vault creator
The token you want to use for the vault (must be supported by EigenLayer for EigenLayer vaults)
Access to the Byzantine Factory contract address
Contract Addresses
Installation
System Requirements
Node.js (v14 or higher)
npm or yarn
TypeScript (optional but recommended)
Installation Steps
Install the SDK
npm install @byzantine/vault-sdk
Create Environment File Create a
.env
file in your project root:
RPC_URL=https://holesky.infura.io/v3/your_api_key_here
# Choose ONE of the following authentication methods:
MNEMONIC=your_wallet_mnemonic
# OR
PRIVATE_KEY=your_wallet_private_key_without_0x_prefix
DEFAULT_CHAIN_ID=17000 # 17000 for Holesky testnet, 1 for Ethereum Mainnet, 560048 for Hoodi Testnet
Basic Setup
import {
ByzantineClient,
ETH_TOKEN_ADDRESS,
BaseParams,
} from "@byzantine/vault-sdk";
import { ethers } from "ethers";
import * as dotenv from "dotenv";
dotenv.config();
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = ethers.Wallet.fromPhrase(process.env.MNEMONIC).connect(provider);
// OR const wallet = new ethers.Wallet(process.env.PRIVATE_KEY).connect(provider);
const client = new ByzantineClient({
chainId: 17000, // 17000 for Holesky, 1 for Mainnet, 560048 for Hoodi
provider: provider,
signer: wallet,
});
Supported Networks
Holesky Testnet (Chain ID: 17000)
Ethereum Mainnet (Chain ID: 1) - Coming Soon
Hoodi Testnet (Chain ID: 560048) - Coming Soon
SymERC20ByzVault Creation
Create a vault that integrates with the Symbiotic ecosystem:
function createSymByzVault(
ByzVaultParams calldata _byzVaultParams,
SymParams calldata _symParams
) external returns (address symByzVault);
// // -
// All import and initialize client as shown on the setup
// -
// Define vault parameters
const baseParams: BaseParams = {
// Either metadata (that will be converted to URI) or directly URI
metadata:
"data:application/json;base64,eyJuYW1lIjoiU3ltYmlvdGljIG1FVEggVmF1bHQiLCJkZXNjcmlwdGlvbiI6IkEgU3ltYmlvdGljIHZhdWx0IGZvciBtRVRIIHJlc3Rha2luZyIsImltYWdlX3VybCI6Imh0dHBzOi8vZXhhbXBsZS5jb20vdXBkYXRlZC12YXVsdC1pbWFnZS5wbmciLCJzb2NpYWxfdHdpdHRlciI6Imh0dHBzOi8veC5jb20vYnl6YW50aW5lX2ZpIiwic29jaWFsX2Rpc2NvcmQiOiJodHRwczovL2Rpc2NvcmQuZ2cvYnl6YW50aW5lIiwic29jaWFsX3RlbGVncmFtIjoiaHR0cHM6Ly90Lm1lL2J5emFudGluZSIsInNvY2lhbF93ZWJzaXRlIjoiaHR0cHM6Ly9ieXphbnRpbmUuZmkiLCJzb2NpYWxfZ2l0aHViIjoiaHR0cHM6Ly9naXRodWIuY29tL2J5emFudGluZS1maSJ9",
token_address: "0x8d09a4502Cc8Cf1547aD300E066060D043f6982D", // wstETH
is_deposit_limit: true,
deposit_limit: ethers.parseUnits("500", 18), // 500 wstETH
is_private: false,
is_tokenized: true,
token_name: "Byzantine wstETH Symbiotic Vault",
token_symbol: "bwstETHs",
curator_fee: 200, // 2% (200 basis points)
role_manager: wallet.address,
role_version_manager: wallet.address,
role_deposit_limit_manager: wallet.address,
role_deposit_whitelist_manager: wallet.address,
role_curator_fee_claimer: wallet.address,
role_curator_fee_claimer_admin: wallet.address,
};
const symbioticParams: SymbioticParams = {
vault_version: 1,
vault_epoch_duration: 604800, // 7 days in seconds
slasher_type: SlasherType.VETO,
slasher_veto_duration: 86400, // 1 day in seconds
slasher_number_epoch_to_set_delay: 3,
burner_delay_settings_applied: 21, // 21 days
burner_global_receiver: "0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd", // Global receiver for wstETH
burner_network_receiver: [],
burner_operator_network_receiver: [],
delegator_type: DelegatorType.NETWORK_RESTAKE,
delegator_hook: "0x0000000000000000000000000000000000000001", // Delegator hook address
delegator_operator: "0x0000000000000000000000000000000000000000", // Not used for NETWORK_RESTAKE
delegator_network: "0x0000000000000000000000000000000000000000", // Not used for NETWORK_RESTAKE
role_delegator_set_hook: address,
role_delegator_set_network_limit: [address],
role_delegator_set_operator_network_limit: [address],
role_burner_owner_burner: address,
};
// Create the vault
const tx = await client.createSymbioticERC20Vault({
base: baseParams,
symbiotic: symbioticParams,
});
// Wait for confirmation
const receipt = await tx.wait();
const vaultAddress = receipt.logs[0].address;
console.log(`Vault created at address: ${vaultAddress}`);
This deploys and initializes the vault and wires it to the selected Symbiotic modules.
✅ You receive the new vault address. You can now whitelist stakers, set delegation limits, or start deposits.
Last updated