How to use a token transfer function into another function ? [ ERC20 ]

Hello i wanna know what i need to do, i’m searching for a long time how to do the next

import './TokenERC20'; // contract A

contract Testing { // contract B

  function buyItem ( address _to , uint _itemPrice ) public {
  
    // Require Metamask alert saying "Token + gas"
    // Use a tokenTransfer here , like | transfer( _to , _itemPrice );
    // Get the item ( example )

  }

}

:computer: Environment
I am using , metamask , solidity , web3 all in lastest versions

:memo:Details
i really want to know how i can use the transfer function into another function asking me if i wanna transfer token and not gas , i know if i use only the transfer function i can do it , the problem for me is how to do that into another function , because wanna use a function that’s require a transfer before complete the item buy ( example ), the problem is with my code because i dont know how to say “when run this function do a transfer before complete the flow”

:1234: Code to reproduce
nothing because i dont know how to do , i trying another things but nothing works for me , i n all cases i have 2 response of the compiler :

  • 1 : The function dont say error but dont show Send Token in metamask
  • 2 : The code Says :

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? gas required exceeds allowance (10000000) or always failing transaction

i dont know what i need to do , help me please, documentation help me too :worried:

1 Like

Hi @kypanz,

In this case, we need to use transferFrom rather than transfer.

When an ERC20 token holder interacts with another contract using the token, two transactions are required:

  1. The token holder calls approve to set an allowance of tokens that the contract can use. (assuming an OpenZeppelin ERC20 implementation can use increaseAllowance)
  2. The token holder calls the contract to perform an action and the contract can transferFrom an amount of tokens within the set allowance.

https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20-transferFrom-address-address-uint256-
Moves amount tokens from sender to recipient using the allowance mechanism. amount is then deducted from the caller’s allowance.

1 Like

@abcoathup

thanks for the answer , im trying this now :

pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;

import "./ERC20Detailed.sol";
import './ERC20.sol';

contract TESTING is ERC20 , ERC20Detailed{
    
    constructor () public ERC20Detailed("SimpleToken", "SIM", 18) {
        _mint(_msgSender(), 10000 * (10 ** uint256(decimals())));
    }
    
    function buyItem ( address _to , uint _itemPrice ) public {
  
    // Require Metamask alert saying "Token + gas"
    transferFrom(msg.sender, _to , _itemPrice); // Error here
    // Use a tokenTransfer here , like | transfer( _to , _itemPrice );
    // Get the item ( example )
    
  }
    
    
}

when i run the buyItem function says :

## Gas estimation failed

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
gas required exceeds allowance (10000000) or always failing transaction

i am doing something wrong :tired_face:

1 Like

Hi @kypanz,

The token holder needs to call approve first, in a separate transaction on the token contract to set an allowance of tokens that the contract can use.

The Testing contract has an allowance of zero currently which is why this fails.

I can put together an example tomorrow if you need.

1 Like

Yess please, if you can , i wanna understand what i doing wrong , thanks again

1 Like

Hi @kypanz,

With ERC20, if we transfer an amount of tokens to a contracts address, the contract has no way of knowing that this occurred.

Instead we first need to approve an allowance for the recipient contract, then in a second transaction, a function we call in the contract can call transferFrom.

The following example consists of:

  • SimpleToken, an ERC20 token where all the tokens are pre-assigned to the creator of the contract.
  • SimpleTokenRecipient, a contract that charges tokens to perform an action (doStuff)
  • SimpleTokenRecipient.test.js, tests that check for performing an action when an allowance is approved, and for revert when attempting to perform an action when an allowance isn’t approved.

The test uses OpenZeppelin Test Environment and Test Helpers.

Let me know if you have any questions.

SimpleToken.sol

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";

/**
 * @title SimpleToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract SimpleToken is ERC20, ERC20Detailed {

    /**
     * @dev Constructor that gives msg.sender all of existing tokens.
     */
    constructor () public ERC20Detailed("SimpleToken", "SIM", 18) {
        _mint(msg.sender, 10000 * (10 ** uint256(decimals())));
    }
}

SimpleTokenRecipient.sol

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title SimpleTokenRecipient
 * @dev Very simple ERC20 Recipient
 */
contract SimpleTokenRecipient {

    IERC20 private _token;

    event DoneStuff(address from, address to, uint256 amount);

    constructor (address token) public {
        _token = IERC20(token);
    }

    function doStuff() external {
        address from = msg.sender;
        address to = address(this);
        uint256 amount = 1e18;

        _token.transferFrom(from, to, amount);
        emit DoneStuff(from, to, amount);
    }
}

SimpleTokenRecipient.test.js

const { accounts, contract } = require('@openzeppelin/test-environment');
const { expect } = require('chai');

const {
  BN,           // Big Number support
  constants,    // Common constants, like the zero address and largest integers
  expectEvent,  // Assertions for emitted events
  expectRevert, // Assertions for transactions that should fail
} = require('@openzeppelin/test-helpers');

const SimpleToken = contract.fromArtifact('SimpleToken');
const SimpleTokenRecipient = contract.fromArtifact('SimpleTokenRecipient');

describe('SimpleTokenRecipient', function () {
  const [ creator, holder ] = accounts;

  beforeEach(async function () {
    this.token = await SimpleToken.new({ from: creator });
    this.recipient = await SimpleTokenRecipient.new(this.token.address);

    this.tokenbits = new BN(10).pow(await this.token.decimals());
    await this.token.transfer(holder, new BN(100).mul(this.tokenbits), { from: creator });
  });

  it('do stuff', async function () {
    // token holder approves allowance
    await this.token.increaseAllowance(this.recipient.address, new BN(1).mul(this.tokenbits), { from: holder });

    // token holder gets recipient contract to do stuff
    await this.recipient.doStuff({ from: holder });

    // check balance of recipient contract
    expect(await this.token.balanceOf(this.recipient.address))
    .to.be.bignumber.equal(new BN(1).mul(this.tokenbits));
  });

  it('do stuff fails when allowance not approved', async function () {
    // transaction reverts when attempting to do stuff without approving an allowance
    await expectRevert(
      this.recipient.doStuff({ from: holder }),
      "ERC20: transfer amount exceeds allowance"
    );

    expect(await this.token.balanceOf(this.recipient.address))
    .to.be.bignumber.equal(new BN(0));
  });
});

Hi @kypanz,

Did the above example make sense? Let me know if you have questions.

A post was split to a new topic: Deploy ERC20 contract