# DelegationManagerV1

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

**DelegationManagerV1** This is an upgradeable contract that allows you to delegate your locks to another account. This contract is integrated with **EmissionManager**, **EscrowManager**, **EscrowVoteManager**, **LockHolderFactory**, **RebaseRewardsDistributor**, **DelegationConditionValidator**. It allows the lock owner to delegate or automate actions such as voting and collecting rebase rewards and incentive rewards.

**Key Roles and Features:**

1. **Access Control:** Restricts **setAssuranceLockParameters** and **setMinLockVeEywa** calls to the **owner** of contract(`owner()`).
2. **Upgradeable via UUPS:** Uses **UUPSUpgradeable** and **OwnableUpgradeable** patterns, restricting contract upgrades to the owner.

***

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

* **UUPSUpgradeable (OpenZeppelin):**\
  Provides upgrade functionality under the UUPS proxy pattern, restricted to the contract owner.
* **OwnableUpgradeable (OpenZeppelin):**\
  Manages ownership, allowing only the owner to modify critical parameters and authorize upgrades.
* **IDelegationManagerV1:**\
  Defines core methods (e.g., `setDelegationParameters`, `delegate`, `vote`) and events for this contract.

**Additional External References:**

* **SafeERC20, IERC20 (OpenZeppelin):** Handles secure ERC20 operations for distributing and approving token transfers.
* **IRebaseRewardsDistributorV2:** Distributes rebase rewards and triggers relevant accounting updates.
* **IDelegationConditionValidatorV1:** Logic to test additional conditions for delegation
* **ILockHolderFactoryV1:** Deployment of new LockHolder contracts
* **IEscrowManagerExtended:** Holds locked token data and checks voting power and freeze logic.
* **IEscrowVoteManagerV1:** Receives gauge emission amounts and coordinates gauge reward distribution.
* **IEmissionManagerV1:** Informs about epoch starts and ensures updated weekly distributions.
* **ILockHolderV1:** Logic for proxied calls to **EscrowManager**, **EscrowVoteManager** and **IncentiveRewardsDistributor** contract functions
* **ICollection:** Components in the ecosystem for NFT.

***

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

```solidity
uint256 private constant EPOCH_DURATION = 1 weeks;
uint256 private constant PRECISION = 100_000;
```

* **EPOCH\_DURATION**: Duration of each emission/gauge epoch (1 week).
* **PRECISION**: The divisior for percentage math.

***

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

* **`s_eywa (IERC20)`**\
  ERC20 token interface for the EYWA token.
* **`s_collection (ICollection)`**\
  ICollection Interface for the NFT collection contract.
* **`s_emissionManager (IEmissionManagerV1)`**\
  IEmissionManagerV1 interface for the EmissionManagerV1 contract.
* **`s_escrowManager (IEscrowManagerExtended)`**\
  IEscrowManager interface for the EscrowManager contract.
* **`s_escrowVoteManager (IEscrowVoteManagerV1)`**\
  IEscrowVoteManagerV1 interface for the EscrowVoteManager contract.
* **`s_lockHolderFactory (ILockHolderFactoryV1)`**\
  ILockHolderFactoryV1 interface for the LockHolderFactoryV1 contract.
* **`s_rebaseRewardsDistributor (IRebaseRewardsDistributorV2)`**\
  IRebaseRewardsDistributorV2 interface for the RebaseRewardsDistributorV2 contract.
* **`s_delegationConditionValidator (IDelegationConditionValidatorV1)`**\
  IDelegationConditionValidatorV1 interface for the DelegationConditionValidator contract.
* **`s_minLockEywa (uint256)`**\
  The min EYWA amount in delegatee's lock.
* **`s_minLockVeEywa (uint256)`**\
  The min veEYWA amount in delegatee's lock.
* **`s_minLockDuration (uint256)`**\
  The min duration for delegatee's lock in seconds.
* **`s_delegaties (address[])`**\
  Array with addresses of all delegates.
* **`s_depositedByDelegatee (mapping(address => uint256))`**\
  Mapping from delegatee to its EYWA deposit information.
* **`s_feeByDelegator (mapping(address => uint256))`**\
  Mapping from delegator to its EYWA fee information.
* **`s_autoVoteByDelegatee (mapping(address => bool))`**\
  Mapping from delegatee to its permission for automatic execution of the autoVote() function.
* **`s_delegationParametersByDelegatee (mapping(address => DelegationParameters))`**\
  Mapping from delegatee to its delegation parameters.
* **`s_delegationInfoByTokenId (mapping(address => DelegationInfo))`**\
  Mapping from token ID to its delegation information.
* **`s_lastClaimedIncentiveTimeByLockHolder (mapping(address => uint256))`**\
  Mapping from LockHolder contract address to its last time claimed incentive.
* **`s_lastClaimedCommissionTimeByLockHolder (mapping(address => uint256))`**\
  Mapping from LockHolder contract address to its last time claimed commission.
* **`s_lockHolders (mapping(address => mapping(address => address)))`**\
  Nested mapping from delegator and delegatee to their LockHolder contract address.
* **`_s_locksByDelegator (mapping(address => uint256))`**\
  Mapping from delegator to its amount of delegated locks.
* **`_s_locksByDelegatee (mapping(address => uint256))`**\
  Mapping from delegatee to its amount of delegated locks.
* **`_s_delegationVoteParametersByDelegatee (mapping(address => DelegationVoteParameters))`**\
  Mapping from delegatee to its delegation vote parameters.
* **`_s_delegationIndexesInfoByTokenId (mapping(address => DelegationIndexesInfo))`**\
  Mapping from token ID to its delegation indexes info.
* **`_s_lockIdByDelegatorAndIndex (address => mapping(uint256 => uint256))`**\
  Nested mapping from delegator and index to its delegated lock ID.
* **`_s_lockIdByDelegateeAndIndex (address => mapping(uint256 => uint256))`**\
  Nested mapping from delegatee and index to its delegated lock ID.
* **`_s_feeByDelegateeAndEpoch (mapping(address => mapping(uint256 => uint256)))`**\
  Nested mapping of delegatee address and an epoch start to a fee.

***

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

```solidity
constructor() {
    _disableInitializers();
}
```

* **Description:**\
  Disables contract initializers to prevent re-initialization in a UUPS proxy context.

***

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

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

```solidity
function initialize(
    address owner_,
    IERC20 eywa_,
    ICollection collection_,
    IEmissionManagerV1 emissionManager_,
    IEscrowManagerExtended escrowManager_,
    IEscrowVoteManagerV1 escrowVoteManager_,
    ILockHolderFactoryV1 lockHolderFactory_,
    IRebaseRewardsDistributorV2 rebaseRewardsDistributor_,
    IDelegationConditionValidatorV1 delegationConditionValidator_
) external initializer;
```

**Description:**\
Configures ownership, references, and initial state:

* Sets `s_minLockEywa` to 500 000 \* 1e18 initially.
* Sets `s_minLockVeEywa` to 1 000 \* 1e18 initially.
* Sets `s_minLockDuration` to 52 weeks initially.
* References the EYWA token, EYWA NFT, escrow manager, escrow vote manager, emission manager, lockHolder factory, rebase rewards distributor, delegation condition validator.

**Parameters:**

* `owner_`: The address of the contract owner.
* `eywa_`: ERC20 token interface for the EYWA token.
* `collection_`: ICollection Interface for the NFT collection contract.
* `emissionManager_`: IEmissionManagerV1 interface for the EmissionManagerV1 contract.
* `escrowManager_`: The IEscrowManagerExtended interface for the EscrowManager contract.
* `escrowVoteManager_`: The IEscrowVoteManagerV1 interface for the EscrowVoteManager contract.
* `lockHolderFactory_`: ILockHolderFactoryV1 interface for the LockHolderFactoryV1 contract.
* `rebaseRewardsDistributor_`: IRebaseRewardsDistributorV2 interface for the RebaseRewardsDistributorV2 contract.
* `delegationConditionValidator_`: IDelegationConditionValidatorV1 interface for the DelegationConditionValidator contract.

***

#### `setAssuranceLockParameters(uint256 minLockEywa_, uint256 minLockDuration_)` <a href="#setassurancelockparameters-uint256-minlockeywa_-uint256-minlockduration" id="setassurancelockparameters-uint256-minlockeywa_-uint256-minlockduration"></a>

```solidity
function setAssuranceLockParameters(
    uint256 minLockEywa_,
    uint256 minLockDuration_
) external onlyOwner;
```

**Description:**\
Setting parameters for the delegate assurance lock

**Parameters:**

```
-   `minLockEywa_`: The minimum number of EYWA tokens that must be in the assurance lock.
-   `minLockDuration_`: The the minimum time before unlocking that a assurance lock should have.
```

**Checks:**

* Only the **owner** of the contract can call this function.

***

#### `setMinLockVeEywa(uint256 minLockVeEywa_)` <a href="#setminlockveeywa-uint256-minlockveeywa" id="setminlockveeywa-uint256-minlockveeywa"></a>

```solidity
function setMinLockVeEywa(uint256 minLockVeEywa_) external onlyOwner;
```

**Description:**\
Setting the minimum veEYWA value for delegated locks

**Parameters:**

* `minLockVeEywa_`: The minimum number of veEYWA that must be in the delegated lock.

**Checks:**

* Only the **owner** of the contract can call this function.

***

#### `setDelegationParameters(DelegationParameters memory delegationParameters_)` <a href="#setdelegationparameters-delegationparameters-memory-delegationparameters" id="setdelegationparameters-delegationparameters-memory-delegationparameters"></a>

```solidity
function setDelegationParameters(InputDelegationParameters memory delegationParameters_) external;
```

**Description:**\
Setting delegation parameters for the delegate If this is the first time a delegate is setting parameters, its address is added to the delegate array (`s_delegaties`) `delegationParameters_.eywaDeposit` and the delegate's current deposit. Delegation parameters can only be changed once the rewards have been received and distributed and rent has been paid for all delegated locks. When one or more parameters are changed: `delegationParameters_.maxDelegatedVeEYWA`, `delegationParameters_.delegationEnd`, `delegationParameters_.eywaDeposit` - the rent per veEYWA unit per epoch is recalculated. Performs a transfer of the required number of EYWA tokens from the delegate's account to his deposit in the contract. This deposit will be used to pay for lock rentals to delegates. The required number is calculated as the difference between

**Parameters:**

* `delegationParameters_`: Parameters of the delegation.

**Checks:**

* The delegate must pass the correct parameters. Otherwise, `WrongDelegationParameters()` is thrown.
* The delegate assuranceLock lock must comply with the requirements set forth. Otherwise, `BadAssuranceLock()` is thrown.
* All rewards for all delegated locks must be received. Otherwise, `RewardsUnclaimed()` is thrown.
* Must be paid rent for all delegated tokens. Otherwise, `DelegationUnpaid()` is thrown.
* The value of `delegationParameters_.maxDelegatedVeEYWA` must not be less than the current total veEYWA value for all locks delegated to this delegate. Otherwise, `MaxDelegatedVeEywaExceeded()` is thrown.

***

#### `setDelegationVoteParameters(address[] calldata pools_, uint256[] calldata weights_)` <a href="#setdelegationvoteparameters-address-calldata-pools_-uint256-calldata-weights" id="setdelegationvoteparameters-address-calldata-pools_-uint256-calldata-weights"></a>

```solidity
function setDelegationVoteParameters(
    address[] calldata pools_,
    uint256[] calldata weights_
) external;
```

**Description:**\
Setting the parameters auto-voting for a specific delegate.

**Parameters:**

* `pools_`: The array of voting pools.
* `weights_`: The array with voice weights for each pool.

**Checks:**

* `pools_` and `weights_` arrays must not be null and must have the same size. Otherwise, `InvalidArrayLengths()` is thrown.

***

#### `setAutoVotePermission(bool permission_)` <a href="#setautovotepermission-bool-permission" id="setautovotepermission-bool-permission"></a>

```solidity
function setAutoVotePermission(bool permission_) external;
```

**Description:**\
Set the permission for automatic voting using the **autoVote** function. With this permission, this **autoVote** function can be called by any account. To perform automatic voting, you must set the parameters with the **setDelegationVoteParameters** function

**Parameters:**

* `permission_`: The permission parameter.

***

#### `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;
```

**Description:**\
The function proxies the call of the **boost** function on the **EscrowManager** contract.

**Parameters:**

* `tokenId_`: The ID of the token representing the lock.
* `collectionTokenIds_`: An array of token IDs from the collection that will be used to boost the lock.

**Checks:**

* The lock must be self-delegation and the caller must be a delegator. Otherwise, `UnauthorizedCaller()` is thrown.
* Delegation time should not be finalized. Otherwise, `DelegateTimeExpired()` is thrown.

***

#### `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;
```

**Description:**\
The function proxies the call of the **deboost** function on the **EscrowManager** contract. And then performs a transfer of the NFTs withdrawn from the lock to the delegator balance.

**Parameters:**

* `tokenId_`: The ID of the token representing the lock.
* `collectionTokenIds_`: An array of token IDs from the collection that will be used to boost the lock.

**Checks:**

* The lock must be self-delegation and the caller must be a delegator. Otherwise, `UnauthorizedCaller()` is thrown.

***

#### `extend(uint256[] calldata tokenIds_, uint256[] calldata lockDurations_)` <a href="#extend-uint256-calldata-tokenids_-uint256-calldata-lockdurations" id="extend-uint256-calldata-tokenids_-uint256-calldata-lockdurations"></a>

```solidity
function extend(
    uint256[] calldata tokenIds_,
    uint256[] calldata lockDurations_
) external;
```

**Description:**\
The function proxies the call of the **extend** function on the **EscrowManager** contract.

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.
* `collectionTokenIds_`: An array of token IDs from the collection that will be used to boost the lock.

**Checks:**

* The `tokenIds_` and `lockDurations_` arrays must have the equal length. Otherwise, `InvalidArrayLengths()` is thrown.
* For each lock from `tokenIds` `delegatee_` must be a delegator. Otherwise, `WrongDelegatee()` is thrown.
* For each lock from `tokenIds_`, it is checked that its delegation time has not yet expired. Otherwise, `DelegateTimeExpired()` is thrown.
* The maximum veEYWA value for dlegation should not be exceeded after extend of the locks. Otherwise, `MaxDelegatedVeEywaExceeded()` is thrown.
* For each lock from `tokenIds_`, it is checked that there exists a LockHolder contract corresponding to the delegate-delegate pair. Otherwise, `LockHolderNotExist()` is thrown.

***

#### `withdrawDeposit(uint256 amount_)` <a href="#withdrawdeposit-uint256-amount" id="withdrawdeposit-uint256-amount"></a>

```solidity
function withdrawDeposit(uint256 amount_) external;
```

**Description:**\
Function for deposit withdrawal. Performs transfer of `amount_` of EYWA tokens from contract balance to `msg.sender` balance. Decreases by `amount_` the value in `s_depositByDelegatee` on the `msg.sender` key. A delegate can only withdraw a deposit if the current delegation has been completed and all payments for all delegated locks have been made.

**Parameters:**

* `amount_`: The amount of EYWA tokens.

**Checks:**

* Checks that the delegate's deposit is not less than `amount_`. Otherwise, `NotEnoughAmount()` is thrown.
* Fee must be paid for each delegated lock. Otherwise, `DelegationUnpaid()` is thrown.

***

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

```solidity
function claim() external;
```

**Description:**\
The function transfers EYWA, received as a commission for delegated locks, to the balance of the delegator

***

#### `delegate(address delegatee_, uint256[] calldata tokenIds_)` <a href="#delegate-address-delegatee_-uint256-calldata-tokenids" id="delegate-address-delegatee_-uint256-calldata-tokenids"></a>

```solidity
function delegate(
    address delegatee_,
    uint256[] calldata tokenIds_
) external;
```

**Description:**\
This function performs a number of necessary checks, after which the internal function `_delegate()` is called, in which delegation takes place.

**Parameters:**

* `delegatee_`: The delegate's address.
* `tokenIds_`: An array of IDs of the token representing the lock.

**Checks:**

* If it is not a self-delegation, it is checked that `delegatee_` has set the delegation parameters. Otherwise, `DelegateeNotExist()` is thrown.
* If it is not self-delegation, it is verified that the condition of the assurance lock is as specified. Otherwise, `BadAssuranceLock()` is thrown.
* If it is not a self-delegation, iit is checked that the maximum number of veEYWA specified in the delegation parameters will not be exceeded. Otherwise, `MaxDelegatedVeEywaExceeded()` is thrown.
* If it is not a self-delegation, additional delegation conditions are checked in the **validateDelegations** function on the **DelegationConditionValidator** contract. Otherwise, `UnvalidatedDelegation()` is thrown.

**Events:**

* Emits `Delegate(delegator, delegatee, tokenIds)`.

***

#### `paymentAndExtendDelegations(uint256[] calldata tokenIds_)` <a href="#paymentandextenddelegations-uint256-calldata-tokenids" id="paymentandextenddelegations-uint256-calldata-tokenids"></a>

```solidity
function paymentAndExtendDelegations(uint256[] calldata tokenIds_) external;
```

**Description:**\
The function transfers lock commissions from the delegatee's deposit to the delegator's deposit, for all epochs since the last time the commission was received, and renews locks

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

***

#### `claimIncentives(uint256[] calldata tokenIds_)` <a href="#claimincentives-uint256-calldata-tokenids" id="claimincentives-uint256-calldata-tokenids"></a>

```solidity
function claimIncentives(uint256[] calldata tokenIds_) external;
```

**Description:**\
The function proxies the call of the **claimIncentives** function on the **LockHoldeV1** contract. After collecting and distributing the bounty, notes that the bounty for the specified locks is received in this epoch.

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

***

#### `revokeDelegations(uint256[] calldata tokenIds_)` <a href="#revokedelegations-uint256-calldata-tokenids" id="revokedelegations-uint256-calldata-tokenids"></a>

```solidity
function revokeDelegations(uint256[] calldata tokenIds_) external;
```

**Description:**\
Function to revoke the delegation. Sets the start of the next epoch to the time the delegation ends. After the start of the next epoch, these delegated locks cannot be voted on.

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

**Checks:**

* For each lock from `tokenIds_`, it is checked that the function is called by a delegator or delegate. Otherwise, `UnauthorizedCaller()` is thrown.
* For each lock from `tokenIds_`, it is checked that its delegation time has not yet expired. Otherwise, `DelegateTimeExpired()` is thrown.

***

#### `recallDelegations(uint256[] calldata tokenIds_)` <a href="#recalldelegations-uint256-calldata-tokenids" id="recalldelegations-uint256-calldata-tokenids"></a>

```solidity
function recallDelegations(uint256[] calldata tokenIds_) external;
```

**Description:**\
Delegation Completion Function. In the normal situation, this function is called in the next epoch, after the **revokeDelegations** function has been called. For self-delegated locks, this function can be called at any time, without first calling the **revokeDelegations** function. If the delegation time specified in the delegation parameters has expired, you can call this function, without first calling the **revokeDelegations** function. After partitioning a lock, reduces by its veEYWA value the amount of veEYWA delegated to the delegate.

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

**Checks:**

* You can't recall assurance lock. Otherwise, `DelegationWithdrawalForbidden()` is thrown.
* For each lock from `tokenIds_`, it is checked that the function is called by a delegator or delegate. Otherwise, `UnauthorizedCaller()` is thrown.
* All rewards for all delegated locks must be received. Otherwise, `RewardsUnclaimed()` is thrown.
* Must be paid rent for all delegated tokens. Otherwise, `DelegationUnpaid()` is thrown.
* The delegation's time must be finalized. Otherwise, `DelegationWithdrawalForbidden()` is thrown.

**Events:**

* Emits `RecallDelegations(tokenIds_)`.

***

#### `function vote(uint256[] calldata tokenIds_, address[][] calldata pools_, uint256[][] calldata weights_)` <a href="#function-vote-uint256-calldata-tokenids_-address-calldata-pools_-uint256-calldata-weights" id="function-vote-uint256-calldata-tokenids_-address-calldata-pools_-uint256-calldata-weights"></a>

```solidity
function vote(
    uint256[] calldata tokenIds_,
    address[][] calldata pools_,
    uint256[][] calldata weights_
) external;
```

**Description:**\
The function proxies the call of the **extend** function on the **EscrowVoteManager** contract.

For each lock from `tokenIds_` the necessary checks are performed in the internal function **\_checkDelegation**, which will be described in detail below

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.
* `pools_`: An array of voting pools.
* `weights_`: An array with voice weights for each pool.

***

#### `autoVote(address delegatee_, uint256[] calldata tokenIds_)` <a href="#autovote-address-delegatee_-uint256-calldata-tokenids" id="autovote-address-delegatee_-uint256-calldata-tokenids"></a>

```solidity
function autoVote(
    address delegatee_,
    uint256[] calldata tokenIds_
) external;
```

**Description:**\
The function proxies the call of the **extend** function on the **EscrowVoteManager** contract.

The delegate must set permission for auto-voting in the **setAutoVotePermission** function and set the voting parameters in the **setDelegationVoteParameters** function. Then any account can perform voting by delegated locks of this delegate using the set parameters.

For each lock from `tokenIds_` the necessary checks are performed in the internal function **\_checkDelegation**, which will be described in detail below

**Parameters:**

* `delegatee_`: An array of IDs of the token representing the lock.
* `tokenIds_`: An array of IDs of the token representing the lock.

**Checks:**

* The `delegatee_` must set the authorization for auto-voting. Otherwise, `NotSetAutoVote()` is thrown.
* The `delegatee_` must set the parameters for auto-voting. Otherwise, `NotSetAutoVoteParameters()` is thrown.
* For each lock from `tokenIds` `delegatee_` must be a delegatee. Otherwise, `WrongDelegatee()` is thrown.

***

#### `reset(uint256[] calldata tokenIds_)` <a href="#reset-uint256-calldata-tokenids" id="reset-uint256-calldata-tokenids"></a>

```solidity
function reset(uint256[] calldata tokenIds_) external;
```

**Description:**\
The function proxies the call of the **reset** function on the **EscrowVoteManager** contract.

For each lock from `tokenIds_` the necessary checks are performed in the internal function **\_checkDelegation**, which will be described in detail below.

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

***

#### `poke(uint256[] calldata tokenIds_)` <a href="#poke-uint256-calldata-tokenids" id="poke-uint256-calldata-tokenids"></a>

```solidity
function poke(uint256[] calldata tokenIds_) external;
```

**Description:**\
The function proxies the call of the **poke** function on the **EscrowVoteManager** contract.

For each lock from `tokenIds_` the necessary checks are performed in the internal function **\_checkDelegation**, which will be described in detail below.

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

***

#### `isAvailableDelegate(address delegator_, address delegatee_, uint256[] calldata tokenIds_)` <a href="#isavailabledelegate-address-delegator_-address-delegatee_-uint256-calldata-tokenids" id="isavailabledelegate-address-delegator_-address-delegatee_-uint256-calldata-tokenids"></a>

```solidity
function isAvailableDelegate(
    address delegator_,
    address delegatee_,
    uint256[] calldata tokenIds_
) external view returns(bool);
```

**Description:**\
The function checks all current delegation parameters accepts determines whether delegation from `delegator_` to `delegatee_` of `tokenIds_` locks is possible. Returns true/false - delegation is or is not possible for the given values

**Parameters:**

* `delegator_`: The delegator's address.
* `delegatee_`: The delegate's address.
* `tokenIds_`: An array of IDs of the token representing the lock.

***

#### `getDelegationsParameters()` <a href="#getdelegationsparameters" id="getdelegationsparameters"></a>

```solidity
function getDelegationsParameters() external view returns(OutputDelegationParameters[] memory);
```

**Description:**\
The function returns an array of parameters of all delegates

***

#### `getDelegationsVoteParametersByDelegate(address delegatee_)` <a href="#getdelegationsvoteparametersbydelegate-address-delegatee" id="getdelegationsvoteparametersbydelegate-address-delegatee"></a>

```solidity
function getDelegationsVoteParametersByDelegate(
    address delegatee_
) external view returns(address[] memory pools_, uint256[] memory weights_);
```

**Description:**\
The function returns the auto-voting parameters for a specific `delegatee_`

**Parameters:**

* `delegatee_`: The delegate's address.

***

#### `getDelegationsInfoByTokenIds(uint256[] calldata tokenIds_)` <a href="#getdelegationsinfobytokenids-uint256-calldata-tokenids" id="getdelegationsinfobytokenids-uint256-calldata-tokenids"></a>

```solidity
function getDelegationsInfoByTokenIds(
    uint256[] calldata tokenIds_
) external view returns(DelegationInfo[] memory);
```

**Description:**\
The function returns an array with delegation information for an array of delegations

**Parameters:**

* `tokenIds_`: An array of IDs of the token representing the lock.

***

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

```solidity
function getDelegationInfoAndParametersByTokenId(
    uint256 tokenId_
) 
    external
    view 
    returns(DelegationInfo memory delegationInfo_, DelegationParameters memory delegationParameters_);
```

**Description:**\
The function returns delegation information `delegationInfo_` and delegation parameters `delegationParameters_` for a specific delegated lock by its `tokenId_`

**Parameters:**

* `tokenId_`: The ID of the token representing the lock.

***

#### `getLockIdsByDelegator(address delegator_)` <a href="#getlockidsbydelegator-address-delegator" id="getlockidsbydelegator-address-delegator"></a>

```solidity
function getLockIdsByDelegator(address delegator_) external view returns(uint256[] memory);
```

**Description:**\
The function returns an array of id's of all locks delegated by the `delegator_`

**Parameters:**

* `delegator_`: The delegator's address.

***

#### `getLockIdsByDelegatee(address delegatee_)` <a href="#getlockidsbydelegatee-address-delegatee" id="getlockidsbydelegatee-address-delegatee"></a>

```solidity
function getLockIdsByDelegatee(address delegatee_) external view returns(uint256[] memory);
```

**Description:**\
The function returns an array of id's of all locks delegated to the `delegatee_`

**Parameters:**

* `delegatee_`: The delegate's address.

***

#### `getAssuranceLockStatus(uint256 tokenId_, address delegatee_)` <a href="#getassurancelockstatus-uint256-tokenid_-address-delegatee" id="getassurancelockstatus-uint256-tokenid_-address-delegatee"></a>

```solidity
function getAssuranceLockStatus(
    uint256 tokenId_,
    address delegatee_
) public view returns(bool);
```

**Description:**\
The function checks and returns true/false the status of `tokenId_` as a Assurance lock for the `delegatee_`

**Parameters:**

* `tokenId_`: The ID of the token representing the lock.
* `delegatee_`: The delegate's address.

***

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

#### `_delegate(IEscrowManagerExtended escrowManager_, DelegationParameters memory delegationParameters_, uint256[] calldata tokenIds_, address delegatee_)` <a href="#delegate-iescrowmanagerextended-escrowmanager_-delegationparameters-memory-delegationparameters_-ui" id="delegate-iescrowmanagerextended-escrowmanager_-delegationparameters-memory-delegationparameters_-ui"></a>

```solidity
function _delegate(
    IEscrowManagerExtended escrowManager_,
    DelegationParameters memory delegationParameters_,
    uint256[] calldata tokenIds_,
    address delegatee_
) private;
```

**Description:**\
The delegation function performs the necessary checks and then performs a lock transfer to the **LockHolder** contract, and the entire veEYWA of the lock is transferred to the `delegate_` account. If this sender delegates locks to this `delegate_` for the first time, a new **LockHolder** contract is deployed for them. The necessary data structures are also created to store information about the delegated lock. If a sender address or null address is specified as `delegate_`, self-delegation occurs.

**Parameters:**

* `escrowManager_`: The IEscrowManagerExtended interface for the EscrowManager contract.
* `delegationParameters_`: Parameters of the delegation.
* `tokenIds_`: The array of IDs of the token representing the lock.
* `delegatee_`: The delegate's address.

**Checks**

* If it is not a self-delegation, checked that the veEYWA value of all lots specified in `tokenIds_` is not less than the `s_minLockVeEywa` value set in the contract `minVeEYWA` set in delegations parameters. Otherwise, `WrongVeEywaAmount()` is thrown.
* If it is not self-delegation, checks that the time to unlock the lock is not lower than the minimum time set by the `delegatee_`. Otherwise, `LittleTimeToUnlock()` is thrown.

***

#### `_recallDelegation(address delegator_, address delegatee_, uint256 tokenId_)` <a href="#recalldelegation-address-delegator_-address-delegatee_-uint256-tokenid" id="recalldelegation-address-delegator_-address-delegatee_-uint256-tokenid"></a>

```solidity
function _recallDelegation(
    address delegator_,
    address delegatee_,
    uint256 tokenId_
) internal;
```

**Description:**\
Delegation recall function

First, a check is made to see if the vote was made by this `tokenId_`, and if so, the **reset** function is called on the **LockHolder** contract to reset the vote. Otherwise it will be impossible to perform a lock transfer.

The data structures are then overwritten and the data of the revocable delegation is deleted.

At the end, a transfer of the voiting power and lock token to the delegator address is made

**Checks:**

* For `tokenId_`, it is checked that there exists a LockHolder contract corresponding to the delegate-delegate pair. Otherwise, `LockHolderNotExist()` is thrown.

**Parameters:**

* `delegator_`: The delegator's address.
* `delegatee_`: The delegate's address.
* `tokenId_` The ID of the token representing the lock.

***

#### `_getVotes(IEscrowManagerExtended escrowManager_, uint256[] calldata tokenIds_)` <a href="#getvotes-iescrowmanagerextended-escrowmanager_-uint256-calldata-tokenids" id="getvotes-iescrowmanagerextended-escrowmanager_-uint256-calldata-tokenids"></a>

```solidity
function _getVotes(
    IEscrowManagerExtended escrowManager_,
    uint256[] calldata tokenIds_
) private view returns(uint256);
```

**Description:**\
Returns the sum of veEYWA from an array of locks `tokenIds_`

**Parameters:**

* `tokenIds_`: The array of IDs of the token representing the lock.

***

#### `_getLastEpochOfDelegation(uint256 timeExpiry_, uint256 delegationEnd_)` <a href="#getlastepochofdelegation-uint256-timeexpiry_-uint256-delegationend" id="getlastepochofdelegation-uint256-timeexpiry_-uint256-delegationend"></a>

```solidity
function _getLastEpochOfDelegation(
    uint256 timeExpiry_,
    uint256 delegationEnd_
) internal view returns (uint256);
```

**Description:**\
The function returns the completion time of the delegation

**Parameters:**

* `timeExpiry_`: The expiry timestamp to verify.
* `delegationEnd_`: The epoch in which the delegation will be completed.

***

#### `_getPaidEpoch(uint256 timeExpiry_, uint256 delegationEnd_, uint256 currentEpochStart_)` <a href="#getpaidepoch-uint256-timeexpiry_-uint256-delegationend_-uint256-currentepochstart" id="getpaidepoch-uint256-timeexpiry_-uint256-delegationend_-uint256-currentepochstart"></a>

```solidity
function _getLastEpochOfDelegation(
    uint256 timeExpiry_,
    uint256 delegationEnd_,
    uint256 currentEpochStart_
) internal view returns (uint256);
```

**Description:**\
The function returns the start time of the last paid epoch

**Parameters:**

* `timeExpiry_`: The expiry timestamp to verify.
* `delegationEnd_`: The epoch in which the delegation will be completed.
* `currentEpochStart_`: The start time of the current epoch.

***

#### `_checkDelegationPaid(bool isSelfDelegation_, uint256 lastPaidEpoch_, uint256 paidEpoch_)` <a href="#checkdelegationpaid-bool-isselfdelegation_-uint256-lastpaidepoch_-uint256-paidepoch" id="checkdelegationpaid-bool-isselfdelegation_-uint256-lastpaidepoch_-uint256-paidepoch"></a>

```solidity
function _checkDelegationPaid(
    bool isSelfDelegation_,
    uint256 lastPaidEpoch_,
    uint256 paidEpoch_
) internal view returns (uint256);
```

**Description:**\
The function checks whether the delegation has been paid in the current epoch. Returned with DelegationUnpaid if the delegation is not paid in the current epoch.

**Parameters:**

* `isSelfDelegation_`: Indicates whether the delegation is self-delegated.
* `lastPaidEpoch_`: An epoch when the last fee payment was made.
* `paidEpoch_`: An epoch that must be paid for.

**Checks**

* Unless it is self-delegation, the last epoch paid should not be less than the epoch to be paid. Otherwise, `DelegationUnpaid()` is thrown.

***

#### `_checkRewardsClaimed(uint256 tokenId_, uint256 currentEpochStart_, address lockHolder_)` <a href="#checkrewardsclaimed-uint256-tokenid_-uint256-currentepochstart_-address-lockholder" id="checkrewardsclaimed-uint256-tokenid_-uint256-currentepochstart_-address-lockholder"></a>

```solidity
function _checkRewardsClaimed(
    uint256 tokenId_,
    uint256 currentEpochStart_,
    address lockHolder_
) internal view returns (uint256);
```

**Description:**\
The function checks to see if available awards have been received. Returned with RewardsUnclaimed if no awards have been received.

**Parameters:**

* `tokenId_`: Indicates whether the delegation is self-delegated.
* `currentEpochStart_`: The current epoch start.
* `lockHolder_`: The lock holder contract address.

**Checks**

* Unless it is self-delegation, the last epoch paid should not be less than the epoch to be paid. Otherwise, `DelegationUnpaid()` is thrown.

***

#### `_checkCaller(address caller_)` <a href="#checkcaller-address-caller" id="checkcaller-address-caller"></a>

```solidity
_checkCaller(address caller_) internal view;
```

**Description:**\
Internal function to check the caller.

**Parameters:**

* `caller_`: The expected caller's address.

**Checks:**

* `msg.sender` must be equal to `caller_`. Otherwise, `UnauthorizedCaller()` is thrown.

***

#### `_checkDelegatorOrDelegatee(address delegator_, address delegatee_)` <a href="#checkdelegatorordelegatee-address-delegator_-address-delegatee" id="checkdelegatorordelegatee-address-delegator_-address-delegatee"></a>

```solidity
function _checkDelegatorOrDelegatee(
    address delegator_,
    address delegatee_
) internal view;
```

**Description:**\
Internal function to verify that the function caller is a delegate or delegator.

**Parameters:**

* `delegator_`: The delegator's address.
* `delegatee_`: The delegate's address.

**Checks:**

* `msg.sender` must be equal to `delegator_` or `delegatee_`. Otherwise, `UnauthorizedCaller()` is thrown.

***

#### `_checkTimeExpiry(uint256 timeExpiry_)` <a href="#checktimeexpiry-uint256-timeexpiry" id="checktimeexpiry-uint256-timeexpiry"></a>

```solidity
function _checkTimeExpiry(uint256 timeExpiry_) internal view
```

**Description:**\
Internal function to check that the delegation time has not expired. If the delegation has been revoked and timeExpiry is not equal to 0, the end time of the delegation must be less than the current time

**Parameters:**

* `timeExpiry_`: The end time of delegation.

**Checks:**

* `block.timestamp` must be not equal 0 and greater than `timeExpiry_`. Otherwise, `DelegateTimeExpired()` is thrown

***

#### `_checkLockHolder(address delegator_, address delegatee_)` <a href="#checklockholder-address-delegator_-address-delegatee" id="checklockholder-address-delegator_-address-delegatee"></a>

```solidity
function _checkLockHolder(
    address delegator_,
    address delegatee_
) internal view returns(address);
```

**Description:**\
Internal Function to check the LockHolder contract address for a pair of delegator and delegate. Returns the LockHolder contract's address.

**Parameters:**

* `delegator_`: The delegator's address.
* `delegatee_`: The delegate's address.

**Checks:**

* a LockHolder contract must be deployed for the `delegator_` and `delegatee_` pair. Otherwise, `LockHolderNotExist()` is thrown

***

#### `_checkAssuranceLock(uint256 assuranceLock_, address delegatee_)` <a href="#checkassurancelock-uint256-assurancelock_-address-delegatee" id="checkassurancelock-uint256-assurancelock_-address-delegatee"></a>

```solidity
function _checkAssuranceLock(
    uint256 assuranceLock_,
    address delegatee_
) internal view returns(address);
```

**Description:**\
Internal function to check the assurance lock. Verification that the lock is a self-made lock, or its assurance lock meets the specified requirements

**Parameters:**

* `assuranceLock_`: The token ID used as the assurance lock.
* `delegatee_`: The delegatee assurance lock.

**Checks:**

* If the conditions are not met for assuarnce lock. Otherwise, `BadAssuranceLock()` is thrown

***

#### `_checkDelegation(DelegationInfo memory delegationInfo_, address caller_, uint256 currentEpochStart_)` <a href="#checkdelegation-delegationinfo-memory-delegationinfo_-address-caller_-uint256-currentepochstart" id="checkdelegation-delegationinfo-memory-delegationinfo_-address-caller_-uint256-currentepochstart"></a>

```solidity
function _checkDelegation(
    DelegationInfo memory delegationInfo_,
    address caller_,
    uint256 currentEpochStart_
) internal view returns(address);
```

**Description:**\
Internal function for check the delegation status. Check caller, time expiry, delegation fee payment. A number of internal functions are called for the checks, which will be described below

**Parameters:**

* `delegationInfo_`: The delegation information associated with the token.
* `caller_`: The expected caller's address.
* `currentEpochStart_`: The current epoch start.

**Checks:**

* The start time of the current epoch must be less than the end time of the delegation. Otherwise, `DelegationEnded()` is thrown.

***

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

```solidity
function _checkForSelfDelegation(uint256 tokenId_) internal view returns(address);
```

**Description:**\
Internal function for checking self-delegation. Returns the LockHolder contract's address.

**Parameters:**

* `tokenId_`: The ID of the token representing the lock.

**Checks:**

* When self-delegating for `tokenId_`, the delegator must be equal to the delegate and both of these values must be equal to `msg.sender`. Otherwise, `UnauthorizedCaller()` is thrown

***

#### `_currentEpochStart()` <a href="#currentepochstart" id="currentepochstart"></a>

```solidity
function _currentEpochStart() internal view returns (uint256);
```

**Description:**\
The function returns the start timestamp of the current epoch

***

#### `_nextEpochStart()` <a href="#nextepochstart" id="nextepochstart"></a>

```solidity
function _nextEpochStart() internal view returns (uint256);
```

**Description:**\
The function returns the start timestamp of the next epoch

***

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

```solidity
function _getTimeToUnlock(uint256 tokenId_) internal view returns(uint256);
```

**Description:**\
The function returns the time until the lock is unlocked

**Parameters:**

* `tokenId_`: The ID of the token representing the lock.

***

#### `_checkDelegateeExist(address delegatee_)` <a href="#checkdelegateeexist-address-delegatee" id="checkdelegateeexist-address-delegatee"></a>

```solidity
function _checkDelegateeExist(address delegatee_) internal view;
```

**Description:**\
Internal function to check if the delegate has set the delegation parameters

**Parameters:**

* `delegatee_`: The delegate's address.

**Checks:**

* `delegatee_` must have delegation parameters set. Otherwise, `DelegateeNotExist()` is thrown.

***

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

* **`Delegate(address indexed delegator, address indexed delegatee, uint256[] tokenIds)`**\
  The event is emitted when the delegation is successful.
* **`RecallDelegations(uint256[] tokenIds)`**\
  The event is emitted when the recall delegation is successful.

***

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

* **`WrongDelegationParameters()`**\
  Thrown if the delegate tries to set the wrong delegation parameters.
* **`BadAssuranceLock()`**\
  Thrown if the assurance lock is not compliant.
* **`DelegateeNotExist()`**\
  Thrown if the delegate has not set the delegation parameters.
* **`InvalidArrayLengths()`**\
  Thrown if the array has an invalid length.
* **`UnauthorizedCaller()`**\
  Thrown when the caller is not authorized to perform the action.
* **`DelegateTimeExpired()`**\
  Thrown when attempting to perform an action with a delegation with expired time.
* **`DelegationEnded()`**\
  Thrown when the delegation is complete.
* **`WrongLockDuration()`**\
  Thrown when attempting to set a new lock auto-extend time lower than the minimum allowed by the delegation parameters.
* **`LockHolderNotExist()`**\
  Thrown if there is no LockHolder for the current delegate and delegate pair.
* **`NotEnoughAmount()`**\
  Thrown when there is an insufficient deposit or fee for the requested operation.
* **`DelegationNotEnded()`**\
  Thrown when the delegation is not ended.
* **`MaxDelegatedVeEywaExceeded()`**\
  Thrown when the maximum number of delegated veEYWA has been exceeded.
* **`UnvalidatedDelegation()`**\
  Thrown when validation failed on the DelegationConditionValidator contract.
* **`WrongVeEywaAmount()`**\
  Thrown when the voting power of the delegated lock is less than s\_minLockVeEywa.
* **`LittleTimeToUnlock()`**\
  Thrown when attempting to delegate a lock that has less time to unlock than the minimum time set by the delegate.
* **`NotSetAutoVote()`**\
  Thrown when attempting to perform auto-voting if no permission is set.
* **`NotSetAutoVoteParameters()`**\
  Thrown when attempting to perform auto-voting if no parameters are set for it.
* **`WrongDelegatee()`**\
  Thrown when attempting to perform an auto-vote if the lock is not delegated to the specified delegate.
* **`DelegationWithdrawalForbidden()`**\
  Thrown when the delegation time has not yet expired, preventing recall.
* **`RewardsUnclaimed()`**\
  Thrown when the delegation time has not yet expired, preventing recall.
* **`DelegationUnpaid()`**\
  Thrown when no awards have been received.

***

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

**DelegationManagerV1** contract allows the castle owner not to track voting and reward collection, and not to spend ether on transaction fees. The delegate, on the other hand, can earn by taking a percentage of the rewards, sharing them with the castle owner. Alternatively, the castle owner can delegate to himself, which would simply automate the execution of voting and collection of rebase rewards and incentive rewards.
