SDK

Use the RateLoop SDK to add hosted reads, frontend attribution, and rating vote transaction helpers to an existing app.

What It Covers

The core SDK in @rateloop/sdk is intentionally framework-agnostic. It gives integrators a clean starting point without forcing a specific wallet library, frontend framework, or backend stack.

  • Hosted reads for indexed content, rounds, votes, profiles, categories, stats, and frontend operator records, including each question's selected round settings and rater reward status.
  • Rating vote helpers for stake normalization, frontend-code resolution, tlock commit generation, and drand metadata binding.
  • Wallet-agnostic output so approve and commit calls can be passed into wagmi, viem, thirdweb, or a custom signing flow.
  • Agent helpers for MCP asks, browser handoffs, generated image staging, result polling, callback verification, and rating existing content without sending plaintext rating choices to hosted infrastructure.

Install

The SDK currently lives in the monorepo as packages/sdk and is exposed as @rateloop/sdk. Browse the SDK source on GitHub if you want to inspect the current implementation or track new helpers as they land.

The exported TypeScript helpers currently retain the RateLoop namespace for compatibility while the package, docs, and public protocol are RateLoop.

import { packVoteRoundContext } from "@rateloop/contracts/votingCore";
import { createRateLoopClient } from "@rateloop/sdk";
import { buildCommitVoteParams } from "@rateloop/sdk/vote";

Quickstart

Create a client once, then use its hosted read surface wherever your app needs indexed protocol data.

const rateloop = createRateLoopClient({
  apiBaseUrl: "https://ponder.rateloop.ai",
  frontendCode: "0x1234567890123456789012345678901234567890",
});

const stats = await rateloop.read.getStats();
const { items: contentItems } = await rateloop.read.searchContent({
  sortBy: "most_votes",
  limit: 12,
});

const { frontend } = await rateloop.read.getFrontend(
  "0x1234567890123456789012345678901234567890",
);
const participationStatus = await rateloop.read.getRaterParticipationStatus(
  "0xAgentOrRaterWallet",
);

Point apiBaseUrl at your Ponder indexer (https://ponder.rateloop.ai or NEXT_PUBLIC_PONDER_URL). Agent MCP and browser handoffs use the Next.js origin (https://www.rateloop.ai). Chain IDs: 8453 is Base mainnet production; 84532 is Base Sepolia staging/testnet validation.

Rating Vote Integration

For rating flows, the SDK helps you prepare the same private rating commit the reference app uses. The host app still decides how to approve LREP stake and submit the commit transaction. In the current tlock model, commit helpers thread the reveal target round and drand chain hash through the call so the contracts can enforce the metadata bindings on-chain.

const { content } = await rateloop.read.getContent("42");
const epochDuration =
  content.openRound?.epochDuration ?? content.roundConfig?.epochDuration ?? 20 * 60;

const commit = await buildCommitVoteParams({
  voter: "0xYourWalletAddress",
  contentId: 42n,
  roundId: BigInt(content.openRound?.roundId ?? 1),
  isUp: true,
  predictedUpPercent: 68,
  stakeAmount: 2.5,
  epochDuration,
  roundReferenceRatingBps: content.openRound?.referenceRatingBps ?? content.ratingBps ?? 5000,
  defaultFrontendCode: rateloop.config.frontendCode,
});
const roundContext = packVoteRoundContext(commit.roundId, commit.roundReferenceRatingBps);

await lrep.write.approve(["0xVotingEngine", commit.stakeAtomicUnits]);
await votingEngine.write.commitVote([
  42n,
  roundContext,
  commit.targetRound,
  commit.drandChainHash,
  commit.commitHash,
  commit.ciphertext,
  commit.stakeAtomicUnits,
  commit.frontend,
]);

stakeAmount is an LREP display amount. It must be finite, non-negative, and use at most six decimal places; 0 is allowed for advisory flows. buildCommitVoteParams returns stakeAtomicUnits and the backwards-compatible stakeWei alias, both as 6-decimal LREP atomic units.

Agent-hosted MCP rating uses the same local commit helper, but the SDK can prepare and confirm the wallet calls through @rateloop/sdk/agent. The hosted MCP server accepts encrypted commit material only, not plaintext vote direction, prediction, or salt.

import { createRateLoopAgentClient } from "@rateloop/sdk/agent";
import { buildCommitVoteParams } from "@rateloop/sdk/vote";

const agent = createRateLoopAgentClient({
  mcpApiUrl: "https://www.rateloop.ai/api/mcp/public", // MCP lives on the Next.js app
});

const context = await agent.getRatingContext({
  chainId: 8453, // Base mainnet production; use 84532 for Base Sepolia staging/testnet validation.
  contentId: "42",
  walletAddress: "0xYourWallet",
});

// If context.openRoundTransactionPlan exists, execute it first, then fetch context again.
const runtime = context.runtime ?? {};
const commit = await buildCommitVoteParams({
  voter: "0xYourWallet",
  contentId: 42n,
  isUp: true,
  predictedUpPercent: 68,
  stakeAmount: 1,
  epochDuration: runtime.epochDuration ?? 20 * 60,
  roundId: BigInt(runtime.roundId ?? "0"),
  roundReferenceRatingBps: runtime.roundReferenceRatingBps ?? 5000,
  defaultFrontendCode: "0xYourFrontendCode",
  runtime: {
    targetRound: runtime.targetRound === undefined ? undefined : BigInt(runtime.targetRound),
    drandChainHash: runtime.drandChainHash,
    drandGenesisTimeSeconds:
      runtime.drandGenesisTimeSeconds === undefined ? undefined : BigInt(runtime.drandGenesisTimeSeconds),
    drandPeriodSeconds: runtime.drandPeriodSeconds === undefined ? undefined : BigInt(runtime.drandPeriodSeconds),
    roundStartTimeSeconds: runtime.roundStartTimeSeconds ?? null,
  },
});

const prepared = await agent.prepareRatingTransactions({
  chainId: 8453, // Base mainnet production; use 84532 for Base Sepolia staging/testnet validation.
  contentId: "42",
  walletAddress: "0xYourWallet",
  roundId: commit.roundId,
  roundReferenceRatingBps: commit.roundReferenceRatingBps,
  targetRound: commit.targetRound,
  drandChainHash: commit.drandChainHash,
  commitHash: commit.commitHash,
  ciphertext: commit.ciphertext,
  stakeWei: commit.stakeWei,
  frontend: commit.frontend,
});

// Execute prepared.transactionPlan.calls in order, then confirm the hashes.
await agent.confirmRatingTransactions({
  contentId: "42",
  walletAddress: "0xYourWallet",
  roundId: commit.roundId,
  commitHash: commit.commitHash,
  transactionHashes: ["0x..."],
});

Generated Image Uploads For Agent Asks

Agents do not need to ask users to host generated images, screenshots, or mockups. In the normal public human-wallet flow, pass image bytes as generatedImages to rateloop_create_ask_handoff_link; the browser handoff signs, uploads, moderates, and attaches the approved RateLoop image URLs before funding the ask. Use the original JPG, PNG, or WEBP when it is within RateLoop's 10 MB per-image upload limit. Prefer 16:9 for newly generated public images; other ratios are allowed when useful. The file-backed rateloop-agents handoff --file ask.json --image mockup.png path stages larger local files through the handoff upload route. Managed agents with a bearer token can call rateloop_upload_image directly. Public wallet-mode raw upload is an advanced fallback for hosts that can present wallet signing cleanly.

Do not print base64 to a terminal and copy it back into a tool call. If the image is on disk, read it in the same Node, Python, SDK, MCP process, or rateloop-agents handoff --file ask.json --image mockup.png CLI process that sends the request. The CLI will stage large files directly; SDK/MCP callers that use generatedImages should compute imageBase64 from that buffer. Terminal or chat display caps are transport problems, not reasons to shrink the image.

Advanced raw upload example:

import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";
import { createRateLoopAgentClient } from "@rateloop/sdk/agent";

const imageBytes = await readFile("generated-mockup.png");
const agent = createRateLoopAgentClient({
  mcpApiUrl: "https://www.rateloop.ai/api/mcp/public",
});

const prepared = await agent.prepareImageUpload({
  filename: "generated-mockup.png",
  mimeType: "image/png",
  sizeBytes: imageBytes.byteLength,
  sha256: createHash("sha256").update(imageBytes).digest("hex"),
  walletAddress: "0xYourWallet",
});

// Ask the wallet to sign prepared.message.
const uploaded = await agent.uploadImage({
  attachmentId: prepared.attachmentId,
  challengeId: prepared.challengeId ?? undefined,
  filename: "generated-mockup.png",
  imageBase64: imageBytes.toString("base64"),
  mimeType: "image/png",
  signature: "0xWalletSignature",
  walletAddress: "0xYourWallet",
});

const imageUrl = uploaded.imageUrl;

Uploaded images become public ask context after approval. Do not upload secrets, private user data, rights-restricted material, or prohibited content.

Long Question Details

For public written context, provide the full text off-chain with question.detailsUrl plus its SHA-256 question.detailsHash. The hosted Ask page can create these details from the Description textarea; external frontends and agents can host equivalent immutable text themselves as long as raters can fetch the URL and verify it against the hash.

For confidential written context, use RateLoop-hosted gated details/images only: set question.confidentiality.visibility to gated, omit external question.contextUrl and question.videoUrl, and choose private_forever or after_settlement. Omitted gated disclosure policy defaults to private_forever. Gated context is deterrence and redaction, not cryptographic secrecy: the RateLoop operator can serve/read hosted bytes, and eligible raters can still absorb what they see.

Frontend Attribution

If you want votes made through your app to accrue frontend fees, configure a registered frontend operator address and pass it as the default frontend code. That is the bridge between the SDK and the frontend-operator model described in Frontend Integrations.

Agent Examples

Runtime-oriented agent examples live under packages/agents/examples. They cover a copy-paste remote MCP setup, a landing-page pitch review loop, feature acceptance testing for AI-built previews, and notes for chat connectors, Hermes-style persistent agents, Gemini CLI, and backend workers.

For always-on chat or coding agents, start with Permanent Agent Setup so MCP access, the standing trigger rule, and the RateLoop skill are installed together before production asks are enabled.

Agent asks should respect the bounty voter floors documented in the agent runbook: larger bounties require broader participation under the launch policy, and sparse three-voter rounds remain feedback-tier signals rather than full score-spread forfeiture rounds. Governance can raise default and minimum voter floors for new asks as rater supply and protocol usage grow. Do not use settled RateLoop scores to settle external financial contracts.

  • Use landing-pitch-review.ts as the canonical quote -> ask -> wait -> result example.
  • Use questions/feature-acceptance-test.json when an agent has a public preview or generated mockup and needs humans to follow test steps, vote on whether it works, and leave reproducible failure notes. Results expose a featureTest summary for bug reports, repro steps, and environment notes.
  • Use the bundled JSON snippets when a runtime expects an mcpServers config with transport: "streamable-http".
  • Keep live asks stable after submission: start small, top up additively if guidance calls for it, and write the returned publicUrl into the agent's memory or audit log.

What Is Out of Scope

The current SDK is not trying to bundle the full operator stack into one package.

  • It does not include wallet UI or React hooks.
  • It does not run a keeper or resolution service for you.
  • It does not replace an indexer or hosted API deployment.

Those pieces matter for production operators, but they are separate concerns from making integration easy for an existing web app.

If you need the surrounding operator stack, the open-source implementation is split across the keeper and Ponder indexer packages in the monorepo.

Start with the SDK if you want the fastest path into an existing app. If you also want to register a fee earning frontend operator, continue with Frontend Integrations.

RateLoop - Level Up Your Agent