When using tokens as utility tokens, we need to try for a good UX. Introducing purses and transactions to end users is a challenge, and it should be clear that the token holder requires ETH to send the token adding some friction to the process. The purpose of this EIP is to abstract the gas for end users, by introducing fees paid in tokens. Third parties can then carry on-chain transactions, pay for gas from the given transaction and get the token from that user.
Implementation proposal
On-chain operation (solidity)
/**
* @notice Submit a presigned transfer
* @param _signature bytes The signature, issued by the owner.
* @param _to address The address which you want to transfer to.
* @param _value uint256 The amount of tokens to be transferred.
* @param _fee uint256 The amount of tokens paid to msg.sender, by the owner.
* @param _nonce uint256 Presigned transaction number.
*/
function transferPreSigned(
bytes _signature,
address _to,
uint256 _value,
uint256 _fee,
uint256 _nonce
)
public
returns (bool)
{
require(_to != address(0));
require(signatures[_signature] == false);
bytes32 hashedTx = transferPreSignedHashing(address(this), _to, _value, _fee, _nonce);
address from = recover(hashedTx, _signature);
require(from != address(0));
balances[from] = balances[from].sub(_value).sub(_fee);
balances[_to] = balances[_to].add(_value);
balances[msg.sender] = balances[msg.sender].add(_fee);
signatures[_signature] = true;
Transfer(from, _to, _value);
Transfer(from, msg.sender, _fee);
TransferPreSigned(from, _to, msg.sender, _value, _fee);
return true;
}
/**
* @notice Hash (keccak256) of the payload used by transferPreSigned
* @param _token address The address of the token.
* @param _to address The address which you want to transfer to.
* @param _value uint256 The amount of tokens to be transferred.
* @param _fee uint256 The amount of tokens paid to msg.sender, by the owner.
* @param _nonce uint256 Presigned transaction number.
*/
function transferPreSignedHashing(
address _token,
address _to,
uint256 _value,
uint256 _fee,
uint256 _nonce
)
public
pure
returns (bytes32)
{
/* "48664c16": transferPreSignedHashing(address,address,address,uint256,uint256,uint256) */
return keccak256(bytes4(0x48664c16), _token, _to, _value, _fee, _nonce);
}
For full implementation Check here : https://github.com/OpenZeppelin/openzeppelin-solidity/pull/741