pragma solidity ^0.6.12; // 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) public { // 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; } }