hats-finance / Intuition-0x538dbadc50cc87b281cd655f1edbc6ebda02a66a

The smart contracts of the Intuition protocol v1.
https://intuition.systems
Other
0 stars 1 forks source link

During creation of Triple, the individual atom ids are never registered to the negative vault #47

Open hats-bug-reporter[bot] opened 1 week ago

hats-bug-reporter[bot] commented 1 week ago

Github username: -- Twitter username: iamandreiski Submission hash (on-chain): 0x73628f75a0501e8b98b61740e5c8a12f7077fd75657a0d09cb7adfcd8bde1709 Severity: medium

Description: Description

During the creation of Triple, the individual ids are never registered to the counter or negative vault, meaning that whenever a user would like to deposit the counter vault, the deposit of the atom fraction would fail, due to getTripleAtoms function not fetching anything.

Attack Scenario

Whenever a triple is created, in the _createTriple() function the underlying vault ids are mapped to the new Triple vault id:

 // map the triple's vault ID to the underlying atom vault IDs
        triples[id] = [subjectId, predicateId, objectId];

But they're never mapped to the counter vault id, i.e. the type(uint256).max - id. So whenever a user wants to make a Triple deposit to the counter vault:

 function depositTriple(address receiver, uint256 id)
        external
        payable
        nonReentrant
        whenNotPaused
        returns (uint256)
    {
        if (!isTripleId(id)) {
            revert Errors.MultiVault_VaultNotTriple();
        }

        if (_hasCounterStake(id, receiver)) {
            revert Errors.MultiVault_HasCounterStake();
        }

        if (msg.value < generalConfig.minDeposit) {
            revert Errors.MultiVault_MinimumDeposit();
        }

        uint256 protocolFee = protocolFeeAmount(msg.value, id);
        uint256 userDepositAfterprotocolFee = msg.value - protocolFee;

        // deposit eth into vault and mint shares for the receiver
        uint256 shares = _deposit(receiver, id, userDepositAfterprotocolFee);

        _transferFeesToProtocolVault(protocolFee);

        // distribute atom shares for all 3 atoms that underly the triple
        uint256 atomDepositFraction = atomDepositFractionAmount(userDepositAfterprotocolFee, id);
        _depositAtomFraction(id, receiver, atomDepositFraction);

        return shares;
    }

_depositAtomFraction() would never be able to perform this action due to the following constraint:


function _depositAtomFraction(uint256 id, address receiver, uint256 amount) internal {
        // load atom IDs
        uint256[3] memory atomsIds;
        (atomsIds[0], atomsIds[1], atomsIds[2]) = getTripleAtoms(id);

        // floor div, so perAtom is slightly less than 1/3 of total input amount
        uint256 perAtom = amount / 3;

        // distribute proportional shares to each atom
        for (uint256 i = 0; i < 3; i++) {
            // deposit assets into each atom vault and mint shares for the receiver
            uint256 shares = _deposit(receiver, atomsIds[i], perAtom);

            // update the mapping which tracks atom shares
            tripleAtomShares[id][atomsIds[i]][receiver] += shares;
        }
    }

getTripleAtoms() wouldn't be able to fetch any vault ids, as the individual vault ids were never registered to the counter vault.

Attachments

  1. Proof of Concept (PoC) File

  2. Revised Code File (Optional)

iamandreiski commented 1 week ago

Adding the getTripleAtoms() function flow as well which shows the above-mentioned case:

 function getTripleAtoms(uint256 id) public view returns (uint256, uint256, uint256) {
        bool isCounterTriple = id > type(uint256).max / 2;
        uint256[3] memory atomIds = isCounterTriple ? triples[type(uint256).max - id] : triples[id];
        return (atomIds[0], atomIds[1], atomIds[2]);
    }

Since the atoms wouldn't registered to the triples[counterId] the mapping won't contain anything for this key, so they'll fetch the default value of 0.

mihailo-maksa commented 4 days ago

The concern regarding the registration of individual atom IDs to the counter vault during the creation of a triple has been reviewed. Here is our detailed explanation:

Functionality Explanation: The function getTripleAtoms is designed to handle the case for counter vaults. It includes a check to determine if the given ID corresponds to a counter vault (id > type(uint256).max / 2). If this condition is met, the function retrieves the underlying atoms from triples[type(uint256).max - id].

Implementation Details: This mechanism ensures that the counter vault IDs are correctly mapped and can fetch the relevant atom IDs as needed. The design effectively addresses the scenario described in the issue report.

No Functional Impact: The current implementation ensures that all necessary mappings are in place for both regular and counter vaults. There is no functional impact or failure in the deposit process for counter vaults.

Conclusion: The reported issue does not indicate a flaw or oversight in the system. The design and implementation of the getTripleAtoms function adequately handle the registration and retrieval of atom IDs for counter vaults. Therefore, we consider this issue to be invalid.

Status: This issue is invalid.