# EscrowManager

### Overview <a href="#overview" id="overview"></a>

**EscrowManager** is a smart contract that manages locked EYWA tokens, each represented by a unique ERC-721 NFT (sometimes referred to as a "veEYWA" token). Each lock NFT stores information about its locked token amount, unlock time, vesting wallets, and booster NFTs. The contract supports operations like depositing, boosting, extending, deboosting, and withdrawing locked tokens, while tracking voting power via time-based checkpoints and epochs. It integrates with an external vote manager contract for governance operations and a collection contract for booster NFTs.

**Key Features:**

1. **Lock Creation & Management:** Users can create locks by transferring EYWA tokens, vesting wallets, or tokens from an NFT collection. They can add more tokens, apply boosters, or extend the lock duration.
2. **Voting Power:** Each lock corresponds to voting power that evolves over time. The contract records checkpoints of ownership and calculates voting weights using a dynamic rate-of-change approach.
3. **Booster Mechanism:** Boosters from the collection can increase a lock’s "coverage," thus effectively increasing its lock amount for voting power calculations.
4. **Cooldown & Freeze Logic:** After certain actions such as deboosting, token transfers may be temporarily frozen to prevent immediate re-deposit or locking manipulations.
5. **Delegation Checks:** The contract can integrate with a delegation manager to move voting power between addresses.

By implementing the `IEscrowManager` interface, the **EscrowManager** contract provides a consistent API for user and external contract interactions in the CrossCurve ecosystem.

***

### Inherited Contracts and Interfaces <a href="#inherited-contracts-and-interfaces" id="inherited-contracts-and-interfaces"></a>

* **ERC721Enumerable, ERC721 (OpenZeppelin):**\
  Provides standard ERC-721 NFT functionality with enumeration capabilities, enabling easy listing of all minted NFTs.
* **ERC721Holder (OpenZeppelin):**\
  Allows the contract to safely hold ERC-721 tokens (necessary when receiving booster NFTs).
* **ReentrancyGuard (OpenZeppelin):**\
  Mitigates re-entrant calls on state-changing functions.
* **SafeERC20, IERC20 (OpenZeppelin):**\
  Provides secure wrappers for ERC20 operations, ensuring safe token transfers.

**External Interfaces:**

* **IEscrowManager:** The interface implemented by this contract, defining locking and booster logic.
* **IEscrowVoteManagerV1:** The vote manager that tracks epochs, triggers freeze logic, and notifies about gauge rewards.
* **ICollection, IWalletFactory, IVestingWallet:** Components in the ecosystem for NFT boosters, creating/managing vesting wallets, and bridging custom data.
* **IMetadataProviderV1:** Supplies metadata URIs for NFTs.
* **VotingPowerHelper (Library):** Used to compute historical voting power and supply based on stored checkpoints and rate-of-change data.

***

### Constants <a href="#constants" id="constants"></a>

* **`ATTACHMENTS_LIMIT` = 100**\
  Maximum number of attachments (vesting wallets or booster NFTs) allowed per lock.
* **`EPOCH_DURATION` = 1 weeks**\
  Governs epoch-based calculations for voting power and lock logic.
* **`MAXIMUM_LOCK_DURATION` = 156 weeks**\
  Maximum allowed lock duration in seconds (approximately 3 years).
* **`MAXIMUM_NUMBER_OF_DELEGATES` = 1024**\
  Maximum delegates that can be tracked for a single account’s checkpoints.
* **`SIGNED_MAXIMUM_LOCK_DURATION` = 156 weeks**\
  Signed integer equivalent for arithmetic purposes.
* **Rarity Multipliers and Capacities:**\
  Predefined numerators and capacity values for Common, Uncommon, Rare, Legendary, and Infinity NFT rarities.
* **`PRECISION` = 100,000**\
  Scaling factor for multiplier-based calculations (e.g., coverage, booster effects).

**Immutable Addresses:**

* **`ESCROW_VOTE_MANAGER (address)`:** The escrow vote manager contract address.
* **`DELEGATION_MANAGER (address)`:** The delegation manager contract address.
* **`EYWA (IERC20)`:** The EYWA token used in locking.
* **`COLLECTION (ICollection)`:** The collection contract supporting booster NFTs.
* **`WALLET_FACTORY (IWalletFactory)`:** Factory contract for validating vesting wallets.
* **`METADATA_PROVIDER (IMetadataProviderV1)`:** Supplies off-chain metadata for NFTs.

***

### State Variables <a href="#state-variables" id="state-variables"></a>

* **`s_nextTokenId (uint256)`**\
  The next NFT token ID to be minted.
* **`s_epoch (uint256)`**\
  Tracks how many epochs have occurred, updated whenever lock states change significantly.
* **`s_totalLocked (uint256)`**\
  Total EYWA tokens locked across all positions.

**Lock and Booster Details:**

* **`_s_lockInfoByTokenId (mapping(uint256 => LockInfo))`:** Internal mapping of lock data.
* **`s_pureLockAmountByTokenId, s_vestingWalletsLockAmountByTokenId`:** Track base token amounts and vesting wallet contributions.
* **`s_currentCoverageByTokenId`:** Booster coverage for each lock.
* **`s_boostersByTokenId, s_boostersByTokenIdAndRarity`:** Maintain sets of booster NFT IDs by token ID and rarity.

**Checkpointing and Voting:**

* **`s_checkpointsNumberByAccount (mapping(address => uint32))`:** Number of checkpoints for each account.
* **`s_checkpoints (mapping(address => mapping(uint32 => Checkpoint)))`:** Account checkpoints listing owned lock NFTs at different times.
* **`s_ownershipChangeBlockNumberByTokenId (mapping(uint256 => uint256))`:** Block number of the last ownership change for each NFT (prevents double-voting in the same block).
* **`s_rateOfChangeByUnlockTime (mapping(uint256 => int128))`:** Tracks changes in voting power at specific unlock times.
* **`s_hasVotedByTokenId (mapping(uint256 => bool))`:** Whether a token has voted in the current epoch.
* **`s_hasVotedByEpochAndTokenId (mapping(uint256 => mapping(uint256 => bool)))`:** Tracks vote status for each token in each epoch.
* **`s_votingPowerPointByEpoch (mapping(uint256 => VotingPowerPoint))`:** Stores aggregated voting power changes per epoch.
* **`s_votingPowerPointByTokenIdAndEpoch (mapping(uint256 => VotingPowerPoint[1000000000]))`:** Voting power data for each token ID across epochs.

**Deboost and Freeze Logic:**

* **`s_lastDeboostTimestampByTokenId (mapping(uint256 => uint256))`:** Records the last time a token was deboosted, used to freeze subsequent transfers.

***

### Constructor <a href="#constructor" id="constructor"></a>

```solidity
constructor(
    address escrowVoteManager_,
    address delegationManager_,
    IERC20 eywa_,
    ICollection collection_,
    IWalletFactory walletFactory_,
    IMetadataProviderV1 metadataProvider_
) 
    ERC721("EYWA DAO NFT", "veEYWA")
{
    ...
}
```

* **Description:**\
  Deploys the **EscrowManager**, sets immutable addresses for the escrow vote manager, delegation manager, EYWA token, collection, wallet factory, and metadata provider, and initializes the NFT name and symbol.

***

### External Functions (Defined by IEscrowManager) <a href="#external-functions-defined-by-iescrowmanager" id="external-functions-defined-by-iescrowmanager"></a>

#### `createLock(uint256 lockAmount_, uint256 lockDuration_, address recipient_)` <a href="#createlock-uint256-lockamount_-uint256-lockduration_-address-recipient" id="createlock-uint256-lockamount_-uint256-lockduration_-address-recipient"></a>

```solidity
function createLock(
    uint256 lockAmount_,
    uint256 lockDuration_,
    address recipient_
) 
    external 
    nonReentrant
```

**Description:**\
Creates a lock by transferring `lockAmount_` of EYWA from the caller, locking it for `lockDuration_` (rounded down to epoch boundaries). Mints an NFT for `recipient_`.

***

#### `createLock(uint256 lockDuration_, address recipient_, address[] calldata vestingWallets_)` <a href="#createlock-uint256-lockduration_-address-recipient_-address-calldata-vestingwallets" id="createlock-uint256-lockduration_-address-recipient_-address-calldata-vestingwallets"></a>

```solidity
function createLock(
    uint256 lockDuration_,
    address recipient_,
    address[] calldata vestingWallets_
) 
    external 
    nonReentrant
```

**Description:**\
Creates a lock by transferring tokens from multiple vesting wallets owned by the caller, then mints an NFT lock. Each vesting wallet's beneficiary must match the caller.

***

#### `createLock(uint256 lockDuration_, address recipient_, uint256[] calldata collectionTokenIds_)` <a href="#createlock-uint256-lockduration_-address-recipient_-uint256-calldata-collectiontokenids" id="createlock-uint256-lockduration_-address-recipient_-uint256-calldata-collectiontokenids"></a>

```solidity
function createLock(
    uint256 lockDuration_,
    address recipient_,
    uint256[] calldata collectionTokenIds_
)
    external 
    nonReentrant
```

**Description:**\
Creates a lock using tokens associated with the given collection token IDs. Collects vesting wallets pinned to those NFTs, locks their balances, and automatically applies boosters via `_modifyBoost`.

***

#### `deposit(uint256 tokenId_, uint256 lockAmount_)` <a href="#deposit-uint256-tokenid_-uint256-lockamount" id="deposit-uint256-tokenid_-uint256-lockamount"></a>

```solidity
function deposit(uint256 tokenId_, uint256 lockAmount_) external nonReentrant
```

**Description:**\
Adds extra EYWA to an existing lock. Requires caller authorization (`_checkAuthorized`).

***

#### `depositFor(uint256 tokenId_, uint256 lockAmount_)` <a href="#depositfor-uint256-tokenid_-uint256-lockamount" id="depositfor-uint256-tokenid_-uint256-lockamount"></a>

```solidity
function depositFor(uint256 tokenId_, uint256 lockAmount_) external nonReentrant
```

**Description:**\
Adds EYWA to an existing lock on behalf of the owner, without caller checks.

***

#### `boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)` <a href="#boost-uint256-tokenid_-uint256-calldata-collectiontokenids" id="boost-uint256-tokenid_-uint256-calldata-collectiontokenids"></a>

```solidity
function boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_) external nonReentrant
```

**Description:**\
Associates additional booster NFTs with a lock, increasing its coverage and potentially its voting power. Booster NFTs may also bring vesting wallets if pinned.

***

#### `deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)` <a href="#deboost-uint256-tokenid_-uint256-calldata-collectiontokenids" id="deboost-uint256-tokenid_-uint256-calldata-collectiontokenids"></a>

```solidity
function deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_) external nonReentrant
```

**Description:**\
Removes booster NFTs from a lock. Verifies that the token hasn't voted in the current epoch. Records the block timestamp in `s_lastDeboostTimestampByTokenId` to freeze transfers for a defined period.

***

#### `withdraw(uint256 tokenId_)` <a href="#withdraw-uint256-tokenid" id="withdraw-uint256-tokenid"></a>

```solidity
function withdraw(uint256 tokenId_) external nonReentrant
```

**Description:**\
Withdraws the tokens from an expired lock, returning booster NFTs, transferring vesting wallets, and burning the lock NFT. The caller must be authorized.

**Events:**

* Emits `LockWithdrawn(recipient, tokenId, value)` upon completion.

***

#### `extend(uint256 tokenId_, uint256 lockDuration_)` <a href="#extend-uint256-tokenid_-uint256-lockduration" id="extend-uint256-tokenid_-uint256-lockduration"></a>

```solidity
function extend(uint256 tokenId_, uint256 lockDuration_) external nonReentrant
```

**Description:**\
Extends the lock duration to a new `unlockTime`. Must be strictly greater than the current one. Updates voting power.

***

#### `setVoteStatus(uint256 tokenId_, bool status_)` <a href="#setvotestatus-uint256-tokenid_-bool-status" id="setvotestatus-uint256-tokenid_-bool-status"></a>

```solidity
function setVoteStatus(uint256 tokenId_, bool status_) external
```

**Description:**\
Only callable by `ESCROW_VOTE_MANAGER`. Marks a token as having voted or not.

***

#### `registerTokenVote(uint256 tokenId_, bool status_)` <a href="#registertokenvote-uint256-tokenid_-bool-status" id="registertokenvote-uint256-tokenid_-bool-status"></a>

```solidity
function registerTokenVote(uint256 tokenId_, bool status_) external
```

**Description:**\
Only callable by `ESCROW_VOTE_MANAGER`. Records that a token has voted (or not) in the current epoch.

***

#### `moveVotes(uint256 tokenId_, address from_, address to_)` <a href="#movevotes-uint256-tokenid_-address-from_-address-to" id="movevotes-uint256-tokenid_-address-from_-address-to"></a>

```solidity
function moveVotes(uint256 tokenId_, address from_, address to_) external
```

**Description:**\
Called by `DELEGATION_MANAGER` to transfer voting power if delegated. Ensures the token exists.

***

#### `getLockInfoByTokenId(uint256 tokenId_)` <a href="#getlockinfobytokenid-uint256-tokenid" id="getlockinfobytokenid-uint256-tokenid"></a>

```solidity
function getLockInfoByTokenId(uint256 tokenId_) 
    external 
    view 
    returns (
        int128 lockAmount_,
        uint256 unlockTime_,
        address[] memory vestingWallets_
    )
```

**Description:**\
Returns the lock’s current amount, unlock timestamp, and associated vesting wallets.

***

#### `getRemainingFreezeTimeByTokenId(uint256 tokenId_)` <a href="#getremainingfreezetimebytokenid-uint256-tokenid" id="getremainingfreezetimebytokenid-uint256-tokenid"></a>

```solidity
function getRemainingFreezeTimeByTokenId(uint256 tokenId_) external view returns (uint256)
```

**Description:**\
Reports how many seconds remain until a token can be transferred again after deboost. Returns 0 if the freeze period has elapsed.

***

#### `getCheckpoint(address account_, uint32 index_)` <a href="#getcheckpoint-address-account_-uint32-index" id="getcheckpoint-address-account_-uint32-index"></a>

```solidity
function getCheckpoint(address account_, uint32 index_) external view returns (Checkpoint memory)
```

**Description:**\
Retrieves the checkpoint at `index_` for `account_`, listing token ownership at that historical checkpoint.

***

#### `getPastVotes(address account_, uint256 timestamp_)` <a href="#getpastvotes-address-account_-uint256-timestamp" id="getpastvotes-address-account_-uint256-timestamp"></a>

```solidity
function getPastVotes(address account_, uint256 timestamp_) external view returns (uint256 votes_)
```

**Description:**\
Calculates an account’s total voting power at a previous `timestamp_`, summing the power of all tokens they held at that time.

***

#### `getTotalSupply()` <a href="#gettotalsupply" id="gettotalsupply"></a>

```solidity
function getTotalSupply() external view returns (uint256)
```

**Description:**\
Returns the total voting power across all locks at the current time.

***

#### `getPastTotalSupply(uint256 timestamp_)` <a href="#getpasttotalsupply-uint256-timestamp" id="getpasttotalsupply-uint256-timestamp"></a>

```solidity
function getPastTotalSupply(uint256 timestamp_) external view returns (uint256)
```

**Description:**\
Returns the total voting power at a specific `timestamp_`. Uses the `VotingPowerHelper` for historical calculations.

***

#### `getPastVotesByTokenId(uint256 tokenId_, uint256 timestamp_)` <a href="#getpastvotesbytokenid-uint256-tokenid_-uint256-timestamp" id="getpastvotesbytokenid-uint256-tokenid_-uint256-timestamp"></a>

```solidity
function getPastVotesByTokenId(uint256 tokenId_, uint256 timestamp_) external view returns (uint256)
```

**Description:**\
Computes a single token’s voting power at a past `timestamp_`, factoring in rate-of-change data.

***

#### `getBoostersByTokenId(uint256 tokenId_)` <a href="#getboostersbytokenid-uint256-tokenid" id="getboostersbytokenid-uint256-tokenid"></a>

```solidity
function getBoostersByTokenId(uint256 tokenId_) external view returns (uint256[] memory boosters_)
```

**Description:**\
Lists all booster NFT IDs currently enhancing the lock identified by `tokenId_`.

***

#### `checkAuthorized(address owner_, address spender_, uint256 tokenId_)` <a href="#checkauthorized-address-owner_-address-spender_-uint256-tokenid" id="checkauthorized-address-owner_-address-spender_-uint256-tokenid"></a>

```solidity
function checkAuthorized(address owner_, address spender_, uint256 tokenId_) external view returns (bool)
```

**Description:**\
Checks if `spender_` is permitted (owner, approved address, or operator) to manage the NFT for `tokenId_`.

***

#### `exists(uint256 tokenId_)` <a href="#exists-uint256-tokenid" id="exists-uint256-tokenid"></a>

```solidity
function exists(uint256 tokenId_) external view returns (bool)
```

**Description:**\
Returns true if an NFT for `tokenId_` has been minted (i.e., the lock exists).

***

### Internal and Private Functions <a href="#internal-and-private-functions" id="internal-and-private-functions"></a>

#### `_createLock(...)` <a href="#createlock" id="createlock"></a>

**Signature:**

```solidity
function _createLock(
    uint256 lockAmount_,
    uint256 lockDuration_,
    address recipient_,
    address[] memory vestingWallets_,
    LockModificationType lockModificationType_
) private
```

**Description:**\
Core logic for creating a new lock. Mints an NFT, stores lock info, and transfers tokens or vesting wallets if needed.

***

#### `_deposit(...)` <a href="#deposit" id="deposit"></a>

**Signature:**

```solidity
function _deposit(uint256 tokenId_, uint256 lockAmount_) private
```

**Description:**\
Adds more EYWA to a lock, updating voting power calculations.

***

#### `_modifyBoost(...)` <a href="#modifyboost" id="modifyboost"></a>

**Signature:**

```solidity
function _modifyBoost(
    uint256 tokenId_, 
    uint256[] memory collectionTokenIds_, 
    LockModificationType lockModificationType_
) private
```

**Description:**\
Adds or removes booster NFTs to/from a lock. Adjusts coverage and recalculates voting power accordingly.

***

#### `_updateLock(...)` <a href="#updatelock" id="updatelock"></a>

**Signature:**

```solidity
function _updateLock(
    uint256 tokenId_,
    LockInfo memory previousLockInfo_,
    LockInfo memory currentLockInfo_
) private
```

**Description:**\
Recomputes and stores new voting power points whenever a lock’s amount or unlock time changes. Adjusts historical checkpoints and the global epoch.

***

#### `_moveVotes(...)` <a href="#movevotes" id="movevotes"></a>

**Signature:**

```solidity
function _moveVotes(uint256 tokenId_, address from_, address to_) private
```

**Description:**\
Reassigns voting power from `from_` to `to_` if the NFT’s ownership changes. Creates or updates checkpoints for both addresses.

***

#### `_clearStorage(...)` <a href="#clearstorage" id="clearstorage"></a>

**Signature:**

```solidity
function _clearStorage(uint256 tokenId_) private
```

**Description:**\
Clears all references and data for a withdrawn or burned lock, freeing storage.

***

#### `_findCheckpoint(...)` <a href="#findcheckpoint" id="findcheckpoint"></a>

**Signature:**

```solidity
function _findCheckpoint(address account_) private view returns (uint32)
```

**Description:**\
Helper to find or create the index for a checkpoint at the current timestamp for a given account.

***

#### `_calculateModifiedLockAmount(...)` <a href="#calculatemodifiedlockamount" id="calculatemodifiedlockamount"></a>

**Signature:**

```solidity
function _calculateModifiedLockAmount(
    uint256 tokenId_,
    uint256 coverage_,
    uint256 lockAmount_
) private view returns (uint256)
```

**Description:**\
Calculates the final lock amount after factoring in booster NFT coverage and rarity-based multipliers. If coverage exceeds lock amount, the algorithm partial-applies boosters in descending rarity.

***

### Events <a href="#events" id="events"></a>

#### `LockWithdrawn(address indexed recipient, uint256 indexed tokenId, uint256 indexed value)` <a href="#lockwithdrawn-address-indexed-recipient-uint256-indexed-tokenid-uint256-indexed-value" id="lockwithdrawn-address-indexed-recipient-uint256-indexed-tokenid-uint256-indexed-value"></a>

**Emitted When:**\
A user withdraws tokens from an expired lock. The NFT is burned, and booster NFTs/vesting wallets are returned.

***

### Errors <a href="#errors" id="errors"></a>

* **`InvalidBeneficiary()`**
* **`InvalidVestingWallet()`**
* **`InvalidLockDuration()`**
* **`InvalidLockAmount()`**
* **`InvalidCollectionTokenId(uint256 tokenId)`**
* **`InvalidArrayLength()`**
* **`InvalidRarity()`**
* **`NonExistentToken()`**
* **`ExtendedUnlockTimeMustBeGreater()`**
* **`AttachmentsLimitExceeded()`**
* **`LockStillActive()`**
* **`LockCurrentlyVoting()`**
* **`MaximumNumberOfDelegatesExceeded()`**
* **`BoostModificationAfterVoting()`**
* **`UnauthorizedCaller()`**
* **`TransferFrozenDueToDeboost()`**

These errors ensure that contract rules regarding lock durations, amounts, boosters, freeze periods, and ownership checks are strictly enforced.

***

### Summary <a href="#summary" id="summary"></a>

**EscrowManager** provides a robust system for locking EYWA tokens in exchange for NFT-based positions (veEYWA). Each lock can combine direct token transfers, vesting wallets, and booster NFTs, forming dynamic voting power that evolves over time. Freeze periods after deboosts and careful checkpointing logic protect against immediate manipulations of lock amounts and ownership. Through a clear interface defined in `IEscrowManager`, external ecosystem components (e.g., delegation managers, vote managers, NFT collections) can seamlessly integrate with this locking mechanism to support governance, incentive distribution, and user engagement within the CrossCurve platform.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.crosscurve.fi/developer-documentation/guide-for-developers/technical-documentation-for-crosscurve-dao-smart-contracts/escrowmanager.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
