Skip to content

ETH Surplus Unaccounted for in batchCreateTriple Function #78

Open
@hats-bug-reporter

Description

Github username: --
Twitter username: --
Submission hash (on-chain): 0x45af594e37907786efc19eea5046d4b897518936ba6dc1ee0e011e4b1bfa26dd
Severity: high

Description:
Description
In the batchCreateTriple function of the EthMultiVault contract, there's an issue where potential ETH surplus from the division of msg.value by the number of triples is not accounted for or returned to the user. This can lead to small amounts of ETH being trapped in the contract, inaccessible to both users and the protocol.

Attack Scenario
While not a direct security vulnerability, this issue can lead to the following problems:

  1. Users consistently lose small amounts of ETH when creating multiple triples.
  2. Over time, these small amounts can accumulate in the contract without any mechanism to retrieve them.
  3. In extreme cases with many transactions, the accumulated ETH could become significant.

Attachments

  1. Proof of Concept (PoC) File

    ) external payable nonReentrant whenNotPaused returns (uint256[] memory) {
    if (subjectIds.length != predicateIds.length || subjectIds.length != objectIds.length) {
    revert Errors.MultiVault_ArraysNotSameLength();
    }
    uint256 length = subjectIds.length;
    uint256 tripleCost = getTripleCost();
    if (msg.value < tripleCost * length) {
    revert Errors.MultiVault_InsufficientBalance();
    }
    uint256 valuePerTriple = msg.value / length;
    uint256 protocolDepositFeeTotal;
    uint256[] memory ids = new uint256[](length);
    for (uint256 i = 0; i < length; i++) {
    uint256 protocolDepositFee;
    (ids[i], protocolDepositFee) = _createTriple(subjectIds[i], predicateIds[i], objectIds[i], valuePerTriple);
    // add protocol deposit fees to total
    protocolDepositFeeTotal += protocolDepositFee;
    }
    uint256 totalFeesForProtocol = tripleConfig.tripleCreationProtocolFee * length + protocolDepositFeeTotal;
    _transferFeesToProtocolVault(totalFeesForProtocol);
    return ids;

  2. Revised Code File (Optional)

function batchCreateTriple(
    uint256[] calldata subjectIds,
    uint256[] calldata predicateIds,
    uint256[] calldata objectIds
) external payable nonReentrant whenNotPaused returns (uint256[] memory) {
    if (subjectIds.length != predicateIds.length || subjectIds.length != objectIds.length) {
        revert Errors.MultiVault_ArraysNotSameLength();
    }

    uint256 length = subjectIds.length;
    uint256 tripleCost = getTripleCost();
    if (msg.value < tripleCost * length) {
        revert Errors.MultiVault_InsufficientBalance();
    }

    uint256 valuePerTriple = msg.value / length;
    uint256 protocolDepositFeeTotal;
    uint256[] memory ids = new uint256[](length);

    for (uint256 i = 0; i < length; i++) {
        uint256 protocolDepositFee;
        (ids[i], protocolDepositFee) = _createTriple(
            subjectIds[i],
            predicateIds[i],
            objectIds[i],
            valuePerTriple
        );

        protocolDepositFeeTotal += protocolDepositFee;
    }

    uint256 totalFeesForProtocol = tripleConfig.tripleCreationProtocolFee * length + protocolDepositFeeTotal;
    _transferFeesToProtocolVault(totalFeesForProtocol);

    // Calculate and refund any surplus
    uint256 surplus = msg.value - (valuePerTriple * length);
    if (surplus > 0) {
        (bool success,) = msg.sender.call{value: surplus}("");
        require(success, "Surplus refund failed");
    }

    return ids;
}

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingduplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions