Assignment - ERC20

Hey, here is my solution:

:blush:

pragma solidity 0.7.4;


contract DarkToken{
    
    
    address owner;
    
    // name of the token
    string internal tokenName;
    
    // symbol of the token
    string internal tokenSymbol;
    
    
    //set decimals
    uint decimal;
    
    // set total supply
    uint _totalSupply;
    
    //declare events
    event Transfer(address _from, address _to,uint _value);
    event Approval(address indexed _owner, address indexed _spender, uint _value);
    
    
    //balance information map
    mapping(address => uint)balance;
    
    //token allowance mapping
    mapping(address =>mapping(address => uint)) public allowed;
    
    
    
    constructor(){
        owner = msg.sender;
        tokenName = "Darkness";
        tokenSymbol = "DARK";
        decimal = 2;
       
    }
    
    function totalSupply() public view returns(uint _totalSupply){
         _totalSupply= 1000;
        return _totalSupply;
        
    }
    
    function name() public view returns(string memory _name){
        _name = tokenName;
        
        return _name;
    }
    
    function symbol() public view returns(string memory _symbol){
        _symbol = tokenSymbol;
        
        return _symbol;
    }
    
    
    
    function balanceOf(address _owner) public view returns(uint _balance){
        _balance = balance[msg.sender];
    }
    
    function transfer(address payable  _to, uint _value) public returns(bool success){
      
        require(balance[msg.sender] >= _value);
       balance[msg.sender] -= _value;
       balance[_to] += _value;
        
        emit  Transfer(msg.sender,_to,_value);
        
       
        
        return true;
    }
    
    
     function approve(address _spender,uint _value) external returns(bool success){
        
        allowed[msg.sender][_spender] = _value;
       emit Approval(msg.sender,_spender,_value);
       
       return true;
    }
    
     function allowance(address _owner,address _spender)external view returns(uint remiaingBalance){
        
        remiaingBalance = allowed[_owner][_spender];
        
    }
    
    function transferFrom(address _from, address _to, uint _value) external returns(bool success){
        require(balance[msg.sender] >= _value);
         require(allowed[_from][msg.sender] >= _value);
        balance[_from] -= _value;
        balance[_to] += _value;
        allowed[_from][msg.sender] -= _value;
        
        emit Transfer(msg.sender,_to,_value);
        
        return true;
        
      
    }
    
   
    
   
    
    
}
1 Like

Here is my code. Some require statements should be handled by modifiers, but for clarity I repeated them in the functions:

pragma solidity 0.8.0;

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);

  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
    require(balances[msg.sender]>=_value, 'Insufficient funds');
    balances[msg.sender]-=_value;
    balances[_to]+=_value;

    emit Transfer( msg.sender, _to, _value);
    _success = true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
      require(balances[msg.sender]>=_value, 'Insufficient funds');
      require(msg.sender != _spender, "Same address as function invoker");
      allowed[msg.sender][_spender] = _value;
      emit Approval(msg.sender, _spender, _value);
      _success = true;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(balances[_from] >= _value, "Insufficient funds");
    require(allowed[_from][msg.sender]>=_value, "Not allowed transfer the requested amount");
    
    // Effects first
    allowed[_from][msg.sender]-=_value;

    // Interactions second
    balances[_from]-=_value;
    balances[_to]+=_value;
    
    emit Transfer( _from, _to, _value);
    
    _success = true;
    
  }

}

@dan-i One question, in the transfer function from the skeleton code, since we do not transfer ETH, isnā€™t the declaration of the address as payable unnecessary?
Thanks.

Good job with the safe math stuff! very informative!

Hereā€™s my assignment! I hope Iā€™m correct haha

pragma solidity 0.8.0;

import "./safemath.sol";

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
    
    using SafeMath for uint256;
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
    require(balances[msg.sender] >= _value, "Not enough tokens");
    require(msg.sender != _to, "Do not send tokens to yourself");
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
    require(balances[msg.sender] >= _value, "Not enough tokens");
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(balances[_from] >= _value, "Not enough tokens");
    require(allowed[_from][msg.sender] >= _value, "Insuficient allowed tokens"); //_from is owner's address, msg.sender is _spender
    balances[_from] = balances[_from].sub(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(_from, _to, _value);
    return true;
  }

}
2 Likes

Hey everyone, I was wondering if I did my homework right. I was trying to implement ā€œchecks-effects-interactions patternā€ at first to avoid re-entrancy attacks, but I got stuck on how it would connect to the approve function.

But I assume that this contract does not have to deal with an ā€œexternal callā€, so I think it is safe?? (given that my assumption is correct). Thanks everyone

1 Like

Hey @karips

@dan-i One question, in the transfer function from the skeleton code, since we do not transfer ETH, isnā€™t the declaration of the address as payable unnecessary?

Yes it is indeed.
Move ERC token just means change data in a mapping, no need for the function to be payable.

Wish you a great day!
Dani

1 Like

NOTE: Reviewing Filipā€™s code after posting this Iā€™ve realized this is some silly code I posted here. So read & consider with caution! Further notes below code.

All righty, hereā€™s the three functions (mostly) fully implemented. This was another great assignment, definitely took some thinking & problem solving.

I didnā€™t have a clever way to return the _success bool in the approve function, so Iā€™m going to see what Filip did. Didnā€™t seem critical to the execution of this code, although I imagine it will be in other contexts.

  function transfer(address payable _to, uint256 _value) public returns (bool _success){
      //CHECKS
    require(balances[msg.sender] >= _value,"transfer ERROR: Insufficient balance for transfer");
      //EFFECTS
    balances[msg.sender] -= _value;
      //INTERACTIONS
    (_success,) = _to.call{value: _value}("");
    emit Transfer(msg.sender,_to,_value);
  }
  function approve(address _spender,uint256 _value) public returns (bool _success) {
      //CHECKS, EFFECTS, INTERACTIONS
    require(balances[msg.sender] >= _value, "approve ERROR: Allowance greater than current balance");
    allowed[msg.sender][_spender] = _value;
     // (?) best way to return the _success bool?
    emit Approval(msg.sender,_spender,_value);
  }
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(_value <= allowed[_from][msg.sender], "transferFrom ERROR: Requires higher allowance for msg.sender");
    require(_value <= balances[_from], "transferFrom ERROR: Sender has insufficient balance.");
    allowed[_from][msg.sender] -= _value;
    balances[_from] -= _value;
    balances[_to] += _value;
    (_success,) = _to.call{value: _value}("");
    emit Transfer(_from,_to,_value);
  }

EDITā€” Okay, so I think Iā€™ve very unnecessarily used the _to.call{value: _value}(""); member of payable addresses ā€¦ perhaps that .call{}() is only for sending Ether value?

1 Like
pragma solidity 0.8.0;

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
        require(balances[msg.sender]>= _value, "Balance not sufficient");
        require(_to == address(_to),"Invalid address");
        balances[msg.sender] -= _value;
        balances[_to] += _value;
        emit Transfer(msg.sender, _to, _value);
        _success = true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
        require(_spender == address(_spender),"Invalid address");
        emit Approval(msg.sender, _spender, _value);
        allowed[msg.sender][ _spender] = _value;
        _success = true;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
        require(allowed[_from][ _to] >= _value, "Should be approved first");
        require(balances[_from] >= _value, "Balance not sufficient");
        balances[_from] -= _value;
        allowed[_from][_to] -= _value;
        balances[_to] += _value;
        emit Transfer(_from, _to, _value);
        _success = true;
  }

}
1 Like

First try, before sneak peek.
I had to make the allowance function public to make this work.

function transfer(address payable _to, uint256 _value) public returns (bool _success){
    require(balances[msg.sender] < _value, "Not enough balance!");
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
    _success;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    _success;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) public view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(allowance(_from, msg.sender) >= _value, "Spender allowed to transfer amount!");
    allowed[_from][msg.sender] -= _value;
    balances[_from] -= _value;
    balances[_to] += _value;
    emit Transfer(_from, _to, _value);
    _success;
  }

Hey @LaszloD

You are missing an important require statement in your transferFrom function :slight_smile:
What happens if the sender does not have enough funds?

Aw Man! :roll_eyes:
Ok hereā€™s that function again:

function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(balances[_from] >= _value);
    require(allowance(_from, msg.sender) >= _value, "Spender not allowed to transfer!");
    allowed[_from][msg.sender] -= _value;
    balances[_from] -= _value;
    balances[_to] += _value;
    emit Transfer(_from, _to, _value);
    _success;
  }
1 Like

Here is a part of the code - just the relevant functions filled out:

/*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
      require(balances[msg.sender] >= _value, "Balance not sufficient");
      require(msg.sender != _to, "Don't transfer money to yourself");
      
      balances[msg.sender] -= _value; //decrease sender balance by value
      balances[_to] += _value; //increase recipient balance by value
      
      emit Transfer(msg.sender, _to, _value); //emit the event upon succesful transfer
      return true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
      require(msg.sender != _spender, "Don't transfer money to yourself");
      
      allowed[msg.sender][_spender] = _value; //in the allowed mapping, set the relevant place equal to value
      
      emit Approval (msg.sender, _spender, _value);
      return true;

  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
      require(balances[_from] >= _value, "Balance not sufficient");
      require(_from != _to, "Don't transfer money to yourself");
      require(allowed[_from][_to] >= _value, "Transfer request exceeds allowance");
      
      balances[_from] -= _value; //decrease sender balance by value
      balances[_to] += _value; //increase recipient balance by value
      allowed[_from][_to] -= _value //decrease the allowance
      
      emit Transfer(_from, _to, _value); //emit the event upon succesful transfer
      return true;
  }

}
1 Like

Good job :slight_smile:

pragma solidity 0.8.0;
import "./Safemath.sol";

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
  /*
   * Use Safemath
   */
   using SafeMath for uint256;
  /*
   * Token name.
   */
  string internal tokenName;
  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
    require (balances[msg.sender] >= _value, "Balance not sufficient");
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[msg.sender].add(_value);
    emit Transfer(msg.sender, _to, _value);
    _success = true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
    (allowed[msg.sender][_spender] = _value, "You cannot approve yourself");
    emit Approval(msg.sender, _spender, _value);
    _success = true;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);
    
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    
    emit Transfer(_from, _to, _value);
    _success = true;
  }

}
1 Like
import "./SafeMath.sol";

contract ArtToken {
    
    using SafeMath for uint;
    
    string internal tokenName;
    string internal tokenSymbol;
    uint internal tokenDecimals;
    uint internal tokenTotalSupply;
    
    mapping (address => uint) internal balances;
    mapping (address => mapping (address => uint)) internal allowed;
    
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    event Transfer(address indexed from, address indexed to, uint tokens);
    
    constructor(string memory _name, string memory _sybol, uint _decimals, uint _initialOwnerBalance) {
        tokenName = _name;
        tokenSymbol = _sybol;
        tokenDecimals = _decimals;
        tokenTotalSupply = _initialOwnerBalance;
        balances[msg.sender] = _initialOwnerBalance;
    }
    
    function balanceOf(address tokenOwner) public view returns (uint) {
        return balances[tokenOwner];
    }
    
    function transfer(address payable receiver, uint numTokens) public returns (bool) {
        require(balances[msg.sender] >= numTokens);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender, receiver, numTokens);
        return true;
    }
    
    // Allows spender to withdraw from your account multiple times, up to the _value amount.
    // If this function is called again it overrites the current allowance with _value.
    function approve(address spender, uint numTokens) public returns (bool) {
        allowed[msg.sender][spender] = numTokens;
        emit Approval(msg.sender, spender, numTokens);
        return true;
    }
    
    // Returns the amount which spender is still allowed to withdraw from owner.
    function allowance(address tokenOwner, address spender) external view returns (uint remaining) {
        remaining = allowed[tokenOwner][spender];
    }

    // Transfer value amount of tokens from tokenOwner to address buyer
    function transferFrom(address tokenOwner, address buyer, uint numTokens) public returns (bool) {
        require(balances[tokenOwner] >= numTokens);
        require(allowed[tokenOwner][msg.sender] >= numTokens);
        
        balances[tokenOwner] = balances[tokenOwner].sub(numTokens);
        allowed[tokenOwner][msg.sender] = allowed[tokenOwner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(tokenOwner, buyer, numTokens);
        return true;
    }
}
1 Like

My code:

pragma solidity 0.8.3;

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
    require(balances[msg.sender] >= _value, "Insufficient balance");
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
    _success = true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
    allowed[msg.sender][_spender] = _value; 
    emit Approval(msg.sender, _spender, _value);
    _success = true;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    require(allowed[_from][msg.sender] >= _value && balances[_from] >= _value, "Insufficient balance");
    balances[_from] -= _value;
    balances[_to] += _value;
    allowed[_from][msg.sender] -= _value;
    _success = true;
  }
}
1 Like

Hi everyone, this amazing new token is not for sale

Best,
Matt

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.0;

import "./safemath.sol";

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
    
    using SafeMath for uint256;
    
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){

    require(balances[msg.sender] >= _value, "Unsufficient balance");
    
    balances[_to] = balances[_to].add(_value);
    balances[msg.sender] = balances[msg.sender].sub(_value);
    
    emit Transfer(msg.sender, _to, _value);
    
    _success = true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
      
      allowed[msg.sender][_spender] = _value;
      
      emit Approval(msg.sender, _spender, _value);
      
      _success = true;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
      
      // Check _from has allowed caller to spend
      require(allowed[_from][msg.sender] >= _value, "Unsufficient allowance");
      
      // Check _from has enough balance
      require(balances[_from] >= _value, "Unsufficient balance");
      
      balances[_to] = balances[_to].add(_value);
      balances[_from] = balances[_from].sub(_value);
      allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 
      
      emit Transfer(_from, _to, _value);
      
      _success = true;
  }

}
1 Like

Hi Everyone.

Here is as far as I got with the ERC20 code but I do not understand some things.

  • So I believe the 3 functions I have coded are working correctly, but I am not sure if I use the return value correctly for the boolean, because itā€™s returning _success false everytime, even for example when a transfer went through.

  • The second thing is regarding the approve function and the allowance. So the exercise says the following: If

    • this function is called again it overwrites the current allowance with _value.
      Does this allowance mean the amount we withdrawed or the allowance for the _owner address how much has remained there?

Thanks for the help as always!

pragma solidity 0.8.0;
import "/.SafeMath.sol";
/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
    using Safemath for uint256;
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
    require(balances[msg.sender] >= _value, "not enough tokens bro");
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(msg.sender, _to, _value);
    return _success;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
    require(balances[msg.sender] >= _value, "not enough tokens bro");
    allowed[msg.sender][_spender] = _value;
    balances[msg.sender] = balances[msg.sender].sub(_value);
    emit Approval(msg.sender, _spender, _value);
    return _success;
  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(_from, _to, _value);
    return _success;

  }

}

I made this way more difficult than it had to be. The Jump from etheruem 101 t0 201 introduced alot of new concepts and because I have no prior coding experince I got a lilttle confused, for example I wasnt sure if we were supposed to use safemath or not or wether we should use a variable during the transfer function to protect against fallback function attacks. After looking at the solution i was suprised to see how simple the answer was, a person dosnt even need to know how to read code to make a token!

pragma solidity 0.8.0;
import "./SafeMath.sol";
/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
    using  SafeMath for uint256;
  /*
   * Token name.
   */
  string internal tokenName;

  /*
   * Token symbol.
   */
  string internal tokenSymbol;

  /*
   * Number of decimals.
   */
  uint8 internal tokenDecimals;

  /*
   * Total supply of tokens.
   */
  uint256 internal tokenTotalSupply;

  /*
   * Balance information map.
   */
  mapping (address => uint256) internal balances;

  /*
   * Token allowance mapping.
   */
  mapping (address => mapping (address => uint256)) internal allowed;

  /*
   * @dev Trigger when tokens are transferred, including zero value transfers.
   */
  event Transfer(address indexed _from,address indexed _to,uint256 _value);

  /*
   * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
   */
  event Approval(address indexed _owner,address indexed _spender,uint256 _value);
  
  constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
      tokenName = _name;
      tokenSymbol = _symbol;
      tokenDecimals = _decimals;
      tokenTotalSupply = _initialOwnerBalance;
      balances[msg.sender] = _initialOwnerBalance;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory _name){
    _name = tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }

  /*
   * @dev Returns the number of decimals the token uses.
   */
  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }

  /*
   * @dev Returns the total token supply.
   */
  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

  /*
   * @dev Returns the account balance of another account with address _owner.
   * @param _owner The address from which the balance will be retrieved.
   */
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
require (balances[msg.sender]>_value,"Cant send what you dont have");
balances[msg.sender]-=(_value);
balances[_to]+=(_value);
emit Transfer(msg.sender, _to, _value);
return true;
  }

  /*
   * @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
  function approve(address _spender,uint256 _value) public returns (bool _success) {
    emit Approval (msg.sender, _spender,_value);
      allowed[msg.sender][_spender]=_value;
      return true;

  }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  /*
   * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
   * Transfer event.
   * @param _from The address of the sender.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
     
      require (balances[_from]>_value,"CANT SEND WHAT U AINT GOT!");
      balances[_from]-=(_value);
      balances[_to]+=(_value); 
      allowed[_from][_to]-=_value;
      emit Transfer(_from,_to,_value);
      return true;

  }

}

Hello there!

This was a bit tricky the first 20 minutes, but when I was going through the previous educational materials I reminded myself of both the SafeMath-contract and also the easy way of just changing the mapping values and creating double mappings :slight_smile:

Here is my solution to this assignment:

pragma solidity 0.8.0;
import "./re_safemath.sol";

/**
 * @title ERC20 standard token implementation.
 * @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
 */
contract Token {
    
    using SafeMath for uint;
    
    /*
    * Token name.
    */
    string internal tokenName;
    
    /*
    * Token symbol.
    */
    string internal tokenSymbol;
    
    /*
    * Number of decimals.
    */
    uint8 internal tokenDecimals;
    
    /*
    * Total supply of tokens.
    */
    uint256 internal tokenTotalSupply;
    
    /*
    * Balance information map.
    */
    mapping (address => uint256) internal balances;
    
    /*
    * Token allowance mapping.
    */
    mapping (address => mapping (address => uint256)) internal allowed;
    
    /*
    * @dev Trigger when tokens are transferred, including zero value transfers.
    */
    event Transfer(address indexed _from,address indexed _to,uint256 _value);
    
    /*
    * @dev Trigger on any successful call to approve(address _spender, uint256 _value).
    */
    event Approval(address indexed _owner,address indexed _spender,uint256 _value);
    
    constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
        tokenName = _name;
        tokenSymbol = _symbol;
        tokenDecimals = _decimals;
        tokenTotalSupply = _initialOwnerBalance;
        balances[msg.sender] = _initialOwnerBalance;
    }

    /*
    * @dev Returns the name of the token.
    */
    function name() external view returns (string memory _name){
        _name = tokenName;
    }
    
    /*
    * @dev Returns the symbol of the token.
    */
    function symbol() external view returns (string memory _symbol){
        _symbol = tokenSymbol;
    }
    
    /*
    * @dev Returns the number of decimals the token uses.
    */
    function decimals() external view returns (uint8 _decimals){
        _decimals = tokenDecimals;
    }
    
    /*
    * @dev Returns the total token supply.
    */
    function totalSupply()external view returns (uint256 _totalSupply){
        _totalSupply = tokenTotalSupply;
    }
    
    /*
    * @dev Returns the account balance of another account with address _owner.
    * @param _owner The address from which the balance will be retrieved.
    */
    function balanceOf(address _owner) external view returns (uint256 _balance){
        _balance = balances[_owner];
    }

  /*
   * @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
   * function SHOULD throw if the "from" account balance does not have enough tokens to spend.
   * @param _to The address of the recipient.
   * @param _value The amount of token to be transferred.
   */
   //event Transfer(address indexed _from,address indexed _to,uint256 _value);
    function transfer(address payable _to, uint256 _value) public returns (bool _success){
        require(balances[msg.sender] >= _value);
        
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        _success = true;
    }
  

  /*
   * @dev Allows _spender to withdraw/transfer from your account multiple times, up to the _value amount. If
   * this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
   * @param _spender The address of the account able to transfer the tokens.
   * @param _value The amount of tokens to be approved for transfer.
   */
   //event Approval(address indexed _owner,address indexed _spender,uint256 _value);
    function approve(address _spender,uint256 _value) public returns (bool _success) {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        _success = true;
    }

  /*
   * @dev Returns the amount which _spender is still allowed to withdraw from _owner.
   * @param _owner The address of the account owning tokens.
   * @param _spender The address of the account able to transfer the tokens.
   */
    function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
        _remaining = allowed[_owner][_spender];
    }
    
    /*
    * @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
    * Transfer event.
    * @param _from The address of the sender.
    * @param _to The address of the recipient.
    * @param _value The amount of token to be transferred.
    */
    //event Transfer(address indexed _from,address indexed _to,uint256 _value);
    function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
        require(balances[_from] >= _value);
        require(allowed[_from][msg.sender] >= _value);
        
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(_from, _to, _value);
        _success = true;
    }
    
}

Really good assignment! I like this one a lot :raised_hands:
Regards

1 Like