Skip to content
0xSlots

Getting Started

Installation

Create a client

SlotsClient reads and writes slots directly over RPC. Addresses come from @0xslots/contracts, which only lists chains the protocol is deployed on — see Deployments.

import { SlotsClient } from "@0xslots/sdk";
import { slotFactoryAddress } from "@0xslots/contracts";
import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { anvil } from "viem/chains";
 
const publicClient = createPublicClient({ chain: anvil, transport: http() });
const walletClient = createWalletClient({
  account: privateKeyToAccount("0x..."),
  chain: anvil,
  transport: http(),
});
 
const client = new SlotsClient({
  factoryAddress: slotFactoryAddress[anvil.id], // only createSlot and collectAll need it
  publicClient,
  walletClient, // omit for read-only use
});

Read a slot

const state = await client.slotState("0x...");
// occupant, price, deposit, taxOwed, isInsolvent, secondsUntilLiquidation,
// taxRateBps, recipient, module, settings, scopes, pending terms, …
 
const cost = await client.quoteBuy("0x...", buyer, depositAmount); // what buy() charges

slotState is one SlotLens.getSlotInfo call, so every figure is from the same block.

Create a slot

import { zeroAddress } from "viem";
 
await client.createSlot({
  currency: zeroAddress, // native ETH; or an ERC-20 address
  manager: zeroAddress,  // nothing is mutable, so there is no manager
  mutableTax: false,
  mutableRecipient: false,
  mutableModule: false,
  taxTerms: {
    recipient: "0x...",
    rateBps: 100,            // 1% of the price per 30 days
    minRunwaySeconds: 86_400, // a buyer must fund one day of tax
  },
  // moduleTerms omitted: no module
});

To install a module, pass moduleTerms: { module, settings } — see Modules.

Write actions

import { parseEther } from "viem";
 
// `account` is who gets seated — it need not be the signer.
// ERC-20 approval is handled, and the quoted total is sent as `maxPayment`.
await client.buy({
  slot: "0x...",
  account: "0x...",
  selfAssessedPrice: parseEther("10"),
  depositAmount: parseEther("1"),
});
 
await client.selfAssess(slot, parseEther("20"));
await client.topUp(slot, parseEther("0.5"));
await client.withdraw(slot, parseEther("0.1"));
await client.release(slot);
await client.collect(slot);   // permissionless
await client.liquidate(slot); // permissionless — no bounty, the slot itself is the reward

React

import { useQuery } from "@tanstack/react-query";
import { useAccount } from "wagmi";
import { useSlotAction, useSlotsClient } from "@0xslots/sdk/react";
 
function SlotView({ address }: { address: `0x${string}` }) {
  const { address: me } = useAccount();
  const client = useSlotsClient();
  const { data: slot, isLoading } = useQuery({
    queryKey: ["slot", address],
    queryFn: () => client.slotState(address),
  });
  const { buy, busy } = useSlotAction({
    onSuccess: (label, hash) => console.log(`${label}: ${hash}`),
  });
 
  if (isLoading || !slot || !me) return null;
 
  return (
    <button
      disabled={busy}
      onClick={() =>
        buy({
          slot: address,
          account: me,
          selfAssessedPrice: 5_000_000n,
          depositAmount: 1_000_000n,
        })
      }
    >
      Buy (current price {slot.price.toString()})
    </button>
  );
}