# LockManager

## Code

* [LockManager.sol](https://github.com/Revest-Finance/RevestContracts/blob/master/hardhat/contracts/LockManager.sol)

## Read-Only Functions

### fnftIdToLock

```
function fnftIdToLock(uint fnftId) public view override returns (IRevest.Lock memory) {
    return locks[fnftIdToLockId[fnftId]];
}
```

Returns the Lock object associated with the passed in fnftId.

### getLock

```
function getLock(uint lockId) external view override returns (IRevest.Lock memory) {
    return locks[lockId];
}
```

Returns the lock object associated with the passed in lockId.

### getSupply

```
function getSupply(uint fnftId) public view override returns (uint) {
    return supply[fnftId];
}
```

Gets the total supply of FNFTs within the given ID.

### getLockMaturity

```
function getLockMaturity(uint fnftId) public view override returns (bool) {
    IRevest.Lock memory lock = locks[fnftIdToLockId[fnftId]];
    if (lock.lockType == IRevest.LockType.TimeLock) {
        return lock.unlocked || lock.timeLockExpiry < block.timestamp;
    }
    else if (lock.lockType == IRevest.LockType.ValueLock) {
        return lock.unlocked || getValueLockMaturity(fnftId);
    }
    else if (lock.lockType == IRevest.LockType.AddressLock) {
        return lock.unlocked || (lock.addressLock.supportsInterface(ADDRESS_LOCK_INTERFACE_ID) &&
                                    IAddressLock(lock.addressLock).isUnlockable(fnftId, fnftIdToLockId[fnftId]));
    }
    else {
        revert("E050");
    }
}
```

Helper function for getLockMaturity. Checks if a value lock is mature.

### lockTypes

```
function lockTypes(uint tokenId) external view override returns (IRevest.LockType) {
    return fnftIdToLock(tokenId).lockType;
}
```

* Gets the lock type for a given Id
* `fnftId` - the FNFT id to check the lock type of

## State-Changing Functions

### pointFNFTToLock

```
function pointFNFTToLock(uint fnftId, uint lockId) external override onlyRevest {
    fnftIdToLockId[fnftId] = lockId;
}
```

Maps an FNFT id to a lock ID.

### createLock

```
function createLock(uint fnftId, IRevest.LockParam memory lock) external override onlyRevest returns (uint) {
    // Extensive validation on creation
    require(lock.lockType != IRevest.LockType.DoesNotExist, "E058");
    IRevest.Lock storage newLock = locks[numLocks];
    newLock.lockType = lock.lockType;
    newLock.creationTime = block.timestamp;
    if(lock.lockType == IRevest.LockType.TimeLock) {
        require(lock.timeLockExpiry > block.timestamp, "E002");
        newLock.timeLockExpiry = lock.timeLockExpiry;
    }
    else if (lock.lockType == IRevest.LockType.ValueLock) {
        require(lock.valueLock.unlockValue > 0, "E003");
        require(lock.valueLock.compareTo != address(0) && lock.valueLock.asset != address(0), "E004");
        //Begin validation code to ensure this is actually keyed to a proper oracle
        IOracleDispatch oracle = IOracleDispatch(lock.valueLock.oracle);
        bool oraclePresent = oracle.getPairHasOracle(lock.valueLock.asset, lock.valueLock.compareTo);
        //If the oracle is not present, attempt to initialize it
        if(!oraclePresent && oracle.oracleNeedsInitialization(lock.valueLock.asset, lock.valueLock.compareTo)) {
            oraclePresent = oracle.initializeOracle(lock.valueLock.asset, lock.valueLock.compareTo);
        }
        require(oraclePresent, "E049");
        newLock.valueLock = lock.valueLock;
    }
    else if (lock.lockType == IRevest.LockType.AddressLock) {
        require(lock.addressLock != address(0), "E004");
        newLock.addressLock = lock.addressLock;
    }
    else {
        require(false, "Invalid type");
    }
    fnftIdToLockId[fnftId] = numLocks;
    numLocks += 1;
    return numLocks - 1;
}
```

* Validates and creates a lock
* `fnftId` - The ID to associate with this lock
* `Lock` - The lock to validate and associate with the fnftId
* RETURNS the lockId of the newly created lock

### unlockFNFT

```
function unlockFNFT(uint fnftId, address sender) external override onlyRevestController returns (bool) {
    uint lockId = fnftIdToLockId[fnftId];
    IRevest.Lock storage lock = locks[lockId];
    IRevest.LockType typeLock = lock.lockType;
    if (typeLock == IRevest.LockType.TimeLock) {
        if(!lock.unlocked && lock.timeLockExpiry <= block.timestamp) {
            lock.unlocked = true;
            //Should refund some gas
            lock.timeLockExpiry = 0;
        }
    }
    else if (typeLock == IRevest.LockType.ValueLock) {
        bool unlockState;
        address oracleAdd =lock.valueLock.oracle;
        if(getLockMaturity(fnftId)) {
            unlockState = true;
        } else {
            IOracleDispatch oracle = IOracleDispatch(oracleAdd);
            unlockState = oracle.updateOracle(lock.valueLock.asset, lock.valueLock.compareTo) &&
                            getLockMaturity(fnftId);
        }
        if(unlockState && oracleAdd != address(0)) {
            //We only want to write this once
            lock.unlocked = true;
            //Refund some gas
            lock.valueLock.oracle = address(0);
            lock.valueLock.asset = address(0);
            lock.valueLock.compareTo = address(0);
            lock.valueLock.unlockValue = 0;
            lock.valueLock.unlockRisingEdge = false;
        }

    }
    else if (typeLock == IRevest.LockType.AddressLock) {
        address addLock = lock.addressLock;
        if (!lock.unlocked && (sender == addLock ||
                (addLock.supportsInterface(ADDRESS_LOCK_INTERFACE_ID) && IAddressLock(addLock).isUnlockable(fnftId, lockId)))
            ) {
            lock.unlocked = true;
            //Refund some gas
            lock.addressLock = address(0);
        }
    }
    return lock.unlocked;
}
```

* Helper function for Revest.sol
* Unlocks address or value locks after checking if they meet the conditions for unlock
* `lockId` - The lockId to unlock
* `Sender` - The address who has sent the request to Revest.sol
* RETURNS - boolean of success at unlocking the lock

## Interface

```
// SPDX-License-Identifier: GNU-GPL v3.0 or later

pragma solidity >=0.8.0;

import "./IRevest.sol";

/**
 * @title Mintable interface for Revest FNFTs
 * @dev ...
 */
interface ILockManager {

    function createLock(uint fnftId, IRevest.LockParam memory lock) external returns (uint);

    function getLock(uint lockId) external view returns (IRevest.Lock memory);

    function fnftIdToLockId(uint fnftId) external view returns (uint);

    function fnftIdToLock(uint fnftId) external view returns (IRevest.Lock memory);

    function pointFNFTToLock(uint fnftId, uint lockId) external;

    function lockTypes(uint tokenId) external view returns (IRevest.LockType);

    function unlockFNFT(uint fnftId, address sender) external returns (bool);

    function getLockMaturity(uint fnftId) external view returns (bool);
}
```

## ABI


---

# 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://dev.revest.finance/smart-contracts/lockmanager.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.
