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 _value <= (([msg.sender] balances) ("insufficient amount"));//amount associated with msg.sender account must be greater than _value
balances[msg.sender] -= _value;//subtracts _value amount from msg.sender account
balances[_to] += _value; //adds it to _to account
_success = true; //returns true if error is not thrown
emit Transfer (msg.sender, _to, _value);//throws event when funtion goes through
}
function approve (address _spender, uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;//allows _spender to withdraw multiple times up to _value amount - if done more than once, updates current allowance w _value
_success = true;//returns true if error is not thrown
emit Approval (msg.sender, _spender, _value);//throws event when funtion goes through
}
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
allowed[_owner][_spender] = _remaining; //returns remaining amount that _spender is allowed to withdraw
}
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(_value <= balances[_from]);//requires amount in _from address to be greater than _value
require(_value <= allowed[_from][msg.sender]);//requres amount in msg.sender address to be greater than _value (which is associated w _from address through 'allowed' double mapping
balances[_from] -= _value;//transfers _value from _from address
balances[_to] += _value;//transfers _value to _to address
allowed[_from][msg.sender] -= _value;//deducts _value amount from the total allowance amount
_success = true;//returns true if error is not thrown
emit Transfer(_from, _to, _value);//throws event when funtion goes through
}
}
// SPDX-License-Identifier: MIT
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);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
/*
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
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){
}
}
Here is my solution:
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] >= 0, "Error");
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
_success = true;
}
/*
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
_success = true;
}
/*
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
* @param _owner The address of the account owning tokens.
* @param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
* Transfer event.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(allowed[_from][msg.sender] >= 0);
require(allowed[_from][msg.sender] <= _value);
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
Summary
pragma solidity 0.8.0;
/**
* @title ERC20 standard token implementation.
* @dev Standard ERC20 token. This contract follows the implementation at https://goo.gl/mLbAPJ.
*/
contract Token {
/*
* Token name.
*/
string internal tokenName;
/*
* Token symbol.
*/
string internal tokenSymbol;
/*
* Number of decimals.
*/
uint8 internal tokenDecimals;
/*
* Total supply of tokens.
*/
uint256 internal tokenTotalSupply;
/*
* Balance information map.
*/
mapping (address => uint256) internal balances;
/*
* Token allowance mapping.
*/
mapping (address => mapping (address => uint256)) internal allowed;
/*
* @dev Trigger when tokens are transferred, including zero value transfers.
*/
event Transfer(address indexed _from,address indexed _to,uint256 _value);
/*
* @dev Trigger on any successful call to approve(address _spender, uint256 _value).
*/
event Approval(address indexed _owner,address indexed _spender,uint256 _value);
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
tokenName = _name;
tokenSymbol = _symbol;
tokenDecimals = _decimals;
tokenTotalSupply = _initialOwnerBalance;
balances[msg.sender] = _initialOwnerBalance;
}
/*
* @dev Returns the name of the token.
*/
function name() external view returns (string memory _name){
_name = tokenName;
}
/*
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory _symbol){
_symbol = tokenSymbol;
}
/*
* @dev Returns the number of decimals the token uses.
*/
function decimals() external view returns (uint8 _decimals){
_decimals = tokenDecimals;
}
/*
* @dev Returns the total token supply.
*/
function totalSupply()external view returns (uint256 _totalSupply){
_totalSupply = tokenTotalSupply;
}
/*
* @dev Returns the account balance of another account with address _owner.
* @param _owner The address from which the balance will be retrieved.
*/
function balanceOf(address _owner) external view returns (uint256 _balance){
_balance = balances[_owner];
}
/*
* @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
* function SHOULD throw if the "from" account balance does not have enough tokens to spend.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transfer(address payable _to, uint256 _value) public returns (bool _success){
require(balances[msg.sender] >= _value, "Insufficient tokens");
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
/*
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
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(allowed[_from][msg.sender] >= _value, "Amount exceeds spending limit");
require(balances[_from] >= _value, "Insufficient funds");
balances[_from] -= _value;
balances[_to] += _value;
emit Transfer(_from, _to, _value);
return true;
}
}
My code literally looks the same as Filips solution. First I tried emitting the transfer event even when the balance was too low cause it said in the text that the function MUST emit the event, but It seemed weird to emit an event then do revert().
pragma solidity 0.8.16;
/**
* @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);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
_success = true;
}
/*
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
_success = true;
}
/*
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
* @param _owner The address of the account owning tokens.
* @param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
* Transfer event.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(allowed[_from][msg.sender] >= _value);
balances[_from] -= _value;
balances[_to] += _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
oh I realised I missed a balance check in the transferFrom function
In the transfer function, we decrement and increment both balances without using .call
.
function transfer(address payable _to, uint256 _value) public returns (bool _success){
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
_success = true;
}
I donāt understand why we didnāt use it ? Is it safe ?
Here is my 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, "Not Enough Balance");
uint previousBalanceSender=balances[msg.sender];
uint previousBalanceReciever=balances[_to];
balances[_to]+=_value;
balances[msg.sender]-=_value;
assert((balances[msg.sender]==previousBalanceSender-_value)&&(balances[_to]==previousBalanceReciever+_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;
}
/*
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
* @param _owner The address of the account owning tokens.
* @param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
* Transfer event.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(allowed[_from][_to]>=_value, "Access denied, You are not approved to withdraw this amount");
require(balances[_from]>_value, "Access approved, but not enough funds in senders wallet");
uint previousBalanceFrom=balances[_from];
uint previousBlanaceTo=balances[_to];
balances[_from]-=_value;
balances[_to]+=_value;
allowed[_from][_to]-=_value;
assert((previousBalanceFrom-_value)==(balances[_from])&&(previousBlanaceTo+_value)==balances[_to]);
emit Approval(_to, _from, _value);
_success=true;
}
}
This is my code for the ERC20 Assignment:
// SPDX-License-Identifier: GPL-3.0
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 myToken {
/*
* Token name.
*/
string internal tokenName;
/*
* Token symbol.
*/
string internal tokenSymbol;
/*
* Number of decimals.
*/
uint8 internal tokenDecimals;
/*
* Total supply of tokens.
*/
uint256 internal tokenTotalSupply;
/*
* Balance information map.
*/
mapping (address => uint256) internal balances;
/*
* Token allowance mapping.
*/
mapping (address => mapping (address => uint256)) internal allowed;
/*
* @dev Trigger when tokens are transferred, including zero value transfers.
*/
event Transfer(address indexed _from,address indexed _to,uint256 _value);
/*
* @dev Trigger on any successful call to approve(address _spender, uint256 _value).
*/
event Approval(address indexed _owner,address indexed _spender,uint256 _value);
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
tokenName = _name;
tokenSymbol = _symbol;
tokenDecimals = _decimals;
tokenTotalSupply = _initialOwnerBalance;
balances[msg.sender] = _initialOwnerBalance;
}
/*
* @dev Returns the name of the token.
*/
function name() external view returns (string memory _name){
_name = tokenName;
}
/*
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory _symbol){
_symbol = tokenSymbol;
}
/*
* @dev Returns the number of decimals the token uses.
*/
function decimals() external view returns (uint8 _decimals){
_decimals = tokenDecimals;
}
/*
* @dev Returns the total token supply.
*/
function totalSupply()external view returns (uint256 _totalSupply){
_totalSupply = tokenTotalSupply;
}
/*
* @dev Returns the account balance of another account with address _owner.
* @param _owner The address from which the balance will be retrieved.
*/
function balanceOf(address _owner) external view returns (uint256 _balance){
_balance = balances[_owner];
}
/*
* @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
* function SHOULD throw if the "from" account balance does not have enough tokens to spend.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transfer(address payable _to, uint256 _value) public returns (bool _success){
require(balances[msg.sender] >= _value, "Insufficient funds in balance. Not possible to 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;
emit Approval(msg.sender, _spender, _value);
_success = true;
}
/*
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
* @param _owner The address of the account owning tokens.
* @param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
* Transfer event.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
Hereās my solution to the ERC20 token contract assignment:
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, "Token balance is not sufficient");
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
/*
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/*
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
* @param _owner The address of the account owning tokens.
* @param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
* Transfer event.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(balances[_from] >= _value, "Balance of owner is not sufficient");
require(allowed[_from][msg.sender] >= _value, "Allowed balance to spend is not sufficient");
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
}
I spent most of my time testing it in Remix. It was a bit of a challenge keeping an overview while changing multiple balances and addresses. But it was awesome exceeding the spender limit and getting the right error warning back (assuming my requirement statements are coded correctly ).
The approve function:
function approve(address spender, uint tokens)public returns (bool success) { allowed[msg.sender][spender] = tokens; Approval(msg.sender, spender, tokens); return true;}
And the transfer function:
function _transfer(address _from, address _to, uint _value) internal {
require(_to != address(0x0));
}
Sorry, not sure what you mean, could you detail it a little more?
Carlos Z
Hello Carlos,
My question is about this course : AssignementERC20
We will see the transfer function and my question is why we didnāt use the .call function to transfer the funds, I thought it was safer
Here is my code
// SPDX-License-Identifier: MIT
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 SampleToken {
using SafeMath for uint;
/*
* Token name.
*/
string internal tokenName;
/*
* Token symbol.
*/
string internal tokenSymbol;
/*
* Number of decimals.
*/
uint8 internal tokenDecimals;
/*
* Total supply of tokens.
*/
uint256 internal tokenTotalSupply;
/*
* Balance information map.
*/
mapping (address => uint256) internal balances;
/*
* Token allowance mapping.
*/
mapping (address => mapping (address => uint256)) internal allowed;
/*
* @dev Trigger when tokens are transferred, including zero value transfers.
*/
event Transfer(address indexed _from,address indexed _to,uint256 _value);
/*
* @dev Trigger on any successful call to approve(address _spender, uint256 _value).
*/
event Approval(address indexed _owner,address indexed _spender,uint256 _value);
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint _initialOwnerBalance) {
tokenName = _name;
tokenSymbol = _symbol;
tokenDecimals = _decimals;
tokenTotalSupply = _initialOwnerBalance;
balances[msg.sender] = _initialOwnerBalance;
}
/*
* @dev Returns the name of the token.
*/
function name() external view returns (string memory _name){
_name = tokenName;
}
/*
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory _symbol){
_symbol = tokenSymbol;
}
/*
* @dev Returns the number of decimals the token uses.
*/
function decimals() external view returns (uint8 _decimals){
_decimals = tokenDecimals;
}
/*
* @dev Returns the total token supply.
*/
function totalSupply()external view returns (uint256 _totalSupply){
_totalSupply = tokenTotalSupply;
}
/*
* @dev Returns the account balance of another account with address _owner.
* @param _owner The address from which the balance will be retrieved.
*/
function balanceOf(address _owner) external view returns (uint256 _balance){
_balance = balances[_owner];
}
/*
* @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event. The
* function SHOULD throw if the "from" account balance does not have enough tokens to spend.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transfer(address payable _to, uint256 _value) public returns (bool _success){
require(balances[msg.sender] >= _value, "Balance not suffiecient");
require(msg.sender != _to, "Do not transfer money to yourself");
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/*
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/*
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
* @param _owner The address of the account owning tokens.
* @param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
* Transfer event.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount of token to be transferred.
*/
function transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(balances[_from] >= _value);
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;
}
}
//SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
/**
* @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");
balances[msg.sender] = balances[msg.sender] - _value;
balances[_to] = 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, "Balance not sufficient");
require(allowed[_from][msg.sender] >= _value, "Approved allowance required");
balances[_from] = balances[_from] - _value;
balances[_to] = balances[_to] + _value;
allowed[_from][msg.sender] = allowed[_from][msg.sender] - _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
// SPDX-License-Identifier: MIT
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 name.
/*
- 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 balanceā);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
_success = true;
}
/*
- @dev Allows _spender to withdraw from your account multiple times, up to the _value amount. If
- this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
- @param _spender The address of the account able to transfer the tokens.
-
@param _value The amount of tokens to be approved for transfer.
*/
function approve(address _spender,uint256 _value) public returns (bool _success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
_success = true;
}
/*
- @dev Returns the amount which _spender is still allowed to withdraw from _owner.
- @param _owner The address of the account owning tokens.
-
@param _spender The address of the account able to transfer the tokens.
*/
function allowance(address _owner,address _spender) external view returns (uint256 _remaining){
_remaining = allowed[_owner][_spender];
}
/*
- @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the
- Transfer event.
- @param _from The address of the sender.
- @param _to The address of the recipient.
-
@param _value The amount of token to be transferred.
*/
function transferFrom(address _from, address _to,uint256 _value) public returns (bool _success){
require(balances[_from] >= _value);
require(allowed[_from][msg.sender] >= _value);
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
_success = true;
}
}
Yeap⦠didnāt use safeMath ā¦
function transfer(address payable _to, uint256 _value) public returns (bool _success){
require(balances[msg.sender] >= _value,"Not enough tokens to spend");
balances[msg.sender] -= _value;
balances[_to] += _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 transferFrom(address _from,address _to,uint256 _value) public returns (bool _success){
require(balances[_from] >= _value,"Not enough tokens to spend");
require(allowed[_from][msg.sender] >= _value,"Not enough tokens allowed");
allowed[_from][msg.sender] -= _value;
balances[_from] -= _value;
balances[_to]+= _value;
emit Transfer(_from, _to, _value);
_success = true;
}
thanks⦠I forgot to adjust the allowed
pragma solidity 0.8.0;
// SPDX-License-Identifier: UNLICENSED
/**
* @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 payable returns (bool _success){
require (_value <= balances[msg.sender]);
balances[msg.sender] -= (_value);
balances[_to] += (_value);
// assert (balances[msg.sender] == balances[msg.sender] - (_value));
// assert (balances[_to] == balances[_to] + (_value));
emit Transfer(msg.sender, _to, _value);
return true;
}
/*
* @dev Allows _spender to withdraw/transfer from your account multiple times, up to the _value amount. If
* this function is called again it overwrites the current allowance with _value. SHOULD emit the Approval event.
* @param _spender The address of the account able to transfer the tokens.
* @param _value The amount of tokens to be approved for transfer.
*/
function approve (address _spender,uint256 _value) public returns (bool _success) {
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]);
require(_to != address(0));
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] = allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
// function transferFrom(address from, address to, uint256 value) public returns (bool){
// require(value <= _balances[from]);
// require(value <= _allowed[from][msg.sender]);
// require(to != address(0));
// _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;
// }
}
QQ - how come the ā=ā is required?
Why canāt it work like this?: balances[_from] - _value; & balances[_to] + _value;