Cross-chain, DeFi and smart contracts · Lesson 2 of 6
DEX swaps, instant exchanges and liquidity flows
12 min read
Almost every laundering trail changes asset somewhere, and the way it changes decides how strong the next link can be. A swap on a decentralized exchange (DEX) is recorded in one transaction, with the pool's event, the token transfers and the reserves before and after. A cross-chain swap protocol can write the destination into the source chain and the source into the destination chain. An instant-exchange service or an OTC desk leaves only a deposit on one side and a payout on the other. This lesson shows how to read each kind of swap as evidence, what liquidity events reveal, which records exist off chain, and what you may state about each link. General decoding is in Lesson 5.1, matching hops across chains in Lesson 5.3, and bridges in Lesson 5.4.
Reading a DEX swap
Pools, token0 and token1
A Uniswap v2-style pair is a contract holding two tokens. The token with the lower address is token0 and the other token1; the order is fixed at creation and has nothing to do with which token is "the price". Every event reports amounts in this order, so look up token0, token1 and both decimals before converting anything.
The v2 event is Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to), topic0 0xd78ad95f…d822. After every change in reserves the pair also emits Sync(uint112 reserve0, uint112 reserve1). A decoded swap in a pair where token0 is USDC (6 decimals) and token1 is WETH (18 decimals):
{
"event": "Swap",
"pair": "0x3f8a…e2d1",
"sender": "0x7a2c…48d0",
"to": "0xa1b2c3d4…9f0e",
"amount0In": "0",
"amount1In": "5000000000000000000",
"amount0Out": "14880819116",
"amount1Out": "0",
"next_log": {"event": "Sync", "reserve0": "2985119180884", "reserve1": "1005000000000000000000"}
}
Five WETH went in and 14,880.819116 USDC came out, an execution price of 2,976.16 USDC per WETH. The sender is usually a router, not the trader, and to is where the output went; confirm the trader from the token transfers in the same transaction.
Other pool designs
Uniswap v3 pools emit Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick), topic0 0xc42079f9…ca67, with amounts signed from the pool's point of view: positive into the pool, negative out. A swap of 2 WETH for USDC shows amount0 = -5994120000 (5,994.12 USDC out) and amount1 = 2000000000000000000 (2 WETH in). The post-swap price is price_raw = (sqrtPriceX96 ÷ 2^96)², in token1 base units per token0 base unit, times 10^(decimals0 − decimals1). For sqrtPriceX96 = 1446501726624926496477173928747177, price_raw ≈ 333,333,333.33; times 10^−12 that is 0.000333333 WETH per USDC, or 3,000 USDC per WETH (tick ≈ 196,256, since price_raw = 1.0001^tick). Skipping the decimal adjustment gives a price off by 10^12.
Uniswap v4 (2025) keeps all pools in one singleton PoolManager, so the log's address no longer identifies the pool; the indexed pool id does. Its Swap event (topic0 0x40e9cecb…112f) signs amounts from the user's point of view, the opposite of v3. Curve pools emit TokenExchange with coin indexes. Keep a decoder per protocol and version, tested on a transaction whose result you know.
Four rules for a trace
- The link is deterministic, the asset changes. Input and output appear in the same transaction. Record both amounts, the effective rate and, for a fiat value, the price source and time. Whatever tracing method you apply (Lesson 3.3), the output of the swap is the proceeds of its input.
- The pool is not a counterparty. A liquidity pool is a contract holding many providers' funds. Funds do not "go to" the pool owner; follow the output, not the pool.
- The recipient may differ from the sender. Routers and aggregators accept a recipient parameter, so the output can be paid to a fresh address in the same transaction. Read the decoded call or the transfers; never assume the caller received the output.
- Net the route. An aggregator splits one order across pools in one transaction. What left the subject and what reached the recipient are the facts; the route is detail.
DEX contracts have no operator who keeps records, but the interface a subject used may: web front ends and aggregator APIs can log IP addresses, user agents and quote requests, and wallet applications may route swaps through their own APIs. Retention depends on the operator.
Netting an aggregator route
| logIndex | Token | From | To | Amount |
|---|---|---|---|---|
| 10 | WETH | Trader | Router | 10 |
| 11 | WETH | Router | Pool A (WETH/USDC) | 6 |
| 12 | USDC | Pool A | Router | 17,880 |
| 13 | WETH | Router | Pool B (WETH/DAI) | 4 |
| 14 | DAI | Pool B | Pool C (DAI/USDC) | 11,930 |
| 15 | USDC | Pool C | Router | 11,925 |
| 16 | USDC | Router | Trader | 29,805 |
Netting every address's ins and outs collapses this to one statement: the trader sold 10 WETH for 29,805 USDC, an average of 2,980.50 USDC per WETH. The router nets to zero and each pool to its own reserve change.
-- Net token change per address within one transaction
SELECT address, token_address, SUM(delta) AS net_raw
FROM (
SELECT to_address AS address, token_address, amount_raw AS delta
FROM token_transfers WHERE transaction_hash = '0x9e1d…b7a4'
UNION ALL
SELECT from_address, token_address, -amount_raw
FROM token_transfers WHERE transaction_hash = '0x9e1d…b7a4'
) t
GROUP BY address, token_address
HAVING SUM(delta) <> 0;
Native ETH legs must be added from traces. In intent-based systems a solver, not the user, sends the transaction, so tx.from is the solver; find the user from the settlement contract's trade events and transfers.
Liquidity flows, price impact and MEV
Adds and removes
Adding stolen funds to a pool and removing them later is not a swap: the depositor receives an LP token or position, and the removal returns the share. Follow the position, not the pool's balance.
| Protocol | Add | Remove | Ownership record |
|---|---|---|---|
| Uniswap v2 | Mint(sender, amount0, amount1) plus LP-token Transfer from the zero address | LP tokens sent to the pair, Burn(sender, amount0, amount1, to), LP Transfer to zero | Fungible LP token (the pair contract) |
| Uniswap v3 | Pool Mint with tick range; IncreaseLiquidity on the position manager | Pool Burn (credits tokens), then Collect (pays them out); DecreaseLiquidity | Position NFT (ERC-721) |
| Uniswap v4 | ModifyLiquidity in the PoolManager | Same event, negative liquidity delta | Position records, often an NFT |
Two traps: in v3 the pool's Mint shows the position manager as owner, so follow the position NFT to the real provider; and a v3 Burn moves no tokens, the money leaves in Collect. A classic rug pull is a deployer who creates a token, adds liquidity, waits for buyers, then removes nearly all liquidity in one transaction; the Burn or DecreaseLiquidity amounts measure what was taken.
Price impact
Price impact compares the execution price with the pool's spot price just before the trade. For a v2 pair, reserves before the swap equal the reserves in its Sync event minus the inputs plus the outputs. In the swap above: 2,985,119.18 + 14,880.82 = 3,000,000 USDC and 1,005 − 5 = 1,000 WETH, a spot price of 3,000.
| Measure | Value |
|---|---|
| Spot price before | 3,000.00 USDC per WETH |
| Execution price | 2,976.16 (−0.79%) |
| Output without the 0.30% fee | 14,925.37, price 2,985.07 (−0.50%) |
| Spot price after (from Sync) | 2,970.27 (−0.99%) |
Of the 0.79% shortfall, about 0.30% is the fee and 0.50% pure price impact; the spot price moved about twice as far as the average price paid, normal for constant-product pools. Large impact on a thin pool signals forced selling, such as an exploiter dumping a stolen token.
MEV patterns
Maximal extractable value (MEV) has recognizable shapes. In a sandwich, in one block and pool, actor X buys token T, a victim buys T, and X sells T right after, often paying the block builder directly (an ETH transfer to the fee recipient, visible in traces); define the actor as the bot contract that received the output, because bots rotate sending addresses. Atomic arbitrage swaps through a cycle of pools (WETH → USDC → DAI → WETH) in one transaction and ends with more of the starting token. Just-in-time (JIT) liquidity is a v3 Mint just before a large swap and a Burn and Collect just after, by one address. Hits are candidates: check quantities and profit, and rule out innocent explanations such as two unrelated arbitrageurs.
Cross-chain swap protocols: memos as evidence
Cross-chain swap protocols exchange native assets between chains through vaults that the protocol's nodes control. THORChain is the reference example, and its records are unusually useful because both sides carry text that names the other.
On the inbound side, the user sends the asset to the protocol's vault: on EVM chains through a router contract that records the memo in its deposit event; on Bitcoin in an OP_RETURN output, which the protocol's documentation limits to 80 bytes. The swap memo format is SWAP:ASSET:DESTADDR/REFUNDADDR:LIMIT/INTERVAL/QUANTITY:AFFILIATE:FEE (the refund address is optional), usually shortened with = for a market swap. On the outbound side, the vault pays the destination asset in a transaction whose memo is OUT: followed by the inbound transaction hash; a failed swap is refunded with a REFUND: memo carrying the same hash. A fictional pair:
Ethereum (inbound, fictional)
tx 0x9a3f…c21e from 0x3f9c…a1d7 to swap router 130.0 ETH
deposit event memo "=:BTC.BTC:bc1q…r7w2::xx:20"
Bitcoin (outbound, fictional)
txid 6d0b…e45a from vault bc1q…v9tn
vout 0 5.16800000 BTC bc1q…r7w2
vout 1 OP_RETURN "OUT:9A3F…C21E"
The inbound memo names the Bitcoin recipient; the outbound memo names the Ethereum transaction. The pair can be verified on both chains from your own nodes, and the protocol's public records give a third, independent confirmation. Three details matter:
- Timing. Streaming swaps execute as sub-swaps over several blocks, and limit swaps can wait in a queue for up to 43,200 protocol blocks (about three days) by default. Set time windows from the memo parameters.
- Affiliates. The affiliate field names, by a registered short name, the interface or wallet that built the transaction: a possible source of logs, though the protocol itself has none.
- Reference memos. To save memo space, a memo can be registered in advance and referenced, for example by an amount-encoded reference; registrations expire after the
MemolessTxnTTLparameter, by default 3,600 blocks (about six hours). Preserve the registration record with the transactions.
Other protocols use different fields, but the method is the same: find what each side says about the other.
Instant-exchange services and OTC desks
Instant-exchange services convert one asset into another without an account: the user gives a payout address, receives a fresh deposit address for the order, sends funds and is paid out, often on another chain. Many call themselves non-custodial because they keep no balances, but they control the funds between deposit and payout, which is why the trail breaks there, and exchanging one virtual asset for another for or on behalf of a customer is VASP activity under the FATF definition used in Recommendation 15. On chain they look like any custodial service: per-order deposit addresses, sweeps, payouts from a hot wallet. Without records, the deposit-payout link is an amount-and-time inference (Lesson 5.3); with records, it is documented. A service may hold:
| Record | Evidential use |
|---|---|
| Order ID, creation time, assets and quoted rate | Ties a deposit address to one order |
| Deposit address and deposit txid | Confirms which deposit belongs to the order |
| Payout address and payout txid | Converts the inferred link into a recorded one |
| Refund address | Often a wallet the subject controls; links other orders |
| IP address, user agent, language settings | Leads for attribution (Lesson 4.7) |
| Email or contact given for support | Identifier for further legal process |
| Partner or affiliate ID | Identifies the wallet or website that sent the order |
| Risk flags, holds and screening results | Shows whether the service froze or questioned the order |
Ask for all orders sharing the payout address, refund address or IP address in the period, not just the one you found: the history often reveals the subject's other wallets. IPs may be VPNs and contact data is unverified. Cooperation is often slow, so send preservation requests as soon as the deposit is identified (Lesson 1.4).
An OTC desk negotiates trades off chain and settles to and from its own addresses. The legs may sit on different chains, or one may be a bank transfer, so there is often no on-chain link at all; the desk's records (due diligence, trade confirmations, settlement instructions, chat logs, bank details) are the only bridge. A broker trading through an account at a larger exchange adds a layer: the exchange sees one customer, the broker (Lesson 6.5).
What you may state about each swap link
| Evidence available | Basis of the link | Wording in a report |
|---|---|---|
| Same-transaction DEX swap | Deterministic (grade A) | "In transaction T, X was exchanged for Y and paid to address B" |
| Cross-chain memo on both chains | Deterministic on both chains (grade A), also protocol-recorded | "The protocol paid Z to address B in respect of inbound transaction A" |
| Instant exchange, amount and time only | Inference (grade D) | "Consistent with", with candidate count and chance-match rate |
| Instant exchange with order record | Record-confirmed (grade B) | "According to the service's records, order N paid Z to address B" |
| OTC desk, no records | None | "The destination of these funds is not known" |
The grades are those of Lesson 3.2. A record-confirmed link is only as reliable as the record: name the producer, the date received and the hash of the file as received.
Exam focus: token0/token1 ordering and decimals; v2 Swap and Sync events; v3 signed amounts (positive into the pool) and converting sqrtPriceX96 with the decimal adjustment; v4's PoolManager, pool id and reversed sign; DEX swaps as deterministic links that change the asset, pools as non-counterparties and recipient parameters; netting an aggregator route and why tx.from may be a router or solver; position NFTs, Burn-then-Collect and rug pulls; price impact from reserves; sandwich, arbitrage and JIT signatures; cross-chain memos, OUT: and REFUND: carrying the inbound hash, swap timing, affiliates and reference memos; instant exchanges as VASPs and their records; OTC desks with no on-chain link; matching wording to the basis of each link.
Practice questions
Check your understanding. These questions do not count towards the exam.
Sign in to save your progress and continue where you left off. It is free. Sign in