diff --git a/.fuzz.yml b/.fuzz.yml index 7d0d1295..3011688a 100644 --- a/.fuzz.yml +++ b/.fuzz.yml @@ -9,10 +9,10 @@ fuzz: quick_check: False build_directory: out sources_directory: src - project: "CVC" + project: "EVC" rpc_url: http://127.0.0.1:8545 deployed_contract_address: "0x5fbdb2315678afecb367f032d93f642f64180aa3" number_of_cores: 32 time_limit: 1hour targets: - - "test/cvc/CreditVaultConnectorScribble.sol" + - "test/evc/EthereumVaultConnectorScribble.sol" diff --git a/README.md b/README.md index b5498d71..1dc3d7e1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Credit Vault Connector +# Ethereum Vault Connector -The Credit Vault Connector (CVC) is an attempt to distill the core functionality required for a lending market into a foundational layer that can be used as a base building block for many diverse protocols. The CVC is primarily a mediator between Credit Vaults, which are contracts that implement the ERC-4626 interface and contain a small amount of additional logic for interfacing with other vaults. +The Ethereum Vault Connector (EVC) is an attempt to distill the core functionality required for a lending market into a foundational layer that can be used as a base building block for many diverse protocols. The EVC is primarily a mediator between Vaults, which are contracts that implement the ERC-4626 interface and contain a small amount of additional logic for interfacing with other vaults. For more information refer to the [WHITEPAPER](docs/whitepaper.md) and the [SPECS](docs/specs.md). @@ -11,10 +11,10 @@ For more information refer to the [WHITEPAPER](docs/whitepaper.md) and the [SPEC ``` . ├── interfaces -│ ├── ICreditVault.sol -│ ├── ICreditVaultConnector.sol +│ ├── IVault.sol +│ ├── IEthereumVaultConnector.sol │ └── IERC1271.sol -├── CreditVaultConnector.sol +├── EthereumVaultConnector.sol ├── ExecutionContext.sol ├── Set.sol └── TransientStorage.sol @@ -22,17 +22,17 @@ For more information refer to the [WHITEPAPER](docs/whitepaper.md) and the [SPEC ## Install -To install Credit Vault Connector in a [**Foundry**](https://github.com/foundry-rs/foundry) project: +To install Ethereum Vault Connector in a [**Foundry**](https://github.com/foundry-rs/foundry) project: ```sh -forge install euler-xyz/euler-cvc +forge install euler-xyz/euler-evc ``` ## Usage -The Credit Vault Connector comes with a comprehensive set of tests written in Solidity, which can be executed using Foundry. +The Ethereum Vault Connector comes with a comprehensive set of tests written in Solidity, which can be executed using Foundry. -For a detailed understanding of the Credit Vault Connector and considerations for its integration, please refer to the [WHITEPAPER](docs/whitepaper.md) and the [SPECS](docs/specs.md). You can find examples of vaults utilizing the Credit Vault Connector in the [CVC Playground](https://github.com/euler-xyz/euler-cvc-playground/tree/master/src) repository. However, these example vaults are not meant for production use as they have not been audited and are intended solely for testing and experimentation purposes. +For a detailed understanding of the Ethereum Vault Connector and considerations for its integration, please refer to the [WHITEPAPER](docs/whitepaper.md) and the [SPECS](docs/specs.md). You can find examples of vaults utilizing the Ethereum Vault Connector in the [EVC Playground](https://github.com/euler-xyz/euler-evc-playground/tree/master/src) repository. However, these example vaults are not meant for production use as they have not been audited and are intended solely for testing and experimentation purposes. To install Foundry: @@ -49,7 +49,7 @@ foundryup To clone the repo and install dependencies: ```sh -git clone https://github.com/euler-xyz/euler-cvc.git && cd euler-cvc && yarn +git clone https://github.com/euler-xyz/euler-evc.git && cd euler-evc && yarn ``` ## Testing @@ -73,13 +73,13 @@ npm install -g eth-scribble To instrument the contracts and run the tests: ```sh -scribble test/cvc/CreditVaultConnectorScribble.sol --output-mode files --arm && forge test +scribble test/evc/EthereumVaultConnectorScribble.sol --output-mode files --arm && forge test ``` To remove instrumentation: ```sh -scribble test/cvc/CreditVaultConnectorScribble.sol --disarm +scribble test/evc/EthereumVaultConnectorScribble.sol --disarm ``` ### in `coverage` mode @@ -94,9 +94,9 @@ This software is **experimental** and is provided "as is" and "as available". **No warranties are provided** and **no liability will be accepted for any loss** incurred through the use of this codebase. -Always include thorough tests when using the Credit Vault Connector to ensure it interacts correctly with your code. +Always include thorough tests when using the Ethereum Vault Connector to ensure it interacts correctly with your code. -The Credit Vault Connector **has not yet undergone an audit** and should not be used in production. +The Ethereum Vault Connector **has not yet undergone an audit** and should not be used in production. ## Known limitations @@ -104,7 +104,7 @@ Refer to the [WHITEPAPER](docs/whitepaper.md#security-considerations) for a list ## Contributing -The code is currently in an experimental phase leading up to the first audit. Feedback or ideas for improving the Credit Vault Connector are appreciated. Contributions are welcome from anyone interested in conducting security research, writing more tests including formal verification, improving readability and documentation, optimizing, simplifying, or developing integrations. +The code is currently in an experimental phase leading up to the first audit. Feedback or ideas for improving the Ethereum Vault Connector are appreciated. Contributions are welcome from anyone interested in conducting security research, writing more tests including formal verification, improving readability and documentation, optimizing, simplifying, or developing integrations. ## License diff --git a/docs/specs.md b/docs/specs.md index 4247d31d..e5df6e0d 100644 --- a/docs/specs.md +++ b/docs/specs.md @@ -1,29 +1,29 @@ -# Credit Vault Connector and Credit Vault Specification +# Ethereum Vault Connector and Vault Specification ## Definitions -- Credit Vault Connector (CVC): A smart contract that mediates between Credit Vaults in order to enable their lending and borrowing functionality. -- Credit Vault (CV): A smart contract that accepts deposits of a single asset and issues shares in return, it may support borrowing functionality. It implements the logic and interface necessary for interaction with other Credit Vaults via the CVC. Optionally, ERC-4626 compliant. -- Account: Every Ethereum address has 256 accounts in the CVC (one private key to rule them all). Each account has an account ID from 0-255. In order to compute the account addresses, the account ID is treated as a uint and XORed (exclusive ORed) with the Ethereum address. Effectively, a group of 256 accounts belonging to the same owner share the first 19 bytes of their address and differ only in the last byte. +- Ethereum Vault Connector (EVC): A smart contract that mediates between Vaults in order to enable their lending and borrowing functionality. +- Vault: A smart contract that accepts deposits of a single asset and issues shares in return, it may support borrowing functionality. It implements the logic and interface necessary for interaction with other Vaults via the EVC. Optionally, ERC-4626 compliant. +- Account: Every Ethereum address has 256 accounts in the EVC (one private key to rule them all). Each account has an account ID from 0-255. In order to compute the account addresses, the account ID is treated as a uint and XORed (exclusive ORed) with the Ethereum address. Effectively, a group of 256 accounts belonging to the same owner share the first 19 bytes of their address and differ only in the last byte. - Account Owner: An EOA or a smart contract Ethereum address, one of the 256 accounts with account ID 0, that has ownership over the group of 256 accounts. - Account Operator: An EOA or smart contract Ethereum address that has been granted a permission to operate on behalf of the Account. The permission can only be granted by the Account Owner. -- Collateral Vault: A Credit Vault which deposits are recognized as collateral for borrowing in other Credit Vaults. An Account can enable up to 20 collaterals. Enabled collateral can be seized by the Controller Vault in case of liquidation. -- Controller Vault: A Credit Vault enabled by a user in order to be able to borrow from it. Enabling Controller submits the specified Account to the rules encoded in the Controller Vault's code. All the funds in all the enabled Collateral Vaults are indirectly under control of the Controller Vault. Whenever a user wants to perform an action such as removing collateral, the Controller Vault is consulted in order to determine whether the action is allowed, or whether it should be blocked since it would make the Account insolvent. An Account can have only one Controller Vault enabled at a time unless it's a transient state during checks deferral. +- Collateral Vault: A Vault which deposits are recognized as collateral for borrowing in other Vaults. An Account can enable up to 20 collaterals. Enabled collateral can be seized by the Controller Vault in case of liquidation. +- Controller Vault: A Vault enabled by a user in order to be able to borrow from it. Enabling Controller submits the specified Account to the rules encoded in the Controller Vault's code. All the funds in all the enabled Collateral Vaults are indirectly under control of the Controller Vault. Whenever a user wants to perform an action such as removing collateral, the Controller Vault is consulted in order to determine whether the action is allowed, or whether it should be blocked since it would make the Account insolvent. An Account can have only one Controller Vault enabled at a time unless it's a transient state during checks deferral. - Permit: An EIP-712 typed data message allowing arbitrary calldata execution on behalf of the signer (Account Owner or Account Operator) of the message. It is useful for implementing "gasless" transactions. -- Callback: A functionality allowing the msg.sender to be called back by the CVC with the specified calldata and specified context set. The callback is executed with Account and Vault Status Checks deferred. +- Callback: A functionality allowing the msg.sender to be called back by the EVC with the specified calldata and specified context set. The callback is executed with Account and Vault Status Checks deferred. - Call: A functionality allowing an Account Owner or Account Operator to execute an arbitrary calldata on behalf of the specified Account while Account and Vault Status Checks are deferred. - Impersonation: A functionality allowing an enabled Controller Vault to execute an arbitrary calldata on any of the enabled Collateral Vaults on behalf of the specified Account while Account and Vault Status Checks are deferred. The Controller Vault must be the only enabled Controller Vault for the Account in order to be able to impersonate the Account. Impersonation is useful for liquidation flows. - Batch: A list of operations that are executed atomically one by one with Account and Vault Status Checks deferred. -- Simulation: An entry point into the CVC that allows for simulating the execution of a batch without modifying the state. It is useful for inspecting the outcome of a batch before executing it. -- Account Status Check: A functionality implemented by Credit Vaults to enforce Account solvency. Vaults must expose a special function that will receive an Account address and this Account's list of enabled Collateral Vaults in order to determine the Account's liquidity status. Account status is checked immediately or is deferred until the end of the top-level call. Account Status Check deferral allows for a transient violation of the Account solvency. -- Vault Status Check: A functionality implemented by Credit Vaults to enforce Vault constraints (i.e. supply/borrow caps). Vaults may expose a special function that implements necessary checks in order to determine acceptable state of the Vault. Vault status is checked immediately or is deferred until the end of the top-level call. Vault Status Check deferral allows for a transient violation of the Vault constraints. +- Simulation: An entry point into the EVC that allows for simulating the execution of a batch without modifying the state. It is useful for inspecting the outcome of a batch before executing it. +- Account Status Check: A functionality implemented by Vaults to enforce Account solvency. Vaults must expose a special function that will receive an Account address and this Account's list of enabled Collateral Vaults in order to determine the Account's liquidity status. Account status is checked immediately or is deferred until the end of the top-level call. Account Status Check deferral allows for a transient violation of the Account solvency. +- Vault Status Check: A functionality implemented by Vaults to enforce Vault constraints (i.e. supply/borrow caps). Vaults may expose a special function that implements necessary checks in order to determine acceptable state of the Vault. Vault status is checked immediately or is deferred until the end of the top-level call. Vault Status Check deferral allows for a transient violation of the Vault constraints. - Checks-deferrable Call: Any of the function calls that defers the Account and Vault Status Checks namely Callback, Call, Impersonation, or Batch call. Checks-deferrable Calls can be nested. - Checks Deferral: A functionality allowing to defer Account and Vault Status Checks until the end of the top-level Checks-deferrable Call. This allows for a transient violation of the Account solvency or Vault constraints. -## Credit Vault Connector Specification +## Ethereum Vault Connector Specification -1. An Owner of the group of 256 accounts is recorded only once upon the first interaction of any of its accounts with the CVC. +1. An Owner of the group of 256 accounts is recorded only once upon the first interaction of any of its accounts with the EVC. 1. Only an Account Owner can authorize an Account Operator to operate on behalf of the Account. 1. An Account can have multiple Account Operators. 1. Each Account can have at most 20 Collateral Vaults enabled at a time. @@ -31,49 +31,49 @@ 1. Only an Account Owner or the Account Operator can enable and disable Collateral Vaults for the Account. 1. Only an Account Owner or the Account Operator can enable Controller Vaults for the Account. 1. Only an enabled Controller Vault can disable itself for the Account. -1. Only an Owner or an Operator of the specified Account can call other contract on behalf of the Account through the CVC. +1. Only an Owner or an Operator of the specified Account can call other contract on behalf of the Account through the EVC. 1. If there's only one enabled Controller Vault for an Account, only that Controller can impersonate the Account's call into any of its enabled Collateral Vaults. -1. CVC supports batches which are lists of operations executed atomically one by one. +1. EVC supports batches which are lists of operations executed atomically one by one. 1. Inside each batch item, an Account is specified. The batch function determines whether or not `msg.sender` is authorised to perform operations on this Account. -1. CVC allows to defer Account and Vault Status Checks until the end of the top-level Checks-deferrable Call. That allows for a transient violation of the Account solvency or Vault constraints. +1. EVC allows to defer Account and Vault Status Checks until the end of the top-level Checks-deferrable Call. That allows for a transient violation of the Account solvency or Vault constraints. 1. If the execution is not within a Checks-deferrable Call, Account and Vault Status Checks must be performed immediately. 1. Checks-deferrable Call can be nested up to 10 levels deep. 1. Account Status Checks can be deferred for at most 20 Accounts at a time. 1. Vault Status Checks can be deferred for at most 20 Vaults at a time. -1. If there's only one enabled Controller Vault for an Account, CVC allows currently enabled Controller to forgive the Account Status Check if it's deferred. -1. CVC allows a Vault to forgive the Vault Status Check for itself if it's deferred. +1. If there's only one enabled Controller Vault for an Account, EVC allows currently enabled Controller to forgive the Account Status Check if it's deferred. +1. EVC allows a Vault to forgive the Vault Status Check for itself if it's deferred. 1. Simulation functions do not modify the state. -1. CVC allows anyone to execute arbitrary calldata that was signed by the Account Owner or Account Operator. +1. EVC allows anyone to execute arbitrary calldata that was signed by the Account Owner or Account Operator. -NOTE: In order to borrow, a user must enable a Controller. From then on, whenever the user wants to perform an action that may affect thir solvency, the Controller must be consulted (the Account Status Check must be performed) in order to determine whether the action is allowed, or whether it should be blocked since it would make the account insolvent. The Account Status Check may be requested by the liability vault by calling the CVC which determines whether the check should be deferred until the very end of the top-level checks-deferrable call (if applicable) or performed immediately. +NOTE: In order to borrow, a user must enable a Controller. From then on, whenever the user wants to perform an action that may affect thir solvency, the Controller must be consulted (the Account Status Check must be performed) in order to determine whether the action is allowed, or whether it should be blocked since it would make the account insolvent. The Account Status Check may be requested by the liability vault by calling the EVC which determines whether the check should be deferred until the very end of the top-level checks-deferrable call (if applicable) or performed immediately. NOTE: Enabling a Controller submits the account to the rules encoded in the Controller contract's code. All the funds in all enabled Collateral Vaults are now indirectly under control of the Controller Vault. NOTE: Only the Controller can disable itself for the Account. This should typically happen upon an Account repaying its debt in full. -NOTE: The protocol deliberately doesn't enforce specific properties about the assets being used as collateral or liabilities. CVC users can therefore create vaults backed by irregular asset classes, such as NFTs, uncollateralised IOUs, or synthetics. +NOTE: The protocol deliberately doesn't enforce specific properties about the assets being used as collateral or liabilities. EVC users can therefore create vaults backed by irregular asset classes, such as NFTs, uncollateralised IOUs, or synthetics. -NOTE: Because the CVC contract can be made to invoke any arbitrary target contract with any arbitrary calldata, it should never be given any privileges, or hold any ETH or tokens. +NOTE: Because the EVC contract can be made to invoke any arbitrary target contract with any arbitrary calldata, it should never be given any privileges, or hold any ETH or tokens. -## Credit Vault Specification +## Vault Specification -1. When a user requests to perform an operation such as borrow, a Credit Vault must call into the CVC in order to ensure that the Account has enabled this vault as a Controller. For that purpose `getCurrentOnBehalfOfAccount` or `isControllerEnabled` functions can be used. -1. Due to the fact that only the Controller can disable itself for the Account, a Credit Vault must implement a standard `disableController` function that can be called by a user in order to disable the Controller for the Account if vault-specific conditions are met (typically, the vault must check whether the Account has repaid its debt in full). -1. After each operation affecting the Account's solvency, a Credit Vault must invoke the CVC in order to request the Account Status Check. The CVC determines whether the check should be deferred until the very end of the top-level checks-deferrable call (if applicable) or performed immediately. -1. Credit Vault must implement `checkAccountStatus` function which gets called for the accounts which have enabled this vault as Controller. The function receives the Account address and the list of Collateral Vaults enabled for the Account. The function must determine whether or not the Account is in an acceptable state by returning the magic value or throwing an exception. If the vault is deposit-only, the function should always return the appropriate magic value. -1. Credit Vault may implement `checkVaultStatus` function which gets called if the vault requests that via the CVC. The CVC determines whether the check should be deferred until the very end of the top-level checks-deferrable call (if applicable) or performed immediately. This is an optional functionality that allows the vault to enforce its constraints (like supply/borrow caps, invariants checks etc.). Vault Status Check must always be requested by the vault after each operation affecting the vault's state. The `checkVaultStatus` function must determine whether or not the Vault is in an acceptable state by returning the magic value or throwing an exception. If the vault doesn't implement this function, the vault mustn't request the Vault Status Check. +1. When a user requests to perform an operation such as borrow, a Vault must call into the EVC in order to ensure that the Account has enabled this vault as a Controller. For that purpose `getCurrentOnBehalfOfAccount` or `isControllerEnabled` functions can be used. +1. Due to the fact that only the Controller can disable itself for the Account, a Vault must implement a standard `disableController` function that can be called by a user in order to disable the Controller for the Account if vault-specific conditions are met (typically, the vault must check whether the Account has repaid its debt in full). +1. After each operation affecting the Account's solvency, a Vault must invoke the EVC in order to request the Account Status Check. The EVC determines whether the check should be deferred until the very end of the top-level checks-deferrable call (if applicable) or performed immediately. +1. Vault must implement `checkAccountStatus` function which gets called for the accounts which have enabled this vault as Controller. The function receives the Account address and the list of Collateral Vaults enabled for the Account. The function must determine whether or not the Account is in an acceptable state by returning the magic value or throwing an exception. If the vault is deposit-only, the function should always return the appropriate magic value. +1. Vault may implement `checkVaultStatus` function which gets called if the vault requests that via the EVC. The EVC determines whether the check should be deferred until the very end of the top-level checks-deferrable call (if applicable) or performed immediately. This is an optional functionality that allows the vault to enforce its constraints (like supply/borrow caps, invariants checks etc.). Vault Status Check must always be requested by the vault after each operation affecting the vault's state. The `checkVaultStatus` function must determine whether or not the Vault is in an acceptable state by returning the magic value or throwing an exception. If the vault doesn't implement this function, the vault mustn't request the Vault Status Check. 1. In order to evaluate the Vault Status, `checkVaultStatus` may need access to a snapshot of the initial vault state which should be taken at the beginning of the action that requires the check. -1. Credit Vault may either be called directly or via the CVC. In order to support sub-accounts, operators, impersonation and permits, vaults can be invoked via the CVC's `call`, `batch`, `impersonate`, or `permit` functions, which will then execute the desired operations on the vault. However, in this case the vault will see the CVC as the `msg.sender`. When a vault detects that `msg.sender` is the CVC, it should call back into the CVC to retrieve current `onBehalfOfAccount` using `getCurrentOnBehalfOfAccount()`. `onBehalfOfAccount` indicates the account that has been authenticated by the CVC. The vault should consider this the true value of `msg.sender` for authorisation purposes. -1. In more complex cases, to avoid status-check-related issues, vaults may choose to always be invoked via the CVC, or use the `callback` function when being called directly. It will ensure the Account and Vault Status Checks are always deferred until the end of the top-level call. +1. Vault may either be called directly or via the EVC. In order to support sub-accounts, operators, impersonation and permits, vaults can be invoked via the EVC's `call`, `batch`, `impersonate`, or `permit` functions, which will then execute the desired operations on the vault. However, in this case the vault will see the EVC as the `msg.sender`. When a vault detects that `msg.sender` is the EVC, it should call back into the EVC to retrieve current `onBehalfOfAccount` using `getCurrentOnBehalfOfAccount()`. `onBehalfOfAccount` indicates the account that has been authenticated by the EVC. The vault should consider this the true value of `msg.sender` for authorisation purposes. +1. In more complex cases, to avoid status-check-related issues, vaults may choose to always be invoked via the EVC, or use the `callback` function when being called directly. It will ensure the Account and Vault Status Checks are always deferred until the end of the top-level call. -NOTE: It may be tempting to allow a large set of collateral assets for a Credit Vault. However, vault creators must be careful about which assets they accept. A malicious Credit Vault could lie about the amount of assets it holds, or reject liquidations when a user is in violation. For this reason, vaults should restrict allowed collaterals to a known-good set of audited addresses, or lookup the addresses in a registry or factory contract to ensure they were created by known-good, audited contracts. +NOTE: It may be tempting to allow a large set of collateral assets for a Vault. However, vault creators must be careful about which assets they accept. A malicious Vault could lie about the amount of assets it holds, or reject liquidations when a user is in violation. For this reason, vaults should restrict allowed collaterals to a known-good set of audited addresses, or lookup the addresses in a registry or factory contract to ensure they were created by known-good, audited contracts. -NOTE: There is a subtle complication that Credit Vault implementations should consider if they use reentrancy guards (which is recommended). When a vault is invoked without Status Checks being deferred (i.e. vault called directly, not via the CVC), then when it calls `require(Account|Vault)StatusCheck` (or similar) on the CVC, the CVC may immediately call back into the vault's `check(Account|Vault)Status` function. A normal reentrancy guard would fail upon re-entering at this point. Because of this, the vault implementation should relax the reentrancy modifier to allow `check(Account|Vault)Status` call while invoking `require(Account|Vault)StatusCheck`. +NOTE: There is a subtle complication that Vault implementations should consider if they use reentrancy guards (which is recommended). When a vault is invoked without Status Checks being deferred (i.e. vault called directly, not via the EVC), then when it calls `require(Account|Vault)StatusCheck` (or similar) on the EVC, the EVC may immediately call back into the vault's `check(Account|Vault)Status` function. A normal reentrancy guard would fail upon re-entering at this point. Because of this, the vault implementation should relax the reentrancy modifier to allow `check(Account|Vault)Status` call while invoking `require(Account|Vault)StatusCheck`. NOTE: It may be critical to protect `check(Account|Vault)Status` functions against reentrancy (depends on individual implementation). For abundance of caution it is recommended to include the following checks as well: -`require(msg.sender == address(cvc) && cvc.areChecksInProgress());` +`require(msg.sender == address(evc) && evc.areChecksInProgress());` NOTE: Care should be taken not to transfer any assets to the Accounts other than the Account Owner (ID 0). Otherwise, the assets may be lost. If unsure, a vault may call `getAccountOwner()` function that returns an address of the Account Owner. -NOTE: If a Credit Vault attempted to read the Collateral or Controller sets of an Account in order to enforce some policy of its own, then it is possible that a user could defer checks in a batch in order to be able to transiently violate them to satisfy the Credit Vault's policy. For this reason, Credit Vaults should not rely on the Controller or Collateral sets of an Account if checks are deferred. +NOTE: If a Vault attempted to read the Collateral or Controller sets of an Account in order to enforce some policy of its own, then it is possible that a user could defer checks in a batch in order to be able to transiently violate them to satisfy the Vault's policy. For this reason, Vaults should not rely on the Controller or Collateral sets of an Account if checks are deferred. diff --git a/docs/whitepaper.md b/docs/whitepaper.md index 8f665241..cd87543f 100644 --- a/docs/whitepaper.md +++ b/docs/whitepaper.md @@ -1,4 +1,4 @@ -# Credit Vault Connector (CVC) +# Ethereum Vault Connector (EVC) Mick de Graaf, Kasper Pawlowski, Dariusz Glowinski, Michael Bentley, Doug Hoyte @@ -31,27 +31,27 @@ Mick de Graaf, Kasper Pawlowski, Dariusz Glowinski, Michael Bentley, Doug Hoyte * [Transient Storage](#transient-storage) * [Security Considerations](#security-considerations) * [Authentication by Vaults](#authentication-by-vaults) - * [CVC Contract Privileges](#cvc-contract-privileges) + * [EVC Contract Privileges](#evc-contract-privileges) * [Read-only Re-entrancy](#read-only-re-entrancy) ## Introduction -The Credit Vault Connector (CVC) is an attempt to distill the core functionality required for a lending market into a foundational layer that can be used as a base building block for many diverse protocols. The CVC is primarily a mediator between Credit Vaults, which are contracts that implement the ERC-4626 interface and contain a small amount of additional logic for interfacing with other vaults. +The Ethereum Vault Connector (EVC) is an attempt to distill the core functionality required for a lending market into a foundational layer that can be used as a base building block for many diverse protocols. The EVC is primarily a mediator between Vaults, which are contracts that implement the ERC-4626 interface and contain a small amount of additional logic for interfacing with other vaults. -In order to borrow from a vault, users must attach their accounts and various collateral vaults to this borrowed-from vault via the CVC. From then on, whenever a user wants to perform an action such as removing collateral, the liability vault (called the "controller") will be consulted in order to determine whether the action is allowed, or whether it should be blocked since it would make the account insolvent. +In order to borrow from a vault, users must attach their accounts and various collateral vaults to this borrowed-from vault via the EVC. From then on, whenever a user wants to perform an action such as removing collateral, the liability vault (called the "controller") will be consulted in order to determine whether the action is allowed, or whether it should be blocked since it would make the account insolvent. -In addition to vault mediation, the CVC contains the functionality required to build flexible products, both for EOAs and smart contracts. Here are some of the benefits of building on the CVC: +In addition to vault mediation, the EVC contains the functionality required to build flexible products, both for EOAs and smart contracts. Here are some of the benefits of building on the EVC: * Batching. Multiple operations can be performed within a single batch operation, even those that concurrently affect multiple vaults. This is more convenient for UI users (no need for smart wallets), more gas efficient, and allows deferring liquidity check until the end of the batch (for flash rebalancing, setting up leveraged positions, etc) -* Simulations were a prized feature of the Euler V1 UI. The CVC exposes the optimal interface for simulating the effects of a set of operations and pre-visualising their effects in a UI. -* Sub-accounts were also a widely appreciated feature of Euler V1. They allowed users to create multiple isolated positions within their single parent account, and easily rebalance collateral/liabilities between them (no approvals needed). The CVC will allow users of any participating protocol to use sub-accounts, without requiring any special logic to be implemented by vaults. +* Simulations were a prized feature of the Euler V1 UI. The EVC exposes the optimal interface for simulating the effects of a set of operations and pre-visualising their effects in a UI. +* Sub-accounts were also a widely appreciated feature of Euler V1. They allowed users to create multiple isolated positions within their single parent account, and easily rebalance collateral/liabilities between them (no approvals needed). The EVC will allow users of any participating protocol to use sub-accounts, without requiring any special logic to be implemented by vaults. * Operators allow users to attach external contracts to act on behalf of a sub-account. This is a generalisation of the E/DToken approval system and will unlock powerful functionality, even for EOAs. We have sketched out many possible use-cases to ensure that this system is fully general. For example, stop-loss/take-profit/trailing-stop/etc modifiers can be added to positions, or entire layered position managers can be built on top. * Gasless transactions (meta-transactions) can be supported for both EOAs and contract wallets. -* The protocol deliberately doesn't enforce specific properties about the assets being used as collateral or liabilities. CVC users can therefore create vaults backed by irregular asset classes, such as NFTs, uncollateralised IOUs, or synthetics. +* The protocol deliberately doesn't enforce specific properties about the assets being used as collateral or liabilities. EVC users can therefore create vaults backed by irregular asset classes, such as NFTs, uncollateralised IOUs, or synthetics. * As well as the primary liquidity enforcement interface, there is an additional vault status check hook which allows vaults to enforce global-concern limits such as supply caps. These checks can also be deferred so that transient violations that are gone at the end of the transaction do not cause a failure. * A common language for liquidations. If vaults choose, they can implement a core liquidation interface that will allow them to rely on an existing network of liquidators to keep their depositors safe. -* The CVC has been carefully designed to support nested vaults without exposing a reentrancy-based attack surface. This will allow Credit Vaults to be used as the underlying asset for other Credit Vaults. Among other things, this will provide the basis for a "base yield" feature of Euler V2 where lower-risk assets can optionally be used as components of higher-yielding products. +* The EVC has been carefully designed to support nested vaults without exposing a reentrancy-based attack surface. This will allow Vaults to be used as the underlying asset for other Vaults. Among other things, this will provide the basis for a "base yield" feature of Euler V2 where lower-risk assets can optionally be used as components of higher-yielding products. As well as providing the above features to a common base ecosystem, their re-use also keeps a substantial amount of complexity out of the core lending/borrowing contracts, leaving them free to focus on their differentiating factors such as pricing and risk management. @@ -59,14 +59,14 @@ As well as providing the above features to a common base ecosystem, their re-use ## Controller -The primary task of the CVC is to maintain a user's voluntary associations with vaults. Typically, a user will deposit funds into one or more collateral vaults, and call `enableCollateral` for each that is intended to be used as a collateral. This adds the vault to the given account's collateral set. Users should obviously be careful which vaults they deposit to, since a malicious vault could refuse to return their funds. +The primary task of the EVC is to maintain a user's voluntary associations with vaults. Typically, a user will deposit funds into one or more collateral vaults, and call `enableCollateral` for each that is intended to be used as a collateral. This adds the vault to the given account's collateral set. Users should obviously be careful which vaults they deposit to, since a malicious vault could refuse to return their funds. -After simply depositing and enabling collaterals, users are not obligated or bound in any way by the CVC, and could freely withdraw funds from the vaults and/or call `disableCollateral` to remove the vaults from the account's collateral set. +After simply depositing and enabling collaterals, users are not obligated or bound in any way by the EVC, and could freely withdraw funds from the vaults and/or call `disableCollateral` to remove the vaults from the account's collateral set. However, suppose a user wants to take out a borrow from a separate vault. In this case, the user must call `enableController` to add this vault to the account's controller set. This is a significant action because the user is now entirely submitting the account to the rules encoded in the controller vault's code. All the funds in all the collateral vaults are now indirectly under control of the controller vault. In particular, if a user attempts to withdraw collateral or `disableCollateral` to remove a vault from the collateral set, the controller could cause the transaction to fail. Moreover, the controller can allow the collateral to be seized in order to repay the debt, using [impersonate](#impersonate). -* When requested to perform an action such as borrow, a liability vault must call into the CVC's `isControllerEnabled` function to ensure that the account has in fact enabled the vault as a controller. -* Only the controller itself can call `disableController` on the CVC. This should typically happen upon an account repaying its debt in full. Vaults must be coded carefully to not have edge cases such as unrepayable dust, otherwise accounts could become permanently associated with a controller. +* When requested to perform an action such as borrow, a liability vault must call into the EVC's `isControllerEnabled` function to ensure that the account has in fact enabled the vault as a controller. +* Only the controller itself can call `disableController` on the EVC. This should typically happen upon an account repaying its debt in full. Vaults must be coded carefully to not have edge cases such as unrepayable dust, otherwise accounts could become permanently associated with a controller. ## Account Status Checks @@ -81,11 +81,11 @@ To encourage borrowing, it may be tempting to allow a large set of collateral as ### Execution Flow -Although the vaults themselves implement `checkAccountStatus`, there is no need for them to invoke this function directly. It will be called by the CVC when necessary. Instead, after performing any operation that could affect an account's liquidity, a vault should invoke `requireAccountStatusCheck` on the CVC to schedule a future callback. Additionally, operations that can affect the liquidity of a *separate* account will need their own `requireAccountStatusCheck` calls. +Although the vaults themselves implement `checkAccountStatus`, there is no need for them to invoke this function directly. It will be called by the EVC when necessary. Instead, after performing any operation that could affect an account's liquidity, a vault should invoke `requireAccountStatusCheck` on the EVC to schedule a future callback. Additionally, operations that can affect the liquidity of a *separate* account will need their own `requireAccountStatusCheck` calls. -Upon a `requireAccountStatusCheck` call, the CVC will determine whether the current execution context is in a batch and if so, it will defer checking the status for this account until the end of the execution context. Otherwise, the account status check will be performed immediately. +Upon a `requireAccountStatusCheck` call, the EVC will determine whether the current execution context is in a batch and if so, it will defer checking the status for this account until the end of the execution context. Otherwise, the account status check will be performed immediately. -There is a subtle complication that vault implementations should consider if they use reentrancy guards (which is recommended). When a vault is invoked *without* account status checks being deferred (ie, directly, not via the CVC), then when it calls `requireAccountStatusCheck` on the CVC, the CVC may immediately call back into the vault's `checkAccountStatus` function. A normal reentrancy guard would fail upon re-entering at this point. Because of this, the vault reference implementation relaxes the reentrancy modifier to allow `checkAccountStatus` call while invoking `requireAccountStatusCheck`. +There is a subtle complication that vault implementations should consider if they use reentrancy guards (which is recommended). When a vault is invoked *without* account status checks being deferred (ie, directly, not via the EVC), then when it calls `requireAccountStatusCheck` on the EVC, the EVC may immediately call back into the vault's `checkAccountStatus` function. A normal reentrancy guard would fail upon re-entering at this point. Because of this, the vault reference implementation relaxes the reentrancy modifier to allow `checkAccountStatus` call while invoking `requireAccountStatusCheck`. ### Single Controller @@ -124,9 +124,9 @@ Secondly, some types of checks require an initial snapshot of the vault state be Vaults must expose an external `checkVaultStatus` function. The vault should evaluate application-specific logic to determine whether or not the vault is in an acceptable state. If so, it should return a special magic success value (the function selector for the `checkVaultStatus` method), otherwise throw an exception. -Although the vaults themselves implement `checkVaultStatus`, there is no need for them to invoke this function directly. It will be called by the CVC when necessary. Instead, after performing any operation that could affect the vault's status, a vault should invoke `requireVaultStatusCheck` on the CVC to schedule a future callback. +Although the vaults themselves implement `checkVaultStatus`, there is no need for them to invoke this function directly. It will be called by the EVC when necessary. Instead, after performing any operation that could affect the vault's status, a vault should invoke `requireVaultStatusCheck` on the EVC to schedule a future callback. -Upon receiving a `requireVaultStatusCheck` call, the CVC will determine whether the current execution context is in a batch and if so, it will defer checking the status for this vault until the end of the execution context. Otherwise, the vault status check will be performed immediately. +Upon receiving a `requireVaultStatusCheck` call, the EVC will determine whether the current execution context is in a batch and if so, it will defer checking the status for this vault until the end of the execution context. Otherwise, the vault status check will be performed immediately. In order to evaluate the vault status, `checkVaultStatus` may need access to a snapshot of the initial vault state. If so, the recommended pattern as implemented in the reference vaults is as follows: @@ -135,20 +135,20 @@ In order to evaluate the vault status, `checkVaultStatus` may need access to a s * The vault should then call `requireVaultStatusCheck` * When the `checkVaultStatus` callback is invoked, it should evaluate the vault status by unpacking the snapshot data stored in transient storage and compare it against the current state of the vault, and return a special magic success value, or revert if there is a violation. -As with the account status check, there is a subtle complication that vault implementations should consider if they use reentrancy guards (which is recommended). When a vault is invoked *without* vault status checks being deferred (ie, directly, not via the CVC), then when it calls `requireVaultStatusCheck` on the CVC, the CVC may immediately call back into the vault's `checkVaultStatus` function. A normal reentrancy guard would fail upon re-entering at this point. Because of this, the vault reference implementation relaxes the reentrancy modifier to allow `checkVaultStatus` call while invoking `requireVaultStatusCheck`. +As with the account status check, there is a subtle complication that vault implementations should consider if they use reentrancy guards (which is recommended). When a vault is invoked *without* vault status checks being deferred (ie, directly, not via the EVC), then when it calls `requireVaultStatusCheck` on the EVC, the EVC may immediately call back into the vault's `checkVaultStatus` function. A normal reentrancy guard would fail upon re-entering at this point. Because of this, the vault reference implementation relaxes the reentrancy modifier to allow `checkVaultStatus` call while invoking `requireVaultStatusCheck`. ## Execution ### Batches -At the time of this writing, public/private keypair Ethereum accounts (EOAs) cannot directly perform multiple operations within a single transaction, except by invoking a smart contract that will do so on their behalf. The CVC exposes a `batch` function that allows multiple operations to be executed together. This has several advantages for users: +At the time of this writing, public/private keypair Ethereum accounts (EOAs) cannot directly perform multiple operations within a single transaction, except by invoking a smart contract that will do so on their behalf. The EVC exposes a `batch` function that allows multiple operations to be executed together. This has several advantages for users: * Atomicity: The user knows that either all of the operations in a batch will execute, or none of them will, so there is no risk of being left with partial or inconsistent positions. * Gas savings: If contracts are invoked multiple times, then the cost of "cold" access can be amortised across all of the invocations. * Status check deferrals: Sometimes multiple operations in a batch may require status checks or it is more convenient or efficient to perform some operation that would leave an account/vault in an invalid state, but fix this state in a subsequent operation in a batch. For example, you may want to perform withdrawal and borrow in one batch or borrow and swap *before* you deposit your collateral. With batches, these checks can be performed once at the end of a batch (which can also itself be more gas efficient). -Batches can be composed of both calls to the CVC itself and external calls (when the `targetContract` is not the CVC). Calling the CVC is how users can enable collateral from within a batch, for example. In order to preseve `msg.sender`, CVC self-`call`s are in fact done with `delegatecall` (except for [permit](#permits)). +Batches can be composed of both calls to the EVC itself and external calls (when the `targetContract` is not the EVC). Calling the EVC is how users can enable collateral from within a batch, for example. In order to preseve `msg.sender`, EVC self-`call`s are in fact done with `delegatecall` (except for [permit](#permits)). Batches will often be a mixture of external calls, some of which call vaults and some of which call other unrelated contracts. For example, a user might withdraw from one vault, then perform a swap on Uniswap, and then deposit into another vault. @@ -156,19 +156,19 @@ Batches will often be a mixture of external calls, some of which call vaults and Inside each batch item, an `onBehalfOfAccount` can be specified. The `batch` function will determine whether or not `msg.sender` is authorised to perform operations on this account: -* If `msg.sender` has never before interacted with the CVC, if it shares the first 19 bytes with the `onBehalfOfAccount`, then `onBehalfOfAccount` is considered to be a *sub-account* of `msg.sender` and therefore `msg.sender` is authorised. Upon that first interaction with the CVC, `msg.sender` address is stored in CVC's storage as an owner of the group of 256 accounts having the same first 19 bytes. -* If `msg.sender` has interacted with the CVC before and it shares the first 19 bytes with the `onBehalfOfAccount`, its address is supposed to match the one stored in the CVC's storage. If it does, then it is authorised. +* If `msg.sender` has never before interacted with the EVC, if it shares the first 19 bytes with the `onBehalfOfAccount`, then `onBehalfOfAccount` is considered to be a *sub-account* of `msg.sender` and therefore `msg.sender` is authorised. Upon that first interaction with the EVC, `msg.sender` address is stored in EVC's storage as an owner of the group of 256 accounts having the same first 19 bytes. +* If `msg.sender` has interacted with the EVC before and it shares the first 19 bytes with the `onBehalfOfAccount`, its address is supposed to match the one stored in the EVC's storage. If it does, then it is authorised. * If `msg.sender` has previously been authorized as an [operator](#operators) for the `onBehalfOfAccount`, it is authorised. -* If the `msg.sender` is the CVC itself, then this must be from a permit and the effective sender is taken from the execution context +* If the `msg.sender` is the EVC itself, then this must be from a permit and the effective sender is taken from the execution context * In all other cases, the batch item is invalid, and the entire batch transaction will fail. #### Sub-Accounts Sub-accounts allow users access to multiple (up to 256) virtual accounts that are entirely isolated from one another. Although multiple separate Ethereum addresses could be used, sub-accounts are often more efficient and convenient because their operations can be grouped together in a batch without setting approvals. -Since an account can only have one controller at a time (except for mid-transaction), sub-accounts are also the only way an Ethereum account can hold multiple Credit Vault borrows concurrently. +Since an account can only have one controller at a time (except for mid-transaction), sub-accounts are also the only way an Ethereum account can hold multiple Vault borrows concurrently. -The CVC also maintains a look-up mapping `ownerLookup` so sub-accounts can be easily resolved to owner addresses, on or off chain. This mapping is populated when an address interacts with the CVC for the first time. In order to resolve a sub-account, the `getAccountOwner` function should be called with a sub-account address. It will either return the account's primary address, or revert with an error if the account has not yet interacted with the CVC. +The EVC also maintains a look-up mapping `ownerLookup` so sub-accounts can be easily resolved to owner addresses, on or off chain. This mapping is populated when an address interacts with the EVC for the first time. In order to resolve a sub-account, the `getAccountOwner` function should be called with a sub-account address. It will either return the account's primary address, or revert with an error if the account has not yet interacted with the EVC. #### Operators @@ -180,20 +180,20 @@ An operator is similar to a controller, in that an account gives considerable pe ### Permits -Instead of invoking the CVC directly, signed messages called `permit`s can also be provided to the CVC. Permits can be invoked by anyone, but they will execute on behalf of the signer of the permit message. They are useful for implementing "gasless" transactions. +Instead of invoking the EVC directly, signed messages called `permit`s can also be provided to the EVC. Permits can be invoked by anyone, but they will execute on behalf of the signer of the permit message. They are useful for implementing "gasless" transactions. Permits are EIP-712 typed data messages with the following fields: * `signer`: The address to execute the operation on behalf of. * `nonceNamespace` and `nonce`: Values used to prevent replaying permit messages, and for sequencing (see below) * `deadline`: A timestamp after which the permit becomes invalid. -* `data`: Arbitrary calldata that will be used to invoke the CVC. Typically this will contain an invocation of the `batch` method. +* `data`: Arbitrary calldata that will be used to invoke the EVC. Typically this will contain an invocation of the `batch` method. There are two types of signature methods supported by permits: ECDSA, which is used by EOAs, and [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) which is used by smart contract wallets. In both cases, the `permit` method can be invoked by any unprivileged address, such as a keeper. If the signature is exactly 65 bytes long, an `ecrecover` is attempted. If the recovered address does not match `signer`, or for signature lengths other than 65, then an ERC-1271 verification is attempted, by staticcalling `isValidSignature` on `signer`. -After verifying `deadline`, `signature`, `nonce`, and `nonceNamespace`, the `data` will be used to invoke the CVC. Although other methods can be invoked, the most general purpose method to use is `batch`. Inside a batch, each batch item can specify an `onBehalfOfAccount` address. This can be any sub-account of the owner, meaning a signed batch can affect multiple sub-accounts, just as a regular non-permit invocation of `batch` can. If the `signer` is an operator of another account, then the other account can also be specified -- this could be useful for gaslessly invoking a restricted "hot wallet" operator. +After verifying `deadline`, `signature`, `nonce`, and `nonceNamespace`, the `data` will be used to invoke the EVC. Although other methods can be invoked, the most general purpose method to use is `batch`. Inside a batch, each batch item can specify an `onBehalfOfAccount` address. This can be any sub-account of the owner, meaning a signed batch can affect multiple sub-accounts, just as a regular non-permit invocation of `batch` can. If the `signer` is an operator of another account, then the other account can also be specified -- this could be useful for gaslessly invoking a restricted "hot wallet" operator. -Internally, `permit` works by `call`ing `address(this)`, which has the effect of setting `msg.sender` to the CVC itself, indicating to the CVC that the actually authenticated user should be taken from the execution context. It is critical that a permit is the only way for this to happen, otherwise the authentication could be bypassed. Note that the CVC can be self-invoked via a batch, but this is done with *delegatecall*, leaving `msg.sender` unchanged. +Internally, `permit` works by `call`ing `address(this)`, which has the effect of setting `msg.sender` to the EVC itself, indicating to the EVC that the actually authenticated user should be taken from the execution context. It is critical that a permit is the only way for this to happen, otherwise the authentication could be bypassed. Note that the EVC can be self-invoked via a batch, but this is done with *delegatecall*, leaving `msg.sender` unchanged. #### Nonce Namespaces @@ -219,9 +219,9 @@ Permit messages can be cancelled in three ways: ### call -The `call` function on the CVC allows users to invoke functions on vaults and other target smart contracts. Unless the `msg.sender` is the same as the `onBehalfOfAccount`, users *must* go through this function rather than calling the vaults directly. This is because vaults themselves don't understand sub-accounts or operators, and defer their authorisation logic to the CVC (see the [Authentication By Vaults](#authentication-by-vaults) section). +The `call` function on the EVC allows users to invoke functions on vaults and other target smart contracts. Unless the `msg.sender` is the same as the `onBehalfOfAccount`, users *must* go through this function rather than calling the vaults directly. This is because vaults themselves don't understand sub-accounts or operators, and defer their authorisation logic to the EVC (see the [Authentication By Vaults](#authentication-by-vaults) section). -`call` also allows users to invoke arbitrary contracts, with arbitrary calldata. These other contracts will see the CVC as `msg.sender`. For this reason, it is critical that the CVC itself never be given any special privileges, or hold any token or ETH balances (except for a few corner cases where it is temporarily safe, see the [CVC Contract Privileges](#cvc-contract-privileges) section). +`call` also allows users to invoke arbitrary contracts, with arbitrary calldata. These other contracts will see the EVC as `msg.sender`. For this reason, it is critical that the EVC itself never be given any special privileges, or hold any token or ETH balances (except for a few corner cases where it is temporarily safe, see the [EVC Contract Privileges](#evc-contract-privileges) section). ### impersonate @@ -233,9 +233,9 @@ This is accomplished by the controller vault calling `impersonate`. It passes in ### Execution Contexts -As mentioned above, when interacting with the CVC, it is often useful to defer certain checks until the end of the transaction. This allows a user to temporarily violate some of the constraints imposed by the vaults, so long as the constraints are satisfied at the end of the transaction. +As mentioned above, when interacting with the EVC, it is often useful to defer certain checks until the end of the transaction. This allows a user to temporarily violate some of the constraints imposed by the vaults, so long as the constraints are satisfied at the end of the transaction. -In order to implement this, the CVC maintains an *execution context* which holds two sets of addresses in regular or transient storage (if supported): `accountStatusChecks` and `vaultStatusChecks`. The execution context will also contain the `onBehalfOfAccount` that has currently been authenticated, so it can be queried by a vault (see [Security Considerations](#security-considerations)). +In order to implement this, the EVC maintains an *execution context* which holds two sets of addresses in regular or transient storage (if supported): `accountStatusChecks` and `vaultStatusChecks`. The execution context will also contain the `onBehalfOfAccount` that has currently been authenticated, so it can be queried by a vault (see [Security Considerations](#security-considerations)). An execution context will exist for the duration of the batch, and is then discarded. Only one execution context can exist at a time. However, nesting batches *is* allowed (see below). @@ -248,17 +248,17 @@ Additionally, the execution context contains some locks that protect critical re #### Nested Execution Contexts -If a vault or other contract is invoked via the CVC, and that contract in turn re-invokes the CVC to call another vault/contract, then the execution context is considered nested. The execution context is however *not* treated as a stack. The sets of deferred account and vault status checks are added to, and only after unwinding the final execution context will they be validated. +If a vault or other contract is invoked via the EVC, and that contract in turn re-invokes the EVC to call another vault/contract, then the execution context is considered nested. The execution context is however *not* treated as a stack. The sets of deferred account and vault status checks are added to, and only after unwinding the final execution context will they be validated. Internally, the execution context stores a batch depth value that increases each time a batch is started and decreases when it ends. Only once it decreases to the initial value of `0` do the deferred checks get performed. Nesting batches is useful because otherwise calling contracts from a batch that themselves want to defer checks would be more complicated, and these contracts would need two code-paths: one that defers and one that doesn't. -The previous value of `onBehalfOfAccount` is stored in a local "cache" variable and is subsequently restored after invoking the target contract. This ensures that contracts can rely on the `onBehalfOfAccount` at all times when `msg.sender` is the CVC (see [Authentication by Vaults](#authentication-by-vaults)). However, when `msg.sender` is not the CVC, vaults cannot rely on `onBehalfOfAccount` because it could have been changed by a nested context. +The previous value of `onBehalfOfAccount` is stored in a local "cache" variable and is subsequently restored after invoking the target contract. This ensures that contracts can rely on the `onBehalfOfAccount` at all times when `msg.sender` is the EVC (see [Authentication by Vaults](#authentication-by-vaults)). However, when `msg.sender` is not the EVC, vaults cannot rely on `onBehalfOfAccount` because it could have been changed by a nested context. #### checksInProgress -The CVC invokes the `checkAccountStatus` and `checkVaultStatus` callbacks using `call` instead of `staticcall` so that controllers can checkpoint state during these operations. However, because of this there is a danger that the CVC could be re-entered during these operations, either directly by a controller, or indirectly by a contract it invokes. +The EVC invokes the `checkAccountStatus` and `checkVaultStatus` callbacks using `call` instead of `staticcall` so that controllers can checkpoint state during these operations. However, because of this there is a danger that the EVC could be re-entered during these operations, either directly by a controller, or indirectly by a contract it invokes. -Because of this, the CVC's execution context maintains a `checksInProgress` mutex that is acquired before unwinding the sets of accounts and vaults that need checking. This mutex is also checked during operations that alter these sets. If it did not do this, then information cached by the higher-level unwinding function (such as the sizes of the sets) could become inconsistent with the underlying storage, which could be used to bypass these critical checks. +Because of this, the EVC's execution context maintains a `checksInProgress` mutex that is acquired before unwinding the sets of accounts and vaults that need checking. This mutex is also checked during operations that alter these sets. If it did not do this, then information cached by the higher-level unwinding function (such as the sizes of the sets) could become inconsistent with the underlying storage, which could be used to bypass these critical checks. #### impersonationInProgress @@ -268,17 +268,17 @@ However, when interacting with complicated vaults that may invoke external contr In order to simplify the implementation of this check, the `impersonateLock` mutex is locked while invoking a collateral vault during the `impersonate` flow. While locked, no accounts' collateral or controller sets can be modified. -Additionally, during an impersonation, the CVC cannot be re-entered via `call`, `batch`, `impersonate`, or `permit`. +Additionally, during an impersonation, the EVC cannot be re-entered via `call`, `batch`, `impersonate`, or `permit`. #### Extra Information -The execution context also indicates some extra information, which could be useful if a contract wants to know extra information about the CVC's authentication. This includes information about simulation, operator, and permit status. +The execution context also indicates some extra information, which could be useful if a contract wants to know extra information about the EVC's authentication. This includes information about simulation, operator, and permit status. ### Simulations -The CVC also supports executing batches in a "simulation" mode. This is only intended to be invoked "off-chain", and is useful for user interfaces because they can show the user what the expected outcome of a sequence of operations will be. +The EVC also supports executing batches in a "simulation" mode. This is only intended to be invoked "off-chain", and is useful for user interfaces because they can show the user what the expected outcome of a sequence of operations will be. Simulations work by actually performing the requested operations but then reverting, which (if called on-chain) reverts all the effects. Although simple in principle, there are a number of design elements involved: @@ -291,7 +291,7 @@ Simulations work by actually performing the requested operations but then revert ## Transient Storage -In order to maintain the execution context, access to the same variables must occur from different invocations of the CVC. This means that they must be held in storage, and not memory. Unfortunately, storage is expensive compared to memory. Luckily, the EVM protocol may soon specify a new type of memory lifetime: transient storage that is accessible to multiple invocations, but is inexpensive to access. +In order to maintain the execution context, access to the same variables must occur from different invocations of the EVC. This means that they must be held in storage, and not memory. Unfortunately, storage is expensive compared to memory. Luckily, the EVM protocol may soon specify a new type of memory lifetime: transient storage that is accessible to multiple invocations, but is inexpensive to access. In order to take advantage of transient storage, the contracts have been structured to keep all the variables that should be stored in transient storage in a separate base class contract `TransientStorage`. By optionally overriding this at compile-time, both old and new networks can be supported. @@ -301,28 +301,28 @@ In order to take advantage of transient storage, the contracts have been structu ### Authentication by Vaults -Vaults out-source their authentication to the CVC, but are responsible for authorisation themselves. +Vaults out-source their authentication to the EVC, but are responsible for authorisation themselves. -In order to support sub-accounts, operators, and impersonating (ie, liquidations), vaults can be invoked via the CVC's `call`, `batch`, or `impersonate` functions, which will then execute the desired operations on the vault. However, the vault will see the CVC as the `msg.sender`. +In order to support sub-accounts, operators, and impersonating (ie, liquidations), vaults can be invoked via the EVC's `call`, `batch`, or `impersonate` functions, which will then execute the desired operations on the vault. However, the vault will see the EVC as the `msg.sender`. -When a vault detects that `msg.sender` is the CVC, it should call back into the CVC to retrieve the current execution context using `getCurrentOnBehalfOfAccount`. This will tell the vault two things: +When a vault detects that `msg.sender` is the EVC, it should call back into the EVC to retrieve the current execution context using `getCurrentOnBehalfOfAccount`. This will tell the vault two things: -* The `onBehalfOfAccount` which indicates the account that has been authenticated by the CVC. The vault should consider this the "true" value of `msg.sender` for authorisation purposes. +* The `onBehalfOfAccount` which indicates the account that has been authenticated by the EVC. The vault should consider this the "true" value of `msg.sender` for authorisation purposes. * The `controllerEnabled` which indicates whether or not a vault is currently enabled as a controller for the `onBehalfOfAccount` account. This information is needed if the vault is performing an operation (such as a borrow) that requires it to be the controller for an account. The caller of `getCurrentOnBehalfOfAccount` itself passes the vault it is interested in via the `controllerToCheck` parameter. When `controllerToCheck` is set to the zero address, the value returned is always `false`. -### CVC Contract Privileges +### EVC Contract Privileges -Because the CVC contract can be made to invoke any arbitrary target contract with any arbitrary calldata, it should never be given any privileges, or hold any ETH or tokens. +Because the EVC contract can be made to invoke any arbitrary target contract with any arbitrary calldata, it should never be given any privileges, or hold any ETH or tokens. -The only exception to this is mid-transaction inside of a batch. If one batch item temporarily moves ETH or tokens into the CVC, but a subsequent batch item moves it out, then as long as no untrusted code runs in between, it is safe. However, moving tokens to the CVC is often unnecessary because tokens can be moved immediately to their final destination with `transferFrom` and by setting various `recipient` parameters in contracts. +The only exception to this is mid-transaction inside of a batch. If one batch item temporarily moves ETH or tokens into the EVC, but a subsequent batch item moves it out, then as long as no untrusted code runs in between, it is safe. However, moving tokens to the EVC is often unnecessary because tokens can be moved immediately to their final destination with `transferFrom` and by setting various `recipient` parameters in contracts. One exception to this is wrapping ETH into WETH. The deposit method will always credit the caller with the WETH tokens. In this case, the user must transfer the WETH in a subsequent batch item (ideally the batch item immediately after the deposit). -One area where the untrustable CVC address may cause problems is tokens that implement hooks/callbacks, such as ERC-777 tokens. In this case, somebody could install a hook for the CVC as a recipient, and cause inbound transfers to fail, or possibly even be redirected. Although the CVC doesn't attempt to comprehensively solve this, the ERC-1820 registry address is blocked and can not be invoked via `call` or batches. +One area where the untrustable EVC address may cause problems is tokens that implement hooks/callbacks, such as ERC-777 tokens. In this case, somebody could install a hook for the EVC as a recipient, and cause inbound transfers to fail, or possibly even be redirected. Although the EVC doesn't attempt to comprehensively solve this, the ERC-1820 registry address is blocked and can not be invoked via `call` or batches. ### Read-only Re-entrancy -The non-transient storage maintained by the CVC *can* be read while checks are deferred. In particular, this includes the lists of collaterals and controllers registered for a given account. +The non-transient storage maintained by the EVC *can* be read while checks are deferred. In particular, this includes the lists of collaterals and controllers registered for a given account. This should not result in "read-only re-entrancy" problems, because each individual operation will leave these lists in a consistent state. In particular, for a controller to be released, that controller itself must invoke the release, which typically means the debt has been repaid. diff --git a/echidna.yaml b/echidna.yaml index 42343ec1..c9b5f647 100644 --- a/echidna.yaml +++ b/echidna.yaml @@ -3,7 +3,7 @@ testMode: "assertion" #testLimit: 1000 solcArgs: "optimize-runs=10000" deployContracts: [ - ["0xdead", "CreditVaultConnectorEchidna"], + ["0xdead", "EthereumVaultConnectorEchidna"], ["0xbeef", "VaultEchidna"], ["0xbeefbeef", "TargetEchidna"], ["0xbeefbeefbeef", "SignerEchidna"] diff --git a/foundry.toml b/foundry.toml index 0c443535..a5941d97 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,7 +6,7 @@ solc = "0.8.20" optimizer_runs = 10000 ignored_error_codes = ["unreachable"] gas_reports = [ - "CreditVaultConnector" + "EthereumVaultConnector" ] remappings = [ "forge-std/=lib/forge-std/src/", @@ -28,7 +28,7 @@ runs = 1000 [profile.smt.model_checker] engine = "chc" timeout = 100_000 -contracts = {"./src/CreditVaultConnector.sol" = ["CreditVaultConnector"]} +contracts = {"./src/EthereumVaultConnector.sol" = ["EthereumVaultConnector"]} invariants = ["contract", "reentrancy"] targets = [ "assert", diff --git a/package.json b/package.json index 5b091f16..3f522cfc 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "euler-cvc", + "name": "euler-evc", "version": "1.0.0", "main": "index.js", - "repository": "https://github.com/euler-xyz/euler-cvc.git", + "repository": "https://github.com/euler-xyz/euler-evc.git", "author": "Euler Labs", "license": "GPL-2.0-or-later", "scripts": { diff --git a/src/Errors.sol b/src/Errors.sol index d6ff4f38..aa5d8297 100644 --- a/src/Errors.sol +++ b/src/Errors.sol @@ -2,30 +2,30 @@ pragma solidity ^0.8.20; -import "./interfaces/ICreditVaultConnector.sol"; +import "./interfaces/IEthereumVaultConnector.sol"; /// @title Errors /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This contract implements the error messages for the Credit Vault Connector. +/// @notice This contract implements the error messages for the Ethereum Vault Connector. contract Errors { - error CVC_NotAuthorized(); - error CVC_AccountOwnerNotRegistered(); - error CVC_OnBehalfOfAccountNotAuthenticated(); - error CVC_InvalidOperatorStatus(); - error CVC_InvalidNonce(); - error CVC_InvalidAddress(); - error CVC_InvalidTimestamp(); - error CVC_InvalidValue(); - error CVC_InvalidData(); - error CVC_ChecksReentrancy(); - error CVC_ImpersonateReentrancy(); - error CVC_ControllerViolation(); - error CVC_SimulationBatchNested(); - error CVC_RevertedBatchResult( - ICVC.BatchItemResult[] batchItemsResult, - ICVC.BatchItemResult[] accountsStatusResult, - ICVC.BatchItemResult[] vaultsStatusResult + error EVC_NotAuthorized(); + error EVC_AccountOwnerNotRegistered(); + error EVC_OnBehalfOfAccountNotAuthenticated(); + error EVC_InvalidOperatorStatus(); + error EVC_InvalidNonce(); + error EVC_InvalidAddress(); + error EVC_InvalidTimestamp(); + error EVC_InvalidValue(); + error EVC_InvalidData(); + error EVC_ChecksReentrancy(); + error EVC_ImpersonateReentrancy(); + error EVC_ControllerViolation(); + error EVC_SimulationBatchNested(); + error EVC_RevertedBatchResult( + IEVC.BatchItemResult[] batchItemsResult, + IEVC.BatchItemResult[] accountsStatusResult, + IEVC.BatchItemResult[] vaultsStatusResult ); - error CVC_BatchPanic(); - error CVC_EmptyError(); + error EVC_BatchPanic(); + error EVC_EmptyError(); } diff --git a/src/CreditVaultConnector.sol b/src/EthereumVaultConnector.sol similarity index 90% rename from src/CreditVaultConnector.sol rename to src/EthereumVaultConnector.sol index 94579d16..e4f20b14 100644 --- a/src/CreditVaultConnector.sol +++ b/src/EthereumVaultConnector.sol @@ -6,14 +6,14 @@ import "./Set.sol"; import "./Events.sol"; import "./Errors.sol"; import "./TransientStorage.sol"; -import "./interfaces/ICreditVaultConnector.sol"; -import "./interfaces/ICreditVault.sol"; +import "./interfaces/IEthereumVaultConnector.sol"; +import "./interfaces/IVault.sol"; import "./interfaces/IERC1271.sol"; -/// @title CreditVaultConnector +/// @title EthereumVaultConnector /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This contract implements the Credit Vault Connector. -contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { +/// @notice This contract implements the Ethereum Vault Connector. +contract EthereumVaultConnector is Events, Errors, TransientStorage, IEVC { using ExecutionContext for EC; using Set for SetStorage; @@ -21,7 +21,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // CONSTANTS // /////////////////////////////////////////////////////////////////////////////////////////////// - string public constant name = "Credit Vault Connector"; + string public constant name = "Ethereum Vault Connector"; string public constant version = "1"; bytes32 public constant PERMIT_TYPEHASH = @@ -50,10 +50,10 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { mapping(address account => SetStorage) internal accountCollaterals; mapping(address account => SetStorage) internal accountControllers; - // Every Ethereum address has 256 accounts in the CVC (including the primary account - called the owner). + // Every Ethereum address has 256 accounts in the EVC (including the primary account - called the owner). // Each account has an account ID from 0-255, where 0 is the owner account's ID. In order to compute the account // addresses, the account ID is treated as a uint256 and XORed (exclusive ORed) with the Ethereum address. - // In order to record the owner of a group of 256 accounts, the CVC uses a definition of a address prefix. + // In order to record the owner of a group of 256 accounts, the EVC uses a definition of a address prefix. // An address prefix is a part of an address having the first 19 bytes common with any of the 256 account // addresses belonging to the same group. // account/152 -> prefix/152 @@ -83,14 +83,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { /////////////////////////////////////////////////////////////////////////////////////////////// /// @notice A modifier that allows only the address recorded as an owner of the address prefix to call the function. - /// @dev The owner of an address prefix is an address that matches the address that has previously been recorded (or will be) as an owner in the ownerLookup. In case of the self-call in the permit() function, the CVC address becomes msg.sender hence the "true" caller address (that is permit message signer) is taken from the execution context. + /// @dev The owner of an address prefix is an address that matches the address that has previously been recorded (or will be) as an owner in the ownerLookup. In case of the self-call in the permit() function, the EVC address becomes msg.sender hence the "true" caller address (that is permit message signer) is taken from the execution context. /// @param addressPrefix The address prefix for which it is checked whether the caller is the owner. modifier onlyOwner(uint152 addressPrefix) virtual { { // calculate a phantom address from the address prefix which can be used as an input to internal functions address account = address(uint160(addressPrefix) << 8); - // CVC can only be msg.sender during the self-call in the permit() function. in that case, + // EVC can only be msg.sender during the self-call in the permit() function. in that case, // the "true" sender address (that is the permit message signer) is taken from the execution context address msgSender = address(this) == msg.sender ? executionContext.getOnBehalfOfAccount() @@ -102,10 +102,10 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { if (owner == address(0)) { setAccountOwnerInternal(account, msgSender); } else if (owner != msgSender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } else { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } @@ -113,11 +113,11 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { } /// @notice A modifier that allows only the owner or an operator of the account to call the function. - /// @dev The owner of an account is an address that matches first 19 bytes of the account address and has been recorded (or will be) as an owner in the ownerLookup. An operator of an account is an address that has been authorized by the owner of an account to perform operations on behalf of the owner. In case of the self-call in the permit() function, the CVC address becomes msg.sender hence the "true" caller address (that is permit message signer) is taken from the execution context. + /// @dev The owner of an account is an address that matches first 19 bytes of the account address and has been recorded (or will be) as an owner in the ownerLookup. An operator of an account is an address that has been authorized by the owner of an account to perform operations on behalf of the owner. In case of the self-call in the permit() function, the EVC address becomes msg.sender hence the "true" caller address (that is permit message signer) is taken from the execution context. /// @param account The address of the account for which it is checked whether the caller is the owner or an operator. modifier onlyOwnerOrOperator(address account) virtual { { - // CVC can only be msg.sender during the self-call in the permit() function. in that case, + // EVC can only be msg.sender during the self-call in the permit() function. in that case, // the "true" sender address (that is the permit message signer) is taken from the execution context address msgSender = address(this) == msg.sender ? executionContext.getOnBehalfOfAccount() @@ -129,12 +129,12 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { if (owner == address(0)) { setAccountOwnerInternal(account, msgSender); } else if (owner != msgSender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } else if ( !isAccountOperatorAuthorizedInternal(account, msgSender) ) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } @@ -148,11 +148,11 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { address controller = accountControllers[account].firstElement; if (numOfControllers != 1) { - revert CVC_ControllerViolation(); + revert EVC_ControllerViolation(); } if (controller != msg.sender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } @@ -165,11 +165,11 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { EC context = executionContext; if (context.areChecksInProgress()) { - revert CVC_ChecksReentrancy(); + revert EVC_ChecksReentrancy(); } if (context.isImpersonationInProgress()) { - revert CVC_ImpersonateReentrancy(); + revert EVC_ImpersonateReentrancy(); } } @@ -181,7 +181,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { EC contextCache = executionContext; if (contextCache.areChecksInProgress()) { - revert CVC_ChecksReentrancy(); + revert EVC_ChecksReentrancy(); } executionContext = contextCache @@ -199,17 +199,17 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Execution internals - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getRawExecutionContext() external view returns (uint256 context) { context = EC.unwrap(executionContext); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getCurrentCallDepth() external view returns (uint256) { return executionContext.getCallDepth(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getCurrentOnBehalfOfAccount( address controllerToCheck ) public view returns (address onBehalfOfAccount, bool controllerEnabled) { @@ -217,7 +217,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // for safety, revert if no account has been auhenticated if (onBehalfOfAccount == address(0)) { - revert CVC_OnBehalfOfAccountNotAuthenticated(); + revert EVC_OnBehalfOfAccountNotAuthenticated(); } controllerEnabled = controllerToCheck == address(0) @@ -225,29 +225,29 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { : accountControllers[onBehalfOfAccount].contains(controllerToCheck); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function areChecksInProgress() external view returns (bool) { return executionContext.areChecksInProgress(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isImpersonationInProgress() external view returns (bool) { return executionContext.isImpersonationInProgress(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isOperatorAuthenticated() external view returns (bool) { return executionContext.isOperatorAuthenticated(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isSimulationInProgress() external view returns (bool) { return executionContext.isSimulationInProgress(); } // Owners and operators - /// @inheritdoc ICVC + /// @inheritdoc IEVC function haveCommonOwner( address account, address otherAccount @@ -255,21 +255,21 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { return haveCommonOwnerInternal(account, otherAccount); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getAddressPrefix(address account) external pure returns (uint152) { return getAddressPrefixInternal(account); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getAccountOwner( address account ) external view returns (address owner) { owner = getAccountOwnerInternal(account); - if (owner == address(0)) revert CVC_AccountOwnerNotRegistered(); + if (owner == address(0)) revert EVC_AccountOwnerNotRegistered(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getNonce( uint152 addressPrefix, uint256 nonceNamespace @@ -277,7 +277,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { return nonceLookup[addressPrefix][nonceNamespace]; } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getOperator( uint152 addressPrefix, address operator @@ -285,7 +285,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { return operatorLookup[addressPrefix][operator]; } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isAccountOperatorAuthorized( address account, address operator @@ -293,27 +293,27 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { return isAccountOperatorAuthorizedInternal(account, operator); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function setNonce( uint152 addressPrefix, uint256 nonceNamespace, uint256 nonce ) public payable virtual onlyOwner(addressPrefix) { if (nonceLookup[addressPrefix][nonceNamespace] >= nonce) { - revert CVC_InvalidNonce(); + revert EVC_InvalidNonce(); } nonceLookup[addressPrefix][nonceNamespace] = nonce; emit NonceUsed(addressPrefix, nonce); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function setOperator( uint152 addressPrefix, address operator, uint256 accountOperatorAuthorized ) public payable virtual onlyOwner(addressPrefix) { - // if CVC is msg.sender (during the self-call in the permit() function), the owner address will + // if EVC is msg.sender (during the self-call in the permit() function), the owner address will // be taken from the storage which must be storing the correct owner address address owner = address(this) == msg.sender ? ownerLookup[addressPrefix] @@ -323,13 +323,13 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { if ( operator == address(0) || haveCommonOwnerInternal(owner, operator) ) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } if ( operatorLookup[addressPrefix][operator] == accountOperatorAuthorized ) { - revert CVC_InvalidOperatorStatus(); + revert EVC_InvalidOperatorStatus(); } else { operatorLookup[addressPrefix][operator] = accountOperatorAuthorized; @@ -341,21 +341,21 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { } } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function setAccountOperator( address account, address operator, bool authorized ) public payable virtual onlyOwnerOrOperator(account) { - // if CVC is msg.sender (during the self-call in the permit() function), it won't have the common owner - // with the account as it would mean that the CVC itself signed the ERC-1271 message which is not + // if EVC is msg.sender (during the self-call in the permit() function), it won't have the common owner + // with the account as it would mean that the EVC itself signed the ERC-1271 message which is not // possible. hence in that case, the owner address will be taken from the storage which // must be storing the correct owner address address owner = haveCommonOwnerInternal(account, msg.sender) ? msg.sender : getAccountOwnerInternal(account); - // if CVC is msg.sender (during the self-call in the permit() function), it acts as if it + // if EVC is msg.sender (during the self-call in the permit() function), it acts as if it // was an owner, meaning it can authorize and deauthorize operators as per signed data. // if it's an operator calling, it can only make changes for itself hence must be equal to msg.sender if ( @@ -363,14 +363,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { operator != msg.sender && address(this) != msg.sender ) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } // the operator can neither be zero address nor can belong to one of 256 accounts of the owner if ( operator == address(0) || haveCommonOwnerInternal(owner, operator) ) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } uint152 addressPrefix = getAddressPrefixInternal(account); @@ -383,7 +383,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { : oldAccountOperatorAuthorized & ~bitMask; if (oldAccountOperatorAuthorized == newAccountOperatorAuthorized) { - revert CVC_InvalidOperatorStatus(); + revert EVC_InvalidOperatorStatus(); } else { operatorLookup[addressPrefix][ operator @@ -399,14 +399,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Collaterals management - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getCollaterals( address account ) external view returns (address[] memory) { return accountCollaterals[account].get(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isCollateralEnabled( address account, address vault @@ -414,12 +414,12 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { return accountCollaterals[account].contains(vault); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function enableCollateral( address account, address vault ) public payable virtual nonReentrant onlyOwnerOrOperator(account) { - if (vault == address(this)) revert CVC_InvalidAddress(); + if (vault == address(this)) revert EVC_InvalidAddress(); if (accountCollaterals[account].insert(vault)) { emit CollateralStatus(account, vault, true); @@ -427,7 +427,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { requireAccountStatusCheck(account); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function disableCollateral( address account, address vault @@ -440,14 +440,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Controllers management - /// @inheritdoc ICVC + /// @inheritdoc IEVC function getControllers( address account ) external view returns (address[] memory) { return accountControllers[account].get(); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isControllerEnabled( address account, address vault @@ -455,12 +455,12 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { return accountControllers[account].contains(vault); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function enableController( address account, address vault ) public payable virtual nonReentrant onlyOwnerOrOperator(account) { - if (vault == address(this)) revert CVC_InvalidAddress(); + if (vault == address(this)) revert EVC_InvalidAddress(); if (accountControllers[account].insert(vault)) { emit ControllerStatus(account, vault, true); @@ -468,7 +468,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { requireAccountStatusCheck(account); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function disableController( address account ) public payable virtual nonReentrant { @@ -480,7 +480,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Permit - /// @inheritdoc ICVC + /// @inheritdoc IEVC function permit( address signer, uint256 nonceNamespace, @@ -493,22 +493,22 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { uint152 addressPrefix = getAddressPrefixInternal(signer); if (signer == address(0) || !isSignerValid(signer)) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } if ( nonce == type(uint256).max || ++nonceLookup[addressPrefix][nonceNamespace] != nonce ) { - revert CVC_InvalidNonce(); + revert EVC_InvalidNonce(); } if (deadline < block.timestamp) { - revert CVC_InvalidTimestamp(); + revert EVC_InvalidTimestamp(); } if (data.length == 0) { - revert CVC_InvalidData(); + revert EVC_InvalidData(); } bytes32 permitHash = getPermitHash( @@ -524,12 +524,12 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { signer != recoverECDSASigner(permitHash, signature) && !isValidERC1271Signature(signer, permitHash, signature) ) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } emit NonceUsed(addressPrefix, nonce); - // CVC address becomes msg.sender for the duration this self-call + // EVC address becomes msg.sender for the duration this self-call (bool success, bytes memory result) = callWithContextInternal( address(this), signer, @@ -544,7 +544,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Calls forwarding - /// @inheritdoc ICVC + /// @inheritdoc IEVC function callback( address onBehalfOfAccount, uint256 value, @@ -552,7 +552,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { ) public payable virtual nonReentrant returns (bytes memory result) { // cannot be called within the self-call of the permit() if (address(this) == msg.sender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } EC contextCache = executionContext; @@ -581,7 +581,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { executionContext = contextCache; } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function call( address targetContract, address onBehalfOfAccount, @@ -589,7 +589,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { bytes calldata data ) public payable virtual nonReentrant returns (bytes memory result) { if (address(this) == targetContract || msg.sender == targetContract) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } EC contextCache = executionContext; @@ -617,7 +617,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { executionContext = contextCache; } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function impersonate( address targetCollateral, address onBehalfOfAccount, @@ -625,7 +625,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { bytes calldata data ) public payable virtual nonReentrant returns (bytes memory result) { if (address(this) == targetCollateral) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } EC contextCache = executionContext; @@ -655,7 +655,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { executionContext = contextCache; } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function batch( BatchItem[] calldata items ) public payable virtual nonReentrant { @@ -676,7 +676,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Simulations - /// @inheritdoc ICVC + /// @inheritdoc IEVC function batchRevert( BatchItem[] calldata items ) public payable virtual nonReentrant { @@ -687,7 +687,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { EC contextCache = executionContext; if (contextCache.areChecksDeferred()) { - revert CVC_SimulationBatchNested(); + revert EVC_SimulationBatchNested(); } executionContext = contextCache @@ -703,14 +703,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { executionContext = contextCache; - revert CVC_RevertedBatchResult( + revert EVC_RevertedBatchResult( batchItemsResult, accountsStatusResult, vaultsStatusResult ); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function batchSimulation( BatchItem[] calldata items ) @@ -728,8 +728,8 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { ); if (success) { - revert CVC_BatchPanic(); - } else if (bytes4(result) != CVC_RevertedBatchResult.selector) { + revert EVC_BatchPanic(); + } else if (bytes4(result) != EVC_RevertedBatchResult.selector) { revertBytes(result); } @@ -746,14 +746,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Account Status Check - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isAccountStatusCheckDeferred( address account ) external view returns (bool) { return accountStatusChecks.contains(account); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireAccountStatusCheck( address account ) public payable virtual nonReentrantChecks { @@ -764,7 +764,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { } } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireAccountStatusCheckNow( address account ) public payable virtual nonReentrantChecks { @@ -772,7 +772,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { requireAccountStatusCheckInternal(account); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireAllAccountsStatusCheckNow() public payable @@ -782,7 +782,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { checkStatusAll(SetType.Account); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function forgiveAccountStatusCheck( address account ) public payable virtual nonReentrantChecks onlyController(account) { @@ -791,14 +791,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { // Vault Status Check - /// @inheritdoc ICVC + /// @inheritdoc IEVC function isVaultStatusCheckDeferred( address vault ) external view returns (bool) { return vaultStatusChecks.contains(vault); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireVaultStatusCheck() public payable @@ -812,7 +812,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { } } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireVaultStatusCheckNow() public payable @@ -823,7 +823,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { requireVaultStatusCheckInternal(msg.sender); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireAllVaultsStatusCheckNow() public payable @@ -833,7 +833,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { checkStatusAll(SetType.Vault); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function forgiveVaultStatusCheck() public payable @@ -843,7 +843,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { vaultStatusChecks.remove(msg.sender); } - /// @inheritdoc ICVC + /// @inheritdoc IEVC function requireAccountAndVaultStatusCheck( address account ) public payable virtual nonReentrantChecks { @@ -871,7 +871,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { value != type(uint256).max && value > address(this).balance ) { - revert CVC_InvalidValue(); + revert EVC_InvalidValue(); } else if (value == type(uint256).max) { value = address(this).balance; } @@ -885,7 +885,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { EC contextCache = executionContext; - // CVC can only be msg.sender after the self-call in the permit() function. in that case, + // EVC can only be msg.sender after the self-call in the permit() function. in that case, // the "true" sender address (that is the permit message signer) is taken from the execution context address msgSender = address(this) == msg.sender ? contextCache.getOnBehalfOfAccount() @@ -928,7 +928,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { returns (bool success, bytes memory result) { if (targetContract == ERC1820_REGISTRY) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } (success, result) = callWithContextInternal( @@ -951,7 +951,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { returns (bool success, bytes memory result) { if (!accountCollaterals[onBehalfOfAccount].contains(targetCollateral)) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } (success, result) = callWithContextInternal( @@ -1022,12 +1022,12 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { address controller = accountControllers[account].firstElement; if (numOfControllers == 0) return (true, ""); - else if (numOfControllers > 1) revert CVC_ControllerViolation(); + else if (numOfControllers > 1) revert EVC_ControllerViolation(); bool success; (success, result) = controller.call( abi.encodeCall( - ICreditVault.checkAccountStatus, + IVault.checkAccountStatus, (account, accountCollaterals[account].get()) ) ); @@ -1036,7 +1036,7 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { success && result.length == 32 && abi.decode(result, (bytes32)) == - bytes32(ICreditVault.checkAccountStatus.selector); + bytes32(IVault.checkAccountStatus.selector); } function requireAccountStatusCheckInternal( @@ -1056,14 +1056,14 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { ) internal returns (bool isValid, bytes memory result) { bool success; (success, result) = vault.call( - abi.encodeCall(ICreditVault.checkVaultStatus, ()) + abi.encodeCall(IVault.checkVaultStatus, ()) ); isValid = success && result.length == 32 && abi.decode(result, (bytes32)) == - bytes32(ICreditVault.checkVaultStatus.selector); + bytes32(IVault.checkVaultStatus.selector); } function requireVaultStatusCheckInternal(address vault) internal virtual { @@ -1282,6 +1282,6 @@ contract CreditVaultConnector is Events, Errors, TransientStorage, ICVC { revert(add(32, errMsg), mload(errMsg)) } } - revert CVC_EmptyError(); + revert EVC_EmptyError(); } } diff --git a/src/Events.sol b/src/Events.sol index ffda46f8..65cb5778 100644 --- a/src/Events.sol +++ b/src/Events.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.20; /// @title Events /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This contract implements the events for the Credit Vault Connector. +/// @notice This contract implements the events for the Ethereum Vault Connector. contract Events { event OwnerRegistered(uint152 indexed addressPrefix, address indexed owner); event NonceUsed(uint152 indexed addressPrefix, uint256 nonce); diff --git a/src/ExecutionContext.sol b/src/ExecutionContext.sol index 3f090dd5..c8d9fde3 100644 --- a/src/ExecutionContext.sol +++ b/src/ExecutionContext.sol @@ -6,7 +6,7 @@ type EC is uint256; /// @title ExecutionContext /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This library provides functions for managing the execution context in the Credit Vault Connector. +/// @notice This library provides functions for managing the execution context in the Ethereum Vault Connector. /// @dev The execution context is a bit field that stores the following information: /// @dev - call depth - used to indicate the number of nested checks-deferrable calls /// @dev - on behalf of account - an account on behalf of which the currently executed operation is being performed diff --git a/src/TransientStorage.sol b/src/TransientStorage.sol index 677b0f20..e2780358 100644 --- a/src/TransientStorage.sol +++ b/src/TransientStorage.sol @@ -7,7 +7,7 @@ import "./Set.sol"; /// @title TransientStorage /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This contract provides transient storage for the Credit Vault Connector. +/// @notice This contract provides transient storage for the Ethereum Vault Connector. /// @dev All the variables in this contract are considered transient meaning that their state does not change between transactions. abstract contract TransientStorage { enum SetType { diff --git a/src/interfaces/ICreditVaultConnector.sol b/src/interfaces/IEthereumVaultConnector.sol similarity index 98% rename from src/interfaces/ICreditVaultConnector.sol rename to src/interfaces/IEthereumVaultConnector.sol index ac34698b..9f755ee8 100644 --- a/src/interfaces/ICreditVaultConnector.sol +++ b/src/interfaces/IEthereumVaultConnector.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.20; -/// @title ICVC +/// @title IEVC /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This interface defines the methods for the Credit Vault Connector. -interface ICVC { +/// @notice This interface defines the methods for the Ethereum Vault Connector. +interface IEVC { /// @notice A struct representing a batch item. /// @dev Each batch item represents a single operation to be performed within a checks deferred context. struct BatchItem { @@ -13,7 +13,7 @@ interface ICVC { address targetContract; /// @notice The account on behalf of which the operation is to be performed. msg.sender must be authorized to act on behalf. address onBehalfOfAccount; - /// @notice The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the CVC contract will be forwarded. + /// @notice The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the EVC contract will be forwarded. uint256 value; /// @notice The encoded data which is called on the target contract. bytes data; @@ -79,7 +79,7 @@ interface ICVC { function getAddressPrefix(address account) external pure returns (uint152); /// @notice Returns the owner for the specified account. - /// @dev The function will revert if the owner is not registered. Registration of the owner happens on the initial interaction with the CVC that requires authentication of an owner. + /// @dev The function will revert if the owner is not registered. Registration of the owner happens on the initial interaction with the EVC that requires authentication of an owner. /// @param account The address of the account whose owner is being retrieved. /// @return owner The address of the account owner. An account owner is an EOA/smart contract which address matches the first 19 bytes of the account address. function getAccountOwner(address account) external view returns (address); @@ -205,14 +205,14 @@ interface ICVC { /// @param account The address for which the calling controller is being disabled. function disableController(address account) external payable; - /// @notice Executes signed arbitrary data by self-calling into the CVC. - /// @dev Low-level call function is used to execute the arbitrary data signed by the owner or the operator on the CVC contract. During that call, CVC becomes msg.sender. + /// @notice Executes signed arbitrary data by self-calling into the EVC. + /// @dev Low-level call function is used to execute the arbitrary data signed by the owner or the operator on the EVC contract. During that call, EVC becomes msg.sender. /// @param signer The address signing the permit message (ECDSA) or verifying the permit message signature (ERC-1271). It's also the owner or the operator of all the accounts for which authentication will be needed during the execution of the arbitrary data call. /// @param nonceNamespace The nonce namespace for which the nonce is being used. /// @param nonce The nonce for the given account and nonce namespace. /// @param deadline The timestamp after which the permit is considered expired. - /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the CVC contract will be forwarded. - /// @param data The encoded data which is self-called on the CVC contract. + /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the EVC contract will be forwarded. + /// @param data The encoded data which is self-called on the EVC contract. /// @param signature The signature of the data signed by the signer. function permit( address signer, @@ -228,7 +228,7 @@ interface ICVC { /// @dev This function defers the account and vault status checks (it's a checks-deferrable call) and increases the call depth for the duration of the call. If the initiall call depth is 0, the account and vault status checks are performed after the call. /// @dev This function can be used to defer account and vault status checks by providing calldata and the context with which the msg.sender will be called back. /// @param onBehalfOfAccount The address of the account which will be set in the context. It assumes the msg.sender has authenticated the account themselves. - /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the CVC contract will be forwarded. + /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the EVC contract will be forwarded. /// @param data The encoded data which is called on the msg.sender /// @return result The result of the call. function callback( @@ -242,7 +242,7 @@ interface ICVC { /// @dev This function can be used to interact with any contract while checks deferred. Only the owner or an operator of the account can call this function. /// @param targetContract The address of the contract to be called. /// @param onBehalfOfAccount The address of the account for which it is checked whether msg.sender is authorized to act on behalf. - /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the CVC contract will be forwarded. + /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the EVC contract will be forwarded. /// @param data The encoded data which is called on the target contract. /// @return result The result of the call. function call( @@ -257,7 +257,7 @@ interface ICVC { /// @dev This function can be used to interact with any contract while checks deferred as long as the contract is enabled as a collateral of the account and the msg.sender is the only enabled controller of the account. /// @param targetCollateral The collateral address to be called. /// @param onBehalfOfAccount The address of the account for which it is checked whether msg.sender is authorized to act on behalf. - /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the CVC contract will be forwarded. + /// @param value The amount of ETH to be forwarded with the call. If the value is type(uint256).max, the whole balance of the EVC contract will be forwarded. /// @param data The encoded data which is called on the target contract. /// @return result The result of the call. function impersonate( diff --git a/src/interfaces/ICreditVault.sol b/src/interfaces/IVault.sol similarity index 88% rename from src/interfaces/ICreditVault.sol rename to src/interfaces/IVault.sol index 3da6244d..f0cdc8d9 100644 --- a/src/interfaces/ICreditVault.sol +++ b/src/interfaces/IVault.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.20; -/// @title ICreditVault +/// @title IVault /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice This interface defines the methods for the Credit Vault for the purpose of integration with the Credit Vault Connector. -interface ICreditVault { +/// @notice This interface defines the methods for the Vault for the purpose of integration with the Ethereum Vault Connector. +interface IVault { /// @notice Disables a controller (this vault) for an account. /// @dev A controller is a vault that has been chosen for an account to have special control over account’s balances in the enabled collaterals vaults. User calls this function in order for the vault to disable itself for the account if the conditions are met (i.e. user has repaid debt in full). /// @param account The address for which the controller is being disabled. diff --git a/test/echidna/CreditVaultConnector.t.sol b/test/echidna/EthereumVaultConnector.t.sol similarity index 50% rename from test/echidna/CreditVaultConnector.t.sol rename to test/echidna/EthereumVaultConnector.t.sol index 383ec5fe..258087db 100644 --- a/test/echidna/CreditVaultConnector.t.sol +++ b/test/echidna/EthereumVaultConnector.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.20; -import "../../src/interfaces/ICreditVault.sol"; -import "../../src/interfaces/ICreditVaultConnector.sol"; +import "../../src/interfaces/IVault.sol"; +import "../../src/interfaces/IEthereumVaultConnector.sol"; import "../../src/interfaces/IERC1271.sol"; -import "../cvc/CreditVaultConnectorEchidna.sol"; +import "../evc/EthereumVaultConnectorEchidna.sol"; interface IHevm { function prank(address) external; @@ -24,221 +24,221 @@ contract TargetEchidna { fallback() external payable {} } -contract VaultEchidna is ICreditVault { +contract VaultEchidna is IVault { IHevm internal constant hevm = IHevm(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)); - CreditVaultConnectorEchidna internal constant cvc = - CreditVaultConnectorEchidna(payable(address(0xdead))); + EthereumVaultConnectorEchidna internal constant evc = + EthereumVaultConnectorEchidna(payable(address(0xdead))); TargetEchidna internal immutable targetEchidna = TargetEchidna(payable(address(0xbeefbeef))); function disableController(address account) external { - cvc.disableController(account); + evc.disableController(account); } function checkAccountStatus( address account, address[] calldata ) public returns (bytes4) { - // try to reenter the CVC + // try to reenter the EVC uint152 prefix = uint152(uint160(account) >> 8); - uint256 nextNonce = cvc.getNonce(prefix, 0) + 1; + uint256 nextNonce = evc.getNonce(prefix, 0) + 1; hevm.prank(account); - try cvc.setNonce(prefix, 0, nextNonce) {} catch {} + try evc.setNonce(prefix, 0, nextNonce) {} catch {} hevm.prank(account); - try cvc.setOperator(prefix, address(this), 0) {} catch {} + try evc.setOperator(prefix, address(this), 0) {} catch {} hevm.prank(account); - try cvc.setAccountOperator(account, address(this), false) {} catch {} + try evc.setAccountOperator(account, address(this), false) {} catch {} hevm.prank(account); - try cvc.disableCollateral(account, address(this)) {} catch {} + try evc.disableCollateral(account, address(this)) {} catch {} hevm.prank(account); - try cvc.enableCollateral(account, address(this)) {} catch {} + try evc.enableCollateral(account, address(this)) {} catch {} hevm.prank(account); - try cvc.enableController(account, address(this)) {} catch {} + try evc.enableController(account, address(this)) {} catch {} hevm.prank(address(this)); - try cvc.disableController(account) {} catch {} + try evc.disableController(account) {} catch {} - try cvc.callback(account, 0, "") {} catch {} + try evc.callback(account, 0, "") {} catch {} hevm.prank(account); - try cvc.call(address(this), account, 0, "") {} catch {} + try evc.call(address(this), account, 0, "") {} catch {} hevm.prank(address(this)); - try cvc.impersonate(address(this), account, 0, "") {} catch {} + try evc.impersonate(address(this), account, 0, "") {} catch {} - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].targetContract = address(this); items[0].onBehalfOfAccount = account; items[0].value = 0; items[0].data = ""; hevm.prank(account); - try cvc.batch(items) {} catch {} + try evc.batch(items) {} catch {} - try cvc.requireAccountStatusCheck(account) {} catch {} - try cvc.requireAccountStatusCheckNow(account) {} catch {} - try cvc.requireAllAccountsStatusCheckNow() {} catch {} + try evc.requireAccountStatusCheck(account) {} catch {} + try evc.requireAccountStatusCheckNow(account) {} catch {} + try evc.requireAllAccountsStatusCheckNow() {} catch {} hevm.prank(address(this)); - try cvc.forgiveAccountStatusCheck(account) {} catch {} + try evc.forgiveAccountStatusCheck(account) {} catch {} hevm.prank(address(this)); - try cvc.requireVaultStatusCheck() {} catch {} + try evc.requireVaultStatusCheck() {} catch {} hevm.prank(address(this)); - try cvc.requireVaultStatusCheckNow() {} catch {} + try evc.requireVaultStatusCheckNow() {} catch {} - try cvc.requireAllVaultsStatusCheckNow() {} catch {} + try evc.requireAllVaultsStatusCheckNow() {} catch {} hevm.prank(address(this)); - try cvc.forgiveVaultStatusCheck() {} catch {} + try evc.forgiveVaultStatusCheck() {} catch {} hevm.prank(address(this)); - try cvc.requireAccountAndVaultStatusCheck(account) {} catch {} + try evc.requireAccountAndVaultStatusCheck(account) {} catch {} return this.checkAccountStatus.selector; } function checkVaultStatus() public returns (bytes4) { - // try to reenter the CVC + // try to reenter the EVC address account = address(1); uint152 prefix = uint152(uint160(account) >> 8); - uint256 nextNonce = cvc.getNonce(prefix, 0) + 1; + uint256 nextNonce = evc.getNonce(prefix, 0) + 1; hevm.prank(account); - try cvc.setNonce(prefix, 0, nextNonce) {} catch {} + try evc.setNonce(prefix, 0, nextNonce) {} catch {} hevm.prank(account); - try cvc.setOperator(prefix, address(this), 0) {} catch {} + try evc.setOperator(prefix, address(this), 0) {} catch {} hevm.prank(account); - try cvc.setAccountOperator(account, address(this), false) {} catch {} + try evc.setAccountOperator(account, address(this), false) {} catch {} hevm.prank(account); - try cvc.disableCollateral(account, address(this)) {} catch {} + try evc.disableCollateral(account, address(this)) {} catch {} hevm.prank(account); - try cvc.enableCollateral(account, address(this)) {} catch {} + try evc.enableCollateral(account, address(this)) {} catch {} hevm.prank(account); - try cvc.enableController(account, address(this)) {} catch {} + try evc.enableController(account, address(this)) {} catch {} hevm.prank(address(this)); - try cvc.disableController(account) {} catch {} + try evc.disableController(account) {} catch {} - try cvc.callback(account, 0, "") {} catch {} + try evc.callback(account, 0, "") {} catch {} hevm.prank(account); - try cvc.call(address(this), account, 0, "") {} catch {} + try evc.call(address(this), account, 0, "") {} catch {} hevm.prank(address(this)); - cvc.enableCollateral(account, address(this)); - try cvc.impersonate(address(this), account, 0, "") {} catch {} + evc.enableCollateral(account, address(this)); + try evc.impersonate(address(this), account, 0, "") {} catch {} - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].targetContract = address(this); items[0].onBehalfOfAccount = account; items[0].value = 0; items[0].data = ""; hevm.prank(account); - try cvc.batch(items) {} catch {} + try evc.batch(items) {} catch {} - try cvc.requireAccountStatusCheck(account) {} catch {} - try cvc.requireAccountStatusCheckNow(account) {} catch {} - try cvc.requireAllAccountsStatusCheckNow() {} catch {} + try evc.requireAccountStatusCheck(account) {} catch {} + try evc.requireAccountStatusCheckNow(account) {} catch {} + try evc.requireAllAccountsStatusCheckNow() {} catch {} hevm.prank(address(this)); - try cvc.forgiveAccountStatusCheck(account) {} catch {} + try evc.forgiveAccountStatusCheck(account) {} catch {} hevm.prank(address(this)); - try cvc.requireVaultStatusCheck() {} catch {} + try evc.requireVaultStatusCheck() {} catch {} hevm.prank(address(this)); - try cvc.requireVaultStatusCheckNow() {} catch {} + try evc.requireVaultStatusCheckNow() {} catch {} - try cvc.requireAllVaultsStatusCheckNow() {} catch {} + try evc.requireAllVaultsStatusCheckNow() {} catch {} hevm.prank(address(this)); - try cvc.forgiveVaultStatusCheck() {} catch {} + try evc.forgiveVaultStatusCheck() {} catch {} hevm.prank(address(this)); - try cvc.requireAccountAndVaultStatusCheck(account) {} catch {} + try evc.requireAccountAndVaultStatusCheck(account) {} catch {} return this.checkVaultStatus.selector; } fallback() external payable { - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); - // try to reenter the CVC + // try to reenter the EVC address account = address(2); uint152 prefix = uint152(uint160(account) >> 8); - uint256 nextNonce = cvc.getNonce(prefix, 0) + 1; + uint256 nextNonce = evc.getNonce(prefix, 0) + 1; hevm.prank(account); - try cvc.setNonce(prefix, 0, nextNonce) {} catch {} + try evc.setNonce(prefix, 0, nextNonce) {} catch {} hevm.prank(account); - try cvc.setOperator(prefix, address(this), 0) {} catch {} + try evc.setOperator(prefix, address(this), 0) {} catch {} hevm.prank(account); - try cvc.setAccountOperator(account, address(this), false) {} catch {} + try evc.setAccountOperator(account, address(this), false) {} catch {} hevm.prank(account); - try cvc.disableCollateral(account, address(this)) {} catch {} + try evc.disableCollateral(account, address(this)) {} catch {} hevm.prank(account); - try cvc.enableCollateral(account, address(this)) {} catch {} + try evc.enableCollateral(account, address(this)) {} catch {} hevm.prank(account); - try cvc.enableController(account, address(this)) {} catch {} + try evc.enableController(account, address(this)) {} catch {} hevm.prank(address(this)); - try cvc.disableController(account) {} catch {} + try evc.disableController(account) {} catch {} hevm.prank(account); - try cvc.call(address(targetEchidna), account, 0, "") {} catch {} + try evc.call(address(targetEchidna), account, 0, "") {} catch {} hevm.prank(account); - try cvc.enableCollateral(account, address(targetEchidna)) {} catch {} + try evc.enableCollateral(account, address(targetEchidna)) {} catch {} hevm.prank(address(this)); - try cvc.impersonate(address(targetEchidna), account, 0, "") {} catch {} + try evc.impersonate(address(targetEchidna), account, 0, "") {} catch {} - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].targetContract = address(targetEchidna); items[0].onBehalfOfAccount = account; items[0].value = 0; items[0].data = ""; hevm.prank(account); - try cvc.batch(items) {} catch {} + try evc.batch(items) {} catch {} - try cvc.requireAccountStatusCheck(account) {} catch {} - try cvc.requireAccountStatusCheckNow(account) {} catch {} - try cvc.requireAllAccountsStatusCheckNow() {} catch {} + try evc.requireAccountStatusCheck(account) {} catch {} + try evc.requireAccountStatusCheckNow(account) {} catch {} + try evc.requireAllAccountsStatusCheckNow() {} catch {} hevm.prank(address(this)); - try cvc.forgiveAccountStatusCheck(account) {} catch {} + try evc.forgiveAccountStatusCheck(account) {} catch {} hevm.prank(address(this)); - try cvc.requireVaultStatusCheck() {} catch {} + try evc.requireVaultStatusCheck() {} catch {} hevm.prank(address(this)); - try cvc.requireVaultStatusCheckNow() {} catch {} + try evc.requireVaultStatusCheckNow() {} catch {} - try cvc.requireAllVaultsStatusCheckNow() {} catch {} + try evc.requireAllVaultsStatusCheckNow() {} catch {} hevm.prank(address(this)); - try cvc.forgiveVaultStatusCheck() {} catch {} + try evc.forgiveVaultStatusCheck() {} catch {} hevm.prank(address(this)); - try cvc.requireAccountAndVaultStatusCheck(account) {} catch {} + try evc.requireAccountAndVaultStatusCheck(account) {} catch {} } receive() external payable {} @@ -247,47 +247,47 @@ contract VaultEchidna is ICreditVault { contract EchidnaTest { IHevm internal constant hevm = IHevm(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)); - CreditVaultConnectorEchidna internal immutable cvc = - CreditVaultConnectorEchidna(payable(address(0xdead))); + EthereumVaultConnectorEchidna internal immutable evc = + EthereumVaultConnectorEchidna(payable(address(0xdead))); VaultEchidna internal immutable vaultEchidna = VaultEchidna(payable(address(0xbeef))); SignerEchidna internal immutable signerEchidna = SignerEchidna(address(0xbeefbeefbeef)); function enableCollateral(address account, address vault) public payable { - if (account == address(0) || account == address(cvc)) return; + if (account == address(0) || account == address(evc)) return; hevm.prank(account); - cvc.enableCollateral(account, vault); + evc.enableCollateral(account, vault); } function disableCollateral(address account, address vault) public payable { - if (account == address(0) || account == address(cvc)) return; + if (account == address(0) || account == address(evc)) return; hevm.prank(account); - cvc.disableCollateral(account, vault); + evc.disableCollateral(account, vault); } function enableController(address account, address) public payable { - if (account == address(0) || account == address(cvc)) return; + if (account == address(0) || account == address(evc)) return; hevm.prank(account); - cvc.enableController(account, address(vaultEchidna)); + evc.enableController(account, address(vaultEchidna)); } function disableController(address account) public payable { - if (account == address(0) || account == address(cvc)) return; - if (cvc.getControllers(account).length > 0) { - hevm.prank(cvc.getControllers(account)[0]); + if (account == address(0) || account == address(evc)) return; + if (evc.getControllers(account).length > 0) { + hevm.prank(evc.getControllers(account)[0]); } - cvc.disableController(account); + evc.disableController(account); } function permit( bytes calldata data, bytes calldata signature ) public payable { - cvc.permit( + evc.permit( address(signerEchidna), 0, - cvc.getNonce(cvc.getAddressPrefix(address(cvc)), 0) + 1, + evc.getNonce(evc.getAddressPrefix(address(evc)), 0) + 1, block.timestamp, 0, data, @@ -300,10 +300,10 @@ contract EchidnaTest { bytes calldata data ) public payable { if ( - onBehalfOfAccount == address(0) || onBehalfOfAccount == address(cvc) + onBehalfOfAccount == address(0) || onBehalfOfAccount == address(evc) ) return; hevm.prank(address(vaultEchidna)); - cvc.callback(onBehalfOfAccount, 0, data); + evc.callback(onBehalfOfAccount, 0, data); } function call( @@ -311,10 +311,10 @@ contract EchidnaTest { bytes calldata data ) public payable { if ( - onBehalfOfAccount == address(0) || onBehalfOfAccount == address(cvc) + onBehalfOfAccount == address(0) || onBehalfOfAccount == address(evc) ) return; hevm.prank(onBehalfOfAccount); - cvc.call(address(vaultEchidna), onBehalfOfAccount, 0, data); + evc.call(address(vaultEchidna), onBehalfOfAccount, 0, data); } function impersonate( @@ -322,27 +322,27 @@ contract EchidnaTest { bytes calldata data ) public payable { if ( - onBehalfOfAccount == address(0) || onBehalfOfAccount == address(cvc) + onBehalfOfAccount == address(0) || onBehalfOfAccount == address(evc) ) return; hevm.prank(onBehalfOfAccount); - cvc.enableCollateral(onBehalfOfAccount, address(vaultEchidna)); + evc.enableCollateral(onBehalfOfAccount, address(vaultEchidna)); hevm.prank(onBehalfOfAccount); - cvc.enableController(onBehalfOfAccount, address(vaultEchidna)); + evc.enableController(onBehalfOfAccount, address(vaultEchidna)); hevm.prank(address(vaultEchidna)); - cvc.impersonate(address(vaultEchidna), onBehalfOfAccount, 0, data); + evc.impersonate(address(vaultEchidna), onBehalfOfAccount, 0, data); } - function batch(ICVC.BatchItem[] calldata items) public payable { + function batch(IEVC.BatchItem[] calldata items) public payable { if (items.length > 0) { - ICVC.BatchItem[] memory _items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory _items = new IEVC.BatchItem[](1); for (uint256 i; i < items.length; ++i) { if ( items[i].onBehalfOfAccount == address(0) || - items[i].onBehalfOfAccount == address(cvc) + items[i].onBehalfOfAccount == address(evc) ) return; } @@ -352,47 +352,47 @@ contract EchidnaTest { _items[0].data = items[0].data; hevm.prank(_items[0].onBehalfOfAccount); - cvc.batch(_items); + evc.batch(_items); - try cvc.batch(items) {} catch {} + try evc.batch(items) {} catch {} } else { - cvc.batch(items); + evc.batch(items); } } function requireAccountStatusCheck(address account) public payable { - cvc.requireAccountStatusCheck(account); + evc.requireAccountStatusCheck(account); } function requireAccountStatusCheckNow(address account) public payable { - cvc.requireAccountStatusCheckNow(account); + evc.requireAccountStatusCheckNow(account); } function requireAllAccountsStatusCheckNow() public payable { - cvc.requireAllAccountsStatusCheckNow(); + evc.requireAllAccountsStatusCheckNow(); } function forgiveAccountStatusCheck(address account) public payable { - cvc.forgiveAccountStatusCheck(account); + evc.forgiveAccountStatusCheck(account); } function requireVaultStatusCheck() public payable { - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); } function requireVaultStatusCheckNow() public payable { - cvc.requireVaultStatusCheckNow(); + evc.requireVaultStatusCheckNow(); } function requireAllVaultsStatusCheckNow() public payable { - cvc.requireAllVaultsStatusCheckNow(); + evc.requireAllVaultsStatusCheckNow(); } function forgiveVaultStatusCheck() public payable { - cvc.forgiveVaultStatusCheck(); + evc.forgiveVaultStatusCheck(); } function requireAccountAndVaultStatusCheck(address account) public payable { - cvc.requireAccountAndVaultStatusCheck(account); + evc.requireAccountAndVaultStatusCheck(account); } } diff --git a/test/cvc/CreditVaultConnectorEchidna.sol b/test/evc/EthereumVaultConnectorEchidna.sol similarity index 94% rename from test/cvc/CreditVaultConnectorEchidna.sol rename to test/evc/EthereumVaultConnectorEchidna.sol index db3d0fef..2e207592 100644 --- a/test/cvc/CreditVaultConnectorEchidna.sol +++ b/test/evc/EthereumVaultConnectorEchidna.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.20; -import "./CreditVaultConnectorScribble.sol"; +import "./EthereumVaultConnectorScribble.sol"; -contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { +contract EthereumVaultConnectorEchidna is EthereumVaultConnectorScribble { using ExecutionContext for EC; using Set for SetStorage; @@ -23,7 +23,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { // calculate a phantom address from the address prefix which can be used as an input to internal functions address account = address(uint160(addressPrefix) << 8); - // CVC can only be msg.sender during the self-call in the permit() function. in that case, + // EVC can only be msg.sender during the self-call in the permit() function. in that case, // the "true" sender address (that is the permit message signer) is taken from the execution context address msgSender = address(this) == msg.sender ? executionContext.getOnBehalfOfAccount() @@ -35,10 +35,10 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { if (owner == address(0)) { setAccountOwnerInternal(account, msgSender); } else if (owner != msgSender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } else { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } @@ -49,7 +49,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { assert(address(this) == msg.sender ? inPermit : true); { - // CVC can only be msg.sender during the self-call in the permit() function. in that case, + // EVC can only be msg.sender during the self-call in the permit() function. in that case, // the "true" sender address (that is the permit message signer) is taken from the execution context address msgSender = address(this) == msg.sender ? executionContext.getOnBehalfOfAccount() @@ -61,12 +61,12 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { if (owner == address(0)) { setAccountOwnerInternal(account, msgSender); } else if (owner != msgSender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } else if ( !isAccountOperatorAuthorizedInternal(account, msgSender) ) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } } @@ -77,7 +77,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { EC contextCache = executionContext; if (contextCache.areChecksInProgress()) { - revert CVC_ChecksReentrancy(); + revert EVC_ChecksReentrancy(); } executionContext = contextCache @@ -130,7 +130,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { ) public payable override nonReentrant returns (bytes memory result) { // copied function body with inserted assertion if (address(this) == msg.sender) { - revert CVC_NotAuthorized(); + revert EVC_NotAuthorized(); } EC contextCache = executionContext; @@ -173,7 +173,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { ) public payable override nonReentrant returns (bytes memory result) { // copied function body with inserted assertion if (address(this) == targetContract || address(this) == msg.sender) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } EC contextCache = executionContext; @@ -214,7 +214,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { bytes calldata data ) public payable override nonReentrant returns (bytes memory result) { if (address(this) == targetCollateral) { - revert CVC_InvalidAddress(); + revert EVC_InvalidAddress(); } EC contextCache = executionContext; @@ -295,7 +295,7 @@ contract CreditVaultConnectorEchidna is CreditVaultConnectorScribble { EC contextCache = executionContext; - // CVC can only be msg.sender after the self-call in the permit() function. in that case, + // EVC can only be msg.sender after the self-call in the permit() function. in that case, // the "true" sender address (that is the permit message signer) is taken from the execution context address msgSender = address(this) == msg.sender ? contextCache.getOnBehalfOfAccount() diff --git a/test/cvc/CreditVaultConnectorHarness.sol b/test/evc/EthereumVaultConnectorHarness.sol similarity index 96% rename from test/cvc/CreditVaultConnectorHarness.sol rename to test/evc/EthereumVaultConnectorHarness.sol index b6b18500..6bfb525b 100644 --- a/test/cvc/CreditVaultConnectorHarness.sol +++ b/test/evc/EthereumVaultConnectorHarness.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.20; -import "./CreditVaultConnectorScribble.sol"; +import "./EthereumVaultConnectorScribble.sol"; import "../utils/mocks/Vault.sol"; -// helper contract that allows to set CVC's internal state and overrides original -// CVC functions in order to verify the account and vault checks -contract CreditVaultConnectorHarness is CreditVaultConnectorScribble { +// helper contract that allows to set EVC's internal state and overrides original +// EVC functions in order to verify the account and vault checks +contract EthereumVaultConnectorHarness is EthereumVaultConnectorScribble { using ExecutionContext for EC; using Set for SetStorage; diff --git a/test/cvc/CreditVaultConnectorScribble.sol b/test/evc/EthereumVaultConnectorScribble.sol similarity index 97% rename from test/cvc/CreditVaultConnectorScribble.sol rename to test/evc/EthereumVaultConnectorScribble.sol index d77ead58..996d9fc9 100644 --- a/test/cvc/CreditVaultConnectorScribble.sol +++ b/test/evc/EthereumVaultConnectorScribble.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; -import "../../src/CreditVaultConnector.sol"; +import "../../src/EthereumVaultConnector.sol"; /// #if_succeeds "call depth doesn't change" old(executionContext.getCallDepth()) == executionContext.getCallDepth(); /// #if_succeeds "on behalf account state doesn't change" old(executionContext.getOnBehalfOfAccount()) == executionContext.getOnBehalfOfAccount(); @@ -20,14 +20,14 @@ import "../../src/CreditVaultConnector.sol"; /// #if_succeeds "each account has at most 1 controller" !old(executionContext.areChecksDeferred()) ==> forall(uint256 i in ownerLookup) forall(uint256 j in 0...256) accountControllers[address(uint160((i << 8) ^ j))].numElements <= 1; /// #invariant "account status checks set has at most 20 elements" accountStatusChecks.numElements <= 20; /// #invariant "vault status checks set has at most 20 elements" vaultStatusChecks.numElements <= 20; -contract CreditVaultConnectorScribble is CreditVaultConnector { +contract EthereumVaultConnectorScribble is EthereumVaultConnector { using ExecutionContext for EC; using Set for SetStorage; /// #if_succeeds "is non-reentant" !old(executionContext.areChecksInProgress()) && !old(executionContext.isImpersonationInProgress()); /// #if_succeeds "the vault is present in the collateral set 1" old(accountCollaterals[account].numElements) < 20 ==> accountCollaterals[account].contains(vault); /// #if_succeeds "number of vaults is equal to the collateral array length 1" accountCollaterals[account].numElements == accountCollaterals[account].get().length; - /// #if_succeeds "collateral cannot be CVC" vault != address(this); + /// #if_succeeds "collateral cannot be EVC" vault != address(this); function enableCollateral( address account, address vault @@ -48,7 +48,7 @@ contract CreditVaultConnectorScribble is CreditVaultConnector { /// #if_succeeds "is non-reentant" !old(executionContext.areChecksInProgress()) && !old(executionContext.isImpersonationInProgress()); /// #if_succeeds "the vault is present in the controller set 1" old(accountControllers[account].numElements) < 20 ==> accountControllers[account].contains(vault); /// #if_succeeds "number of vaults is equal to the controller array length 1" accountControllers[account].numElements == accountControllers[account].get().length; - /// #if_succeeds "controller cannot be CVC" vault != address(this); + /// #if_succeeds "controller cannot be EVC" vault != address(this); function enableController( address account, address vault @@ -87,7 +87,7 @@ contract CreditVaultConnectorScribble is CreditVaultConnector { } /// #if_succeeds "is non-reentant" !old(executionContext.areChecksInProgress()) && !old(executionContext.isImpersonationInProgress()); - /// #if_succeeds "the caller cannot be CVC" msg.sender != address(this); + /// #if_succeeds "the caller cannot be EVC" msg.sender != address(this); function callback( address onBehalfOfAccount, uint256 value, diff --git a/test/gas/CVCGas.t.sol b/test/gas/EVCGas.t.sol similarity index 74% rename from test/gas/CVCGas.t.sol rename to test/gas/EVCGas.t.sol index bd58f6e5..dabf970f 100644 --- a/test/gas/CVCGas.t.sol +++ b/test/gas/EVCGas.t.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../src/CreditVaultConnector.sol"; +import "../../src/EthereumVaultConnector.sol"; -contract CVCHarness is CreditVaultConnector { +contract EVCHarness is EthereumVaultConnector { function permitHash( address signer, uint nonceNamespace, @@ -28,13 +28,13 @@ contract CVCHarness is CreditVaultConnector { } } -contract CVCGas is Test { +contract EVCGas is Test { using Set for SetStorage; - CVCHarness cvc; + EVCHarness evc; function setUp() public { - cvc = new CVCHarness(); + evc = new EVCHarness(); } function testGas_getPermitHash( @@ -45,11 +45,11 @@ contract CVCGas is Test { uint value, bytes calldata data ) public view { - cvc.permitHash(signer, nonceNamespace, nonce, deadline, value, data); + evc.permitHash(signer, nonceNamespace, nonce, deadline, value, data); } function testGas_haveCommonOwner(address a, address b) public view { - cvc.haveCommonOwner(a, b); + evc.haveCommonOwner(a, b); } function testGas_isValidSignature_eoa( @@ -57,9 +57,9 @@ contract CVCGas is Test { bytes32 hash, bytes memory signature ) public { - vm.assume(!cvc.haveCommonOwner(signer, address(0))); + vm.assume(!evc.haveCommonOwner(signer, address(0))); vm.assume(signature.length < 100); - cvc.getIsValidERC1271Signature(signer, hash, signature); + evc.getIsValidERC1271Signature(signer, hash, signature); } function testGas_isValidSignature_contract( @@ -67,9 +67,9 @@ contract CVCGas is Test { bytes32 hash, bytes memory signature ) public { - vm.assume(signer != address(cvc) && uint160(signer) > 1000); + vm.assume(signer != address(evc) && uint160(signer) > 1000); vm.assume(signature.length < 100); vm.etch(signer, "ff"); - cvc.getIsValidERC1271Signature(signer, hash, signature); + evc.getIsValidERC1271Signature(signer, hash, signature); } } diff --git a/test/invariants/CreditVaultConnector.t.sol b/test/invariants/EthereumVaultConnector.t.sol similarity index 91% rename from test/invariants/CreditVaultConnector.t.sol rename to test/invariants/EthereumVaultConnector.t.sol index 4a79e42a..1eecbba9 100644 --- a/test/invariants/CreditVaultConnector.t.sol +++ b/test/invariants/EthereumVaultConnector.t.sol @@ -4,13 +4,13 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; import "../../src/interfaces/IERC1271.sol"; -import "../cvc/CreditVaultConnectorScribble.sol"; +import "../evc/EthereumVaultConnectorScribble.sol"; -contract VaultMock is ICreditVault { - ICVC public immutable cvc; +contract VaultMock is IVault { + IEVC public immutable evc; - constructor(ICVC _cvc) { - cvc = _cvc; + constructor(IEVC _evc) { + evc = _evc; } function disableController(address account) public override {} @@ -27,8 +27,8 @@ contract VaultMock is ICreditVault { } fallback(bytes calldata) external payable returns (bytes memory) { - cvc.requireAccountStatusCheck(address(0)); - cvc.requireVaultStatusCheck(); + evc.requireAccountStatusCheck(address(0)); + evc.requireVaultStatusCheck(); return ""; } @@ -44,7 +44,7 @@ contract SignerMock { } } -contract CreditVaultConnectorHandler is CreditVaultConnectorScribble, Test { +contract EthereumVaultConnectorHandler is EthereumVaultConnectorScribble, Test { using Set for SetStorage; address internal vaultMock; @@ -52,7 +52,7 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorScribble, Test { address[] public touchedAccounts; constructor() { - vaultMock = address(new VaultMock(ICVC(address(this)))); + vaultMock = address(new VaultMock(IEVC(address(this)))); signerMock = address(new SignerMock()); } @@ -386,25 +386,25 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorScribble, Test { } } -contract CreditVaultConnectorInvariants is Test { - CreditVaultConnectorHandler internal cvc; +contract EthereumVaultConnectorInvariants is Test { + EthereumVaultConnectorHandler internal evc; function setUp() public { - cvc = new CreditVaultConnectorHandler(); + evc = new EthereumVaultConnectorHandler(); - targetContract(address(cvc)); + targetContract(address(evc)); } function invariant_ExecutionContext() external { - vm.expectRevert(Errors.CVC_OnBehalfOfAccountNotAuthenticated.selector); - cvc.getCurrentOnBehalfOfAccount(address(0)); + vm.expectRevert(Errors.EVC_OnBehalfOfAccountNotAuthenticated.selector); + evc.getCurrentOnBehalfOfAccount(address(0)); - assertEq(cvc.getRawExecutionContext(), 1 << 200); - assertEq(cvc.getCurrentCallDepth(), 0); - assertEq(cvc.areChecksInProgress(), false); - assertEq(cvc.isImpersonationInProgress(), false); - assertEq(cvc.isOperatorAuthenticated(), false); - assertEq(cvc.isSimulationInProgress(), false); + assertEq(evc.getRawExecutionContext(), 1 << 200); + assertEq(evc.getCurrentCallDepth(), 0); + assertEq(evc.areChecksInProgress(), false); + assertEq(evc.isImpersonationInProgress(), false); + assertEq(evc.isOperatorAuthenticated(), false); + assertEq(evc.isSimulationInProgress(), false); } function invariant_AccountAndVaultStatusChecks() external { @@ -413,7 +413,7 @@ contract CreditVaultConnectorInvariants is Test { address[] memory accountStatusChecks, uint8 vaultStatusChecksNumElements, address[] memory vaultStatusChecks - ) = cvc.exposeAccountAndVaultStatusCheck(); + ) = evc.exposeAccountAndVaultStatusCheck(); assertTrue(accountStatusChecksNumElements == 0); for (uint i = 0; i < accountStatusChecks.length; i++) { @@ -427,13 +427,13 @@ contract CreditVaultConnectorInvariants is Test { } function invariant_ControllersCollaterals() external { - address[] memory touchedAccounts = cvc.getTouchedAccounts(); + address[] memory touchedAccounts = evc.getTouchedAccounts(); for (uint i = 0; i < touchedAccounts.length; i++) { // controllers ( uint8 accountControllersNumElements, address[] memory accountControllersArray - ) = cvc.exposeAccountControllers(touchedAccounts[i]); + ) = evc.exposeAccountControllers(touchedAccounts[i]); assertTrue( accountControllersNumElements == 0 || @@ -454,7 +454,7 @@ contract CreditVaultConnectorInvariants is Test { ( uint8 accountCollateralsNumCollaterals, address[] memory accountCollateralsArray - ) = cvc.exposeAccountCollaterals(touchedAccounts[i]); + ) = evc.exposeAccountCollaterals(touchedAccounts[i]); assertTrue(accountCollateralsNumCollaterals <= Set.MAX_ELEMENTS); for (uint j = 0; j < accountCollateralsNumCollaterals; j++) { diff --git a/test/unit/CreditVaultConnector/Impersonate.sol b/test/unit/CreditVaultConnector/Impersonate.sol deleted file mode 100644 index aedb30a5..00000000 --- a/test/unit/CreditVaultConnector/Impersonate.sol +++ /dev/null @@ -1,400 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -pragma solidity ^0.8.20; - -import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; - -contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { - using Set for SetStorage; - - function handlerImpersonate( - address targetContract, - address onBehalfOfAccount, - uint value, - bytes calldata data - ) public payable returns (bytes memory result) { - (bool success, ) = msg.sender.call( - abi.encodeWithSelector(Vault.clearChecks.selector) - ); - success; - clearExpectedChecks(); - - result = super.impersonate( - targetContract, - onBehalfOfAccount, - value, - data - ); - - verifyVaultStatusChecks(); - verifyAccountStatusChecks(); - } -} - -contract ImpersonateTest is Test { - CreditVaultConnectorHandler internal cvc; - - event CallWithContext( - address indexed caller, - address indexed targetContract, - address indexed onBehalfOfAccount, - bytes4 selector - ); - - function setUp() public { - cvc = new CreditVaultConnectorHandler(); - } - - function test_Impersonate(address alice, uint96 seed) public { - vm.assume(alice != address(0) && alice != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - vm.assume(collateral != address(cvc)); - vm.assume(!cvc.haveCommonOwner(alice, controller)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - bytes memory data = abi.encodeWithSelector( - Target(collateral).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(controller, seed); - vm.expectEmit(true, true, true, true, address(cvc)); - emit CallWithContext( - controller, - collateral, - alice, - Target.impersonateTest.selector - ); - vm.prank(controller); - bytes memory result = cvc.handlerImpersonate{value: seed}( - collateral, - alice, - seed, - data - ); - assertEq(abi.decode(result, (uint)), seed); - - cvc.clearExpectedChecks(); - Vault(controller).clearChecks(); - } - - function test_RevertIfDepthExceeded_Impersonate(address alice) external { - vm.assume(alice != address(cvc)); - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - cvc.setCallDepth(10); - - vm.prank(controller); - vm.expectRevert(ExecutionContext.CallDepthViolation.selector); - cvc.impersonate(collateral, alice, 0, ""); - } - - function test_RevertIfChecksReentrancy_Impersonate( - address alice, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - vm.assume(collateral != address(cvc)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - cvc.setChecksLock(true); - - bytes memory data = abi.encodeWithSelector( - Target(address(cvc)).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(alice, seed); - vm.prank(alice); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.impersonate{value: seed}(collateral, alice, seed, data); - } - - function test_RevertIfImpersonateReentrancy_Impersonate( - address alice, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - vm.assume(collateral != address(cvc)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - cvc.setImpersonateLock(true); - - bytes memory data = abi.encodeWithSelector( - Target(address(cvc)).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(alice, seed); - vm.prank(alice); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.impersonate{value: seed}(collateral, alice, seed, data); - } - - function test_RevertIfTargetContractInvalid_Impersonate( - address alice, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - - address controller = address(new Vault(cvc)); - - vm.prank(alice); - cvc.enableController(alice, controller); - - // target contract is the CVC - bytes memory data = abi.encodeWithSelector( - Target(address(cvc)).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(alice, seed); - vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.impersonate{value: seed}(address(cvc), alice, seed, data); - } - - function test_RevertIfNoControllerEnabled_Impersonate( - address alice, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - - vm.assume(collateral != address(cvc)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - bytes memory data = abi.encodeWithSelector( - Target(collateral).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(controller, seed); - vm.prank(controller); - vm.expectRevert(Errors.CVC_ControllerViolation.selector); - cvc.impersonate{value: seed}(collateral, alice, seed, data); - } - - function test_RevertIfMultipleControllersEnabled_Impersonate( - address alice, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller_1 = address(new Vault(cvc)); - address controller_2 = address(new Vault(cvc)); - - vm.assume(collateral != address(cvc)); - - // mock checks deferred to enable multiple controllers - cvc.setCallDepth(1); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller_1); - - vm.prank(alice); - cvc.enableController(alice, controller_2); - - bytes memory data = abi.encodeWithSelector( - Target(collateral).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(controller_1, seed); - vm.prank(controller_1); - vm.expectRevert(Errors.CVC_ControllerViolation.selector); - cvc.impersonate{value: seed}(collateral, alice, seed, data); - } - - function test_RevertIfMsgSenderIsNotEnabledController_Impersonate( - address alice, - address randomAddress, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(uint160(randomAddress) > 10 && randomAddress != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - - vm.assume(collateral != address(cvc)); - vm.assume(randomAddress != controller); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - bytes memory data = abi.encodeWithSelector( - Target(collateral).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(randomAddress, seed); - vm.prank(randomAddress); - vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_NotAuthorized.selector) - ); - cvc.impersonate{value: seed}(collateral, alice, seed, data); - } - - function test_RevertIfTargetContractIsNotEnabledCollateral_Impersonate( - address alice, - address targetContract, - uint seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(targetContract != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - - vm.assume(targetContract != collateral); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - bytes memory data = abi.encodeWithSelector( - Target(collateral).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - vm.deal(controller, seed); - vm.prank(controller); - vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_NotAuthorized.selector) - ); - cvc.impersonate{value: seed}(targetContract, alice, seed, data); - } - - function test_RevertIfValueExceedsBalance_Impersonate( - address alice, - uint128 seed - ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(seed > 0); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - vm.assume(collateral != address(cvc) && controller != address(cvc)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - bytes memory data = abi.encodeWithSelector( - Target(address(cvc)).impersonateTest.selector, - address(cvc), - address(cvc), - seed, - alice - ); - - // reverts if value exceeds balance - vm.deal(controller, seed); - vm.prank(controller); - vm.expectRevert(Errors.CVC_InvalidValue.selector); - cvc.impersonate{value: seed - 1}(collateral, alice, seed, data); - - // succeeds if value does not exceed balance - vm.prank(controller); - cvc.impersonate{value: seed}(collateral, alice, seed, data); - } - - function test_RevertIfInternalCallIsUnsuccessful_Impersonate( - address alice - ) public { - // call setUp() explicitly for Dilligence Fuzzing tool to pass - setUp(); - - vm.assume(alice != address(0)); - vm.assume(alice != address(cvc)); - - address collateral = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); - vm.assume(collateral != address(cvc) && controller != address(cvc)); - - vm.prank(alice); - cvc.enableCollateral(alice, collateral); - - vm.prank(alice); - cvc.enableController(alice, controller); - - bytes memory data = abi.encodeWithSelector( - Target(collateral).revertEmptyTest.selector - ); - - vm.prank(controller); - vm.expectRevert(Errors.CVC_EmptyError.selector); - cvc.impersonate(collateral, alice, 0, data); - } -} diff --git a/test/unit/CreditVaultConnector/IsVaultStatusCheckDeferred.t.sol b/test/unit/CreditVaultConnector/IsVaultStatusCheckDeferred.t.sol deleted file mode 100644 index 6ecae0ff..00000000 --- a/test/unit/CreditVaultConnector/IsVaultStatusCheckDeferred.t.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -pragma solidity ^0.8.20; - -import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; - -contract IsVaultStatusCheckDeferredTest is Test { - CreditVaultConnectorHarness internal cvc; - - function setUp() public { - cvc = new CreditVaultConnectorHarness(); - } - - function test_IsVaultStatusCheckDeferred(uint8 numberOfVaults) external { - vm.assume(numberOfVaults <= Set.MAX_ELEMENTS); - - for (uint i = 0; i < numberOfVaults; ++i) { - // we're not in a batch thus the check will not get deferred - cvc.setCallDepth(0); - - address vault = address(new Vault(cvc)); - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); - - vm.prank(vault); - cvc.requireVaultStatusCheck(); - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); - - // simulate being in a batch - cvc.setCallDepth(1); - - vm.prank(vault); - cvc.requireVaultStatusCheck(); - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); - - cvc.reset(); - } - } -} diff --git a/test/unit/CreditVaultConnector/AccountAndVaultStatus.sol b/test/unit/EthereumVaultConnector/AccountAndVaultStatus.sol similarity index 74% rename from test/unit/CreditVaultConnector/AccountAndVaultStatus.sol rename to test/unit/EthereumVaultConnector/AccountAndVaultStatus.sol index a0300282..d2918852 100644 --- a/test/unit/CreditVaultConnector/AccountAndVaultStatus.sol +++ b/test/unit/EthereumVaultConnector/AccountAndVaultStatus.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract AccountAndVaultStatusTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_RequireAccountAndVaultStatusCheck( @@ -28,8 +28,8 @@ contract AccountAndVaultStatusTest is Test { accounts[i] = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - controllers[i] = address(new Vault(cvc)); - vaults[i] = address(new Vault(cvc)); + controllers[i] = address(new Vault(evc)); + vaults[i] = address(new Vault(evc)); } for (uint i = 0; i < numberOfAddresses; i++) { @@ -38,9 +38,9 @@ contract AccountAndVaultStatusTest is Test { address vault = vaults[i]; vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); Vault(controller).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); // check all the options: states are ok, states are violated with // vault/controller returning false and reverting @@ -83,13 +83,13 @@ contract AccountAndVaultStatusTest is Test { } vm.prank(vault); - cvc.requireAccountAndVaultStatusCheck(account); + evc.requireAccountAndVaultStatusCheck(account); - cvc.verifyAccountStatusChecks(); - cvc.verifyVaultStatusChecks(); + evc.verifyAccountStatusChecks(); + evc.verifyVaultStatusChecks(); Vault(controller).clearChecks(); Vault(vault).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); } } @@ -108,39 +108,39 @@ contract AccountAndVaultStatusTest is Test { accounts[i] = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - controllers[i] = address(new Vault(cvc)); - vaults[i] = address(new Vault(cvc)); + controllers[i] = address(new Vault(evc)); + vaults[i] = address(new Vault(evc)); } for (uint i = 0; i < numberOfAddresses; i++) { - cvc.setCallDepth(0); + evc.setCallDepth(0); address account = accounts[i]; address controller = controllers[i]; address vault = vaults[i]; vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); Vault(controller).setAccountStatusState(1); Vault(vault).setVaultStatusState(1); // status checks will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); // even though the account status state and the vault status state were // set to 1 which should revert, it doesn't because in checks deferral // we only add the accounts to the set so that the checks can be performed // later - assertFalse(cvc.isAccountStatusCheckDeferred(account)); - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); + assertFalse(evc.isAccountStatusCheckDeferred(account)); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); vm.prank(vault); - cvc.requireAccountAndVaultStatusCheck(account); + evc.requireAccountAndVaultStatusCheck(account); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); - cvc.reset(); + evc.reset(); } } @@ -151,19 +151,19 @@ contract AccountAndVaultStatusTest is Test { vm.assume(index < accounts.length); vm.assume(accounts.length > 0 && accounts.length <= Set.MAX_ELEMENTS); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); vm.prank(vault); - cvc.requireAccountAndVaultStatusCheck(accounts[index]); + evc.requireAccountAndVaultStatusCheck(accounts[index]); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(vault); - cvc.requireAccountAndVaultStatusCheck(accounts[index]); + evc.requireAccountAndVaultStatusCheck(accounts[index]); } function test_AcquireChecksLock_RequireAccountAndVaultStatusChecks( @@ -182,20 +182,20 @@ contract AccountAndVaultStatusTest is Test { uint160(uint(keccak256(abi.encode(i, seed)))) ); - controllers[i] = address(new VaultMalicious(cvc)); - vaults[i] = address(new VaultMalicious(cvc)); + controllers[i] = address(new VaultMalicious(evc)); + vaults[i] = address(new VaultMalicious(evc)); vm.prank(accounts[i]); - cvc.enableController(accounts[i], controllers[i]); + evc.enableController(accounts[i], controllers[i]); VaultMalicious(controllers[i]).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); - // function will revert with CVC_AccountStatusViolation according to VaultMalicious implementation + // function will revert with EVC_AccountStatusViolation according to VaultMalicious implementation vm.expectRevert(bytes("malicious vault")); vm.prank(vaults[i]); - cvc.requireAccountAndVaultStatusCheck(accounts[i]); + evc.requireAccountAndVaultStatusCheck(accounts[i]); } } } diff --git a/test/unit/CreditVaultConnector/AccountStatus.sol b/test/unit/EthereumVaultConnector/AccountStatus.sol similarity index 66% rename from test/unit/CreditVaultConnector/AccountStatus.sol rename to test/unit/EthereumVaultConnector/AccountStatus.sol index 443e7673..61cc8b86 100644 --- a/test/unit/CreditVaultConnector/AccountStatus.sol +++ b/test/unit/EthereumVaultConnector/AccountStatus.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract AccountStatusTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_RequireAccountStatusCheck( @@ -23,12 +23,12 @@ contract AccountStatusTest is Test { address account = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); Vault(controller).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); // check all the options: account state is ok, account state is violated with // controller returning false and reverting @@ -48,11 +48,11 @@ contract AccountStatusTest is Test { ); } - cvc.requireAccountStatusCheck(account); + evc.requireAccountStatusCheck(account); - cvc.verifyAccountStatusChecks(); + evc.verifyAccountStatusChecks(); Vault(controller).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); } } @@ -63,42 +63,42 @@ contract AccountStatusTest is Test { vm.assume(numberOfAccounts > 0 && numberOfAccounts <= Set.MAX_ELEMENTS); for (uint i = 0; i < numberOfAccounts; i++) { - cvc.setCallDepth(0); + evc.setCallDepth(0); address account = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); Vault(controller).setAccountStatusState(1); // account status check will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); // even though the account status state was set to 1 which should revert, // it doesn't because in checks deferral we only add the accounts to the set // so that the checks can be performed later - assertFalse(cvc.isAccountStatusCheckDeferred(account)); - cvc.requireAccountStatusCheck(account); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); - cvc.reset(); + assertFalse(evc.isAccountStatusCheckDeferred(account)); + evc.requireAccountStatusCheck(account); + assertTrue(evc.isAccountStatusCheckDeferred(account)); + evc.reset(); } } function test_RevertIfChecksReentrancy_RequireAccountStatusCheck( address account ) external { - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.requireAccountStatusCheck(account); + evc.requireAccountStatusCheck(account); - cvc.setChecksLock(false); - cvc.requireAccountStatusCheck(account); + evc.setChecksLock(false); + evc.requireAccountStatusCheck(account); } function test_AcquireChecksLock_RequireAccountStatusChecks( @@ -111,18 +111,18 @@ contract AccountStatusTest is Test { address account = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - address controller = address(new VaultMalicious(cvc)); + address controller = address(new VaultMalicious(evc)); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); VaultMalicious(controller).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); - // function will revert with CVC_AccountStatusViolation according to VaultMalicious implementation + // function will revert with EVC_AccountStatusViolation according to VaultMalicious implementation vm.expectRevert(bytes("malicious vault")); - cvc.requireAccountStatusCheck(account); + evc.requireAccountStatusCheck(account); } } @@ -139,17 +139,17 @@ contract AccountStatusTest is Test { accounts[i] = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - controllers[i] = address(new Vault(cvc)); + controllers[i] = address(new Vault(evc)); } for (uint i = 0; i < numberOfAccounts; i++) { address account = accounts[i]; address controller = controllers[i]; - cvc.setCallDepth(0); + evc.setCallDepth(0); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); // check all the options: account state is ok, account state is violated with // controller returning false and reverting @@ -163,13 +163,13 @@ contract AccountStatusTest is Test { // first, schedule the check to be performed later to prove that after being peformed on the fly // account is no longer contained in the set to be performed later - cvc.setCallDepth(1); - cvc.requireAccountStatusCheck(account); + evc.setCallDepth(1); + evc.requireAccountStatusCheck(account); Vault(controller).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); if (!(allStatusesValid || uint160(account) % 3 == 0)) { vm.expectRevert( uint160(account) % 3 == 1 @@ -177,29 +177,29 @@ contract AccountStatusTest is Test { : abi.encode(bytes4(uint32(2))) ); } - cvc.requireAccountStatusCheckNow(account); + evc.requireAccountStatusCheckNow(account); if (allStatusesValid || uint160(account) % 3 == 0) { - assertFalse(cvc.isAccountStatusCheckDeferred(account)); + assertFalse(evc.isAccountStatusCheckDeferred(account)); } else { - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); } - cvc.verifyAccountStatusChecks(); + evc.verifyAccountStatusChecks(); - cvc.reset(); + evc.reset(); } // schedule the checks to be performed later to prove that after being peformed on the fly // accounts are no longer contained in the set to be performed later - cvc.setCallDepth(1); + evc.setCallDepth(1); for (uint i = 0; i < numberOfAccounts; ++i) { - cvc.requireAccountStatusCheck(accounts[i]); + evc.requireAccountStatusCheck(accounts[i]); Vault(controllers[i]).clearChecks(); - assertTrue(cvc.isAccountStatusCheckDeferred(accounts[i])); + assertTrue(evc.isAccountStatusCheckDeferred(accounts[i])); } - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); for (uint i = 0; i < numberOfAccounts; ++i) { address account = accounts[i]; @@ -211,29 +211,29 @@ contract AccountStatusTest is Test { : abi.encode(bytes4(uint32(2))) ); } - cvc.requireAccountStatusCheckNow(account); + evc.requireAccountStatusCheckNow(account); if (allStatusesValid || uint160(account) % 3 == 0) { - assertFalse(cvc.isAccountStatusCheckDeferred(account)); + assertFalse(evc.isAccountStatusCheckDeferred(account)); } else { - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); } } - cvc.verifyAccountStatusChecks(); + evc.verifyAccountStatusChecks(); } function test_RevertIfChecksReentrancy_RequireAccountStatusCheckNow( address account ) external { - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.requireAccountStatusCheckNow(account); + evc.requireAccountStatusCheckNow(account); - cvc.setChecksLock(false); - cvc.requireAccountStatusCheckNow(account); + evc.setChecksLock(false); + evc.requireAccountStatusCheckNow(account); } function test_AcquireChecksLock_RequireAccountStatusChecksNow( @@ -246,18 +246,18 @@ contract AccountStatusTest is Test { address account = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - address controller = address(new VaultMalicious(cvc)); + address controller = address(new VaultMalicious(evc)); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); VaultMalicious(controller).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); - // function will revert with CVC_AccountStatusViolation according to VaultMalicious implementation + // function will revert with EVC_AccountStatusViolation according to VaultMalicious implementation vm.expectRevert(bytes("malicious vault")); - cvc.requireAccountStatusCheckNow(account); + evc.requireAccountStatusCheckNow(account); } } @@ -274,7 +274,7 @@ contract AccountStatusTest is Test { accounts[i] = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - controllers[i] = address(new Vault(cvc)); + controllers[i] = address(new Vault(evc)); } uint invalidAccountsCounter; @@ -284,11 +284,11 @@ contract AccountStatusTest is Test { address account = accounts[i]; address controller = controllers[i]; - cvc.reset(); - cvc.setCallDepth(0); + evc.reset(); + evc.setCallDepth(0); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); // check all the options: account state is ok, account state is violated with // controller returning false and reverting @@ -300,13 +300,13 @@ contract AccountStatusTest is Test { : 2 ); - cvc.setCallDepth(1); - cvc.requireAccountStatusCheck(account); + evc.setCallDepth(1); + evc.requireAccountStatusCheck(account); Vault(controller).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); if (!(allStatusesValid || uint160(account) % 3 == 0)) { // for later check invalidAccounts[invalidAccountsCounter++] = account; @@ -317,30 +317,30 @@ contract AccountStatusTest is Test { : abi.encode(bytes4(uint32(2))) ); } - cvc.requireAllAccountsStatusCheckNow(); + evc.requireAllAccountsStatusCheckNow(); if (allStatusesValid || uint160(account) % 3 == 0) { - assertFalse(cvc.isAccountStatusCheckDeferred(account)); + assertFalse(evc.isAccountStatusCheckDeferred(account)); } else { - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); } - cvc.verifyAccountStatusChecks(); + evc.verifyAccountStatusChecks(); } - cvc.reset(); + evc.reset(); - cvc.setCallDepth(1); + evc.setCallDepth(1); for (uint i = 0; i < accounts.length; ++i) { - cvc.requireAccountStatusCheck(accounts[i]); + evc.requireAccountStatusCheck(accounts[i]); } for (uint i = 0; i < controllers.length; ++i) { Vault(controllers[i]).clearChecks(); } - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); for (uint i = 0; i < accounts.length; ++i) { - assertTrue(cvc.isAccountStatusCheckDeferred(accounts[i])); + assertTrue(evc.isAccountStatusCheckDeferred(accounts[i])); } if (invalidAccountsCounter > 0) { vm.expectRevert( @@ -349,26 +349,26 @@ contract AccountStatusTest is Test { : abi.encode(bytes4(uint32(2))) ); } - cvc.requireAllAccountsStatusCheckNow(); + evc.requireAllAccountsStatusCheckNow(); for (uint i = 0; i < accounts.length; ++i) { assertEq( - cvc.isAccountStatusCheckDeferred(accounts[i]), + evc.isAccountStatusCheckDeferred(accounts[i]), invalidAccountsCounter > 0 ); } - cvc.verifyAccountStatusChecks(); + evc.verifyAccountStatusChecks(); } function test_RevertIfChecksReentrancy_RequireAllAccountsStatusCheckNow( bool locked ) external { - cvc.setChecksLock(locked); + evc.setChecksLock(locked); if (locked) vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.requireAllAccountsStatusCheckNow(); + evc.requireAllAccountsStatusCheckNow(); } function test_AcquireChecksLock_RequireAllAccountsStatusChecksNow( @@ -384,23 +384,23 @@ contract AccountStatusTest is Test { uint160(uint(keccak256(abi.encode(i, seed)))) ); - controllers[i] = address(new VaultMalicious(cvc)); + controllers[i] = address(new VaultMalicious(evc)); vm.prank(accounts[i]); - cvc.enableController(accounts[i], controllers[i]); + evc.enableController(accounts[i], controllers[i]); VaultMalicious(controllers[i]).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); } - cvc.setCallDepth(1); + evc.setCallDepth(1); for (uint i = 0; i < accounts.length; ++i) { - cvc.requireAccountStatusCheck(accounts[i]); + evc.requireAccountStatusCheck(accounts[i]); } vm.expectRevert(bytes("malicious vault")); - cvc.requireAllAccountsStatusCheckNow(); + evc.requireAllAccountsStatusCheckNow(); } function test_ForgiveAccountStatusCheck( @@ -416,58 +416,58 @@ contract AccountStatusTest is Test { ); } - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); for (uint i = 0; i < numberOfAccounts; i++) { address account = accounts[i]; // account status check will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); vm.prank(controller); - cvc.forgiveAccountStatusCheck(account); - assertFalse(cvc.isAccountStatusCheckDeferred(account)); + evc.forgiveAccountStatusCheck(account); + assertFalse(evc.isAccountStatusCheckDeferred(account)); - cvc.reset(); + evc.reset(); } - cvc.setCallDepth(1); + evc.setCallDepth(1); for (uint i = 0; i < accounts.length; ++i) { - assertFalse(cvc.isAccountStatusCheckDeferred(accounts[i])); - cvc.requireAccountStatusCheck(accounts[i]); - assertTrue(cvc.isAccountStatusCheckDeferred(accounts[i])); + assertFalse(evc.isAccountStatusCheckDeferred(accounts[i])); + evc.requireAccountStatusCheck(accounts[i]); + assertTrue(evc.isAccountStatusCheckDeferred(accounts[i])); } for (uint i = 0; i < accounts.length; ++i) { vm.prank(controller); - cvc.forgiveAccountStatusCheck(accounts[i]); - assertFalse(cvc.isAccountStatusCheckDeferred(accounts[i])); + evc.forgiveAccountStatusCheck(accounts[i]); + assertFalse(evc.isAccountStatusCheckDeferred(accounts[i])); } } function test_RevertIfChecksReentrancy_ForgiveAccountStatusCheckNow( address account ) external { - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(controller); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.forgiveAccountStatusCheck(account); + evc.forgiveAccountStatusCheck(account); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(controller); - cvc.forgiveAccountStatusCheck(account); + evc.forgiveAccountStatusCheck(account); } function test_RevertIfNoControllerEnabled_ForgiveAccountStatusCheck( @@ -482,17 +482,17 @@ contract AccountStatusTest is Test { ); // account status check will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); - assertFalse(cvc.isAccountStatusCheckDeferred(account)); - cvc.requireAccountStatusCheck(account); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertFalse(evc.isAccountStatusCheckDeferred(account)); + evc.requireAccountStatusCheck(account); + assertTrue(evc.isAccountStatusCheckDeferred(account)); // the check does not get forgiven - vm.expectRevert(Errors.CVC_ControllerViolation.selector); - cvc.forgiveAccountStatusCheck(account); + vm.expectRevert(Errors.EVC_ControllerViolation.selector); + evc.forgiveAccountStatusCheck(account); - cvc.reset(); + evc.reset(); } } @@ -501,8 +501,8 @@ contract AccountStatusTest is Test { bytes memory seed ) external { vm.assume(numberOfAccounts > 0 && numberOfAccounts <= Set.MAX_ELEMENTS); - address controller_1 = address(new Vault(cvc)); - address controller_2 = address(new Vault(cvc)); + address controller_1 = address(new Vault(evc)); + address controller_2 = address(new Vault(evc)); for (uint i = 0; i < numberOfAccounts; i++) { address account = address( @@ -510,20 +510,20 @@ contract AccountStatusTest is Test { ); // account status check will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(account); - cvc.enableController(account, controller_1); + evc.enableController(account, controller_1); vm.prank(account); - cvc.enableController(account, controller_2); + evc.enableController(account, controller_2); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); vm.prank(controller_1); - vm.expectRevert(Errors.CVC_ControllerViolation.selector); - cvc.forgiveAccountStatusCheck(account); + vm.expectRevert(Errors.EVC_ControllerViolation.selector); + evc.forgiveAccountStatusCheck(account); - cvc.reset(); + evc.reset(); } } @@ -533,24 +533,24 @@ contract AccountStatusTest is Test { ) external { vm.assume(numberOfAccounts > 0 && numberOfAccounts <= Set.MAX_ELEMENTS); - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); for (uint i = 0; i < numberOfAccounts; i++) { address account = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); // account status check will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + assertTrue(evc.isAccountStatusCheckDeferred(account)); vm.prank(address(uint160(controller) + 1)); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.forgiveAccountStatusCheck(account); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.forgiveAccountStatusCheck(account); - cvc.reset(); + evc.reset(); } } } diff --git a/test/unit/CreditVaultConnector/Batch.sol b/test/unit/EthereumVaultConnector/Batch.sol similarity index 69% rename from test/unit/CreditVaultConnector/Batch.sol rename to test/unit/EthereumVaultConnector/Batch.sol index c2bc2009..8e5e088a 100644 --- a/test/unit/CreditVaultConnector/Batch.sol +++ b/test/unit/EthereumVaultConnector/Batch.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; -contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { +contract EthereumVaultConnectorHandler is EthereumVaultConnectorHarness { using ExecutionContext for EC; using Set for SetStorage; @@ -17,7 +17,7 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { } } -contract CreditVaultConnectorNoRevert is CreditVaultConnectorHarness { +contract EthereumVaultConnectorNoRevert is EthereumVaultConnectorHarness { using Set for SetStorage; function batchRevert( @@ -29,7 +29,7 @@ contract CreditVaultConnectorNoRevert is CreditVaultConnectorHarness { } contract BatchTest is Test { - CreditVaultConnectorHandler internal cvc; + EthereumVaultConnectorHandler internal evc; event CallWithContext( address indexed caller, @@ -39,38 +39,38 @@ contract BatchTest is Test { ); function setUp() public { - cvc = new CreditVaultConnectorHandler(); + evc = new EthereumVaultConnectorHandler(); } function test_Batch(address alice, address bob, uint seed) external { vm.assume( - alice != address(0) && alice != address(cvc) && bob != address(cvc) + alice != address(0) && alice != address(evc) && bob != address(evc) ); - vm.assume(bob != address(0) && !cvc.haveCommonOwner(alice, bob)); + vm.assume(bob != address(0) && !evc.haveCommonOwner(alice, bob)); vm.assume(seed >= 4); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](6); - address controller = address(new Vault(cvc)); - address otherVault = address(new Vault(cvc)); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](6); + address controller = address(new Vault(evc)); + address otherVault = address(new Vault(evc)); address alicesSubAccount = address(uint160(alice) ^ 0x10); vm.assume(bob != controller); // -------------- FIRST BATCH ------------------------- items[0].onBehalfOfAccount = alice; - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].value = 0; items[0].data = abi.encodeWithSelector( - cvc.enableController.selector, + evc.enableController.selector, alice, controller ); items[1].onBehalfOfAccount = alice; - items[1].targetContract = address(cvc); + items[1].targetContract = address(evc); items[1].value = 0; items[1].data = abi.encodeWithSelector( - cvc.setAccountOperator.selector, + evc.setAccountOperator.selector, alice, bob, true @@ -92,7 +92,7 @@ contract BatchTest is Test { otherVault, abi.encodeWithSelector( Target.callTest.selector, - address(cvc), + address(evc), controller, seed / 3, alice, @@ -105,33 +105,33 @@ contract BatchTest is Test { items[4].value = type(uint).max; items[4].data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed - seed / 3, alice, false ); items[5].onBehalfOfAccount = alicesSubAccount; - items[5].targetContract = address(cvc); + items[5].targetContract = address(evc); items[5].value = 0; items[5].data = abi.encodeWithSelector( - cvc.enableController.selector, + evc.enableController.selector, alicesSubAccount, controller ); vm.deal(alice, seed); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( alice, otherVault, alicesSubAccount, Vault.requireChecks.selector ); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext(alice, controller, alice, Vault.call.selector); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( alice, otherVault, @@ -139,37 +139,37 @@ contract BatchTest is Test { Target.callTest.selector ); vm.prank(alice); - cvc.handlerBatch{value: seed}(items); + evc.handlerBatch{value: seed}(items); - assertTrue(cvc.isControllerEnabled(alice, controller)); - assertTrue(cvc.isControllerEnabled(alicesSubAccount, controller)); - assertEq(cvc.isAccountOperatorAuthorized(alice, bob), true); + assertTrue(evc.isControllerEnabled(alice, controller)); + assertTrue(evc.isControllerEnabled(alicesSubAccount, controller)); + assertEq(evc.isAccountOperatorAuthorized(alice, bob), true); assertEq(address(otherVault).balance, seed); - cvc.reset(); + evc.reset(); Vault(controller).reset(); Vault(otherVault).reset(); // -------------- SECOND BATCH ------------------------- - items = new ICVC.BatchItem[](1); + items = new IEVC.BatchItem[](1); items[0].onBehalfOfAccount = alice; - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].value = 0; items[0].data = abi.encodeWithSelector( - cvc.call.selector, - address(cvc), + evc.call.selector, + address(evc), alice, 0, "" ); vm.prank(bob); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.handlerBatch(items); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.handlerBatch(items); // -------------- THIRD BATCH ------------------------- - items = new ICVC.BatchItem[](4); + items = new IEVC.BatchItem[](4); items[0].onBehalfOfAccount = alice; items[0].targetContract = controller; @@ -200,42 +200,42 @@ contract BatchTest is Test { items[3].value = 0; items[3].data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 0, alice, true ); vm.prank(bob); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( bob, controller, alice, Vault.disableController.selector ); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( bob, controller, bob, Vault.requireChecks.selector ); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( bob, otherVault, bob, Vault.requireChecks.selector ); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext(bob, otherVault, alice, Target.callTest.selector); - cvc.handlerBatch(items); - assertFalse(cvc.isControllerEnabled(alice, controller)); + evc.handlerBatch(items); + assertFalse(evc.isControllerEnabled(alice, controller)); // -------------- FOURTH BATCH ------------------------- - items = new ICVC.BatchItem[](1); + items = new IEVC.BatchItem[](1); items[0].onBehalfOfAccount = alice; items[0].targetContract = otherVault; @@ -243,24 +243,24 @@ contract BatchTest is Test { items[0].data = abi.encodeWithSelector(Target.revertEmptyTest.selector); vm.prank(alice); - vm.expectRevert(Errors.CVC_EmptyError.selector); - cvc.handlerBatch(items); + vm.expectRevert(Errors.EVC_EmptyError.selector); + evc.handlerBatch(items); } function test_RevertIfDepthExceeded_Batch(address alice) external { - vm.assume(alice != address(0) && alice != address(cvc)); - address vault = address(new Vault(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); + address vault = address(new Vault(evc)); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](10); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](10); for (int i = int(items.length - 1); i >= 0; --i) { uint j = uint(i); items[j].onBehalfOfAccount = alice; - items[j].targetContract = address(cvc); + items[j].targetContract = address(evc); items[j].value = 0; if (j == items.length - 1) { - ICVC.BatchItem[] memory nestedItems = new ICVC.BatchItem[](2); + IEVC.BatchItem[] memory nestedItems = new IEVC.BatchItem[](2); // non-checks-deferrable call nestedItems[0].onBehalfOfAccount = alice; @@ -273,24 +273,24 @@ contract BatchTest is Test { // non-checks-deferrable call nestedItems[1].onBehalfOfAccount = alice; - nestedItems[1].targetContract = address(cvc); + nestedItems[1].targetContract = address(evc); nestedItems[1].value = 0; nestedItems[1].data = abi.encodeWithSelector( - cvc.enableController.selector, + evc.enableController.selector, alice, vault ); items[j].data = abi.encodeWithSelector( - cvc.batch.selector, + evc.batch.selector, nestedItems ); } else { - ICVC.BatchItem[] memory nestedItems = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory nestedItems = new IEVC.BatchItem[](1); nestedItems[0] = items[j + 1]; items[j].data = abi.encodeWithSelector( - cvc.batch.selector, + evc.batch.selector, nestedItems ); } @@ -298,57 +298,57 @@ contract BatchTest is Test { vm.prank(alice); vm.expectRevert(ExecutionContext.CallDepthViolation.selector); - cvc.batch(items); + evc.batch(items); // should succeed when one less item. doesn't revert anymore, // but checks are performed only once, when the top level batch concludes - ICVC.BatchItem[] memory itemsOneLess = new ICVC.BatchItem[](8); + IEVC.BatchItem[] memory itemsOneLess = new IEVC.BatchItem[](8); for (uint i = 1; i <= itemsOneLess.length; ++i) { itemsOneLess[i - 1] = items[i]; } vm.prank(alice); - cvc.batch(itemsOneLess); + evc.batch(itemsOneLess); } // for coverage function test_RevertIfSimulationBatchNested_BatchRevert_BatchSimulation( address alice ) external { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].onBehalfOfAccount = alice; items[0].targetContract = address(0); items[0].value = 0; items[0].data = ""; - cvc.setCallDepth(10); + evc.setCallDepth(10); vm.prank(alice); - vm.expectRevert(Errors.CVC_SimulationBatchNested.selector); - cvc.batchRevert(items); + vm.expectRevert(Errors.EVC_SimulationBatchNested.selector); + evc.batchRevert(items); vm.prank(alice); - vm.expectRevert(Errors.CVC_SimulationBatchNested.selector); - cvc.batchSimulation(items); + vm.expectRevert(Errors.EVC_SimulationBatchNested.selector); + evc.batchSimulation(items); } function test_RevertIfChecksReentrancy_AcquireChecksLock_Batch( address alice ) external { - vm.assume(alice != address(cvc)); - cvc.setChecksLock(true); + vm.assume(alice != address(evc)); + evc.setChecksLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.batch(new ICVC.BatchItem[](0)); - cvc.setChecksLock(false); + evc.batch(new IEVC.BatchItem[](0)); + evc.setChecksLock(false); - address vault = address(new VaultMalicious(cvc)); + address vault = address(new VaultMalicious(evc)); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].onBehalfOfAccount = alice; items[0].targetContract = vault; items[0].value = 0; @@ -358,37 +358,37 @@ contract BatchTest is Test { false ); - // internal batch in the malicious vault reverts with CVC_ChecksReentrancy error, + // internal batch in the malicious vault reverts with EVC_ChecksReentrancy error, // check VaultMalicious implementation VaultMalicious(vault).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); vm.prank(alice); vm.expectRevert(bytes("malicious vault")); - cvc.batch(items); + evc.batch(items); } function test_RevertIfChecksReentrancy_AcquireChecksLock_BatchRevert_BatchSimulation( address alice ) external { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.batchRevert(new ICVC.BatchItem[](0)); + evc.batchRevert(new IEVC.BatchItem[](0)); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.batchSimulation(new ICVC.BatchItem[](0)); - cvc.setChecksLock(false); + evc.batchSimulation(new IEVC.BatchItem[](0)); + evc.setChecksLock(false); - address vault = address(new VaultMalicious(cvc)); + address vault = address(new VaultMalicious(evc)); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].onBehalfOfAccount = alice; items[0].targetContract = vault; items[0].value = 0; @@ -398,15 +398,15 @@ contract BatchTest is Test { true ); - // internal batch in the malicious vault reverts with CVC_ChecksReentrancy error, + // internal batch in the malicious vault reverts with EVC_ChecksReentrancy error, // check VaultMalicious implementation // error will be encoded in the result - ICVC.BatchItemResult[] - memory expectedBatchItemsResult = new ICVC.BatchItemResult[](1); - ICVC.BatchItemResult[] - memory expectedAccountsStatusResult = new ICVC.BatchItemResult[](1); - ICVC.BatchItemResult[] - memory expectedVaultsStatusResult = new ICVC.BatchItemResult[](1); + IEVC.BatchItemResult[] + memory expectedBatchItemsResult = new IEVC.BatchItemResult[](1); + IEVC.BatchItemResult[] + memory expectedAccountsStatusResult = new IEVC.BatchItemResult[](1); + IEVC.BatchItemResult[] + memory expectedVaultsStatusResult = new IEVC.BatchItemResult[](1); expectedBatchItemsResult[0].success = true; expectedBatchItemsResult[0].result = ""; @@ -421,31 +421,31 @@ contract BatchTest is Test { ); VaultMalicious(vault).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); vm.prank(alice); vm.expectRevert( abi.encodeWithSelector( - Errors.CVC_RevertedBatchResult.selector, + Errors.EVC_RevertedBatchResult.selector, expectedBatchItemsResult, expectedAccountsStatusResult, expectedVaultsStatusResult ) ); - cvc.batchRevert(items); + evc.batchRevert(items); // same should happen for batchSimulation() but without reverting with standard error VaultMalicious(vault).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); vm.prank(alice); ( - ICVC.BatchItemResult[] memory batchItemsResult, - ICVC.BatchItemResult[] memory accountsStatusResult, - ICVC.BatchItemResult[] memory vaultsStatusResult - ) = cvc.batchSimulation(items); + IEVC.BatchItemResult[] memory batchItemsResult, + IEVC.BatchItemResult[] memory accountsStatusResult, + IEVC.BatchItemResult[] memory vaultsStatusResult + ) = evc.batchSimulation(items); assertEq(batchItemsResult.length, 1); assertEq( @@ -481,33 +481,33 @@ contract BatchTest is Test { function test_RevertIfImpersonateReentrancy_AcquireImpersonateLock_Batch( address alice ) external { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ImpersonateReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ImpersonateReentrancy.selector) ); - cvc.batch(new ICVC.BatchItem[](0)); - cvc.setImpersonateLock(false); + evc.batch(new IEVC.BatchItem[](0)); + evc.setImpersonateLock(false); - address controller = address(new Vault(cvc)); - address collateral = address(new VaultMalicious(cvc)); + address controller = address(new Vault(evc)); + address collateral = address(new VaultMalicious(evc)); vm.prank(alice); - cvc.enableController(alice, controller); + evc.enableController(alice, controller); vm.prank(alice); - cvc.enableCollateral(alice, collateral); + evc.enableCollateral(alice, collateral); - // internal batch in the malicious vault reverts with CVC_ImpersonateReentrancy error, + // internal batch in the malicious vault reverts with EVC_ImpersonateReentrancy error, // check VaultMalicious implementation VaultMalicious(collateral).setExpectedErrorSelector( - Errors.CVC_ImpersonateReentrancy.selector + Errors.EVC_ImpersonateReentrancy.selector ); vm.prank(controller); vm.expectRevert("callBatch/expected-error"); - cvc.impersonate( + evc.impersonate( collateral, alice, 0, @@ -518,39 +518,39 @@ contract BatchTest is Test { function test_RevertIfImpersonateReentrancy_AcquireImpersonateLock_BatchRevert_BatchSimulation( address alice ) external { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ImpersonateReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ImpersonateReentrancy.selector) ); - cvc.batchRevert(new ICVC.BatchItem[](0)); + evc.batchRevert(new IEVC.BatchItem[](0)); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ImpersonateReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ImpersonateReentrancy.selector) ); - cvc.batchSimulation(new ICVC.BatchItem[](0)); + evc.batchSimulation(new IEVC.BatchItem[](0)); - cvc.setImpersonateLock(false); + evc.setImpersonateLock(false); - address controller = address(new Vault(cvc)); - address collateral = address(new VaultMalicious(cvc)); + address controller = address(new Vault(evc)); + address collateral = address(new VaultMalicious(evc)); vm.prank(alice); - cvc.enableController(alice, controller); + evc.enableController(alice, controller); vm.prank(alice); - cvc.enableCollateral(alice, collateral); + evc.enableCollateral(alice, collateral); - // internal batch in the malicious vault reverts with CVC_ImpersonateReentrancy error, + // internal batch in the malicious vault reverts with EVC_ImpersonateReentrancy error, // check VaultMalicious implementation VaultMalicious(collateral).setExpectedErrorSelector( - Errors.CVC_ImpersonateReentrancy.selector + Errors.EVC_ImpersonateReentrancy.selector ); vm.prank(controller); vm.expectRevert("callBatch/expected-error"); - cvc.impersonate( + evc.impersonate( collateral, alice, 0, @@ -562,12 +562,12 @@ contract BatchTest is Test { address alice, uint128 seed ) external { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(seed > 0); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); items[0].onBehalfOfAccount = alice; items[0].targetContract = vault; items[0].value = seed; @@ -579,29 +579,29 @@ contract BatchTest is Test { // reverts if value exceeds balance vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidValue.selector); - cvc.batch{value: seed - 1}(items); + vm.expectRevert(Errors.EVC_InvalidValue.selector); + evc.batch{value: seed - 1}(items); // succeeds if value does not exceed balance vm.prank(alice); - cvc.batch{value: seed}(items); + evc.batch{value: seed}(items); } function test_BatchRevert_BatchSimulation(address alice) external { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); - ICVC.BatchItemResult[] - memory expectedBatchItemsResult = new ICVC.BatchItemResult[](1); - ICVC.BatchItemResult[] - memory expectedAccountsStatusResult = new ICVC.BatchItemResult[](1); - ICVC.BatchItemResult[] - memory expectedVaultsStatusResult = new ICVC.BatchItemResult[](1); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); + IEVC.BatchItemResult[] + memory expectedBatchItemsResult = new IEVC.BatchItemResult[](1); + IEVC.BatchItemResult[] + memory expectedAccountsStatusResult = new IEVC.BatchItemResult[](1); + IEVC.BatchItemResult[] + memory expectedVaultsStatusResult = new IEVC.BatchItemResult[](1); - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); vm.prank(alice); - cvc.enableController(alice, controller); + evc.enableController(alice, controller); items[0].onBehalfOfAccount = alice; items[0].targetContract = controller; @@ -616,38 +616,38 @@ contract BatchTest is Test { expectedAccountsStatusResult[0].success = true; expectedAccountsStatusResult[0].result = abi.encode( - ICreditVault.checkAccountStatus.selector + IVault.checkAccountStatus.selector ); expectedVaultsStatusResult[0].success = true; expectedVaultsStatusResult[0].result = abi.encode( - ICreditVault.checkVaultStatus.selector + IVault.checkVaultStatus.selector ); // regular batch doesn't revert vm.prank(alice); - cvc.batch(items); + evc.batch(items); { vm.prank(alice); - try cvc.batchRevert(items) { + try evc.batchRevert(items) { assert(false); } catch (bytes memory err) { - assertEq(bytes4(err), Errors.CVC_RevertedBatchResult.selector); + assertEq(bytes4(err), Errors.EVC_RevertedBatchResult.selector); assembly { err := add(err, 4) } ( - ICVC.BatchItemResult[] memory batchItemsResult, - ICVC.BatchItemResult[] memory accountsStatusResult, - ICVC.BatchItemResult[] memory vaultsStatusResult + IEVC.BatchItemResult[] memory batchItemsResult, + IEVC.BatchItemResult[] memory accountsStatusResult, + IEVC.BatchItemResult[] memory vaultsStatusResult ) = abi.decode( err, ( - ICVC.BatchItemResult[], - ICVC.BatchItemResult[], - ICVC.BatchItemResult[] + IEVC.BatchItemResult[], + IEVC.BatchItemResult[], + IEVC.BatchItemResult[] ) ); @@ -695,10 +695,10 @@ contract BatchTest is Test { { vm.prank(alice); ( - ICVC.BatchItemResult[] memory batchItemsResult, - ICVC.BatchItemResult[] memory accountsStatusResult, - ICVC.BatchItemResult[] memory vaultsStatusResult - ) = cvc.batchSimulation(items); + IEVC.BatchItemResult[] memory batchItemsResult, + IEVC.BatchItemResult[] memory accountsStatusResult, + IEVC.BatchItemResult[] memory vaultsStatusResult + ) = evc.batchSimulation(items); assertEq(expectedBatchItemsResult.length, batchItemsResult.length); assertEq( @@ -757,28 +757,28 @@ contract BatchTest is Test { // regular batch reverts now vm.prank(alice); vm.expectRevert(bytes("account status violation")); - cvc.batch(items); + evc.batch(items); { vm.prank(alice); - try cvc.batchRevert(items) { + try evc.batchRevert(items) { assert(false); } catch (bytes memory err) { - assertEq(bytes4(err), Errors.CVC_RevertedBatchResult.selector); + assertEq(bytes4(err), Errors.EVC_RevertedBatchResult.selector); assembly { err := add(err, 4) } ( - ICVC.BatchItemResult[] memory batchItemsResult, - ICVC.BatchItemResult[] memory accountsStatusResult, - ICVC.BatchItemResult[] memory vaultsStatusResult + IEVC.BatchItemResult[] memory batchItemsResult, + IEVC.BatchItemResult[] memory accountsStatusResult, + IEVC.BatchItemResult[] memory vaultsStatusResult ) = abi.decode( err, ( - ICVC.BatchItemResult[], - ICVC.BatchItemResult[], - ICVC.BatchItemResult[] + IEVC.BatchItemResult[], + IEVC.BatchItemResult[], + IEVC.BatchItemResult[] ) ); @@ -826,10 +826,10 @@ contract BatchTest is Test { { vm.prank(alice); ( - ICVC.BatchItemResult[] memory batchItemsResult, - ICVC.BatchItemResult[] memory accountsStatusResult, - ICVC.BatchItemResult[] memory vaultsStatusResult - ) = cvc.batchSimulation(items); + IEVC.BatchItemResult[] memory batchItemsResult, + IEVC.BatchItemResult[] memory accountsStatusResult, + IEVC.BatchItemResult[] memory vaultsStatusResult + ) = evc.batchSimulation(items); assertEq(expectedBatchItemsResult.length, batchItemsResult.length); assertEq( @@ -872,11 +872,11 @@ contract BatchTest is Test { function test_RevertIfBatchRevertDoesntRevert_BatchSimulation( address alice ) external { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - ICVC cvc_noRevert = new CreditVaultConnectorNoRevert(); + IEVC evc_noRevert = new EthereumVaultConnectorNoRevert(); vm.prank(alice); - vm.expectRevert(Errors.CVC_BatchPanic.selector); - cvc_noRevert.batchSimulation(new ICVC.BatchItem[](0)); + vm.expectRevert(Errors.EVC_BatchPanic.selector); + evc_noRevert.batchSimulation(new IEVC.BatchItem[](0)); } } diff --git a/test/unit/CreditVaultConnector/Call.t.sol b/test/unit/EthereumVaultConnector/Call.t.sol similarity index 63% rename from test/unit/CreditVaultConnector/Call.t.sol rename to test/unit/EthereumVaultConnector/Call.t.sol index 7dedf8b7..2400be3f 100644 --- a/test/unit/CreditVaultConnector/Call.t.sol +++ b/test/unit/EthereumVaultConnector/Call.t.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; -contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { +contract EthereumVaultConnectorHandler is EthereumVaultConnectorHarness { using Set for SetStorage; function handlerCall( @@ -22,7 +22,7 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { } contract CallTest is Test { - CreditVaultConnectorHandler internal cvc; + EthereumVaultConnectorHandler internal evc; event CallWithContext( address indexed caller, @@ -32,18 +32,18 @@ contract CallTest is Test { ); function setUp() public { - cvc = new CreditVaultConnectorHandler(); + evc = new EthereumVaultConnectorHandler(); } function test_Call(address alice, uint96 seed) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); address account; if (seed % 2 == 0) { // in this case the account is not alice's sub-account thus alice must be an operator account = address(uint160(alice) ^ 256); vm.prank(account); - cvc.setAccountOperator(account, alice, true); + evc.setAccountOperator(account, alice, true); } else { // in this case the account is alice's sub-account account = address(uint160(alice) ^ (seed % 256)); @@ -51,29 +51,37 @@ contract CallTest is Test { vm.assume(account != address(0)); address targetContract = address(new Target()); + address nestedTargetContract = address(new TargetWithNesting()); + address controller = address(new Vault(evc)); + vm.assume( + targetContract != alice && + targetContract != address(evc) && + !evc.haveCommonOwner(targetContract, alice) && + !evc.haveCommonOwner(targetContract, account) + ); vm.assume( - targetContract != address(cvc) && - !cvc.haveCommonOwner(targetContract, alice) && - !cvc.haveCommonOwner(targetContract, account) + nestedTargetContract != alice && + nestedTargetContract != address(evc) && + !evc.haveCommonOwner(nestedTargetContract, alice) && + !evc.haveCommonOwner(nestedTargetContract, account) ); - address controller = address(new Vault(cvc)); vm.prank(alice); - cvc.enableController(account, controller); - cvc.reset(); + evc.enableController(account, controller); + evc.reset(); Vault(controller).reset(); bytes memory data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, account, seed % 2 == 0 ); vm.deal(alice, seed); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( alice, targetContract, @@ -81,7 +89,7 @@ contract CallTest is Test { Target.callTest.selector ); vm.prank(alice); - bytes memory result = cvc.handlerCall{value: seed}( + bytes memory result = evc.handlerCall{value: seed}( targetContract, account, seed, @@ -89,15 +97,14 @@ contract CallTest is Test { ); assertEq(abi.decode(result, (uint)), seed); - cvc.reset(); + evc.reset(); Vault(controller).reset(); // on behalf of account should be correct in a nested call as well - address nestedTargetContract = address(new TargetWithNesting()); data = abi.encodeWithSelector( TargetWithNesting(nestedTargetContract).nestedCallTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), targetContract, seed, account, @@ -105,14 +112,14 @@ contract CallTest is Test { ); vm.deal(alice, seed); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( alice, nestedTargetContract, account, TargetWithNesting.nestedCallTest.selector ); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( nestedTargetContract, targetContract, @@ -120,7 +127,7 @@ contract CallTest is Test { Target.callTest.selector ); vm.prank(alice); - result = cvc.handlerCall{value: seed}( + result = evc.handlerCall{value: seed}( nestedTargetContract, account, seed, @@ -130,13 +137,13 @@ contract CallTest is Test { } function test_RevertIfDepthExceeded_Call(address alice) external { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); - cvc.setCallDepth(10); + evc.setCallDepth(10); vm.prank(alice); vm.expectRevert(ExecutionContext.CallDepthViolation.selector); - cvc.call(address(0), alice, 0, ""); + evc.call(address(0), alice, 0, ""); } function test_RevertIfNotOwnerOrOperator_Call( @@ -144,17 +151,17 @@ contract CallTest is Test { address bob, uint seed ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(!cvc.haveCommonOwner(alice, bob)); + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(!evc.haveCommonOwner(alice, bob)); vm.assume(bob != address(0)); address targetContract = address(new Target()); - vm.assume(targetContract != address(cvc)); + vm.assume(targetContract != address(evc)); bytes memory data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, alice, false @@ -162,25 +169,25 @@ contract CallTest is Test { vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.call{value: seed}(targetContract, bob, seed, data); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.call{value: seed}(targetContract, bob, seed, data); } function test_RevertIfChecksReentrancy_Call( address alice, uint seed ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); address targetContract = address(new Target()); - vm.assume(targetContract != address(cvc)); + vm.assume(targetContract != address(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); bytes memory data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, alice, false @@ -188,25 +195,25 @@ contract CallTest is Test { vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.call{value: seed}(targetContract, alice, seed, data); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.call{value: seed}(targetContract, alice, seed, data); } function test_RevertIfImpersonateReentrancy_Call( address alice, uint seed ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); address targetContract = address(new Target()); - vm.assume(targetContract != address(cvc)); + vm.assume(targetContract != address(evc)); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); bytes memory data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, alice, false @@ -214,8 +221,8 @@ contract CallTest is Test { vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.call{value: seed}(targetContract, alice, seed, data); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.call{value: seed}(targetContract, alice, seed, data); } function test_RevertIfTargetContractInvalid_Call( @@ -226,13 +233,13 @@ contract CallTest is Test { setUp(); vm.assume(alice != address(0)); - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - // target contract is the CVC - address targetContract = address(cvc); + // target contract is the EVC + address targetContract = address(evc); bytes memory data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), + address(evc), targetContract, seed, alice, @@ -241,30 +248,30 @@ contract CallTest is Test { vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.call{value: seed}(targetContract, alice, seed, data); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.call{value: seed}(targetContract, alice, seed, data); // target contract is the msg.sender targetContract = address(this); data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, address(this), false ); vm.deal(address(this), seed); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.call{value: seed}(targetContract, address(this), seed, data); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.call{value: seed}(targetContract, address(this), seed, data); // target contract is the ERC1820 registry targetContract = 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24; data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, alice, false @@ -272,24 +279,24 @@ contract CallTest is Test { vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.call{value: seed}(targetContract, alice, seed, data); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.call{value: seed}(targetContract, alice, seed, data); } function test_RevertIfValueExceedsBalance_Call( address alice, uint128 seed ) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(seed > 0); address targetContract = address(new Target()); - vm.assume(targetContract != address(cvc)); + vm.assume(targetContract != address(evc)); bytes memory data = abi.encodeWithSelector( Target(targetContract).callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, alice, false @@ -298,12 +305,12 @@ contract CallTest is Test { // reverts if value exceeds balance vm.deal(alice, seed); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidValue.selector); - cvc.call{value: seed - 1}(targetContract, alice, seed, data); + vm.expectRevert(Errors.EVC_InvalidValue.selector); + evc.call{value: seed - 1}(targetContract, alice, seed, data); // succeeds if value does not exceed balance vm.prank(alice); - cvc.call{value: seed}(targetContract, alice, seed, data); + evc.call{value: seed}(targetContract, alice, seed, data); } function test_RevertIfInternalCallIsUnsuccessful_Call( @@ -313,17 +320,17 @@ contract CallTest is Test { setUp(); vm.assume(alice != address(0)); - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); address targetContract = address(new Target()); - vm.assume(targetContract != address(cvc)); + vm.assume(targetContract != address(evc)); bytes memory data = abi.encodeWithSelector( Target(targetContract).revertEmptyTest.selector ); vm.prank(alice); - vm.expectRevert(Errors.CVC_EmptyError.selector); - cvc.call(targetContract, alice, 0, data); + vm.expectRevert(Errors.EVC_EmptyError.selector); + evc.call(targetContract, alice, 0, data); } } diff --git a/test/unit/CreditVaultConnector/Callback.t.sol b/test/unit/EthereumVaultConnector/Callback.t.sol similarity index 62% rename from test/unit/CreditVaultConnector/Callback.t.sol rename to test/unit/EthereumVaultConnector/Callback.t.sol index ae628f6f..259ba9fc 100644 --- a/test/unit/CreditVaultConnector/Callback.t.sol +++ b/test/unit/EthereumVaultConnector/Callback.t.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; -contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { +contract EthereumVaultConnectorHandler is EthereumVaultConnectorHarness { using Set for SetStorage; function handlerCallback( @@ -21,7 +21,7 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { } contract CallbackTest is Test { - CreditVaultConnectorHandler internal cvc; + EthereumVaultConnectorHandler internal evc; event CallWithContext( address indexed caller, @@ -31,7 +31,7 @@ contract CallbackTest is Test { ); function setUp() public { - cvc = new CreditVaultConnectorHandler(); + evc = new EthereumVaultConnectorHandler(); } fallback(bytes calldata data) external payable returns (bytes memory) { @@ -47,14 +47,14 @@ contract CallbackTest is Test { bytes memory data, uint96 seed ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - address controller = address(new Vault(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); + address controller = address(new Vault(evc)); // first, test with a fallback function vm.deal(address(this), seed); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext(address(this), address(this), alice, bytes4(data)); - bytes memory result = cvc.handlerCallback{value: seed}( + bytes memory result = evc.handlerCallback{value: seed}( alice, seed, data @@ -63,20 +63,20 @@ contract CallbackTest is Test { // then, test with a function selector vm.prank(alice); - cvc.enableController(alice, controller); - cvc.reset(); + evc.enableController(alice, controller); + evc.reset(); Vault(controller).reset(); data = abi.encodeWithSelector( Target(controller).callbackTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), seed, alice ); vm.deal(controller, seed); - vm.expectEmit(true, true, true, true, address(cvc)); + vm.expectEmit(true, true, true, true, address(evc)); emit CallWithContext( controller, controller, @@ -84,44 +84,44 @@ contract CallbackTest is Test { Target.callbackTest.selector ); vm.prank(controller); - result = cvc.handlerCallback{value: seed}(alice, seed, data); + result = evc.handlerCallback{value: seed}(alice, seed, data); assertEq(abi.decode(result, (uint)), seed); } function test_RevertIfDepthExceeded_Callback(address alice) external { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - cvc.setCallDepth(10); + evc.setCallDepth(10); vm.prank(alice); vm.expectRevert(ExecutionContext.CallDepthViolation.selector); - cvc.callback(alice, 0, ""); + evc.callback(alice, 0, ""); } function test_RevertIfChecksReentrancy_Callback( address alice, uint seed ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.deal(address(this), seed); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.callback{value: seed}(alice, seed, ""); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.callback{value: seed}(alice, seed, ""); } function test_RevertIfImpersonateReentrancy_Callback( address alice, uint seed ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.deal(address(this), seed); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.callback{value: seed}(alice, seed, ""); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.callback{value: seed}(alice, seed, ""); } function test_RevertIfMsgSenderNotAuthorized_Callback( @@ -129,42 +129,42 @@ contract CallbackTest is Test { uint seed ) public { vm.assume(alice != address(0)); - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - // msg.sender is the CVC - vm.deal(address(cvc), seed); - vm.prank(address(cvc)); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.callback{value: seed}(alice, seed, ""); + // msg.sender is the EVC + vm.deal(address(evc), seed); + vm.prank(address(evc)); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.callback{value: seed}(alice, seed, ""); } function test_RevertIfValueExceedsBalance_Call( address alice, uint128 seed ) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(seed > 0); // reverts if value exceeds balance vm.deal(address(this), seed); - vm.expectRevert(Errors.CVC_InvalidValue.selector); - cvc.callback{value: seed - 1}(alice, seed, ""); + vm.expectRevert(Errors.EVC_InvalidValue.selector); + evc.callback{value: seed - 1}(alice, seed, ""); // succeeds if value does not exceed balance - cvc.callback{value: seed}(alice, seed, ""); + evc.callback{value: seed}(alice, seed, ""); } function test_RevertIfInternalCallIsUnsuccessful_Callback( address alice ) public { vm.assume(alice != address(0)); - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); bytes memory data = abi.encodeWithSelector( this.revertEmptyTest.selector ); - vm.expectRevert(Errors.CVC_EmptyError.selector); - cvc.callback(alice, 0, data); + vm.expectRevert(Errors.EVC_EmptyError.selector); + evc.callback(alice, 0, data); } } diff --git a/test/unit/CreditVaultConnector/CollateralsManagement.sol b/test/unit/EthereumVaultConnector/CollateralsManagement.sol similarity index 58% rename from test/unit/CreditVaultConnector/CollateralsManagement.sol rename to test/unit/EthereumVaultConnector/CollateralsManagement.sol index ddd8d9d8..2b0b5c8c 100644 --- a/test/unit/CreditVaultConnector/CollateralsManagement.sol +++ b/test/unit/EthereumVaultConnector/CollateralsManagement.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; -contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { +contract EthereumVaultConnectorHandler is EthereumVaultConnectorHarness { using ExecutionContext for EC; using Set for SetStorage; @@ -35,7 +35,7 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { } contract CollateralsManagementTest is Test { - CreditVaultConnectorHandler internal cvc; + EthereumVaultConnectorHandler internal evc; event CollateralStatus( address indexed account, @@ -44,7 +44,7 @@ contract CollateralsManagementTest is Test { ); function setUp() public { - cvc = new CreditVaultConnectorHandler(); + evc = new EthereumVaultConnectorHandler(); } function test_CollateralsManagement( @@ -56,47 +56,47 @@ contract CollateralsManagementTest is Test { // call setUp() explicitly for Dilligence Fuzzing tool to pass setUp(); - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(numberOfVaults > 0 && numberOfVaults <= Set.MAX_ELEMENTS); vm.assume(seed > 1000); address account = address(uint160(uint160(alice) ^ subAccountId)); - vm.expectRevert(Errors.CVC_AccountOwnerNotRegistered.selector); - cvc.getAccountOwner(account); + vm.expectRevert(Errors.EVC_AccountOwnerNotRegistered.selector); + evc.getAccountOwner(account); // test collaterals management with use of an operator address msgSender = alice; if ( seed % 2 == 0 && - !cvc.haveCommonOwner(account, address(uint160(seed))) + !evc.haveCommonOwner(account, address(uint160(seed))) ) { msgSender = address( uint160(uint(keccak256(abi.encodePacked(seed)))) ); vm.prank(alice); - cvc.setAccountOperator(account, msgSender, true); - assertEq(cvc.getAccountOwner(account), alice); + evc.setAccountOperator(account, msgSender, true); + assertEq(evc.getAccountOwner(account), alice); } // enable a controller to check if account status check works properly - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); if (seed % 3 == 0) { vm.prank(alice); - cvc.enableController(account, controller); - assertEq(cvc.getAccountOwner(account), alice); + evc.enableController(account, controller); + assertEq(evc.getAccountOwner(account), alice); } // enabling collaterals for (uint i = 1; i <= numberOfVaults; ++i) { Vault(controller).clearChecks(); - address[] memory collateralsPre = cvc.getCollaterals(account); + address[] memory collateralsPre = evc.getCollaterals(account); address vault = i % 5 == 0 ? collateralsPre[seed % collateralsPre.length] - : address(new Vault(cvc)); + : address(new Vault(evc)); - bool alreadyEnabled = cvc.isCollateralEnabled(account, vault); + bool alreadyEnabled = evc.isCollateralEnabled(account, vault); assert( (alreadyEnabled && i % 5 == 0) || @@ -104,13 +104,13 @@ contract CollateralsManagementTest is Test { ); if (!alreadyEnabled) { - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit CollateralStatus(account, vault, true); } vm.prank(msgSender); - cvc.handlerEnableCollateral(account, vault); + evc.handlerEnableCollateral(account, vault); - address[] memory collateralsPost = cvc.getCollaterals(account); + address[] memory collateralsPost = evc.getCollaterals(account); if (alreadyEnabled) { assertEq(collateralsPost.length, collateralsPre.length); @@ -125,17 +125,17 @@ contract CollateralsManagementTest is Test { } // disabling collaterals - while (cvc.getCollaterals(account).length > 0) { + while (evc.getCollaterals(account).length > 0) { Vault(controller).clearChecks(); - address[] memory collateralsPre = cvc.getCollaterals(account); + address[] memory collateralsPre = evc.getCollaterals(account); address vault = collateralsPre[seed % collateralsPre.length]; - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit CollateralStatus(account, vault, false); vm.prank(msgSender); - cvc.handlerDisableCollateral(account, vault); + evc.handlerDisableCollateral(account, vault); - address[] memory collateralsPost = cvc.getCollaterals(account); + address[] memory collateralsPost = evc.getCollaterals(account); assertEq(collateralsPost.length, collateralsPre.length - 1); @@ -151,128 +151,128 @@ contract CollateralsManagementTest is Test { ) public { vm.assume( alice != address(0) && - alice != address(cvc) && + alice != address(evc) && bob != address(0) && - bob != address(cvc) + bob != address(evc) ); - vm.assume(!cvc.haveCommonOwner(alice, bob)); + vm.assume(!evc.haveCommonOwner(alice, bob)); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.enableCollateral(bob, vault); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.enableCollateral(bob, vault); vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.disableCollateral(bob, vault); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.disableCollateral(bob, vault); vm.prank(bob); - cvc.setAccountOperator(bob, alice, true); + evc.setAccountOperator(bob, alice, true); vm.prank(alice); - cvc.enableCollateral(bob, vault); + evc.enableCollateral(bob, vault); vm.prank(alice); - cvc.disableCollateral(bob, vault); + evc.disableCollateral(bob, vault); } function test_RevertIfChecksReentrancy_CollateralsManagement( address alice ) public { - vm.assume(alice != address(cvc)); - address vault = address(new Vault(cvc)); + vm.assume(alice != address(evc)); + address vault = address(new Vault(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(alice); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.enableCollateral(alice, vault); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.enableCollateral(alice, vault); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(alice); - cvc.enableCollateral(alice, vault); + evc.enableCollateral(alice, vault); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(alice); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.disableCollateral(alice, vault); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.disableCollateral(alice, vault); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(alice); - cvc.disableCollateral(alice, vault); + evc.disableCollateral(alice, vault); } function test_RevertIfImpersonateReentrancy_CollateralsManagement( address alice ) public { - vm.assume(alice != address(cvc)); - address vault = address(new Vault(cvc)); + vm.assume(alice != address(evc)); + address vault = address(new Vault(evc)); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.prank(alice); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.enableCollateral(alice, vault); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.enableCollateral(alice, vault); - cvc.setImpersonateLock(false); + evc.setImpersonateLock(false); vm.prank(alice); - cvc.enableCollateral(alice, vault); + evc.enableCollateral(alice, vault); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.prank(alice); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.disableCollateral(alice, vault); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.disableCollateral(alice, vault); - cvc.setImpersonateLock(false); + evc.setImpersonateLock(false); vm.prank(alice); - cvc.disableCollateral(alice, vault); + evc.disableCollateral(alice, vault); } function test_RevertIfInvalidVault_CollateralsManagement( address alice ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.enableCollateral(alice, address(cvc)); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.enableCollateral(alice, address(evc)); } function test_RevertIfAccountStatusViolated_CollateralsManagement( address alice ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - address vault = address(new Vault(cvc)); - address controller = address(new Vault(cvc)); + address vault = address(new Vault(evc)); + address controller = address(new Vault(evc)); vm.prank(alice); - cvc.enableController(alice, controller); + evc.enableController(alice, controller); Vault(controller).setAccountStatusState(1); // account status is violated vm.prank(alice); vm.expectRevert(bytes("account status violation")); - cvc.enableCollateral(alice, vault); + evc.enableCollateral(alice, vault); vm.prank(alice); vm.expectRevert(bytes("account status violation")); - cvc.disableCollateral(alice, vault); + evc.disableCollateral(alice, vault); Vault(controller).setAccountStatusState(0); // account status is NOT violated Vault(controller).clearChecks(); vm.prank(alice); - cvc.enableCollateral(alice, vault); + evc.enableCollateral(alice, vault); Vault(controller).clearChecks(); vm.prank(alice); - cvc.disableCollateral(alice, vault); + evc.disableCollateral(alice, vault); } } diff --git a/test/unit/CreditVaultConnector/ControllersManagement.sol b/test/unit/EthereumVaultConnector/ControllersManagement.sol similarity index 55% rename from test/unit/CreditVaultConnector/ControllersManagement.sol rename to test/unit/EthereumVaultConnector/ControllersManagement.sol index 4c337c30..857ad4f7 100644 --- a/test/unit/CreditVaultConnector/ControllersManagement.sol +++ b/test/unit/EthereumVaultConnector/ControllersManagement.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; -contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { +contract EthereumVaultConnectorHandler is EthereumVaultConnectorHarness { using ExecutionContext for EC; using Set for SetStorage; @@ -37,7 +37,7 @@ contract CreditVaultConnectorHandler is CreditVaultConnectorHarness { } contract ControllersManagementTest is Test { - CreditVaultConnectorHandler internal cvc; + EthereumVaultConnectorHandler internal evc; event ControllerStatus( address indexed account, @@ -46,7 +46,7 @@ contract ControllersManagementTest is Test { ); function setUp() public { - cvc = new CreditVaultConnectorHandler(); + evc = new EthereumVaultConnectorHandler(); } function test_ControllersManagement( @@ -54,7 +54,7 @@ contract ControllersManagementTest is Test { uint8 subAccountId, uint seed ) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(seed > 1000); address account = address(uint160(uint160(alice) ^ subAccountId)); @@ -63,69 +63,69 @@ contract ControllersManagementTest is Test { address msgSender = alice; if ( seed % 2 == 0 && - !cvc.haveCommonOwner(account, address(uint160(seed))) + !evc.haveCommonOwner(account, address(uint160(seed))) ) { msgSender = address(uint160(uint(keccak256(abi.encode(seed))))); vm.prank(alice); - cvc.setAccountOperator(account, msgSender, true); + evc.setAccountOperator(account, msgSender, true); } // enabling controller - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); - assertFalse(cvc.isControllerEnabled(account, vault)); - address[] memory controllersPre = cvc.getControllers(account); + assertFalse(evc.isControllerEnabled(account, vault)); + address[] memory controllersPre = evc.getControllers(account); - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit ControllerStatus(account, vault, true); vm.prank(msgSender); - cvc.handlerEnableController(account, vault); + evc.handlerEnableController(account, vault); - address[] memory controllersPost = cvc.getControllers(account); + address[] memory controllersPost = evc.getControllers(account); assertEq(controllersPost.length, controllersPre.length + 1); assertEq(controllersPost[controllersPost.length - 1], vault); - assertTrue(cvc.isControllerEnabled(account, vault)); + assertTrue(evc.isControllerEnabled(account, vault)); // enabling the same controller again should succeed (duplicate will not be added and the event won't be emitted) - assertTrue(cvc.isControllerEnabled(account, vault)); - controllersPre = cvc.getControllers(account); + assertTrue(evc.isControllerEnabled(account, vault)); + controllersPre = evc.getControllers(account); vm.prank(msgSender); - cvc.handlerEnableController(account, vault); + evc.handlerEnableController(account, vault); - controllersPost = cvc.getControllers(account); + controllersPost = evc.getControllers(account); assertEq(controllersPost.length, controllersPre.length); assertEq(controllersPost[0], controllersPre[0]); - assertTrue(cvc.isControllerEnabled(account, vault)); + assertTrue(evc.isControllerEnabled(account, vault)); // trying to enable second controller will throw on the account status check - address otherVault = address(new Vault(cvc)); + address otherVault = address(new Vault(evc)); vm.prank(msgSender); - vm.expectRevert(Errors.CVC_ControllerViolation.selector); - cvc.handlerEnableController(account, otherVault); + vm.expectRevert(Errors.EVC_ControllerViolation.selector); + evc.handlerEnableController(account, otherVault); // only the controller vault can disable itself - assertTrue(cvc.isControllerEnabled(account, vault)); - controllersPre = cvc.getControllers(account); + assertTrue(evc.isControllerEnabled(account, vault)); + controllersPre = evc.getControllers(account); vm.prank(msgSender); - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit ControllerStatus(account, vault, false); Vault(vault).call( - address(cvc), + address(evc), abi.encodeWithSelector( - cvc.handlerDisableController.selector, + evc.handlerDisableController.selector, account ) ); - controllersPost = cvc.getControllers(account); + controllersPost = evc.getControllers(account); assertEq(controllersPost.length, controllersPre.length - 1); assertEq(controllersPost.length, 0); - assertFalse(cvc.isControllerEnabled(account, vault)); + assertFalse(evc.isControllerEnabled(account, vault)); } function test_RevertIfNotOwnerOrNotOperator_EnableController( @@ -134,130 +134,130 @@ contract ControllersManagementTest is Test { ) public { vm.assume( alice != address(0) && - alice != address(cvc) && + alice != address(evc) && bob != address(0) && - bob != address(cvc) + bob != address(evc) ); - vm.assume(!cvc.haveCommonOwner(alice, bob)); + vm.assume(!evc.haveCommonOwner(alice, bob)); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.handlerEnableController(bob, vault); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.handlerEnableController(bob, vault); vm.prank(bob); - cvc.setAccountOperator(bob, alice, true); + evc.setAccountOperator(bob, alice, true); vm.prank(alice); - cvc.handlerEnableController(bob, vault); + evc.handlerEnableController(bob, vault); } function test_RevertIfProgressReentrancy_ControllersManagement( address alice ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(alice); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.enableController(alice, vault); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.enableController(alice, vault); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(alice); - cvc.enableController(alice, vault); + evc.enableController(alice, vault); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(vault); - vm.expectRevert(Errors.CVC_ChecksReentrancy.selector); - cvc.disableController(alice); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.disableController(alice); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(vault); - cvc.disableController(alice); + evc.disableController(alice); } function test_RevertIfImpersonateReentrancy_ControllersManagement( address alice ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.prank(alice); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.enableController(alice, vault); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.enableController(alice, vault); - cvc.setImpersonateLock(false); + evc.setImpersonateLock(false); vm.prank(alice); - cvc.enableController(alice, vault); + evc.enableController(alice, vault); - cvc.setImpersonateLock(true); + evc.setImpersonateLock(true); vm.prank(vault); - vm.expectRevert(Errors.CVC_ImpersonateReentrancy.selector); - cvc.disableController(alice); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.disableController(alice); - cvc.setImpersonateLock(false); + evc.setImpersonateLock(false); vm.prank(vault); - cvc.disableController(alice); + evc.disableController(alice); } function test_RevertIfInvalidVault_ControllersManagement( address alice ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.enableController(alice, address(cvc)); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.enableController(alice, address(evc)); } function test_RevertIfAccountStatusViolated_ControllersManagement( address alice ) public { - vm.assume(alice != address(cvc)); + vm.assume(alice != address(evc)); - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); Vault(vault).setAccountStatusState(1); // account status is violated vm.prank(alice); vm.expectRevert("account status violation"); - cvc.handlerEnableController(alice, vault); + evc.handlerEnableController(alice, vault); vm.prank(alice); // succeeds as there's no controller to perform the account status check Vault(vault).call( - address(cvc), - abi.encodeWithSelector(cvc.handlerDisableController.selector, alice) + address(evc), + abi.encodeWithSelector(evc.handlerDisableController.selector, alice) ); Vault(vault).setAccountStatusState(1); // account status is still violated vm.prank(alice); // succeeds as there's no controller to perform the account status check - cvc.enableCollateral(alice, vault); + evc.enableCollateral(alice, vault); Vault(vault).setAccountStatusState(0); // account status is no longer violated in order to enable controller vm.prank(alice); - cvc.handlerEnableController(alice, vault); + evc.handlerEnableController(alice, vault); Vault(vault).setAccountStatusState(1); // account status is violated again vm.prank(alice); // it won't succeed as this time we have a controller so the account status check is performed vm.expectRevert("account status violation"); - cvc.enableCollateral(alice, vault); + evc.enableCollateral(alice, vault); } } diff --git a/test/unit/CreditVaultConnector/GetExecutionContext.t.sol b/test/unit/EthereumVaultConnector/GetExecutionContext.t.sol similarity index 59% rename from test/unit/CreditVaultConnector/GetExecutionContext.t.sol rename to test/unit/EthereumVaultConnector/GetExecutionContext.t.sol index 321db17b..4715daeb 100644 --- a/test/unit/CreditVaultConnector/GetExecutionContext.t.sol +++ b/test/unit/EthereumVaultConnector/GetExecutionContext.t.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract GetExecutionContextTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_GetExecutionContext( @@ -17,32 +17,32 @@ contract GetExecutionContextTest is Test { uint8 callDepth, uint8 seed ) external { - vm.assume(account != address(0) && account != address(cvc)); + vm.assume(account != address(0) && account != address(evc)); vm.assume(callDepth <= 10); - address controller = address(new Vault(cvc)); + address controller = address(new Vault(evc)); - vm.expectRevert(Errors.CVC_OnBehalfOfAccountNotAuthenticated.selector); - cvc.getCurrentOnBehalfOfAccount(controller); + vm.expectRevert(Errors.EVC_OnBehalfOfAccountNotAuthenticated.selector); + evc.getCurrentOnBehalfOfAccount(controller); - uint context = cvc.getRawExecutionContext(); + uint context = evc.getRawExecutionContext(); assertEq(context, 1 << 200); if (seed % 2 == 0) { vm.prank(account); - cvc.enableController(account, controller); + evc.enableController(account, controller); } - cvc.setCallDepth(seed % 3 == 0 ? callDepth : 0); - cvc.setOnBehalfOfAccount(account); - cvc.setChecksLock(seed % 4 == 0 ? true : false); - cvc.setImpersonateLock(seed % 5 == 0 ? true : false); - cvc.setOperatorAuthenticated(seed % 6 == 0 ? true : false); - cvc.setSimulation(seed % 7 == 0 ? true : false); + evc.setCallDepth(seed % 3 == 0 ? callDepth : 0); + evc.setOnBehalfOfAccount(account); + evc.setChecksLock(seed % 4 == 0 ? true : false); + evc.setImpersonateLock(seed % 5 == 0 ? true : false); + evc.setOperatorAuthenticated(seed % 6 == 0 ? true : false); + evc.setSimulation(seed % 7 == 0 ? true : false); - (address onBehalfOfAccount, bool controllerEnabled) = cvc + (address onBehalfOfAccount, bool controllerEnabled) = evc .getCurrentOnBehalfOfAccount(controller); - context = cvc.getRawExecutionContext(); + context = evc.getRawExecutionContext(); assertEq(onBehalfOfAccount, account); assertEq(controllerEnabled, seed % 2 == 0 ? true : false); @@ -51,7 +51,7 @@ contract GetExecutionContextTest is Test { 0x00000000000000000000000000000000000000000000000000000000000000FF, seed % 3 == 0 ? callDepth : 0 ); - assertEq(cvc.getCurrentCallDepth(), seed % 3 == 0 ? callDepth : 0); + assertEq(evc.getCurrentCallDepth(), seed % 3 == 0 ? callDepth : 0); assertEq( context & 0x0000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00, @@ -63,27 +63,27 @@ contract GetExecutionContextTest is Test { 0, seed % 4 == 0 ? true : false ); - assertEq(cvc.areChecksInProgress(), seed % 4 == 0 ? true : false); + assertEq(evc.areChecksInProgress(), seed % 4 == 0 ? true : false); assertEq( context & 0x000000000000000000FF00000000000000000000000000000000000000000000 != 0, seed % 5 == 0 ? true : false ); - assertEq(cvc.isImpersonationInProgress(), seed % 5 == 0 ? true : false); + assertEq(evc.isImpersonationInProgress(), seed % 5 == 0 ? true : false); assertEq( context & 0x0000000000000000FF0000000000000000000000000000000000000000000000 != 0, seed % 6 == 0 ? true : false ); - assertEq(cvc.isOperatorAuthenticated(), seed % 6 == 0 ? true : false); + assertEq(evc.isOperatorAuthenticated(), seed % 6 == 0 ? true : false); assertEq( context & 0x00000000000000FF000000000000000000000000000000000000000000000000 != 0, seed % 7 == 0 ? true : false ); - assertEq(cvc.isSimulationInProgress(), seed % 7 == 0 ? true : false); + assertEq(evc.isSimulationInProgress(), seed % 7 == 0 ? true : false); } } diff --git a/test/unit/EthereumVaultConnector/Impersonate.sol b/test/unit/EthereumVaultConnector/Impersonate.sol new file mode 100644 index 00000000..363a08be --- /dev/null +++ b/test/unit/EthereumVaultConnector/Impersonate.sol @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +pragma solidity ^0.8.20; + +import "forge-std/Test.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; + +contract EthereumVaultConnectorHandler is EthereumVaultConnectorHarness { + using Set for SetStorage; + + function handlerImpersonate( + address targetContract, + address onBehalfOfAccount, + uint value, + bytes calldata data + ) public payable returns (bytes memory result) { + (bool success, ) = msg.sender.call( + abi.encodeWithSelector(Vault.clearChecks.selector) + ); + success; + clearExpectedChecks(); + + result = super.impersonate( + targetContract, + onBehalfOfAccount, + value, + data + ); + + verifyVaultStatusChecks(); + verifyAccountStatusChecks(); + } +} + +contract ImpersonateTest is Test { + EthereumVaultConnectorHandler internal evc; + + event CallWithContext( + address indexed caller, + address indexed targetContract, + address indexed onBehalfOfAccount, + bytes4 selector + ); + + function setUp() public { + evc = new EthereumVaultConnectorHandler(); + } + + function test_Impersonate(address alice, uint96 seed) public { + vm.assume(alice != address(0) && alice != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + vm.assume(collateral != address(evc)); + vm.assume(!evc.haveCommonOwner(alice, controller)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + bytes memory data = abi.encodeWithSelector( + Target(collateral).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(controller, seed); + vm.expectEmit(true, true, true, true, address(evc)); + emit CallWithContext( + controller, + collateral, + alice, + Target.impersonateTest.selector + ); + vm.prank(controller); + bytes memory result = evc.handlerImpersonate{value: seed}( + collateral, + alice, + seed, + data + ); + assertEq(abi.decode(result, (uint)), seed); + + evc.clearExpectedChecks(); + Vault(controller).clearChecks(); + } + + function test_RevertIfDepthExceeded_Impersonate(address alice) external { + vm.assume(alice != address(evc)); + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + evc.setCallDepth(10); + + vm.prank(controller); + vm.expectRevert(ExecutionContext.CallDepthViolation.selector); + evc.impersonate(collateral, alice, 0, ""); + } + + function test_RevertIfChecksReentrancy_Impersonate( + address alice, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + vm.assume(collateral != address(evc)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + evc.setChecksLock(true); + + bytes memory data = abi.encodeWithSelector( + Target(address(evc)).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(alice, seed); + vm.prank(alice); + vm.expectRevert(Errors.EVC_ChecksReentrancy.selector); + evc.impersonate{value: seed}(collateral, alice, seed, data); + } + + function test_RevertIfImpersonateReentrancy_Impersonate( + address alice, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + vm.assume(collateral != address(evc)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + evc.setImpersonateLock(true); + + bytes memory data = abi.encodeWithSelector( + Target(address(evc)).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(alice, seed); + vm.prank(alice); + vm.expectRevert(Errors.EVC_ImpersonateReentrancy.selector); + evc.impersonate{value: seed}(collateral, alice, seed, data); + } + + function test_RevertIfTargetContractInvalid_Impersonate( + address alice, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + + address controller = address(new Vault(evc)); + + vm.prank(alice); + evc.enableController(alice, controller); + + // target contract is the EVC + bytes memory data = abi.encodeWithSelector( + Target(address(evc)).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(alice, seed); + vm.prank(alice); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.impersonate{value: seed}(address(evc), alice, seed, data); + } + + function test_RevertIfNoControllerEnabled_Impersonate( + address alice, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + + vm.assume(collateral != address(evc)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + bytes memory data = abi.encodeWithSelector( + Target(collateral).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(controller, seed); + vm.prank(controller); + vm.expectRevert(Errors.EVC_ControllerViolation.selector); + evc.impersonate{value: seed}(collateral, alice, seed, data); + } + + function test_RevertIfMultipleControllersEnabled_Impersonate( + address alice, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + + address collateral = address(new Vault(evc)); + address controller_1 = address(new Vault(evc)); + address controller_2 = address(new Vault(evc)); + + vm.assume(collateral != address(evc)); + + // mock checks deferred to enable multiple controllers + evc.setCallDepth(1); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller_1); + + vm.prank(alice); + evc.enableController(alice, controller_2); + + bytes memory data = abi.encodeWithSelector( + Target(collateral).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(controller_1, seed); + vm.prank(controller_1); + vm.expectRevert(Errors.EVC_ControllerViolation.selector); + evc.impersonate{value: seed}(collateral, alice, seed, data); + } + + function test_RevertIfMsgSenderIsNotEnabledController_Impersonate( + address alice, + address randomAddress, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(uint160(randomAddress) > 10 && randomAddress != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + + vm.assume(collateral != address(evc)); + vm.assume(randomAddress != controller); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + bytes memory data = abi.encodeWithSelector( + Target(collateral).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(randomAddress, seed); + vm.prank(randomAddress); + vm.expectRevert( + abi.encodeWithSelector(Errors.EVC_NotAuthorized.selector) + ); + evc.impersonate{value: seed}(collateral, alice, seed, data); + } + + function test_RevertIfTargetContractIsNotEnabledCollateral_Impersonate( + address alice, + address targetContract, + uint seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(targetContract != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + + vm.assume(targetContract != collateral); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + bytes memory data = abi.encodeWithSelector( + Target(collateral).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + vm.deal(controller, seed); + vm.prank(controller); + vm.expectRevert( + abi.encodeWithSelector(Errors.EVC_NotAuthorized.selector) + ); + evc.impersonate{value: seed}(targetContract, alice, seed, data); + } + + function test_RevertIfValueExceedsBalance_Impersonate( + address alice, + uint128 seed + ) public { + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(seed > 0); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + vm.assume(collateral != address(evc) && controller != address(evc)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + bytes memory data = abi.encodeWithSelector( + Target(address(evc)).impersonateTest.selector, + address(evc), + address(evc), + seed, + alice + ); + + // reverts if value exceeds balance + vm.deal(controller, seed); + vm.prank(controller); + vm.expectRevert(Errors.EVC_InvalidValue.selector); + evc.impersonate{value: seed - 1}(collateral, alice, seed, data); + + // succeeds if value does not exceed balance + vm.prank(controller); + evc.impersonate{value: seed}(collateral, alice, seed, data); + } + + function test_RevertIfInternalCallIsUnsuccessful_Impersonate( + address alice + ) public { + // call setUp() explicitly for Dilligence Fuzzing tool to pass + setUp(); + + vm.assume(alice != address(0)); + vm.assume(alice != address(evc)); + + address collateral = address(new Vault(evc)); + address controller = address(new Vault(evc)); + vm.assume(collateral != address(evc) && controller != address(evc)); + + vm.prank(alice); + evc.enableCollateral(alice, collateral); + + vm.prank(alice); + evc.enableController(alice, controller); + + bytes memory data = abi.encodeWithSelector( + Target(collateral).revertEmptyTest.selector + ); + + vm.prank(controller); + vm.expectRevert(Errors.EVC_EmptyError.selector); + evc.impersonate(collateral, alice, 0, data); + } +} diff --git a/test/unit/CreditVaultConnector/IsAccountStatusCheckDeferred.t.sol b/test/unit/EthereumVaultConnector/IsAccountStatusCheckDeferred.t.sol similarity index 56% rename from test/unit/CreditVaultConnector/IsAccountStatusCheckDeferred.t.sol rename to test/unit/EthereumVaultConnector/IsAccountStatusCheckDeferred.t.sol index f909437d..b8604458 100644 --- a/test/unit/CreditVaultConnector/IsAccountStatusCheckDeferred.t.sol +++ b/test/unit/EthereumVaultConnector/IsAccountStatusCheckDeferred.t.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract IsAccountStatusCheckDeferredTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_IsAccountStatusCheckDeferred( @@ -20,23 +20,23 @@ contract IsAccountStatusCheckDeferredTest is Test { for (uint i = 0; i < numberOfAccounts; ++i) { // we're not in a batch thus the check will not get deferred - cvc.setCallDepth(0); + evc.setCallDepth(0); address account = address( uint160(uint(keccak256(abi.encode(i, seed)))) ); - assertFalse(cvc.isAccountStatusCheckDeferred(account)); + assertFalse(evc.isAccountStatusCheckDeferred(account)); - cvc.requireAccountStatusCheck(account); - assertFalse(cvc.isAccountStatusCheckDeferred(account)); + evc.requireAccountStatusCheck(account); + assertFalse(evc.isAccountStatusCheckDeferred(account)); // simulate being in a batch - cvc.setCallDepth(1); + evc.setCallDepth(1); - cvc.requireAccountStatusCheck(account); - assertTrue(cvc.isAccountStatusCheckDeferred(account)); + evc.requireAccountStatusCheck(account); + assertTrue(evc.isAccountStatusCheckDeferred(account)); - cvc.reset(); + evc.reset(); } } } diff --git a/test/unit/EthereumVaultConnector/IsVaultStatusCheckDeferred.t.sol b/test/unit/EthereumVaultConnector/IsVaultStatusCheckDeferred.t.sol new file mode 100644 index 00000000..63cb7d81 --- /dev/null +++ b/test/unit/EthereumVaultConnector/IsVaultStatusCheckDeferred.t.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +pragma solidity ^0.8.20; + +import "forge-std/Test.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; + +contract IsVaultStatusCheckDeferredTest is Test { + EthereumVaultConnectorHarness internal evc; + + function setUp() public { + evc = new EthereumVaultConnectorHarness(); + } + + function test_IsVaultStatusCheckDeferred(uint8 numberOfVaults) external { + vm.assume(numberOfVaults <= Set.MAX_ELEMENTS); + + for (uint i = 0; i < numberOfVaults; ++i) { + // we're not in a batch thus the check will not get deferred + evc.setCallDepth(0); + + address vault = address(new Vault(evc)); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); + + vm.prank(vault); + evc.requireVaultStatusCheck(); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); + + // simulate being in a batch + evc.setCallDepth(1); + + vm.prank(vault); + evc.requireVaultStatusCheck(); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); + + evc.reset(); + } + } +} diff --git a/test/unit/CreditVaultConnector/Permit.t.sol b/test/unit/EthereumVaultConnector/Permit.t.sol similarity index 73% rename from test/unit/CreditVaultConnector/Permit.t.sol rename to test/unit/EthereumVaultConnector/Permit.t.sol index 1be8b213..7f8e3dab 100644 --- a/test/unit/CreditVaultConnector/Permit.t.sol +++ b/test/unit/EthereumVaultConnector/Permit.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; import "../../utils/mocks/Target.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; import "openzeppelin/utils/cryptography/ECDSA.sol"; import {ShortStrings, ShortString} from "openzeppelin/utils/ShortStrings.sol"; @@ -77,11 +77,13 @@ abstract contract EIP712 { } contract SignerECDSA is EIP712, Test { - CreditVaultConnector private immutable cvc; + EthereumVaultConnector private immutable evc; uint256 private privateKey; - constructor(CreditVaultConnector _cvc) EIP712(_cvc.name(), _cvc.version()) { - cvc = _cvc; + constructor( + EthereumVaultConnector _evc + ) EIP712(_evc.name(), _evc.version()) { + evc = _evc; } function setPrivateKey(uint256 _privateKey) external { @@ -96,7 +98,7 @@ contract SignerECDSA is EIP712, Test { _hashedName, _hashedVersion, block.chainid, - address(cvc) + address(evc) ) ); } @@ -111,7 +113,7 @@ contract SignerECDSA is EIP712, Test { ) external view returns (bytes memory signature) { bytes32 structHash = keccak256( abi.encode( - cvc.PERMIT_TYPEHASH(), + evc.PERMIT_TYPEHASH(), signer, nonceNamespace, nonce, @@ -129,12 +131,14 @@ contract SignerECDSA is EIP712, Test { } contract SignerERC1271 is EIP712, IERC1271 { - CreditVaultConnector private immutable cvc; + EthereumVaultConnector private immutable evc; bytes32 private signatureHash; bytes32 private permitHash; - constructor(CreditVaultConnector _cvc) EIP712(_cvc.name(), _cvc.version()) { - cvc = _cvc; + constructor( + EthereumVaultConnector _evc + ) EIP712(_evc.name(), _evc.version()) { + evc = _evc; } function _buildDomainSeparator() internal view override returns (bytes32) { @@ -145,7 +149,7 @@ contract SignerERC1271 is EIP712, IERC1271 { _hashedName, _hashedVersion, block.chainid, - address(cvc) + address(evc) ) ); } @@ -164,7 +168,7 @@ contract SignerERC1271 is EIP712, IERC1271 { ) external { bytes32 structHash = keccak256( abi.encode( - cvc.PERMIT_TYPEHASH(), + evc.PERMIT_TYPEHASH(), signer, nonceNamespace, nonce, @@ -186,7 +190,7 @@ contract SignerERC1271 is EIP712, IERC1271 { } } -contract CreditVaultConnectorWithFallback is CreditVaultConnectorHarness { +contract EthereumVaultConnectorWithFallback is EthereumVaultConnectorHarness { bytes32 internal expectedHash; uint internal expectedValue; bool internal shouldRevert; @@ -224,7 +228,7 @@ contract CreditVaultConnectorWithFallback is CreditVaultConnectorHarness { } contract PermitTest is Test { - CreditVaultConnectorWithFallback internal cvc; + EthereumVaultConnectorWithFallback internal evc; SignerECDSA internal signerECDSA; SignerERC1271 internal signerERC1271; @@ -237,8 +241,8 @@ contract PermitTest is Test { ); function setUp() public { - cvc = new CreditVaultConnectorWithFallback(); - signerECDSA = new SignerECDSA(cvc); + evc = new EthereumVaultConnectorWithFallback(); + signerECDSA = new SignerECDSA(evc); } function test_ECDSA_Permit( @@ -255,11 +259,11 @@ contract PermitTest is Test { 115792089237316195423570985008687907852837564279074904382605163141518161494337 ); address alice = vm.addr(privateKey); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && alice != address(cvc) + !evc.haveCommonOwner(alice, address(0)) && alice != address(evc) ); vm.assume(nonce > 0 && nonce < type(uint).max); @@ -269,12 +273,12 @@ contract PermitTest is Test { if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } - cvc.clearFallbackCalled(); - cvc.setExpectedHash(data); - cvc.setExpectedValue(value); + evc.clearFallbackCalled(); + evc.setExpectedHash(data); + evc.setExpectedValue(value); bytes memory signature = signerECDSA.signPermit( alice, @@ -285,11 +289,11 @@ contract PermitTest is Test { data ); - vm.expectEmit(true, false, false, true, address(cvc)); - emit NonceUsed(cvc.getAddressPrefix(alice), nonce); - vm.expectEmit(true, true, true, true, address(cvc)); - emit CallWithContext(address(this), address(cvc), alice, bytes4(data)); - cvc.permit{value: address(this).balance}( + vm.expectEmit(true, false, false, true, address(evc)); + emit NonceUsed(evc.getAddressPrefix(alice), nonce); + vm.expectEmit(true, true, true, true, address(evc)); + emit CallWithContext(address(this), address(evc), alice, bytes4(data)); + evc.permit{value: address(this).balance}( alice, nonceNamespace, nonce, @@ -298,11 +302,11 @@ contract PermitTest is Test { data, signature ); - assertTrue(cvc.fallbackCalled()); + assertTrue(evc.fallbackCalled()); // it's not possible to carry out a reply attack - vm.expectRevert(Errors.CVC_InvalidNonce.selector); - cvc.permit{value: address(this).balance}( + vm.expectRevert(Errors.EVC_InvalidNonce.selector); + evc.permit{value: address(this).balance}( alice, nonceNamespace, nonce, @@ -321,11 +325,11 @@ contract PermitTest is Test { bytes calldata signature, uint16 value ) public { - address alice = address(new SignerERC1271(cvc)); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + address alice = address(new SignerERC1271(evc)); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); - vm.assume(!cvc.haveCommonOwner(alice, address(0))); + vm.assume(!evc.haveCommonOwner(alice, address(0))); vm.assume(nonce > 0 && nonce < type(uint).max); vm.warp(deadline); @@ -334,12 +338,12 @@ contract PermitTest is Test { if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } - cvc.clearFallbackCalled(); - cvc.setExpectedHash(data); - cvc.setExpectedValue(value); + evc.clearFallbackCalled(); + evc.setExpectedHash(data); + evc.setExpectedValue(value); SignerERC1271(alice).setPermitHash( alice, @@ -350,11 +354,11 @@ contract PermitTest is Test { data ); - vm.expectEmit(true, false, false, true, address(cvc)); - emit NonceUsed(cvc.getAddressPrefix(alice), nonce); - vm.expectEmit(true, true, true, true, address(cvc)); - emit CallWithContext(address(this), address(cvc), alice, bytes4(data)); - cvc.permit{value: address(this).balance}( + vm.expectEmit(true, false, false, true, address(evc)); + emit NonceUsed(evc.getAddressPrefix(alice), nonce); + vm.expectEmit(true, true, true, true, address(evc)); + emit CallWithContext(address(this), address(evc), alice, bytes4(data)); + evc.permit{value: address(this).balance}( alice, nonceNamespace, nonce, @@ -363,11 +367,11 @@ contract PermitTest is Test { data, signature ); - assertTrue(cvc.fallbackCalled()); + assertTrue(evc.fallbackCalled()); // it's not possible to carry out a reply attack - vm.expectRevert(Errors.CVC_InvalidNonce.selector); - cvc.permit{value: address(this).balance}( + vm.expectRevert(Errors.EVC_InvalidNonce.selector); + evc.permit{value: address(this).balance}( alice, nonceNamespace, nonce, @@ -388,19 +392,19 @@ contract PermitTest is Test { bytes calldata signature ) public { alice = address(uint160(bound(uint160(alice), 0, 0xFF))); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); vm.assume(nonce > 0 && nonce < type(uint).max); vm.warp(deadline); if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } // reverts if signer is zero address - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.permit( + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.permit( alice, nonceNamespace, nonce, @@ -420,20 +424,20 @@ contract PermitTest is Test { bytes memory data, bytes calldata signature ) public { - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && alice != address(cvc) + !evc.haveCommonOwner(alice, address(0)) && alice != address(evc) ); vm.assume(nonce > 0); vm.warp(deadline); vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); + evc.setNonce(addressPrefix, nonceNamespace, nonce); // reverts if nonce is invalid - vm.expectRevert(Errors.CVC_InvalidNonce.selector); - cvc.permit( + vm.expectRevert(Errors.EVC_InvalidNonce.selector); + evc.permit( alice, nonceNamespace, nonce, @@ -453,10 +457,10 @@ contract PermitTest is Test { bytes memory data, bytes calldata signature ) public { - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && alice != address(cvc) + !evc.haveCommonOwner(alice, address(0)) && alice != address(evc) ); vm.assume(nonce > 0 && nonce < type(uint).max); vm.assume(deadline < type(uint).max); @@ -464,12 +468,12 @@ contract PermitTest is Test { if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } // reverts if deadline is missed - vm.expectRevert(Errors.CVC_InvalidTimestamp.selector); - cvc.permit( + vm.expectRevert(Errors.EVC_InvalidTimestamp.selector); + evc.permit( alice, nonceNamespace, nonce, @@ -494,10 +498,10 @@ contract PermitTest is Test { 115792089237316195423570985008687907852837564279074904382605163141518161494337 ); address alice = vm.addr(privateKey); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && alice != address(cvc) + !evc.haveCommonOwner(alice, address(0)) && alice != address(evc) ); vm.assume(nonce > 0 && nonce < type(uint).max); vm.assume(value > 0); @@ -515,13 +519,13 @@ contract PermitTest is Test { if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } // reverts if value exceeds balance - vm.deal(address(cvc), value - 1); - vm.expectRevert(Errors.CVC_InvalidValue.selector); - cvc.permit( + vm.deal(address(evc), value - 1); + vm.expectRevert(Errors.EVC_InvalidValue.selector); + evc.permit( alice, nonceNamespace, nonce, @@ -532,8 +536,8 @@ contract PermitTest is Test { ); // succeeds if value does not exceed balance - vm.deal(address(cvc), value); - cvc.permit( + vm.deal(address(evc), value); + evc.permit( alice, nonceNamespace, nonce, @@ -552,21 +556,21 @@ contract PermitTest is Test { uint value, bytes calldata signature ) public { - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && alice != address(cvc) + !evc.haveCommonOwner(alice, address(0)) && alice != address(evc) ); vm.assume(nonce > 0 && nonce < type(uint).max); vm.warp(deadline); if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } // reverts if data is empty - vm.expectRevert(Errors.CVC_InvalidData.selector); - cvc.permit( + vm.expectRevert(Errors.EVC_InvalidData.selector); + evc.permit( alice, nonceNamespace, nonce, @@ -592,28 +596,28 @@ contract PermitTest is Test { 115792089237316195423570985008687907852837564279074904382605163141518161494337 ); address alice = vm.addr(privateKey); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); data = abi.encode(keccak256(data)); signerECDSA.setPrivateKey(privateKey); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && alice != address(cvc) + !evc.haveCommonOwner(alice, address(0)) && alice != address(evc) ); vm.assume(nonce > 0 && nonce < type(uint).max); vm.warp(deadline); - vm.deal(address(cvc), value); + vm.deal(address(evc), value); - cvc.clearFallbackCalled(); - cvc.setExpectedHash(data); - cvc.setExpectedValue(value); - cvc.setShouldRevert(true); + evc.clearFallbackCalled(); + evc.setExpectedHash(data); + evc.setExpectedValue(value); + evc.setShouldRevert(true); if (nonce > 1) { vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } - // reverts if CVC self-call unsuccessful + // reverts if EVC self-call unsuccessful bytes memory signature = signerECDSA.signPermit( alice, nonceNamespace, @@ -624,7 +628,7 @@ contract PermitTest is Test { ); vm.expectRevert(bytes("fallback reverted")); - cvc.permit( + evc.permit( alice, nonceNamespace, nonce, @@ -634,10 +638,10 @@ contract PermitTest is Test { signature ); - // succeeds if CVC self-call successful - cvc.setShouldRevert(false); + // succeeds if EVC self-call successful + evc.setShouldRevert(false); - cvc.permit( + evc.permit( alice, nonceNamespace, nonce, @@ -646,7 +650,7 @@ contract PermitTest is Test { data, signature ); - assertTrue(cvc.fallbackCalled()); + assertTrue(evc.fallbackCalled()); } function test_RevertIfSignerIsNotContractERC1271_Permit( @@ -659,11 +663,11 @@ contract PermitTest is Test { uint16 value ) public { vm.assume( - !cvc.haveCommonOwner(signer, address(0)) && signer != address(cvc) + !evc.haveCommonOwner(signer, address(0)) && signer != address(evc) ); vm.assume(nonce > 0 && nonce < type(uint).max); - uint152 addressPrefix = cvc.getAddressPrefix(signer); + uint152 addressPrefix = evc.getAddressPrefix(signer); data = abi.encode(keccak256(data)); vm.warp(deadline); @@ -671,11 +675,11 @@ contract PermitTest is Test { if (nonce > 1) { vm.prank(signer); - cvc.setNonce(addressPrefix, nonceNamespace, nonce - 1); + evc.setNonce(addressPrefix, nonceNamespace, nonce - 1); } - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit{value: address(this).balance}( + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit{value: address(this).balance}( signer, nonceNamespace, nonce, @@ -698,7 +702,7 @@ contract PermitTest is Test { address alice = vm.addr(privateKey); signerECDSA.setPrivateKey(privateKey); - vm.assume(!cvc.haveCommonOwner(alice, address(0))); + vm.assume(!evc.haveCommonOwner(alice, address(0))); vm.warp(deadline); // ECDSA signature invalid due to signer. @@ -711,8 +715,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid due to nonce namespace. // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -724,8 +728,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid due to nonce. // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -737,8 +741,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid due to deadline. // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -750,8 +754,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid due to value. // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -763,8 +767,8 @@ contract PermitTest is Test { 1, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid due to data. // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -776,8 +780,8 @@ contract PermitTest is Test { 0, bytes("1") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid (wrong length due to added 1). // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -800,26 +804,26 @@ contract PermitTest is Test { } signature = abi.encodePacked(r, s, v, uint8(1)); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid (r is 0). // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful signature = abi.encodePacked(uint(0), s, v); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid (s is 0). // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful signature = abi.encodePacked(r, uint(0), v); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid (v is 0). // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful signature = abi.encodePacked(r, s, uint8(0)); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature invalid (malleability protection). // ERC-1271 signature invalid as the signer is EOA and isValidSignature() call is unsuccesful @@ -830,24 +834,24 @@ contract PermitTest is Test { ), v ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ECDSA signature valid hence the transaction succeeds - cvc.setExpectedHash(bytes("0")); + evc.setExpectedHash(bytes("0")); signature = abi.encodePacked(r, s, v); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); - assertTrue(cvc.fallbackCalled()); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + assertTrue(evc.fallbackCalled()); } function test_RevertIfInvalidERC1271Signature_Permit( uint128 deadline, bytes calldata signature ) public { - address alice = address(new SignerERC1271(cvc)); + address alice = address(new SignerERC1271(evc)); SignerERC1271(alice).setSignatureHash(signature); - vm.assume(!cvc.haveCommonOwner(alice, address(0))); + vm.assume(!evc.haveCommonOwner(alice, address(0))); vm.warp(deadline); // ECDSA signature is always invalid here hence we fall back to ERC-1271 signature @@ -861,8 +865,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ERC-1271 signature invalid due to the nonce namespace SignerERC1271(alice).setPermitHash( @@ -873,8 +877,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ERC-1271 signature invalid due to the nonce SignerERC1271(alice).setPermitHash( @@ -885,8 +889,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ERC-1271 signature invalid due to the deadline SignerERC1271(alice).setPermitHash( @@ -897,8 +901,8 @@ contract PermitTest is Test { 0, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ERC-1271 signature invalid due to the value SignerERC1271(alice).setPermitHash( @@ -909,8 +913,8 @@ contract PermitTest is Test { 1, bytes("0") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ERC-1271 signature invalid due to the data SignerERC1271(alice).setPermitHash( @@ -921,11 +925,11 @@ contract PermitTest is Test { 0, bytes("1") ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); // ERC-1271 signature valid hence the transaction succeeds - cvc.setExpectedHash(bytes("0")); + evc.setExpectedHash(bytes("0")); SignerERC1271(alice).setPermitHash( alice, 0, @@ -934,8 +938,8 @@ contract PermitTest is Test { 0, bytes("0") ); - cvc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); - assertTrue(cvc.fallbackCalled()); + evc.permit(alice, 0, 1, deadline, 0, bytes("0"), signature); + assertTrue(evc.fallbackCalled()); } function test_Permit(uint privateKey) public { @@ -945,19 +949,19 @@ contract PermitTest is Test { 115792089237316195423570985008687907852837564279074904382605163141518161494337 ); address alice = vm.addr(privateKey); - address bob = address(new SignerERC1271(cvc)); + address bob = address(new SignerERC1271(evc)); address target = address(new Target()); vm.assume( - !cvc.haveCommonOwner(alice, address(0)) && - !cvc.haveCommonOwner(alice, bob) + !evc.haveCommonOwner(alice, address(0)) && + !evc.haveCommonOwner(alice, bob) ); vm.deal(address(this), type(uint128).max); signerECDSA.setPrivateKey(privateKey); // encode a call that doesn't need authentication to prove it can be signed by anyone bytes memory data = abi.encodeWithSelector( - ICVC.requireAccountStatusCheck.selector, + IEVC.requireAccountStatusCheck.selector, address(0) ); @@ -970,21 +974,21 @@ contract PermitTest is Test { 0, data ); - cvc.permit(alice, 0, 1, block.timestamp, 0, data, signature); + evc.permit(alice, 0, 1, block.timestamp, 0, data, signature); // a call using ERC-1271 signature succeeds signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 1, block.timestamp, 0, data); - cvc.permit(bob, 0, 1, block.timestamp, 0, data, signature); + evc.permit(bob, 0, 1, block.timestamp, 0, data, signature); // encode a call that doesn't need authentication wrapped in a batch - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](1); - items[0].targetContract = address(cvc); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](1); + items[0].targetContract = address(evc); items[0].onBehalfOfAccount = address(0); items[0].value = 0; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); // a call using ECDSA signature succeeds signature = signerECDSA.signPermit( @@ -995,17 +999,17 @@ contract PermitTest is Test { 0, data ); - cvc.permit(alice, 0, 2, block.timestamp, 0, data, signature); + evc.permit(alice, 0, 2, block.timestamp, 0, data, signature); // a call using ERC-1271 signature succeeds signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 2, block.timestamp, 0, data); - cvc.permit(bob, 0, 2, block.timestamp, 0, data, signature); + evc.permit(bob, 0, 2, block.timestamp, 0, data, signature); // encode a call that needs authentication to prove it cannot be signed by anyone data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, bob, address(0) ); @@ -1019,32 +1023,32 @@ contract PermitTest is Test { 0, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 3, block.timestamp, 0, data, signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 3, block.timestamp, 0, data, signature); // a call using ERC1271 signature fails because bob signed on behalf of alice data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, alice, address(0) ); signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 3, block.timestamp, 0, data); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(bob, 0, 3, block.timestamp, 0, data, signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(bob, 0, 3, block.timestamp, 0, data, signature); // encode a call that needs authentication wrapped in a batch data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, bob, address(0) ); - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].onBehalfOfAccount = bob; items[0].value = 0; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); // a call using ECDSA signature fails because alice signed on behalf of bob signature = signerECDSA.signPermit( @@ -1055,30 +1059,30 @@ contract PermitTest is Test { 0, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(alice, 0, 3, block.timestamp, 0, data, signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(alice, 0, 3, block.timestamp, 0, data, signature); // a call using ERC1271 signature fails because bob signed on behalf of alice data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, alice, address(0) ); - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].onBehalfOfAccount = alice; items[0].value = 0; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 3, block.timestamp, 0, data); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(bob, 0, 3, block.timestamp, 0, data, signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(bob, 0, 3, block.timestamp, 0, data, signature); // encode a call that needs authentication data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, alice, address(0) ); @@ -1092,11 +1096,11 @@ contract PermitTest is Test { 0, data ); - cvc.permit(alice, 0, 3, block.timestamp, 0, data, signature); + evc.permit(alice, 0, 3, block.timestamp, 0, data, signature); // a call using ERC1271 signature succeeds because bob signed on behalf of himself data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, bob, address(0) ); @@ -1104,19 +1108,19 @@ contract PermitTest is Test { signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 3, block.timestamp, 0, data); - cvc.permit(bob, 0, 3, block.timestamp, 0, data, signature); + evc.permit(bob, 0, 3, block.timestamp, 0, data, signature); // encode a call that needs authentication wrapped in a batch data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, alice, address(0) ); - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].onBehalfOfAccount = alice; items[0].value = 0; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); // a call using ECDSA signature succeeds because alice signed on behalf of herself signature = signerECDSA.signPermit( @@ -1127,35 +1131,35 @@ contract PermitTest is Test { 0, data ); - cvc.permit(alice, 0, 4, block.timestamp, 0, data, signature); + evc.permit(alice, 0, 4, block.timestamp, 0, data, signature); // a call using ERC1271 signature succeeds because bob signed on behalf of himself data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, bob, address(0) ); - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].onBehalfOfAccount = bob; items[0].value = 0; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 4, block.timestamp, 0, data); - cvc.permit(bob, 0, 4, block.timestamp, 0, data, signature); + evc.permit(bob, 0, 4, block.timestamp, 0, data, signature); // encode a call to an external target contract data = abi.encodeWithSelector( - ICVC.call.selector, + IEVC.call.selector, target, bob, 123, abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 123, bob, false @@ -1171,8 +1175,8 @@ contract PermitTest is Test { type(uint).max, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit{value: 123}( + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit{value: 123}( alice, 0, 5, @@ -1184,14 +1188,14 @@ contract PermitTest is Test { // a call using ERC1271 signature fails because bob signed on behalf of alice data = abi.encodeWithSelector( - ICVC.call.selector, + IEVC.call.selector, target, alice, 123, abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 123, alice, false @@ -1208,8 +1212,8 @@ contract PermitTest is Test { type(uint).max, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit{value: 123}( + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit{value: 123}( bob, 0, 5, @@ -1222,8 +1226,8 @@ contract PermitTest is Test { // encode a call to an external target contract wrapped in a batch data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 123, bob, false @@ -1232,7 +1236,7 @@ contract PermitTest is Test { items[0].onBehalfOfAccount = bob; items[0].value = 123; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); // a call using ECDSA signature fails because alice signed on behalf of bob signature = signerECDSA.signPermit( @@ -1243,8 +1247,8 @@ contract PermitTest is Test { type(uint).max, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit{value: 123}( + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit{value: 123}( alice, 0, 5, @@ -1257,8 +1261,8 @@ contract PermitTest is Test { // a call using ERC1271 signature fails because bob signed on behalf of alice data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 123, alice, false @@ -1267,7 +1271,7 @@ contract PermitTest is Test { items[0].onBehalfOfAccount = alice; items[0].value = 123; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); @@ -1279,8 +1283,8 @@ contract PermitTest is Test { type(uint).max, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit{value: 123}( + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit{value: 123}( bob, 0, 5, @@ -1292,14 +1296,14 @@ contract PermitTest is Test { // encode a call to an external target contract data = abi.encodeWithSelector( - ICVC.call.selector, + IEVC.call.selector, target, alice, 123, abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 123, alice, false @@ -1315,7 +1319,7 @@ contract PermitTest is Test { type(uint).max, data ); - cvc.permit{value: 123}( + evc.permit{value: 123}( alice, 0, 5, @@ -1327,14 +1331,14 @@ contract PermitTest is Test { // a call using ERC1271 signature succeeds because bob signed on behalf of himself data = abi.encodeWithSelector( - ICVC.call.selector, + IEVC.call.selector, target, bob, 123, abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 123, bob, false @@ -1351,7 +1355,7 @@ contract PermitTest is Test { type(uint).max, data ); - cvc.permit{value: 123}( + evc.permit{value: 123}( bob, 0, 5, @@ -1364,8 +1368,8 @@ contract PermitTest is Test { // encode a call to an external target contract wrapped in a batch data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 456, alice, false @@ -1374,7 +1378,7 @@ contract PermitTest is Test { items[0].onBehalfOfAccount = alice; items[0].value = 456; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); // a call using ECDSA signature succeeds because alice signed on behalf of herself signature = signerECDSA.signPermit( @@ -1385,7 +1389,7 @@ contract PermitTest is Test { 456, data ); - cvc.permit{value: 456}( + evc.permit{value: 456}( alice, 0, 6, @@ -1398,8 +1402,8 @@ contract PermitTest is Test { // a call using ERC1271 signature succeeds because bob signed on behalf of himself data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 456, bob, false @@ -1408,12 +1412,12 @@ contract PermitTest is Test { items[0].onBehalfOfAccount = bob; items[0].value = 456; items[0].data = data; - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 6, block.timestamp, 456, data); - cvc.permit{value: 456}( + evc.permit{value: 456}( bob, 0, 6, @@ -1435,17 +1439,17 @@ contract PermitTest is Test { 115792089237316195423570985008687907852837564279074904382605163141518161494335 ); address alice = vm.addr(privateKey); - address bob = address(new SignerERC1271(cvc)); - uint152 addressPrefixAlice = cvc.getAddressPrefix(alice); - uint152 addressPrefixBob = cvc.getAddressPrefix(bob); + address bob = address(new SignerERC1271(evc)); + uint152 addressPrefixAlice = evc.getAddressPrefix(alice); + uint152 addressPrefixBob = evc.getAddressPrefix(bob); address operator = vm.addr(privateKey + 1); address otherOperator = vm.addr(privateKey + 2); vm.assume(alice != address(0) && bob != address(0)); - vm.assume(operator != address(0) && operator != address(cvc)); + vm.assume(operator != address(0) && operator != address(evc)); vm.assume( - !cvc.haveCommonOwner(alice, operator) && - !cvc.haveCommonOwner(bob, operator) + !evc.haveCommonOwner(alice, operator) && + !evc.haveCommonOwner(bob, operator) ); vm.assume( subAccountId1 > 0 && @@ -1454,38 +1458,38 @@ contract PermitTest is Test { ); signerECDSA.setPrivateKey(privateKey); - ICVC.BatchItem[] memory items = new ICVC.BatchItem[](3); + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](3); // encode the setAccountOperator to prove that it's possible to set an operator // on behalf of the signer or their accounts - items[0].targetContract = address(cvc); + items[0].targetContract = address(evc); items[0].onBehalfOfAccount = address(0); items[0].value = 0; items[0].data = abi.encodeWithSelector( - ICVC.setAccountOperator.selector, + IEVC.setAccountOperator.selector, alice, operator, true ); - items[1].targetContract = address(cvc); + items[1].targetContract = address(evc); items[1].onBehalfOfAccount = address(0); items[1].value = 0; items[1].data = abi.encodeWithSelector( - ICVC.setAccountOperator.selector, + IEVC.setAccountOperator.selector, address(uint160(alice) ^ subAccountId1), operator, true ); - items[2].targetContract = address(cvc); + items[2].targetContract = address(evc); items[2].onBehalfOfAccount = address(0); items[2].value = 0; items[2].data = abi.encodeWithSelector( - ICVC.setOperator.selector, + IEVC.setOperator.selector, addressPrefixAlice, operator, (1 << 0) | (1 << subAccountId1) | (1 << subAccountId2) ); - bytes memory data = abi.encodeWithSelector(ICVC.batch.selector, items); + bytes memory data = abi.encodeWithSelector(IEVC.batch.selector, items); // a call using ECDSA signature succeeds bytes memory signature = signerECDSA.signPermit( @@ -1496,100 +1500,100 @@ contract PermitTest is Test { 0, data ); - cvc.permit(alice, 0, 1, block.timestamp, 0, data, signature); - assertEq(cvc.isAccountOperatorAuthorized(alice, operator), true); + evc.permit(alice, 0, 1, block.timestamp, 0, data, signature); + assertEq(evc.isAccountOperatorAuthorized(alice, operator), true); assertEq( - cvc.isAccountOperatorAuthorized( + evc.isAccountOperatorAuthorized( address(uint160(alice) ^ subAccountId1), operator ), true ); assertEq( - cvc.isAccountOperatorAuthorized( + evc.isAccountOperatorAuthorized( address(uint160(alice) ^ subAccountId2), operator ), true ); assertEq( - cvc.getOperator(addressPrefixAlice, operator), + evc.getOperator(addressPrefixAlice, operator), (1 << 0) | (1 << subAccountId1) | (1 << subAccountId2) ); // a call using ERC-1271 signature succeeds items[0].data = abi.encodeWithSelector( - ICVC.setAccountOperator.selector, + IEVC.setAccountOperator.selector, bob, operator, true ); items[1].data = abi.encodeWithSelector( - ICVC.setAccountOperator.selector, + IEVC.setAccountOperator.selector, address(uint160(bob) ^ subAccountId1), operator, true ); items[2].data = abi.encodeWithSelector( - ICVC.setOperator.selector, + IEVC.setOperator.selector, addressPrefixBob, operator, (1 << 0) | (1 << subAccountId1) | (1 << subAccountId2) ); - data = abi.encodeWithSelector(ICVC.batch.selector, items); + data = abi.encodeWithSelector(IEVC.batch.selector, items); signature = bytes("bob's signature"); SignerERC1271(bob).setSignatureHash(signature); SignerERC1271(bob).setPermitHash(bob, 0, 1, block.timestamp, 0, data); - cvc.permit(bob, 0, 1, block.timestamp, 0, data, signature); - assertEq(cvc.isAccountOperatorAuthorized(bob, operator), true); + evc.permit(bob, 0, 1, block.timestamp, 0, data, signature); + assertEq(evc.isAccountOperatorAuthorized(bob, operator), true); assertEq( - cvc.isAccountOperatorAuthorized( + evc.isAccountOperatorAuthorized( address(uint160(bob) ^ subAccountId1), operator ), true ); assertEq( - cvc.isAccountOperatorAuthorized( + evc.isAccountOperatorAuthorized( address(uint160(bob) ^ subAccountId2), operator ), true ); assertEq( - cvc.getOperator(addressPrefixBob, operator), + evc.getOperator(addressPrefixBob, operator), (1 << 0) | (1 << subAccountId1) | (1 << subAccountId2) ); // if the operator tries to authorize some other operator directly, it's not possible vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefixAlice, operator, 0); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefixAlice, operator, 0); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefixAlice, otherOperator, 0); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefixAlice, otherOperator, 0); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(alice, otherOperator, true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(alice, otherOperator, true); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefixBob, operator, 0); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefixBob, operator, 0); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefixBob, otherOperator, 0); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefixBob, otherOperator, 0); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(bob, otherOperator, true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(bob, otherOperator, true); // but it succeeds if it's done using the signed data data = abi.encodeWithSelector( - ICVC.setOperator.selector, + IEVC.setOperator.selector, addressPrefixAlice, otherOperator, 2 @@ -1604,9 +1608,9 @@ contract PermitTest is Test { data ); vm.prank(operator); - cvc.permit(alice, 0, 2, block.timestamp, 0, data, signature); + evc.permit(alice, 0, 2, block.timestamp, 0, data, signature); assertEq( - cvc.isAccountOperatorAuthorized( + evc.isAccountOperatorAuthorized( address(uint160(alice) ^ 1), otherOperator ), @@ -1614,7 +1618,7 @@ contract PermitTest is Test { ); data = abi.encodeWithSelector( - ICVC.setAccountOperator.selector, + IEVC.setAccountOperator.selector, alice, otherOperator, true @@ -1629,11 +1633,11 @@ contract PermitTest is Test { data ); vm.prank(operator); - cvc.permit(alice, 0, 3, block.timestamp, 0, data, signature); - assertEq(cvc.isAccountOperatorAuthorized(alice, otherOperator), true); + evc.permit(alice, 0, 3, block.timestamp, 0, data, signature); + assertEq(evc.isAccountOperatorAuthorized(alice, otherOperator), true); data = abi.encodeWithSelector( - ICVC.setOperator.selector, + IEVC.setOperator.selector, addressPrefixBob, otherOperator, 2 @@ -1644,9 +1648,9 @@ contract PermitTest is Test { SignerERC1271(bob).setPermitHash(bob, 0, 2, block.timestamp, 0, data); vm.prank(operator); - cvc.permit(bob, 0, 2, block.timestamp, 0, data, signature); + evc.permit(bob, 0, 2, block.timestamp, 0, data, signature); assertEq( - cvc.isAccountOperatorAuthorized( + evc.isAccountOperatorAuthorized( address(uint160(bob) ^ 1), otherOperator ), @@ -1654,7 +1658,7 @@ contract PermitTest is Test { ); data = abi.encodeWithSelector( - ICVC.setAccountOperator.selector, + IEVC.setAccountOperator.selector, bob, otherOperator, true @@ -1664,14 +1668,14 @@ contract PermitTest is Test { SignerERC1271(bob).setPermitHash(bob, 0, 3, block.timestamp, 0, data); vm.prank(operator); - cvc.permit(bob, 0, 3, block.timestamp, 0, data, signature); - assertEq(cvc.isAccountOperatorAuthorized(bob, otherOperator), true); + evc.permit(bob, 0, 3, block.timestamp, 0, data, signature); + assertEq(evc.isAccountOperatorAuthorized(bob, otherOperator), true); // when the operator is authorized, it can sign permit messages on behalf of the authorized account signerECDSA.setPrivateKey(privateKey + 1); data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, alice, address(0) ); @@ -1684,14 +1688,14 @@ contract PermitTest is Test { 0, data ); - cvc.permit(operator, 0, 1, block.timestamp, 0, data, signature); - assertEq(cvc.isCollateralEnabled(alice, address(0)), true); + evc.permit(operator, 0, 1, block.timestamp, 0, data, signature); + assertEq(evc.isCollateralEnabled(alice, address(0)), true); // and another one data = abi.encodeWithSelector( Target.callTest.selector, - address(cvc), - address(cvc), + address(evc), + address(evc), 0, alice, true @@ -1705,18 +1709,18 @@ contract PermitTest is Test { 0, data ); - cvc.permit(operator, 0, 2, block.timestamp, 0, data, signature); + evc.permit(operator, 0, 2, block.timestamp, 0, data, signature); // but it cannot sign permit messages on behalf of other accounts for which it's not authorized vm.prank(operator); - cvc.setAccountOperator( + evc.setAccountOperator( address(uint160(alice) ^ subAccountId1), operator, false ); data = abi.encodeWithSelector( - ICVC.enableCollateral.selector, + IEVC.enableCollateral.selector, address(uint160(alice) ^ subAccountId1), address(0) ); @@ -1729,7 +1733,7 @@ contract PermitTest is Test { 0, data ); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.permit(operator, 0, 3, block.timestamp, 0, data, signature); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.permit(operator, 0, 3, block.timestamp, 0, data, signature); } } diff --git a/test/unit/CreditVaultConnector/SetNonce.sol b/test/unit/EthereumVaultConnector/SetNonce.sol similarity index 50% rename from test/unit/CreditVaultConnector/SetNonce.sol rename to test/unit/EthereumVaultConnector/SetNonce.sol index 05a3d8e5..20a9b3df 100644 --- a/test/unit/CreditVaultConnector/SetNonce.sol +++ b/test/unit/EthereumVaultConnector/SetNonce.sol @@ -3,15 +3,15 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract SetNonceTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; event NonceUsed(uint152 indexed addressPrefix, uint nonce); function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_SetNonce( @@ -20,18 +20,18 @@ contract SetNonceTest is Test { uint nonce, uint8 iterations ) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(iterations > 0 && iterations < 5); vm.assume(nonce > 0 && nonce <= type(uint).max - 256 * iterations); - uint152 addressPrefix = cvc.getAddressPrefix(alice); - assertEq(cvc.getNonce(addressPrefix, nonceNamespace), 0); + uint152 addressPrefix = evc.getAddressPrefix(alice); + assertEq(evc.getNonce(addressPrefix, nonceNamespace), 0); - vm.expectEmit(true, false, false, true, address(cvc)); + vm.expectEmit(true, false, false, true, address(evc)); emit NonceUsed(addressPrefix, ++nonce); vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); - assertEq(cvc.getNonce(addressPrefix, nonceNamespace), nonce); + evc.setNonce(addressPrefix, nonceNamespace, nonce); + assertEq(evc.getNonce(addressPrefix, nonceNamespace), nonce); } function test_RevertIfSenderNotOwner_SetNonce( @@ -40,34 +40,34 @@ contract SetNonceTest is Test { uint nonceNamespace, uint nonce ) public { - uint152 addressPrefix = cvc.getAddressPrefix(alice); - vm.assume(alice != address(0) && alice != address(cvc)); + uint152 addressPrefix = evc.getAddressPrefix(alice); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(addressPrefix != type(uint152).max); vm.assume(operator != address(0)); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(!evc.haveCommonOwner(alice, operator)); vm.assume(nonce > 0 && nonce < type(uint).max); // fails if address prefix does not belong to an owner vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setNonce(addressPrefix + 1, nonceNamespace, nonce); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setNonce(addressPrefix + 1, nonceNamespace, nonce); // succeeds if address prefix belongs to an owner vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); + evc.setNonce(addressPrefix, nonceNamespace, nonce); // fails if owner not consistent vm.prank(address(uint160(uint160(alice) ^ 1))); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setNonce(addressPrefix, nonceNamespace, nonce); // reverts if sender is an operator vm.prank(alice); - cvc.setAccountOperator(alice, operator, true); + evc.setAccountOperator(alice, operator, true); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setNonce(addressPrefix, nonceNamespace, nonce); } function test_RevertIfInvalidNonce_SetNonce( @@ -75,23 +75,23 @@ contract SetNonceTest is Test { uint nonceNamespace, uint nonce ) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(nonce > 0); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); // fails if invalid nonce vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidNonce.selector); - cvc.setNonce(addressPrefix, nonceNamespace, 0); + vm.expectRevert(Errors.EVC_InvalidNonce.selector); + evc.setNonce(addressPrefix, nonceNamespace, 0); // succeeds if valid nonce vm.prank(alice); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); + evc.setNonce(addressPrefix, nonceNamespace, nonce); // fails again if invalid nonce vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidNonce.selector); - cvc.setNonce(addressPrefix, nonceNamespace, nonce); + vm.expectRevert(Errors.EVC_InvalidNonce.selector); + evc.setNonce(addressPrefix, nonceNamespace, nonce); } } diff --git a/test/unit/CreditVaultConnector/SetOperator.t.sol b/test/unit/EthereumVaultConnector/SetOperator.t.sol similarity index 52% rename from test/unit/CreditVaultConnector/SetOperator.t.sol rename to test/unit/EthereumVaultConnector/SetOperator.t.sol index f1f63d0a..3f3181ad 100644 --- a/test/unit/CreditVaultConnector/SetOperator.t.sol +++ b/test/unit/EthereumVaultConnector/SetOperator.t.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract SetOperatorTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; event OperatorStatus( uint152 indexed addressPrefix, @@ -16,7 +16,7 @@ contract SetOperatorTest is Test { event OwnerRegistered(uint152 indexed addressPrefix, address indexed owner); function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_WhenOwnerCalling_SetOperator( @@ -24,72 +24,72 @@ contract SetOperatorTest is Test { address operator, uint operatorBitField ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(operator != address(0) && operator != address(cvc)); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(operator != address(0) && operator != address(evc)); + vm.assume(!evc.haveCommonOwner(alice, operator)); vm.assume(operatorBitField > 0); - uint152 addressPrefix = cvc.getAddressPrefix(alice); - vm.expectRevert(Errors.CVC_AccountOwnerNotRegistered.selector); - cvc.getAccountOwner(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); + vm.expectRevert(Errors.EVC_AccountOwnerNotRegistered.selector); + evc.getAccountOwner(alice); - assertEq(cvc.getOperator(addressPrefix, operator), 0); + assertEq(evc.getOperator(addressPrefix, operator), 0); - vm.expectEmit(true, true, false, false, address(cvc)); + vm.expectEmit(true, true, false, false, address(evc)); emit OwnerRegistered(addressPrefix, alice); - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit OperatorStatus(addressPrefix, operator, operatorBitField); vm.prank(alice); - cvc.setOperator(addressPrefix, operator, operatorBitField); + evc.setOperator(addressPrefix, operator, operatorBitField); - assertEq(cvc.getOperator(addressPrefix, operator), operatorBitField); + assertEq(evc.getOperator(addressPrefix, operator), operatorBitField); for (uint i = 0; i < 256; ++i) { address account = address(uint160(uint160(alice) ^ i)); bool isAlreadyAuthorized = operatorBitField & (1 << i) != 0; assertEq( - cvc.isAccountOperatorAuthorized(account, operator), + evc.isAccountOperatorAuthorized(account, operator), isAlreadyAuthorized ); // authorize the operator if (!isAlreadyAuthorized) { - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit OperatorStatus( addressPrefix, operator, operatorBitField | (1 << i) ); vm.prank(alice); - cvc.setAccountOperator(account, operator, true); + evc.setAccountOperator(account, operator, true); } - assertEq(cvc.isAccountOperatorAuthorized(account, operator), true); + assertEq(evc.isAccountOperatorAuthorized(account, operator), true); // deauthorize the operator - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit OperatorStatus( addressPrefix, operator, operatorBitField & ~(1 << i) ); vm.prank(alice); - cvc.setAccountOperator(account, operator, false); - assertEq(cvc.isAccountOperatorAuthorized(account, operator), false); + evc.setAccountOperator(account, operator, false); + assertEq(evc.isAccountOperatorAuthorized(account, operator), false); // restore to the original state if needed - if (cvc.getOperator(addressPrefix, operator) != operatorBitField) { + if (evc.getOperator(addressPrefix, operator) != operatorBitField) { vm.prank(alice); - cvc.setOperator(addressPrefix, operator, operatorBitField); + evc.setOperator(addressPrefix, operator, operatorBitField); } } // reset the operator status - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit OperatorStatus(addressPrefix, operator, 0); vm.prank(alice); - cvc.setOperator(addressPrefix, operator, 0); + evc.setOperator(addressPrefix, operator, 0); - assertEq(cvc.getOperator(addressPrefix, operator), 0); + assertEq(evc.getOperator(addressPrefix, operator), 0); } function test_WhenOperatorCalling_SetOperator( @@ -97,51 +97,51 @@ contract SetOperatorTest is Test { address operator, uint seed ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(operator != address(0) && operator != address(cvc)); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(operator != address(0) && operator != address(evc)); + vm.assume(!evc.haveCommonOwner(alice, operator)); for (uint i = 0; i < 256; ++i) { address account = address(uint160(uint160(alice) ^ i)); - uint152 addressPrefix = cvc.getAddressPrefix(account); - assertEq(cvc.isAccountOperatorAuthorized(account, operator), false); + uint152 addressPrefix = evc.getAddressPrefix(account); + assertEq(evc.isAccountOperatorAuthorized(account, operator), false); if (i == 0) { - vm.expectRevert(Errors.CVC_AccountOwnerNotRegistered.selector); - cvc.getAccountOwner(account); + vm.expectRevert(Errors.EVC_AccountOwnerNotRegistered.selector); + evc.getAccountOwner(account); } else { - assertEq(cvc.getAccountOwner(account), alice); + assertEq(evc.getAccountOwner(account), alice); } // authorize the operator if (i == 0) { - vm.expectEmit(true, true, false, false, address(cvc)); - emit OwnerRegistered(cvc.getAddressPrefix(alice), alice); + vm.expectEmit(true, true, false, false, address(evc)); + emit OwnerRegistered(evc.getAddressPrefix(alice), alice); } - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit OperatorStatus(addressPrefix, operator, 1 << i); vm.recordLogs(); vm.prank(alice); - cvc.setAccountOperator(account, operator, true); + evc.setAccountOperator(account, operator, true); Vm.Log[] memory logs = vm.getRecordedLogs(); assertTrue(i == 0 ? logs.length == 2 : logs.length == 1); // OwnerRegistered event is emitted only once - assertEq(cvc.isAccountOperatorAuthorized(account, operator), true); - assertEq(cvc.getAccountOwner(account), alice); + assertEq(evc.isAccountOperatorAuthorized(account, operator), true); + assertEq(evc.getAccountOwner(account), alice); // the operator cannot call setOperator() vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefix, operator, seed); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefix, operator, seed); // but the operator can deauthorize itself calling setAccountOperator() - vm.expectEmit(true, true, false, true, address(cvc)); + vm.expectEmit(true, true, false, true, address(evc)); emit OperatorStatus(addressPrefix, operator, 0); vm.prank(operator); - cvc.setAccountOperator(account, operator, false); + evc.setAccountOperator(account, operator, false); - assertEq(cvc.isAccountOperatorAuthorized(account, operator), false); - assertEq(cvc.getAccountOwner(account), alice); + assertEq(evc.isAccountOperatorAuthorized(account, operator), false); + assertEq(evc.getAccountOwner(account), alice); } } @@ -150,21 +150,21 @@ contract SetOperatorTest is Test { address operator, uint operatorBitField ) public { - vm.assume(alice != address(0) && alice != address(cvc)); - vm.assume(operator != address(0) && operator != address(cvc)); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(alice != address(0) && alice != address(evc)); + vm.assume(operator != address(0) && operator != address(evc)); + vm.assume(!evc.haveCommonOwner(alice, operator)); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + uint152 addressPrefix = evc.getAddressPrefix(alice); if (operatorBitField > 0) { vm.prank(alice); - cvc.setOperator(addressPrefix, operator, operatorBitField); + evc.setOperator(addressPrefix, operator, operatorBitField); } // revert when trying to set the same operator status vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidOperatorStatus.selector); - cvc.setOperator(addressPrefix, operator, operatorBitField); + vm.expectRevert(Errors.EVC_InvalidOperatorStatus.selector); + evc.setOperator(addressPrefix, operator, operatorBitField); for (uint i = 0; i < 256; ++i) { address account = address(uint160(uint160(alice) ^ i)); @@ -172,8 +172,8 @@ contract SetOperatorTest is Test { // revert when trying to set the same operator status vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidOperatorStatus.selector); - cvc.setAccountOperator(account, operator, isAlreadyAuthorized); + vm.expectRevert(Errors.EVC_InvalidOperatorStatus.selector); + evc.setAccountOperator(account, operator, isAlreadyAuthorized); } } @@ -182,31 +182,31 @@ contract SetOperatorTest is Test { address operator, uint operatorBitField ) public { - uint152 addressPrefix = cvc.getAddressPrefix(alice); - vm.assume(alice != address(0) && alice != address(cvc)); + uint152 addressPrefix = evc.getAddressPrefix(alice); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume(operator != address(0)); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(!evc.haveCommonOwner(alice, operator)); vm.assume(addressPrefix != type(uint152).max); vm.assume(operatorBitField > 0); // fails if address prefix does not belong to an owner vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefix + 1, operator, operatorBitField); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefix + 1, operator, operatorBitField); // succeeds if address prefix belongs to an owner vm.prank(alice); - cvc.setOperator(addressPrefix, operator, operatorBitField); + evc.setOperator(addressPrefix, operator, operatorBitField); // fails if owner not consistent vm.prank(address(uint160(uint160(alice) ^ 1))); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefix, operator, operatorBitField); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefix, operator, operatorBitField); // reverts if sender is an operator vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setOperator(addressPrefix, operator, operatorBitField); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setOperator(addressPrefix, operator, operatorBitField); } function test_RevertIfSenderNotOwnerAndNotOperator_SetAccountOperator( @@ -216,100 +216,100 @@ contract SetOperatorTest is Test { vm.assume( alice != address(0) && alice != address(0xfe) && - alice != address(cvc) + alice != address(evc) ); vm.assume(operator != address(0)); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(!evc.haveCommonOwner(alice, operator)); address account = address(uint160(uint160(alice) ^ 256)); vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(account, operator, true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(account, operator, true); // succeeds if sender is authorized account = address(uint160(uint160(alice) ^ 255)); vm.prank(address(uint160(uint160(alice) ^ 254))); - cvc.setAccountOperator(account, operator, true); + evc.setAccountOperator(account, operator, true); // reverts if sender is not a registered owner nor operator vm.prank(alice); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(account, operator, true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(account, operator, true); // reverts if sender is not a registered owner nor operator vm.prank(address(uint160(uint160(operator) ^ 1))); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(account, operator, true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(account, operator, true); } function test_RevertWhenOperatorNotAuthorizedToPerformTheOperation_SetAccountOperator( address alice, address operator ) public { - vm.assume(alice != address(0) && alice != address(cvc)); + vm.assume(alice != address(0) && alice != address(evc)); vm.assume( operator != address(0) && address(uint160(operator) ^ 1) != address(0) && - operator != address(cvc) + operator != address(evc) ); - vm.assume(!cvc.haveCommonOwner(alice, operator)); + vm.assume(!evc.haveCommonOwner(alice, operator)); - assertEq(cvc.isAccountOperatorAuthorized(alice, operator), false); + assertEq(evc.isAccountOperatorAuthorized(alice, operator), false); vm.prank(alice); - cvc.setAccountOperator(alice, operator, true); - assertEq(cvc.isAccountOperatorAuthorized(alice, operator), true); + evc.setAccountOperator(alice, operator, true); + assertEq(evc.isAccountOperatorAuthorized(alice, operator), true); // operator cannot change authorization status for any other operator nor account vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(address(uint160(alice) ^ 1), operator, true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(address(uint160(alice) ^ 1), operator, true); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(alice, address(uint160(operator) ^ 1), true); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(alice, address(uint160(operator) ^ 1), true); vm.prank(alice); - cvc.setAccountOperator(alice, address(uint160(operator) ^ 1), true); + evc.setAccountOperator(alice, address(uint160(operator) ^ 1), true); vm.prank(operator); - vm.expectRevert(Errors.CVC_NotAuthorized.selector); - cvc.setAccountOperator(alice, address(uint160(operator) ^ 1), false); + vm.expectRevert(Errors.EVC_NotAuthorized.selector); + evc.setAccountOperator(alice, address(uint160(operator) ^ 1), false); // operator can deauthorize itself vm.prank(operator); - cvc.setAccountOperator(alice, operator, false); + evc.setAccountOperator(alice, operator, false); - assertEq(cvc.isAccountOperatorAuthorized(alice, operator), false); + assertEq(evc.isAccountOperatorAuthorized(alice, operator), false); } function test_RevertIfOperatorIsInvalidAddress_SetOperator( address alice, uint8 subAccountId ) public { - vm.assume(alice != address(cvc)); - uint152 addressPrefix = cvc.getAddressPrefix(alice); + vm.assume(alice != address(evc)); + uint152 addressPrefix = evc.getAddressPrefix(alice); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.setOperator(addressPrefix, address(0), 0); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.setOperator(addressPrefix, address(0), 0); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.setAccountOperator(alice, address(0), true); + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.setAccountOperator(alice, address(0), true); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.setOperator( + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.setOperator( addressPrefix, address(uint160(alice) ^ subAccountId), 0 ); vm.prank(alice); - vm.expectRevert(Errors.CVC_InvalidAddress.selector); - cvc.setAccountOperator( + vm.expectRevert(Errors.EVC_InvalidAddress.selector); + evc.setAccountOperator( alice, address(uint160(alice) ^ subAccountId), true diff --git a/test/unit/CreditVaultConnector/VaultStatus.t.sol b/test/unit/EthereumVaultConnector/VaultStatus.t.sol similarity index 70% rename from test/unit/CreditVaultConnector/VaultStatus.t.sol rename to test/unit/EthereumVaultConnector/VaultStatus.t.sol index 3048902e..b2fe7c0d 100644 --- a/test/unit/CreditVaultConnector/VaultStatus.t.sol +++ b/test/unit/EthereumVaultConnector/VaultStatus.t.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.20; import "forge-std/Test.sol"; -import "../../cvc/CreditVaultConnectorHarness.sol"; +import "../../evc/EthereumVaultConnectorHarness.sol"; contract VaultStatusTest is Test { - CreditVaultConnectorHarness internal cvc; + EthereumVaultConnectorHarness internal evc; function setUp() public { - cvc = new CreditVaultConnectorHarness(); + evc = new EthereumVaultConnectorHarness(); } function test_RequireVaultStatusCheck( @@ -19,7 +19,7 @@ contract VaultStatusTest is Test { vm.assume(vaultsNumber > 0 && vaultsNumber <= Set.MAX_ELEMENTS); for (uint i = 0; i < vaultsNumber; i++) { - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); // check all the options: vault state is ok, vault state is violated with // vault returning false and reverting @@ -39,9 +39,9 @@ contract VaultStatusTest is Test { : abi.encode(bytes4(uint32(1))) ); } - cvc.requireVaultStatusCheck(); - cvc.verifyVaultStatusChecks(); - cvc.clearExpectedChecks(); + evc.requireVaultStatusCheck(); + evc.verifyVaultStatusChecks(); + evc.clearExpectedChecks(); } } @@ -52,7 +52,7 @@ contract VaultStatusTest is Test { vm.assume(vaultsNumber > 0 && vaultsNumber <= Set.MAX_ELEMENTS); for (uint i = 0; i < vaultsNumber; i++) { - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); // check all the options: vault state is ok, vault state is violated with // vault returning false and reverting @@ -65,22 +65,22 @@ contract VaultStatusTest is Test { ); Vault(vault).setVaultStatusState(1); - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(vault); // even though the vault status state was set to 1 which should revert, // it doesn't because in checks deferral we only add the vaults to the set // so that the checks can be performed later - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); if (!(allStatusesValid || uint160(vault) % 3 == 0)) { // checks no longer deferred - cvc.setCallDepth(0); + evc.setCallDepth(0); vm.prank(vault); vm.expectRevert(bytes("vault status violation")); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); } } } @@ -94,20 +94,20 @@ contract VaultStatusTest is Test { address[] memory vaults = new address[](vaultsNumber); for (uint i = 0; i < vaultsNumber; i++) { - vaults[i] = address(new Vault(cvc)); + vaults[i] = address(new Vault(evc)); } - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(vaults[index]); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(vaults[index]); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); } function test_AcquireChecksLock_RequireVaultStatusChecks( @@ -117,16 +117,16 @@ contract VaultStatusTest is Test { address[] memory vaults = new address[](numberOfVaults); for (uint i = 0; i < numberOfVaults; i++) { - vaults[i] = address(new VaultMalicious(cvc)); + vaults[i] = address(new VaultMalicious(evc)); VaultMalicious(vaults[i]).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); vm.prank(vaults[i]); - // function will revert with CVC_VaultStatusViolation according to VaultMalicious implementation + // function will revert with EVC_VaultStatusViolation according to VaultMalicious implementation vm.expectRevert(bytes("malicious vault")); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); } } @@ -138,7 +138,7 @@ contract VaultStatusTest is Test { address[] memory vaults = new address[](vaultsNumber); for (uint i = 0; i < vaultsNumber; i++) { - vaults[i] = address(new Vault(cvc)); + vaults[i] = address(new Vault(evc)); address vault = vaults[i]; // check all the options: vault state is ok, vault state is violated with @@ -153,15 +153,15 @@ contract VaultStatusTest is Test { // first, schedule the check to be performed later to prove that after being peformed on the fly // vault is no longer contained in the set to be performed later - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(vault); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); Vault(vault).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); vm.prank(vault); if (!(allStatusesValid || uint160(vault) % 3 == 0)) { vm.expectRevert( @@ -170,27 +170,27 @@ contract VaultStatusTest is Test { : abi.encode(bytes4(uint32(1))) ); } - cvc.requireVaultStatusCheckNow(); + evc.requireVaultStatusCheckNow(); if (allStatusesValid || uint160(vault) % 3 == 0) { - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); } else { - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); } - cvc.verifyVaultStatusChecks(); + evc.verifyVaultStatusChecks(); } // schedule the checks to be performed later to prove that after being peformed on the fly // vaults are no longer contained in the set to be performed later - cvc.setCallDepth(1); + evc.setCallDepth(1); for (uint i = 0; i < vaultsNumber; i++) { address vault = vaults[i]; vm.prank(vault); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); Vault(vault).clearChecks(); - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); } - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); for (uint i = 0; i < vaultsNumber; i++) { address vault = vaults[i]; @@ -203,15 +203,15 @@ contract VaultStatusTest is Test { : abi.encode(bytes4(uint32(1))) ); } - cvc.requireVaultStatusCheckNow(); + evc.requireVaultStatusCheckNow(); if (allStatusesValid || uint160(vault) % 3 == 0) { - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); } else { - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); } } - cvc.verifyVaultStatusChecks(); + evc.verifyVaultStatusChecks(); } function test_RevertIfChecksReentrancy_RequireVaultStatusCheckNow( @@ -221,18 +221,18 @@ contract VaultStatusTest is Test { address[] memory vaults = new address[](numberOfVaults); for (uint i = 0; i < numberOfVaults; i++) { - vaults[i] = address(new Vault(cvc)); + vaults[i] = address(new Vault(evc)); - cvc.setChecksLock(true); + evc.setChecksLock(true); vm.prank(vaults[i]); vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.requireVaultStatusCheckNow(); + evc.requireVaultStatusCheckNow(); - cvc.setChecksLock(false); + evc.setChecksLock(false); vm.prank(vaults[i]); - cvc.requireVaultStatusCheckNow(); + evc.requireVaultStatusCheckNow(); } } @@ -242,21 +242,21 @@ contract VaultStatusTest is Test { vm.assume(numberOfVaults > 0 && numberOfVaults <= Set.MAX_ELEMENTS); for (uint i = 0; i < numberOfVaults; i++) { - address vault = address(new VaultMalicious(cvc)); + address vault = address(new VaultMalicious(evc)); - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(vault); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); VaultMalicious(vault).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); - // function will revert with CVC_VaultStatusViolation according to VaultMalicious implementation + // function will revert with EVC_VaultStatusViolation according to VaultMalicious implementation vm.prank(vault); vm.expectRevert(bytes("malicious vault")); - cvc.requireVaultStatusCheckNow(); + evc.requireVaultStatusCheckNow(); } } @@ -268,7 +268,7 @@ contract VaultStatusTest is Test { address[] memory vaults = new address[](numberOfVaults); for (uint i = 0; i < numberOfVaults; i++) { - vaults[i] = address(new Vault(cvc)); + vaults[i] = address(new Vault(evc)); } uint invalidVaultsCounter; @@ -277,8 +277,8 @@ contract VaultStatusTest is Test { for (uint i = 0; i < numberOfVaults; i++) { address vault = vaults[i]; - cvc.reset(); - cvc.setCallDepth(0); + evc.reset(); + evc.setCallDepth(0); // check all the options: vault state is ok, vault state is violated with // vault returning false and reverting @@ -290,15 +290,15 @@ contract VaultStatusTest is Test { : 2 ); - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(vault); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); Vault(vault).clearChecks(); - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); if (!(allStatusesValid || uint160(vault) % 3 == 0)) { // for later check invalidVaults[invalidVaultsCounter++] = vault; @@ -309,28 +309,28 @@ contract VaultStatusTest is Test { : abi.encode(bytes4(uint32(1))) ); } - cvc.requireAllVaultsStatusCheckNow(); + evc.requireAllVaultsStatusCheckNow(); if (allStatusesValid || uint160(vault) % 3 == 0) { - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); } else { - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); } - cvc.verifyVaultStatusChecks(); + evc.verifyVaultStatusChecks(); } - cvc.reset(); + evc.reset(); - cvc.setCallDepth(1); + evc.setCallDepth(1); for (uint i = 0; i < vaults.length; ++i) { vm.prank(vaults[i]); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); Vault(vaults[i]).clearChecks(); } - cvc.clearExpectedChecks(); + evc.clearExpectedChecks(); for (uint i = 0; i < vaults.length; ++i) { - assertTrue(cvc.isVaultStatusCheckDeferred(vaults[i])); + assertTrue(evc.isVaultStatusCheckDeferred(vaults[i])); } if (invalidVaultsCounter > 0) { vm.expectRevert( @@ -339,26 +339,26 @@ contract VaultStatusTest is Test { : abi.encode(bytes4(uint32(1))) ); } - cvc.requireAllVaultsStatusCheckNow(); + evc.requireAllVaultsStatusCheckNow(); for (uint i = 0; i < vaults.length; ++i) { assertEq( - cvc.isVaultStatusCheckDeferred(vaults[i]), + evc.isVaultStatusCheckDeferred(vaults[i]), invalidVaultsCounter > 0 ); } - cvc.verifyVaultStatusChecks(); + evc.verifyVaultStatusChecks(); } function test_RevertIfChecksReentrancy_RequireAllVaultsStatusCheckNow( bool locked ) external { - cvc.setChecksLock(locked); + evc.setChecksLock(locked); if (locked) vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.requireAllVaultsStatusCheckNow(); + evc.requireAllVaultsStatusCheckNow(); } function test_AcquireChecksLock_RequireAllVaultsStatusChecksNow( @@ -368,50 +368,50 @@ contract VaultStatusTest is Test { address[] memory vaults = new address[](numberOfVaults); for (uint i = 0; i < numberOfVaults; i++) { - vaults[i] = address(new VaultMalicious(cvc)); + vaults[i] = address(new VaultMalicious(evc)); - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(vaults[i]); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); VaultMalicious(vaults[i]).setExpectedErrorSelector( - Errors.CVC_ChecksReentrancy.selector + Errors.EVC_ChecksReentrancy.selector ); } vm.expectRevert(bytes("malicious vault")); - cvc.requireAllVaultsStatusCheckNow(); + evc.requireAllVaultsStatusCheckNow(); } function test_ForgiveVaultStatusCheck(uint8 vaultsNumber) external { vm.assume(vaultsNumber > 0 && vaultsNumber <= Set.MAX_ELEMENTS); for (uint i = 0; i < vaultsNumber; i++) { - address vault = address(new Vault(cvc)); + address vault = address(new Vault(evc)); // vault status check will be scheduled for later due to deferred state - cvc.setCallDepth(1); + evc.setCallDepth(1); vm.prank(vault); - cvc.requireVaultStatusCheck(); + evc.requireVaultStatusCheck(); - assertTrue(cvc.isVaultStatusCheckDeferred(vault)); + assertTrue(evc.isVaultStatusCheckDeferred(vault)); vm.prank(vault); - cvc.forgiveVaultStatusCheck(); - assertFalse(cvc.isVaultStatusCheckDeferred(vault)); + evc.forgiveVaultStatusCheck(); + assertFalse(evc.isVaultStatusCheckDeferred(vault)); } } function test_RevertIfChecksReentrancy_ForgiveVaultStatusCheck( bool locked ) external { - cvc.setChecksLock(locked); + evc.setChecksLock(locked); if (locked) vm.expectRevert( - abi.encodeWithSelector(Errors.CVC_ChecksReentrancy.selector) + abi.encodeWithSelector(Errors.EVC_ChecksReentrancy.selector) ); - cvc.forgiveVaultStatusCheck(); + evc.forgiveVaultStatusCheck(); } } diff --git a/test/utils/mocks/Target.sol b/test/utils/mocks/Target.sol index defa0033..278f8654 100644 --- a/test/utils/mocks/Target.sol +++ b/test/utils/mocks/Target.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.20; -import "../../../src/CreditVaultConnector.sol"; +import "../../../src/EthereumVaultConnector.sol"; -// mock target contract that allows to test call(), callback() and impersonate() functions of the CVC +// mock target contract that allows to test call(), callback() and impersonate() functions of the EVC contract Target { function callTest( - address cvc, + address evc, address msgSender, uint value, address onBehalfOfAccount, bool operatorAuthenticated ) external payable returns (uint) { - try ICVC(cvc).getCurrentOnBehalfOfAccount(address(0)) returns ( + try IEVC(evc).getCurrentOnBehalfOfAccount(address(0)) returns ( address _onBehalfOfAccount, bool ) { @@ -30,33 +30,33 @@ contract Target { require(msg.sender == msgSender, "ct/invalid-sender"); require(msg.value == value, "ct/invalid-msg-value"); require( - ICVC(cvc).getCurrentCallDepth() > 0, + IEVC(evc).getCurrentCallDepth() > 0, "ct/invalid-checks-deferred" ); - require(!ICVC(cvc).areChecksInProgress(), "ct/checks-lock"); - require(!ICVC(cvc).isImpersonationInProgress(), "ct/impersonate-lock"); + require(!IEVC(evc).areChecksInProgress(), "ct/checks-lock"); + require(!IEVC(evc).isImpersonationInProgress(), "ct/impersonate-lock"); require( operatorAuthenticated - ? ICVC(cvc).isOperatorAuthenticated() - : !ICVC(cvc).isOperatorAuthenticated(), + ? IEVC(evc).isOperatorAuthenticated() + : !IEVC(evc).isOperatorAuthenticated(), "ct/operator-authenticated" ); - ICVC(cvc).requireAccountStatusCheck(onBehalfOfAccount); + IEVC(evc).requireAccountStatusCheck(onBehalfOfAccount); require( - ICVC(cvc).isAccountStatusCheckDeferred(onBehalfOfAccount), + IEVC(evc).isAccountStatusCheckDeferred(onBehalfOfAccount), "ct/account-status-checks-not-deferred" ); return msg.value; } function impersonateTest( - address cvc, + address evc, address msgSender, uint value, address onBehalfOfAccount ) external payable returns (uint) { - try ICVC(cvc).getCurrentOnBehalfOfAccount(address(0)) returns ( + try IEVC(evc).getCurrentOnBehalfOfAccount(address(0)) returns ( address _onBehalfOfAccount, bool ) { @@ -73,15 +73,15 @@ contract Target { require(msg.sender == msgSender, "it/invalid-sender"); require(msg.value == value, "it/invalid-msg-value"); require( - ICVC(cvc).getCurrentCallDepth() > 0, + IEVC(evc).getCurrentCallDepth() > 0, "it/invalid-checks-deferred" ); - require(!ICVC(cvc).areChecksInProgress(), "it/checks-lock"); - require(ICVC(cvc).isImpersonationInProgress(), "it/impersonate-lock"); + require(!IEVC(evc).areChecksInProgress(), "it/checks-lock"); + require(IEVC(evc).isImpersonationInProgress(), "it/impersonate-lock"); - ICVC(cvc).requireAccountStatusCheck(onBehalfOfAccount); + IEVC(evc).requireAccountStatusCheck(onBehalfOfAccount); require( - ICVC(cvc).isAccountStatusCheckDeferred(onBehalfOfAccount), + IEVC(evc).isAccountStatusCheckDeferred(onBehalfOfAccount), "it/account-status-checks-not-deferred" ); @@ -89,12 +89,12 @@ contract Target { } function callbackTest( - address cvc, + address evc, address msgSender, uint value, address onBehalfOfAccount ) external payable returns (uint) { - try ICVC(cvc).getCurrentOnBehalfOfAccount(address(0)) returns ( + try IEVC(evc).getCurrentOnBehalfOfAccount(address(0)) returns ( address _onBehalfOfAccount, bool ) { @@ -111,20 +111,20 @@ contract Target { require(msg.sender == msgSender, "cbt/invalid-sender"); require(msg.value == value, "ct/invalid-msg-value"); require( - ICVC(cvc).getCurrentCallDepth() > 0, + IEVC(evc).getCurrentCallDepth() > 0, "cbt/invalid-checks-deferred" ); - require(!ICVC(cvc).areChecksInProgress(), "cbt/impersonate-lock"); - require(!ICVC(cvc).isImpersonationInProgress(), "cbt/impersonate-lock"); + require(!IEVC(evc).areChecksInProgress(), "cbt/impersonate-lock"); + require(!IEVC(evc).isImpersonationInProgress(), "cbt/impersonate-lock"); require( - !ICVC(cvc).isOperatorAuthenticated(), + !IEVC(evc).isOperatorAuthenticated(), "cbt/operator-authenticated" ); - ICVC(cvc).requireAccountStatusCheck(onBehalfOfAccount); + IEVC(evc).requireAccountStatusCheck(onBehalfOfAccount); require( - ICVC(cvc).isAccountStatusCheckDeferred(onBehalfOfAccount), + IEVC(evc).isAccountStatusCheckDeferred(onBehalfOfAccount), "cbt/account-status-checks-not-deferred" ); return msg.value; @@ -137,14 +137,14 @@ contract Target { contract TargetWithNesting { function nestedCallTest( - address cvc, + address evc, address msgSender, address targetContract, uint value, address onBehalfOfAccount, bool operatorAuthenticated ) external payable returns (uint) { - try ICVC(cvc).getCurrentOnBehalfOfAccount(address(0)) returns ( + try IEVC(evc).getCurrentOnBehalfOfAccount(address(0)) returns ( address _onBehalfOfAccount, bool ) { @@ -161,26 +161,26 @@ contract TargetWithNesting { require(msg.sender == msgSender, "nct/invalid-sender"); require(msg.value == value, "nct/invalid-msg-value"); require( - ICVC(cvc).getCurrentCallDepth() > 0, + IEVC(evc).getCurrentCallDepth() > 0, "nct/invalid-checks-deferred" ); - require(!ICVC(cvc).areChecksInProgress(), "nct/checks-lock"); - require(!ICVC(cvc).isImpersonationInProgress(), "nct/impersonate-lock"); + require(!IEVC(evc).areChecksInProgress(), "nct/checks-lock"); + require(!IEVC(evc).isImpersonationInProgress(), "nct/impersonate-lock"); require( operatorAuthenticated - ? ICVC(cvc).isOperatorAuthenticated() - : !ICVC(cvc).isOperatorAuthenticated(), + ? IEVC(evc).isOperatorAuthenticated() + : !IEVC(evc).isOperatorAuthenticated(), "nct/operator-authenticated" ); - bytes memory result = ICVC(cvc).call( + bytes memory result = IEVC(evc).call( targetContract, address(this), 0, abi.encodeWithSelector( Target.callTest.selector, - cvc, - cvc, + evc, + evc, 0, address(this), false, @@ -189,7 +189,7 @@ contract TargetWithNesting { ); require(abi.decode(result, (uint)) == 0, "nct/result"); - try ICVC(cvc).getCurrentOnBehalfOfAccount(address(0)) returns ( + try IEVC(evc).getCurrentOnBehalfOfAccount(address(0)) returns ( address _onBehalfOfAccount, bool ) { @@ -204,17 +204,17 @@ contract TargetWithNesting { ); } require( - ICVC(cvc).getCurrentCallDepth() > 0, + IEVC(evc).getCurrentCallDepth() > 0, "nct/invalid-checks-deferred-2" ); require( - !ICVC(cvc).isImpersonationInProgress(), + !IEVC(evc).isImpersonationInProgress(), "nct/impersonate-lock-2" ); require( operatorAuthenticated - ? ICVC(cvc).isOperatorAuthenticated() - : !ICVC(cvc).isOperatorAuthenticated(), + ? IEVC(evc).isOperatorAuthenticated() + : !IEVC(evc).isOperatorAuthenticated(), "nct/operator-authenticated-2" ); diff --git a/test/utils/mocks/Vault.sol b/test/utils/mocks/Vault.sol index a29d63eb..15e2090d 100644 --- a/test/utils/mocks/Vault.sol +++ b/test/utils/mocks/Vault.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.20; import "./Target.sol"; -import "../../../src/interfaces/ICreditVault.sol"; +import "../../../src/interfaces/IVault.sol"; // mock vault contract that implements required interface and helps with status checks verification -contract Vault is ICreditVault, Target { - ICVC public immutable cvc; +contract Vault is IVault, Target { + IEVC public immutable evc; uint internal vaultStatusState; uint internal accountStatusState; @@ -15,8 +15,8 @@ contract Vault is ICreditVault, Target { bool[] internal vaultStatusChecked; address[] internal accountStatusChecked; - constructor(ICVC _cvc) { - cvc = _cvc; + constructor(IEVC _evc) { + evc = _evc; } function reset() external { @@ -60,7 +60,7 @@ contract Vault is ICreditVault, Target { } function disableController(address account) external virtual override { - cvc.disableController(account); + evc.disableController(account); } function checkVaultStatus() @@ -69,17 +69,17 @@ contract Vault is ICreditVault, Target { override returns (bytes4 magicValue) { - try cvc.getCurrentOnBehalfOfAccount(address(0)) { + try evc.getCurrentOnBehalfOfAccount(address(0)) { revert("cvs/on-behalf-of-account"); } catch (bytes memory reason) { if ( bytes4(reason) != - Errors.CVC_OnBehalfOfAccountNotAuthenticated.selector + Errors.EVC_OnBehalfOfAccountNotAuthenticated.selector ) { revert("cvs/on-behalf-of-account-2"); } } - require(cvc.areChecksInProgress(), "cvs/checks-not-in-progress"); + require(evc.areChecksInProgress(), "cvs/checks-not-in-progress"); if (vaultStatusState == 0) { return 0x4b3d1223; @@ -94,17 +94,17 @@ contract Vault is ICreditVault, Target { address, address[] memory ) external virtual override returns (bytes4 magicValue) { - try cvc.getCurrentOnBehalfOfAccount(address(0)) { + try evc.getCurrentOnBehalfOfAccount(address(0)) { revert("cas/on-behalf-of-account"); } catch (bytes memory reason) { if ( bytes4(reason) != - Errors.CVC_OnBehalfOfAccountNotAuthenticated.selector + Errors.EVC_OnBehalfOfAccountNotAuthenticated.selector ) { revert("cas/on-behalf-of-account-2"); } } - require(cvc.areChecksInProgress(), "cas/checks-not-in-progress"); + require(evc.areChecksInProgress(), "cas/checks-not-in-progress"); if (accountStatusState == 0) { return 0xb168c58f; @@ -116,8 +116,8 @@ contract Vault is ICreditVault, Target { } function requireChecks(address account) external payable { - cvc.requireAccountStatusCheck(account); - cvc.requireVaultStatusCheck(); + evc.requireAccountStatusCheck(account); + evc.requireVaultStatusCheck(); } function requireChecksWithSimulationCheck( @@ -125,12 +125,12 @@ contract Vault is ICreditVault, Target { bool expectedSimulationInProgress ) external payable { require( - cvc.isSimulationInProgress() == expectedSimulationInProgress, + evc.isSimulationInProgress() == expectedSimulationInProgress, "requireChecksWithSimulationCheck/simulation" ); - cvc.requireAccountStatusCheck(account); - cvc.requireVaultStatusCheck(); + evc.requireAccountStatusCheck(account); + evc.requireVaultStatusCheck(); } function call(address target, bytes memory data) external payable virtual { @@ -142,15 +142,15 @@ contract Vault is ICreditVault, Target { contract VaultMalicious is Vault { bytes4 internal expectedErrorSelector; - constructor(ICVC _cvc) Vault(_cvc) {} + constructor(IEVC _evc) Vault(_evc) {} function setExpectedErrorSelector(bytes4 selector) external { expectedErrorSelector = selector; } function callBatch() external payable { - (bool success, bytes memory result) = address(cvc).call( - abi.encodeWithSelector(cvc.batch.selector, new ICVC.BatchItem[](0)) + (bool success, bytes memory result) = address(evc).call( + abi.encodeWithSelector(evc.batch.selector, new IEVC.BatchItem[](0)) ); require(!success, "callBatch/succeeded"); @@ -159,24 +159,24 @@ contract VaultMalicious is Vault { } function checkVaultStatus() external virtual override returns (bytes4) { - try cvc.getCurrentOnBehalfOfAccount(address(0)) { + try evc.getCurrentOnBehalfOfAccount(address(0)) { revert("cvs/on-behalf-of-account"); } catch (bytes memory reason) { if ( bytes4(reason) != - Errors.CVC_OnBehalfOfAccountNotAuthenticated.selector + Errors.EVC_OnBehalfOfAccountNotAuthenticated.selector ) { revert("cvs/on-behalf-of-account-2"); } } - require(cvc.areChecksInProgress(), "cvs/checks-not-in-progress"); + require(evc.areChecksInProgress(), "cvs/checks-not-in-progress"); if (expectedErrorSelector == 0) { return this.checkVaultStatus.selector; } - (bool success, bytes memory result) = address(cvc).call( - abi.encodeWithSelector(cvc.batch.selector, new ICVC.BatchItem[](0)) + (bool success, bytes memory result) = address(evc).call( + abi.encodeWithSelector(evc.batch.selector, new IEVC.BatchItem[](0)) ); if (success || bytes4(result) != expectedErrorSelector) { @@ -190,24 +190,24 @@ contract VaultMalicious is Vault { address, address[] memory ) external override returns (bytes4) { - try cvc.getCurrentOnBehalfOfAccount(address(0)) { + try evc.getCurrentOnBehalfOfAccount(address(0)) { revert("cas/on-behalf-of-account"); } catch (bytes memory reason) { if ( bytes4(reason) != - Errors.CVC_OnBehalfOfAccountNotAuthenticated.selector + Errors.EVC_OnBehalfOfAccountNotAuthenticated.selector ) { revert("cas/on-behalf-of-account-2"); } } - require(cvc.areChecksInProgress(), "cas/checks-not-in-progress"); + require(evc.areChecksInProgress(), "cas/checks-not-in-progress"); if (expectedErrorSelector == 0) { return this.checkAccountStatus.selector; } - (bool success, bytes memory result) = address(cvc).call( - abi.encodeWithSelector(cvc.batch.selector, new ICVC.BatchItem[](0)) + (bool success, bytes memory result) = address(evc).call( + abi.encodeWithSelector(evc.batch.selector, new IEVC.BatchItem[](0)) ); if (success || bytes4(result) != expectedErrorSelector) {