Algo Ssstablecoinsss

AI First Flight #2
Beginner FriendlyDeFi
EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Rebasing collateral breaks accounting and can lock withdrawals

Root + Impact

Description

  • the engine’s internal collateral accounting should represent the real amount of assets currently backing each user’s debt position.

    That means if the protocol believes a user has deposited 100 units of collateral, the engine should either actually hold 100 units attributable to that user or use an accounting model that correctly maps changing balances to user ownership.

  • the engine stores a fixed nominal token amount per user in user_to_token_address_to_amount_deposited, and later relies on that stored amount for collateral valuation, health factor checks, minting limits, redemption logic, and liquidation math.

    This model only works for non-rebasing tokens whose balances never change except through explicit transfers.

    For rebasing collateral, token balances can increase or decrease without any transfer taking place.

    As a result, the engine’s actual token balance can drift away from the user’s recorded deposit balance, but the protocol never detects or reconciles that difference. A negative rebase is especially dangerous because the engine will continue to treat the old stored amount as real collateral even after the token contract has reduced the engine’s balance. This allows users to mint DSC against collateral that no longer exists.

    A positive rebase is also problematic because the engine accumulates excess collateral with no ownership attribution, meaning the protocol’s accounting becomes economically incorrect in both directions.

    Over time, this mismatch can surface as failed redemptions, failed liquidations, inaccurate health factor calculations, hidden undercollateralization, and stranded collateral.

def _deposit_collateral(
token_collateral_address: address, amount_collateral: uint256
):
...
<self.user_to_token_address_to_amount_deposited[msg.sender][
token_collateral_address
] += amount_collateral>
...
Relevant downstream reliance on the stale stored balance:
def _get_account_collateral_value(user: address) -> uint256:
total_collateral_value_in_usd: uint256 = 0
for token: address in COLLATERAL_TOKENS:
amount: uint256 = self.user_to_token_address_to_amount_deposited[user][
token
]
total_collateral_value_in_usd += self._get_usd_value(token, amount)
return total_collateral_value_in_usd
def _redeem_collateral(
token_collateral_address: address,
amount_collateral: uint256,
_from: address,
_to: address,
):
self.user_to_token_address_to_amount_deposited[_from][
token_collateral_address
] -= amount_collateral
success: bool = extcall IERC20(token_collateral_address).transfer(
_to, amount_collateral
)

Risk

Likelihood:

  • This occurs whenever a rebasing token is used as collateral.

  • The design has no share-based accounting or balance reconciliation.

Impact:

  • Users can mint against collateral that no longer exists after a negative rebase.

  • Redemptions and liquidations can revert because the engine tries to transfer more tokens than it holds.

Proof of Concept

/*
Assume a rebasing token is accepted as collateral.
1. A user deposits 100 tokens.
The engine records:
user_to_token_address_to_amount_deposited[user][token] = 100
2. The user mints DSC using that recorded collateral.
3. The token later performs a -20% rebase.
Actual engine balance falls from 100 to 80.
4. The protocol does not update internal accounting.
It still believes the user has 100 tokens deposited.
5. Health factor and collateral value are still calculated using 100,
even though only 80 tokens actually back the position.
6. The user is now undercollateralized in reality, but the protocol may still
treat the position as healthy until redemption or liquidation is attempted.
7. When collateral is redeemed or seized, the engine may not hold enough tokens
to transfer the recorded amount, causing insolvency or withdrawal failure.
*/
Short numerical example:
/*
Assume:
- 1 token = $1
- liquidation threshold = 50%
Before rebase:
- recorded collateral = 100
- real collateral = 100
- safe debt = $50
User mints $50 DSC.
After a -20% rebase:
- recorded collateral = 100
- real collateral = 80
- real safe debt should be only $40
The protocol still prices the position as if it has $100 collateral,
so the user remains overstated by $20 of collateral value.
*/

Recommended Mitigation

- support arbitrary ERC20 collateral with fixed-balance accounting
+ explicitly reject rebasing collateral
+ document that only non-rebasing vanilla ERC20 collateral is supported
+ add collateral listing checks and governance policies that forbid elastic-supply assets
+ if rebasing support is required, redesign accounting around shares rather than nominal token balances
+ derive user ownership from a proportional share of the total pool instead of storing fixed token units
+ reconcile protocol accounting against real token balances whenever collateral state is used
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 6 days 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!