> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kimia.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a Keeper

> Crank funding, liquidations, rewards, and rebalancing on Kimia, permissionlessly.

Several Kimia operations are permissionless cranks. Running a keeper bot
requires no whitelist, and you can earn by being first to liquidate or by
layering your own fee structure on funding updates.

## Cranks on offer

| Program      | Instruction           | Pays what                                             |
| ------------ | --------------------- | ----------------------------------------------------- |
| kimia-perp   | `update_funding_rate` | Nothing direct; rate-setter sees the fresh cumulative |
| kimia-perp   | `settle_funding`      | Nothing direct                                        |
| kimia-perp   | `liquidate`           | 2.5% of closed notional                               |
| delta-vault  | `rebalance`           | Nothing direct (you keep the protocol healthy)        |
| delta-vault  | `claim_funding`       | Nothing direct                                        |
| split-engine | `update_rewards`      | Nothing direct                                        |

## Minimal Node bot

```ts theme={null}
import { createSolanaRpc, createSolanaRpcSubscriptions } from '@solana/kit';

const rpc = createSolanaRpc(process.env.RPC_URL!);

async function tickFunding() {
  const market = await fetchMarket(rpc, marketPda);
  const now = Math.floor(Date.now() / 1000);
  if (now - Number(market.lastFundingUpdate) >= Number(market.fundingPeriod)) {
    const postIxs = await fetchAndBuildOraclePost(SOL_USD_FEED_ID);
    const ix = getUpdateFundingRateInstruction({
      keeper: wallet,
      market: marketPda,
      oracle: priceUpdate,
      orderbook: orderbookPda,
    });
    await sendTransaction([...postIxs, ix]);
  }
}

setInterval(tickFunding, 60_000);
```

## Finding liquidatable users

Subscribe to program accounts for `kimia-perp::UserAccount`, read
`base_amount`, `collateral`, `market_index`, and compute health off-chain with
the `perps-math` model. Then call `liquidate`:

```ts theme={null}
const ix = getLiquidateInstruction({
  liquidator: wallet,
  liquidatorTokenAccount: wsolAta,     // receives fee
  userAccount: victim,
  market: marketPda,
  oracle: priceUpdate,
  collateralVault: market.collateralVault,
  insuranceVault: market.insuranceVault,
  orderbook: orderbookPda,
});
```

<Warning>
  `liquidate` touches the orderbook (to cancel the victim's resting orders)
  and reads the oracle. Always prepend a fresh oracle post, a stale price will
  revert with `StaleOracle`.
</Warning>

## Rebalance the vault

```ts theme={null}
import { getRebalanceInstruction } from '@/app/generated/delta-vault/instructions';

const vaultState = await fetchVault(rpc, vault);
if (abs(spotLegValue - perpLegValue) * 10_000 / totalValue >
    vaultState.rebalanceThresholdBps) {
  await sendTransaction([
    ...oraclePostIxs,
    getRebalanceInstruction({ /* ... */ }),
  ]);
}
```

## Operational tips

* **RPC quality matters.** Liquidation races reward low-latency RPCs and
  tightly-controlled transaction priority fees.
* **Sync reward\_per\_share before claiming.** For vault integrators, calling
  `update_rewards` before `claim_yield` maximizes the user's payout.
* **Don't assume idempotency.** `update_funding_rate` enforces `elapsed ≥
  funding_period`; wasted calls just fail silently with `FundingTooEarly`.
