Skip to main content

The Logistic Map as a Market Maker

If you build on-chain tokenomics, you have two options for supply. Either it stays fixed forever, or a human decides when it changes. A multisig votes. A team unlocks. A keeper bot follows a schedule. In every case, a person is in the loop.

There is a third option: wire supply decisions to a deterministic equation that runs on-chain and takes no external inputs. No price feed. No governance. No keeper with discretion. The equation advances, checks its own state, and acts, mint, burn, or nothing, on a fixed schedule that no one can predict without recomputing every step.

This article walks through one implementation of that idea. It runs on chaotic.markets, a Solana launchpad where every token's supply is governed by the logistic map. We will cover the equation, how it maps to supply actions, how it is implemented on-chain, what effects it has on the market, and what properties a market maker acquires when it operates without market data.

The logistic map is a recurrence.

x_{n+1} = r * x_n * (1 - x_n)
xn+1 = r · xn · (1 − xn)r = 3.99
Step 0 / 18x0 = 0.500Idle

What happens when you use this recurrence to control token supply on-chain?

It uses the value of x_n after each step to decide whether to mint, burn, or do nothing.

How the map makes supply decisions

At chaotic.markets, each token is initialized with x = 0.5 and a creator-chosen r between 3.57 and 4.0. The equation advances once per hour via a permissionless tick() instruction. After each advance, the program checks where x landed and takes one of three actions:

x rangeActionSupply
x > 0.8Mint 1% of treasury tokens, swap for SOL on Raydium CPMMExpands
x < 0.2Swap treasury SOL for tokens on Raydium CPMM, burn tokensContracts
0.2 ≤ x ≤ 0.8NothingUnchanged

The amount minted or burned is always 1% of the treasury balance. A $10 treasury moves $0.10. A $10,000 treasury moves $100. The mechanism scales with the token.

The map has no access to market data. It does not know the token's price, its order book depth, or its trading volume. It receives one input: its own previous state. The decision to mint, burn, or idle is a function of x_n and r and nothing else.

The r parameter determines how often and how unpredictably x crosses the thresholds. A token at r = 3.78 might spend weeks in the idle band. A token at r = 3.97 might hit mint and burn zones several times a day. The frontend labels tokens with one of five regime names (Ordered, Cyclical, Volatile, Turbulent, Chaotic) based on r, but the mechanics are identical at every r. The only variable is the trajectory.

On-chain implementation

Solana programs use integer arithmetic. The logistic map is computed in fixed-point with a scale factor of 1,000,000,000. x = 500,000,000 means 0.5. r = 3,990,000,000 means 3.99.

pub fn advance_x(x: u64, r: u64) -> u64 {
let x_u128 = x as u128;
let r_u128 = r as u128;
let scale_u128 = SCALE as u128;
let one_minus_x = scale_u128 - x_u128;
let product = r_u128 * x_u128 * one_minus_x;
(product / (scale_u128 * scale_u128)) as u64
}

Token creation uses the create_and_graduate instruction. The creator provides a name, symbol, r value, and initial SOL. The program mints initial_sol * 1000 tokens at 6 decimals. It sends 10% to a treasury PDA and 90% to the creator, seeds the treasury with 10% of the initial SOL, then calls Raydium CPMM to create a token/SOL pool. The token trades immediately. No bonding curve.

The tick() instruction runs once per hour. It is permissionless. The four steps:

  1. x_next = advance_x(current_x, r_value). Overwrite stored current_x.
  2. Check zone.
  3. Mint path: mint 1% of treasury tokens, swap for SOL, verify treasury SOL increased. Burn path: swap SOL for tokens, burn tokens, verify treasury tokens decreased. Idle path: skip.
  4. Set last_tick_ts to current clock. 1-hour cooldown enforced.

Both swap paths cap slippage at 5%. The program derives canonical Raydium vault PDAs and rejects any instruction with mismatched vault addresses. The idle path fires in roughly 60% of ticks because the middle band covers 60% of the interval.

Effects on the market

Each tick either adds tokens to the market or removes them. Over weeks, the cumulative effect reshapes the supply curve.

The treasury is self-funding. At r = 4.0, the logistic map has a known invariant density: it visits every subinterval of [0, 1] in proportion to its width. The mint zone (x > 0.8) is 20% of the interval. The burn zone (x < 0.2) is also 20%. Over a long sequence, roughly 20% of ticks mint, 20% burn, and 60% idle. If mint cycles generate more SOL than burn cycles spend, the treasury grows. If not, it drains. The protocol's viability depends on this mechanical balance, not on governance.

The timing of each supply action is expensive to predict. To know which tick will cross a threshold, you must simulate the map forward. Each step requires computing r * x * (1 - x). You cannot skip steps because sensitivity to initial conditions means small rounding differences compound. Simulating faster than the chain is theoretically possible but practically equivalent to running a copy of the keeper bot, at which point the information has already been absorbed.

What emerges

Because supply decisions come from a program that takes no external inputs, the system has a few fixed properties.

It is verifiable. Given x = 0.5 and a known r, anyone can replay the logistic map and confirm every tick produced the result required by the math. The full supply history is auditable from first principles.

It has no override mechanism. The program does not expose an instruction to skip a threshold check or change the supply policy. The map advances, checks the zone, and acts. There is nothing else to call.

It distributes information equally. When a mint tick fires, the tokens hit the pool and the price moves. Anyone watching the chain sees this at the same time. No participant knows the supply schedule in advance because no one, including the program, knows it until the tick executes.


chaotic.markets runs on Solana devnet. Pick an r, launch a token, call tick() after an hour, and verify the equation produced the result you expected. Every tick is a real on-chain transaction.

For the protocol's security model and test coverage, see the self-audit of the launchpad protocol. For the bonding curve that preceded this architecture, see the guide to building a bonding curve on Solana.