Assignment - ERC20

Hey @mcgrane5

Few things to note:

  • Function mint is missing.

  • function transfer(address payable _to, uint256 _value)
    The _to address does not need to be payable.

  • When you declare a return variable in your function declaration such as returns (bool _success) you have to make sure to set the _success before returning, otherwise it will always return false. Example:

function test () public view returns (bool _success) {
        return _success;
    }

This always returns ‘false’.

    function test () public view returns (bool _success) {
        _success = true;
        return _success;
    }

This returns true.

Cheers,
Dani

1 Like

hey @dan-i
Thank you so much for the great advice, Oh great i wasnt aware we needed to code a mint function for that assignment but yes i may go back and add that in. Especially big thanks about the “returning bool _success” something small but i would not have noticed that myself and its obvioulsy quite important thank you for that. Will go back and make those changes ASAP.

Evan

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, "Owner does not have enough token balance to perform transaction");
      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(balances[_from] > _value, "Owner does not have enough token balance to perform transaction");
      require(allowed[_from][msg.sender] > _value, "The sender does not have approval to spend from this address");
      allowed[_from][msg.sender] -= _value;
      balances[_from] -= _value;
      balances[_to] += _value;
      emit Transfer(msg.sender,_to,_value);
      _success = true;
  }

}
1 Like
Token.sol
pragma solidity 0.8.0;

import "./SafeMath.sol";


contract Token {

  using SafeMath for uint256;
  

  string internal tokenName;


  string internal tokenSymbol;


  uint8 internal tokenDecimals;


  uint256 internal tokenTotalSupply;


  mapping (address => uint256) internal balances;

 
  mapping (address => mapping (address => uint256)) internal allowed;


  event Transfer(address indexed _from,address indexed _to,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;
  }


  function name() external view returns (string memory _name){
    _name = tokenName;
  }


  function symbol() external view returns (string memory _symbol){
    _symbol = tokenSymbol;
  }


  function decimals() external view returns (uint8 _decimals){
    _decimals = tokenDecimals;
  }


  function totalSupply()external view returns (uint256 _totalSupply){
    _totalSupply = tokenTotalSupply;
  }

 
  function balanceOf(address _owner) external view returns (uint256 _balance){
    _balance = balances[_owner];
  }

 
  function transfer(address payable _to, uint256 _value) public returns (bool _success){
      
      require(balances[msg.sender].sub(_value) >= 0, "");
      
      balances[msg.sender] = balances[msg.sender].sub(_value);
      balances[_to] = balances[_to].add(_value);
      
      emit Transfer(msg.sender, _to, _value);
     _success = true; 

  }   
  


  function approve(address _spender,uint256 _value) public returns (bool _success) {
      allowed[msg.sender][_spender] = _value;
      emit Approval(msg.sender, _spender, _value);
      _success = true;
    
  }

 
  function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
    _remaining = allowed[_owner][_spender];
  }

  
  function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    balances[_from].sub(_value);
    balances[_to].add(_value);

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

}

Ok, I’m stuck on the transfer function… the error i keep getting is:

transact to Token.transfer errored: VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

what the hell am I doing wrong…?

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 _to, uint256 _value) payable public returns (bool _success){
      require(balances[msg.sender] >= _value, "Insufficient Funds.");
      require(msg.sender != _to, "Cannot send your own cryptoassets to yourself.");
      balances[msg.sender] - _value;
      balances[_to] + _value;
      assert(balances[msg.sender] == balances[msg.sender] - _value);
     
  }
  
  //function _transfer(address _from, address _to, uint _value) private {
      //balances[_from] - _value;
      //balances[_to] + _value;
  //}

  /*
   * @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) {

  }

  /*
   * @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){

  }

}
1 Like

hey @William. Firstly the reason you get that error is because you have written an approve function, Therefore you cant transfer funds to any accounts as you dont have the permission. And thats the reason the transfer is getting reverted because you have insufficent balance since your not approved. You need to first write your approve function so that you can actually deposit funds into an account that you pass in to spend or send to another.

The approve function have a double maping which maps from the the msg.sender account and the spendsers account to some defined balance that the spender account is allowed to spend. Then when you have that mapping in your approve function you could say something like

allowed[msg.sender][spender] += value

then that person has authorisation to spend tokens and thus you can spend tokens with that account. Secondly in your transfer function you have written

balances[msg.sender] - _value;
balances[_to] + _value;

this should be

balances[msg.sender] -= _value;
balances[_to] += _value;

yoi need to add on the balance each time to the previous amount for the to address and subtratc the balnce each time for the msg.sender. Using + and - only will not work. you need += and -=. Once you address these two things you should be able to make a transfer. There maybe other bugs in your code but i have not looked thoroughly through it. Let me know if the transfer call works when you fix those two issues first.

3 Likes

cashback feature is dope… nice job

1 Like

Couple of notes -->

  1. I realize I created a “getBalance” function, when BalanceOf already existed.

  2. I imported SafeMath and definitely didn’t call anything from the library. Would some of the code I wrote (especially in the transfer/transferfrom functions) normally incorporate some of these safemath calls?

Question: In a live token contract on the ETH platform (or any platform), will the function allowance() automatically run (through code that automatically executes that?) or does someone literally have to manually input both “allowance()” and “approval()” arguments each time?

pragma solidity 0.8.0;

import "./SafeMath.sol";
import "./Ownable.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 _to, uint256 _value) payable public returns (bool _success){
      require(balances[msg.sender] >= _value, "Insufficient Funds.");
      require(msg.sender != _to, "Cannot send your own cryptoassets to yourself.");
      balances[msg.sender] = balances[msg.sender].sub(_value);
      balances[_to] = balances[_to].add(_value);
      emit Transfer(msg.sender, _to, _value);
     
  }

  /*
   * @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, "You don't have permission to do that.");
      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(_value <= balances[_from], "You don't have permission to do that.");
      require(_value <= allowed[_from][msg.sender], "Value amount is too high. Shit head");
      balances[_from] -= _value;
      balances[_to] += _value;
      allowed[_from][msg.sender] -= _value;
      emit Transfer(_from, _to, _value);
      return true;
  }
  
  function getBalance() public view returns (uint){
        return balances[msg.sender];
    }

}
1 Like

Hey William in regards to your safe math question. One of the earlier posts in this fourm shows that as of soldiity 0.8.0 safe math it automatically inherited so you dont have to use it if you dont want to. Perhaps its good practice but i personally dont use it now since solidity 0.8.0 implements it.

As for the second question you will see over the next few videos exactly how the allowance() /arrove() functions are actually implemented ina project. I think these are very much just learning excercises to get us used to the scope of openzeppelin and the general format of a good token contratts.

The way approve is used in the last project in this course is that you have a dex and you need to approve a token/their supply for your wllet to be used with the dex. Think of uniswap and how each time you transact with a new token it says “add this token to you metaMask wallet”. Its quite like thatt. But from what i understand the ERC20 contracts serve as a template if you will. Their functions can can be modified (inherited from) and changed or left out even depending on what the goal of your dapp is.

I imaginge when building dappps these backend functions dont have to be run over and over like your curious about because a front end would be set up in such a way where your just clicking buttons and many of the function calls are happening behind the scenes.

1 Like

very well explained. Thank you

1 Like

Think this works but not sure how to deploy the token in remix.

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);
        require(msg.sender != _to);
        
        
        balances[msg.sender].sub(_value);
        balances[_to].add(_value);
        
        
        _success = true;
        emit Transfer(msg.sender, _to, _value);
  }

  /*
   * @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 != msg.sender);
        require(balances[_spender] >= _value);
        
        allowed[msg.sender][_spender].add(_value);
        
        _success = true;
        
        emit Approval(msg.sender, _spender, _value);
  }

  /*
   * @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[msg.sender][_from] >= _value);
      require(_from != msg.sender);
      
      balances[_from].sub(_value);
      balances[_to].add(_value);
     
      _success = true;
      
      emit Transfer(_from,_to,_value);

  }

}
1 Like

Hey guys here my code:

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,"Doesn't have sufficient balance");
      require(msg.sender != _to,"Sender address can not be same as recipient address!");
      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 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,"Sender address & spender address can't be same!");
      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 balance!");
     require(allowed[_from][msg.sender] >= _value);
     balances[_from]= balances[_from].sub(_value); 
     balances[_to]= balances[_to].add(_value);
     allowed[_from][msg.sender] -= _value;
     emit Transfer(_from, _to, _value);
     _success = true;
    
    
  }

}
1 Like

For Ethereum programming 201, you should be using truffle (if you havent reach that lesson yet, no worries, you will). With truffle you will be able to deploy your contracts using openzeppelin modules properly.

Carlos Z

Regarding approve function, I don’t understand how by just updating mapping we approve _spender to make a transfer? Please help me to understand that.

hey @Kamil37,
The allowed mapping simply maps and address to an address to a number. We can use this to ‘map’ a token holders address to a spenders address to some amount, hence the spenders address now has a certain allowance that they are able to spend of msg.senders tokens.

allowed[msg.sender][_spender] = value

this double mapping forges a relationship between the msg.sender and some token spender. In other words when we approve using this approval function, we are allowing the token spender to spend a certain number of msg.senders tokens`. The amount that they are allowed to spend is dictated by the amount passed into the approve function.

However this alone does not mean anything. In order for this to actually have an effect we need to make a requirement in the transferFrom function. By making a requirement in the transfer functionFrom function that the spender must have a allowance value greater than the amount of tokens we are trying to send, ultimately allows us to restrict the _spender to only be able to transfer an amount of tokens that is dictated to how much we set via the approve function,.

For example say we approve addressB to be able to spend 1000 of AddressA’s tokens. We initialise it like so

allowed[AddressA][AddressB] = 1000

Now say we, as AdressB want to send some of AddressA’s tokens to someone. The we can use the trasnsferFrom function. So remember that our allowance is set to 1000. so if we call the transfer function and try to trasnfer 2000 tokens we will get an error because this exceeds our balance

function transferFrom(AddressB, AddressC, 2000) public returns .......
//including this requirment prevents us from spending above your allowance
require(allowed[AddressA][AddressB] >= value;

this will throw an error because we do not have a large enough allowance. So remember that the double mapping establishes a relationship between a two addresses and some value. msg.sender is the address with the tokens, address _spender is the address we are approving to spend msg.senders tokens and the value is the amount of tokens we permit the _sender to spend. Hope this makes sense

2 Likes

This is what I didn’t get! I didn’t fully understand what Filip is saying about transferFrom, although he is very clear about that. It’s me, I noticed I make it, in my head, more confusing than it really is.

Thank you for that, it was very very helpful, I got it now and will try to finish that probably tomorrow when will get more time.

1 Like

Would that work? I don’t think I understand that fully, but I think I’m getting there :laughing:

function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
    
    require(_to == msg.sender);
    
    balances[_from] -= _value;
    balances[_to] += _value;
    allowed[_from][msg.sender] -= _value;
    
    emit Transfer(_from, _to, _value);
    _success = true;
    
  }
1 Like

hey @Kamil, yeah this looks nearly perfect the only thing you need to change is to add the requirment that the value being send is less than or equal to the allowance as we dont want the user to be able to transfer more than they are allowed to spend and lastly your requirment statment. Shoulld be != instead of == as we want to make sure that the sender of the funds is not transfering to him/herself.

//add this reqirment
require(allowed[_from][msg.sender] >= _value);

I thought we want sender to transfer funds to himself. I think I am confusing something again. I see it that way e.g.:
Your deploy the contract, than you allow another address (me) to be able to transfer tokens. Than I go and switch to my address which you allowed and transfer tokens to myself?

so in function transferFrom the _from have to be always address that have approved transfer but not necessarily address that deployed the contract?

1 Like