// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./Ownable.sol";
import "./Stakeable.sol";
contract ExabitsToken is Ownable,Stakeable {
/**
* The token needs the variables needed for the operation
*/
uint private _totalSupply;
uint private _totalCalculate;
uint8 private _decimals;
string private _symbol;
string private _name;
address private _calculateAddress;
/**
* _balances
*/
mapping (address => uint256) private _balances;
/**
* Transfer
*
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* _allowances is used to manage and control allownace
* An allowance is the right to use another accounts balance, or part of it
*/
mapping (address => mapping (address => uint256)) private _allowances;
/**
* Approval is emitted when a new Spender is approved to spend Tokens on
* the Owners account
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* _name:Token
* _short_symbol:Token
* token_decimals:Token decimals,default 18
* _totalSupply:Token Supply
*/
constructor(string memory token_name, string memory short_symbol, uint8 token_decimals, uint256 token_totalSupply,address calculateAddress){
_name = token_name;
_symbol = short_symbol;
_decimals = token_decimals;
_totalSupply = token_totalSupply;
_totalCalculate = token_totalSupply * 1 / 10;
_calculateAddress = calculateAddress;
// Add all tokens created to the creator of the token
_balances[msg.sender] = _totalSupply - _totalCalculate;
_balances[calculateAddress] = _totalCalculate;
// A Transfer event is issued to notify the blockchain that it happened
emit Transfer(address(0), msg.sender, _totalSupply);
emit Transfer(address(0), _calculateAddress, _totalCalculate);
}
/**
* Get Token decimals
*/
function decimals() external view returns (uint8) {
return _decimals;
}
/**
* Get Token symbol
*/
function symbol() external view returns (string memory){
return _symbol;
}
/**
* Get Token Name
*/
function name() external view returns (string memory){
return _name;
}
/**
* Get Token totalSupply
*/
function totalSupply() external view returns (uint256){
return _totalSupply;
}
/**
* Get Token totalCalculate
*/
function totalCalculate() external view returns (uint256){
return _totalCalculate;
}
/**
* Returns the balance of the specified account
*/
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
/**
* Tokens will be created on the entered address and then the total supply will be increased
*
* It is required that the address receiving the token is not a zero address
*/
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ExabitsToken: cannot mint to zero address");
// mint
_totalSupply = _totalSupply + (amount);
// Add the amount to the account balance using the balance map
_balances[account] = _balances[account] + amount;
emit Transfer(address(0), account, amount);
}
/**
* The token will be destroyed from the entered address and then the total supply will be reduced
*
* Requires
* - Account cannot be zero
* - Account balance has to be bigger or equal to amount
*/
function _burn(address account, uint256 amount) internal {
require(account != address(0), "ExabitsToken: cannot burn from zero address");
require(_balances[account] >= amount, "ExabitsToken: Cannot burn more than the account owns");
// Remove the amount from the account balance
_balances[account] = _balances[account] - amount;
_totalSupply = _totalSupply - amount;
emit Transfer(account, address(0), amount);
}
/**
* burn is used to destroy tokens on an address
*
* See {_burn}
* Requires
* - msg.sender must be the token owner
*
*/
function burn(address account, uint256 amount) public onlyOwner returns(bool) {
_burn(account, amount);
return true;
}
/**
* mint is used to create tokens and assign them to msg.sender
*
* See {_mint}
* Requires
* - msg.sender must be the token owner
*
*/
function mint(address account, uint256 amount) public onlyOwner returns(bool) {
_mint(account, amount);
return true;
}
/**
* For money transfers: This function can only be called from outside the contract
* _transfer
*
* Requires
* - The caller cannot be zero
* - amount
*
*/
function transfer(address recipient, uint256 amount) external returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* For internal transfers
*
* Events
* - Transfer
*
* Requires
* - Sender
* - recipient
* - Sender
*/
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "ExabitsToken: transfer from zero address");
require(recipient != address(0), "ExabitsToken: transfer to zero address");
require(_balances[sender] >= amount, "ExabitsToken: cant transfer more than your account holds");
_balances[sender] = _balances[sender] - amount;
_balances[recipient] = _balances[recipient] + amount;
emit Transfer(sender, recipient, amount);
}
/**
* getOwner just calls Ownables owner function.
* returns owner of the token
*
*/
function getOwner() external view returns (address) {
return owner();
}
/**
* allowance is used view how much allowance an spender has
*/
function allowance(address owner, address spender) external view returns(uint256){
return _allowances[owner][spender];
}
/**
* approve will use the senders address and allow the spender to use X amount of tokens on his behalf
*/
function approve(address spender, uint256 amount) external returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* _approve is used to add a new Spender to a Owners account
*
* Events
* - {Approval}
*
* Requires
* - owner and spender cannot be zero address
*/
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "ExabitsToken: approve cannot be done from zero address");
require(spender != address(0), "ExabitsToken: approve cannot be to zero address");
// Set the allowance of the spender address at the Owner mapping over accounts to the amount
_allowances[owner][spender] = amount;
emit Approval(owner,spender,amount);
}
/**
* transferFrom is uesd to transfer Tokens from a Accounts allowance
* Spender address should be the token holder
*
* Requires
* - The caller must have a allowance = or bigger than the amount spending
*/
function transferFrom(address spender, address recipient, uint256 amount) external returns(bool){
// Make sure spender is allowed the amount
require(_allowances[spender][msg.sender] >= amount, "ExabitsToken: You cannot spend that much on this account");
// Transfer first
_transfer(spender, recipient, amount);
// Reduce current allowance so a user cannot respend
_approve(spender, msg.sender, _allowances[spender][msg.sender] - amount);
return true;
}
/**
* increaseAllowance
* Adds allowance to a account from the function caller address
*/
function increaseAllowance(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender]+amount);
return true;
}
/**
* decreaseAllowance
* Decrease the allowance on the account inputted from the caller address
*/
function decreaseAllowance(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender]-amount);
return true;
}
/**
* Add functionality like burn to the _stake afunction
*
*/
function stake(uint256 _amount,string memory stakeId) public {
// Make sure staker actually is good for it
require(_amount < _balances[msg.sender], "ExabitsToken: Cannot stake more than you own");
_stake(_amount,stakeId);
// Burn the amount of tokens on the sender
_burn(msg.sender, _amount);
}
/**
* withdrawStake is used to withdraw stakes from the account holder
*/
function withdrawStake(uint256 amount,string memory withdrawnId) public {
uint256 amount_to_mint = _withdrawStake(amount,withdrawnId);
// Return staked tokens to user
_mint(msg.sender, amount_to_mint);
}
function paymentStake(address payer ,uint256 amount,string memory paidId) public {
require(payer != address(0), "ExabitsToken: payment from zero address");
require(msg.sender == _calculateAddress, "ExabitsToken: only calculater can call this function");
uint256 amount_to_mint = _paymentStake(payer,amount,paidId);
// Return staked tokens to user
_mint(msg.sender, amount_to_mint);
}
function rewardStake(address payer,uint256 amount,string memory rewardId) public {
require(payer != address(0), "ExabitsToken: reward from zero address");
require(msg.sender == _calculateAddress, "ExabitsToken: only calculater can call this function");
uint256 amount_to_mint = _rewardStake(payer,amount,rewardId);
_mint(msg.sender, amount_to_mint);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* Contract is a inheritable smart contract that will add a
* New modifier called onlyOwner available in the smart contract inherting it
*
* onlyOwner makes a function only callable from the Token owner
*
*/
contract Ownable {
// _owner is the owner of the Token
address private _owner;
/**
* Event OwnershipTransferred is used to log that a ownership change of the token has occured
*/
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* Modifier
* We create our own function modifier called onlyOwner, it will Require the current owner to be
* the same as msg.sender
*/
modifier onlyOwner() {
require(_owner == msg.sender, "Ownable: only owner can call this function");
// This _; is not a TYPO, It is important for the compiler;
_;
}
constructor() {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @notice owner() returns the currently assigned owner of the Token
*
*/
function owner() public view returns(address) {
return _owner;
}
/**
* renounceOwnership will set the owner to zero address
* This will make the contract owner less, It will make ALL functions with
* onlyOwner no longer callable.
* There is no way of restoring the owner
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* transferOwnership will assign the {newOwner} as owner
*
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* _transferOwnership will assign the {newOwner} as owner
*
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* Stakeable is a contract who is ment to be inherited by other contract that wants Staking capabilities
*/
contract Stakeable {
/**
* Constructor since this contract is not ment to be used without inheritance
* push once to stakeholders for it to work proplerly
*/
constructor() {
// This push is needed so we avoid index 0 causing bug of index-1
}
uint private _currentRemaining;
/**
* stakes is used to keep track of the INDEX for the stakers in the stakes array
*/
mapping(address => uint256) internal stakes;
/**
* Staked event is triggered whenever a user stakes tokens
*/
event Staked(address indexed user, uint256 amount,string stakeId,uint remaining, uint256 timestamp);
/**
* Paid event is triggered whenever a user paid tokens
*/
event Paid(address indexed user, uint256 amount,string paidId,uint remaining, uint256 timestamp);
/**
* Withdrawn event is triggered whenever a user paid tokens
*/
event Withdrawn(address indexed user, uint256 amount,string paidId,uint remaining, uint256 timestamp);
/**
* Rewarded event is triggered whenever a user paid tokens
*/
event Rewarded(address indexed user, uint256 amount,string rewardedId,uint remaining, uint256 timestamp);
/**
* _Stake is used to make a stake for an sender. It will remove the amount staked from the stakers account and place those tokens inside a stake container
* StakeID
*/
function _stake(uint256 amount,string memory stakeId) internal{
// Simple check so that user does not stake 0
require(amount > 0, "Cannot stake nothing");
_currentRemaining = stakes[msg.sender];
stakes[msg.sender] = _currentRemaining + amount;
uint256 timestamp = block.timestamp;
// Emit an event that the stake has occured
emit Staked(msg.sender, amount,stakeId,_currentRemaining,timestamp);
}
function _paymentStake(address payer,uint256 amount,string memory paidId) internal returns(uint256){
require(amount > 0, "Cannot payment nothing");
require(stakes[payer] >= amount, "Payment: Cannot payment more than you have staked");
_currentRemaining = stakes[payer];
stakes[payer] = stakes[payer] - amount;
uint256 timestamp = block.timestamp;
emit Paid(payer, amount,paidId,_currentRemaining,timestamp);
return amount;
}
function _rewardStake(address payer,uint256 amount,string memory rewardId) internal returns(uint256){
require(amount > 0, "Cannot reward nothing");
_currentRemaining = stakes[payer];
stakes[payer] = stakes[payer] + amount;
uint256 timestamp = block.timestamp;
emit Rewarded(payer, amount,rewardId,_currentRemaining,timestamp);
return amount;
}
/**
* withdrawStake takes in an amount and a index of the stake and will remove tokens from that stake
* Will return the amount to MINT onto the acount
* Will also calculateStakeReward and reset timer
*/
function _withdrawStake(uint256 amount,string memory withdrawnId) internal returns(uint256){
require(stakes[msg.sender] >= amount, "Staking: Cannot withdraw more than you have staked");
uint256 timestamp = block.timestamp;
_currentRemaining = stakes[msg.sender];
stakes[msg.sender] = stakes[msg.sender] - amount;
emit Withdrawn(msg.sender, amount,withdrawnId,_currentRemaining,timestamp);
return amount;
}
/**
* stakeBalance is used to check if a account has stakes and the total amount along with all the seperate stakes
*/
function stakeBalance(address account) public view returns(uint256){
// totalStakeAmount is used to count total staked amount of the address
return stakes[account];
}
}
{
"compilationTarget": {
"ExabitsToken.sol": "ExabitsToken"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"token_name","type":"string"},{"internalType":"string","name":"short_symbol","type":"string"},{"internalType":"uint8","name":"token_decimals","type":"uint8"},{"internalType":"uint256","name":"token_totalSupply","type":"uint256"},{"internalType":"address","name":"calculateAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","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":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"paidId","type":"string"},{"indexed":false,"internalType":"uint256","name":"remaining","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Paid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"rewardedId","type":"string"},{"indexed":false,"internalType":"uint256","name":"remaining","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Rewarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"stakeId","type":"string"},{"indexed":false,"internalType":"uint256","name":"remaining","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"paidId","type":"string"},{"indexed":false,"internalType":"uint256","name":"remaining","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"payer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"paidId","type":"string"}],"name":"paymentStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"rewardId","type":"string"}],"name":"rewardStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"stakeId","type":"string"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"stakeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCalculate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"withdrawnId","type":"string"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]