LogoLogo
  • CrossCurve MetaLayer
    • ⚙️What is CrossCurve MetaLayer
      • CrossCurve Consensus bridge
      • CrossCurve Pools v2
    • 🗺️Roadmap
      • 2024
  • 🏢CrossCurve DAO
    • Overview of CrossCurve DAO
    • Voting
    • Obtaining veEYWA and Calculating the Boost
    • Staking mechanics
    • NFTs
      • CrossCurve DAO NFT
      • EYWA NFT Collection
  • 💼Earn with CrossCurve
    • Staking in CrossCurve
    • Providing Liquidity to CrossCurve Pools
    • Voting for Incentives
  • 📖user documentation
    • 🛸Migration to Sonic
      • Why are we moving to Sonic
      • Sonic Upgrade Stages
      • Liquidity transfer from Fantom to Sonic
      • Sonic Incentives on CrossCurve MetaLayer
    • 🔃Swap interface
      • How to trade
      • Slippage settings
      • Routing
    • 🌊Liquidity Interface
      • Easy mode
      • via Curve (Balanced)
      • Liquidity provision use cases
        • Deposit
          • Easy mode (Imbalanced)
          • via Curve (Balanced)
        • Withdraw
          • Easy mode (Imbalanced)
          • via Curve (Balanced)
        • Curve Knowledge Database
          • Balanced liquidity provision
          • Guide to transferring CRV from Fantom chain to Ethereum mainnet
          • Disclamer
    • 🏢DAO
      • Locker Interface
      • Vote Interface
      • Incentives Interface
      • Working with the EYWA Locker contract in Arbiscan.
    • 🌾Yield
      • Farms Interface
        • Staking liquidity and earning rewards
      • APR Calculator
      • EYWA pool via Convex
    • 💼Vesting
      • Claim portal interface
      • Early farming program interface
    • EYWA NFT
      • Bridge interface in the Aurora chain
      • Merge interface in the Arbitrum chain
      • EYWA NFT Manager interface
      • Dashboard interface
    • Leaderboard
    • ❄️Outdated
      • Early farming program
  • 📖Developer documentation
    • Pools/asset contracts
      • Hubchain Pools and Assets
      • 💱Supported tokens
    • 🔗CrossCurve smart contracts
    • 💻Guide for Developers
      • Technical Documentation for CrossCurve DAO Smart Contracts
        • CalldataHelperV1
        • DelegationManagerV1
        • DelegationConditionValidatorV1
        • EmissionManagerV1
        • EscrowManager
        • EscrowVoteManagerV1
        • GaugeFactoryV1
        • GaugeV1
        • IncentiveRewardsDistributor
        • LockHolderFactoryV1
        • LockHolderV1
        • ProposalManager
        • RebaseRewardsDistributorV1
        • RewardsDistributorFactoryV1
        • Treasury
      • 🔃Make cross-chain swap
      • 🔦Tracking cross-chain swap
      • 📔Pusher API Reference
      • 📝Glossary
      • API Specification
  • 📣About CrossCurve
    • 🛡️Security audits
    • 🧠Team
    • Project History
    • Website
    • Telegram
    • Twitter
    • Medium
    • Discord
    • YouTube
    • LinkedIn
    • GitHub
Powered by GitBook
On this page
  • Overview
  • Inherited Contracts and Interfaces
  • Constants
  • State Variables
  • Constructor
  • External Functions (Defined by IEscrowManager)
  • Internal and Private Functions
  • Events
  • Errors
  • Summary
Export as PDF
  1. Developer documentation
  2. Guide for Developers
  3. Technical Documentation for CrossCurve DAO Smart Contracts

EscrowManager

Overview

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

  • 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

  • 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

  • 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

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)

createLock(uint256 lockAmount_, uint256 lockDuration_, address recipient_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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_)

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()

function getTotalSupply() external view returns (uint256)

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


getPastTotalSupply(uint256 timestamp_)

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_)

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_)

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_)

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_)

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

_createLock(...)

Signature:

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(...)

Signature:

function _deposit(uint256 tokenId_, uint256 lockAmount_) private

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


_modifyBoost(...)

Signature:

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(...)

Signature:

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(...)

Signature:

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(...)

Signature:

function _clearStorage(uint256 tokenId_) private

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


_findCheckpoint(...)

Signature:

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(...)

Signature:

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

LockWithdrawn(address indexed recipient, uint256 indexed tokenId, uint256 indexed value)

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


Errors

  • 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

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.

PreviousEmissionManagerV1NextEscrowVoteManagerV1

Last updated 1 month ago

📖
💻