How it works
A JIKA price is made in eight steps, all inside the program, every time someone calls update. This page walks through them in order, with the constants the program uses.
1. Venues
Each feed (one per token mint) holds up to 8 pools, called venues. The supported DEX programs are:
| Kind | DEX | Program |
|---|---|---|
| 0 | Orca Whirlpool | whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc |
| 1 | Raydium CLMM | CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK |
| 2 | Raydium CPMM | CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C |
| 3 | Raydium AMM v4 | 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 |
| 4 | Meteora DLMM | LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo |
| 5 | pump.fun bonding curve | 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P |
| 6 | PumpSwap | pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA |
The other side of a pool must be wSOL, or USDC. A USDC pool is converted to SOL through the USDC feed's own steady price. Every byte offset was checked against live mainnet accounts, and a test compares each kind with an independent decoder: price within 1 tick, depth within 0.1%.
2. Ticks
A price is a tick: 1.0001^tick lamports per raw unit of the token. One tick is one basis point, so a constant-product pool, a concentrated pool and a bin-based pool all land on one integer scale. Ticks are bounded to plus or minus 400,000.
To turn a tick into SOL per whole token: 1.0001^tick x 10^(decimals - 9).
3. Depth
For each venue, depth is the SOL that trades within 2% of its price, both sides added.
| Pool type | How depth is read |
|---|---|
| Constant product (CPMM, AMM v4, PumpSwap) | quote reserve x (sqrt 1.02 - sqrt 0.98) |
| Concentrated (Whirlpool, Raydium CLMM) | the same on the in-range virtual reserve, capped by what the vaults hold |
| Meteora DLMM | the bins within 2% in the active bin array |
| pump.fun curve | virtual reserve on the way up, real SOL on the way down |
4. Weight: only depth that stayed
A venue's weight is the lower of its depth now and its confirmed depth. Confirmed depth takes the median of the previous reading, this reading and the running value, then averages it over about 10 minutes (time constant 1,500 slots, each reading credited for at most 75 slots).
Liquidity that appears for one transaction buys no weight. A new pool starts at zero weight and earns it by keeping its depth.
5. Spot: the depth-weighted median
Line the venues up by price and walk up until half the weight has been passed. That tick is the spot. Moving it up needs more than half the weight; a thin pool far from the others moves it by nothing.
On TERMINAL at slot 453,199,769: PumpSwap at tick -44,649 with 23.3% of the weight, two Meteora DLMM pools at -44,351 (24.2%) and -44,282 (52.5%). The median is the deep DLMM pool's tick.
6. The band
conf_ticks is the half-width of the band, the sum of four things in ticks of the same price:
- How far the venues sit from the median, weighted by depth.
- The gap between the spot and the steady price.
- The move a 1 SOL trade would cause: 400.04 x 1 SOL / depth, in ticks.
- The USDC feed's own band, when a USDC pool carries weight.
The band as a percentage is (1.0001^conf_ticks - 1) x 100. Pools that disagree, a spot that jumps away from the steady price, or a token too thin to take 1 SOL all widen it.
7. The steady price
The steady price is the one programs read. Every update records the spot in its 10-second bucket (25 slots), keeping the lowest and highest seen. The steady price:
- moves at most once per slot,
- only when each of the last three buckets has a sample,
- only toward the least extreme of them: up to their lowest sample, down to their highest,
- with the pull clamped to 1,000 ticks and weighted hold / (300 + hold), hold capped at 75 slots.
So it moves at most 1,000 x 25 / 325 = 76.9 ticks (0.77%) per 10-second bucket, and one honest update in any bucket of the window pins it.
8. Lazy and gated
Anyone may call update; nothing runs on its own. The first update in a slot takes the slot's sample; later ones in the same slot do nothing. last_update_slot is stored and returned. A feed is live after 600 credited slots (about 4 minutes of updates). read(max_age_slots, max_conf_ticks) fails with NotLive, Stale or TooUncertain rather than hand over a number the caller said it cannot use.
A worked example: TERMINAL
| Value | |
|---|---|
| Venues | PumpSwap 10.47 SOL, Meteora DLMM 23.58 SOL, Meteora DLMM 10.88 SOL of depth |
| Total depth | 44.93 SOL ($5,437 at $121.02 per SOL) |
| Steady price | 0.00001194 SOL ($0.001445) per token |
| Band | plus or minus 1.2% |
The pools disagreed by 3.7% at the snapshot; that disagreement is in the band, and the median stayed on the deep pool.
NextArchitecture