Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Types – ERC-8128
Skip to content

Types

Glossary of types in @slicekit/erc8128.

Hex

Hex-encoded string with 0x prefix.

type Hex = `0x${string}`

Address

Ethereum address (40 hex characters with 0x prefix).

type Address = `0x${string}`

EthHttpSigner

Interface for Ethereum message signing. Used by signRequest and signedFetch.

interface EthHttpSigner {
  /** Ethereum address (EOA or smart contract account) */
  address: Address
  
  /** Chain ID for the keyid */
  chainId: number
  
  /** Sign the RFC 9421 signature base as an Ethereum message (EIP-191) */
  signMessage: (message: Uint8Array) => Promise<Hex>
}

Example

Here's how to create an EthHttpSigner using viem's privateKeyToAccount:

import type { EthHttpSigner } from '@slicekit/erc8128'
import { privateKeyToAccount } from 'viem/accounts'
 
const account = privateKeyToAccount('0x...')
 
const signer: EthHttpSigner = {
  chainId: 1,
  address: account.address,
  signMessage: async (message) => {
    return account.signMessage({ message: { raw: message } })
  },
}

SignOptions

Options for signRequest and signedFetch.

type SignOptions = {
  /** Signature label (default: "request") */
  label?: string
  
  /** Binding mode (default: "request-bound") */
  binding?: BindingMode
  
  /** Unix timestamp when signature becomes valid (default: now) */
  created?: number
  
  /** Unix timestamp when signature expires (default: created + ttlSeconds) */
  expires?: number
  
  /** Library default: 60; prefer the shortest delivery-safe duration. */
  ttlSeconds?: number
  
  /** Custom nonce/generator, or null to make the request Replayable */
  nonce?: string | (() => Promise<string>) | null
  
  /** Content-Digest handling (default: "auto") */
  contentDigest?: ContentDigestMode
  
  /** Additional components to sign beyond the default set */
  components?: string[]
}

BindingMode

Controls which request components are signed.

type BindingMode = "request-bound" | "class-bound"
ValueDescription
request-boundSign @scheme, @authority, @method, @path, and @query unconditionally, plus received content fields. This is the secure default.
class-boundSign only the components you explicitly specify. Requires components array.

ReplayMode

Describes the replay posture returned by verification. Signing infers this posture solely from nonce presence: the default generated nonce is Non-Replayable and { nonce: null } is Replayable.

type ReplayMode = "non-replayable" | "replayable"
ValueDescription
non-replayableInclude a nonce (auto-generated if not provided). Default.
replayableNo nonce. Signature can be reused within its validity window. Trades single-use guarantee for reduced overhead.

ContentDigestMode

Controls Content-Digest header handling.

type ContentDigestMode = "auto" | "recompute" | "require" | "off"
ValueDescription
autoAdd Content-Digest if body is present and components include it. Default.
recomputeAlways recompute Content-Digest even if header exists.
requireRequire existing Content-Digest header.
offDisable automatic digest handling. Signing throws if covered components require content-digest.

VerifyPolicy

Policy for verifyRequest.

type VerifyPolicy = {
  /** Select base-profile (`direct`), delegated, or either principal class. */
  principal?: "direct" | "delegated" | "either"
 
  /** Base-profile account verification policy (default: "universal"). */
  accountVerification?: "universal" | "eoa-only"
 
  /**
   * Extra components required in addition to the default request-bound set.
   * Use this for custom headers like 'x-idempotency-key'.
   */
  additionalRequestBoundComponents?: string[]
 
  /** Require these request headers to be covered whenever they are present. */
  requiredCoveredHeadersWhenPresent?: string[]
  
  /**
   * Class-bound policies (one list or a list of lists).
   * If any policy list is covered by the signed components, the signature is accepted.
   * `@authority` is always required (added if missing).
   * An empty list disables class-bound acceptance.
   */
  classBoundPolicies?: string[] | string[][]
  
  /** Allow replayable (nonce-less) signatures (default: false) */
  replayable?: boolean
 
  /**
   * Optional replayable invalidation (per-keyid).
   * When set and a signature is replayable, requests with created < notBefore are rejected.
   */
  replayableNotBefore?: (keyid: string) => number | null | undefined | Promise<number | null | undefined>
 
  /**
   * Optional per-signature invalidation hook for replayable signatures.
   * Return true to mark the signature as invalidated.
   */
  replayableInvalidated?: (args: {
    keyid: string
    signature: Hex
  }) => boolean | Promise<boolean>
  
  /** Maximum number of request-signature candidates to verify (default: 8) */
  maxSignatureVerifications?: number
 
  /**
   * Universal Account classification/proof calls shared across candidates.
   * Defaults to 2 + the configured delegation-chain depth.
   */
  maxAccountVerificationCalls?: number
  
  /** Current time function (default: Date.now() / 1000) */
  now?: () => number
  
  /** Allowed clock skew in seconds (default: 0) */
  clockSkewSec?: number
  
  /** Maximum validity window in seconds (default: 300) */
  maxValiditySec?: number
  
  /** Maximum nonce validity window (optional) */
  maxNonceWindowSec?: number
  
  /**
   * Custom key generator for nonce storage. The key must derive only from
   * covered signature material, and all verifier backends must share one
   * logical nonce namespace.
   */
  nonceKey?: (keyid: string, nonce: string) => string
 
  /** Required to accept delegated signatures. */
  delegation?: DelegationPolicy
}
type DelegationPolicy = {
  grantCache?: DelegationGrantCache
  /** Default 60 seconds; 0 bypasses proof-cache reads and writes. */
  grantCacheTtlSec?: number
  maxChainDepth?: number
  maxGrantValiditySec?: number
  requiredPermissions?: readonly string[]
  permissionsSupported?: boolean
  verifyStatuses: (
    contexts: readonly DelegationStatusContext[]
  ) =>
    | readonly DelegationStatus[]
    | Promise<readonly DelegationStatus[]>
}

Positive grant-proof caches are keyed by the grant digest and signature bytes. DelegationGrantCache.set receives an absolute Unix expiry, and get must not return the entry once that expiry has passed. Deployments must document how the configured TTL bounds stale acceptance after an SCA state change.

verifyStatuses receives every ordered link in the resolved chain at once and returns one status in the same order. This lets registry-backed verifiers use a single multicall rather than one RPC request per link. Registry chain and address are not grant fields or ordinary signer configuration.


NonceStore

Interface for replay protection storage. See NonceStore implementations.

interface NonceStore {
  /**
   * Atomically consume a nonce.
   * Returns true if newly stored (not seen before), false if already exists.
   */
  consume(key: string, ttlSeconds: number): Promise<boolean>
}

VerifyMessageFn

Function type for verifying Ethereum signatures. See VerifyMessageFn with viem.

type VerifyMessageFn = (args: {
  address: Address
  chainId: number
  message: { raw: Hex }
  signature: Hex
}) => boolean | 'unavailable' | Promise<boolean | 'unavailable'>

createUniversalAccountVerifier({ getCode, verifySmartAccount }) constructs this function with ERC-6492-first verification, ERC-1271 for code-bearing accounts, and strict local recovery for code-free EOAs. RPC failures return "unavailable".


VerifyResult

Result of verifyRequest.

type VerifyResult =
  | {
      ok: true
      principal: { address: Address; chainId: number }
      signer: { address: Address; chainId: number }
      delegated: false
      label: string
      components: ComponentIdentifier[]
      params: SignatureParams
      replay: ReplayMode
      binding: BindingMode
    }
  | {
      ok: true
      principal: { address: Address; chainId: number }
      signer: { address: Address; chainId: number }
      delegated: true
      delegationIds: Hex[]
      replay: ReplayMode
      binding: BindingMode
    }
  | {
      ok: false
      reason: VerifyFailReason
      detail?: string
    }

Success Properties

PropertyTypeDescription
oktrueVerification succeeded
principalAccountIdentityAuthenticated root or base-profile account
signerAccountIdentityAccount that signed the request
delegatedbooleanWhether a delegation authorization authenticated the principal
delegationIdsHex[]Ordered signed revocation IDs for the verified chain
labelstringSignature label that was verified
componentsComponentIdentifier[]Structurally parsed signed components
paramsSignatureParamsParsed signature parameters
replayReplayModeWhether the signature is replayable or non-replayable
bindingBindingModeBinding mode used by the signature

Failure Properties

PropertyTypeDescription
okfalseVerification failed
reasonVerifyFailReasonWhy verification failed
detailstring?Optional detail message

SignatureParams

Parsed signature parameters from Signature-Input header.

type SignatureParams = {
  created: number
  expires: number
  keyid: string
  nonce?: string
  tag?: string
}

VerifyFailReason

All possible verification failure reasons. See Failure Reasons for descriptions.

type VerifyFailReason =
  | "signature_missing"
  | "no_acceptable_signature"
  | "signature_input_invalid"
  | "signature_too_large"
  | "invalid_keyid"
  | "invalid_time"
  | "request_not_yet_valid"
  | "request_expired"
  | "request_validity_too_long"
  | "invalid_nonce"
  | "insufficient_coverage"
  | "content_digest_required"
  | "bad_content_digest"
  | "nonce_required"
  | "nonce_reused"
  | "replayable_not_allowed"
  | "unsupported_algorithm"
  | "bad_signature"
  | "signature_verification_unavailable"
  | "principal_not_allowed"
  | "unsupported_delegation"
  | "bad_delegation_field"
  | "delegation_too_large"
  | "delegation_not_covered"
  | "delegate_mismatch"
  | "delegation_chain_too_long"
  | "delegation_chain_discontinuous"
  | "delegation_attenuation_violation"
  | "grant_expired"
  | "grant_not_yet_valid"
  | "grant_validity_too_long"
  | "request_outside_grant_window"
  | "bad_grant_signature"
  | "audience_mismatch"
  | "delegation_nonce_required"
  | "delegation_request_validity_exceeded"
  | "delegation_components_unsupported"
  | "delegation_components_uncovered"
  | "unsupported_permissions"
  | "insufficient_permissions"
  | "authorization_revoked"
  | "authorization_epoch_mismatch"
  | "grant_verification_unavailable"
  | "revocation_unavailable"

SignerClient

Return type of createSignerClient. Provides bound methods for signing requests.

type SignerClient = {
  signRequest: {
    (input: RequestInfo, opts?: SignOptions): Promise<Request>
    (input: RequestInfo, init: RequestInit | undefined, opts?: SignOptions): Promise<Request>
  }
  signedFetch: {
    (input: RequestInfo, opts?: FetchOptions): Promise<Response>
    (input: RequestInfo, init: RequestInit | undefined, opts?: FetchOptions): Promise<Response>
  }
  fetch: {
    (input: RequestInfo, opts?: FetchOptions): Promise<Response>
    (input: RequestInfo, init: RequestInit | undefined, opts?: FetchOptions): Promise<Response>
  }
  setServerConfig: (origin: string, config: ServerConfig | null) => void
}

Methods

MethodDescription
signRequestSign a request without sending
signedFetchSign and send a request
fetchAlias for signedFetch
setServerConfigSet or remove per-origin discovery config

FetchOptions

Per-call options for client.fetch() and client.signedFetch(). Extends SignOptions with an optional fetch implementation override.

type FetchOptions = SignOptions & { fetch?: typeof fetch }

SignerClientOptions

Options for createSignerClient.

type SignerClientOptions = SignOptions & {
  fetch?: typeof fetch
  serverConfigs?: Record<string, ServerConfig>
  preferReplayable?: boolean
}

VerifierClient

Return type of createVerifierClient. Provides a bound method for verifying requests.

type VerifierClient = {
  verifyRequest: (args: {
    request: Request
    policy?: VerifyPolicy
    setHeaders?: (name: string, value: string) => void
  }) => Promise<VerifyResult>
}

Methods

MethodDescription
verifyRequestVerify a signed request

VerifierClientOptions

Options for createVerifierClient and client methods. Extends VerifyPolicy.

type VerifierClientOptions = VerifyPolicy

SetHeadersFn

Callback to set response headers. Used by verifyRequest to emit Accept-Signature with one canonical signature shape per supported policy.

type SetHeadersFn = (name: string, value: string) => void

VerifyRequestArgs

Argument object for verifyRequest.

type VerifyRequestArgs = {
  request: Request
  verifyMessage: VerifyMessageFn
  nonceStore: NonceStore
  policy?: VerifyPolicy
  setHeaders?: SetHeadersFn
}
PropertyTypeDescription
requestRequestThe HTTP request to verify
verifyMessageVerifyMessageFnSignature verification function
nonceStoreNonceStoreReplay protection store
policyVerifyPolicyOptional verification policy
setHeadersSetHeadersFnOptional callback to set Accept-Signature response header

VerifierClientVerifyRequestArgs

Argument object for verifierClient.verifyRequest(). The client already has verifyMessage and nonceStore bound, so only request and optional overrides are needed.

type VerifierClientVerifyRequestArgs = {
  request: Request
  policy?: VerifyPolicy
  setHeaders?: SetHeadersFn
}

CreateVerifierClientArgs

Argument object for createVerifierClient.

type CreateVerifierClientArgs = {
  verifyMessage: VerifyMessageFn
  nonceStore: NonceStore
  defaults?: VerifyPolicy
}
PropertyTypeDescription
verifyMessageVerifyMessageFnSignature verification function
nonceStoreNonceStoreReplay protection store
defaultsVerifyPolicyDefault policy applied to all requests

Erc8128Error

Custom error class for ERC-8128 operations.

class Erc8128Error extends Error {
  code: Erc8128ErrorCode
}

Erc8128ErrorCode

Error codes for Erc8128Error.

type Erc8128ErrorCode =
  | "CRYPTO_UNAVAILABLE"   // WebCrypto not available
  | "INVALID_OPTIONS"      // Bad sign options
  | "UNSUPPORTED_REQUEST"  // Can't sign this request
  | "BODY_READ_FAILED"     // Can't read request body
  | "DIGEST_REQUIRED"      // Content-Digest required but not present
  | "BAD_DERIVED_VALUE"    // Can't derive component value
  | "BAD_HEADER_VALUE"     // Invalid header format
  | "PARSE_ERROR"          // Can't parse input

Example

Catch Erc8128Error to handle specific error codes during signing or verification:

import { signRequest, Erc8128Error } from '@slicekit/erc8128'
 
try {
  const signedRequest = await signRequest(input, signer)
} catch (error) {
  if (error instanceof Erc8128Error) {
    console.error(`Error (${error.code}): ${error.message}`)
  }
  throw error
}