// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "forge-std/console.sol";
interface Token {
/// @param _owner The address from which the balance will be retrieved
/// @return balance the balance
function balanceOf(address _owner) external view returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transfer(
address _to,
uint256 _value
) external returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transferFrom(
address _from,
address _to,
uint256 _value
) external returns (bool success);
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return success Whether the approval was successful or not
function approve(
address _spender,
uint256 _value
) external returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return remaining Amount of remaining tokens allowed to spent
function allowance(
address _owner,
address _spender
) external view returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
}
contract Standard_Token is Token {
uint256 private constant MAX_UINT256 = 2 ** 256 - 1;
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowed;
uint256 public totalSupply;
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name; //fancy name: eg Simon Bucks
uint8 public decimals; //How many decimals to show.
string public symbol; //An identifier: eg SBX
constructor(
uint256 _initialAmount,
string memory _tokenName,
uint8 _decimalUnits,
string memory _tokenSymbol
) {
balances[msg.sender] = _initialAmount; // Give the creator all initial tokens
totalSupply = _initialAmount; // Update total supply
name = _tokenName; // Set the name for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
}
function transfer(
address _to,
uint256 _value
) public override returns (bool success) {
require(
balances[msg.sender] >= _value,
"token balance is lower than the value requested"
);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars
return true;
}
function transferFrom(
address _from,
address _to,
uint256 _value
) public override returns (bool success) {
uint256 allowance = allowed[_from][msg.sender];
require(
balances[_from] >= _value && allowance >= _value,
"token balance or allowance is lower than amount requested"
);
balances[_to] += _value;
balances[_from] -= _value;
if (allowance < MAX_UINT256) {
allowed[_from][msg.sender] -= _value;
}
emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars
return true;
}
function balanceOf(
address _owner
) public view override returns (uint256 balance) {
return balances[_owner];
}
function approve(
address _spender,
uint256 _value
) public override returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars
return true;
}
function allowance(
address _owner,
address _spender
) public view override returns (uint256 remaining) {
return allowed[_owner][_spender];
}
function mintToken(address _to, uint _amount) public {
balances[_to] += _amount;
}
}
contract Payment {
function transferERC20(
address _token,
address _to,
uint256 _amount
) public {
Token(_token).transferFrom(msg.sender, _to, _amount);
}
}
//////////////////////////////////////////// Test
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {Test, Vm} from "forge-std/Test.sol";
import "forge-std/console.sol";
import {Standard_Token, Payment} from "../src/HelloWorld.sol";
contract testSample is Test {
Standard_Token public _Standard_Token;
Payment public _Payment;
address private immutable SELLER = address(1);
address private constant BUYER = address(2);
function setUp() public {
_Standard_Token = new Standard_Token(0, "Token", 18, "Token");
_Payment = new Payment();
_Standard_Token.mintToken(SELLER, 10e18);
}
function testTransfer(address, address, uint) public {
// console user balance
console.log(
"balance of SELLER before",
_Standard_Token.balanceOf(SELLER)
);
// vm setup to seller account
vm.startPrank(SELLER);
// TX1, Approve
_Standard_Token.approve(address(_Payment), 5e18);
// TX2, Transfer
_Payment.transferERC20(address(_Standard_Token), address(0), 5e18);
console.log(
"balance of SELLER after",
_Standard_Token.balanceOf(SELLER)
);
}
}