Skip to content

Latest commit

 

History

History
1913 lines (1510 loc) · 55.3 KB

LiquidityMining.md

File metadata and controls

1913 lines (1510 loc) · 55.3 KB

LiquidityMining.sol

View Source: contracts/farm/LiquidityMining.sol

↗ Extends: ILiquidityMining, LiquidityMiningStorage

LiquidityMining contract

Contract Members

Constants & Variables

uint256 public constant PRECISION;
uint256 public constant BONUS_BLOCK_MULTIPLIER;
uint256 public constant SECONDS_PER_BLOCK;

Events

event SOVTransferred(address indexed receiver, uint256  amount);
event PoolTokenAdded(address indexed user, address indexed poolToken, uint256  allocationPoint);
event PoolTokenUpdated(address indexed user, address indexed poolToken, uint256  newAllocationPoint, uint256  oldAllocationPoint);
event Deposit(address indexed user, address indexed poolToken, uint256  amount);
event RewardClaimed(address indexed user, address indexed poolToken, uint256  amount);
event Withdraw(address indexed user, address indexed poolToken, uint256  amount);
event EmergencyWithdraw(address indexed user, address indexed poolToken, uint256  amount, uint256  accumulatedReward);

Functions


initialize

Initialize mining. *

function initialize(IERC20 _SOV, uint256 _rewardTokensPerBlock, uint256 _startDelayBlocks, uint256 _numberOfBonusBlocks, address _wrapper, ILockedSOV _lockedSOV, uint256 _unlockedImmediatelyPercent) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_SOV IERC20 The SOV token.
_rewardTokensPerBlock uint256 The number of reward tokens per block.
_startDelayBlocks uint256 The number of blocks should be passed to start mining.
_numberOfBonusBlocks uint256 The number of blocks when each block will be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).
_wrapper address
_lockedSOV ILockedSOV The contract instance address of the lockedSOV vault. SOV rewards are not paid directly to liquidity providers. Instead they are deposited into a lockedSOV vault contract.
_unlockedImmediatelyPercent uint256 The % which determines how much will be unlocked immediately.
Source Code
function initialize(
        IERC20 _SOV,
        uint256 _rewardTokensPerBlock,
        uint256 _startDelayBlocks,
        uint256 _numberOfBonusBlocks,
        address _wrapper,
        ILockedSOV _lockedSOV,
        uint256 _unlockedImmediatelyPercent
    ) external onlyAuthorized {
        /// @dev Non-idempotent function. Must be called just once.
        require(address(SOV) == address(0), "Already initialized");
        require(address(_SOV) != address(0), "Invalid token address");
        require(_startDelayBlocks > 0, "Invalid start block");
        require(
            _unlockedImmediatelyPercent < 10000,
            "Unlocked immediately percent has to be less than 10000."
        );

        SOV = _SOV;
        rewardTokensPerBlock = _rewardTokensPerBlock;
        startBlock = block.number + _startDelayBlocks;
        bonusEndBlock = startBlock + _numberOfBonusBlocks;
        wrapper = _wrapper;
        lockedSOV = _lockedSOV;
        unlockedImmediatelyPercent = _unlockedImmediatelyPercent;
    }

setLockedSOV

Sets lockedSOV contract.

function setLockedSOV(ILockedSOV _lockedSOV) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_lockedSOV ILockedSOV The contract instance address of the lockedSOV vault.
Source Code
function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {
        require(address(_lockedSOV) != address(0), "Invalid lockedSOV Address.");
        lockedSOV = _lockedSOV;
    }

setUnlockedImmediatelyPercent

Sets unlocked immediately percent.

function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_unlockedImmediatelyPercent uint256 The % which determines how much will be unlocked immediately.
Source Code
function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)
        external
        onlyAuthorized
    {
        require(
            _unlockedImmediatelyPercent <= 10000,
            "Unlocked immediately percent has to be less than equal to 10000."
        );
        unlockedImmediatelyPercent = _unlockedImmediatelyPercent;
    }

setPoolTokenUnlockedImmediatelyPercent

Sets unlocked immediately percent overwrite for specific pool token.

function setPoolTokenUnlockedImmediatelyPercent(address _poolToken, uint256 _poolTokenUnlockedImmediatelyPercent) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_poolToken address the address of pool token
_poolTokenUnlockedImmediatelyPercent uint256 The % which determines how much will be unlocked immediately.
Source Code
function setPoolTokenUnlockedImmediatelyPercent(
        address _poolToken,
        uint256 _poolTokenUnlockedImmediatelyPercent
    ) external onlyAuthorized {
        require(
            _poolTokenUnlockedImmediatelyPercent <= 10000,
            "Unlocked immediately percent has to be less than equal to 10000."
        );
        poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;
    }

setWrapper

sets wrapper proxy contract

function setWrapper(address _wrapper) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_wrapper address
Source Code
function setWrapper(address _wrapper) external onlyAuthorized {
        wrapper = _wrapper;
    }

stopMining

stops mining by setting end block

function stopMining() external nonpayable onlyAuthorized 
Source Code
function stopMining() external onlyAuthorized {
        require(endBlock == 0, "Already stopped");

        endBlock = block.number;
    }

transferSOV

Transfers SOV tokens to given address. Owner use this function to withdraw SOV from LM contract into another account.

function transferSOV(address _receiver, uint256 _amount) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_receiver address The address of the SOV receiver.
_amount uint256 The amount to be transferred.
Source Code
function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {
        require(_receiver != address(0), "Receiver address invalid");
        require(_amount != 0, "Amount invalid");

        /// @dev Do not transfer more SOV than available.
        uint256 SOVBal = SOV.balanceOf(address(this));
        if (_amount > SOVBal) {
            _amount = SOVBal;
        }

        /// @dev The actual transfer.
        require(SOV.transfer(_receiver, _amount), "Transfer failed");

        /// @dev Event log.
        emit SOVTransferred(_receiver, _amount);
    }

getMissedBalance

Get the missed SOV balance of LM contract. *

function getMissedBalance() external view
returns(uint256)
Source Code
function getMissedBalance() external view returns (uint256) {
        uint256 balance = SOV.balanceOf(address(this));
        return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);
    }

add

adds a new lp to the pool. Can only be called by the owner or an admin

function add(address _poolToken, uint96 _allocationPoint, bool _withUpdate) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_poolToken address the address of pool token
_allocationPoint uint96 the allocation point (weight) for the given pool
_withUpdate bool the flag whether we need to update all pools
Source Code
function add(
        address _poolToken,
        uint96 _allocationPoint,
        bool _withUpdate
    ) external onlyAuthorized {
        require(_allocationPoint > 0, "Invalid allocation point");
        require(_poolToken != address(0), "Invalid token address");
        require(poolIdList[_poolToken] == 0, "Token already added");

        if (_withUpdate) {
            updateAllPools();
        }

        uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
        totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);

        poolInfoList.push(
            PoolInfo({
                poolToken: IERC20(_poolToken),
                allocationPoint: _allocationPoint,
                lastRewardBlock: lastRewardBlock,
                accumulatedRewardPerShare: 0
            })
        );
        //indexing starts from 1 in order to check whether token was already added
        poolIdList[_poolToken] = poolInfoList.length;

        emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);
    }

update

updates the given pool's reward tokens allocation point

function update(address _poolToken, uint96 _allocationPoint, bool _updateAllFlag) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_poolToken address the address of pool token
_allocationPoint uint96 the allocation point (weight) for the given pool
_updateAllFlag bool the flag whether we need to update all pools
Source Code
function update(
        address _poolToken,
        uint96 _allocationPoint,
        bool _updateAllFlag
    ) external onlyAuthorized {
        if (_updateAllFlag) {
            updateAllPools();
        } else {
            updatePool(_poolToken);
        }
        _updateToken(_poolToken, _allocationPoint);
    }

_updateToken

function _updateToken(address _poolToken, uint96 _allocationPoint) internal nonpayable

Arguments

Name Type Description
_poolToken address
_allocationPoint uint96
Source Code
function _updateToken(address _poolToken, uint96 _allocationPoint) internal {
        uint256 poolId = _getPoolId(_poolToken);

        uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;
        totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(
            _allocationPoint
        );
        poolInfoList[poolId].allocationPoint = _allocationPoint;

        emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);
    }

updateTokens

updates the given pools' reward tokens allocation points

function updateTokens(address[] _poolTokens, uint96[] _allocationPoints, bool _updateAllFlag) external nonpayable onlyAuthorized 

Arguments

Name Type Description
_poolTokens address[] array of addresses of pool tokens
_allocationPoints uint96[] array of allocation points (weight) for the given pools
_updateAllFlag bool the flag whether we need to update all pools
Source Code
function updateTokens(
        address[] calldata _poolTokens,
        uint96[] calldata _allocationPoints,
        bool _updateAllFlag
    ) external onlyAuthorized {
        require(_poolTokens.length == _allocationPoints.length, "Arrays mismatch");

        if (_updateAllFlag) {
            updateAllPools();
        }
        uint256 length = _poolTokens.length;
        for (uint256 i = 0; i < length; i++) {
            if (!_updateAllFlag) {
                updatePool(_poolTokens[i]);
            }
            _updateToken(_poolTokens[i], _allocationPoints[i]);
        }
    }

_getPassedBlocksWithBonusMultiplier

returns reward multiplier over the given _from to _to block

function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to) internal view
returns(uint256)

Arguments

Name Type Description
_from uint256 the first block for a calculation
_to uint256 the last block for a calculation
Source Code
function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)
        internal
        view
        returns (uint256)
    {
        if (_from < startBlock) {
            _from = startBlock;
        }
        if (endBlock > 0 && _to > endBlock) {
            _to = endBlock;
        }
        if (_to <= bonusEndBlock) {
            return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);
        } else if (_from >= bonusEndBlock) {
            return _to.sub(_from);
        } else {
            return
                bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));
        }
    }

_getUserAccumulatedReward

function _getUserAccumulatedReward(uint256 _poolId, address _user) internal view
returns(uint256)

Arguments

Name Type Description
_poolId uint256
_user address
Source Code
function _getUserAccumulatedReward(uint256 _poolId, address _user)
        internal
        view
        returns (uint256)
    {
        PoolInfo storage pool = poolInfoList[_poolId];
        UserInfo storage user = userInfoMap[_poolId][_user];

        uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;
        uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));
        if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {
            (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);
            accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);
        }

        return
            user.accumulatedReward.add(
                user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)
            );
    }

getUserAccumulatedReward

returns accumulated reward

function getUserAccumulatedReward(address _poolToken, address _user) external view
returns(uint256)

Arguments

Name Type Description
_poolToken address the address of pool token
_user address the user address
Source Code
function getUserAccumulatedReward(address _poolToken, address _user)
        external
        view
        returns (uint256)
    {
        uint256 poolId = _getPoolId(_poolToken);
        return _getUserAccumulatedReward(poolId, _user);
    }

getEstimatedReward

returns estimated reward

function getEstimatedReward(address _poolToken, uint256 _amount, uint256 _duration) external view
returns(uint256)

Arguments

Name Type Description
_poolToken address the address of pool token
_amount uint256 the amount of tokens to be deposited
_duration uint256 the duration of liquidity providing in seconds
Source Code
function getEstimatedReward(
        address _poolToken,
        uint256 _amount,
        uint256 _duration
    ) external view returns (uint256) {
        uint256 poolId = _getPoolId(_poolToken);
        PoolInfo storage pool = poolInfoList[poolId];
        uint256 start = block.number;
        uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));
        (, uint256 accumulatedRewardPerShare) =
            _getPoolAccumulatedReward(pool, _amount, start, end);
        return _amount.mul(accumulatedRewardPerShare).div(PRECISION);
    }

updateAllPools

Updates reward variables for all pools.

function updateAllPools() public nonpayable
Source Code
function updateAllPools() public {
        uint256 length = poolInfoList.length;
        for (uint256 i = 0; i < length; i++) {
            _updatePool(i);
        }
    }

updatePool

Updates reward variables of the given pool to be up-to-date

function updatePool(address _poolToken) public nonpayable

Arguments

Name Type Description
_poolToken address the address of pool token
Source Code
function updatePool(address _poolToken) public {
        uint256 poolId = _getPoolId(_poolToken);
        _updatePool(poolId);
    }

_updatePool

function _updatePool(uint256 _poolId) internal nonpayable

Arguments

Name Type Description
_poolId uint256
Source Code
function _updatePool(uint256 _poolId) internal {
        PoolInfo storage pool = poolInfoList[_poolId];

        //this pool has been updated recently
        if (block.number <= pool.lastRewardBlock) {
            return;
        }

        uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));
        if (poolTokenBalance == 0) {
            pool.lastRewardBlock = block.number;
            return;
        }

        (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =
            _getPoolAccumulatedReward(pool);
        pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(
            accumulatedRewardPerShare_
        );
        pool.lastRewardBlock = block.number;

        totalUsersBalance = totalUsersBalance.add(accumulatedReward_);
    }

_getPoolAccumulatedReward

function _getPoolAccumulatedReward(struct LiquidityMiningStorage.PoolInfo _pool) internal view
returns(uint256, uint256)

Arguments

Name Type Description
_pool struct LiquidityMiningStorage.PoolInfo
Source Code
function _getPoolAccumulatedReward(PoolInfo storage _pool)
        internal
        view
        returns (uint256, uint256)
    {
        return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);
    }

_getPoolAccumulatedReward

function _getPoolAccumulatedReward(struct LiquidityMiningStorage.PoolInfo _pool, uint256 _additionalAmount, uint256 _startBlock, uint256 _endBlock) internal view
returns(uint256, uint256)

Arguments

Name Type Description
_pool struct LiquidityMiningStorage.PoolInfo
_additionalAmount uint256
_startBlock uint256
_endBlock uint256
Source Code
function _getPoolAccumulatedReward(
        PoolInfo storage _pool,
        uint256 _additionalAmount,
        uint256 _startBlock,
        uint256 _endBlock
    ) internal view returns (uint256, uint256) {
        uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);
        uint256 accumulatedReward =
            passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(
                totalAllocationPoint
            );

        uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));
        poolTokenBalance = poolTokenBalance.add(_additionalAmount);
        uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);
        return (accumulatedReward, accumulatedRewardPerShare);
    }

deposit

deposits pool tokens

function deposit(address _poolToken, uint256 _amount, address _user) external nonpayable

Arguments

Name Type Description
_poolToken address the address of pool token
_amount uint256 the amount of pool tokens
_user address the address of user, tokens will be deposited to it or to msg.sender
Source Code
function deposit(
        address _poolToken,
        uint256 _amount,
        address _user
    ) external {
        _deposit(_poolToken, _amount, _user, false);
    }

onTokensDeposited

⤾ overrides ILiquidityMining.onTokensDeposited

if the lending pools directly mint/transfer tokens to this address, process it like a user deposit

function onTokensDeposited(address _user, uint256 _amount) external nonpayable

Arguments

Name Type Description
_user address the user address
_amount uint256 the minted amount
Source Code
function onTokensDeposited(address _user, uint256 _amount) external {
        //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert
        _deposit(msg.sender, _amount, _user, true);
    }

_deposit

internal function for depositing pool tokens

function _deposit(address _poolToken, uint256 _amount, address _user, bool alreadyTransferred) internal nonpayable

Arguments

Name Type Description
_poolToken address the address of pool token
_amount uint256 the amount of pool tokens
_user address the address of user, tokens will be deposited to it
alreadyTransferred bool true if the pool tokens have already been transferred
Source Code
function _deposit(
        address _poolToken,
        uint256 _amount,
        address _user,
        bool alreadyTransferred
    ) internal {
        require(poolIdList[_poolToken] != 0, "Pool token not found");
        address userAddress = _user != address(0) ? _user : msg.sender;

        uint256 poolId = _getPoolId(_poolToken);
        PoolInfo storage pool = poolInfoList[poolId];
        UserInfo storage user = userInfoMap[poolId][userAddress];

        _updatePool(poolId);
        //sends reward directly to the user
        _updateReward(pool, user);

        if (_amount > 0) {
            //receives pool tokens from msg.sender, it can be user or WrapperProxy contract
            if (!alreadyTransferred)
                pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);
            user.amount = user.amount.add(_amount);
        }
        _updateRewardDebt(pool, user);
        emit Deposit(userAddress, _poolToken, _amount);
    }

claimReward

transfers reward tokens

function claimReward(address _poolToken, address _user) external nonpayable

Arguments

Name Type Description
_poolToken address the address of pool token
_user address the address of user to claim reward from (can be passed only by wrapper contract)
Source Code
function claimReward(address _poolToken, address _user) external {
        address userAddress = _getUserAddress(_user);

        uint256 poolId = _getPoolId(_poolToken);
        _claimReward(poolId, userAddress, true);
    }

_claimReward

function _claimReward(uint256 _poolId, address _userAddress, bool _isStakingTokens) internal nonpayable

Arguments

Name Type Description
_poolId uint256
_userAddress address
_isStakingTokens bool
Source Code
function _claimReward(
        uint256 _poolId,
        address _userAddress,
        bool _isStakingTokens
    ) internal {
        PoolInfo storage pool = poolInfoList[_poolId];
        UserInfo storage user = userInfoMap[_poolId][_userAddress];

        _updatePool(_poolId);
        _updateReward(pool, user);
        _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);
        _updateRewardDebt(pool, user);
    }

claimRewardFromAllPools

transfers reward tokens from all pools

function claimRewardFromAllPools(address _user) external nonpayable

Arguments

Name Type Description
_user address the address of user to claim reward from (can be passed only by wrapper contract)
Source Code
function claimRewardFromAllPools(address _user) external {
        address userAddress = _getUserAddress(_user);

        uint256 length = poolInfoList.length;
        for (uint256 i = 0; i < length; i++) {
            uint256 poolId = i;
            _claimReward(poolId, userAddress, false);
        }

        if (
            lockedSOV.getLockedBalance(userAddress) > 0 ||
            lockedSOV.getUnlockedBalance(userAddress) > 0
        ) {
            lockedSOV.withdrawAndStakeTokensFrom(userAddress);
        }
    }

withdraw

⤾ overrides ILiquidityMining.withdraw

withdraws pool tokens and transfers reward tokens

function withdraw(address _poolToken, uint256 _amount, address _user) external nonpayable

Arguments

Name Type Description
_poolToken address the address of pool token
_amount uint256 the amount of pool tokens
_user address the user address will be used to process a withdrawal (can be passed only by wrapper contract)
Source Code
function withdraw(
        address _poolToken,
        uint256 _amount,
        address _user
    ) external {
        require(poolIdList[_poolToken] != 0, "Pool token not found");
        address userAddress = _getUserAddress(_user);

        uint256 poolId = _getPoolId(_poolToken);
        PoolInfo storage pool = poolInfoList[poolId];
        UserInfo storage user = userInfoMap[poolId][userAddress];
        require(user.amount >= _amount, "Not enough balance");

        _updatePool(poolId);
        _updateReward(pool, user);
        _transferReward(_poolToken, user, userAddress, false, false);

        user.amount = user.amount.sub(_amount);

        //msg.sender is wrapper -> send to wrapper
        if (msg.sender == wrapper) {
            pool.poolToken.safeTransfer(address(msg.sender), _amount);
        }
        //msg.sender is user or pool token (lending pool) -> send to user
        else {
            pool.poolToken.safeTransfer(userAddress, _amount);
        }

        _updateRewardDebt(pool, user);
        emit Withdraw(userAddress, _poolToken, _amount);
    }

_getUserAddress

function _getUserAddress(address _user) internal view
returns(address)

Arguments

Name Type Description
_user address
Source Code
function _getUserAddress(address _user) internal view returns (address) {
        address userAddress = msg.sender;
        if (_user != address(0)) {
            //only wrapper can pass _user parameter
            require(
                msg.sender == wrapper || poolIdList[msg.sender] != 0,
                "only wrapper or pools may withdraw for a user"
            );
            userAddress = _user;
        }
        return userAddress;
    }

_updateReward

function _updateReward(struct LiquidityMiningStorage.PoolInfo pool, struct LiquidityMiningStorage.UserInfo user) internal nonpayable

Arguments

Name Type Description
pool struct LiquidityMiningStorage.PoolInfo
user struct LiquidityMiningStorage.UserInfo
Source Code
function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {
        //update user accumulated reward
        if (user.amount > 0) {
            //add reward for the previous amount of deposited tokens
            uint256 accumulatedReward =
                user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(
                    user.rewardDebt
                );
            user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);
        }
    }

_updateRewardDebt

function _updateRewardDebt(struct LiquidityMiningStorage.PoolInfo pool, struct LiquidityMiningStorage.UserInfo user) internal nonpayable

Arguments

Name Type Description
pool struct LiquidityMiningStorage.PoolInfo
user struct LiquidityMiningStorage.UserInfo
Source Code
function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {
        //reward accumulated before amount update (should be subtracted during next reward calculation)
        user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);
    }

_transferReward

Send reward in SOV to the lockedSOV vault.

function _transferReward(address _poolToken, struct LiquidityMiningStorage.UserInfo _user, address _userAddress, bool _isStakingTokens, bool _isCheckingBalance) internal nonpayable

Arguments

Name Type Description
_poolToken address
_user struct LiquidityMiningStorage.UserInfo The user info, to get its reward share.
_userAddress address The address of the user, to send SOV in its behalf.
_isStakingTokens bool The flag whether we need to stake tokens
_isCheckingBalance bool The flag whether we need to throw error or don't process reward if SOV balance isn't enough
Source Code
function _transferReward(
        address _poolToken,
        UserInfo storage _user,
        address _userAddress,
        bool _isStakingTokens,
        bool _isCheckingBalance
    ) internal {
        uint256 userAccumulatedReward = _user.accumulatedReward;
        /// @dev get unlock immediate percent of the pool token.
        uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);

        /// @dev Transfer if enough SOV balance on this LM contract.
        uint256 balance = SOV.balanceOf(address(this));
        if (balance >= userAccumulatedReward) {
            totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);
            _user.accumulatedReward = 0;

            /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).
            ///   else, deposit it into lockedSOV vault contract, but first
            ///   SOV deposit must be approved to move the SOV tokens
            ///   from this LM contract into the lockedSOV vault.
            if (calculatedUnlockedImmediatelyPercent == 10000) {
                SOV.transfer(_userAddress, userAccumulatedReward);
            } else {
                require(SOV.approve(address(lockedSOV), userAccumulatedReward), "Approve failed");
                lockedSOV.deposit(
                    _userAddress,
                    userAccumulatedReward,
                    calculatedUnlockedImmediatelyPercent
                );

                if (_isStakingTokens) {
                    lockedSOV.withdrawAndStakeTokensFrom(_userAddress);
                }
            }

            /// @dev Event log.
            emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);
        } else {
            require(!_isCheckingBalance, "Claiming reward failed");
        }
    }

emergencyWithdraw

withdraws pool tokens without transferring reward tokens

function emergencyWithdraw(address _poolToken) external nonpayable

Arguments

Name Type Description
_poolToken address the address of pool token
Source Code
function emergencyWithdraw(address _poolToken) external {
        uint256 poolId = _getPoolId(_poolToken);
        PoolInfo storage pool = poolInfoList[poolId];
        UserInfo storage user = userInfoMap[poolId][msg.sender];

        _updatePool(poolId);
        _updateReward(pool, user);

        totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);
        uint256 userAmount = user.amount;
        uint256 userAccumulatedReward = user.accumulatedReward;
        user.amount = 0;
        user.rewardDebt = 0;
        user.accumulatedReward = 0;
        pool.poolToken.safeTransfer(address(msg.sender), userAmount);

        emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);
    }

getPoolId

returns pool id

function getPoolId(address _poolToken) external view
returns(uint256)

Arguments

Name Type Description
_poolToken address the address of pool token
Source Code
function getPoolId(address _poolToken) external view returns (uint256) {
        return _getPoolId(_poolToken);
    }

_getPoolId

function _getPoolId(address _poolToken) internal view
returns(uint256)

Arguments

Name Type Description
_poolToken address
Source Code
function _getPoolId(address _poolToken) internal view returns (uint256) {
        uint256 poolId = poolIdList[_poolToken];
        require(poolId > 0, "Pool token not found");
        return poolId - 1;
    }

getPoolLength

returns count of pool tokens

function getPoolLength() external view
returns(uint256)
Source Code
function getPoolLength() external view returns (uint256) {
        return poolInfoList.length;
    }

getPoolInfoList

returns list of pool token's info

function getPoolInfoList() external view
returns(struct LiquidityMiningStorage.PoolInfo[])
Source Code
function getPoolInfoList() external view returns (PoolInfo[] memory) {
        return poolInfoList;
    }

getPoolInfo

returns pool info for the given token

function getPoolInfo(address _poolToken) external view
returns(struct LiquidityMiningStorage.PoolInfo)

Arguments

Name Type Description
_poolToken address the address of pool token
Source Code
function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {
        uint256 poolId = _getPoolId(_poolToken);
        return poolInfoList[poolId];
    }

getUserBalanceList

returns list of [amount, accumulatedReward] for the given user for each pool token

function getUserBalanceList(address _user) external view
returns(uint256[2][])

Arguments

Name Type Description
_user address the address of the user
Source Code
function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {
        uint256 length = poolInfoList.length;
        uint256[2][] memory userBalanceList = new uint256[2][](length);
        for (uint256 i = 0; i < length; i++) {
            userBalanceList[i][0] = userInfoMap[i][_user].amount;
            userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);
        }
        return userBalanceList;
    }

getUserInfo

returns UserInfo for the given pool and user

function getUserInfo(address _poolToken, address _user) public view
returns(struct LiquidityMiningStorage.UserInfo)

Arguments

Name Type Description
_poolToken address the address of pool token
_user address the address of the user
Source Code
function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {
        uint256 poolId = _getPoolId(_poolToken);
        return userInfoMap[poolId][_user];
    }

getUserInfoList

returns list of UserInfo for the given user for each pool token

function getUserInfoList(address _user) external view
returns(struct LiquidityMiningStorage.UserInfo[])

Arguments

Name Type Description
_user address the address of the user
Source Code
function getUserInfoList(address _user) external view returns (UserInfo[] memory) {
        uint256 length = poolInfoList.length;
        UserInfo[] memory userInfoList = new UserInfo[](length);
        for (uint256 i = 0; i < length; i++) {
            userInfoList[i] = userInfoMap[i][_user];
        }
        return userInfoList;
    }

getUserAccumulatedRewardList

returns accumulated reward for the given user for each pool token

function getUserAccumulatedRewardList(address _user) external view
returns(uint256[])

Arguments

Name Type Description
_user address the address of the user
Source Code
function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {
        uint256 length = poolInfoList.length;
        uint256[] memory rewardList = new uint256[](length);
        for (uint256 i = 0; i < length; i++) {
            rewardList[i] = _getUserAccumulatedReward(i, _user);
        }
        return rewardList;
    }

getUserPoolTokenBalance

⤾ overrides ILiquidityMining.getUserPoolTokenBalance

returns the pool token balance a user has on the contract

function getUserPoolTokenBalance(address _poolToken, address _user) external view
returns(uint256)

Arguments

Name Type Description
_poolToken address the address of pool token
_user address the address of the user
Source Code
function getUserPoolTokenBalance(address _poolToken, address _user)
        external
        view
        returns (uint256)
    {
        UserInfo memory ui = getUserInfo(_poolToken, _user);
        return ui.amount;
    }

getUserAccumulatedRewardToBePaidLiquid

returns the accumulated liquid reward for the given user for each pool token

function getUserAccumulatedRewardToBePaidLiquid(address _user) external view
returns(uint256)

Arguments

Name Type Description
_user address the address of the user
Source Code
function getUserAccumulatedRewardToBePaidLiquid(address _user)
        external
        view
        returns (uint256)
    {
        uint256 length = poolInfoList.length;
        uint256 result;
        for (uint256 i = 0; i < length; i++) {
            address _poolToken = address(poolInfoList[i].poolToken);
            uint256 calculatedUnlockedImmediatelyPercent =
                calcUnlockedImmediatelyPercent(_poolToken);
            result = result.add(
                calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(
                    10000
                )
            );
        }

        return result;
    }

getUserAccumulatedRewardToBeVested

returns the accumulated vested reward for the given user for each pool token

function getUserAccumulatedRewardToBeVested(address _user) external view
returns(uint256)

Arguments

Name Type Description
_user address the address of the user
Source Code
function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {
        uint256 length = poolInfoList.length;
        uint256 result;
        for (uint256 i = 0; i < length; i++) {
            address _poolToken = address(poolInfoList[i].poolToken);
            uint256 calculatedUnlockedImmediatelyPercent =
                calcUnlockedImmediatelyPercent(_poolToken);
            result = result.add(
                (10000 - calculatedUnlockedImmediatelyPercent)
                    .mul(_getUserAccumulatedReward(i, _user))
                    .div(10000)
            );
        }

        return result;
    }

calcUnlockedImmediatelyPercent

calculate the unlocked immediate percentage of specific pool token use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent

function calcUnlockedImmediatelyPercent(address _poolToken) public view
returns(uint256)

Arguments

Name Type Description
_poolToken address
Source Code
function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {
        uint256 poolTokenUnlockedImmediatelyPercent =
            poolTokensUnlockedImmediatelyPercent[_poolToken];
        return
            poolTokenUnlockedImmediatelyPercent > 0
                ? poolTokenUnlockedImmediatelyPercent
                : unlockedImmediatelyPercent;
    }

Contracts