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%).

AttackTargetSpikesTimeCost SOLCost USDJIKA price movedBandLender
Push, read, sell back in one transaction1%11 slot0.60$720.00%2.77%reads, price unmoved
5%11 slot2.96$3580.00%8.98%refuses
20%11 slot11.49$1,3910.00%22.36%refuses
Push, hold one slot, arbitraged back1%11 slot0.31$370.00%2.77%reads, price unmoved
5%11 slot2.01$2430.00%8.98%refuses
20%11 slot17.72$2,1440.00%22.36%refuses
One spike per 10 s, nobody else updating1%880 s14.32$1,7331.15%2.38%reads
5%11110 s69.16$8,3705.24%7.33%refuses
20%26260 s241.51$29,22820.27%22.48%refuses
One spike per 10 s, a keeper updating1%, 5%, 20%60, gave up624 s107 to 5380.00%1.2 to 1.9%reads, price unmoved
Hold the market, a keeper updating1%held80 s360.51 (estimate)$43,629 (estimate)1.15%2.31%reads
5%held110 s2,595 (estimate)$314,099 (estimate)5.24%5.35%refuses
20%held260 s24,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

ThreatDefence
Push a pool, read, sell backSteady price follows only the least extreme of three consecutive 10-second buckets; the band widens at once
Repeated spikes to walk the priceClamp 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 weightWeight = min(depth now, confirmed depth); confirmed depth uses the median of three readings
A thin pool far from the othersDepth-weighted median; its distance is added to the band
A fake pool programOnly the seven hard-coded DEX program ids are accepted
A pool for another token or quoteBoth mints checked at add and at every read; quote must be wSOL or USDC
Two feeds for one tokenFeed PDA = ["feed", mint], created with init
An updater hiding venuesEvery stored venue must be passed, in order, with exactly the accounts the pool names
Omitting the USDC bridgeBridgeRequired on update; add_venue refuses a USDC pool unless the USDC feed exists
A stale bridgeUSDC venues drop out unless the USDC feed is live and updated within 150 slots
Spamming venue slotsMax 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 poolsRead as no sample
OverflowTicks 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 update per 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.
NextEconomics