The rebalance algorithm
The engine in site/assets/core/maker.js is the algorithm the keeper runs. The keeper adds only network code around it (keeper/logic.mjs).
Inputs
- the state of both curves: pump.fun
(vSol, vTok), Pons(q, t), - the Pons creator fee,
- the rate: dollars per SOL and per ETH,
- the pool for this coin:
a.cashin SOL anda.tokof pump.fun tokens,b.cashin ETH andb.tokof Pons tokens, - the band and the target (default 0.5 %).
Step 1: measure
pumpUsd = (vSol / vTok) * SOL_USD
ponsUsd = (q / t) * ETH_USD
spread = pumpUsd / ponsUsd - 1
If |spread| <= band, stop.
Step 2: choose the side
rich = spread > 0 ? pump.fun : Pons
cheap = the other one
Step 3: size the trade
The size is solved by bisection so that the spread lands back at the target.
- With inventory of the rich chain: the smallest
n <= inventory(rich)such that sellingnthere brings the spread to the target. - Without inventory: the smallest
c <= cash(cheap)such that buying withcon the cheap chain brings the spread to the target.
Sixty iterations. The keeper turns the result into a transaction with a minimum output of the simulated output minus 1.5 %.
Step 4: chain up to three steps
One trade may not be enough, for example when the pool runs out of tokens on the rich chain. It then continues with a buy on the cheap chain, up to three steps in all. If the pool has nothing to use, it holds and reports vault empty.
Properties checked by tests
- Inside the band, nothing happens.
- Outside the band, a sell on the rich chain is preferred when inventory exists.
- It only sells tokens of the chain that is rich.
- Cash does not cross chains: a pool with only ETH cannot buy on pump.fun.
- A move in the SOL/ETH rate alone opens a gap and the maker narrows it.
- A $5,000 pool keeps the coin in band at least 85 % of the time in a moderate market, no maker at most 30 %.
- Cash and inventory never go negative.
Trade execution
| Chain | Buy | Sell |
|---|---|---|
| Solana | pump.fun buy from the keeper wallet, with a create-ATA and an init-volume-accumulator step when needed | pump.fun sell |
| Robinhood Chain | GlintVault.buy(ethIn, minTokensOut) | GlintVault.sell(tokensIn, minEthOut) |
Both Solana transactions were simulated against mainnet state and the vault calls run against the live Pons in the fork tests, see test results.