codehawks-2023-08-sparkn-l12

[L-12] Organizers are not incentivized to deploy and distribute to winners causing that winners may not to be rewarded for a long time and force the protocol owner to manage the distribution

보고서

Summary

주최자가 빠르게 리워드를 분배해도 인센티브가 없고, 늦어도 패널티가 없다. 따라서 주최자가 의도적으로 리워드를 분배하지 않아 관리자가 대신 정산하도록 상황을 조장할 수 있다.

Keyword

dos

Vulnerability

주최자는 deployProxyAndDistribute 함수를 이용해 리워드를 분배한다. 여기에는 현지 시간이 컨테스트 종료 시간보다 큰지만 확인하며, 다른 제한 사항은 없다.

File: ProxyFactory.sol
127:     function deployProxyAndDistribute(bytes32 contestId, address implementation, bytes calldata data)
128:         public
129:         returns (address)
130:     {
131:         bytes32 salt = _calculateSalt(msg.sender, contestId, implementation);
132:         if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
133:         // can set close time to current time and end it immediately if organizer wish
134:         if (saltToCloseTime[salt] > block.timestamp) revert ProxyFactory__ContestIsNotClosed();
...
...

EXPIRATION_TIME(7일)이 지난 후에도 정산을 하지 않는다면 관리자가 끼어들어 리워드를 대신 정산할 수 있다.

File: ProxyFactory.sol
179:     function deployProxyAndDistributeByOwner(
180:         address organizer,
181:         bytes32 contestId,
182:         address implementation,
183:         bytes calldata data
184:     ) public onlyOwner returns (address) {
185:         bytes32 salt = _calculateSalt(organizer, contestId, implementation);
186:         if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
187:         if (saltToCloseTime[salt] + EXPIRATION_TIME > block.timestamp) revert ProxyFactory__ContestIsNotExpired();
...
...

주최자가 늦게 리워드 정산을 해도 아무 손해보는 것이 없다. 컨테스트가 마감되어도 시간 제한 없이 deployProxyAndDistribute를 호출할 수 있다. 또한 주최자에게는 토큰을 분배하여 얻는 인센티브가 없다. 따라서 악의적인 주최자는 직접 deployProxyAndDistribute를 호출하는 대신 관리자가 정산해주기를 무기한 기다릴 수 있다. 관리자가 중재하지 않는 한 유저들은 오랫동안 리워드를 받을 수 없다.

Impact

주최자가 의도적으로 리워드를 분배하지 않아 관리자가 리워드를 분배하게 한다.

Mitigation

EXPIRATION_TIME이 지나면 주최자의 리워드 분배 자격을 박탈한다. 또한, 주최자에게 패널티를 주거나 제때 분배하면 얻을 수 있는 인센티브를 주어야 한다.

    function deployProxyAndDistribute(bytes32 contestId, address implementation, bytes calldata data)
        public
        returns (address)
    {
        bytes32 salt = _calculateSalt(msg.sender, contestId, implementation);
        if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
        // can set close time to current time and end it immediately if organizer wish
        if (saltToCloseTime[salt] > block.timestamp) revert ProxyFactory__ContestIsNotClosed();
++      if (saltToCloseTime[salt] + EXPIRATION_TIME < block.timestamp) revert();
        address proxy = _deployProxy(msg.sender, contestId, implementation);
        _distribute(proxy, data);
        return proxy;
    }

tags: bughunting, sparkn, smart contract, solidity, dos, severity low