Cluster deployment and management using scripts
The euler-vault-scripts repository provides a script-based framework for deploying, configuring, and managing clusters of EVK vaults. It is intended for advanced users, DAOs, and protocol developers who need automation and support for complex, governed markets.
What is a cluster?
A cluster is a collection of vaults that accept each other as collateral and share a common governor. Clusters are defined and managed in Solidity scripts, enabling programmable and reproducible market deployments that can be reviewed before execution.
Key features
- Automated deployment and delta management
- Support for Safe multisigs, timelocks, and risk stewards
- Batching, emergency operations, and governance contract integration
Defining a cluster: example
Below are annotated snippets from a typical cluster script (Cluster.s.sol).
1. Define cluster assets
function defineCluster() internal override {
// List the assets for which vaults will be deployed
cluster.assets = [WETH, USDC, USDT, sUSDS];
}This sets up the vaults in your cluster. Each asset will have its own vault. Do not define more than one vault per asset.
2. Configure cluster parameters
function configureCluster() internal override {
// Set the governor addresses for vaults and oracle routers
cluster.oracleRoutersGovernor = getDeployer();
cluster.vaultsGovernor = getDeployer();
// Set the unit of account (e.g., USD)
cluster.unitOfAccount = USD;
// Percentage values use 1e4 = 100%.
cluster.feeReceiver = address(0);
cluster.interestFee = 0.1e4; // 10%
cluster.maxLiquidationDiscount = 0.15e4; // 15%
cluster.liquidationCoolOffTime = 1; // seconds
// Set hooks, config flags, etc. as needed
cluster.hookTarget = address(0);
cluster.hookedOps = 0;
cluster.configFlags = 0;
}This block configures governance, risk, and operational parameters for the cluster. You can override parameters per asset if needed.
3. Set oracle providers
// Assign oracle adapters or external vaults for each asset
cluster.oracleProviders[WETH ] = "0x10674C8C1aE2072d4a75FE83f1E159425fd84E1D";
cluster.oracleProviders[USDC ] = "0x6213f24332D35519039f2afa7e3BffE105a37d3F";
cluster.oracleProviders[USDT ] = "0x587CABe0521f5065b561A6e68c25f338eD037FF9";
cluster.oracleProviders[sUSDS] = "ExternalVault|0xD0dAb9eDb2b1909802B03090eFBF14743E7Ff967";Assets used in priced borrowing relationships need the required quote route. Use ExternalVault| only when the intended route should consume a reviewed ERC-4626 convertToAssets conversion and no direct pair oracle should take precedence. Apply the manipulation, decimals, redeemability, liquidity, and recursive-dependency checks in Oracle router deployment.
Deploy your own oracle adapters for the intended routes — the Oracle Deployer supports the available adapter types — rather than reusing adapters discovered onchain. If you do reuse one, verify chain, address, source, update behavior, governance, and suitability for the intended route first.
4. Set supply and borrow caps
cluster.supplyCaps[WETH ] = 10_000;
cluster.supplyCaps[USDC ] = 10_000_000;
cluster.supplyCaps[USDT ] = 10_000_000;
cluster.supplyCaps[sUSDS] = 10_000_000;
cluster.borrowCaps[WETH ] = 9_000;
cluster.borrowCaps[USDC ] = 9_000_000;
cluster.borrowCaps[USDT ] = 9_000_000;
cluster.borrowCaps[sUSDS] = type(uint256).max; // no capCaps control the maximum supply and borrowable amounts for each vault.
5. Assign interest rate models (IRMs)
uint256[4] memory irmETH = [uint256(0), uint256(194425692), uint256(41617711740), uint256(3865470566)];
uint256[4] memory irmUSD = [uint256(0), uint256(399976852), uint256(39767751304), uint256(3865470566)];
cluster.kinkIRMParams[WETH ] = irmETH;
cluster.kinkIRMParams[USDC ] = irmUSD;
cluster.kinkIRMParams[USDT ] = irmUSD;Interest rate models are set per asset. Use the provided scripts/utilities or Creator UI to generate IRM parameters as needed.
6. Configure LTVs and liquidation parameters
// Liquidation LTV matrix: columns = liability vaults, rows = collateral vaults
cluster.ltvs = [
// WETH USDC USDT sUSDS
[uint16(0.00e4), 0.85e4, 0.85e4, 0.00e4], // WETH
[uint16(0.87e4), 0.00e4, 0.95e4, 0.00e4], // USDC
[uint16(0.87e4), 0.95e4, 0.00e4, 0.00e4], // USDT
[uint16(0.87e4), 0.95e4, 0.95e4, 0.00e4] // sUSDS
];7. Configure spread LTV
// Set the spread LTV for the entire cluster
cluster.spreadLTV = 0.02e4; // 2% spreadThe spread LTV represents the difference between the liquidation threshold and the maximum LTV for all assets in the cluster. This creates a buffer zone before liquidation can occur, but it does not prevent liquidations during price moves, oracle updates, liquidity changes, or execution delays.
Environment setup and running scripts
Prerequisites
- Install Foundry:
curl -L https://foundry.paradigm.xyz | bash
foundryup- Clone the repository:
git clone https://github.com/euler-xyz/euler-vault-scripts.git
cd euler-vault-scripts-
Prepare the
.envfile using.env.exampleas a template. Define the RPC URLs for all the chain IDs you need. If you plan to submit transactions through Safe, defineSAFE_API_KEYas described in the current repository README. Treat that README as the source of truth for current environment variables and command options. -
Install dependencies:
./install.sh- Compile the contracts:
forge clean && forge compileRunning scripts
The scripts are experimental and provided as-is. Pin and review the repository revision you use, test the complete cluster configuration and scripts, run the documented dry run, and independently review every generated transaction and Safe payload before production execution. A successful dry run does not validate asset, oracle, liquidity, governance, cap, LTV, fee, or liquidation-risk choices.
Use the ExecuteSolidityScript.sh script to run the management script:
./script/ExecuteSolidityScript.sh script/clusters/[CLUSTER_FILE] [options]Replace [CLUSTER_FILE] with your cluster-specific file name (e.g., Cluster.s.sol).
Important options:
--dry-run: Simulates the script without executing transactions--rpc-url URL|CHAIN_ID: Required ifDEPLOYMENT_RPC_URLnot defined in.env--account ACCOUNTor--ledger: Required ifDEPLOYER_KEYnot defined in.env--batch-via-safe: Creates a batch payload file for Safe multisig execution--safe-address SAFE_ADDRESS: Authorized Safe multisig address--timelock-address: Schedules transactions in the timelock controller--risk-steward-address: Executes transactions via the risk steward contract
Example commands:
Initial deployment:
./script/ExecuteSolidityScript.sh ./script/clusters/Cluster.s.sol --account DEPLOYER --rpc-url 1Managing a deployed cluster with governance contracts:
./script/ExecuteSolidityScript.sh ./script/clusters/Cluster.s.sol --batch-via-safe --safe-address DAO --timelock-address wildcard --rpc-url 1Important notes
- Always use
--dry-runfirst, then inspect the target chain, callers, destinations, calldata, values, role paths, and resulting state before signing - Environment variables in
.envtake precedence over command line arguments - After deployment, commit the generated
.jsonfiles in the scripts directory as they serve as the deployed contracts addresses cache