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:
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_)
createLock(uint256 lockAmount_, uint256 lockDuration_, address recipient_)
Signature:
Description:
Creates a new lock by transferring lockAmount_
EYWA tokens from the caller and minting an NFT to recipient_
.
Effects:
Validates
lockDuration_
andlockAmount_
.Transfers EYWA tokens.
Calls
_createLock
withLockModificationType.CREATION
.
createLock(uint256 lockDuration_, address recipient_, address[] calldata vestingWallets_)
createLock(uint256 lockDuration_, address recipient_, address[] calldata vestingWallets_)
Signature:
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
withLockModificationType.CREATION2
.
createLock(uint256 lockDuration_, address recipient_, uint256[] calldata collectionTokenIds_)
createLock(uint256 lockDuration_, address recipient_, uint256[] calldata collectionTokenIds_)
Signature:
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
withLockModificationType.CREATION2
.Calls
_modifyBoost
withLockModificationType.BOOST
.
deposit(uint256 tokenId_, uint256 lockAmount_)
deposit(uint256 tokenId_, uint256 lockAmount_)
Signature:
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_)
depositFor(uint256 tokenId_, uint256 lockAmount_)
Signature:
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_)
boost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)
Signature:
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_)
deboost(uint256 tokenId_, uint256[] calldata collectionTokenIds_)
Signature:
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_)
withdraw(uint256 tokenId_)
Signature:
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_)
extend(uint256 tokenId_, uint256 lockDuration_)
Signature:
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_)
setVoteStatus(uint256 tokenId_, bool status_)
Signature:
Description:
Can only be called by ESCROW_VOTE_MANAGER
. Sets whether a token has voted this epoch.
registerTokenVote(uint256 tokenId_)
registerTokenVote(uint256 tokenId_)
Signature:
Description:
Marks a token as having voted in the current epoch. Only callable by ESCROW_VOTE_MANAGER
.
moveVotes(uint256 tokenId_, address from_, address to_)
moveVotes(uint256 tokenId_, address from_, address to_)
Signature:
Description:
Called by DELEGATION_MANAGER
to move voting power due to delegation changes.
getLockInfoByTokenId(uint256 tokenId_)
getLockInfoByTokenId(uint256 tokenId_)
Signature:
Description: Returns lock details (amount, unlock time, vesting wallets) for the specified lock ID.
getCheckpoint(address account_, uint32 index_)
getCheckpoint(address account_, uint32 index_)
Signature:
Description: Returns a specific checkpoint for an account.
getPastVotes(address account_, uint256 timestamp_)
getPastVotes(address account_, uint256 timestamp_)
Signature:
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()
getTotalSupply()
Signature:
Description: Returns current total voting power at the current timestamp.
getPastTotalSupply(uint256 timestamp_)
getPastTotalSupply(uint256 timestamp_)
Signature:
Description: Returns total voting power at a given past timestamp.
getVotesByTokenId(uint256 tokenId_)
getVotesByTokenId(uint256 tokenId_)
Signature:
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_)
getPastVotesByTokenId(uint256 tokenId_, uint256 timestamp_)
Signature:
Description: Returns the voting power of a token ID at a specific past timestamp.
getBoostersByTokenId(uint256 tokenId_)
getBoostersByTokenId(uint256 tokenId_)
Signature:
Description: Returns all booster NFT IDs associated with a given lock NFT.
checkAuthorized(address owner_, address spender_, uint256 tokenId_)
checkAuthorized(address owner_, address spender_, uint256 tokenId_)
Signature:
Description:
Checks if spender_
is authorized to manage the lock represented by tokenId_
.
exists(uint256 tokenId_)
exists(uint256 tokenId_)
Signature:
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
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