Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: medium
Invalid

Native Tokens can't be used as collateral in `createOffer`

Summary

Whenever a new offer is created, after calling createOffer, a call to tillIn is made, which handles the transfer of tokens to the CapitalPool. It should support ERC20 token and native token transfers, however, it can only handle ERC20/Wrapped token transfers.

Vulnerability Details

The function createOffer in PreMarkets.sol is used by a Maker in order to create an offer to buy/sell points. With the creation of the offer, they must also provide collateral in order to back the points from the offer. Their tokens get transferred from the msg.sender to the CapitalPool using the function tillIn.

An issue arises within the implementation of tillIn, as it's intended for it to support ERC20 token and native token, however, the only thing that supports Native tokens is that the function is currently payable. Although it can receive native tokens, it can't transfer them to the CapitalPool.

Coded PoC

This can be tested by pasting the simple test from below into Premarkets.t.sol

function testTillInNativeEther() public {
vm.startPrank(user1);
// create an array and add nativeEther to it
address[] memory tokenAddressList = new address[](1);
address nativeEther = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
tokenAddressList[0] = address(nativeEther);
// whitelist the native ether
tokenManager.updateTokenWhiteListed(tokenAddressList, true);
vm.deal(user1, 1 ether);
vm.expectRevert();
preMarktes.createOffer{value: 1 ether}(
CreateOfferParams(
marketPlace, address(nativeEther), 1000, 0.01 * 1e18, 12000, 300, OfferType.Ask, OfferSettleType.Turbo
)
);
}

To further prove my point, you can replace the else statement in the tillIn function with the following:

...
} else if (msg.value > 0) {
console2.log("capitalPoolAddr balance before", capitalPoolAddr.balance);
(bool sent, bytes memory data) = capitalPoolAddr.call{value: msg.value}("");
require(sent, "Failed to send Ether");
console2.log("capitalPoolAddr balance after", capitalPoolAddr.balance);
} else {
/// @notice token is ERC20 token
_transfer(_tokenAddress, _accountAddress, capitalPoolAddr, _amount, capitalPoolAddr);
emit TillIn(_accountAddress, _tokenAddress, _amount, _isPointToken);
}
...

Make sure to import the console in TokenManager using: import "forge-std/console2.sol";

After which you can, delete the vm.expectRevert line from the test and run it. The test will pass successfully again, but this time the Native Ether was actually sent to the CapitalPool

Impact

createOffer's functionality is broken for native token transfers.

Tools Used

Manual Review

Recommendations

Consider refactoring the way tillIn handles token transfers, by including a case where the native tokens are actually transferred to the CapitalPool.

Updates

Lead Judging Commences

0xnevi Lead Judge
over 1 year ago
0xnevi Lead Judge over 1 year 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!