RebateFi Hook

First Flight #53
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: low
Invalid

Using the illegitimate 1,000,000 minted ReFi tokens for the owner in the constructor, they can drain the pool

Root + Impact

Description

  • In the ReFi::constructor function, 1,000,000 tokens are minted to the owner. Since it neither is mentioned in the description of the protocol nor in the Natspec of the constructor, I assume it is done mistakenly.

  • It makes a means of fraud for the owner because they can easily swap the ReFi tokens for some other ERC20 token and drain the pool.

constructor() ERC20("RebateFi", "ReFi") Ownable(msg.sender) {
@> _mint(msg.sender, 1_000_000 * 10 ** decimals());
}

Risk

Likelihood: Low

  • Assuming the owner is trustworthy and they care about the continuity of the business, it is less likely to happen.


Impact: High

  • However, if they decide to do so, it will severly disrupt the protocol's functionality or may even completely wreck it.

Proof of Concept

Please copy/paste the following test function in the test file, and run it.

function test_OwnerCanDrainEthFromPool() public {
//Arrange
uint256 ethAmount = 100 ether;
vm.deal(user1, 1000 ether);
vm.startPrank(user1);
SwapParams memory params = SwapParams({
zeroForOne: true,
amountSpecified: int256(ethAmount),
sqrtPriceLimitX96: TickMath.MIN_SQRT_PRICE + 1
});
PoolSwapTest.TestSettings memory testSettings = PoolSwapTest
.TestSettings({takeClaims: false, settleUsingBurn: false});
// user1 pays ETH and buys the token
swapRouter.swap{value: ethAmount}(key, params, testSettings, ZERO_BYTES);
vm.stopPrank();
address owner = address(this);
uint256 ownerBalanceBefore = owner.balance;
uint256 reFiAmount = 100 ether;
// Act
vm.startPrank(owner);
reFiToken.approve(address(rebateHook), type(uint256).max);
params = SwapParams({
zeroForOne: false, // ReFi -> ETH
amountSpecified: -int256(reFiAmount),
sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
});
// Owner swaps easy-earned abundant ReFi token for ETH from the pool
swapRouter.swap(key, params, testSettings, ZERO_BYTES);
vm.stopPrank();
uint256 ownerBalanceAfter = owner.balance;
// Assert
assertGt(ownerBalanceAfter, ownerBalanceBefore, "Owner should drain ETH from pool");
}

Recommended Mitigation

To solve the issue, simply remove the _mint function call from the constructor.

constructor() ERC20("RebateFi", "ReFi") Ownable(msg.sender) {
- _mint(msg.sender, 1_000_000 * 10 ** decimals());
}
Updates

Lead Judging Commences

chaossr Lead Judge 12 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!