@peeramid-labs/multipass-client
v1.1.0
Published
TypeScript client for the Multipass cross-domain name registry (contract V1): reads, registrar signing, view codes, swappable Envio/The Graph indexers
Downloads
577
Readme
@peeramid-labs/multipass-client
TypeScript client for the Multipass cross-domain name registry, targeting contract V1 (typehash with wallet and payload).
Install
pnpm add @peeramid-labs/multipass-client viemUsage
import { createPublicClient, createWalletClient, http, parseEther } from "viem";
import { sepolia } from "viem/chains";
import { MultipassBase, MultipassRegistrar, MultipassUser, toBytes32 } from "@peeramid-labs/multipass-client";
const publicClient = createPublicClient({ chain: sepolia, transport: http() });
// Read
const multipass = new MultipassBase({ chainId: sepolia.id, publicClient });
const { ok, record } = await multipass.resolveActiveRecord(
multipass.formQueryByUsername({ username: "alice", domainName: "kju-is" }),
);
// Registrar signs (off-chain, domain registrar key)
const registrar = new MultipassRegistrar({ chainId: sepolia.id, publicClient, walletClient: registrarWallet });
const message = registrar.buildRegisterMessage({
username: "alice",
id: "alice-id",
domainName: "kju-is",
validUntil: Math.floor(Date.now() / 1000) + 30 * 24 * 3600,
wallet: userAddress, // bound into the signature (V1)
nonce: 1n, // first registration requires >= 1, strictly increasing after
payload: toBytes32("answer"), // arbitrary attested bytes32 (V1)
});
const signature = await registrar.signRegisterMessage(message);
// User submits
const user = new MultipassUser({ chainId: sepolia.id, publicClient, walletClient: userWallet });
await user.register({ record: message, registrarSignature: signature, value: fee });Deployments
| Chain | Address | EIP-712 domain |
|---|---|---|
| Sepolia (11155111) | 0x418F82fd0014a4CA402F145978bfaF0555a9cA06 | MultipassDNS / 1.0.0 |
Chains not listed can be used by passing deployment: { address, eip712Name, eip712Version } to any constructor. Pre-V1 deployments (old typehash without wallet/payload) are incompatible.
V1 contract semantics worth knowing
- The registrar signature covers
walletandpayload; a record cannot be front-run under a different wallet. - Nonces are registrar-signed and strictly increasing per
id; first registration needsnonce >= 1, and every signature is single-use. renewRecordwrites the signed record; itsidandwalletmust match the existing record.resolveRecorddoes not check expiry — useresolveActiveRecordor checkvalidUntilyourself.
Indexers (Envio ⇄ The Graph)
listDomains/listRecords read indexed events through a swappable backend:
import { EnvioIndexer, GraphIndexer, MultipassBase } from "@peeramid-labs/multipass-client";
const indexer = new EnvioIndexer({ endpoint: "http://localhost:8080/v1/graphql" });
// or: new GraphIndexer({ endpoint: "https://api.studio.thegraph.com/query/<id>/<name>/<v>" })
const multipass = new MultipassBase({ chainId, publicClient, indexer });
const records = await multipass.listRecords(true);Both implement the MultipassIndexer interface; GraphIndexer accepts an entities map when your subgraph's collection names differ from graph-cli defaults.
View codes (opt-in privacy)
import { deriveViewCode, decodeRecord, verifyViewCode } from "@peeramid-labs/multipass-client";
// registrar side (holds the view-code key)
const { message, viewCode } = registrar.buildOptInRegisterMessage({
handle: "fatpig", platformId: "12345678", domainName: "telegram",
validUntil, wallet, viewcodeKey,
});
// verifier side (holds only the view code)
verifyViewCode(viewCode, record); // payload commitment check
const { handle, platformId } = decodeRecord(record, viewCode);