Open hats-bug-reporter[bot] opened 3 days ago
Github username: -- Twitter username: -- Submission hash (on-chain): 0x766ad11162ca820ffb4609089bf9a36dbec3919fcaada77d1760298d67719d45 Severity: high
Description: Description\ In the batchCreateAtom function of the EthMultiVault contract, there's a potential for loss of user funds due to imprecise division when calculating valuePerAtom. This occurs when the msg.value is not perfectly divisible by the number of atoms being created. The surplus amount is not accounted for and effectively becomes locked in the contract, inaccessible to both the user and the protocol. https://github.com/hats-finance/Intuition-0x538dbadc50cc87b281cd655f1edbc6ebda02a66a/blob/b2e422ff0c3e3729e58d2699fdf2ef8699fbd172/src/EthMultiVault.sol#L412-L440
batchCreateAtom
valuePerAtom
msg.value
Attack Scenario\
Attachments
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
import "./EthMultiVault.sol";
contract EthMultiVaultExploit { EthMultiVault public vault;
constructor(address _vaultAddress) { vault = EthMultiVault(_vaultAddress); } function exploitSurplus() external payable { require(msg.value == 119, "Send exactly 119 wei"); bytes[] memory atomUris = new bytes[](3); atomUris[0] = "uri1"; atomUris[1] = "uri2"; atomUris[2] = "uri3"; vault.batchCreateAtom{value: 119}(atomUris); // At this point, 2 wei are locked in the contract }
}
2. **Revised Code File (Optional)** ```solidity function batchCreateAtom(bytes[] calldata atomUris) external payable nonReentrant whenNotPaused returns (uint256[] memory) { uint256 length = atomUris.length; if (msg.value < getAtomCost() * length) { revert Errors.MultiVault_InsufficientBalance(); } uint256 valuePerAtom = msg.value / length; uint256 protocolDepositFeeTotal; uint256[] memory ids = new uint256[](length); for (uint256 i = 0; i < length; i++) { uint256 protocolDepositFee; (ids[i], protocolDepositFee) = _createAtom(atomUris[i], valuePerAtom); // add protocol deposit fees to total protocolDepositFeeTotal += protocolDepositFee; } uint256 totalFeesForProtocol = atomConfig.atomCreationProtocolFee * length + protocolDepositFeeTotal; _transferFeesToProtocolVault(totalFeesForProtocol); // Calculate and refund any surplus uint256 surplus = msg.value - (valuePerAtom * length); if (surplus > 0) { payable(msg.sender).transfer(surplus); //optional add WETH fallback send } return ids; }
Github username: -- Twitter username: -- Submission hash (on-chain): 0x766ad11162ca820ffb4609089bf9a36dbec3919fcaada77d1760298d67719d45 Severity: high
Description: Description\ In the
batchCreateAtom
function of the EthMultiVault contract, there's a potential for loss of user funds due to imprecise division when calculatingvaluePerAtom
. This occurs when themsg.value
is not perfectly divisible by the number of atoms being created. The surplus amount is not accounted for and effectively becomes locked in the contract, inaccessible to both the user and the protocol. https://github.com/hats-finance/Intuition-0x538dbadc50cc87b281cd655f1edbc6ebda02a66a/blob/b2e422ff0c3e3729e58d2699fdf2ef8699fbd172/src/EthMultiVault.sol#L412-L440Attack Scenario\
batchCreateAtom
to create 3 atoms, sending 119 wei as themsg.value
.valuePerAtom
as 119 / 20 = 5 wei.Attachments
import "./EthMultiVault.sol";
contract EthMultiVaultExploit { EthMultiVault public vault;
}