# BaseVault

**Inherits:** IBaseVault, Pausable, CallbackHandler, ReentrancyGuardTransient, Auth2Step, IERC721Receiver

This contract embeds core Aera platform functionality: the ability to enlist off-chain guardians to take guarded actions on a vault. It is meant to either be extended with deposit/withdraw capabilities for users or used directly. When used directly, a depositor can simply transfer assets to the vault and a guardian can transfer them out when needed Registered guardians call the submit function and trigger vault operations. The vault may run before and after submit hooks and revert if a guardian is using an unauthorized operation. Authorized operations are configured in an off-chain merkle tree and guardians need to provide a merkle proof for each operation. In addition to validating operation targets (the contract and function being called), the merkle tree can maintain custom per-operation hooks that extract specific parts of the calldata for validation or even perform (possibly stateful) validation during the submit call

## State Variables

### HOOK\_CALL\_TYPE\_SLOT

ERC7201-compliant transient storage slot for the current hook call type flag

*Equal to keccak256(abi.encode(uint256(keccak256("aera.basevault.hookCallType")) - 1)) & \~bytes32(uint256(0xff));*

```solidity
bytes32 internal constant HOOK_CALL_TYPE_SLOT = 0xb8706f504833578f7e830b12e31c3cfba31669a85b02596177f00c6a7faf6e00;
```

### WHITELIST

The whitelist contract that controls vault permissions

```solidity
IWhitelist public immutable WHITELIST;
```

### submitHooks

Address of the submit hooks contract for vault-level operations

```solidity
ISubmitHooks public submitHooks;
```

### guardianRoots

Enumerable map of each guardian address to their merkle root

```solidity
EnumerableMap.AddressToBytes32Map internal guardianRoots;
```

## Functions

### onlyAuthOrGuardian

Ensures caller either has auth authorization requiresAuth (owner or authorized role) or is a guardian

```solidity
modifier onlyAuthOrGuardian();
```

### constructor

```solidity
constructor() Pausable() Auth2Step(msg.sender, Authority(address(0)));
```

### receive

Receive function to allow the vault to receive native tokens

```solidity
receive() external payable;
```

### submit

Submit a series of operations to the vault

```solidity
/// @notice Submit a series of operations to the vault
/// @param data Encoded array of operations to submit
/// ┌─────────────────────────────┬─────────────────────────┬───────────────────────────────────────────────┐
/// │ FIELDS                      │ SIZE                    │ DESCRIPTION                                   │
/// ├─────────────────────────────┴─────────────────────────┴───────────────────────────────────────────────┤
/// │ operationsLength              1 byte                    Number of operations in the array             │
/// │                                                                                                       │
/// │ [for each operation]:                                                                                 │
/// │                                                                                                       │
/// │   SIGNATURE                                                                                           │
/// │   target                      20 bytes                  Target contract address                       │
/// │   calldataLength              2 bytes                   Length of calldata                            │
/// │   calldata                    <calldataLength> bytes    Calldata (before pipelining)                  │
/// │                                                                                                       │
/// │   CLIPBOARD                                                                                           │
/// │   clipboardsLength            1 byte                    Number of clipboards                          │
/// │   [for each clipboard entry]:                                                                         │
/// │       resultIndex             1 byte                    Which operation to take from                  │
/// │       copyWord                1 byte                    Which word to copy                            │
/// │       pasteOffset             2 bytes                   What offset to paste it at                    │
/// │                                                                                                       │
/// │   CALL TYPE                                                                                           │
/// │   isStaticCall                1 byte                    1 if static, 0 if a regular call              │
/// │   [if isStaticCall == 0]:                                                                             │
/// │                                                                                                       │
/// │     CALLBACK HANDLING                                                                                 │
/// │     hasCallback               1 byte                    Whether to allow callbacks during operation   │
/// │     [if hasCallback == 1]:                                                                            │
/// │       callbackData =          26 bytes                  Expected callback info                        │
/// │       ┌────────────────────┬──────────────────────────┬───────────────────┐                           │
/// │       │ selector (4 bytes) │ calldataOffset (2 bytes) │ caller (20 bytes) │                           │
/// │       └────────────────────┴──────────────────────────┴───────────────────┘                           │
/// │                                                                                                       │
/// │     HOOKS                                                                                             │
/// │     hookConfig =              1 byte                    Hook configuration                            │
/// │     ┌─────────────────┬────────────────────────────────────────┐                                      │
/// │     │ hasHook (1 bit) │ configurableHookOffsetsLength (7 bits) │                                      │
/// │     └─────────────────┴────────────────────────────────────────┘                                      │
/// │     if configurableHookOffsetsLength > 0:                                                             │
/// │         configurableHookOffsets 32 bytes                Packed configurable hook offsets              │
/// │     if hasHook == 1:                                                                                  │
/// │         hook                 20 bytes                   Hook contract address                         │
/// │                                                                                                       │
/// │     MERKLE PROOF                                                                                      │
/// │     proofLength              1 byte                     Merkle proof length                           │
/// │     proof                    <proofLength> * 32 bytes   Merkle proof data                             │
/// │                                                                                                       │
/// │     PAYABILITY                                                                                        │
/// │     hasValue                 1 byte                     Whether to send native token with the call    │
/// │     [if hasValue == 1]:                                                                               │
/// │       value                  32 bytes                   Amount of native token to send                │
/// └───────────────────────────────────────────────────────────────────────────────────────────────────────┘
function submit(bytes calldata data) external whenNotPaused nonReentrant;
```

**Parameters**

| Name   | Type    |
| ------ | ------- |
| `data` | `bytes` |

### setGuardianRoot

Set the merkle root for a guardian Used to add guardians and update their permissions

```solidity
function setGuardianRoot(address guardian, bytes32 root) external virtual requiresAuth;
```

**Parameters**

| Name       | Type      | Description             |
| ---------- | --------- | ----------------------- |
| `guardian` | `address` | Address of the guardian |
| `root`     | `bytes32` | Merkle root             |

### removeGuardian

Removes a guardian from the vault

```solidity
function removeGuardian(address guardian) external virtual requiresAuth;
```

**Parameters**

| Name       | Type      | Description             |
| ---------- | --------- | ----------------------- |
| `guardian` | `address` | Address of the guardian |

### checkGuardianWhitelist

Check if the guardian is whitelisted and set the root to zero if not Used to disable guardians who were removed from the whitelist after being selected as guardians

```solidity
function checkGuardianWhitelist(address guardian) external returns (bool isRemoved);
```

**Parameters**

| Name       | Type      | Description          |
| ---------- | --------- | -------------------- |
| `guardian` | `address` | The guardian address |

**Returns**

| Name        | Type   | Description                                         |
| ----------- | ------ | --------------------------------------------------- |
| `isRemoved` | `bool` | Whether the guardian was removed from the whitelist |

### setSubmitHooks

Set the submit hooks address

```solidity
function setSubmitHooks(ISubmitHooks newSubmitHooks) external virtual requiresAuth;
```

**Parameters**

| Name             | Type           | Description                              |
| ---------------- | -------------- | ---------------------------------------- |
| `newSubmitHooks` | `ISubmitHooks` | Address of the new submit hooks contract |

### pause

Pause the vault, halting the ability for guardians to submit

```solidity
function pause() external onlyAuthOrGuardian;
```

### unpause

Unpause the vault, allowing guardians to submit operations

```solidity
function unpause() external requiresAuth;
```

### getActiveGuardians

Get all active guardians

```solidity
function getActiveGuardians() external view returns (address[] memory);
```

**Returns**

| Name     | Type        | Description                        |
| -------- | ----------- | ---------------------------------- |
| `<none>` | `address[]` | Array of active guardian addresses |

### getGuardianRoot

Get the guardian root for a guardian

```solidity
function getGuardianRoot(address guardian) external view returns (bytes32);
```

**Parameters**

| Name       | Type      | Description          |
| ---------- | --------- | -------------------- |
| `guardian` | `address` | The guardian address |

**Returns**

| Name     | Type      | Description       |
| -------- | --------- | ----------------- |
| `<none>` | `bytes32` | The guardian root |

### getCurrentHookCallType

Get the current hook call type

```solidity
function getCurrentHookCallType() external view returns (HookCallType);
```

**Returns**

| Name     | Type           | Description                |
| -------- | -------------- | -------------------------- |
| `<none>` | `HookCallType` | The current hook call type |

### onERC721Received

*Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.*

```solidity
function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4);
```

### \_handleCallbackOperations

```solidity
/// @notice Internal handler for validated callbacks
/// @dev Callback operations are like regular operations, but with a return value, which are encoded after
/// operations array
/// ┌─────────────────────────────┬─────────────────────────┬───────────────────────────────────────────────┐
/// │ FIELDS                      │ SIZE                    │ DESCRIPTION                                   │
/// ├─────────────────────────────┴─────────────────────────┴───────────────────────────────────────────────┤
/// │  returnTypeFlag              1 byte                     0 = no return, 1 = static, 2 = dynamic        │
/// │  [if returnTypeFlag == 1]:                                                                            │
/// │     returnDataLength         2 bytes                    Length of return data                         │
/// │     returnData               <returnDataLength> bytes   Static return data                            │
/// └───────────────────────────────────────────────────────────────────────────────────────────────────────┘
/// @param root The merkle root of the callback
/// @param cursor The cursor to the callback data
/// @return returnValue The return value of the callback
function _handleCallbackOperations(bytes32 root, uint256 cursor)
    internal
    virtual
    override
    returns (bytes memory returnValue);
```

**Parameters**

| Name     | Type      | Description                     |
| -------- | --------- | ------------------------------- |
| `root`   | `bytes32` | The merkle root of the callback |
| `cursor` | `uint256` | The cursor to the callback data |

**Returns**

| Name          | Type    | Description                      |
| ------------- | ------- | -------------------------------- |
| `returnValue` | `bytes` | The return value of the callback |

### \_processExpectedCallback

Prepare for a callback if the guardian expects one

*Writes to transient storage to encode callback expectations*

```solidity
function _processExpectedCallback(CalldataReader reader, bytes32 root) internal returns (CalldataReader, uint208);
```

**Parameters**

| Name     | Type             | Description                                                        |
| -------- | ---------------- | ------------------------------------------------------------------ |
| `reader` | `CalldataReader` | Current position in the calldata                                   |
| `root`   | `bytes32`        | The merkle root of the active guardian that triggered the callback |

**Returns**

| Name     | Type             | Description             |
| -------- | ---------------- | ----------------------- |
| `<none>` | `CalldataReader` | Updated cursor position |
| `<none>` | `uint208`        | Packed callback data    |

### \_beforeSubmitHooks

Call the before submit hooks if defined

*Submit hooks passed as an argument to reduce storage loading*

```solidity
function _beforeSubmitHooks(address hooks, bytes calldata data) internal;
```

**Parameters**

| Name    | Type      | Description                                 |
| ------- | --------- | ------------------------------------------- |
| `hooks` | `address` | Address of the submit hooks contract        |
| `data`  | `bytes`   | Calldata to pass to the before submit hooks |

### \_afterSubmitHooks

Call the after submit hooks if defined

*Submit hooks passed as an argument to reduce storage loading*

```solidity
function _afterSubmitHooks(address hooks, bytes calldata data) internal;
```

**Parameters**

| Name    | Type      | Description                                |
| ------- | --------- | ------------------------------------------ |
| `hooks` | `address` | Address of the submit hooks contract       |
| `data`  | `bytes`   | Calldata to pass to the after submit hooks |

### \_beforeOperationHooks

Call the before operation hooks if defined

```solidity
function _beforeOperationHooks(address operationHooks, bytes memory data, uint256 i)
    internal
    returns (bytes memory result);
```

**Parameters**

| Name             | Type      | Description                             |
| ---------------- | --------- | --------------------------------------- |
| `operationHooks` | `address` | Address of the operation-specific hooks |
| `data`           | `bytes`   | Operation calldata                      |
| `i`              | `uint256` | Operation index                         |

**Returns**

| Name     | Type    | Description              |
| -------- | ------- | ------------------------ |
| `result` | `bytes` | Result of the hooks call |

### \_afterOperationHooks

Call the after operation hooks if defined

```solidity
function _afterOperationHooks(address operationHooks, bytes memory data, uint256 i) internal;
```

**Parameters**

| Name             | Type      | Description                             |
| ---------------- | --------- | --------------------------------------- |
| `operationHooks` | `address` | Address of the operation-specific hooks |
| `data`           | `bytes`   | Operation calldata                      |
| `i`              | `uint256` | Operation index                         |

### \_executeSubmit

Executes a series of operations

*Approvals are tracked so we can verify if they have been zeroed out at the end of submit*

```solidity
function _executeSubmit(bytes32 root, CalldataReader reader, bool isCalledFromCallback)
    internal
    returns (Approval[] memory approvals, uint256 approvalsLength, bytes[] memory results, CalldataReader newReader);
```

**Parameters**

| Name                   | Type             | Description                                                        |
| ---------------------- | ---------------- | ------------------------------------------------------------------ |
| `root`                 | `bytes32`        | The merkle root of the active guardian that triggered the callback |
| `reader`               | `CalldataReader` | Current position in the calldata                                   |
| `isCalledFromCallback` | `bool`           | Whether the submit is called from a callback                       |

**Returns**

| Name              | Type             | Description                                          |
| ----------------- | ---------------- | ---------------------------------------------------- |
| `approvals`       | `Approval[]`     | Array of outgoing approvals created during execution |
| `approvalsLength` | `uint256`        | Length of approvals array                            |
| `results`         | `bytes[]`        | Array of results from the operations                 |
| `newReader`       | `CalldataReader` | Updated cursor position                              |

### \_processBeforeOperationHooks

Processes all hooks for operation

Returns extracted data if configurable or contract before operation hooks is defined

*Custom hooks (with contracts) can run before and after each operation but a configurable hooks can only run before an operation. This function processes all of the possible configurations of hooks which doesn't allow using both a custom before hook and a configurable before hook*

```solidity
function _processBeforeOperationHooks(CalldataReader reader, bytes memory callData, uint256 i)
    internal
    returns (CalldataReader, bytes memory, uint256, address);
```

**Parameters**

| Name       | Type             | Description                      |
| ---------- | ---------------- | -------------------------------- |
| `reader`   | `CalldataReader` | Current position in the calldata |
| `callData` | `bytes`          | Operation calldata               |
| `i`        | `uint256`        | Operation index                  |

**Returns**

| Name     | Type             | Description                                |
| -------- | ---------------- | ------------------------------------------ |
| `<none>` | `CalldataReader` | reader Updated reader position             |
| `<none>` | `bytes`          | extractedData Extracted chunks of calldata |
| `<none>` | `uint256`        | hooksConfigBytes hooks configuration bytes |
| `<none>` | `address`        | operationHooks Operation hooks address     |

### \_setSubmitHooks

Set the submit hooks address

```solidity
function _setSubmitHooks(ISubmitHooks submitHooks_) internal;
```

**Parameters**

| Name           | Type           | Description                          |
| -------------- | -------------- | ------------------------------------ |
| `submitHooks_` | `ISubmitHooks` | Address of the submit hooks contract |

### \_setGuardianRoot

Set the guardian root

```solidity
function _setGuardianRoot(address guardian, bytes32 root) internal virtual;
```

**Parameters**

| Name       | Type      | Description             |
| ---------- | --------- | ----------------------- |
| `guardian` | `address` | Address of the guardian |
| `root`     | `bytes32` | Merkle root             |

### \_setHookCallType

Set the hook call type

```solidity
function _setHookCallType(HookCallType hookCallType) internal;
```

**Parameters**

| Name           | Type           | Description        |
| -------------- | -------------- | ------------------ |
| `hookCallType` | `HookCallType` | The hook call type |

### \_noPendingApprovalsInvariant

Verify no pending approvals remain at the end of a submit

*We iterate backwards to avoid extra i variable*

*While loop is preferred over for(;approvalsLength != 0;)*

*Iterator variable is not used because it's not needed and decrement needs to be unchecked*

```solidity
function _noPendingApprovalsInvariant(Approval[] memory approvals, uint256 approvalsLength) internal view;
```

**Parameters**

| Name              | Type         | Description                 |
| ----------------- | ------------ | --------------------------- |
| `approvals`       | `Approval[]` | Array of approvals to check |
| `approvalsLength` | `uint256`    | Length of approvals array   |

### \_getReturnValue

Get the return value from the operations

```solidity
function _getReturnValue(CalldataReader reader, bytes[] memory results)
    internal
    pure
    returns (CalldataReader newReader, bytes memory returnValue);
```

**Parameters**

| Name      | Type             | Description                          |
| --------- | ---------------- | ------------------------------------ |
| `reader`  | `CalldataReader` | Current position in the calldata     |
| `results` | `bytes[]`        | Array of results from the operations |

**Returns**

| Name          | Type             | Description                      |
| ------------- | ---------------- | -------------------------------- |
| `newReader`   | `CalldataReader` | Updated reader position          |
| `returnValue` | `bytes`          | Return value from the operations |

### \_verifyOperation

Verify an operation by validating the merkle proof

```solidity
function _verifyOperation(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure;
```

**Parameters**

| Name    | Type        | Description               |
| ------- | ----------- | ------------------------- |
| `proof` | `bytes32[]` | The merkle proof          |
| `root`  | `bytes32`   | The merkle root           |
| `leaf`  | `bytes32`   | The merkle leaf to verify |

### \_createMerkleLeaf

Create a merkle leaf

```solidity
function _createMerkleLeaf(OperationContext memory ctx, bytes memory extractedData) internal pure returns (bytes32);
```

**Parameters**

| Name            | Type               | Description           |
| --------------- | ------------------ | --------------------- |
| `ctx`           | `OperationContext` | The operation context |
| `extractedData` | `bytes`            | The extracted data    |

**Returns**

| Name     | Type      | Description          |
| -------- | --------- | -------------------- |
| `<none>` | `bytes32` | leaf The merkle leaf |

### \_extractApprovalSpender

Extract spender address from approval data

*Extract spender address from approval data*

```solidity
function _extractApprovalSpender(bytes memory data) internal pure returns (address spender);
```

**Parameters**

| Name   | Type    | Description       |
| ------ | ------- | ----------------- |
| `data` | `bytes` | Approval calldata |

**Returns**

| Name      | Type      | Description            |
| --------- | --------- | ---------------------- |
| `spender` | `address` | Address of the spender |

### \_hasBeforeHooks

Check if hooks needs to be called before the submit/operation

*Check if hooks needs to be called before the submit/operation*

```solidity
function _hasBeforeHooks(address hooks) internal pure returns (bool);
```

**Parameters**

| Name    | Type      | Description            |
| ------- | --------- | ---------------------- |
| `hooks` | `address` | Hooks address to check |

**Returns**

| Name     | Type   | Description                                                  |
| -------- | ------ | ------------------------------------------------------------ |
| `<none>` | `bool` | True if hooks needs to be called before the submit/operation |

### \_hasAfterHooks

least significant bit is 1 indicating it's a before hooks

Check if submit hooks needs to be called after the submit/operation

*Check if submit hooks needs to be called after the submit/operation*

```solidity
function _hasAfterHooks(address hooks) internal pure returns (bool);
```

**Parameters**

| Name    | Type      | Description                   |
| ------- | --------- | ----------------------------- |
| `hooks` | `address` | Submit hooks address to check |

**Returns**

| Name     | Type   | Description                                                        |
| -------- | ------ | ------------------------------------------------------------------ |
| `<none>` | `bool` | True if submit hooks needs to be called after the submit/operation |

### \_isAllowanceSelector

second least significant bit is 1 indicating it's a after hooks

Check if the selector is an allowance handling selector

*Check if the selector is an allowance handling selector*

```solidity
function _isAllowanceSelector(bytes4 selector) internal pure returns (bool);
```

**Parameters**

| Name       | Type     | Description       |
| ---------- | -------- | ----------------- |
| `selector` | `bytes4` | Selector to check |

**Returns**

| Name     | Type   | Description                                            |
| -------- | ------ | ------------------------------------------------------ |
| `<none>` | `bool` | True if the selector is an allowance handling selector |
