hats-finance / Intuition-0x538dbadc50cc87b281cd655f1edbc6ebda02a66a

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

Multiple Usage of Atoms in Triples Leading to Inconsistent State and Potential Insolvency #83

Open hats-bug-reporter[bot] opened 2 days ago

hats-bug-reporter[bot] commented 2 days ago

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

Description: Description\ In the EthMultiVault contract, the createTriple function allows the same atom to be used in multiple triples. This design choice leads to several critical issues:

  1. Inconsistent Share Tracking: The tripleAtomShares mapping doesn't account for atoms being part of multiple triples, leading to inaccurate share tracking.

  2. Direct Deposits Inconsistency: Direct deposits to atoms are not reflected in the tripleAtomShares mapping, causing discrepancies between actual holdings and recorded shares in triples.

These issues can lead to protocol insolvency, incorrect share calculations, and potential exploitation of the system.

Attack Scenario\

  1. Users depositing directly into atoms used in triples will have their shares underrepresented in the triple context.
  2. Redemptions from triples may not accurately reflect the true asset distribution among atoms.

Attachments

   function testMultipleTripleInconsistency() external {
        // Create atoms
        uint256 atomCost = vault.getAtomCost();
        uint256 atom1 = vault.createAtom{value: atomCost}("atom1");
        uint256 atom2 = vault.createAtom{value: atomCost}("atom2");
        uint256 atom3 = vault.createAtom{value: atomCost}("atom3");

        // Set non-zero atomDepositFractionOnTripleCreation
        vault.setAtomDepositFractionOnTripleCreation(1 ether);

        // Create two triples using the same atom1
        uint256 tripleCost = vault.getTripleCost();
        uint256 triple1 = vault.createTriple{value: tripleCost}(atom1, atom2, atom3);
        uint256 triple2 = vault.createTriple{value: tripleCost}(atom2, atom1, atom3);

        // Check atom1's total assets
        uint256 atom1Assets = vault.vaults(atom1).totalAssets;

        // This assertion will likely show that atom1 has received double the expected deposit
        assert(atom1Assets == 2 ether);

        // Now try to redeem all shares from atom1
        uint256 atom1Shares = vault.vaults(atom1).balanceOf[address(this)];
        vault.redeemAtom(atom1Shares, address(this), atom1);

        // Check if we were able to withdraw more than we should
        uint256 finalBalance = address(this).balance;
        assert(finalBalance > 2 ether); // This might succeed, indicating over-withdrawal
    }
  1. Revised Code File (Optional)
    • Prevent Atom Reuse:
    • Implement a check in the createTriple function to ensure that an atom is not already part of another triple.
    • Maintain a mapping of atoms to their associated triple (if any).
    • Pros: Simplifies accounting and prevents inconsistencies.
    • Cons: Limits flexibility in creating semantic relationships.