Transfer amount exceeds allowance, but tokens are approved

I don't get why it doesn't work..... the logs show that the amount is approved.... yes it's easier to just use transfer() here, but shouldn't the aprove() + transferFrom() also work?

const usdc = (await getContractAt('@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', USDC_ADDRESS)) as unknown as IERC20;

await usdc.connect(user).approve(flashLoanReceiver.target, FEE_AMOUNT);

console.log(await usdc.allowance(user.address, flashLoanReceiver.target));
console.log(FEE_AMOUNT);

await usdc.transferFrom(user.address, flashLoanReceiver.target, FEE_AMOUNT);

Don't really use javascript to interact with contracts but might be able to point you in the right direction.

await usdc.connect(user).approve(flashLoanReceiver.target, FEE_AMOUNT); - this approves the flashLoanReceiver as a spender on behalf of user

await usdc.transferFrom(user.address, flashLoanReceiver.target, FEE_AMOUNT); - but then you are trying to transferFrom from some random account, not flashLoanReceiver.

probably should be something like: await usdc.connect(flashLoanReceiver).transferFrom(/*...*/)

You're missing the whole point in the approve/transferFrom scheme, which consists of the following two transactions:

  1. entity executes tokenContract.approve(someContract), in order to allow someContract to transfer funds from entity

  2. entity executes someContract.someFunc, which internally executes tokenContract.transferFrom(entity) in order to transfer funds from entity to somewhere (either to someContract itself, or to some other account)

Note that entity can be either an externally-owned account (aka wallet), or a smart-contract account.

In your case, since you're using the approve/transferFrom scheme from an off-chain script, entity has to be an externally-owned account of course.