Security and trust
JIKA moves no funds and holds none; the only lamports it touches are a feed's rent. The risk lives in the programs that act on its price. This page says how wrong the price can be made, at what cost, and what a consumer has to check.
The measured attack table
Market: TERMINAL (9ZmkKpVR3NdUcCmG5NByMHBzvjuqGnYpCPYu4zSSBtJv), a thin long-tail token, at mainnet slot 453,199,769, with 44.93 SOL of depth within 2% across three pools. 1 SOL = $121.02, the USDC feed's own price at the same snapshot.
Every row ran the real JIKA program next to the real cloned DEX programs, trading with real swaps. The attacker pushes every venue it needs to the target price. Cost is the attacker's own SOL before and after. Band is JIKA's band right after. Lender is a read with a max age of 150 slots and a max band of 300 ticks (3%).
| Attack | Target | Spikes | Time | Cost SOL | Cost USD | JIKA price moved | Band | Lender |
|---|---|---|---|---|---|---|---|---|
| Push, read, sell back in one transaction | 1% | 1 | 1 slot | 0.60 | $72 | 0.00% | 2.77% | reads, price unmoved |
| 5% | 1 | 1 slot | 2.96 | $358 | 0.00% | 8.98% | refuses | |
| 20% | 1 | 1 slot | 11.49 | $1,391 | 0.00% | 22.36% | refuses | |
| Push, hold one slot, arbitraged back | 1% | 1 | 1 slot | 0.31 | $37 | 0.00% | 2.77% | reads, price unmoved |
| 5% | 1 | 1 slot | 2.01 | $243 | 0.00% | 8.98% | refuses | |
| 20% | 1 | 1 slot | 17.72 | $2,144 | 0.00% | 22.36% | refuses | |
| One spike per 10 s, nobody else updating | 1% | 8 | 80 s | 14.32 | $1,733 | 1.15% | 2.38% | reads |
| 5% | 11 | 110 s | 69.16 | $8,370 | 5.24% | 7.33% | refuses | |
| 20% | 26 | 260 s | 241.51 | $29,228 | 20.27% | 22.48% | refuses | |
| One spike per 10 s, a keeper updating | 1%, 5%, 20% | 60, gave up | 624 s | 107 to 538 | 0.00% | 1.2 to 1.9% | reads, price unmoved | |
| Hold the market, a keeper updating | 1% | held | 80 s | 360.51 (estimate) | $43,629 (estimate) | 1.15% | 2.31% | reads |
| 5% | held | 110 s | 2,595 (estimate) | $314,099 (estimate) | 5.24% | 5.35% | refuses | |
| 20% | held | 260 s | 24,230 (estimate) | $2,932,385 (estimate) | 20.27% | 20.92% | refuses |
The holding costs are the only estimates: one real push-then-arbitrage cycle at the held level, times the slots held. The slots held and the price moves are measured.
What each attack runs into
- A spike inside one transaction or one bundle moves the spot and nothing else. The steady price's window still holds the honest buckets, so it moves 0.00%. The band widens by the gap at once, so a lender that gates on a 3% band refuses during the spike.
- The confirmed-depth cap. A pool's weight is capped by the depth it has held across updates. A pool that adds liquidity for one update gets no extra weight. A pool pushed and left there is soon weighted by the thin depth it has at the pushed price, so a lasting push has to move every venue.
- A walk with nobody watching is the real exposure. Spikes in three or more consecutive buckets walk the steady price at up to 0.77% per 10 seconds: 20% took 26 spikes, 260 seconds and 241.51 SOL. When anyone updates honestly afterwards, the gap shows in the band and a lender refuses. These costs assume the attacker pays other LPs' fees; an attacker who owns the DLMM bins it trades through gets back the LP share (90% on these pools), so treat this row as an upper bound.
- One honest update per bucket blocks the walk. 60 spikes over 624 seconds moved the steady price 0.00%. The only way left is to hold the market where everyone sees it, which costs arbitrage every slot.
Threats and defences
| Threat | Defence |
|---|---|
| Push a pool, read, sell back | Steady price follows only the least extreme of three consecutive 10-second buckets; the band widens at once |
| Repeated spikes to walk the price | Clamp of 1,000 ticks and hold / (300 + hold): at most 0.77% per 10 s; one honest update per bucket blocks it |
| Flash liquidity to gain weight | Weight = min(depth now, confirmed depth); confirmed depth uses the median of three readings |
| A thin pool far from the others | Depth-weighted median; its distance is added to the band |
| A fake pool program | Only the seven hard-coded DEX program ids are accepted |
| A pool for another token or quote | Both mints checked at add and at every read; quote must be wSOL or USDC |
| Two feeds for one token | Feed PDA = ["feed", mint], created with init |
| An updater hiding venues | Every stored venue must be passed, in order, with exactly the accounts the pool names |
| Omitting the USDC bridge | BridgeRequired on update; add_venue refuses a USDC pool unless the USDC feed exists |
| A stale bridge | USDC venues drop out unless the USDC feed is live and updated within 150 slots |
| Spamming venue slots | Max 8; a slot is replaced only if its venue is older than 3,000 slots and holds under 1% of confirmed depth |
| Paused or closed pools | Read as no sample |
| Overflow | Ticks bounded to plus or minus 400,000; wide products done limb by limb; saturating sums |
Trust assumptions
- The seven DEX programs store what they claim and let anyone trade at their price. All seven are upgradeable by their teams; a layout change can silence a venue, but every read re-checks owner, discriminator, length, both mints and the vault accounts.
- SOL is the unit. USDC is not assumed to be worth $1 anywhere in the program; dollar prices are a ratio of two feeds, done by the reader.
- Someone updates. Safety against slow manipulation needs one honest
updateper feed per 25-slot bucket. - No admin. There is no privileged instruction and no config account. The upgrade authority is the deployer's choice; the recommended path is a multisig during a short probation, then immutable.
Known limits
- Without a keeper the steady price can be walked (see the table).
- Depth is an estimate: concentrated depth is capped by vault balances; DLMM depth counts only the active bin array.
- Lag: a real move reaches the steady price after the window fills (up to 30 s), then at most 0.77% per 10 s. A real 50% crash takes about 15 minutes to reach the steady price; the spot and the band show it at once, so a lender should use the band too.
- Raydium AMM v4 open-book orders are not counted.
- No external audit yet.