How to Accept ERC20 tokens into a Smart Contract as Payment instead of Ether

payable function modifier provides a way to receive ethers in your smart contract. But what if you want to receive ERC20 Tokens into your smart contract. In this article, We will have a look at how you can do this.

In order to accept tokens into the contract, you need to import the token contract into your custom contract.

import "./ExampleToken.sol";

create a global variable to store the contract instance as shown below:

ExampleToken private token;

In the constructor of your contract, accept the address of the token contract, create a token contract instance and store it into the token variable as given below:

constructor(address _token) payable {
    owner = msg.sender;
    TokenAddress = _token;
    token = ExampleToken(_token);
}

Now create a function that is going to accept tokens as payment.

function AcceptTokens(uint256 _amount) public {
    token.transferFrom(msg.sender, address(this), amount);
}

In order to use the transferFrom(address _from,address _to, uint256 _amount) in AcceptTokens(uint256 _amount), we first need to first call approve(address _spender, uint256 _value) from the ERC20 Token contract. To learn more about this, you can read this Article.

const Web3 = require("web3");
const RPC_URL = 'place RPC URL here';
const token_abi = 'place token contract abi here';
const token_address = 'place token contract address here';
const smart_contract_address = 'place smart contract address here';
const smart_contract_abi = 'place smart contract abi here';
const web3 = new Web3(RPC_URL);

const admin_address = " place admin EOA address here";

// creating token contract and Custom Smart contract Instance
const tokenContractInstance = new web3.eth.contract({
    token_abi , token_address 
});
const smartContractInstance = new web3.eth.contract({
    smart_contract_abi , smart_contract_address 
});

//calling approve method from ERC20 token contract
const approve_reciept = await tokenContractInstance.methods
.approve(smart_contract_address, 10 )
.send({from : admin_address});

// calling AcceptTokens method from your custom smart contract.
const AcceptTokensReciept = await smartContractInstance.methods
.AcceptTokens(10)
.send({ from : admin_address });

In this way, you can receive tokens in your smart contract as payment. This flow is known as the withdrawal flow. But as you can correctly point out, this flow makes a dull user experience as the user needs to conduct two transactions to accomplish a single task. Batch transactions to the rescue. We can batch both of these transactions (approve method call and AcceptTokens method call). To learn more about this, you can have a look at this article.