First I'm deploying Cafe contract and get deployedId from it and then deploy CAFToken contract with deployedId of cafe contract. I've also added deploy script and test case, I guess everything is going correctly but somehow getting ERC20: insufficient allowance error while calling sendToken function. May be I miss something can you please guide me on this.
Cafe Contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Cafe is Ownable {
address public cafeToken;
function setCafeToken(address _cafeToken) public onlyOwner {
cafeToken = _cafeToken;
}
//send token to other receipent
function sendToken(address _receiverAddress, uint _tokenAmount) public {
require(_tokenAmount > 0, "token should be more than 0");
IERC20(cafeToken).transferFrom(
address(this),
_receiverAddress,
_tokenAmount
);
}
// Get rewards of user has 10 or more than 10 tokens
function getRewards() public returns (bool) {
require(
IERC20(cafeToken).balanceOf(msg.sender) >= 10,
"Not enough token for rewards!"
);
IERC20(cafeToken).transferFrom(msg.sender, address(this), 10);
return true;
}
}
Cafe Token Contract (ERC20 token)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CAFToken is ERC20 {
constructor(
uint256 initialSupply,
address cafeAddress
) ERC20("Cafe", "CAF") {
_mint(cafeAddress, initialSupply); // mint intial supply to cafe contract
}
}
Deploy script:
const { ethers } = require("hardhat");
const hre = require("hardhat");
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
async function main() {
const Cafe = await hre.ethers.getContractFactory("Cafe");
const cafeContract = await Cafe.deploy();
await cafeContract.deployed();
const Token = await hre.ethers.getContractFactory("CAFToken");
const cafeToken = await Token.deploy(
ethers.utils.parseEther("100000"),
cafeContract.address
);
await cafeToken.deployed();
console.log(`deployed to cafe contract ${cafeContract.address}`);
console.log("Token deployed to:", cafeToken.address);
/////////////// Verification ////////////////////
console.log("Wait for verifying...");
await delay(5000);
// verify cafe contract
await await hre.run("verify:verify", {
address: cafeContract.address,
constructorArguments: [],
contract: "contracts/Cafe.sol:Cafe",
});
// verify cafe token
await await hre.run("verify:verify", {
address: cafeToken.address,
constructorArguments: [
ethers.utils.parseEther("100000"),
cafeContract.address,
],
contract: "contracts/CAFToken.sol:CAFToken",
});
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Test case:
const { expect, assert } = require("chai");
const { ethers } = require("hardhat");
describe("Initial Test case", () => {
let cafeContract, cafeToken, accounts;
beforeEach(async () => {
const Cafe = await ethers.getContractFactory("Cafe");
cafeContract = await Cafe.deploy();
await cafeContract.deployed();
const Token = await ethers.getContractFactory("CAFToken");
cafeToken = await Token.deploy(
ethers.utils.parseEther("100000"),
cafeContract.address
);
await cafeToken.deployed();
accounts = await ethers.getSigners();
});
describe("first", async () => {
it("check", async () => {
// Before transaction initial logs and balances
console.log("Balance", await cafeToken.totalSupply());
// Send token to another address
await cafeContract.setCafeToken(cafeToken.address);
await cafeToken.allowance(cafeToken.address, cafeContract.address);
// Approve transaction
await cafeToken.approve(
cafeContract.address,
ethers.utils.parseEther("10000")
);
await cafeContract.sendToken(
accounts[1].address,
ethers.utils.parseEther("10")
);
// await token.transfer();
console.log("--after transaction--");
const balance11 = await cafeToken.balanceOf(accounts[1].address);
console.log("Balance-11", balance11.toString());
assert.equal(balance11.toString(), ethers.utils.parseEther("10"));
});
});
});
Best Answer
You're having this error because you didn't give allowance for your
transferFrom
to succeeds.transferFrom
works withapprove
.You can fix this by using
transfer
or by callingapprove
before usingtransferFrom
.Here's how the sendToken function should look:
or simply