EVC Utils Guide
EVCUtil.sol
is a utility abstract contract designed to make it easier and safer 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 always called through the EVC when required.
Why Use EVCUtil
?
- Authentication: Ensures your contract is only called by the EVC in the correct context, protecting against unauthorized access.
- 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. - Best Practices: Encourages secure patterns for vaults, modules, and periphery contracts that need to integrate with the EVC.
Key Features and Patterns
1. callThroughEVC
Modifier
The callThroughEVC
modifier ensures that a function is always executed 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.
Why is this needed?
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
, you ensure that the status checks are always deferred to the end of the operation or batch, even for direct calls.
Usage:
function myFunction() external callThroughEVC {
// This will always execute in the correct EVC context
}
2. onlyEVCAccount
and onlyEVCAccountOwner
Modifiers
onlyEVCAccount
: Ensures standard authentication path allowing the account owner or any of its EVC accounts.onlyEVCAccountOwner
: Ensures standard authentication path allowing only the account owner. This modifier is typically used for governance functions that should only be callable by the account owner.
Usage:
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.
Usage:
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).
Usage:
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();
// ...
}
}