SDK Reference
The invisible-wallet-sdk is a TypeScript package providing a React hook and utility functions for integrating Veil into web applications.
Package: invisible-wallet-sdk
Source: sdk/src/
Entry: dist/index.js / dist/index.d.ts
Installation
npm install invisible-wallet-sdk stellar-sdkuseInvisibleWallet
The primary React hook. Manages wallet state and exposes register/sign/login methods.
import { useInvisibleWallet } from 'invisible-wallet-sdk'
const wallet = useInvisibleWallet(factoryAddress: string)Parameters
| Name | Type | Description |
|---|---|---|
factoryAddress | string | Soroban factory contract address (Strkey format). Used in Phase 3+ for wallet deployment. |
Return value — InvisibleWallet
interface InvisibleWallet {
// State
address: string | null // Wallet contract address, null if not registered
isPending: boolean // true while any async operation is in flight
error: string | null // Last error message
// Methods
register(username: string): Promise<void>
signAuthEntry(signaturePayload: Uint8Array): Promise<WebAuthnSignature | null>
login(): Promise<void>
}register(username)
Creates a new passkey credential and initializes the wallet.
await wallet.register('alice')Flow:
- Calls
navigator.credentials.create()withalg: -7(ES256/P-256) - Extracts the 65-byte uncompressed public key via
extractP256PublicKey() - (Phase 3) Deploys wallet via factory contract using the public key
- Stores
wallet_address,key_id, andpublic_keyinlocalStorage
Throws if WebAuthn is not supported or the user cancels.
The challenge used during registration is a random 32-byte nonce — it is not a Soroban payload. Only signAuthEntry uses the actual payload as the challenge.
signAuthEntry(signaturePayload)
Signs a Soroban authorization entry using the device biometric.
const sig: WebAuthnSignature | null = await wallet.signAuthEntry(payload)Parameters
| Name | Type | Description |
|---|---|---|
signaturePayload | Uint8Array | 32-byte Soroban HashIdPreimage (the auth entry hash) |
Returns WebAuthnSignature | null — null if the user cancels or no credential is found.
Flow:
- Calls
navigator.credentials.get()withchallenge = signaturePayload - The device prompts the user for biometric/PIN verification
- Extracts
authDataandclientDataJSONfrom the assertion response - Converts DER-encoded signature to raw 64-byte format via
derToRawSignature() - Returns the full
WebAuthnSignaturebundle
Encoding for __check_auth:
// Encode as Vec<Val>[4] using stellar-sdk XDR
const sigVec = [
xdr.ScVal.scvBytes(sig.publicKey),
xdr.ScVal.scvBytes(sig.authData),
xdr.ScVal.scvBytes(sig.clientDataJSON),
xdr.ScVal.scvBytes(sig.signature),
]login()
Restores a wallet session from localStorage. Does not trigger a biometric prompt.
await wallet.login()
// wallet.address is now set if a previous session existsWebAuthnSignature type
interface WebAuthnSignature {
publicKey: Uint8Array // 65 bytes: 0x04 || x (32B) || y (32B)
authData: Uint8Array // WebAuthn authenticatorData (variable length)
clientDataJSON: Uint8Array // UTF-8 JSON containing base64url(challenge)
signature: Uint8Array // 64 bytes: r (32B) || s (32B)
}Utility Functions (utils.ts)
derToRawSignature(derSig: ArrayBuffer): Uint8Array
Converts a WebAuthn DER-encoded P-256 signature to the raw 64-byte r || s format expected by __check_auth.
import { derToRawSignature } from 'invisible-wallet-sdk'
const raw = derToRawSignature(assertion.response.signature)
// Uint8Array(64)DER format: 30 <len> 02 <rLen> <r> 02 <sLen> <s>
Output: r (32B, zero-padded) || s (32B, zero-padded)
extractP256PublicKey(response: AuthenticatorAttestationResponse): Promise<Uint8Array>
Extracts the 65-byte uncompressed P-256 public key from a WebAuthn attestation response.
const pubkey = await extractP256PublicKey(credential.response)
// Uint8Array(65): 0x04 || x || yUses getPublicKey() + SubtleCrypto importKey / exportKey — avoids manual CBOR/SPKI parsing. Requires Chrome 95+, Firefox 93+, Safari 16+.
sha256(data: Uint8Array): Promise<Uint8Array>
SHA-256 hash using the Web Crypto API.
const hash = await sha256(new TextEncoder().encode('hello'))
// Uint8Array(32)computeWebAuthnMessageHash(authData, clientDataJSON): Promise<Uint8Array>
Computes SHA256(authData || SHA256(clientDataJSON)) — the exact message hash the authenticator signs over.
const msgHash = await computeWebAuthnMessageHash(
assertion.response.authenticatorData,
assertion.response.clientDataJSON,
)parseAuthData(authData: ArrayBuffer)
Parses the binary authenticatorData structure.
const { rpIdHash, flags, signCount } = parseAuthData(authData)
// rpIdHash: Uint8Array(32)
// flags: { userPresent, userVerified, attestedCredData, extensionData }
// signCount: numberparseClientDataJSON(clientDataJSON: ArrayBuffer)
Decodes clientDataJSON and returns a typed object.
const { type, challenge, origin } = parseClientDataJSON(clientDataJSON)
// type: "webauthn.get" | "webauthn.create"
// challenge: base64url string
// origin: stringbase64UrlEncode(bytes: Uint8Array): string
Encodes bytes as base64url without padding.
base64UrlEncode(new Uint8Array([1, 2, 3])) // "AQID"bufferToHex(input: Uint8Array | ArrayBuffer): string
bufferToHex(new Uint8Array([0xde, 0xad])) // "dead"hexToUint8Array(hex: string): Uint8Array
hexToUint8Array('deadbeef') // Uint8Array([0xde, 0xad, 0xbe, 0xef])encodeU64(num: bigint): Uint8Array
Encodes a bigint as an 8-byte big-endian buffer for XDR u64 fields.
encodeU64(1000n) // Uint8Array(8)