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