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");
//example of longer version for updating balance
uint previousSenderBalance = balances[msg.sender];
balances[msg.sender]=previousSenderBalance-_value;
//example of shorter version for updating balance
balances[_to]+=_value;
emit Transfer(msg.sender,_to,_value);
assert(balances[msg.sender]==previousSenderBalance-_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) {
//double mapping. First key owner, then spender and amount
//order of mapping is also seen in function allowance bellow
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);
//3rd party who wants to spend (msg.sender) have to have the allowance from the _from address
require(allowed[_from][msg.sender]>=_value);
balances[_from]-=_value;
balances[_to]+=_value;
allowed[_from][msg.sender]-=_value;
emit Transfer(_from,_to,_value);
_success=true;
}
}
// SPDX-License-Identifier: UNLICENSED
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 allowedToSpend;
/*
* @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) {
return tokenName;
}
/*
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory Symbol) {
return tokenSymbol;
}
/*
* @dev Returns the number of decimals the token uses.
*/
function decimals() external view returns (uint8 Decimals) {
return tokenDecimals;
}
/*
* @dev Returns the total token supply.
*/
function totalSupply() external view returns (uint256 TotalSupply) {
return 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) {
return 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) external returns (bool Success) {
require(balances[msg.sender] >= _value, "You do not have enough tokens to spend");
require(msg.sender != _to, "You cannot transfer tokens to yourself");
_transfer(msg.sender, _to, _value);
emit Transfer(msg.sender, _to, _value);
return true;
}
function _transfer(address _from, address _to, uint256 _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) external returns (bool Success) {
require(msg.sender != _spender, "You cannot approve your own address");
allowedToSpend[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) {
return allowedToSpend[_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) external returns (bool Success) {
require(msg.sender == _from || allowedToSpend[_from][msg.sender] >= _value, "You are not allowed to spend for this address");
require(balances[_from] >= _value, "Owner does not have enough tokens");
_transfer(_from, _to, _value);
allowedToSpend[_from][msg.sender] -= _value; //Edit: Added after viewing solution
emit Transfer(_from, _to, _value);
return true;
}
}
This was fun to fill in, I was confused what the
transferFrom()
function would be used for as it appeared it could do the exact same thing as the transfer()
function with the benefit of also being used with the allowed
state variable, so I filled that in to be able to do both; after reviewing above answers I noticed that if I do this I’ll want to update the allowed
value, so that was added after my code was complete. Thanks everyone!
pragma solidity 0.8.7;
/**
* @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);
uint256 prevBalanceSender = balances[msg.sender];
uint256 prevBalanceTo = balances[_to];
_transfer(msg.sender, _to, _value);
assert(prevBalanceSender == balances[msg.sender] + _value);
assert(prevBalanceTo == 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){
// Unsure of the purpose of this function? Is it for the allowed state variable?
require(balances[_from] >= _value);
if (_from != msg.sender) {
require(allowed[_from][msg.sender] >= _value);
}
uint256 prevBalanceFrom = balances[_from];
uint256 prevBalanceTo = balances[_to];
_transfer(_from, _to, _value);
allowed[_from][msg.sender] -= _value; // added after reviewing previous answers
assert(prevBalanceFrom == balances[_from] + _value);
assert(prevBalanceTo == balances[_to] - _value);
emit Transfer(_from, _to, _value);
_success = true;
}
function _transfer(address _from, address _to, uint256 _amount) private {
balances[_from] -= _amount;
balances[_to] += _amount;
}
}
I used SafeMath
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;
....
function transfer(address payable _to, uint256 _value) public returns (bool _success){
require(balances[msg.sender] >= _value); //checks
balances[msg.sender] = balances[msg.sender].sub(_value); //effects
balances[_to] = balances[_to].add(_value); //effects
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(balances[_from] >= _value); //checks
require(allowed[_from][msg.sender] >= _value); //checks
balances[_from] = balances[_from].sub(_value); //effects
balances[_to] = balances[_to].add(_value); //effects
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); //effects
emit Transfer(_from, _to, _value);
return true;
}
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
Here’s the solution for the assignment!
pragma solidity 0.8.0;
import '../SafeMathCourse/SafeMath';
/**
* @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(balanceOf(msg.sender) >= _value, "Error: Balance not enough!");
require(_to != msg.sender, "Error: Cannot send to self!");
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) {
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(balanceOf(_from) >= _value, "Error: Address does not have enough balance!");
require(allowed[_from][msg.sender] >= _value, "Error: Amount more than approved!");
// Deducting allowed value of token transfer for sender/spender
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;
}
}
How BlockChain know what contract address we mean when we call e g Transfer()?
Hi all,
Here’s my solution.
Is there a solution where the code is more compact?
Please let me know!
pragma solidity 0.8.0;
/**
* @title ERC20 standard token implementation.
* @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
*/
import "./SafeMath.sol";
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(_value <= balances[msg.sender]);
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(_value <= balances[msg.sender]);
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]);
require(_value <= allowed[_from][msg.sender]);
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, msg.sender, _value);
return true;
}
}
Hello🤩
Here is my solution and happy learning in 2022!
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);
//return true
_success = true;
}
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender] [_spender] = _value;
emit Approval(msg.sender, _spender, _value);
//return true
_success = true;
}
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(balances[_from] >= _value);
require(allowed [_from] [msg.sender] >= _value);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from] [msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
//return true
_success = true;
}
}
pragma solidity 0.8.0;
// SPDX-License-Identifier: MIT
/**
* @title ERC20 standard token implementation.
* @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
*/
import "./Safemath.sol";
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 _owner,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) public returns (bool){
require(balances[msg.sender] >= _value, "You do not have enough tokens");
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, "You do not have enough tokens"); // this was invalid
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 _owner to address _to, and MUST fire the
* Transfer event.
* @param _owner The address of the sender. // this is confusing. Is this msg.sender?
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _owner, address _to, uint256 _value) public returns (bool _success){
require(allowed[_owner][msg.sender] >= _value, "Not enough allowance remaining");
require(balances[_owner] >= _value, "Not enough coins in source balance");
balances[_owner] = balances[_owner].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_owner][msg.sender] = allowed[_owner][msg.sender].sub(_value);
return true;
}
}
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(balance[msg.sender] >= _value, "Insufficient funds");
emit Transfer(msg.sender, _to, _value);
balance[msg.sender] -= _value;
balance[_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) {
allowed[msg.sender][_spender] = _value;
emit Approve(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(allowed[_from][msg.sender] >= _value, "Not allowed to spend");
require(balance[_from] >= _value, "Non-available funds");
balance[_from] -= _value;
balance[_to] += _value;
allowed[_from][msg.sender]-=_value;
emit Transfer(_from, _to, _value);
return true;
}
}
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"); // create the code for transfer()
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; // create the code for approve()
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, "You are not approved to make this transfer"); // create the code for transferFrom()
require(balances[_from] >= _value, "Balance not sufficient");
allowed[_from][msg.sender] = allowed[_from][msg.sender] - _value;
balances[_from] -= _value;
balances[_to] += _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
Transfer as a function or Event? any case the blockchain does not know it, you have to specify it on the code.
Carlos Z
Here is my solution. I have only amended the three empty functions as the scope of the exercise was limited to those.
I am not sure if my implementation of the return value “_success” makes any sense as it is, could you please check it out and let me know if there is any better / more useful way?
Many thanks in advance!
Click here to view the code
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, "The amount requested exceeds the address balance");
uint256 balanceBefore = balances[_to];
uint256 balancesSum = balances[msg.sender] + balances[_to]; // store the sum of the two balances for invariants checks
balances[_to] += _value;
balances[msg.sender] -= _value;
assert(balancesSum == (balances[msg.sender] + balances[_to]) );
assert(balanceBefore == (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, "The amount requested exceeds the address balance");
require(allowed[_from][msg.sender] >= _value, "The transfer amount exceeds the allowance");
uint256 balanceBefore = balances[_to]; // store the original balance of payee for invariants checks
uint256 balancesSum = balances[_from] + balances[_to]; // store the sum of the two balances for invariants checks
allowed[_from][msg.sender] -= _value; // reduce allowance by the amount being transferred
balances[_to] += _value;
balances[_from] -= _value;
assert(balancesSum == (balances[_from] + balances[_to]) );
assert(balanceBefore == (balances[_to] - _value) );
emit Transfer(_from, _to, _value);
_success=true;
}
}
Returned values might be need it in case you want to do something after triggering a function.
So there are 2 ways, the one you are using which is specifying the name of the returned value, or just return a variable type.
function balanceOf(address _owner) external view returns (uint256){
return balances[_owner];
}
Carlos Z
Might need some refactor.
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, "Insufficient Balance");
require(_to != msg.sender);
uint256 lastBalance = balances[msg.sender];
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
_success = lastBalance != balances[msg.sender];
}
/*
* @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, "Insufficient Amount");
require(allowed[_from][msg.sender] >= _value, "Insufficient Allowance");
require( _from != _to);
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;
}
}
Here is my solution:
//SPDX-License-Identifier: UNLICENSED
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 SimpleToken {
// not using SafeMath
// because of pragma 0.8 overflow handling
/*
* 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, "ERC20: Not enough tokens to spend");
require(_to != msg.sender, "ERC20: No self tx");
balances[msg.sender] -= _value;
balances[_to] += _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) {
allowed[msg.sender][_spender] = _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[_from][msg.sender] >= _value, "Not allowed to spend that much");
require(balances[_from] >= _value, "ERC20: Not enough tokens to spend");
require(_from != _to, "ERC20: No self txs");
allowed[_from][msg.sender] -= _value;
balances[_from] -= _value;
balances[_to] += _value;
_success = true;
emit Transfer(_from, _to, _value);
}
}
Hi, this is my code:
// SPDX-License-Identifier: GPL 3.0
pragma solidity 0.8.0;
contract ERC20Token {
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,
uint256 _initialOwnerBalance
) {
tokenName = _name;
tokenSymbol = _symbol;
tokenDecimals = _decimals;
tokenTotalSupply = _initialOwnerBalance;
balances[msg.sender] = _initialOwnerBalance;
}
function name() external view returns (string memory) {
return tokenName;
}
function symbol() external view returns (string memory) {
return tokenSymbol;
}
function decimals() external view returns (uint8) {
return tokenDecimals;
}
function totalSupply() external view returns (uint256) {
return tokenTotalSupply;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
balance = balances[_owner];
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf(msg.sender) >= _value, "The amount you enter is too large");
uint256 initialRecipientBalance = balances[_to];
_transfer(msg.sender, _to, _value);
success = balances[_to] == initialRecipientBalance + _value;
emit Transfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
uint256 initialAllowance = allowance(_from, msg.sender);
require(initialAllowance >= _value, "The amount you enter is too large");
require(balanceOf(_from) >= _value, "The balance of owner is insufficient");
allowed[_from][msg.sender] -= _value;
balances[_from] -= _value;
uint256 initialRecipientBalance = balances[_to];
balances[_to] += _value;
success = (allowed[_from][msg.sender] == initialAllowance - _value) && (balances[_to] == initialRecipientBalance + _value);
emit Transfer(_from, _to, _value);
}
function _transfer(address _from, address _to, uint256 _value) private {
balances[_from] -= _value;
balances[_to] += _value;
}
function approve(address _spender, uint256 _value) public returns (bool success) {
require(balanceOf(msg.sender) >= _value, "The amount you enter is too large");
uint256 initialAllowance = allowance(msg.sender, _spender);
allowed[msg.sender][_spender] = _value;
success = allowed[msg.sender][_spender] == initialAllowance + _value;
Approval(msg.sender, _spender, _value);
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
remaining = allowed[_owner][_spender];
}
}
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, "Not enough 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) {
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, "Not enough funds");
require(allowed[_from][msg.sender] >= _value, "Allowance limited");
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
A bit confused about the transferFrom function in this exercise and hoping someone can provide some clarification. As far as I understand transferFrom is used with the approval function as it gives someone the permission to spend your funds right? What confuses me though is who is the “from” and who is the “to” in the transferFrom?
For example, supposing I approve someone to spend my funds. That person can then use the transferFrom to send my funds to whomever he wants correct? So in the trasnferFrom function the “from” address is the person i have approved to spend my funds (not me) right? And the “to”/msg.sender" is where he is sending the funds i have given him the approval to spend? Or do i have something mixed up here?
Hey @Bitborn, hope you are well.
Indeed, inside the function body, the logic is very clear that it checks if the caller of the function, does have allowance to spent the tokens.
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
// if have any allowance, this will return a number that will be used to verify if the amount does not exceeds the allowance
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
unchecked {
_approve(sender, _msgSender(), currentAllowance - amount);
}
return true;
}
Taking this example, You approve my address to spend your DAI tokens (you will trigger approve()
in the DAI contract to approve my address to spent a certain amount of that token), then, I could call the transferFrom(YourAddress, myAddress, amount)
and I should be able to transfer me the allowed amount.
Same goes with contracts, you have to approve them to spent a certain amount of your token before they can transfer to them (the contract, let say you want to stake some DAI in aave)
Hope this helps.
Carlos Z