I'm trying to create an ERC20 Token that can send Tokens to a Receiver Contract similar to how ERC223 does and i decided to try ERC677 but i can't understand how to update this code to match Solidity 0.5>. I'm using the Draft from ERC677 repo at https://github.com/smartcontractkit/LinkToken
When i update the code to match Solidity 0.5.4, i get an error for payable address that can be found in ERC677Token contract > transferAndCall
at `super.transfer. The error i get is:
TypeError: Member "transfer" not found or not visible after argument-dependent lookup in address.
address(super).transfer(_to, _value);
What's wrong ? Do i need to make the ERC20 balances payable ?
ERC20 Token + ERC677:
pragma solidity ^0.5.4;
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) { return 0;}
uint256 c = a * b;
require(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0);
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
contract linkERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
contract linkERC20 is linkERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract ERC677 is linkERC20 {
function transferAndCall(address payable to, uint value, bytes memory data) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint value, bytes data);
}
contract ERC677Receiver {
function onTokenTransfer(address _sender, uint _value, bytes memory _data) public;
}
contract linkBasicToken is linkERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
contract linkStandardToken is linkERC20, linkBasicToken {
mapping (address => mapping (address => uint256)) allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
uint _allowance = allowed[_from][msg.sender];
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
// require (_value <= _allowance);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = _allowance.sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/*
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
*/
function increaseApproval (address _spender, uint _addedValue)
public returns (bool success) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval (address _spender, uint _subtractedValue)
public returns (bool success) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
contract ERC677Token is ERC677 {
/**
* @dev transfer token to a contract address with additional data if the recipient is a contact.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
* @param _data The extra data to be passed to the receiving contract.
*/
function transferAndCall(address payable _to, uint _value, bytes memory _data)
public
returns (bool success)
{
super.transfer(_to, _value);
Transfer(msg.sender, _to, _value, _data);
if (isContract(_to)) {
contractFallback(_to, _value, _data);
}
return true;
}
// PRIVATE
function contractFallback(address _to, uint _value, bytes memory _data)
private
{
ERC677Receiver receiver = ERC677Receiver(_to);
receiver.onTokenTransfer(msg.sender, _value, _data);
}
function isContract(address _addr)
private
returns (bool hasCode)
{
uint length;
assembly { length := extcodesize(_addr) }
return length > 0;
}
}
contract LinkToken is linkStandardToken, ERC677Token {
uint public constant totalSupply = 10**27;
string public constant name = 'ChainLink Token';
uint8 public constant decimals = 18;
string public constant symbol = 'LINK';
constructor() public {
balances[msg.sender] = totalSupply;
}
/**
* @dev transfer token to a specified address with additional data if the recipient is a contract.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
* @param _data The extra data to be passed to the receiving contract.
*/
function transferAndCall(address payable _to, uint _value, bytes memory _data)
public
validRecipient(_to)
returns (bool success)
{
return super.transferAndCall(_to, _value, _data);
}
/**
* @dev transfer token to a specified address.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint _value)
public
validRecipient(_to)
returns (bool success)
{
return super.transfer(_to, _value);
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value)
public
validRecipient(_spender)
returns (bool)
{
return super.approve(_spender, _value);
}
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value)
public
validRecipient(_to)
returns (bool)
{
return super.transferFrom(_from, _to, _value);
}
// MODIFIERS
modifier validRecipient(address _recipient) {
require(_recipient != address(0) && _recipient != address(this));
_;
}
}
contract Token677 is linkStandardToken, ERC677Token {
string public constant name = "Example ERC677 Token";
string public constant symbol = "ERC677";
uint8 public constant decimals = 18;
uint256 public totalSupply;
constructor(uint _initialBalance) public {
balances[msg.sender] = _initialBalance;
totalSupply = _initialBalance;
}
}
contract Token677ReceiverMock {
address public tokenSender;
uint public sentValue;
bytes public tokenData;
bool public calledFallback = false;
function onTokenTransfer(address _sender, uint _value, bytes memory _data)
public {
calledFallback = true;
tokenSender = _sender;
sentValue = _value;
tokenData = _data;
}
}
Hope someone is more knowledgeable and knows a safer way to approach this matter. I don't want to use standard ERC20 + proxy oracle that listens and updates after it receives events. I want to use something like ERC677 or ERC223. I'm open to hear pros and cons and best practices.
Thank you in advance !!!
Best Answer
Ended up with an ERC223 implementation :) Thanks !