This skill should be used when the user asks about "EVC", "Ethereum Vault Connector", "sub-accounts", "collateral", "controller", "batch", "permit", "status checks", or needs to understand Euler's foundational infrastructure.
Manages cross-vault operations, sub-accounts, and deferred solvency checks for Euler's lending protocol.
npx claudepluginhub cyotee/euler-lending-skillThis skill inherits all available tools. When active, it can use any tool Claude has access to.
The EVC is the foundational infrastructure layer that enables cross-vault coordination in Euler's lending ecosystem. It mediates all vault interactions, manages sub-accounts, and enforces solvency through deferred status checks.
┌──────────────────────────────────────────────────────────────┐
│ ETHEREUM VAULT CONNECTOR │
├──────────────────────────────────────────────────────────────┤
│ │
│ User (Owner) │
│ └── 256 Sub-Accounts (0-255) │
│ │ │
│ ├── Sub-Account 0: Main position │
│ │ ├── Collateral: [Vault A, Vault B] │
│ │ └── Controller: Vault C (lending) │
│ │ │
│ ├── Sub-Account 1: Isolated position │
│ │ ├── Collateral: [Vault D] │
│ │ └── Controller: Vault E │
│ │ │
│ └── Sub-Account N: ... │
│ │
│ EVC Functions: │
│ ├── call() - Route calls with deferred checks │
│ ├── batch() - Execute multiple operations atomically │
│ ├── controlCollateral() - Liquidation collateral seizure │
│ ├── permit() - EIP-712 gasless authorization │
│ ├── enableCollateral/disableCollateral │
│ └── enableController/disableController │
│ │
└──────────────────────────────────────────────────────────────┘
Each Ethereum address gets 256 sub-accounts via address prefix encoding:
// Sub-account address = owner address XOR account ID
// Account ID is in the last byte (0-255)
function getAddressPrefix(address account) internal pure returns (bytes19) {
return bytes19(uint152(uint160(account) >> 8));
}
function getSubAccount(address owner, uint8 subAccountId) internal pure returns (address) {
return address(uint160(owner) ^ uint160(subAccountId));
}
// Examples:
// Owner: 0x1234...5678
// Sub-account 0: 0x1234...5678 (same as owner)
// Sub-account 1: 0x1234...5679
// Sub-account 255: 0x1234...5687
Benefits:
// Storage per account
mapping(address account => SetStorage) internal accountCollaterals; // Max 10
mapping(address account => SetStorage) internal accountControllers; // Max 10 (1 at check time)
// Enable collateral vault for an account
function enableCollateral(address account, address vault) external payable {
// Authenticate caller
// Add vault to account's collateral set
// Emit CollateralStatus(account, vault, true)
}
// Enable controller (lending vault) for an account
function enableController(address account, address vault) external payable {
// Only the account itself or authorized operator
// Add vault to account's controller set
// Emit ControllerStatus(account, vault, true)
}
// Get enabled collaterals/controllers
function getCollaterals(address account) external view returns (address[] memory);
function getControllers(address account) external view returns (address[] memory);
function isCollateralEnabled(address account, address vault) external view returns (bool);
function isControllerEnabled(address account, address vault) external view returns (bool);
Key Distinction:
The EVC defers solvency checks until the end of a batch, allowing temporary insolvency during multi-step operations:
// Execution context tracking
struct ExecutionContext {
uint256 batchDepth; // Nesting level of batches
bool checksDeferred; // Whether checks are currently deferred
bool controlCollateralInProgress;
address onBehalfOfAccount; // Current authenticated account
// ... status check sets
}
// Require a status check at batch end
function requireAccountStatusCheck(address account) external payable {
// Schedule check - will be called at batch end
executionContext.accountStatusChecks.insert(account);
}
function requireVaultStatusCheck(address vault) external payable {
executionContext.vaultStatusChecks.insert(vault);
}
// Called on each scheduled account at batch end
interface IVault {
function checkAccountStatus(
address account,
address[] calldata collaterals
) external view returns (bytes4 magicValue);
// Returns 0xe90a5c72 (selector) if healthy
// Reverts if unhealthy
}
/// @notice Execute a call through EVC with deferred checks
function call(
address targetContract,
address onBehalfOfAccount,
uint256 value,
bytes calldata data
) external payable returns (bytes memory) {
// Authenticate: caller must be owner or operator of onBehalfOfAccount
// Set execution context
// Forward call to targetContract
// At end: run deferred status checks
}
struct BatchItem {
address targetContract;
address onBehalfOfAccount;
uint256 value;
bytes data;
}
/// @notice Execute multiple operations atomically
function batch(BatchItem[] calldata items) external payable {
// All operations share deferred check context
// Status checks run once at the very end
// Entire batch reverts if any check fails
}
// Example: Add collateral and borrow in one atomic batch
BatchItem[] memory items = new BatchItem[](2);
items[0] = BatchItem({
targetContract: collateralVault,
onBehalfOfAccount: myAccount,
value: 0,
data: abi.encodeCall(IVault.deposit, (amount, myAccount))
});
items[1] = BatchItem({
targetContract: lendingVault,
onBehalfOfAccount: myAccount,
value: 0,
data: abi.encodeCall(IVault.borrow, (borrowAmount, myAccount))
});
evc.batch(items);
// Status check happens here - must be solvent after both operations
/// @notice Controller vault seizes collateral during liquidation
function controlCollateral(
address collateralVault,
address onBehalfOfAccount,
uint256 value,
bytes calldata data
) external payable returns (bytes memory) {
// Only callable by enabled controller of the account
// Temporarily grants controller power over collateral vault
// Used for transferring collateral to liquidator
}
/// @notice Check if an operator is authorized for an account
function isAccountOperatorAuthorized(
address account,
address operator
) external view returns (bool);
/// @notice Authorize an operator for your accounts
function setAccountOperator(
address account,
address operator,
bool authorized
) external payable;
// Internal authentication
function authenticateCaller(address account) internal view returns (bool) {
// True if:
// 1. Caller is the account owner (same prefix)
// 2. Caller is an authorized operator
// 3. EVC is calling on behalf of authenticated context
}
/// @notice Execute operations via EIP-712 signature
function permit(
address signer,
address sender, // Who can submit the permit
uint256 nonceNamespace, // Nonce namespace for replay protection
uint256 nonce,
uint256 deadline,
uint256 value,
bytes calldata data, // Encoded batch or single call
bytes calldata signature // ECDSA or ERC-1271
) external payable;
// Nonce management
function getNonce(
bytes19 addressPrefix,
uint256 nonceNamespace
) external view returns (uint256);
// Invalidate nonces (cancel pending permits)
function setNonce(
bytes19 addressPrefix,
uint256 nonceNamespace,
uint256 nonce
) external payable;
Owner-level controls that apply to all sub-accounts:
/// @notice Lock down all accounts under this prefix
function setLockdownMode(
bytes19 addressPrefix,
bool enabled
) external payable;
// When locked: no new collateral/controller can be enabled
/// @notice Disable permit for this prefix
function setPermitDisabledMode(
bytes19 addressPrefix,
bool enabled
) external payable;
// Prevents gasless operations
// Check status
function isLockdownMode(bytes19 addressPrefix) external view returns (bool);
function isPermitDisabledMode(bytes19 addressPrefix) external view returns (bool);
// Get current execution context
function getCurrentOnBehalfOfAccount(
address controllerToCheck
) external view returns (address, bool);
// Returns (account, isControllerEnabled)
function areChecksDeferred() external view returns (bool);
function isControlCollateralInProgress() external view returns (bool);
// Useful for vaults to understand current context
function getRawExecutionContext() external view returns (uint256);
event CollateralStatus(address indexed account, address indexed collateral, bool enabled);
event ControllerStatus(address indexed account, address indexed controller, bool enabled);
event AccountOperatorAuthorized(address indexed account, address indexed operator, uint256 authMask);
event NonceUsed(bytes19 indexed addressPrefix, uint256 indexed nonceNamespace, uint256 nonce);
event LockdownModeSet(bytes19 indexed addressPrefix, bool enabled);
event PermitDisabledModeSet(bytes19 indexed addressPrefix, bool enabled);
┌──────────────────────────────────────────────────────────────┐
│ STATUS CHECK EXECUTION │
├──────────────────────────────────────────────────────────────┤
│ │
│ 1. User calls evc.batch([deposit, borrow]) │
│ └── checksDeferred = true │
│ │
│ 2. deposit() executes │
│ └── vault.requireAccountStatusCheck(account) │
│ └── Adds account to check set (deferred) │
│ │
│ 3. borrow() executes │
│ └── vault.requireAccountStatusCheck(account) │
│ └── Already in set (no-op) │
│ │
│ 4. Batch ends, checks execute: │
│ └── For each account in check set: │
│ └── controller.checkAccountStatus(account, collats) │
│ └── Returns magic value if healthy │
│ └── Reverts if unhealthy │
│ │
│ 5. If any check fails → entire batch reverts │
│ │
└──────────────────────────────────────────────────────────────┘
ethereum-vault-connector/src/EthereumVaultConnector.sol - Main EVC contractethereum-vault-connector/src/Set.sol - Set data structure for collateral/controllersethereum-vault-connector/src/ExecutionContext.sol - Execution context managementethereum-vault-connector/src/interfaces/IEthereumVaultConnector.sol - Full interfaceExpert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.