//////////////////////////////////////////
// PROJECT HYDRO
// Multi Chain Token
//////////////////////////////////////////
pragma solidity ^0.6.0;
contract Ownable {
address public owner;
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 transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
interface Raindrop {
function authenticate(address _sender, uint _value, uint _challenge, uint _partnerId) external;
}
interface tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes calldata _extraData) external;
}
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the token decimals.
*/
function decimals() external view returns (uint8);
/**
* @dev Returns the token symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the token name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address _owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract HydroToken is Ownable,IERC20 {
using SafeMath for uint256;
string public _name;
string public _symbol;
uint8 public _decimals; // Number of decimals of the smallest unit
uint public _totalSupply;
address public raindropAddress;
uint256 ratio;
uint256 public MAX_BURN= 100000000000000000; //0.1 hydro tokens
mapping (address => uint256) public balances;
// `allowed` tracks any extra transfer rights as in all ERC20 tokens
mapping (address => mapping (address => uint256)) public allowed;
mapping(address=>bool) public whitelistedDapps; //dapps that can burn tokens
//makes sure only dappstore apps can burn tokens
modifier onlyFromDapps(address _dapp){
require(whitelistedDapps[msg.sender]==true,'Hydro: Burn error');
_;
}
event dappBurned(address indexed _dapp, uint256 _amount );
////////////////
// Constructor
////////////////
/// @notice Constructor to create a HydroToken
constructor(uint256 _ratio) public {
_name='HYDRO TOKEN';
_symbol='HYDRO';
_decimals=18;
raindropAddress=address(0);
_totalSupply = (11111111111 * 10**18)/_ratio;
// Give the creator all initial tokens
balances[msg.sender] = _totalSupply;
ratio = _ratio;
emit Transfer(address(0), msg.sender, _totalSupply);
}
///////////////////
// ERC20 Methods
///////////////////
//transfers an amount of tokens from one account to another
//accepts two variables
function transfer(address _to, uint256 _amount) public override returns (bool success) {
doTransfer(msg.sender, _to, _amount);
return true;
}
/**
* @dev Returns the token symbol.
*/
function symbol() public override view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the token name.
*/
function name() public override view returns (string memory) {
return _name;
}
//transfers an amount of tokens from one account to another
//accepts three variables
function transferFrom(address _from, address _to, uint256 _amount
) public override returns (bool success) {
// The standard ERC 20 transferFrom functionality
require(allowed[_from][msg.sender] >= _amount);
allowed[_from][msg.sender] -= _amount;
doTransfer(_from, _to, _amount);
return true;
}
//allows the owner to change the MAX_BURN amount
function changeMaxBurn(uint256 _newBurn) public onlyOwner returns(uint256 ) {
MAX_BURN=_newBurn;
return (_newBurn);
}
//internal function to implement the transfer function and perform some safety checks
function doTransfer(address _from, address _to, uint _amount
) internal {
// Do not allow transfer to 0x0 or the token contract itself
require((_to != address(0)) && (_to != address(this)));
require(_amount <= balances[_from]);
balances[_from] = balances[_from].sub(_amount);
balances[_to] = balances[_to].add(_amount);
emit Transfer(_from, _to, _amount);
}
//returns balance of an address
function balanceOf(address _owner) public override view returns (uint256 balance) {
return balances[_owner];
}
//allows an address to approve another address to spend its tokens
function approve(address _spender, uint256 _amount) public override returns (bool success) {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender,0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
require((_amount == 0) || (allowed[msg.sender][_spender] == 0));
allowed[msg.sender][_spender] = _amount;
emit Approval(msg.sender, _spender, _amount);
return true;
}
//sends the approve function but with a data argument
function approveAndCall(address _spender, uint256 _value, bytes memory _extraData) public returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, address(this), _extraData);
return true;
}
}
/**
* @dev Returns the token decimals.
*/
function decimals() external view override returns (uint8) {
return _decimals;
}
//returns the allowance an address has granted a spender
function allowance(address _owner, address _spender
) public view override returns (uint256 remaining) {
return allowed[_owner][_spender];
}
//allows an owner to whitelist a dapp so it can burn tokens
function _whiteListDapp(address _dappAddress) public onlyOwner returns(bool){
whitelistedDapps[_dappAddress]=true;
return true;
}
//allows an owner to blacklist a dapp so it can stop burn tokens
function _blackListDapp(address _dappAddress) public onlyOwner returns(bool){
whitelistedDapps[_dappAddress]=false;
return false;
}
//returns current hydro totalSupply
function totalSupply() public view override returns (uint) {
return _totalSupply;
}
//allows the owner to set the Raindrop
function setRaindropAddress(address _raindrop) public onlyOwner {
raindropAddress = _raindrop;
}
//the main public burn function which uses the internal burn function
function burn(address _from,uint256 _value) external returns(uint burnAmount) {
_burn(_from,_value);
emit dappBurned(msg.sender,_value);
return(burnAmount);
}
function authenticate(uint _value, uint _challenge, uint _partnerId) public {
Raindrop raindrop = Raindrop(raindropAddress);
raindrop.authenticate(msg.sender, _value, _challenge, _partnerId);
doTransfer(msg.sender, owner, _value);
}
//internal burn function which makes sure that only whitelisted addresses can burn
function _burn(address account, uint256 amount) internal onlyFromDapps(msg.sender) {
require(account != address(0), "ERC20: burn from the zero address");
require(amount >= MAX_BURN,'ERC20: Exceeds maximum burn amount');
balances[account] = balances[account].sub(amount);
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
}
{
"compilationTarget": {
"HydroToken.sol": "HydroToken"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"_ratio","type":"uint256"}],"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":"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":"_dapp","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"dappBurned","type":"event"},{"inputs":[],"name":"MAX_BURN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_dappAddress","type":"address"}],"name":"_blackListDapp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_dappAddress","type":"address"}],"name":"_whiteListDapp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"remaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowed","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":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_challenge","type":"uint256"},{"internalType":"uint256","name":"_partnerId","type":"uint256"}],"name":"authenticate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"burnAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newBurn","type":"uint256"}],"name":"changeMaxBurn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","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":[],"name":"raindropAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_raindrop","type":"address"}],"name":"setRaindropAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedDapps","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]