-
-
Save barchef/99e5d2694f04ca75e35258259390819d to your computer and use it in GitHub Desktop.
Locker.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.13; | |
/** | |
* Locker | |
*/ | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import "@openzeppelin/contracts/utils/math/SafeMath.sol"; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import "./LockerStaking.sol"; | |
contract Locker is Ownable { | |
using SafeMath for uint256; | |
IERC20 public lockerToken; | |
LockerStaking public stakingPool; | |
/* | |
* deposit vars | |
*/ | |
struct Items { | |
address tokenAddress; | |
address withdrawalAddress; | |
uint256 tokenAmount; | |
uint256 unlockTime; | |
bool withdrawn; | |
} | |
uint256 public depositId; | |
uint256[] public allDepositIds; | |
mapping(address => uint256[]) public depositsByWithdrawalAddress; | |
mapping(uint256 => Items) public lockedToken; | |
mapping(address => mapping(address => uint256)) public walletTokenBalance; | |
mapping(address => uint256) public tokenFees; | |
mapping(address => uint256) public tokenFeesClaimed; | |
mapping(address => mapping(address => bool)) public isClaimed; | |
uint256 public feePercentage = 100; // 1% * 100; no fee if staking locker token | |
uint256 public minStakeAmount = 10000 * 1e18; | |
event LogLock( | |
address tokenAddress, | |
address fromAddress, | |
uint256 amount, | |
uint256 unlockTime, | |
uint256 depositId | |
); | |
event LogWithdrawal(address SentToAddress, uint256 AmountTransferred); | |
/** | |
* Constrctor function | |
*/ | |
constructor(address _token, address _staking) public { | |
lockerToken = IERC20(_token); | |
stakingPool = LockerStaking(_staking); | |
} | |
/** | |
*lock tokens | |
*/ | |
function lockTokens( | |
address _tokenAddress, | |
address _withdrawalAddress, | |
uint256 _lockAmount, | |
uint256 _unlockTime | |
) public returns (uint256 _id) { | |
require( | |
_unlockTime < 10000000000, | |
"Enter an unix timestamp in seconds, not milliseconds" | |
); | |
require( | |
_unlockTime >= block.timestamp, | |
"Enter an unix timestamp in the future" | |
); | |
require( | |
IERC20(_tokenAddress).approve(address(this), _lockAmount), | |
"Approve tokens failed" | |
); | |
// support fee tokens by chking contract balance before & after xfer | |
uint256 _balanceBefore = IERC20(_tokenAddress).balanceOf(address(this)); | |
require( | |
IERC20(_tokenAddress).transferFrom( | |
msg.sender, | |
address(this), | |
_lockAmount | |
), | |
"Transfer of tokens failed" | |
); | |
uint256 _balanceAfter = IERC20(_tokenAddress).balanceOf(address(this)); | |
_lockAmount = _balanceAfter.sub(_balanceBefore); | |
require(_lockAmount > 0, "token amount must be greater than zero"); | |
uint256 balance; | |
(balance, , ) = stakingPool.accountInfos(_withdrawalAddress); | |
uint256 feeAmount; | |
if (balance < minStakeAmount) { | |
feeAmount = _lockAmount.mul(feePercentage).div(10000); | |
} | |
tokenFees[_tokenAddress] = tokenFees[_tokenAddress].add(feeAmount); | |
uint256 _amount = _lockAmount.sub(feeAmount); | |
//update balance in address | |
walletTokenBalance[_tokenAddress][ | |
_withdrawalAddress | |
] = walletTokenBalance[_tokenAddress][_withdrawalAddress].add(_amount); | |
_id = ++depositId; | |
lockedToken[_id].tokenAddress = _tokenAddress; | |
lockedToken[_id].withdrawalAddress = _withdrawalAddress; | |
lockedToken[_id].tokenAmount = _amount; | |
lockedToken[_id].unlockTime = _unlockTime; | |
lockedToken[_id].withdrawn = false; | |
allDepositIds.push(_id); | |
depositsByWithdrawalAddress[_withdrawalAddress].push(_id); | |
emit LogLock( | |
_tokenAddress, | |
_withdrawalAddress, | |
_amount, | |
_unlockTime, | |
_id | |
); | |
} | |
/** | |
*withdraw tokens | |
*/ | |
function withdrawTokens(uint256 _id) public { | |
require( | |
block.timestamp >= lockedToken[_id].unlockTime, | |
"Lock time has not passed" | |
); | |
require( | |
msg.sender == lockedToken[_id].withdrawalAddress, | |
"Can withdraw by withdrawal Address only" | |
); | |
require(!lockedToken[_id].withdrawn, "Tokens already withdrawn"); | |
lockedToken[_id].withdrawn = true; | |
require( | |
IERC20(lockedToken[_id].tokenAddress).transfer( | |
msg.sender, | |
lockedToken[_id].tokenAmount | |
), | |
"Transfer of tokens failed" | |
); | |
//update balance in address | |
walletTokenBalance[lockedToken[_id].tokenAddress][ | |
msg.sender | |
] = walletTokenBalance[lockedToken[_id].tokenAddress][msg.sender].sub( | |
lockedToken[_id].tokenAmount | |
); | |
//remove this id from this address | |
uint256 i; | |
uint256 j; | |
for ( | |
j = 0; | |
j < | |
depositsByWithdrawalAddress[lockedToken[_id].withdrawalAddress] | |
.length; | |
j++ | |
) { | |
if ( | |
depositsByWithdrawalAddress[lockedToken[_id].withdrawalAddress][ | |
j | |
] == _id | |
) { | |
for ( | |
i = j; | |
i < | |
depositsByWithdrawalAddress[ | |
lockedToken[_id].withdrawalAddress | |
] | |
.length - | |
1; | |
i++ | |
) { | |
depositsByWithdrawalAddress[ | |
lockedToken[_id].withdrawalAddress | |
][i] = depositsByWithdrawalAddress[ | |
lockedToken[_id].withdrawalAddress | |
][i + 1]; | |
} | |
depositsByWithdrawalAddress[lockedToken[_id].withdrawalAddress] | |
.pop(); | |
break; | |
} | |
} | |
emit LogWithdrawal(msg.sender, lockedToken[_id].tokenAmount); | |
} | |
function pendingRewards(address sender, address _tokenAddress) | |
public | |
view | |
returns (uint256) | |
{ | |
uint256 balance; | |
(balance, , ) = stakingPool.accountInfos(sender); | |
uint256 totalStaked = lockerToken.balanceOf(address(stakingPool)); | |
uint256 totalTokenFee = | |
tokenFees[_tokenAddress].add(tokenFeesClaimed[_tokenAddress]); | |
uint256 reward = balance.mul(totalTokenFee).div(totalStaked); | |
return reward; | |
} | |
function claimFee(address _tokenAddress) public { | |
require(!isClaimed[_tokenAddress][msg.sender], "Already claimed"); | |
require(tokenFees[_tokenAddress] > 0, "All distributed"); | |
uint256 userRewardAmount = pendingRewards(msg.sender, _tokenAddress); | |
if (tokenFees[_tokenAddress] < userRewardAmount) { | |
userRewardAmount = tokenFees[_tokenAddress]; | |
} | |
isClaimed[_tokenAddress][msg.sender] = true; | |
IERC20(_tokenAddress).transfer(msg.sender, userRewardAmount); | |
tokenFees[_tokenAddress] = tokenFees[_tokenAddress].sub( | |
userRewardAmount | |
); | |
tokenFeesClaimed[_tokenAddress] = tokenFeesClaimed[_tokenAddress].add( | |
userRewardAmount | |
); | |
} | |
/*get total token balance in contract*/ | |
function getTotalTokenBalance(address _tokenAddress) | |
public | |
view | |
returns (uint256) | |
{ | |
return IERC20(_tokenAddress).balanceOf(address(this)); | |
} | |
/*get total token balance by address*/ | |
function getTokenBalanceByAddress( | |
address _tokenAddress, | |
address _walletAddress | |
) public view returns (uint256) { | |
return walletTokenBalance[_tokenAddress][_walletAddress]; | |
} | |
/*get allDepositIds*/ | |
function getAllDepositIds() public view returns (uint256[] memory) { | |
return allDepositIds; | |
} | |
/*get getDepositDetails*/ | |
function getDepositDetails(uint256 _id) | |
public | |
view | |
returns ( | |
address, | |
address, | |
uint256, | |
uint256, | |
bool | |
) | |
{ | |
return ( | |
lockedToken[_id].tokenAddress, | |
lockedToken[_id].withdrawalAddress, | |
lockedToken[_id].tokenAmount, | |
lockedToken[_id].unlockTime, | |
lockedToken[_id].withdrawn | |
); | |
} | |
/*get DepositsByWithdrawalAddress*/ | |
function getDepositsByWithdrawalAddress(address _withdrawalAddress) | |
public | |
view | |
returns (uint256[] memory) | |
{ | |
return depositsByWithdrawalAddress[_withdrawalAddress]; | |
} | |
function setFeePercentage(uint256 _feePercentage) | |
external | |
onlyOwner | |
{ | |
require (_feePercentage <= 500, "fee cannot exceed 500"); | |
feePercentage = _feePercentage; | |
} | |
function setMinStakeAmount(uint256 _minStakeAmount) external onlyOwner { | |
minStakeAmount = _minStakeAmount; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment