Algo Ssstablecoinsss

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

CollateralDeposited event omits the collateral token, breaking off-chain accounting

Root + Impact

Description

The engine accepts two distinct collateral tokens (WETH and WBTC), and positions are tracked per token in user_to_token_address_to_amount_deposited. Events exist so off-chain consumers — indexers, dashboards, accounting systems, liquidation bots — can reconstruct this on-chain state without replaying every call. For that reconstruction to work, a deposit event must identify which token was deposited.

The specific problem is that CollateralDeposited logs only user and amount and omits the collateral token. The sibling CollateralRedeemed event does include the token, so the two halves of the same accounting flow are inconsistent: an observer can attribute redemptions to a token but not deposits.

event CollateralDeposited:
user: indexed(address)
amount: indexed(uint256)
@> # missing: token: indexed(address)

Risk

Likelihood:

  • Every deposit emits this incomplete event, so the issue is always present.

Impact:

  • Off-chain systems cannot reliably rebuild per-token collateral balances from logs → incorrect dashboards, broken monitoring/liquidation bots, faulty accounting integrations.

  • No direct on-chain fund loss; the impact is on the correctness and usability of event-derived data.

Proof of Concept

Explanation: Two deposits of the same size for different collateral tokens emit byte-for-byte identical events, so no off-chain consumer can tell them apart. The test below makes one WETH deposit and one WBTC deposit and shows the emitted CollateralDeposited events are indistinguishable and carry no token field:

import boa
​
def test_deposit_event_cannot_distinguish_token(engine, weth, wbtc, alice):
# alice deposits 1e18 of WETH, then 1e18 of WBTC
with boa.env.prank(alice):
engine.deposit_collateral(weth.address, 10**18)
engine.deposit_collateral(wbtc.address, 10**18)
​
logs = engine.get_logs()
deposits = [e for e in logs if type(e).__name__ == "CollateralDeposited"]
​
# Both events are identical (same user, same amount)...
assert deposits[0].user == deposits[1].user
assert deposits[0].amount == deposits[1].amount
# ...and neither carries a `token` field, so WETH vs WBTC is unrecoverable from logs -> BUG
assert not hasattr(deposits[0], "token")

An indexer reading these logs cannot determine which deposit was WETH and which was WBTC, so any per-token balance it reconstructs is wrong.

Recommended Mitigation

Explanation: Add the token address as an indexed field on the event (mirroring CollateralRedeemed) and include it when logging in _deposit_collateral, so deposits are fully attributable per token.

event CollateralDeposited:
user: indexed(address)
+ token: indexed(address)
amount: indexed(uint256)

(and update the log CollateralDeposited(...) call in _deposit_collateral to pass the token)

Updates

Lead Judging Commences

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