Original token contract
// contracts/TestToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor () ERC20("TestToken", "LNR") {
_mint(msg.sender, 1000000 * (10 ** uint256(decimals())));
_approve(address(this), msg.sender, totalSupply());
}
}
The secondary contract, which will have additional functionality.
// contracts/SecondaryContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract SecondaryContract is Initializable, AccessControlUpgradeable {
IERC20 public testToken;
function initialize (IERC20 _testToken) public initializer {
__AccessControl_init();
testToken = _testToken;
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function requestPayFromUser(uint256 _amount) external {
uint256 amount = _amount;
testToken.approve(msg.sender, amount);
testToken.approve(address(this), amount);
// Only have both here to test approving from both addresses,
// while during actual testing I used only one approve call.
testToken.transferFrom(msg.sender, address(this), amount);
}
}
Hello, I'm new to developing smart contracts and I have run into an issue while trying to test sending ERC20 minted tokens from a user to a contract. Ideally, what I am trying to do is to make it possible for the user to send tokens to a contract as payment for digital goods. However, I have not been able to successfully create a way where users can do this.
If I am using truffle, I can enter the console and enter
> const TestToken = await TestToken.deployed();
> await TestToken.approve([UserAddressHere], 1);
> await TestToken.transferFrom([UserAddressHere], [SecondaryContractAddress], 1);
Which will provide the transfer successfully. However, running this (seemingly same code; correct me if I'm wrong!) code within the secondary contract does not work and returns the error
"ERC20: transfer amount exceeds allowance".
I have tried this both through truffle console such as:
> const token = await TestToken.deployed();
> const secondContract = SecondaryContract.deployed();
> await secondContract.initialize(token.address);
> await secondContract.requestPayFromUser(1);
Also I have tried this on remix and achieved the same result.
I am not sure I understand how this works precisely. My assumptions were that while testing through Truffle or Remix, the transactions would auto-pay the gas fees, much like when migrating / deploying contracts or minting tokens. I assume that the user would have to approve this through metamask when initiating this function from the front-end application. Seeing as how this is not working, I guess I am wrong!
I have spent several hours trying to work this out, and I have not been able to find any answers that seem to answer my question exactly. So, I thought I should ask the community for help on this one.