ERC-20 Introduction — Part 3

Dejan Jovanovic
TheBlockchainHub
Published in
5 min readFeb 20, 2019

Token Transfer

There are two mechanisms for transferring tokens from one account to another. First case is simply using transfer() method. The transfer() method transfer the number of tokens from directly from message sender to specified another account. This method doesn’t make any checks on recipient address so all responsibility lays on sender to make sure that provided information is correct.

Let’s now explore the cases when interaction is between two smart contracts. Example will be based on service smart contract ServiceContract that is responsible for selling services to consumers. ServiceContract has method called provideService() that requires 10 SCT (ServiceContract Tokens) in order to operate.

The consumer has in his account 100 SCT. So, her is the two step process that needs to be executed. First step is that consumer provides approval for ServiceContract address to transfer required number of SCT tokens. The consume, in this case also a token holder call the method approve() to provide this information.

In our example consumers address is 0x2ff…….0004d21 and ServiceContract address is 0x98A…….98BBF8. From the allowance table above we can see that consumer has already sett allowance of 10 SCT for ServiceContract. Once this is done ServiceContract can transfer allocated tokens for the operation. So when consumer now calls method provideService(), provideService() will call transferFrom() method in order to transfer 10 SCT for the service. In the case that consumer do not have sufficient founds provideService() method will fail.

Important Notes: it is important to notice that allowances are preliminary one, “soft”, as both individual and cumulative allowances can exceed and address balance. Any contract using allowance() must consider the balance of the consumer, holder when calculating the number of tokens available to it.

Smart Contract service payments with tokens

In this section we are going to go over case when tokens are used to pay for a service provided by another smart contract.

For paying for service function in Ether code looks like this:

function processRequest(unit256 payload) public payable {
require(msg.value == 2 ether);
process(msg.sender, payload);
}

Unfortunately, in the case that we have our own token, this is not possible as payable is always in Ethers and can not be in amount of tokens. Instead consumer and service provide must communicate with ServiceContract in order to move tokens from consumer to service provider.

There are three different ways how to achieve this transfer:

1. approve() and transferFrom()

Bothe functions are part of the ERC-20 standard and should be part of any compliant token implementation. The role of the approve() method is to authorize a third party to transfer tokens from the sender’s account. For detail sequence diagram please see below diagram:

transferFrom() is called as a part of processRequest() implementation. Example implementation of the processRequest() method is:

function processRequest(unit256 payload) public payable {
require(tokenContract.transferFrom(msg.sender, address(this),
10));
process(msg.sender, payload);
}

2. approveAndCall()

Previous case requires two separate requests from the sender. In the case of approveAndCall() implementation, it allows sender to carry out the same work with a single transaction. Detail sequence diagram is shown below:

receiveApproval() method is called inside the implementation of approveAndCall() method implementation. This requires approveAndCall() methid to I be implemented as following:

function approveAndCall(address _recipient, uint256 _value, bytes _extraData){
approve(_recipient, _value);
TokenRecipient(_recipient).receiveApproval(msg.sender, _value,
address(this), _extraData);
}

The receiveApproval() method in the ServiceContract is as follows:

function receiveApproval(address _sender, uint256 _value,TokenContract _tokenContract, bytes _extraData){
require(_tokenContract == tokenContract);
require(tokenContract.transferFrom(_sender, address(this), 10));

unit256 payloadSize;
uint256 payload;

assembly{
payloadSize := mload(_extraData)
payload := mload(add(_extraData, 0x20))
}
payload = payload >> 8*(32 — payloadSize);
process(msg.sender, payload);
}

First line confirms that it is token contract that is calling this method. Second line of code obtains the required tokens. The rest of the code obtains the payload and calls the processing method.

There are few points that needs to be noticed with definition of approveAndCall() as it is not part of ERC-20 standard:

1. some token contracts do not support approveAndCall()

2. some token contracts only support a single hardcoded receiveApproval() method as the target of approveAndCall()

3. some token contracts support calling arbitrary service contract methods by adding the relevant method signature to the approveAndCall() transmitted by the sender

3. transferAndCall()

ERC-677 standard provides the alternative to approveAndCall() method called transferAndCall() method. transferAndCall() method carries out transfer() and then calls a function on the service contract. Following sequence diagram shows the detail of the interaction:

The transferAndCall() method implementation should look following:

function transferAndCall(address _recipient, uint256 _value, bytes _extraData){
transfer(_recipient, _value);
require(TokenRecipient(_recipient).tokenFallback(msg.sender,
_value,_extraData));
}

The tokenFallback() method implementation should look like this:

function tokenFallback(address _sender, uint256 _value, bytes _extraData)return (bool){
require(msg.sender == tokenContract);
require(_value == 10);
……
// implementation of the code what needs to be done
return true;
}

transferAndCall() method is a upgrade solution from approveAndCall() method. It provides similar functionality for less gas cost and lower complexity.

There are cases where this solution is not so good, for example when we have variable price of the transactions. In this case sender doesn’t know the cost of the price in advance as price can for example depend of the service demand.

Second case where this implementation presents the limitation is in the case of repeated transactions. An example of this as a gambling contract where multiple bets can be placed across different games. So instead of calling approve() method every time, sender could call it just once and save on gas.

Conclusion: each method presented here has benefits and drawbacks. When building a service contract that accepts tokens as payment it is important to clearly define requirements as this will allow proper selection of the method that best fits the contracts’s needs.

The Blockchain Hub is an inclusive education and innovation hub, with a strong network of diverse alumni from many industry verticals. Would you like to add your voice to ours, and have your articles featured in The Blockchain Hub? Just send us a note at content@theblockchainhub.com

Disclaimer: The views and opinions expressed in this article are those of the author. They do not purport to reflect the policies, views, opinions or positions of The Blockchain Hub, any other agency, entity, organization, employer or company.

--

--

Dejan Jovanovic
TheBlockchainHub

Seasoned executive, business and technology leader, entrepreneur, blockchain and smart contract expert