DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: medium
Invalid

Unfair Share Distribution in PerpetualVault

Vulnerability Details

In PerpetualVault, depositors who contribute collateral before a position is opened receive shares based on the full value of their deposited collateral. However, depositors who deposit during an active position receive shares based on the value of collateral that actually increases the position, after adjusting for fees and price impact. This discrepancy results in early depositors gaining more shares than they should, leading to an unfair distribution of collateral upon withdrawal.

Impact

  • Unfair Share Allocation: Early depositors receive disproportionately higher shares, which leads to them receiving more collateral upon withdrawal than they are entitled to.

  • Potential Exploitability: Users could strategically time deposits to maximize their share allocation, leading to unfair advantages.

  • Financial Imbalance: Later depositors effectively subsidize the withdrawals of earlier depositors, creating an unintended redistribution of funds.

Proof of Concept (PoC)

function test_Rice_Check_Shares_Minted() external {
address keeper = PerpetualVault(vault).keeper();
address alice = makeAddr("alice");
depositFixture(alice, 1e12);
(,uint256 shares,,,,) = PerpetualVault(vault).depositInfo(1);
emit log_named_decimal_uint("Actual collateral deposited by Alice", 1e12, 6);
emit log_named_decimal_uint("Shares Minted when no pos open", shares, 8);
MarketPrices memory prices = mockData.getMarketPrices();
bytes[] memory data = new bytes[](1);
data[0] = abi.encode(3380000000000000);
vm.prank(keeper);
PerpetualVault(vault).run(true, false, prices, data); // 1x SHORT POSITION
PerpetualVault.FLOW flow = PerpetualVault(vault).flow();
assertEq(uint8(flow), 2);
GmxOrderExecuted(true);
bytes32 curPositionKey = PerpetualVault(vault).curPositionKey();
VaultReader.PositionData memory positionData = reader.getPositionInfo(curPositionKey, prices);
console.log("1x Short Position");
emit log_named_decimal_uint("Size In USD", positionData.sizeInUsd, 30);
emit log_named_decimal_uint("Size In Tokens", positionData.sizeInTokens, 18);
emit log_named_decimal_uint("Actual Collateral Amount In Position", positionData.collateralAmount, 6);
emit log_named_decimal_uint("Net Value", positionData.netValue, 30);
emit log_named_decimal_uint("Shares Should have been minted", positionData.collateralAmount * 1e8, 8);
emit log_named_decimal_uint("Discrepancy in shares", shares - positionData.collateralAmount * 1e8, 8);
vm.prank(keeper);
PerpetualVault(vault).runNextAction(prices, new bytes[](0));
}

Log Outputs:

Actual collateral deposited by Alice: 1000000.000000
Shares Minted when no pos open: 1000000000000.00000000
1x Short Position
Size In USD: 1000029.671490240875000000000000000000
Size In Tokens: 295.708305093179833937
Actual Collateral Amount In Position: 999399.994001
Net Value: 999009.647820615252607991711363023142
Shares Should have been minted: 999399994001.00000000
Discrepancy in shares: 600005999.00000000

Tools Used

  • Manual Review

  • Foundry

Recommendations

  • Modify the share allocation mechanism to ensure all depositors receive shares proportionate to the actual collateral value adjusted for fees and price impact.

  • Implement a consistent share calculation methodology regardless of whether a position is open or not.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

riceee Submitter
9 months ago
riceee Submitter
9 months ago
0xl33 Auditor
9 months ago
riceee Submitter
9 months ago
n0kto Lead Judge
8 months ago
n0kto Lead Judge 8 months 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!