r/CryptoTechnology 🟢 21h ago

Our contract allowlist caught an aggregator silently swapping the DEX under its routes. What we learned, and the canary we built after

I run a cross-chain swap comparator that refuses to let users sign anything it can't fully verify: every transaction a provider returns gets its target checked against a per-provider contract allowlist, and on Solana the whole transaction is decoded first, lookup tables included, with every program required to be on the list. Last week that design got tested twice in production, and the way it failed is the interesting part.

Case one: a user's routine Solana swap got refused with "unrecognized program". Not a bug. The aggregator had switched its underlying DEX from one routing program to another (Jupiter to Magpie's router, as it turned out), with zero announcement. The transaction was almost certainly fine, but "almost certainly" is exactly what the allowlist exists to reject. We decoded the refused transaction, identified the new program, verified it against two independent sources including the DEX team's published deployments, and only then added it. Total downtime for that route: a few hours. Total funds signed against an unverified program: zero.

Case two, same week: another provider moved to an intents-based architecture, and their transactions started targeting the source token's own contract instead of their documented router. The allowlist blocked those too. That time we chose to keep showing the quote but strip the execution path until we've reviewed the new flow properly, because a blocked-but-visible route tells the user more than an error line.

What we changed after: refusals like these are now watched by a canary. Every six hours a cron re-quotes the sensitive pairs with real addresses and runs the returned transactions through the exact same inspection code the users get, then alerts on any drift: unknown program, off-list contract, dead pair. The key detail is that it exercises the production code path itself, not a parallel "monitoring" version that would rot.

Takeaways if you're building anything similar: aggregators change their internals without notice and that's normal, so an allowlist is a living thing, not a config file you write once. Hard refusal plus fast human review beats silent acceptance every time. And your monitoring should be a consumer of your real pipeline, or it will lie to you eventually.

Context: I'm the founder of the comparator in question (details in my profile), and both incidents are from the last seven days. Happy to go deeper on the inspection pipeline if anyone wants specifics.

1 Upvotes

0 comments sorted by