Skip to content

invite-only · devnet/testnet first

Custody infrastructure where no complete private key ever exists — every signature requires a quorum spanning two independent trust domains.

Embedded wallets and transaction signing for teams that read security models before they read pricing pages. FROST threshold signatures, a policy engine built on value-conservation invariants, and approvals that a stolen token cannot forge.

sign-devnet-tx.ts
import { FabricClient } from "@signing-fabric/sdk-server";

const fabric = new FabricClient({
  apiKey: process.env.FABRIC_API_KEY, // sf_test_…
});

const wallet = await fabric.wallets.create({
  chain: "solana-devnet",
});

// Policy evaluation, quorum signing across two trust
// domains, and an append-only audit record — one call.
const { signature } = await fabric.transactions.sign({
  walletId: wallet.id,
  transaction: serializedTx,
});

Built to integrate in an afternoon

Three calls from zero to a signed transaction

  1. 01

    Create an organization

    One API call. Members, roles, and policies are scoped to your org from the first request — there is no default tenant.

    const org = await fabric.organizations.create({
      name: "acme-treasury",
    });
  2. 02

    Mint a key

    Distributed key generation runs across two independent trust domains. Each holds a share; the complete key never exists.

    const wallet = await fabric.wallets.create({
      chain: "solana-devnet",
      policy: "value-conservation:default",
    });
  3. 03

    Sign a devnet transaction

    The policy engine decodes and evaluates the transaction, the quorum signs, and the decision is written to your audit log.

    const { signature } = await fabric.transactions.sign({
      walletId: wallet.id,
      transaction: serializedTx,
    });

API shape shown is illustrative; the SDK and public docs ship with access. Test keys are prefixed sf_test_, live keys sf_live_.

Trust model

Two independent trust domains. Neither is sufficient alone.

Key shares live in two deliberately different environments: a hardware-attested confidential-compute enclave, and physically isolated bare metal. They share no operator credentials and no control plane. A signature exists only when both participate in a FROST threshold ceremony (RFC 9591) — the complete private key is never assembled in any process, at any time, including backup and migration.

Transaction intent

Raw bytes + decoded, human-readable effect

Policy engine

  • Value-conservation invariants — not destination allowlists
  • Recursive decode of nested program invocations
  • Unknown instruction → deny. No permissive catch-all.

verdict must precede any use of a key share

Trust domain A

Hardware-attested confidential-compute enclave

key share A

Trust domain B

Physically isolated bare metal

key share B

Aggregated threshold signature

FROST (RFC 9591). The complete private key is never assembled — not here, not anywhere.

Neither domain alone can sign. Compromising one yields a share that is useless without the other.

The full security model, including what we deliberately do not do →

Policy engine

Policies are invariants, not lists

Value conservation, not allowlists

Policies state invariants over what a transaction may do to your balances — value in versus value out — rather than enumerating destinations. A spend cap is an upper bound; conservation is an equation. Novel drain paths that respect no allowlist still violate the equation, and are denied.

Recursive instruction decoding

On-chain programs invoke other programs. The engine decodes nested cross-program invocations recursively and evaluates the policy against the full tree — not just the top-level instruction a wallet UI happens to render.

Unknown means no

Every instruction the engine cannot parse into a strictly-typed, known form is denied. Support for new programs is added as typed decoders with unknown fields rejected — never as a permissive catch-all.

Fail closed

The policy verdict precedes any use of a key share, on every path. There is no reduced-quorum fallback, no emergency bypass, no fast path that skips a check.

Built for teams

The controls a treasury actually operates

Approval inbox with quorum

Signing requests are durable objects with an explicit lifecycle. Require N-of-M approvals from members holding the signer role; a single approver cannot move funds alone, and expired requests are dead, not dormant.

Roles and members

Owner, admin, signer, viewer — with explicit permissions, org-scoped API keys shown once and hashed at rest, and invitations that never grant more than they say.

Append-only audit records

Every policy decision, approval, and key operation is recorded per tenant with actor, timestamp, and outcome. Admins can read and export the history; nobody can edit it.

Request-signed operations

High-value operations — creating a signing request, changing a policy, approving — are signed by the member's own key, not merely bearer-authed. A stolen session token is not enough to move value.

For latency-critical flows, the platform supports a colocated fast path: your services deployed adjacent to the signing infrastructure, skipping public network round-trips — while passing through exactly the same policy engine and checks as every other request.

Access is invite-only while we onboard design partners

Tell us what you are building and what you need from a custody layer.

Or email access@signing-fabric.example.