@orangecheck/sdk
The core protocol SDK. Three functions cover 90% of integrations; the rest are building blocks.
yarn add @orangecheck/sdk
The three load-bearing functions
check()
Sybil-gate primitive. Discovers the most recent attestation for a subject, verifies the signature, recomputes metrics, compares against thresholds.
import { check } from '@orangecheck/sdk';
const r = await check({
addr: 'bc1q...',
minSats: 100_000,
minDays: 30,
});
if (r.ok) {
// let them through
} else {
console.log('rejected:', r.reasons);
}
Accepts addr, id (attestation ID), or identity ({ protocol, identifier }). Returns a CheckResult.
verify()
Raw (addr, msg, sig) verification. Use when you have the envelope in hand.
import { verify } from '@orangecheck/sdk';
const outcome = await verify({
addr: 'bc1q...',
msg: canonicalMessage,
sig: signature,
scheme: 'bip322',
});
if (outcome.ok) {
const { sats_bonded, days_unspent, score } = outcome.metrics!;
}
createAttestation()
Package a signed message + signature into a self-contained JSON envelope.
import {
buildCanonicalMessage,
createAttestation,
publishAttestation,
} from '@orangecheck/sdk';
const message = buildCanonicalMessage(
{ address, identities },
{ bond: '1000000', expires: '2027-01-15T12:00:00Z' }
);
const signature = await userWallet.signMessage(message);
const envelope = await createAttestation({
message, signature, scheme: 'bip322', address, identities,
});
// Optional — publish to Nostr
await publishAttestation({ envelope, npub: userNpub });
Signed-challenge auth
For gates that can't trust the address source (public headers, query strings):
import { issueChallenge, verifyChallenge } from '@orangecheck/sdk';
// Server — issue
const c = issueChallenge({
address: userAddr,
audience: 'https://example.com',
purpose: 'login',
});
req.session.ocNonce = c.nonce;
res.json({ message: c.message });
// Server — verify (on POST)
const r = await verifyChallenge({
message: req.body.message,
signature: req.body.signature,
expectedNonce: req.session.ocNonce,
});
if (r.ok) req.session.verifiedAddress = r.address; // cryptographically proven
See Sign in with Bitcoin for the full flow.
Discovery
import {
discoverAttestations,
getAttestationsForAddress,
getAttestationsForIdentity,
} from '@orangecheck/sdk';
await discoverAttestations({ attestationId: 'a3f5b8c2…' });
await getAttestationsForAddress('bc1q...');
await getAttestationsForIdentity('github', 'alice');
Identity verification
Handle ownership is self-asserted inside a signed message. Verify out-of-band:
import { verifyIdentity } from '@orangecheck/sdk';
const r = await verifyIdentity({
protocol: 'github',
identifier: 'alice',
attestationId: envelope.attestation_id,
proof: 'https://gist.github.com/alice/abc123',
});
Supported protocols: nostr, github, dns, twitter.
Public API surface
// Load-bearing
check(params: CheckParams): Promise<CheckResult>
verify(input: VerifyInput, options?: VerifyOptions): Promise<VerifyOutcome>
createAttestation(options: CreateAttestationOptions): Promise<AttestationEnvelope>
// Signed-challenge auth
issueChallenge(options): Challenge
verifyChallenge(options): Promise<VerifyChallengeResult>
// Building blocks
buildCanonicalMessage(...)
generateAttestationId(msg: string): Promise<string>
publishAttestation({ envelope, npub, relays? })
discoverAttestations({ attestationId | address | identity, relays? })
verifyIdentity({ protocol, identifier, attestationId, proof? })
computeScore(sats, days, { algorithm: 'v0' | 'tier' | 'none' })
Full types are exported — import with:
import type {
CheckResult,
VerifyOutcome,
AttestationEnvelope,
IdentityBinding,
Challenge,
} from '@orangecheck/sdk';
Guarantees
- No custody. Signs messages; never spends coins.
- No telemetry. The SDK talks only to public Bitcoin explorers and Nostr relays you pass in.
- Offline-verifiable.
verify()for an envelope you already hold needs only the message, signature, address, and chain state.
Tree-shaking
Every function has a dedicated entry point:
import { check } from '@orangecheck/sdk/check';
import { verify } from '@orangecheck/sdk/verify';
import { issueChallenge } from '@orangecheck/sdk/challenge';
import { computeScore } from '@orangecheck/sdk/scoring';
License
MIT.