Re-entrancy points
User control of execution mostly stems from the fact that users exercise full control over asset
and pipeToContract
in FNFTConfig
. Users control ValueLock
's oracle
and AddressLock
's trigger
, which can also lead to external, user-controlled calls.
Finally, it is important to keep in mind a callback is called on to
whenever an ERC1155
is minted. Although there are so many re-entrancy points, they're not directly exploitable as every external function is marked nonReentrant
.
Revest.sol
Revest.sol:{333, 354} - user controls fnftConfig.asset
333: IERC20(fnftConfig.asset).safeTransferFrom(_msgSender(), addressesProvider.getAdmin(), totalERC20Fee);
...
354: IERC20(fnftConfig.asset).safeTransferFrom(_msgSender(), vault, totalQuantity * fnftConfig.depositAmount);
Revest.sol:136 - user controls trigger
136: IAddressLock(trigger).createLock(fnftId, lockId, arguments);
Revest.sol:{203, 248} - user controls pipeToContract
203: IOutputReceiverV3(config.pipeToContract).handleTimelockExtensions(fnftId, endTime, msg.sender);
...
248: IOutputReceiverV3(fnft.pipeToContract).handleAdditionalDeposit(fnftId, amount, quantity, msg.sender);
Revest.sol:358-362 - ERC1155 _mint
executes callback on to
358: if(!isSingular) {
359: getFNFTHandler().mintBatchRec(recipients, quantities, fnftId, totalQuantity, '');
360: } else {
361: getFNFTHandler().mint(recipients[0], fnftId, quantities[0], '');
362: }
LockManager.sol
LockManager.sol:{60, 158} - user controls lock.valueLock.oracle
60: IOracleDispatch oracle = IOracleDispatch(lock.valueLock.oracle);
...
158: IOracleDispatch oracle = IOracleDispatch(lock.valueLock.oracle);
LockManager.sol:{121, 143} - user controls lock.addressLock
121: IAddressLock(addLock).isUnlockable(fnftId, lockId))
...
143: IAddressLock(lock.addressLock).isUnlockable(fnftId, fnftIdToLockId[fnftId])
TokenVault.sol
TokenVault.sol:{60, 104, 110, 229} - user controls asset
60: currentAmount = IERC20(asset).balanceOf(address(this));
...
104: IERC20(asset).safeTransfer(user, withdrawAmount);
...
110: IERC20(asset).safeTransfer(fnft.pipeToContract, withdrawAmount);
...
229: currentAmount = IERC20(fnfts[fnftId].asset).balanceOf(address(this));
TokenVault.sol:{114, 224} - user controls pipeToContract
114: IOutputReceiver(pipeTo).receiveRevestOutput(fnftId, asset, payable(user), quantity);
...
224: return IOutputReceiver(fnfts[fnftId].pipeToContract).getValue((fnftId));
FNFTHandler.sol (fnft-migration
branch)
FNFTHandler.sol:{106, 117} - user controls pipeToContract
106: IOutputReceiverV4(config.pipeToContract).onTransferFNFT(ids[0], operator, from, to, amounts[0], data);
...
117: IOutputReceiverV4(config.pipeToContract).onTransferFNFT(ids[i], operator, from, to, amounts[i], data);