账户
0x56...15e2
0x56...15e2

0x56...15e2

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.6.12+commit.27d51765
语言
Solidity
合同源代码
文件 1 的 1:LiqLpStaker.sol
pragma solidity ^0.6.0;

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;
        return c;
    }
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
    }
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }
    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

contract Ownable is Context {
    address private _owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }
    function owner() public view returns (address) {
        return _owner;
    }
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }
}

abstract contract LiqLpContract {
    function balanceOf(address account) external view virtual returns (uint256);
    function transfer(address recipient, uint256 amount) external virtual returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external virtual returns (bool);
}

abstract contract RewardContract {
    function getFogBalance() external view virtual returns (uint256);
    function giveFogReward(address recipient, uint256 amount) external virtual returns (bool);
}

contract LiqLpStaker is Ownable {
    using SafeMath for uint256;

    LiqLpContract private _liqLpContract;                   // Liq UniswapPair token contract
    RewardContract private _rewardContract;                 // reward contract

    mapping (address => StakerInfo) private _stakeMap;      // map for stakers

    address private _devWallet;                             // dev wallet address
    uint256 private _devLastClaimTimestamp;                 // dev wallet address
    address[] private _stakers;                             // staker's array
    
    uint256 private _totalStakedAmount = 0;                // total staked amount
    
    uint256 private _rewardPortion = 10;                    // reward portion 10%
    
    uint256 private _rewardFee = 98;                        // reward fee 98%, rest for dev 2%

    
    struct StakerInfo {
        uint256 stakedAmount;
        uint256 lastClaimTimestamp;
        uint256 rewardAmount;
    }
    
    // Events
    event Staked(address indexed staker, uint256 amount);
    event Unstaked(address indexed staker, uint256 amount);
    event Claim(address indexed staker, uint256 amount);
    
    constructor (LiqLpContract liqLpContract, address devWallet) public {
        _liqLpContract = liqLpContract;
        _devWallet = devWallet;
        
    }
    
    function stake(uint256 amount) public {
      
        require(
            _liqLpContract.transferFrom(
                _msgSender(),
                address(this),
                amount
            ),
            "liqLpStaker: stake failed."
        );
        
        uint256 StakedAmount = amount;
        uint256 currentTimestamp = uint256(now);
        
        if(_stakers.length == 0)
            _devLastClaimTimestamp = currentTimestamp;

        if(_stakeMap[_msgSender()].stakedAmount == 0) {
            _stakers.push(_msgSender());
            _stakeMap[_msgSender()].lastClaimTimestamp = currentTimestamp;
        } else {
            _stakeMap[_msgSender()].rewardAmount = _stakeMap[_msgSender()].rewardAmount.add(calcReward(_msgSender(), currentTimestamp));
            _stakeMap[_msgSender()].lastClaimTimestamp = currentTimestamp;
        }
            
        _stakeMap[_msgSender()].stakedAmount = _stakeMap[_msgSender()].stakedAmount.add(StakedAmount);
        _totalStakedAmount = _totalStakedAmount.add(amount);
        
        emit Staked(_msgSender(), StakedAmount);
    }
    
    function unstake(uint256 amount) public {
        require(
            _stakeMap[_msgSender()].stakedAmount >= amount,
            "LiqLpStaker: unstake amount exceededs the staked amount."
        );

        uint256 currentTimestamp = uint256(now);

        _stakeMap[_msgSender()].rewardAmount = _stakeMap[_msgSender()].rewardAmount.add(calcReward(_msgSender(), currentTimestamp));
        _stakeMap[_msgSender()].lastClaimTimestamp = currentTimestamp;
        
        _stakeMap[_msgSender()].stakedAmount = _stakeMap[_msgSender()].stakedAmount.sub(amount);
        _totalStakedAmount = _totalStakedAmount.sub(amount);
        
        require(
            _liqLpContract.transfer(
                _msgSender(),
                amount
            ),
            "LiqLpStaker: unstake failed."
        );

        if(_stakeMap[_msgSender()].stakedAmount == 0) {
            _stakeMap[_msgSender()].lastClaimTimestamp = 0;
            for(uint i=0; i<_stakers.length; i++) {
                if(_stakers[i] == _msgSender()) {
                    _stakers[i] = _stakers[_stakers.length-1];
                    _stakers.pop();
                    break;
                }
            }
        }
        emit Unstaked(_msgSender(), amount);
    }
    
    function claim() public {
        uint256 currentTimestamp = uint256(now);
        uint256 rewardAmount = _stakeMap[_msgSender()].rewardAmount.add(calcReward(_msgSender(), currentTimestamp));
        _stakeMap[_msgSender()].lastClaimTimestamp = currentTimestamp;
        
        require(
            _rewardContract.giveFogReward(_msgSender(), rewardAmount),
            "LiqLpStaker: claim failed."
        );
        
        _stakeMap[_msgSender()].rewardAmount = 0;
	    emit Claim(_msgSender(), rewardAmount);
	    
	    if(currentTimestamp.sub(_devLastClaimTimestamp) >= 86400) {
	        rewardAmount = calcDevReward(currentTimestamp);
	        _devLastClaimTimestamp = currentTimestamp;
	        
	         require(
                _rewardContract.giveFogReward(_devWallet, rewardAmount),
                "LiqLpStaker: dev reward claim failed."
            );
	        emit Claim(_devWallet, rewardAmount);
	    }
    }
    
    function endStake() external {
        unstake(_stakeMap[_msgSender()].stakedAmount);
        claim();
    }
    
    function calcReward(address staker, uint256 currentTimestamp) private view returns (uint256) {
        if(_totalStakedAmount == 0)
            return 0;
        uint256 rewardPoolBalance = _rewardContract.getFogBalance();
        uint256 passTime = currentTimestamp.sub(_stakeMap[staker].lastClaimTimestamp);
        uint256 rewardAmountForStakers = rewardPoolBalance.mul(_rewardPortion).div(100).mul(_rewardFee).div(100);
        uint256 rewardAmount = rewardAmountForStakers.mul(passTime).div(86400).mul(_stakeMap[staker].stakedAmount).div(_totalStakedAmount);
        return rewardAmount;
    }
    
    function calcDevReward(uint256 currentTimestamp) private view returns (uint256) {
        uint256 rewardPoolBalance = _rewardContract.getFogBalance();
        uint256 passTime = currentTimestamp.sub(_devLastClaimTimestamp);
        uint256 rewardAmount = rewardPoolBalance.mul(_rewardPortion).div(100).mul(uint256(100).sub(_rewardFee)).div(100).mul(passTime).div(86400);
        return rewardAmount;
    }

    /**
     * Get store wallet
     */
    function getRewardContract() external view returns (address) {
        return address(_rewardContract);
    }
     
    /**
     * Get total staked amount
     */
    function getTotalStakedAmount() external view returns (uint256) {
        return _totalStakedAmount;
    }
    
    /**
     * Get reward amount of staker
     */
    function getReward(address staker) external view returns (uint256) {
        return _stakeMap[staker].rewardAmount.add(calcReward(staker, now));
    }
    
    /**
     * Get reward pool balance (LAVA)
     */
    function getRewardPoolBalance() external view returns (uint256) {
        return _rewardContract.getFogBalance();
    }
    
    /**
     * Get last claim timestamp
     */
    function getLastClaimTimestamp(address staker) external view returns (uint256) {
        return _stakeMap[staker].lastClaimTimestamp;
    }
    
    /**
     * Get staked amount of staker
     */
    function getStakedAmount(address staker) external view returns (uint256) {
        return _stakeMap[staker].stakedAmount;
    }
    
    /**
     * Get rewards portion
     */
    function getRewardPortion() external view returns (uint256) {
        return _rewardPortion;
    }
    
    /**
     * Get staker count
     */
    function getStakerCount() external view returns (uint256) {
        return _stakers.length;
    }
    
     /**
     * Get rewards fee
     */
    function getRewardFee() external view returns (uint256) {
        return _rewardFee;
    }
    
    /**
     * Get staked rank
     */
    function getStakedRank(address staker) external view returns (uint256) {
        uint256 rank = 1;
        uint256 senderStakedAmount = _stakeMap[staker].stakedAmount;
        
        for(uint i=0; i<_stakers.length; i++) {
            if(_stakers[i] != staker && senderStakedAmount < _stakeMap[_stakers[i]].stakedAmount)
                rank = rank.add(1);
        }
        return rank;
    }
    
    /**
     * Set store wallet contract address
     */
    function setRewardContract(RewardContract rewardContract) external onlyOwner returns (bool) {
        require(address(rewardContract) != address(0), 'LiqLpStaker: reward contract address should not be zero address.');

        _rewardContract = rewardContract;
        return true;
    }

    /**
     * Set rewards portion in store balance. 
     * ex: 10 => 10%
     */
    function setRewardPortion(uint256 rewardPortion) external onlyOwner returns (bool) {
        require(rewardPortion >= 10 && rewardPortion <= 100, 'LiqLpStaker: reward portion should be in 10 ~ 100.');

        _rewardPortion = rewardPortion;
        return true;
    }
    
    /**
     * Set rewards portion for stakers in rewards amount. 
     * ex: 98 => 98% (2% for dev)
     */
    function setRewardFee(uint256 rewardFee) external onlyOwner returns (bool) {
        require(rewardFee >= 96 && rewardFee <= 100, 'LiqLpStaker: reward fee should be in 96 ~ 100.' );

        _rewardFee = rewardFee;
        return true;
    }
}
设置
{
  "compilationTarget": {
    "LiqLpStaker.sol": "LiqLpStaker"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"contract LiqLpContract","name":"liqLpContract","type":"address"},{"internalType":"address","name":"devWallet","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getLastClaimTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardPoolBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardPortion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStakedRank","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract RewardContract","name":"rewardContract","type":"address"}],"name":"setRewardContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardFee","type":"uint256"}],"name":"setRewardFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardPortion","type":"uint256"}],"name":"setRewardPortion","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]