eth-erc20/GiftableToken.sol

161 lines
5.5 KiB
Solidity
Raw Normal View History

2020-12-01 14:46:29 +01:00
pragma solidity ^0.6.12;
2020-11-17 19:23:57 +01:00
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
/*
* This is a MOCK token used for DEVELOPMENT PURPOSES ONLY.
* It allows anyone to freely mint tokens with themselves as beneficiaries
* Code is based on the ERC20Token contract from Bancor's contracts-solidity repository
*
* @dev ERC20 Standard Token implementation
*/
contract GiftableToken { //is IERC20Token, Utils {
//using SafeMath for uint256;
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
/**
* @dev triggered when tokens are transferred between wallets
*
* @param _from source address
* @param _to target address
* @param _value transfer amount
*/
event Transfer(address indexed _from, address indexed _to, uint256 _value);
/**
* @dev triggered when a wallet allows another wallet to transfer tokens from on its behalf
*
* @param _owner wallet that approves the allowance
* @param _spender wallet that receives the allowance
* @param _value allowance amount
*/
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event ChangedSupply(uint256 _oldTotal, uint256 _newTotal);
/**
* @dev initializes a new ERC20Token instance
*
* @param _name token name
* @param _symbol token symbol
* @param _decimals decimal points, for display purposes
* @param _initialSupply total supply of token units
*/
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _initialSupply) {
// validate input
require(bytes(_name).length > 0, "ERR_INVALID_NAME");
require(bytes(_symbol).length > 0, "ERR_INVALID_SYMBOL");
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _initialSupply;
balanceOf[msg.sender] = _initialSupply;
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
_validAddress(_address);
_;
}
// error message binary size optimization
function _validAddress(address _address) internal pure {
require(_address != address(0), "ERR_INVALID_ADDRESS");
}
function gift(address _to, uint256 _value)
public
virtual
validAddress(_to)
returns (bool)
{
totalSupply = totalSupply + _value;
uint256 oldSupply = balanceOf[_to];
balanceOf[_to] = balanceOf[_to] + _value;
emit ChangedSupply(oldSupply, balanceOf[_to]);
emit Transfer(address(0x00), _to, _value);
return true;
}
/**
* @dev transfers tokens to a given address
* throws on any error rather then return a false flag to minimize user errors
*
* @param _to target address
* @param _value transfer amount
*
* @return true if the transfer was successful, false if it wasn't
*/
function transfer(address _to, uint256 _value)
public
virtual
validAddress(_to)
returns (bool)
{
balanceOf[msg.sender] = balanceOf[msg.sender] - _value;
balanceOf[_to] = balanceOf[_to] + _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev transfers tokens to a given address on behalf of another address
* throws on any error rather then return a false flag to minimize user errors
*
* @param _from source address
* @param _to target address
* @param _value transfer amount
*
* @return true if the transfer was successful, false if it wasn't
*/
function transferFrom(address _from, address _to, uint256 _value)
public
virtual
validAddress(_from)
validAddress(_to)
returns (bool)
{
allowance[_from][msg.sender] = allowance[_from][msg.sender] - _value;
balanceOf[_from] = balanceOf[_from] - _value;
balanceOf[_to] = balanceOf[_to] + _value;
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev allows another account/contract to transfers tokens on behalf of the caller
* throws on any error rather then return a false flag to minimize user errors
*
* also, to minimize the risk of the approve/transferFrom attack vector
* (see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice
* in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value
*
* @param _spender approved address
* @param _value allowance amount
*
* @return true if the approval was successful, false if it wasn't
*/
function approve(address _spender, uint256 _value)
public
virtual
validAddress(_spender)
returns (bool)
{
// if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
require(_value == 0 || allowance[msg.sender][_spender] == 0, "ERR_INVALID_AMOUNT");
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
}