Skip to content

Commit 70c7e8a

Browse files
vendrell46saucepoint0xdevant
authored
StateView & Flash Accounting guides added (#848)
Co-authored-by: saucepoint <98790946+saucepoint@users.noreply.github.com> Co-authored-by: ant <0xdevant@gmail.com>
1 parent d5ce3fa commit 70c7e8a

File tree

2 files changed

+544
-0
lines changed

2 files changed

+544
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
---
2+
title: StateView
3+
---
4+
5+
# Introduction
6+
7+
When building on **Uniswap v4**, you will often need to read pool state for both onchain and offchain use cases. Onchain contracts can directly invoke the [**StateLibrary**](https://github.com/Uniswap/v4-core/blob/main/src/libraries/StateLibrary.sol) to execute these reads during transactions, but offchain systems—such as frontends or analytics services—require a deployed contract with view functions. This is where [**StateView**](https://github.com/Uniswap/v4-periphery/blob/main/src/lens/StateView.sol) comes in.
8+
9+
> *In short: Use StateLibrary within onchain contracts and use StateView with an RPC for frontends and analytics.*
10+
>
11+
12+
By providing a dedicated interface for offchain reads, **StateView** helps:
13+
14+
- Retrieve pool state without paying gas
15+
- Simplify integration for frontends, dashboards, and analytics
16+
- Ensure a clean separation between onchain logic and offchain queries
17+
18+
## Comparing onchain and offhain Access
19+
20+
If you’re familiar with [Reading Pool State](/contracts/v4/guides/read-pool-state), you already know that Uniswap v4 uses **extsload** for efficient data access. For onchain usage, we rely on **StateLibrary** within contracts. However, offchain clients cannot rely on an onchain library for state reads.
21+
22+
Instead, **StateView** provides these same calls in a single contract designed explicitly for offchain consumption.
23+
24+
> *Because StateLibrary operates via onchain function calls, it’s not directly accessible to offchain clients. Hence, StateView provides a simple, gas-free interface designed for frontends and analytics.*
25+
>
26+
27+
For instance, an onchain contract might use the `StateLibrary` as follows:
28+
29+
```solidity
30+
// Onchain contract using StateLibrary
31+
contract MyProtocol {
32+
using StateLibrary for IPoolManager;
33+
34+
function checkPoolPrice(PoolId poolId) external returns (uint160) {
35+
(uint160 sqrtPriceX96, , , ) = poolManager.getSlot0(poolId);
36+
// ... use the price in contract logic ...
37+
return sqrtPriceX96;
38+
}
39+
}
40+
```
41+
42+
By contrast, an offchain frontend or analytics service should interact with `StateView`:
43+
44+
```tsx
45+
// Frontend or analytics client using StateView
46+
const stateView = getContract({
47+
address: STATE_VIEW_ADDRESS,
48+
abi: stateViewABI
49+
});
50+
51+
const { sqrtPriceX96 } = await stateView.read.getSlot0([poolId]);
52+
// ... use the price in your application ...
53+
```
54+
55+
This separation ensures that each context (onchain vs. offchain) uses the most efficient data reading pattern.
56+
57+
# Usage With Frontend Clients
58+
59+
Frontend applications frequently display real-time information about pools, positions, and other market data—without incurring transaction costs. **StateView** addresses these requirements by exposing read-only functions tailored for offchain integrations.
60+
61+
## Setting Up With Viem
62+
63+
We’ll use [**viem**](https://viem.sh/), a TypeScript library for Ethereum, to demonstrate how to connect to **StateView**.
64+
65+
```tsx
66+
import { createPublicClient, http } from 'viem';
67+
import { mainnet } from 'viem/chains';
68+
69+
// Initialize the client
70+
const client = createPublicClient({
71+
chain: mainnet,
72+
transport: http()
73+
});
74+
75+
// Set up StateView contract instance
76+
const stateView = getContract({
77+
address: STATE_VIEW_ADDRESS,
78+
abi: stateViewABI,
79+
client
80+
})
81+
```
82+
83+
> **Note:** _The stateView object comes from our getContract call above. Make sure you’ve imported stateViewABI correctly before attempting to read from the contract._
84+
>
85+
86+
With this setup, you can now:
87+
88+
- **Connect to an Ethereum network**
89+
- **Call StateView’s read functions**
90+
- **Retrieve pool information offchain at no gas cost**
91+
92+
### Handling Errors and Invalid Pool IDs
93+
94+
When calling `stateView.read.<function>([poolId])`, be mindful that:
95+
96+
- If you pass an invalid `poolId` (typically a [`bytes32`](https://github.com/Uniswap/v4-core/blob/main/src/types/PoolId.sol#L6) in Uniswap v4), the call may revert or return unexpected data.
97+
- Consider adding try-catch (or equivalent error handling in your framework) to gracefully handle failures if the pool does not exist or if the call fails onchain.
98+
99+
# Reading Pool Data
100+
101+
Here are common examples of how to retrieve pool data using **StateView**.
102+
103+
## Getting Pool State
104+
105+
A pool’s core state, such as its current price or fees, is often necessary for frontends. Use `getSlot0`:
106+
107+
```tsx
108+
// Example: Reading pool price and fees
109+
const getPoolState = async (poolId: string) => {
110+
// getSlot0 returns:
111+
// - Current price (sqrtPriceX96) in Q64.96 fixed-point format
112+
// - Active tick
113+
// - Protocol and LP fee settings
114+
const {
115+
sqrtPriceX96,
116+
tick,
117+
protocolFee,
118+
lpFee
119+
} = await stateView.read.getSlot0([poolId]);
120+
121+
return {
122+
price: calculatePrice(sqrtPriceX96), // implement your math logic for Q64.96
123+
tick,
124+
protocolFee,
125+
lpFee
126+
};
127+
};
128+
```
129+
130+
**What it Returns:**
131+
132+
- **`sqrtPriceX96`**: The current pool price in Q64.96 fixed-point format.
133+
- **`tick`**: The current tick in which the pool is operating.
134+
- **`protocolFee`** and **`lpFee`**: Fee parameters for protocol and LP fee tiers.
135+
136+
## Getting Pool Liquidity
137+
138+
To understand how much liquidity a pool holds:
139+
140+
```tsx
141+
// Example: Reading the total active liquidity of a pool
142+
const getPoolLiquidity = async (poolId: string) => {
143+
// getLiquidity returns the total liquidity currently active in the pool
144+
const liquidity = await stateView.read.getLiquidity([poolId]);
145+
return liquidity;
146+
};
147+
```
148+
149+
**Why It Matters:**
150+
151+
- Helps gauge the depth of the pool
152+
- Influences price impact calculations in trading
153+
- Provides context for the pool’s capacity to absorb trades
154+
155+
# Core Functions and Return Types
156+
157+
While **StateView** exposes many functions, here are several essential calls for most offchain applications. Each function typically takes a `poolId` (of type `bytes32`) as the key input, identifying which pool to query.
158+
159+
1. **[`getSlot0(poolId)`](/contracts/v4/reference/periphery/lens/StateView#getslot0)**
160+
- Returns `(uint160 sqrtPriceX96, int24 tick, uint8 protocolFee, uint8 lpFee)`.
161+
- Essential for displaying real-time price data and fees.
162+
2. **[`getLiquidity(poolId)`](/contracts/v4/reference/periphery/lens/StateView#getliquidity)**
163+
- Returns `uint128 liquidity` (the total active pool liquidity).
164+
- Used to assess trading depth and volatility.
165+
3. **[`getPositionInfo(positionId)`](/contracts/v4/reference/periphery/lens/StateView#getpositioninfo)**
166+
- Returns `(uint128 liquidity, uint256 feeGrowthInside0Last, uint256 feeGrowthInside1Last)`.
167+
- Critical for tracking user positions, especially to calculate earned fees over time.
168+
4. **[`getFeeGrowthGlobals(poolId)`](/contracts/v4/reference/periphery/lens/StateView#getfeegrowthglobals)**
169+
- Returns `(uint256 feeGrowthGlobal0, uint256 feeGrowthGlobal1)`.
170+
- Useful for analytics around total fee accumulation in the pool.
171+
172+
### Note on `poolId` and `positionId`
173+
174+
- In **Uniswap v4**, a `poolId` is typically a `bytes32` that is derived by calling
175+
`keccak256(abi.encode(poolKey))` where poolKey contains:
176+
- currency0: The lower currency address of the pool
177+
- currency1: The higher currency address of the pool
178+
- fee: The pool LP fee (uint24)
179+
- tickSpacing: The tick spacing value (int24)
180+
- hooks: The hooks contract address
181+
- A `positionId` may also be a `bytes32` or other unique identifier that references a specific position.
182+
183+
# Security and Gas Considerations
184+
185+
- **Offchain Reads**: Calls to `StateView` are purely read-only, so they cost no gas. This makes them ideal for frequently refreshing UI/analytics data.
186+
- **Onchain vs. Offchain**: Remember that if you need to integrate pool data into a live transaction, you must use `StateLibrary` within your smart contract.
187+
- **Edge Cases**: Always verify the returned data before using it in your application. Network or contract errors could lead to unexpected values.
188+
189+
# Conclusion
190+
191+
**StateView** is a powerful and efficient way to read Uniswap v4 pool data offchain. By separating onchain logic (using `StateLibrary`) and offchain reads (using `StateView`), Uniswap ensures the best developer experience for both contexts.
192+
193+
To recap:
194+
195+
1. **Setup**: Use libraries like `viem` to connect to the Ethereum network.
196+
2. **Read**: Call `getSlot0`, `getLiquidity`, `getPositionInfo`, and other methods for crucial state data.
197+
3. **Handle Errors**: Implement basic checks for invalid `poolId` or connection failures.

0 commit comments

Comments
 (0)