Hock

How Hock works

Hock offers fixed-term, non-recourse loans against Elysium tokens. Every term of a loan is set when it is opened. This page explains how each one is determined.

The loan

You lock tokens in Hock and receive HYPE straight away. Three things are fixed when you sign and never change: how much you borrowed, the fee, and the date. There's no interest that grows, no health factor, and no price feed involved.

Terms run 1, 3, 7, 14 days. The fee is deducted from the loan, so the HYPE you receive is the loan minus the fee, and what you repay is the loan itself.

At the date

Before the date you can repay at any time and your tokens come back to you in the same transaction. After the date passes unpaid, the loan ends: the vault that funded it keeps your tokens and you keep the HYPE. You owe nothing further.

Nothing happens between signing and the date. If the price halves, nobody can sell your tokens. If it triples, the gain is still yours as long as you repay in time.

Sale value

Hock never asks what a token is worth on a chart. It asks the token's own pool what your exact amount would sell for right now, after slippage, using the same quoter any swap uses. That number is the sale value shown on your loan.

This is what makes lending without an oracle safe enough to try. Pumping a thin pool doesn't help a borrower much, because the sale value of a large position in a thin pool is small, and the loan is a fraction of that.

Loan-to-value and caps

Loan-to-value is a share of sale value, set per token by each vault's curator and lower for thinner pools. Hock caps it at 50% for any token. The live figures are on the Markets page, read from the contracts.

Each vault also sets how much it will lend against a token in total. On top of that, the core contract refuses a loan if the vault's outstanding loans against a token would exceed what all of that token's collateral could be sold for at once, times its loan-to-value. That keeps defaulted collateral small enough to actually sell.

Fees

TermFee, share of the loan
1 day1%
3 days2.5%
7 days5%
14 days9%

Fees go to the vault that funded the loan, less a protocol share of 10% that goes to the Hock treasury. Repaying early doesn't refund any of the fee.

Vaults and curators

Lenders deposit HYPE into vaults. Each vault is run by a curator who sets which tokens it takes, its loan-to-value limits and terms, within Hock's limits. Depositors earn the fees; when a loan defaults, depositors share its collateral.

A conservative vault takes deep pools at short terms and earns less. An aggressive one takes thinner tokens at low loan-to-value and charges for the risk. Pick the book you'd want to be.

$HOCK

$HOCK is live on volta.family with a 1% fee on every trade: 35% of it buys back and burns $HOCK, 35% is the creator share that Hock deposits into its vault and lends out as HYPE, and 30% goes to Volta. Hock's 10% share of every loan fee goes to $HOCK stakers: each core's treasury is the HockStaking contract at 0xbe31F5305167EE3cF2801d384160161AaEBc9aD5, which streams what arrives to stakers over seven days, in HYPE. It has no owner, and staking has no lockup. More on $HOCK.

Price checks

A loan is priced from a live sell quote, scaled back if the pool's price sits above a recent snapshot of it. That stops anyone pumping a pool in the same transaction to borrow more. A snapshot counts once it is a minute old and stops counting after 30 minutes.

Snapshots are taken by every loan and by anyone who asks. If a token has been quiet for half an hour, the borrow page offers a price check: one small transaction, then a minute's wait, and the loan can be opened.

Risks

Lenders can lose money. Borrowers may let a loan mature unpaid when the collateral is worth less than the loan, and lenders then hold that collateral, which may be hard to sell. Fees are set to cover this but are not guaranteed. Hock is unaudited software on a new chain, and vault deposits are capped while it is.

Elysium itself is new. Withdrawals from it to HyperEVM take about seven days, and its sequencer can delay transactions by up to a minute, so don't leave a repayment to the last minute.

Contracts

All on Elysium, chain id 99901. Elysium can't verify contract source yet, so the ABIs are published here as plain JSON that viem, ethers or cast can read as they are.

HockStaking

Stake $HOCK, earn the protocol's share of every loan fee in HYPE

0xbe31F5305167EE3cF2801d384160161AaEBc9aD5

For tokens that trade on Uniswap's v4 PoolManager (Volta, Ascend, Montra and most launchpads):

HockCore

Loans, collateral, pricing and the market list

0xbFE23356e705D2c2eD512972E40fF0DF5eD2E1C8
ABI

Hock Volta Vault

ERC-4626 vault of wrapped HYPE that funds loans

0x141E0d88eD0C52700eeF5eb8C64265f4aa25cd94
ABI

HockVaultLauncher

Opens a funded, configured project vault in one transaction

0x8a1Fa5B86bd7ad9a5F5aB6DC1e5B4f4DC16CA9e6

HockVaultFactory

Deploys vaults for the core

0x56eE8b3DBe862D3A41b5079c4A9A7ff8974a0B96
ABI

For tokens that trade on ElysPump's own PoolManager:

HockCore

Loans, collateral, pricing and the market list

0xE055B1827BDf6912E8071A9F65703C4d9e63C5b5
ABI

Hock ElysPump Vault

ERC-4626 vault of wrapped HYPE that funds loans

0xA20DC61e529F1F0f750343084171230C3f7fdea9
ABI

HockVaultLauncher

Opens a funded, configured project vault in one transaction

0xB383833F2d075F1548376640fB5d5B748075E196

HockVaultFactory

Deploys vaults for the core

0xefaf7e3A677e9a29E281C300c6b99362AD3fc458
ABI

V4Quoter (ElysPump)

Uniswap's V4Quoter, bound to ElysPump's PoolManager

0x07C56161D805abB793E06E2d254DCa0D2152Ab08

For tokens that trade on Kleos's own PoolManager:

HockCore

Loans, collateral, pricing and the market list

0xff667023d6702bd0A8d4a89AbeFCc4a7d9C92D30
ABI

Hock Kleos Vault

ERC-4626 vault of wrapped HYPE that funds loans

0xFD43E7a558fB097a00349e0D66Bf4A265C1C0891
ABI

HockVaultLauncher

Opens a funded, configured project vault in one transaction

0xE8d7f04F2FaA7b83b9C551a1112Aa61081A9AB36

HockVaultFactory

Deploys vaults for the core

0xB1f227b4F5ED01bb41D574b966943A164469442a
ABI

V4Quoter (Kleos)

Uniswap's V4Quoter, bound to Kleos's PoolManager

0xEee51DAB3fC95f319f0fA4B66E29A0bA3303ed10

$HOCK

Hock's token, launched on volta.family

0x4Bb51327Eb190aBE8372215dcfb1CE0B46837A1d

HockBoost

$HOCK boost for Hock Volta Vault depositors: stake shares, earn $HOCK. No owner.

0xcD9e4106089F571547D6E6187d1237bB0f136f9c

Tokens Hock lends against, each through its own v4 pool:

Hock prices and sells through Uniswap's v4 deployment on Elysium (the PoolManager at 0xE2e105d3F7209A9DA11f83cCf3E7398a753823F1 and the V4Quoter at 0x379F556c5a748BD7Cc9baF0F7A344094Ac1814f5) and through ElysPump's own PoolManager at 0x5fb015a49f5b35073f9Ce01C2aDb287A75F89600 and Kleos's at 0xb308B5df891c300a5f5a5b8fdBC30108bA842490, each with Uniswap's quoter deployed for it. Vaults hold wrapped HYPE at 0xbA876237B0F021A6c6D852d6c26E107997cC5E81.

Project vaults

Anyone can open a vault for a listed token, and a token's team is the natural one to. Put HYPE behind the token and its holders can borrow against their bags instead of selling them. The vault belongs to the wallet that opened it: it earns every loan fee (less Hock's 10%), and its owner can change the LTV and limit, stop lending, or withdraw unlent HYPE at any time.

Open a project vault does it in one transaction through the HockVaultLauncher for the token's deployment: it creates the vault, sets the four term fees and the token's policy, deposits the HYPE sent with the call as the sender's deposit, and hands the vault to the sender. Borrowers always get the best offer across every vault that lends against their token.

For AI agents

Agents can use Hock with their own wallets. Give yours this line, in Claude Code, OpenClaw, Codex or any runtime that reads a skill file:

Read https://hock.markets/skill.md and follow it.

The skill file has the contracts, every call with examples, and the rules an agent follows: it only borrows or repays when its owner asks, confirms the terms first, and tracks each due date so a loan never expires by accident.

MCP server

Hock runs a hosted MCP server, with no key or sign-up. Add it to any MCP client as a Streamable HTTP server:

https://hock.markets/mcp

In Claude Code: claude mcp add --transport http hock https://hock.markets/mcp

It reads from the chain: list_markets (LTV, HYPE available, fees), quote_loan (exact HYPE received, HYPE to repay, due date) and get_loans (a wallet's loans and due dates). The build_* tools return unsigned transactions for a price check, approval, borrow or repayment. The server never holds keys or signs anything: your agent signs with its own wallet, and only when you ask it to.

Hock Agent 001

Hock Agent 001 is an agent with its own wallet that borrows against $HOCK every hour and repays early, using only the public MCP server above. It runs on a ten-minute schedule and sends at most one transaction per run. This is its full source; fork it for your own agent.

agent/run.ts
/**
 * Hock Agent 001: an autonomous borrower that uses Hock exactly the way any outside agent would,
 * through the public MCP server (hock.markets/mcp). Every hour it locks $HOCK, borrows HYPE on a
 * one-day loan, and repays it early, so its repayment record builds in public on-chain.
 *
 * It runs on the Worker's cron every ten minutes. Each run does at most one thing: a price check,
 * an approval, a borrow or a repayment, then exits; the next run sees the result. Its key is the
 * Cloudflare secret HOCK_AGENT_KEY and never leaves the Worker.
 */
import {
  createPublicClient,
  createWalletClient,
  defineChain,
  erc20Abi,
  formatEther,
  parseEther,
  type Address,
  type Hex,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { HOCK_TOKEN, RPC_URL, deploymentOf, rpcTransport } from "../lib/deployment";
import { handleMcp } from "../mcp/server";

export const AGENT_NAME = "Hock Agent 001";
/** $HOCK it locks for each loan. */
export const COLLATERAL = "500000";
export const TERM_DAYS = 1;
/** More than the whole $HOCK supply, so one approval covers every loan. */
const APPROVE_ONCE = "1000000000000";
/** Repay a loan once it has been open this long. */
// runs land a few seconds early on the ten-minute marks; 35 min means the 40-minute run repays
const HOLD_S = 35 * 60;
/** Open the next loan once this long has passed since the last one opened. */
const EVERY_S = 55 * 60;
/** Never hold a loan closer than this to its due date. */
const REPAY_WINDOW_S = 6 * 3600;

type Tx = { chainId: number; to: Address; data: Hex; value: string };
type Plan = { action: string; why: string; tx?: Tx };
/** One MCP tool call, as the agent made it: for the public activity feed. */
export type Step = { tool: string; args: Record<string, unknown>; result: string; ms: number };

let rpcId = 0;
/** Call one of Hock's MCP tools, through the same JSON-RPC interface outside agents use. */
async function tool<T = Record<string, unknown>>(
  trace: Step[],
  name: string,
  args: Record<string, unknown>,
  summary: (r: T) => string,
) {
  const t0 = Date.now();
  const res = await handleMcp(
    new Request("https://hock.markets/mcp", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0",
        id: ++rpcId,
        method: "tools/call",
        params: { name, arguments: args },
      }),
    }),
  );
  const j = (await res.json()) as {
    result?: { isError?: boolean; structuredContent?: T; content?: { text: string }[] };
  };
  if (!j.result || j.result.isError) {
    const msg = j.result?.content?.[0]?.text ?? "no result";
    trace.push({ tool: name, args, result: `error: ${msg}`, ms: Date.now() - t0 });
    throw new Error(`${name}: ${msg}`);
  }
  const out = j.result.structuredContent as T;
  trace.push({ tool: name, args, result: summary(out), ms: Date.now() - t0 });
  return out;
}

const elysium = defineChain({
  id: 99901,
  name: "Elysium",
  nativeCurrency: { name: "HYPE", symbol: "HYPE", decimals: 18 },
  rpcUrls: { default: { http: [RPC_URL] } },
});
export const client = createPublicClient({
  chain: elysium,
  transport: rpcTransport({ retryCount: 3 }),
});

/** Decide the one thing to do now. */
export async function plan(me: Address, trace: Step[] = []): Promise<Plan> {
  const { loans } = await tool<{
    loans: {
      loan_id: string;
      state: string;
      seconds_left: number;
      repay_hype: number;
      opened: string;
    }[];
  }>(trace, "get_loans", { wallet: me }, (r) => {
    const n = r.loans.filter((l) => l.state === "active").length;
    return `${r.loans.length} loans, ${n} open`;
  });
  const now = Date.now() / 1000;
  const open = loans.find((l) => l.state === "active");
  if (open) {
    const age = now - Date.parse(open.opened) / 1000;
    if (age < HOLD_S && open.seconds_left > REPAY_WINDOW_S)
      return { action: "wait", why: `loan ${open.loan_id} open ${Math.round(age / 60)} min` };
    const r = await tool<{ transaction: Tx }>(
      trace,
      "build_repay",
      { loan_id: open.loan_id },
      () => `unsigned tx, value ${open.repay_hype} HYPE`,
    );
    return {
      action: "repay",
      why: `repaying ${open.repay_hype} HYPE on ${open.loan_id}`,
      tx: r.transaction,
    };
  }

  // no open loan: borrow again on the hour
  const last = Math.max(0, ...loans.map((l) => Date.parse(l.opened) / 1000));
  const since = now - last;
  // the price check must be 1 to 30 minutes old at borrow time, so it goes in one run early
  if (since < EVERY_S - 10 * 60)
    return { action: "wait", why: `next loan in ${Math.round((EVERY_S - since) / 60)} min` };
  const core = deploymentOf(HOCK_TOKEN).core;
  const allowed = await client.readContract({
    address: HOCK_TOKEN,
    abi: erc20Abi,
    functionName: "allowance",
    args: [me, core],
  });
  if (allowed < parseEther(COLLATERAL)) {
    // approve once for every future loan, not just this one
    const r = await tool<{ transaction: Tx }>(
      trace,
      "build_approve",
      { token: HOCK_TOKEN, amount: APPROVE_ONCE },
      () => "unsigned tx",
    );
    return { action: "approve", why: "approving $HOCK for its loans", tx: r.transaction };
  }
  const q = await tool<{
    ok: boolean;
    reason?: string;
    message?: string;
    receive_now_hype?: number;
  }>(trace, "quote_loan", { token: HOCK_TOKEN, amount: COLLATERAL, term_days: TERM_DAYS }, (r) =>
    r.ok ? `receive ${r.receive_now_hype} HYPE now` : `not now: ${r.reason}`,
  );
  // no snapshot to price against, or the price ran up past the last one: record a fresh one
  if (!q.ok && (q.reason === "needs_price_check" || q.reason === "PriceMoving")) {
    const r = await tool<{ transaction: Tx }>(
      trace,
      "build_price_check",
      { token: HOCK_TOKEN },
      () => "unsigned tx",
    );
    return {
      action: "price_check",
      why:
        q.reason === "PriceMoving"
          ? "the price ran up since the last check, so it records a new one"
          : "the quote needs a fresh price snapshot",
      tx: r.transaction,
    };
  }
  if (!q.ok) return { action: "wait", why: q.message ?? q.reason ?? "no quote" };
  if (since < EVERY_S)
    return { action: "wait", why: `next loan in ${Math.round((EVERY_S - since) / 60)} min` };

  const r = await tool<{ transaction: Tx | null; reason?: string }>(
    trace,
    "build_borrow",
    { token: HOCK_TOKEN, amount: COLLATERAL, term_days: TERM_DAYS },
    (b) => (b.transaction ? "unsigned tx" : `not now: ${b.reason}`),
  );
  if (!r.transaction) return { action: "wait", why: r.reason ?? "borrow not available" };
  return {
    action: "borrow",
    why: `borrowing ${q.receive_now_hype} HYPE against ${COLLATERAL} $HOCK on a ${TERM_DAYS}-day loan`,
    tx: r.transaction,
  };
}

/** One cron run: plan, then sign and send at most one transaction. */
export async function tick(key: string | undefined, dryRun = false) {
  if (!key) return { action: "off", why: "HOCK_AGENT_KEY is not set" };
  const account = privateKeyToAccount(key as Hex);
  const me = account.address;
  // a transaction from the last run still in flight: let it land first
  const [latest, pending] = await Promise.all([
    client.getTransactionCount({ address: me, blockTag: "latest" }),
    client.getTransactionCount({ address: me, blockTag: "pending" }),
  ]);
  if (pending > latest) return { action: "wait", why: "previous transaction still pending" };

  const p = await plan(me);
  const out: Record<string, unknown> = { agent: me, ...p, tx: undefined };
  if (!p.tx || dryRun) {
    console.log(`[${AGENT_NAME}] ${p.action}: ${p.why}`);
    return { ...out, tx: p.tx };
  }
  const balance = await client.getBalance({ address: me });
  if (balance < BigInt(p.tx.value) + parseEther("0.002"))
    return { ...out, action: "wait", why: `needs more HYPE (has ${formatEther(balance)})` };
  const wallet = createWalletClient({ account, chain: elysium, transport: rpcTransport() });
  const hash = await wallet.sendTransaction({
    to: p.tx.to,
    data: p.tx.data,
    value: BigInt(p.tx.value),
  });
  console.log(`[${AGENT_NAME}] ${p.action}: ${p.why} → ${hash}`);
  return { ...out, hash };
}

Network

Network
Elysium
Chain id
99901
RPC
https://rpc.elysium.kinetiq.xyz
Explorer
https://explorer.volta.family
Gas
HYPE