Background
While adding realized swap deltas to trade results (PR feat/realized-swap-results), we discovered the deployed Arbitrum Sepolia contract is not the v0.2.1 source tag — it was built from a later commit that unified close + liquidation events.
Concretely, the deployed TakerClosed is:
TakerClosed(uint256 posId, SwapResult sr, int256 funding, uint256 utilFees, uint256 liqFee, bool isLiquidation)
(two extra trailing fields vs the v0.2.1 source / old binding). Verified against the live log topic0 0xc6d1565765c65beb63cd0a76e37c058e0908e6e24a609d0dc1a724106ae0576e. That binding is now fixed, with a SIGNATURE_HASH regression assertion in abi_lock.
The risk
The same drift likely affects the other close/liquidation events, which were not emitted in the open/adjust/close fork test and so remain unverified against the chain:
MakerClosed
TakerLiquidated
MakerLiquidated
- possibly
MakerAdjusted / MakerConverted
If any binding's topic0 doesn't match the deployed event, decode_log silently returns None and the event is dropped. Legion's market_data.rs depends on these for external-close/liquidation eviction, so a mismatch means it never notices a position was closed/liquidated out from under it.
Why the easy routes don't work
- The contracts are not verified on the Arbitrum Sepolia explorer (blockscout
getabi → "not verified"), so no ABI to pull.
- The
abi_lock test only checks each binding against itself, not against the chain — it won't catch deployment drift.
Proposed work
- Add a fork test that emits each event (open→close a maker; stage a liquidation if feasible) and capture the real topic0s.
- For each, compute
cast keccak of the candidate signature (with SwapResult expanded to its 7-field tuple) and compare; fix any mismatched sol! binding in contracts.rs.
- Add
SIGNATURE_HASH assertions to abi_lock for each, so future drift is caught.
See memory note / PR feat/realized-swap-results for the verification method.
Background
While adding realized swap deltas to trade results (PR
feat/realized-swap-results), we discovered the deployed Arbitrum Sepolia contract is not thev0.2.1source tag — it was built from a later commit that unified close + liquidation events.Concretely, the deployed
TakerClosedis:(two extra trailing fields vs the v0.2.1 source / old binding). Verified against the live log topic0
0xc6d1565765c65beb63cd0a76e37c058e0908e6e24a609d0dc1a724106ae0576e. That binding is now fixed, with aSIGNATURE_HASHregression assertion inabi_lock.The risk
The same drift likely affects the other close/liquidation events, which were not emitted in the open/adjust/close fork test and so remain unverified against the chain:
MakerClosedTakerLiquidatedMakerLiquidatedMakerAdjusted/MakerConvertedIf any binding's topic0 doesn't match the deployed event,
decode_logsilently returnsNoneand the event is dropped. Legion'smarket_data.rsdepends on these for external-close/liquidation eviction, so a mismatch means it never notices a position was closed/liquidated out from under it.Why the easy routes don't work
getabi→ "not verified"), so no ABI to pull.abi_locktest only checks each binding against itself, not against the chain — it won't catch deployment drift.Proposed work
cast keccakof the candidate signature (withSwapResultexpanded to its 7-field tuple) and compare; fix any mismatchedsol!binding incontracts.rs.SIGNATURE_HASHassertions toabi_lockfor each, so future drift is caught.See memory note / PR
feat/realized-swap-resultsfor the verification method.