Is it possible to call the erc20 approve function from another contract?

I’m trying to write a function that allows my contract to approve another contract to spend my contract’s erc20 token. The transaction is always failing however, and I’m not sure why.

The code is as simple as erc20Contract.approve(<spender-address>, 10000000)

:computer: Environment

Solidity 0.5.15
Buidler

:memo:Details

:1234: Code to reproduce

function approveOtherContract() external {
    IERC20(<token-address>).approve(<spender-address>, 100000000);
}
1 Like

Hi @michaelcohen716,

Yes we can.

I created the following example (using OpenZeppelin CLI)

Holder.sol

Holder of tokens

pragma solidity ^0.6.0;

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

contract Holder {
    function approveOtherContract(IERC20 token, address recipient) public {
        token.approve(recipient, 1e18);
    }

    function doStuff(Recipient recipient) public {
        recipient.doStuff();
    }
}

SimpleToken.sol

Simple ERC20 token

pragma solidity ^0.6.0;

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

contract SimpleToken is ERC20 {
    constructor(address holder) public ERC20("Simple Token", "SIM") {
        _mint(holder, 1000*10**uint256(decimals()));
    }
}

Recipient.sol

pragma solidity ^0.6.0;

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

contract Recipient {
    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);
    }
}

Deploy

Deploy Holder

$ npx oz deploy
✓ Compiled contracts with solc 0.6.6 (commit.6c089d02)
? Choose the kind of deployment regular
? Pick a network development
? Pick a contract to deploy Holder
✓ Deployed instance of Holder
0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab

Deploy SimpleToken where the total supply will be minted to the Holder contract

$ npx oz deploy
Nothing to compile, all contracts are up to date.
? Choose the kind of deployment regular
? Pick a network development
? Pick a contract to deploy SimpleToken
? holder: address: 0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
✓ Deployed instance of SimpleToken
0x5b1869D9A4C187F2EAa108f3062412ecf0526b24

Deploy the Recipient contract providing the SimpleToken address

$ npx oz deploy
Nothing to compile, all contracts are up to date.
? Choose the kind of deployment regular
? Pick a network development
? Pick a contract to deploy Recipient
? token: address: 0x5b1869D9A4C187F2EAa108f3062412ecf0526b24
✓ Deployed instance of Recipient
0xCfEB869F69431e42cdB54A4F4f105C19C080A601

Approve

Call Holder contract to approve an allowance for SimpleToken to Recipient contract

$ npx oz send-tx
? Pick a network development
? Pick an instance Holder at 0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
? Select which function approveOtherContract(token: address, recipient: address)
? token: address: 0x5b1869D9A4C187F2EAa108f3062412ecf0526b24
? recipient: address: 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
✓ Transaction successful. Transaction hash: 0xf130fe4378cd4b6c569ba073db1734216283ce529e53d6c9c5794813c4ec2a13

Allowance

Check the allowance that Holder has given Recipient

$ npx oz call
? Pick a network development
? Pick an instance SimpleToken at 0x5b1869D9A4C187F2EAa108f3062412ecf0526b24
? Select which function allowance(owner: address, spender: address)
? owner: address: 0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
? spender: address: 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
✓ Method 'allowance(address,address)' returned: 1000000000000000000
1000000000000000000

Do Stuff

Send transaction to Holder which calls Recipient which does stuff which requires an amount of SimpleToken

$ npx oz send-tx
? Pick a network development
? Pick an instance Holder at 0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
? Select which function doStuff(recipient: address)
? recipient: address: 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
✓ Transaction successful. Transaction hash: 0xb6c810825baf6060d47ba081078d7a5e6280faabf074dc7f22e9ac1bbbb7e429

Balance of Recipient

$ npx oz call
? Pick a network development
? Pick an instance SimpleToken at 0x5b1869D9A4C187F2EAa108f3062412ecf0526b24
? Select which function balanceOf(account: address)
? account: address: 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
✓ Method 'balanceOf(address)' returned: 1000000000000000000
1000000000000000000

thanks so much for this thorough answer @abcoathup. My code looks fairly similar to this so the bug must be elsewhere

1 Like

Hi @michaelcohen716,

Feel free to share code snippets here or try yourself with OpenZeppelin CLI.