Skip to main content
The SDK exposes two signing methods. Both require a provisioned wallet, and both verify the PIN before calling the native layer when requirePin is true. All signatures are:
  • 0x-prefixed 130-character hex strings
  • Recoverable ECDSA in r(32) ‖ s(32) ‖ v(1) format
  • Low-s normalised (EIP-2 compliant)
  • v ∈ {27, 28} — verifiable with ecrecover

Sign a personal message (EIP-191)

signMessage prepends the \x19Ethereum Signed Message:\n{length} prefix before hashing and signing. This matches the personal_sign RPC method used by SIWE, login challenges, and most WalletConnect flows.
When requirePin is false, omit the PIN:

Sign a 32-byte hash

signTransactionHash signs a pre-computed 32-byte digest directly, without adding any prefix. Use it for:
  • ERC-4337 userOpHash
  • EIP-712 structured-data digests
  • Raw Ethereum transaction hashes
  • Any other 32-byte payload you have already hashed yourself
The argument must decode to exactly 32 bytes; the 0x prefix is optional. Anything else throws signInvalidHash.

Server-side verification

Signatures are ECDSA-recoverable. Your backend (or a smart contract) only needs the address from initWallet():

Gating pattern

A common pattern is to ask for the PIN only when requirePin is true, and skip the prompt otherwise:
Because pin is undefined when the gate is off, the same call site works in both modes.

Prerequisites checklist

Before calling either signing method you need:
  1. A provisioned wallet (initWallet() succeeded, or hasWallet() is true)
  2. A PIN set (hasPin() is true) — only when requirePin is true
Calling a signing method without satisfying these throws pinNotSet, or pinInvalid if you omit the PIN entirely while the gate is on.