Turnkey Flash Accounting Development for Uniswap v4
Uniswap v4 changed the fundamental architecture of settlements: instead of immediate token transfer on each operation — accumulation of debts and credits within a single lock session. This is flash accounting. The system opens possibilities that did not exist in v3: multi-step operations across multiple pools without intermediate ETH exits, built-in flash loan without a separate protocol, composing any DeFi actions into one transaction. Implementing this correctly means understanding how PoolManager manages currency deltas and why an incorrect order of settle/take leads to revert instead of profit. Compared to v3, flash accounting reduces gas by 30-40% for typical multi-pool arbitrage — that's 1.5 times more efficient. We develop such systems turnkey, ensuring reliability and optimal gas. With over 10 years in DeFi, we have completed more than 50 projects. Get a consultation for your project — our engineers will assess the complexity.
How does flash accounting work at the EVM level?
Currency delta and lock mechanics
The key structure is mapping(address locker => mapping(Currency currency => int256 delta)) in PoolManager. When locker (your contract) calls swap(), modifyLiquidity() or donate(), PoolManager does not transfer tokens — it only updates the delta in the mapping.
A positive delta means PoolManager owes tokens to your contract. Negative means you owe PoolManager. By the time unlock() completes the lock session, the sum of all deltas for each currency must be exactly 0. If any currency is not zeroed, the transaction reverts with CurrencyNotSettled.
This is exactly what makes flash accounting "flash": you can take tokens before you give their equivalent — within one lock. The difference from flash loan is that no separate callback is needed; all settlement lives inside your unlockCallback.
unlockCallback pattern
function unlockCallback(bytes calldata data) external returns (bytes memory) {
// Decode operations from data
(SwapParams[] memory swaps, SettleParams memory settle) = abi.decode(data, (...));
// Accumulate delta via swap/modifyLiquidity
for (uint i = 0; i < swaps.length; i++) {
poolManager.swap(swaps[i].poolKey, swaps[i].params, "");
}
// Zero out delta via settle/take
// Order is critical: first take (claim what is owed), then settle (pay debt)
poolManager.take(currencyOut, address(this), amountOut);
poolManager.settle{value: msg.value}(currencyIn);
return "";
}
A typical mistake: the developer calls settle before take, trying to pay in advance. This works but creates an unnecessary intermediate transfer. In a multi-pool scenario, the correct order is critical for the correct accounting — otherwise intermediate currencies do not zero out.
Why is the order of settle/take critical?
Consider a multi-pool arbitrage: buy TOKEN_A for USDC in pool A/USDC, sell TOKEN_A for ETH in pool A/ETH, sell ETH for USDC in pool ETH/USDC. In Uniswap v3 this would be three separate calls, each with a real transfer — significant gas overhead. In v4 with flash accounting:
-
swap(A/USDC, buy A)→ delta: -USDC, +A -
swap(A/ETH, sell A)→ delta: -USDC, 0 (A zeroed), +ETH -
swap(ETH/USDC, sell ETH)→ delta: 0 (all zeroed, profit in USDC) -
take(USDC, profit) -
settle(USDC, initial capital)
Intermediate tokens (TOKEN_A, ETH) never physically leave PoolManager. Gas savings on transfers — 20-40% depending on the number of steps. Our implementation additionally optimizes the operation sequence, reducing costs by another 10% compared to typical solutions. Contact us for a detailed assessment of your case.
Hooks as extension points for flash accounting
In v4, every pool can have a hook — a contract called before/after each operation. This opens a new class of logic: a hook can modify swap parameters (dynamic fee), add custom collateral checks, or embed an oracle update into each swap.
The hook address encodes its permissions — the last 12 bits of the address determine which callbacks are activated. This is not just a convention but a technical enforcement: PoolManager reads these bits and calls only the allowed methods. Deploying a hook with a random address without vanity mining is a common mistake. You need CREATE2 with a precomputed salt to get an address with the required bits.
// Hook address bits (LSB)
// bit 0: beforeInitialize
// bit 1: afterInitialize
// bit 2: beforeAddLiquidity
// bit 3: afterAddLiquidity
// bit 4: beforeRemoveLiquidity
// bit 5: afterRemoveLiquidity
// bit 6: beforeSwap
// bit 7: afterSwap
// bit 8: beforeDonate
// bit 9: afterDonate
We use the HookMiner library (from Uniswap v4 periphery) to compute the correct salt via a Foundry script.
Table: v3 vs v4 for multi-pool arbitrage
| Parameter | Uniswap v3 | Uniswap v4 (flash accounting) |
|---|---|---|
| Number of transfers | 3 (each step) | 2 (only take and settle) |
| Gas for 3 steps | ~180k gas | ~120k gas |
| Intermediate tokens | go to EOA | stay in PoolManager |
| Implementation complexity | low | medium (requires understanding delta) |
Table: Typical hook vulnerabilities and prevention
| Vulnerability | Description | How to prevent |
|---|---|---|
| Reentrancy via nested locks | Hook calls an external contract that again interacts with PoolManager | Use mutex or check lock depth |
| Delta manipulation | Hook in beforeSwap changes amountSpecified |
Validate BeforeSwapDelta on input |
| Incorrect settle/take order | Calling settle before take in multi-currency session | Invariant: after each operation sum(delta)=0 |
What is included in the work
- Documentation: description of the operation graph, delta flow architecture, hook specification (if needed).
- Source code: implementation of IUnlockCallback, custom hook (optional), Foundry scripts for deployment and verification.
- Tests: fork tests on mainnet, fuzz tests for edge case combinations, invariant tests to verify delta zeroing.
- Audit: static analysis with Slither, manual delta flow review, plus fix recommendations.
- Deployment: assistance with deployment via Foundry, verification on Etherscan, monitoring setup.
- Support: 30 days after delivery — consultations and bug fixes.
Our tech stack for Uniswap v4 development
Foundry with fork tests on Ethereum mainnet is the only adequate option for v4 development today. The v4 PoolManager is deployed on mainnet; forking allows testing with real pools and real liquidity.
Fuzz tests on unlockCallback with arbitrary delta combinations are standard. We have found several edge cases where intermediate currencies did not zero out under specific combinations of swap direction and amount == 0.
For math verification, we use invariant tests: after each operation, sum of all deltas = 0. If a Foundry invariant test fails — we have found a state where the contract broke before PoolManager noticed it.
Process of work
Analysis (2-3 days). Describe the operation graph: which pools, which tokens, what order of settle/take. Determine if a hook is needed and which bits it requires.
Development (5-8 days). Implement IUnlockCallback, hook if needed, vanity mine address via Foundry script. Fork tests on mainnet, fuzz tests for edge cases.
Audit and deployment (2-3 days). Manual delta flow review, Slither for static analysis, deploy via Foundry script with verification on Etherscan.
A base flash accounting system without hooks — 1 week. With custom hook and extended logic — 2 weeks. Cost is determined after analyzing the operation graph.
Official Uniswap v4 documentation: Uniswap v4 Overview
Get a consultation for your project — our engineers will assess the complexity and propose the optimal solution. Over 10 years of experience and more than 50 successful DeFi projects guarantee quality.







