Meson
CautionGeneral note 5/10https://meson.fi · Cross-chain stablecoin swap (modified HTLC, signature-based unlock)
The swap path most Meson users take has no safety net — once your tokens leave your wallet you cannot cancel, and this code was never audited or documented.
Acknowledgments
Our thanks to Meson's team — and to MrFish in particular — for receiving our feedback constructively and opening an engineering contact with us on 2026-10-28. We look forward to reviewing the findings together and will update this report as fixes land.
Scores (0–10)
10 = max effort spent on this project. Done: fork-testing rounds 1–2 against the live deployment with the 26-test suite, 45-selector deployed-interface reconstruction, cross-chain storage/admin reads, three disclosure rounds with the team plus the engineering contact, re-verification of the deployed implementation on 10-16. Not done: formal invariant campaigns, Solana-side auction review, post-contact cooperative iterations, second-auditor cross-check.
TL;DR
Meson is a cross-chain stablecoin swap protocol live on Ethereum, Tron, Bitcoin and ~40 EVM chains, all sharing one canonical contract address. DefiLlama reports $692k TVL (2026-10-11); true TVL is likely higher — Bitcoin taproot custody and the Solana/Sui pools are untracked.
Four audits from 2022 (SSLab, Trail of Bits ×3) cover the core escrow machinery. 17 of the 37 functions in today's official SDK ABI were added after those audits — including every function that now carries most live traffic — and none of them appears in any audit or any documentation. The public source repo was privatized, so even a source-level re-audit by outsiders is no longer possible.
We fork-tested the live Ethereum deployment (proxy verified, implementation is unverified bytecode, solc 0.8.28). No mainnet transactions were sent.
- F-1 (Medium): a late-acting LP can keep a passive user's source funds after the swap window — the promised penalty was never implemented.
- F-1b (Medium): the dominant swap path pulls from user wallets with no escrow, no lock, no cancelSwap — zero on-chain recourse.
- F-4 (Medium): one EOA key controls the upgrade path on every EVM chain; no multisig, no timelock, none of it documented.
- F-2 (Low): every swap under $0.50 fails to release on the target chain (arithmetic panic).
- F-3 (Info): re-posting a cancelled swap panics instead of reverting gracefully.
- F-5 (Info): deployed bytecode drifts from the audited sources; docs links to the repo are dead.
Scope & method
Tested: the live Ethereum deployment — proxy 0x25aB…48D3 (verified ERC1967Proxy, Sourcify full-match 2024-08-08) and implementation 0x3c77…D906 (unverified, 20,503-byte runtime bytecode, solc 0.8.28). Findings were established by executing the deployed contracts on a local fork of Ethereum mainnet state, cross-checked against live on-chain data (recent transaction paths, on-chain storage and constants) and the four published audit reports (SSLab 2022-02, Trail of Bits design + security + fix reviews 2022-07/10). Scope covered the full swap lifecycle on both the escrow and direct paths, the service-fee and lock-time constants, refund paths, and the on-chain admin surface.
- Not tested: the TRON TVM leg, the Bitcoin taproot custody leg, Solana/Sui/Aptos legs, live relayer infrastructure internals, adjustToPool semantics (unresolved), pool-1 owner identity.
- No mainnet transactions were sent.
Undocumented changes (drift log)
The deployed contract still contains the audited escrow machinery — but the protocol's trust model has quietly changed. The direct flow (directSwap / directRelease / directExecuteSwap / simpleExecuteSwap) pulls the swap amount from the user's wallet, gated only by a pre-signed release signature, into a shared custody pool. There is no escrow, no 40-minute lock, no LP collateral and no cancelSwap on this path. Most live traffic runs on it; the docs still describe and guarantee the old, atomic flow.
A promised control has not been implemented. Trail of Bits' 2022 fix review records the team's response: "the Meson team plans to enact a penalty for misbehaving LPs." Four years later, the deployed 2026 bytecode contains no penalty or slashing mechanism.
| Docs say | Deployed reality | Verified by |
|---|---|---|
| process.md: lock is "(tentatively 20 minutes)" | LOCK_TIME_PERIOD is 2400 s = 40 minutes (bytecode constant; solidity.md itself says 40) | Fork test + bytecode constant |
| "Atomic swap guarantees either both transfers happen or neither" (readme/lp.md) | The dominant direct-flow path has no escrow, no lock, no cancelSwap — the guarantee does not hold there | Fork tests + live method sampling |
| waiting-time.md: "publish release signature → release & executeSwap: right away, the order doesn't matter" | security.md's own red-severity "Release too late" mode shows the order matters — the two docs contradict each other | Docs cross-check + fork tests |
| No on-chain admin surface is documented | Live UUPS upgrade path + owner EOA + EIP-7702-delegated premium manager + owner-gated token list, fee and pool-owner transfers | Storage-slot reads + bytecode analysis |
| fee.md intro: "0.5%" | max(amount/2000, $0.5 floor) = 0.05% with a $0.50 minimum (fee table version wins) | Fork fee matrix test |
| Docs describe the classic escrow flow only | The direct flow — most live traffic — is documented nowhere | Docs cross-check |
| Docs link to github.com/MesonFi/meson-contracts-solidity | Repo privatized; audited sources no longer retrievable; docs links dead | Repo check 2026-10-12 |
Findings
Late-release loss mode: an LP can keep a passive user's funds — the promised penalty was never implemented
MesonSwap / MesonPools on the deployed implementation
What we demonstrated (fork of the live deployment, exact balance deltas)
- User postSwap 100 USDC on Ethereum with an honest LP.
- LP locks the equivalent on the target chain.
- LP withholds the release signature past LOCK_TIME_PERIOD (40 min per deployed bytecode — twice what process.md says).
- After the lock window the LP calls unlock() to recover its own collateral AND executeSwap() to take the user's 100 USDC. executeSwap has no authorization check and no expiry enforcement — anyone holding the release signature can call it, even after expireTs.
- The user's legitimate release() now reverts "Swap does not exist" — funds gone. Net: user −100 USDC, attacker +100 USDC, LP pool intact.
Why this rates Medium (not High)
The 40-minute window is raceable by the user themselves: the user signs the release signature, release() on the target chain is permissionless and valid until lock + 40 min, and executeSwap() on the source chain is permissionless. A user-side watcher can self-release and self-execute inside the window and complete the swap honestly — making the theft impossible. The loss therefore requires the user to stay passive for 40+ minutes after the target-side lock, exactly the scenario the docs' own "Release too late" red-severity warning describes. Aggravators kept: no cross-chain linkage on-chain, no contract recourse for passive app users, theft irreversible, per-swap loss capped at 100k (MAX_SWAP_AMOUNT), and the penalty promised in 2022 never shipped.
Evidence
- The loss replay was demonstrated on a fork of the live deployment with exact balance deltas: user −100 USDC, attacker +100 USDC, LP pool intact.
- executeSwap has no caller check and no expiry enforcement — demonstrated directly against the deployed bytecode, including after expireTs.
- The 40-minute window is real: release succeeds one second before the deadline and reverts one second after.
- Meson's own docs acknowledge the mode (docs.meson.fi protocol/security.md, "Release too late", red severity).
- SSLab 2022 found the economically equivalent mempool-delay variant, marked "Confirmed and Fixed" — the fix was the 100k per-swap amount cap, which bounds loss but does not close the window.
Recommendation
- Bind executeSwap to a commitment deadline: it must execute within LOCK_TIME_PERIOD of the release signature being witnessed on the target chain, independent of expireTs.
- Require the release signature to be witnessed on the target chain before executeSwap succeeds on the source chain.
- Add an on-chain per-swap state transition so the same encoding cannot be both unlocked and executed.
- Implement the LP penalty promised in the 2022 audit response.
Team response
2026-10-28, Meson Discord admin ("MrFish"): "some of the code may have deviated over time, that is expected as new features or code is pushed; the audit of such deviation will only be done at a later stage or when possible… I too am aware that some of the information in the docs are outdated. They will be updated at a later time." The same admin later called the report "a minor thing" that does not "warrant immediate attention." No technical dispute was received. Update, later the same day: after our follow-up, MrFish acknowledged the feedback and an engineering contact was established.
The dominant swap path pulls from user wallets — no escrow, no lock, no cancel
directSwap / directRelease / directExecuteSwap / simpleExecuteSwap on the deployed implementation
37 of the last 50 MESON-labelled Ethereum transactions run the direct flow (22× directRelease, 12× simpleExecuteSwap, 3× directExecuteSwap) versus only 2× executeSwap and 5× postSwap on the audited escrow path. The direct flow is a pull model absent from all four audits and from all documentation.
- directExecuteSwap(encoded, …) pulls `amount` from the initiator's wallet into a shared pool (index 1, owner 0x0014Eb…53C), gated only by the user's pre-signed release signature.
- No target-side proof, no lock, no 40-minute wait, no LP collateral.
- cancelSwap reverts ("Swap does not exist") — postedSwap == 0 on this path — so the user has zero on-chain recourse if the pool operator misbehaves.
- Funds land in the operator-custody pool; withdraw() is owner-gated. The pull is therefore not directly profitable for random outsiders — it is a custodial trust position: operator-drain risk plus a phishing vector for the pre-signed release. Fake-support accounts hunting exactly such signatures are active in Meson's own Discord (see User guidance).
- Fork-demonstrated: user −100 USDC exact. simpleExecuteSwap is benign — it self-pulls from msg.sender, not from the user.
Recommendation
- Document the direct flow's trust model prominently — users currently cannot see which trust model their swap uses.
- Add target-side proof before the source-side pull, and an on-chain cancel window.
- Consider per-operator caps on the pull path.
Team response
Same as F-1: no technical dispute. Update, 2026-10-28: an engineering contact was established; the deviation-audit question is now reviewed together with the team.
One EOA key controls the upgrade path on every EVM chain — and that surface is undocumented
ProxyToMeson (UUPS) / MesonConfig — admin surface
The deployment is a UUPS proxy whose implementation is unverified bytecode on every explorer. The admin surface, reconstructed from bytecode storage-slot analysis, event topics, and live probes:
| Role / mechanism | Address | Detail |
|---|---|---|
| Proxy owner (slot 0x134) | 0x000039DdCF1F63Cf3555e62a8D32a11bD1E7E1E1 | Plain EOA. Controls the UUPS upgrade path (upgradeTo / upgradeToAndCall), the token list (addSupportToken / removeSupportToken / addMultipleSupportedTokens), withdrawServiceFee, transferPoolOwner, transferPremiumManager, and adjustToPool(uint8,uint256,uint40) — semantics unresolved. |
| PremiumManager (slot 0x135) | 0x666d6b8a44d226150ca9058bEEbafe0e3aC065A2 | EIP-7702-delegated EOA; delegate 0xe40ccb2d94975c51bff0c004efdfd9b3a5796fa4 — 47.9 KB, verified 2026-08-25 as a generic OpenZeppelin-based ERC-4337 SmartWalletEntry (validateUserOp, execute/multicall, ERC-1271, ERC-165, P256/WebAuthn). Whoever controls the EOA key can route arbitrary calldata through the account. |
- No timelock, no pause, no multisig, and no signature-invalidation capability exists in the 45-selector dispatch.
- The owner-gated set touches nothing in the posted-swap state — an owner cannot cancel swaps, but can replace the entire implementation at will.
- Single point of failure: the same canonical proxy address is deployed on every EVM chain. One compromised owner key = implementation replacement across all chains simultaneously.
Recommendation
- Move ownership to a multisig with a timelock; publish the admin-surface policy.
- Verify the implementation source on all explorers — it is currently unverified bytecode.
- Document the premiumManager role and the 7702 delegate's capabilities.
- Resolve and publish adjustToPool semantics.
Every swap under $0.50 fails to release on the target chain
MesonPools release()
releaseAmount = amount − lpFee − max(amount/2000, 500000) underflows whenever amount − lpFee < 1000 units ($0.50 in USDC-6 decimals): Solidity arithmetic panic 0x11. release() permanently reverts for that encoding. The relayer admits swaps down to $0.01, so sub-$0.50 target legs always fail to release; the user must wait for expiry + cancelSwap to recover funds. No fund loss — a liveness bug on a real user path.
- Evidence: the panic was reproduced on a fork for any sub-$0.50 encoding.
- Suggested fix: clamp releaseAmount to zero, or skip the service-fee floor when amount < 1000 units.
Re-posting a cancelled-then-expired swap panics instead of reverting gracefully
verifyEncodedSwap
Re-posting the encoding of a swap that was cancelled and then expired hits an arithmetic panic (0x11) instead of a clean revert — demonstrated on a fork. No value at risk; raw panics make failure harder to debug for integrators.
Deployed bytecode drifts from the audited sources — and the sources are now private
Deployed implementation vs audited commit 47836cbe…
17 of the 37 functions in the official SDK ABI (npm mesonfi-contract-abis@1.14.0) are absent from the audited 2022/2023 sources: directSwap, directRelease, directExecuteSwap, adjustToPool, withdrawServiceFee, transferPoolOwner, transferPremiumManager, addSupportToken, removeSupportToken, addMultipleSupportedTokens, simpleExecuteSwap, postSwapWithSignature, postSwapFromInitiator, postSwapFromContract, lockSwap, and the UUPS standard functions. The meson-contracts-solidity repo has been privatized, so no outsider can source-diff the deployed bytecode against the audited commit, and the docs' GitHub links are dead. We reconstructed the deployed interface (45 selectors, swap encoding layout, signature digest schemes) and shared it with the team, together with a fork-test suite, so they can audit the drift against their private repo.
User guidance
What actually protects you
- The escrow path's 40-minute LP lock — and the fact that you can outrun a stalling LP yourself: release() on the target chain and executeSwap() on the source chain are permissionless for the signature holder. Don't sit on your release signature.
- cancelSwap refunds after expiry, and the 100k per-swap amount cap (MAX_SWAP_AMOUNT).
- The service fee is waived for small activity (≤ $3,000 / 3 swaps/day/address).
What does not protect you
- The direct flow — where most traffic runs: no escrow, no lock, no collateral, no cancelSwap. Your recourse there is the pool operator's good behavior, nothing on-chain.
- executeSwap accepts anyone holding your release signature and has no expiry enforcement on the source leg.
- Admin: one EOA key can replace the implementation on every EVM chain. No multisig, no timelock, undocumented.
Scam warning — fake support is active in Meson's community channels
During our own disclosure conversation with the real team (October 2026), we were approached multiple times by fake "support" accounts in Meson's Discord. Whoever holds a Meson release signature can take the user's source funds even after expiry (F-1) — exactly what a fake-support scammer will ask you for. Treat every unsolicited DM from someone claiming to be Meson staff or support as hostile until they verify themselves in a public channel.
Practical rules if you use Meson
- Publish your release signature immediately once the target-side lock appears — or self-release and self-execute inside the 40-minute window.
- Treat direct-flow swaps as trusting Meson's pool operator directly. Keep those sizes small until the path is documented or fixed.
- Never share your release signature with anyone — whoever holds it can take your source funds, past expiry.
- You can tell which path you are on from the transaction method: directRelease / simpleExecuteSwap / directExecuteSwap = direct path (operator custody); postSwap / executeSwap = escrow path (locked LP collateral).
- Sub-$0.50 swaps will fail to release on the target chain — wait for expiry + cancelSwap for the refund.
- Never engage a "support" DM: fake-support accounts approached us multiple times in Meson's Discord while we were talking to the real team. Real staff verify in public channels; a legitimate supporter will never need your release signature, seed phrase, or a link you got in a DM.
Audit-coverage cross-check
Each prior audit's findings were tested against the live deployment and its status recorded — fixed, unfixed, or fixed-in-name-only.
| Prior audit | Relevant content | Status on the live deployment |
|---|---|---|
| SSLab (2022-02), Finding #4 — LP grabs release signature from mempool | High severity; economically equivalent to our F-1 | Marked "Confirmed and Fixed" — the fix is the 100k per-swap amount cap only. The loss window itself is still open on the 2026 bytecode. |
| SSLab (2022-02), Finding #8 — monitoring + on-chain blacklist recommendation | Off-chain detection + blacklist support for dishonest LPs | "Confirmed" — never implemented. No blacklist or invalidation capability exists in the 45-selector dispatch. |
| ToB design review (2022-07) — LP misbehavior | Team response: "the Meson team plans to enact a penalty for misbehaving LPs" | Penalty promised 2022 — no penalty mechanism in the 2026 bytecode. |
| ToB security review (2022-10) — 15 findings | Closest: TOB-MES-1 hash collision (High) | 13/15 resolved per the fix review; typed encodings (TOB-MES-2) unresolved. None cover the direct flow. |
| All four audits | Scope | 20 of 37 SDK-ABI functions trace to audited sources. The direct flow — most live traffic — is in none of them. |
Disclosure timeline
- 2026-10-11/12Findings verified by fork-testing the live deployment; docs-vs-code drift and the direct flow mapped.
- 2026-10-13Full disclosure document delivered to Meson via Discord ticket (findings summary, F-1/F-1b/F-2 details, admin surface, ask, suggested mitigations).
- 2026-10-16Implementation re-verified unchanged (0x3c77…D906); user recourse paths re-checked; F-1 rated Medium — the 40-minute window is user-raceable.
- 2026-10-28Team response on Discord (admin "MrFish"): docs drift acknowledged, deviation audit deferred "at a later stage or when possible", report called "a minor thing." We replied offering a 15-minute walkthrough with an engineer; no engineer contact followed.
- 2026-10-28 · updateMrFish received our feedback and acknowledged it; an engineering contact was established. The findings move into cooperative review.
- 2026-10 (disclosure window)While in a live ticket with the real team, our researchers were approached multiple times by fake "support" accounts in Meson's Discord. We offered the team free monitoring for such scammer activity.
- 2026-11-04This report published. A 30-day window for the F-1/F-1b fixes starts at publication.
Methodology & reproducibility
Findings were established by executing the deployed contracts on a local fork of Ethereum mainnet state and cross-checking live on-chain behavior — recent transaction paths, on-chain storage and constants, revert messages, and exact balance deltas in the demonstrated scenarios. No mainnet transactions were sent. SpotBlock's testing methodology is internal and is not part of this report. The verification package (reconstructed interface and executable test suite) was offered to the Meson team during disclosure and remains available to them on request; a summary of the findings was shared in the disclosure document.
About SpotBlock Labs
SpotBlock Labs (Zurich) builds blockchain threat intelligence: we watch Ethereum mainnet around the clock, flag malicious contracts and wallet behavior, and deep-analyze suspicious deployments. The same telemetry powers the audits above — live deployments tested the way an attacker would, with working proofs and disclosure handled with the team first. We offer audits of live deployments, real-time contract/wallet monitoring, and custom integrations. spotblock.org · contact