codehawks-2023-08-sparkn-l08
[L-08] DAI Tokens at Risk Due to Lack of address(0) Check in distribute
Summary
DAI는 address(0)로 토큰을 전송하는 것을 막지 않기 때문에, 수상자 주소에 address(0)가 포함되어 있다면 DAI 토큰이 영구적으로 손실될 수 있다.
Keyword
lack of input validation, transfer to address(0), asset lock
Vulnerability
USDC나 USDT의 경우 토큰 자체에서 address(0)로 보내는 것을 막는다. 하지만 DAI 토큰의 경우 address(0) 로 토큰을 전송할 수 있다.
DAI 토큰 소스코드를 보면, address(0)로 토큰을 전송하는 것을 막지 않음을 확인할 수 있다.
function transfer(address dst, uint wad) external returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public returns (bool)
{
require(balanceOf[src] >= wad, "Dai/insufficient-balance");
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance");
allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
}
balanceOf[src] = sub(balanceOf[src], wad);
balanceOf[dst] = add(balanceOf[dst], wad);
emit Transfer(src, dst, wad);
return true;
}리워드를 분배하는 _distribute 함수에서는 수상자가 address(0)인지 아닌지를 확인하지 않는다. 따라서 수상자 주소에 address(0)가 포함되어 있다면 DAI 토큰이 영구적으로 손실될 수 있다.
function _distribute(address token, address[] memory winners, uint256[] memory percentages, bytes memory data)
internal
{
// token address input check
if (token == address(0)) revert Distributor__NoZeroAddress();
if (!_isWhiteListed(token)) {
revert Distributor__InvalidTokenAddress();
}
// winners and percentages input check
if (winners.length == 0 || winners.length != percentages.length) revert Distributor__MismatchedArrays();
uint256 percentagesLength = percentages.length;
uint256 totalPercentage;
for (uint256 i; i < percentagesLength;) {
totalPercentage += percentages[i];
unchecked {
++i;
}
}
// check if totalPercentage is correct
if (totalPercentage != (10000 - COMMISSION_FEE)) {
revert Distributor__MismatchedPercentages();
}
IERC20 erc20 = IERC20(token);
uint256 totalAmount = erc20.balanceOf(address(this));
// if there is no token to distribute, then revert
if (totalAmount == 0) revert Distributor__NoTokenToDistribute();
uint256 winnersLength = winners.length; // cache length
for (uint256 i; i < winnersLength;) {
uint256 amount = totalAmount * percentages[i] / BASIS_POINTS;
erc20.safeTransfer(winners[i], amount);
unchecked {
++i;
}
}
// send commission fee as well as all the remaining tokens to STADIUM_ADDRESS to avoid dust remaining
_commissionTransfer(erc20);
emit Distributed(token, winners, percentages, data);
}DAI는 프로토콜 개발자가 이용한다고 예시로 든 토큰 중 하나이므로 특별히 주의를 기울일 필요가 있다.
Impact
수상자 주소에 address(0)가 포함되어 있다면 DAI 토큰이 영구적으로 손실될 수 있다.
Mitigation
수상자 중 address(0)가 있는지 확인한다.
tags: bughunting, sparkn, smart contract, solidity, lack-of-input-validation-vul, erc20, transfer to address(0), asset lock, severity low