Algo Ssstablecoinsss

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

# `CollateralDeposited` omits the collateral token, breaking off-chain accounting in a multi-collateral system

CollateralDeposited omits the collateral token, breaking off-chain accounting in a multi-collateral system

Severity: Low · Impact: Low · Likelihood: High

Description

  • In a multi-collateral engine, deposit events must identify which token was deposited so indexers can reconstruct per-token balances.

  • CollateralDeposited logs only (user, amount) — it never records the token address — while the sibling CollateralRedeemed event does include the token. It also indexes amount (a non-filterable value) instead of the token.

event CollateralDeposited:
user: indexed(address)
@> amount: indexed(uint256) # no token field; indexes amount instead of the token
# emitted as:
@> log CollateralDeposited(msg.sender, amount_collateral)

Risk

Likelihood:

  • Occurs on every deposit — the event is permanently missing the token dimension.

Impact:

  • Off-chain systems cannot attribute a deposit to WETH vs WBTC from the event alone, corrupting balance accounting, dashboards, and liquidation monitoring.

Proof of Concept

Save the block below as tests/poc_l2.py inside the cloned repo and run mox test tests/poc_l2.py. Two deposits of the same size but different collateral tokens emit byte-for-byte identical events, and neither event contains the token address — proving the token cannot be recovered from the log.

import boa
from eth_utils import to_wei
from src import dsc_engine, decentralized_stable_coin
from src.mocks import mock_token, MockV3Aggregator
def test_deposit_event_cannot_distinguish_token():
dsc = decentralized_stable_coin.deploy()
weth = mock_token.deploy()
wbtc = mock_token.deploy()
p1 = MockV3Aggregator.deploy(8, 2_000 * 10**8)
p2 = MockV3Aggregator.deploy(8, 2_000 * 10**8)
engine = dsc_engine.deploy(
[weth.address, wbtc.address], [p1.address, p2.address], dsc
)
dsc.set_minter(engine.address, True)
dsc.transfer_ownership(engine.address)
user = boa.env.generate_address("user")
amount = to_wei(1, "ether")
with boa.env.prank(user):
weth.mock_mint()
wbtc.mock_mint()
weth.approve(engine.address, amount)
engine.deposit_collateral(weth.address, amount)
weth_event = engine.get_logs()[-1]
wbtc.approve(engine.address, amount)
engine.deposit_collateral(wbtc.address, amount)
wbtc_event = engine.get_logs()[-1]
# Both events are CollateralDeposited(user, amount) with no token field, so a
# WETH deposit and a WBTC deposit of the same size are byte-for-byte identical.
assert repr(weth_event) == repr(wbtc_event)
# And neither event's data contains the token address that was deposited.
assert weth.address.lower() not in repr(weth_event).lower()
assert wbtc.address.lower() not in repr(wbtc_event).lower()

Recommended Mitigation

Add the token address to the event and index the fields that are actually filtered on.

event CollateralDeposited:
user: indexed(address)
+ token: indexed(address)
- amount: indexed(uint256)
+ amount: uint256
- log CollateralDeposited(msg.sender, amount_collateral)
+ log CollateralDeposited(msg.sender, token_collateral_address, amount_collateral)
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours 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!