npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kryard/sdk

v0.4.0

Published

Client for Kryard's Turnkey-compatible wallet infrastructure: X-Stamp'd key creation, secp256k1 signing (raw payload + EVM transaction), HPKE private-key export, and the managed EIP-7702 relay (sponsored execute with optional ERC-20 gas).

Readme

@kryard/sdk

A client for Kryard's Turnkey-compatible wallet infrastructure:

  • Wallets & signing — create secp256k1 keys, sign raw payloads and EVM transactions through Kryard's Turnkey-shaped activity API (X-Stamp authed).
  • Key export — pull a key out as an HPKE-sealed bundle (RFC 9180) and recover it locally; the plaintext never leaves the signer except encrypted to you.
  • Managed EIP-7702 relay — a user signs a 7702 authorization + batch digest; Kryard signs, fronts gas, and broadcasts the type-4 transaction (gasless, batched, no 4337 bundler). Optionally the user pays gas in any ERC-20.

All three share the same X-Stamp API-key stamper. Pairs with the on-chain KryardDelegate and Kryard's public API.

Install

Published to both npm and GitHub Packages (same version):

# npm (public)
npm i @kryard/sdk viem

From GitHub Packages, add to your .npmrc first:

@kryard:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}   # a PAT with read:packages

then npm i @kryard/sdk viem.

Quick start

import { createWalletClient, http, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { sepolia } from "viem/chains";
import { KryardRelayClient, createApiKeyStamper, sponsorExecute, type UserSigner, type Call } from "@kryard/sdk";

// 1. The Kryard relay client (the relayer ORG's API key stamps the request).
const client = new KryardRelayClient({
  baseUrl: "https://api.kryard.com",
  organizationId: process.env.KRYARD_ORG!,
  stamper: createApiKeyStamper({
    apiPublicKey: process.env.KRYARD_API_PUBLIC_KEY!,
    apiPrivateKey: process.env.KRYARD_API_PRIVATE_KEY!,
  }),
});

// 2. Adapt the USER's wallet to the UserSigner interface.
const account = privateKeyToAccount(process.env.USER_PK as Hex);
const wallet = createWalletClient({ account, chain: sepolia, transport: http() });
const signer: UserSigner = {
  address: account.address,
  // v2.1: RAW ECDSA over the EIP-712 digest — NOT personal_sign / signMessage({ raw }).
  signDigest: (digest) => account.sign({ hash: digest }),
  async signAuthorization({ contractAddress, chainId }) {
    const a = await wallet.signAuthorization({ account, contractAddress, chainId });
    return { address: a.address, chainId: a.chainId, nonce: a.nonce, r: a.r, s: a.s, yParity: a.yParity ?? 0 };
  },
};

// 3. Sponsor a batch (e.g. an ERC-20 transfer) — gasless for the user.
const calls: Call[] = [{ to: TOKEN, value: 0n, data: transferCalldata }];
const tx = await sponsorExecute({
  client, signer,
  chainId: 11155111,
  signWith: process.env.KRYARD_SIGN_WITH!, // the relayer key
  delegateAddress: KRYARD_DELEGATE,        // deployed v2.1 KryardDelegate on this chain
  calls,
  nonce: BigInt(Date.now()),               // single-use delegate nonce
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // Unix-seconds expiry (contract rejects now > deadline)
});
console.log(tx.id, tx.txHash);

// Poll to completion:
let status = tx;
while (!["confirmed", "failed", "expired"].includes(status.status)) {
  await new Promise((r) => setTimeout(r, 4000));
  status = await client.get(tx.id);
}

ERC-20 gas payment ("pay gas in any token")

Add gasToken + gasTokenAmount + relayer to sponsorExecute. The user signs an exact fee (the relayer can't inflate it); the on-chain KryardDelegate transfers that token amount to the relayer as the batch's last step:

await sponsorExecute({
  client, signer, chainId, signWith, delegateAddress, calls, nonce, deadline,
  gasToken: USDC,
  gasTokenAmount: 50_000n,   // Kryard quotes this off-chain (gas × price × rate × margin)
  relayer: RELAYER_ADDRESS,  // the address the relayer signs with on this chain
});

Custom delegate (delegate-agnostic) — e.g. a sweep

If you use your OWN 7702 delegate (not KryardDelegate), build the calldata + any inner delegate signature yourself, then use sponsorCall — the SDK signs only the 7702 authorization and submits, making no assumption about the delegate:

import { sponsorCall } from "@kryard/sdk";

// You build the call to your delegate (e.g. SweepDelegate.sweep(order, sweepSig)).
const sweepData = encodeFunctionData({ abi: SWEEP_DELEGATE_ABI, functionName: "sweep", args: [order, sweepSig] });

const tx = await sponsorCall({
  client, signer,                 // signer only needs { address, signAuthorization }
  chainId, signWith,
  delegateAddress: SWEEP_DELEGATE, // the 7702 target the user authorizes
  data: sweepData,                 // your pre-built calldata
  // optional ERC-20 accounting (if your call reimburses the relayer in token):
  // gasToken: USDC, gasTokenAmount: skimmedGasInToken,
});

sponsorExecute (above) is just sponsorCall with the KryardDelegate calldata built for you.

ERC-4337 gas sponsorship (verifying paymaster)

For account-abstraction accounts you send a UserOperation through a bundler, not a raw transaction. KryardPaymasterClient is the 4337 counterpart of the 7702 relay: it does not submit anything — it vouches for gas by signing your v0.7 UserOp for Kryard's verifying paymaster and returns the paymasterAndData to splice on before the bundler sends it. A policy denial comes back as a typed SponsorshipDeniedError (with a SponsorshipReasonCode).

import { KryardPaymasterClient, applyPaymasterAndData, SponsorshipDeniedError } from "@kryard/sdk";

const paymaster = new KryardPaymasterClient({
  baseUrl: "https://api.kryard.com",
  organizationId: process.env.KRYARD_ORG!,
  stamper: createApiKeyStamper({
    apiPublicKey: process.env.KRYARD_API_PUBLIC_KEY!,
    apiPrivateKey: process.env.KRYARD_API_PRIVATE_KEY!,
  }),
});

try {
  // `userOp` is your packed v0.7 UserOperation (bigint gas fields; packed bytes32 limits).
  const { paymasterAndData } = await paymaster.sponsorUserOperation(userOp, { chainId: 11155111 });
  const sponsored = applyPaymasterAndData(userOp, paymasterAndData); // immutable — splice it on
  // ...now sign `sponsored` and hand it to your bundler.
} catch (e) {
  if (e instanceof SponsorshipDeniedError) console.error("denied:", e.reasonCode); // e.g. SPONSOR_DAILY_CAP
}

buildPaymasterAndData / splitPaymasterAndData are the pure v0.7 byte-layout helpers (paymaster ‖ verificationGas(16) ‖ postOpGas(16) ‖ abi(uint48 validUntil, uint48 validAfter) ‖ signature(65)), byte-parity with the on-chain paymaster.

Wallets & signing

KryardClient wraps Kryard's Turnkey-compatible activity API. Every method stamps the exact request body with your API key and parses the single-nested activity envelope, throwing an ActivityError (carrying the server's code + message) when an activity does not complete.

import { KryardClient, createApiKeyStamper, ActivityError } from "@kryard/sdk";

const kryard = new KryardClient({
  baseUrl: "https://api.kryard.com",
  organizationId: process.env.KRYARD_ORG!,
  stamper: createApiKeyStamper({
    apiPublicKey: process.env.KRYARD_API_PUBLIC_KEY!,
    apiPrivateKey: process.env.KRYARD_API_PRIVATE_KEY!,
  }),
});

// Create a secp256k1 EVM key (defaults: CURVE_SECP256K1, ADDRESS_FORMAT_ETHEREUM).
const { privateKeyId, addresses } = await kryard.createPrivateKey({ name: "hot-wallet-1" });
// → addresses: [{ addressFormat: "ADDRESS_FORMAT_ETHEREUM", address: "0x…" }]

// Sign an EVM transaction (signedTransaction is hex WITHOUT 0x — ready to broadcast).
const { signedTransaction } = await kryard.signTransaction({
  signWith: privateKeyId,            // a key id OR an address the org owns
  unsignedTransaction: "0x02ef…",    // serialized EIP-1559 tx, e.g. from viem
});

// Sign a raw payload (r/s/v components).
const { r, s, v } = await kryard.signRawPayload({
  signWith: privateKeyId,
  payload: "0xdeadbeef",
  hashFunction: "HASH_FUNCTION_KECCAK256",
});

try {
  await kryard.signTransaction({ signWith: "0xUnknown", unsignedTransaction: "0x02ef…" });
} catch (e) {
  if (e instanceof ActivityError) console.error(e.code, e.message); // typed failure
}

You may also import any Turnkey-protocol stamper (e.g. @turnkey/api-key-stamper) — Kryard speaks the Turnkey protocol — or inject your own Stamper.

Against a local signer (open-source, no account)

The open-source signer (Kryard/signer) runs the same API locally. In dev mode (DEV_ADMIN_ENABLED=true) it exposes an unauthenticated bootstrap that mints a throwaway org + API key, so you don't need a managed account. bootstrapLocalClient does that and hands back a ready client:

import { bootstrapLocalClient } from "@kryard/sdk";

const { client } = await bootstrapLocalClient(); // defaults to http://localhost:8787
const { addresses } = await client.createPrivateKey({ name: "local-evm", curve: "CURVE_SECP256K1" });

Dev-only — it targets /admin/dev/*, which the API exposes only in dev mode; never point it at a public deployment. Creating keys and queries work out of the box; to also sign locally, run the API with POLICY_BYPASS_ALLOWED=true (or seed a policy).

Key export

Export pulls a key out as an HPKE-sealed bundle (RFC 9180, suite DHKEM(P-256, HKDF-SHA256) / HKDF-SHA256 / AES-256-GCM, info "kryard-export-v1", aad = the key id). The signer decrypts the key inside its boundary and re-seals it to a recipient public key you supply — plaintext never crosses the wire.

// Convenience: generate an ephemeral recipient keypair, request the sealed bundle,
// HPKE-open it locally, and return the recovered key. The recipient key is zeroized.
const { privateKey } = await kryard.exportPrivateKey({ signWith: privateKeyId });
// privateKey: hex (no 0x) — handle like any raw key (do not log / persist / transmit).

Bring-your-own-recipient (e.g. an HSM or air-gapped key holds the recipient secret):

import { decryptExportBundle, generateRecipientKeyPair } from "@kryard/sdk";

const recipient = await generateRecipientKeyPair();           // P-256, SEC1-uncompressed hex
const { privateKeyId: resolvedId, exportBundle } = await kryard.exportPrivateKeyBundle({
  signWith: privateKeyId,
  targetPublicKey: recipient.publicKeyHex,
});
// Open with the recipient private key. The aad MUST be the resolved key id.
const keyBytes = await decryptExportBundle(exportBundle, recipient.privateKey, resolvedId);

The bundle is a clean RFC-9180 HPKE format and interops with the Go (CIRCL) signer; it is not byte-compatible with Turnkey's enclave-wrapped decryptExportBundle.

Lower-level building blocks

  • submitActivity(...) — stamp + POST any activity, parse the envelope, throw on FAILED.
  • delegateDigest(...) — the raw 32-byte EIP-712 digest the user signs with plain ECDSA (v2.1; mirrors the contract).
  • domainSeparator(...) — the EIP-712 domain separator (EOA as verifyingContract).
  • encodeExecute / encodeExecuteWithGasReimbursement — KryardDelegate calldata.
  • buildSponsoredExecute(...) — assemble a relay submit body from already-signed pieces (pure).
  • KryardRelayClient.submit / .get — the raw relay route, X-Stamp authed.
  • KryardPaymasterClient.sponsorUserOperation — request 4337 gas sponsorship (verifying paymaster).
  • buildPaymasterAndData / splitPaymasterAndData / applyPaymasterAndData — pure v0.7 paymasterAndData byte-layout helpers.

License

MIT.