Verified Contract
0x47ac007000F24AD4758eaA6Fcd1dAC020143C16a
Pin to watchlist
scan to copy
zkLTC Balance
0
hard money native
Transactions
32
Token transfers
26
Validations
0
blocks produced
Hard Money Score
55
/100
MIXED
share of activity in native zkLTC vs. tokens
native
32
tokens
26
Contract name
LiquidityProvider
Compiler
v0.8.20+commit.a1b79de6
Optimization
disabled
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface ILPToken is IERC20 {
function token0() external view returns (address);
function token1() external view returns (address);
}
contract LiquidityProvider is Ownable {
// Info of each user.
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
uint256 pendingRewards;
}
// Info of each pool.
struct PoolInfo {
address lpToken;
uint256 allocPoint;
uint256 lastRewardBlock;
uint256 accTokenPerShare;
uint256 totalLocked;
}
// The reward token
address public rewardToken;
// Rewards per block
uint256 public rewardPerBlock = 1e18; // 1 token per block
// Bonus mulitplier for early miners
uint256 public constant BONUS_MULTIPLIER = 1;
// Max emission rate
uint256 public constant MAX_EMISSION = 10e18;
// Info of each pool
PoolInfo[] public poolInfo;
// Info of each user that stakes LP tokens
mapping(uint256 => mapping(address => UserInfo)) public userInfo;
// Total allocation points
uint256 public totalAllocPoint = 0;
// The block number when mining starts
uint256 public startBlock;
// The block number when mining ends
uint256 public endBlock;
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event PoolAdded(uint256 pid, address lpToken, uint256 allocPoint);
event SetPool(uint256 pid, uint256 allocPoint);
event UpdateEmissionRate(uint256 rewardPerBlock);
constructor(address _rewardToken, address _owner) Ownable() {
_transferOwnership(_owner);
rewardToken = _rewardToken;
startBlock = block.number;
endBlock = startBlock + 5256000; // ~1 year with 2s block time
}
function poolLength() external view returns (uint256) {
return poolInfo.length;
}
function addPool(uint256 _allocPoint, address _lpToken, bool _withUpdate) external onlyOwner {
if (_withUpdate) {
massUpdatePools();
}
uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
totalAllocPoint = totalAllocPoint + _allocPoint;
poolInfo.push(PoolInfo({
lpToken: _lpToken,
allocPoint: _allocPoint,
lastRewardBlock: lastRewardBlock,
accTokenPerShare: 0,
totalLocked: 0
}));
emit PoolAdded(poolInfo.length - 1, _lpToken, _allocPoint);
}
function setPool(uint256 _pid, uint256 _allocPoint, bool _withUpdate) external onlyOwner {
if (_withUpdate) {
massUpdatePools();
}
totalAllocPoint = totalAllocPoint - poolInfo[_pid].allocPoint + _allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
emit SetPool(_pid, _allocPoint);
}
function setRewardPerBlock(uint256 _rewardPerBlock) external onlyOwner {
require(_rewardPerBlock <= MAX_EMISSION, "Too high");
rewardPerBlock = _rewardPerBlock;
emit UpdateEmissionRate(_rewardPerBlock);
}
function pendingReward(uint256 _pid, address _user) external view returns (uint256) {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
uint256 accTokenPerShare = pool.accTokenPerShare;
uint256 lpSupply = pool.totalLocked;
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 tokenReward = multiplier * rewardPerBlock * pool.allocPoint / totalAllocPoint;
accTokenPerShare = accTokenPerShare + tokenReward * 1e12 / lpSupply;
}
return user.amount * accTokenPerShare / 1e12 - user.rewardDebt + user.pendingRewards;
}
function deposit(uint256 _pid, uint256 _amount) external {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
updatePool(_pid);
if (user.amount > 0) {
uint256 pending = user.amount * pool.accTokenPerShare / 1e12 - user.rewardDebt + user.pendingRewards;
user.pendingRewards = pending;
}
if (_amount > 0) {
IERC20(pool.lpToken).transferFrom(msg.sender, address(this), _amount);
user.amount = user.amount + _amount;
pool.totalLocked = pool.totalLocked + _amount;
}
user.rewardDebt = user.amount * pool.accTokenPerShare / 1e12;
emit Deposit(msg.sender, _pid, _amount);
}
function withdraw(uint256 _pid, uint256 _amount) external {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
require(user.amount >= _amount, "Withdraw amount exceeds balance");
updatePool(_pid);
uint256 pending = user.amount * pool.accTokenPerShare / 1e12 - user.rewardDebt + user.pendingRewards;
user.pendingRewards = 0;
if (pending > 0) {
IERC20(rewardToken).transfer(msg.sender, pending);
}
if (_amount > 0) {
user.amount = user.amount - _amount;
pool.totalLocked = pool.totalLocked - _amount;
IERC20(pool.lpToken).transfer(msg.sender, _amount);
}
user.rewardDebt = user.amount * pool.accTokenPerShare / 1e12;
emit Withdraw(msg.sender, _pid, _amount);
}
function emergencyWithdraw(uint256 _pid) external {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
uint256 amount = user.amount;
user.amount = 0;
user.rewardDebt = 0;
user.pendingRewards = 0;
pool.totalLocked = pool.totalLocked - amount;
IERC20(pool.lpToken).transfer(msg.sender, amount);
emit EmergencyWithdraw(msg.sender, _pid, amount);
}
function getMultiplier(uint256 from, uint256 to) public pure returns (uint256) {
return to - from;
}
function updatePool(uint256 _pid) public {
PoolInfo storage pool = poolInfo[_pid];
if (block.number <= pool.lastRewardBlock) {
return;
}
uint256 lpSupply = pool.totalLocked;
if (lpSupply == 0) {
pool.lastRewardBlock = block.number;
return;
}
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 tokenReward = multiplier * rewardPerBlock * pool.allocPoint / totalAllocPoint;
pool.accTokenPerShare = pool.accTokenPerShare + tokenReward * 1e12 / lpSupply;
pool.lastRewardBlock = block.number;
}
function massUpdatePools() public {
uint256 length = poolInfo.length;
for (uint256 pid = 0; pid < length; ++pid) {
updatePool(pid);
}
}
function rescueTokens(address token, address to, uint256 amount) external onlyOwner {
require(to != address(0), "Invalid recipient");
IERC20(token).transfer(to, amount);
}
}