EscrowManager

Overview

EscrowManager is a comprehensive smart contract that manages locked EYWA tokens represented as ERC-721 NFTs (veEYWA tokens). Each lock corresponds to a unique NFT and includes various attributes such as lock amount, lock duration, associated vesting wallets, and optional booster NFTs. The contract integrates with other EYWA ecosystem componentsβ€”like the escrow vote manager and delegation managerβ€”to align token locking with governance, voting, and incentives.

Key Features:

  • Lock Creation & Modification: Users can create locks from direct tokens, vesting wallets, or collection tokens, deposit additional tokens, extend locks, and add boosters.

  • Withdrawals & Burning: On lock expiration, owners can withdraw their tokens and burn the NFT, returning any booster NFTs and releasing vesting wallets.

  • Voting Power Tracking: Maintains detailed checkpointing and voting power calculations over epochs, enabling historical queries of voting power.

  • Access Control & Authorization: Ensures only authorized parties (owner, approved operator, or required managers) can modify locks or move votes.


Inherited Contracts and Interfaces

  • ERC721Enumerable, ERC721 (OpenZeppelin): Provides standard NFT functionality and enumerable token lists.

  • ERC721Holder (OpenZeppelin): Allows the contract to hold ERC-721 tokens safely.

  • ReentrancyGuard (OpenZeppelin): Protects against re-entrancy attacks on sensitive functions.

  • SafeERC20, IERC20 (OpenZeppelin): Safe wrappers for ERC20 token operations.

  • EnumerableSet (OpenZeppelin): Used for managing sets of booster token IDs efficiently.

External Interfaces:

  • IEscrowManager: Interface implemented by this contract.

  • IEscrowVoteManagerV1: Manages epochs and voting logic.

  • ICollection, IWalletFactory, IVestingWallet: Provides NFT collections, wallet factories, and vesting wallets functionality.

  • IMetadataProviderV1: Supplies metadata URIs for the NFTs.

  • VotingPowerHelper (Library): Assists in calculating historical voting power and supply.


Constants

  • ATTACHMENTS_LIMIT = 100

  • EPOCH_DURATION = 1 weeks

  • MAXIMUM_LOCK_DURATION = 156 weeks

  • MAXIMUM_NUMBER_OF_DELEGATES = 1024

  • SIGNED_MAXIMUM_LOCK_DURATION = 156 weeks

Rarity Multipliers and Capacities: Defined for Common, Uncommon, Rare, Legendary, Infinity rarities, controlling lock modifications via boosters.

  • PRECISION = 100_000

Immutable Addresses:

  • ESCROW_VOTE_MANAGER

  • DELEGATION_MANAGER

  • EYWA

  • COLLECTION

  • WALLET_FACTORY

  • METADATA_PROVIDER

Set via constructor and cannot be changed after deployment.


State Variables

  • s_nextTokenId (uint256): Next NFT ID to be minted for new locks.

  • s_epoch (uint256): Current epoch count in the contract.

  • s_totalLocked (uint256): Total EYWA tokens locked across all locks.

Lock Data and Voting Power:

  • _s_lockInfoByTokenId (mapping(uint256 => LockInfo)): Stores lock info.

  • s_pureLockAmountByTokenId (mapping(uint256 => uint256)): Base locked amount per token.

  • s_vestingWalletsLockAmountByTokenId (mapping(uint256 => uint256)): Lock amount from vesting wallets.

  • s_currentCoverageByTokenId (mapping(uint256 => uint256)): Booster coverage.

  • s_epochByTokenId (mapping(uint256 => uint256)): Epoch associated with each token’s last modification.

  • s_lastOwnerByTokenId (mapping(uint256 => address)): Last known owner of each NFT.

  • s_rateOfChangeByUnlockTime (mapping(uint256 => int128)): Rate of change in voting power tied to unlock times.

  • s_hasVotedByTokenId (mapping(uint256 => bool)): Whether a token voted in the current epoch.

  • s_hasVotedByEpochAndTokenId (mapping(uint256 => mapping(uint256 => bool))): Token’s voting status per epoch.

Checkpoints:

  • s_checkpointsNumberByAccount (mapping(address => uint32)): Number of checkpoints per account.

  • s_checkpoints (mapping(address => mapping(uint32 => Checkpoint))): Checkpoints of owned tokens per account.

  • s_ownershipChangeBlockNumberByTokenId (mapping(uint256 => uint256)): Block number of last ownership change.

  • s_votingPowerPointByEpoch (mapping(uint256 => VotingPowerPoint)): Voting power data per epoch.

  • s_votingPowerPointByTokenIdAndEpoch (mapping(uint256 => VotingPowerPoint[1000000000])): Voting power points per token ID and epoch.

Boosters:

  • _s_boostersByTokenId (mapping(uint256 => EnumerableSet.UintSet)): Booster NFTs for each lock.

  • _s_boostersByTokenIdAndRarity (mapping(uint256 => mapping(ICollection.Rarity => EnumerableSet.UintSet))): Booster NFTs categorized by rarity.


Constructor

Signature:

constructor(
    address escrowVoteManager_,
    address delegationManager_,
    IERC20 eywa_,
    ICollection collection_,
    IWalletFactory walletFactory_,
    IMetadataProviderV1 metadataProvider_
) ERC721("veEYWA", "veEYWA")

Description: Sets up references to key ecosystem contracts (escrow vote manager, delegation manager, EYWA token, collection, wallet factory, metadata provider) and initializes the NFT with name β€œveEYWA” and symbol β€œveEYWA”.


External Functions (Defined by IEscrowManager)

createLock(uint256 lockAmount_, uint256 lockDuration_, address recipient_)

Signature:

function createLock(uint256 lockAmount_, uint256 lockDuration_, address recipient_) external

Description: Creates a new lock by transferring lockAmount_ EYWA tokens from the caller and minting an NFT to recipient_.

Effects:

  • Validates lockDuration_ and lockAmount_.

  • Transfers EYWA tokens.

  • Calls _createLock with LockModificationType.CREATION.


createLock(uint256 lockDuration_, address recipient_, address[] calldata vestingWallets_)

Signature:

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

Description: Creates a lock from multiple vesting wallets owned by the caller. Transfers their EYWA balances to this contract.

Effects:

  • Checks valid vesting wallets.

  • Accumulates tokens from vesting wallets.

  • Calls _createLock with LockModificationType.CREATION2.


createLock(uint256 lockDuration_, address recipient_, uint256[] calldata collectionTokenIds_)

Signature:

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

Description: Creates a lock using tokens associated with given collection token IDs and applies booster NFTs.

Effects:

  • Accumulates lock amount from collection tokens.

  • Collects and unpins vesting wallets.

  • Calls _createLock with LockModificationType.CREATION2.

  • Calls _modifyBoost with LockModificationType.BOOST.


deposit(uint256 tokenId_, uint256 lockAmount_)

Signature:

function deposit(uint256 tokenId_, uint256 lockAmount_) external

Description: Deposits additional EYWA tokens into an existing lock. Caller must be authorized.

Effects:

  • Transfers EYWA from caller.

  • Updates lock amount and calls _updateLock.


depositFor(uint256 tokenId_, uint256 lockAmount_)

Signature:

function depositFor(uint256 tokenId_, uint256 lockAmount_) external

Description: Deposits EYWA tokens into an existing lock without authorization checks (on behalf of the lock owner).

Effects:

  • Similar to deposit, updates lock and voting power.


boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)

Signature:

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

Description: Adds booster NFTs to the specified lock. Caller must be authorized. Boosters increase coverage and potentially the lock’s voting power.

Effects:

  • Transfers booster NFTs to contract.

  • Recalculates lock amount and updates voting power.


deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)

Signature:

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

Description: Removes previously added booster NFTs from the lock. Cannot be done if the token has voted in the current epoch.

Effects:

  • Transfers booster NFTs back to caller.

  • Updates coverage and lock amount.

  • Calls _updateLock.


withdraw(uint256 tokenId_)

Signature:

function withdraw(uint256 tokenId_) external

Description: Withdraws tokens from an expired lock and burns the NFT. Returns booster NFTs and vesting wallets to the owner or associated beneficiary.

Effects:

  • Checks if lock is expired.

  • Burns NFT, updates totals.

  • Calls _clearStorage.

  • Emits LockWithdrawn.


extend(uint256 tokenId_, uint256 lockDuration_)

Signature:

function extend(uint256 tokenId_, uint256 lockDuration_) external

Description: Extends the lock duration. Caller must be authorized. New unlock time must be greater than the current one.

Effects:

  • Updates unlock time.

  • Recalculates voting power with _updateLock.


setVoteStatus(uint256 tokenId_, bool status_)

Signature:

function setVoteStatus(uint256 tokenId_, bool status_) external

Description: Can only be called by ESCROW_VOTE_MANAGER. Sets whether a token has voted this epoch.


registerTokenVote(uint256 tokenId_)

Signature:

function registerTokenVote(uint256 tokenId_) external

Description: Marks a token as having voted in the current epoch. Only callable by ESCROW_VOTE_MANAGER.


moveVotes(uint256 tokenId_, address from_, address to_)

Signature:

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

Description: Called by DELEGATION_MANAGER to move voting power due to delegation changes.


getLockInfoByTokenId(uint256 tokenId_)

Signature:

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

Description: Returns lock details (amount, unlock time, vesting wallets) for the specified lock ID.


getCheckpoint(address account_, uint32 index_)

Signature:

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

Description: Returns a specific checkpoint for an account.


getPastVotes(address account_, uint256 timestamp_)

Signature:

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

Description: Calculates the voting power of an account at a past timestamp by summing the voting power of all tokens owned at the checkpoint closest to timestamp_.


getTotalSupply()

Signature:

function getTotalSupply() external view returns (uint256)

Description: Returns current total voting power at the current timestamp.


getPastTotalSupply(uint256 timestamp_)

Signature:

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

Description: Returns total voting power at a given past timestamp.


getVotesByTokenId(uint256 tokenId_)

Signature:

function getVotesByTokenId(uint256 tokenId_) external view returns (uint256)

Description: Returns current voting power for a specific token ID, unless ownership changed in the current block (then returns 0).


getPastVotesByTokenId(uint256 tokenId_, uint256 timestamp_)

Signature:

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

Description: Returns the voting power of a token ID at a specific past timestamp.


getBoostersByTokenId(uint256 tokenId_)

Signature:

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

Description: Returns all booster NFT IDs associated with a given lock NFT.


checkAuthorized(address owner_, address spender_, uint256 tokenId_)

Signature:

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

Description: Checks if spender_ is authorized to manage the lock represented by tokenId_.


exists(uint256 tokenId_)

Signature:

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

Description: Returns true if an NFT with the given tokenId_ exists.


Internal and Private Functions

_createLock(…), _deposit(…), _modifyBoost(…), _updateLock(…), _moveVotes(…), _clearStorage(…), _findCheckpoint(…), _calculateModifiedLockAmount(…):

These internal functions encapsulate the core logic of lock creation, updates, voting power recalculations, storage cleanup, and booster effects. They are called by the public functions after performing checks and transfers.


Events

LockWithdrawn

Emitted When: A lock is withdrawn and the NFT is burned.

Parameters:

  • recipient: The address receiving withdrawn tokens.

  • tokenId: The ID of the burned NFT.

  • value: The amount of tokens withdrawn.


Errors

  • InvalidBeneficiary()

  • InvalidVestingWallet()

  • InvalidLockDuration()

  • InvalidLockAmount()

  • InvalidCollectionTokenId(uint256 tokenId)

  • InvalidArrayLength()

  • InvalidRarity()

  • NonExistentToken()

  • ExtendedUnlockTimeMustBeGreater()

  • AttachmentsLimitExceeded()

  • LockStillActive()

  • LockCurrentlyVoting()

  • MaximumNumberOfDelegatesExceeded()

  • BoostModificationAfterVoting()

  • UnauthorizedCaller()

These errors ensure that contract invariants are upheld and that actions are only performed by authorized entities or under valid conditions.


Summary

EscrowManager orchestrates the lifecycle of locked EYWA token positions, represented as NFTs with robust features such as vesting wallets, booster NFTs, and dynamic voting power. By integrating with multiple ecosystem components (voting, delegation, collections, and vesting), it provides a flexible, secure, and transparent mechanism for token locking and governance participation. Its extensive logging and historical data (checkpoints, voting power points) create a foundation for complex governance and incentive models.

Last updated