Summary
The safeTransferFrom function is commonly used to transfer tokens between addresses in a secure manner, especially when working with ERC-20 tokens. In Ethereum, for a contract to move tokens on behalf of an account, the account needs to approve the contract to spend a certain amount of tokens using the approve function but it doesn't seem to be as expected
Vulnerability Details
function distributeFees(uint256 _amount) external onlyManager {
uint256 tstTotal = getTstTotal();
if (tstTotal > 0) {
<------ @audit no approval function here!
IERC20(EUROs).safeTransferFrom(msg.sender, address(this), _amount);
for (uint256 i = 0; i < holders.length; i++) {
address _holder = holders[i];
positions[_holder].EUROs += _amount * positions[_holder].TST / tstTotal;
}
for (uint256 i = 0; i < pendingStakes.length; i++) {
pendingStakes[i].EUROs += _amount * pendingStakes[i].TST / tstTotal;
}
}
}
POC
interface IERC20 {
function safetransferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function safeApprove(address spender, uint256 amount) external returns (bool);
}
IERC20 public EUROs;
function unsafeTransfer(uint256 amount, address to) external {
EUROs.safeTransferFrom(msg.sender, to, amount);
}
In this example, the unsafeTransfer function attempts to transfer amount of EUROs from msg.sender to another address using EUROs.tsaferansferFrom. However, if msg.sender has not previously approved this contract to spend EUROs on its behalf using safeApprove, the transaction will revert.
Impact
Without proper approval using the approve function, attempts to transfer tokens using transferFrom may fail, resulting in reverted transactions. Users expecting successful token transfers could face unexpected errors.
Tools Used
Manual Review
Recommendations
function distributeFees(uint256 _amount) external onlyManager {
uint256 tstTotal = getTstTotal();
if (tstTotal > 0) {
+ IERC20(EUROs).safeApprove(address(this), _amount);
IERC20(EUROs).safeTransferFrom(address(this), _amount);
for (uint256 i = 0; i < holders.length; i++) {
address _holder = holders[i];
positions[_holder].EUROs += _amount * positions[_holder].TST / tstTotal;
}
for (uint256 i = 0; i < pendingStakes.length; i++) {
pendingStakes[i].EUROs += _amount * pendingStakes[i].TST / tstTotal;
}
}
}