code-423n4 / 2023-12-revolutionprotocol-findings

3 stars 2 forks source link

Ether will get stuck in ERC20TokenEmitter #651

Closed c4-bot-4 closed 10 months ago

c4-bot-4 commented 10 months ago

Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/ERC20TokenEmitter.sol#L152-L230

Vulnerability details

ERC20TokenEmitter.sol:buyToken distributes the funds sent to purchase the tokens in the following way:

This leaves in the contract the remainder of funds, which is equal to:

((msg.value * 0.975) * creatorRateBps / 10_000) * (10_000 - entropyRateBps) / 10_000;

Given that there is no withdrawal mechanism to get this remainder out of the contract, the funds are stuck in the contract.

Impact

Ether will get stuck in the contract.

Proof of Concept

function testAuditBuyToken() public {
    uint256 creatorRate = 8_000; // 80%
    uint256 entropyRate = 4_000; // 40%

    // Setup
    vm.startPrank(address(dao));
    erc20TokenEmitter.setCreatorRateBps(creatorRate);
    erc20TokenEmitter.setEntropyRateBps(entropyRate);
    erc20TokenEmitter.setCreatorsAddress(address(80));
    vm.stopPrank();

    // Purchase data
    address[] memory recipients = new address[](1);
    recipients[0] = address(1);
    uint256[] memory bps = new uint256[](1);
    bps[0] = 10_000; // 100%
    uint256 valueSent = 1 ether;

    // Perform token purchase
    uint256 erc20TokenEmitterInitialBalance = address(erc20TokenEmitter).balance;
    vm.startPrank(address(this));
    erc20TokenEmitter.buyToken{ value: valueSent }(
        recipients,
        bps,
        IERC20TokenEmitter.ProtocolRewardAddresses({
            builder: address(0),
            purchaseReferral: address(0),
            deployer: address(0)
        })
    );

    // Distribution calculations
    uint256 rewardAmount = erc20TokenEmitter.computeTotalReward(valueSent);
    uint256 toPayTreasury = ((valueSent - rewardAmount) * (10_000 - creatorRate)) / 10_000;
    uint256 creatorDirectPayment = ((valueSent - rewardAmount - toPayTreasury) * entropyRate) / 10_000;
    uint256 valueLocked = valueSent - rewardAmount - toPayTreasury - creatorDirectPayment;

    assertEq(rewardAmount, 0.025 ether);
    assertEq(toPayTreasury, 0.195 ether);
    assertEq(toPayTreasury, erc20TokenEmitter.treasury().balance);
    assertEq(creatorDirectPayment, 0.312 ether);
    assertEq(creatorDirectPayment, erc20TokenEmitter.creatorsAddress().balance);
    assertEq(valueLocked, 0.468 ether);
    assertEq(valueLocked, address(erc20TokenEmitter).balance - erc20TokenEmitterInitialBalance);
}

Tools Used

Manual inspection.

Recommended Mitigation Steps

It is not clear who should be the recipient of the remainder of the funds. In any case, the solution would be to add the amount not distributed to the amounts sent to one of the existing recipients or send it to a new recipient.

Assessed type

ETH-Transfer

c4-pre-sort commented 10 months ago

raymondfam marked the issue as sufficient quality report

c4-pre-sort commented 10 months ago

raymondfam marked the issue as duplicate of #13

c4-pre-sort commented 10 months ago

raymondfam marked the issue as duplicate of #406

c4-judge commented 9 months ago

MarioPoneder marked the issue as satisfactory