/**
* Token staking contract developed for kauricrypto.com by Radek Ostrowski radek@startonchain.com
*/
pragma solidity ^0.5.13;
/**
* @title ERC20
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
uint256 public totalSupply;
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
*/
function renounceOwnership() public onlyOwner {
owner = address(0);
emit OwnershipRenounced(owner);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
owner = _newOwner;
emit OwnershipTransferred(owner, _newOwner);
}
}
contract KauriStaking is Ownable {
event TokensStaked(address stakedBy, address stakedFor, uint256 time, uint256 duration, uint256 amount);
event TokensUnstaked(address staker, uint256 time, uint256 amount, uint256 remaining);
ERC20 public token;
struct Staked {
uint256 time;
uint256 duration;
uint256 amount;
}
mapping(address => Staked) private stakedTokens;
constructor(ERC20 _token) public {
token = _token;
}
function stakeTokens(uint256 _amount, uint256 _duration) public {
require(stakedTokens[msg.sender].amount == 0, "some tokens are already staked for this address");
token.transferFrom(msg.sender, address(this), _amount);
stakedTokens[msg.sender] = Staked(now, _duration, _amount);
emit TokensStaked(msg.sender, msg.sender, now, _duration, _amount);
}
function stakeTokensFor(address _staker, uint256 _amount, uint256 _duration) public onlyOwner {
require(stakedTokens[_staker].amount == 0, "some tokens are already staked for this address");
token.transferFrom(msg.sender, address(this), _amount);
stakedTokens[_staker] = Staked(now, _duration, _amount);
emit TokensStaked(msg.sender, _staker, now, _duration, _amount);
}
function withdrawTokens(uint256 _amount) public {
Staked memory staked = stakedTokens[msg.sender];
require(!isLocked(now, staked.time, staked.duration), "tokens are still locked");
require(staked.amount > 0, "no staked tokens to withdraw");
//if trying to withdraw more than available, withdraw all
uint256 toWithdaw = _amount;
if(toWithdaw > staked.amount){
toWithdaw = staked.amount;
}
token.transfer(msg.sender, toWithdaw);
if(staked.amount == toWithdaw){
//withdrawing all
stakedTokens[msg.sender] = Staked(0, 0, 0);
} else {
stakedTokens[msg.sender] = Staked(staked.time, staked.duration, staked.amount - toWithdaw);
}
emit TokensUnstaked(msg.sender, now, toWithdaw, staked.amount - toWithdaw);
}
function isLocked(uint256 _now, uint256 _time, uint256 _duration) internal pure returns (bool) {
return _now >= _time + _duration ? false:true;
}
function stakedDetails(address _staker) public view returns (uint256, uint256, uint256, bool) {
Staked memory staked = stakedTokens[_staker];
return (staked.time,
staked.duration,
staked.amount,
isLocked(now, staked.time, staked.duration));
}
}
{
"compilationTarget": {
"KauriStaking.sol": "KauriStaking"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract ERC20","name":"_token","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","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":false,"internalType":"address","name":"stakedBy","type":"address"},{"indexed":false,"internalType":"address","name":"stakedFor","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remaining","type":"uint256"}],"name":"TokensUnstaked","type":"event"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"stakeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"stakeTokensFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"stakedDetails","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]