Quickstart
Place a sealed order from code, check that the relay included it, then run the whole system on your own machine.
buildOrder()localKasumiOrder for the open epoch
signAndSeal()localEIP-712 signature, then timelock ciphertext
submit()to relayenvelope out, signed receipt back
verifyInclusion()after cutoffreceipt checked against the root
Place a sealed order#
The SDK is @kasumi/sdk in packages/sdk. It is consumed from the workspace as TypeScript source.
import { KasumiClient, SIDE_BUY, toProtocolPrice } from "@kasumi/sdk";
import { privateKeyToAccount } from "viem/accounts";
const client = new KasumiClient({ relayUrl: "https://kasumisystems.com/api/v1" });
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const { markets, mode } = await client.config();
const aapl = markets.find((m) => m.symbol === "AAPL")!;
// Bound to the epoch that is open now, valid through its settlement deadline.
const order = await client.buildOrder({
owner: account.address,
market: aapl,
side: SIDE_BUY,
baseAmount: 10n ** 18n, // 1 token, raw units
limitPrice: toProtocolPrice("333.00", aapl.baseDecimals, aapl.quoteDecimals),
});
// Signed, then encrypted, in this process. Nothing has been sent yet.
const sealed = await client.signAndSeal(order, (typedData) => account.signTypedData(typedData));
// Only the envelope leaves the machine. The receipt signature is checked before this returns.
const receipt = await client.submit(sealed.envelope);
The order is real: it can fill on Robinhood Chain if the owner holds the token it spends and has approved the settlement contract for it.
Keep sealed.cancelSecret. Revealing it to the relay before the cutoff cancels the order:
await client.cancel(sealed);
Verify inclusion#
After the epoch closes the batch is fixed. Check that the relay kept its word:
const check = await client.verifyInclusion(receipt /*, rootFromChain */);
// { ok, receiptSignatureValid, receivedBeforeCutoff, includedInRoot, censored }
Pass the root read from KasumiEpochManager.rootOf(epochId) as the second argument for a check that does
not trust the relay. Without it the relay's own reported root is used, which only detects an inconsistent
relay. censored: true means the relay signed a valid receipt and then left the order out of the root. The
receipt is the evidence.
Read the result#
Once the epoch is decrypted and settled, every order in it is public:
const res = await fetch(`https://kasumisystems.com/api/v1/epochs/${receipt.epochId}`);
const epoch = await res.json();
const mine = epoch.result?.orders.find((o) => o.commitment === receipt.orderCommitment);
// mine.outcome: "FILLED" | "PARTIAL" | "UNFILLED" | "REJECTED"
Run it locally#
Requirements: Node 22, pnpm 10, Foundry, Rust.
git clone --recurse-submodules <repo>
pnpm install
pnpm dev # terminal and relay on http://localhost:3000
Local development needs no environment variables and sends no transactions. Reference prices are read from
the Chainlink feeds on Robinhood Chain through the public RPC. docs/DEVELOPMENT.md in the repository has
the details.
Run the tests#
| Command | What it runs |
|---|---|
pnpm test:contracts |
Foundry unit and fuzz tests, plus the cross-check that replays SDK vectors through real settlement |
pnpm test:matcher |
Rust matcher against fixtures/matching.json |
pnpm test:sdk |
SDK unit tests, including a live drand round trip (KASUMI_OFFLINE=1 skips it) |
pnpm --filter @kasumi/operator e2e |
A full epoch against contracts on a local anvil chain, with real drand |
pnpm --filter @kasumi/web live-e2e |
The relay engine against contracts on a local anvil chain |
pnpm --filter @kasumi/operator rehearse |
The same on a fork of Robinhood Chain mainnet with the real tokens and feeds |
pnpm fixtures |
Regenerates the shared fixtures from the TypeScript reference |
The three implementations are tied together by fixtures. fixtures/matching.json must produce identical
result hashes in Rust and TypeScript. fixtures/crosscheck.json is produced by the SDK and replayed by
contracts/test/CrossCheck.t.sol, so the contracts and the SDK agree on the EIP-712 digest, the commitment,
the Merkle leaf and proof format, rounding and the result hashes.