Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Valid

Over-Allocation of Credit Delegation to Multiple Markets

Summary

updateVaultAndCreditDelegationWeight updates all credit delegations for connected markets with the total assets of the vault. _updateCreditDelegations calls market.updateTotalDelegatedCredit, which adds 100% of the vault’s assets to each connected market. This results in each market receiving 100% of the vault's credit, leading to over-allocation, more credit is delegated than the vault can actually provide.


Vulnerability Details

This function updateVaultAndCreditDelegationWeight updates the creditDelegation.weight for all connected markets and the totalCreditDelegationWeight of the vault to the same value:

creditDelegation.weight = newWeight;
self.totalCreditDelegationWeight = newWeight;

Here, newWeight is derived from the vault's total assets:

uint128 newWeight = uint128(IERC4626(self.indexToken).totalAssets());

Then _updateCreditDelegations calculates the creditDelegationShareX18 for each market as:

UD60x18 creditDelegationShareX18 = ud60x18(creditDelegation.weight).div(ud60x18(totalCreditDelegationWeightCache));

Since creditDelegation.weight and totalCreditDelegationWeight are set to the same value (newWeight), the division results in:

creditDelegationShareX18 = newWeight / newWeight = 1e18 (100%)

If creditDelegationShareX18 is always 1e18 (100%), then the creditDeltaUsdX18 calculation and delegation update in market:

UD60x18 creditDeltaUsdX18 = newCreditDelegationUsdX18.sub(previousCreditDelegationUsdX18);
Market.Data storage market = Market.load(connectedMarketId);
market.updateTotalDelegatedCredit(creditDeltaUsdX18);

Thus _updateCreditDelegations will always allocate 100% of the vault's credit capacity to each market. This is clearly problematic, as it would mean that every market receives the full credit capacity of the vault, leading to over-allocation and potential insolvency.

In CreditDelegationBranch, we have withdrawUsdTokenFromMarket, which calculates market's credit capacity by deducting market's debt from market's delegated credit from vault. It then checks the credit capacity of the market, mints USD token to caller and increase market's debt.

Suppose there are 5 markets connected to a vault. If vault has 100 credit capacity, it will delegate 100 credit to all markets. Calls to withdrawUsdTokenFromMarket will check market's credit capacity and then mint tokens and increase debt. If one market uses 100 credit and add 100 debt, vault's credit capacity will become zero. But the other 4 markets still have 100 delegated credit. So other markets will keep issueing USD token to engine. As a result the vault's debt will be too much and the vault will become very unhealthy and it will not have sufficient asset to back the USD tokens minted


Impact

  • Each market would be allocated 100% of the vault's credit capacity, which is impossible in practice. This would lead to a situation where the vault's credit capacity is exhausted by the first market, leaving no liquidity for other markets

  • credit calculations will lead to liquidity shortages, insolvencies, or protocol failures.


Recommendation

Ensure Proper Credit Delegation Distribution Across Connected Markets. Instead of allocating 100% of vault assets to each market, the contract should distribute credit proportionally across markets

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Market Credit Delegation Weights Are Incorrectly Distributed

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!