Fee transfers occur without owner consent and can be front-run
Description
The createBatchStream
and createStream
functions are used to create streams for the owner of NFTs. In case the NFTs are not owned by the caller of the functions, some fees are transferred to the address that originated the transaction:
function createStream(uint256 tokenId) external nonReentrant whenNotPaused {
require(block.number >= vestingStartBlock, "Vesting has not started yet");
require(claimedBlock[tokenId] == 0, "Stream already created");
claimedBlock[tokenId] = vestingStartBlock;
address onbehalfOf = credentialNFT.ownerOf(tokenId);
uint256 instantAmount = (allocationPerNFT * instantUnlockPercentage) / 100;
uint256 gasFee = 0;
if (tx.origin != onbehalfOf) {
gasFee = fee;
require(gasFee != 0, "Gas fee not set");
instantAmount -= gasFee;
transfer(tx.origin, gasFee);
}
transfer(onbehalfOf, instantAmount);
emit StreamCreated(tokenId, onbehalfOf, allocationPerNFT, gasFee);
}
If someone calls this function on behalf of the NFT owner before the owner does, they receive a fee (gasFee
) deducted from the owner's allocation (instantAmount
). This could reduce the owner's intended allocation without their consent.
Additionally, anyone monitoring the mempool could spot a transaction calling createBatchStream
or createStream
and propose an identical transaction with a higher gas fee to front-run it, capturing the fee for themselves.
Impact
The NFT owner's allocation is reduced without their consent, and the fee can be captured by generalized MEV bots.
Recommendations
Consider implementing a time window during which only the owner can call the functions. The owner must call the functions within a week (seven days or 86,400 blocks from vestingStartBlock
); otherwise, the function becomes open to any caller.