EVC utils guide
EVCUtil.sol is a utility abstract contract designed to make it easier to build contracts that interact with the Ethereum Vault Connector (EVC). It provides authentication helpers, context-aware modifiers, and patterns for enforcing that your contract is called through the EVC when required.
Why use EVCUtil?
- Authentication: Checks that your contract is called by the EVC in the correct context, reducing unauthorized-access risk when implemented correctly.
- Context Awareness: Provides helpers to retrieve the true sender (
onBehalfOfAccount) and to check if your contract is being called as part of a batch, liquidation, or operator action. - Implementation Patterns: Encourages consistent patterns for vaults, modules, and periphery contracts that need to integrate with the EVC.
Key features and patterns
1. callThroughEVC modifier
The callThroughEVC modifier routes a function through the EVC, even if it is called directly. If the call does not originate from the EVC, the modifier will route the call through the EVC's call() method, which then calls back into the contract with the correct execution context.
Vaults and contracts often rely on the EVC to trigger the requested account and vault status checks. These checks typically must be performed at the end of the operation or batch. By using callThroughEVC, direct calls are routed through the same context so status checks are deferred to the end of the operation or batch.
function myFunction() external callThroughEVC {
// This will always execute in the correct EVC context
}2. onlyEVCAccount and onlyEVCAccountOwner modifiers
onlyEVCAccount: Uses the standard authentication rule allowing the account owner or any of its EVC accounts.onlyEVCAccountOwner: Uses the standard authentication rule allowing only the account owner. This modifier is typically used for governance functions that should only be callable by the account owner.
function restrictedAction() external onlyEVCAccount {
// Only callable by the EVC or a valid EVC account
}3. _msgSender and _msgSenderForBorrow
_msgSender(): Returns the logical sender, resolving the EVC context if needed._msgSenderForBorrow(): Like_msgSender, but also checks that the contract is enabled as a controller for the account.
function doSomething() external {
address user = _msgSender();
// Use 'user' as the logical sender
}4. Address prefix and common owner checks
_getAddressPrefix(address): Returns the 19-byte prefix shared by all sub-accounts of an owner._haveCommonOwner(address, address): Checks if two accounts share the same owner (i.e., same prefix).
bytes19 prefix = _getAddressPrefix(account);
bool sameOwner = _haveCommonOwner(account1, account2);Example: minimal EVC-aware contract
import "ethereum-vault-connector/utils/EVCUtil.sol";
contract Example is EVCUtil {
constructor(address evc) EVCUtil(evc) {}
function onlyEVCOwnerOperation() external onlyEVCAccountOwner {
address user = _msgSender();
// ...
}
}