Skip to main content

@urblock/connect-core

Framework-agnostic TypeScript library powering urblock connect. Use it directly for custom integrations without React, or as the foundation for any frontend framework.

npm install @urblock/connect-core
info

Sole runtime dependency: viem ^2.21.0 (for ABI encoding, hashing, and RPC calls).


WebAuthn (Passkeys)

registerPasskey(params)

Register a new FIDO2 passkey using the platform authenticator (Touch ID, Face ID, Windows Hello).

import { registerPasskey } from "@urblock/connect-core";

const credential = await registerPasskey({
rpId: "myapp.com",
rpName: "My App",
userId: "user-123",
userName: "alice@example.com",
});

// credential.credentialId — base64url string
// credential.publicKey.x — P-256 x coordinate (bytes32 hex)
// credential.publicKey.y — P-256 y coordinate (bytes32 hex)
// credential.algorithm — "ES256"
ParamTypeDescription
rpIdstringRelying Party ID (your domain)
rpNamestringRelying Party display name
userIdstringUnique user identifier
userNamestringDisplay name for the credential
challengeUint8Array(optional) Custom challenge bytes

Returns: WebAuthnCredential{ credentialId, publicKey: { x, y }, algorithm, clientDataJSON? }

Uses navigator.credentials.create() with ES256 (P-256), platform authenticator, resident key required.


signWithPasskey(params)

Sign a challenge using an existing passkey.

import { signWithPasskey } from "@urblock/connect-core";

const assertion = await signWithPasskey({
rpId: "myapp.com",
challenge: "0xabcdef...", // hex or Uint8Array
credentialId: "base64url...", // optional: restrict to specific key
});

// assertion.signature.r — P-256 r component (hex)
// assertion.signature.s — P-256 s component (hex)
// assertion.authenticatorData — raw bytes
// assertion.clientDataJSON — raw string
// assertion.challengeOffset — byte offset of challenge in clientDataJSON

Returns: WebAuthnAssertion


encodeWebAuthnSignature(signerId, assertion, usePrecompiled?)

ABI-encode a WebAuthn assertion for Kernel v3.1's WebAuthnValidator.

import { encodeWebAuthnSignature } from "@urblock/connect-core";

const signature = encodeWebAuthnSignature(signerId, assertion);
// Ready to set as userOp.signature

Encodes: (bytes authenticatorData, string clientDataJSON, uint256 challengeOffset, uint256 r, uint256 s, bool usePrecompiled)


Passkey Storage

Persist and restore passkey credentials across sessions:

import {
persistStoredPasskey,
loadStoredPasskey,
clearStoredPasskey,
} from "@urblock/connect-core";

// Save after registration
persistStoredPasskey(credential);

// Restore on page load
const stored = loadStoredPasskey();
if (stored) {
console.log("Reconnecting with passkey:", stored.credentialId);
}

// Clear on disconnect
clearStoredPasskey();

Storage key: "urblock:passkey" in localStorage. The clientDataJSON field is stripped before persisting.


UserOp Builder (ERC-4337)

buildUserOp(params)

Build an unsigned ERC-4337 v0.7 packed UserOperation.

import { buildUserOp, type Call } from "@urblock/connect-core";

const calls: Call[] = [
{ target: "0xRecipient...", value: 1000000000000000n }, // send ETH
{ target: "0xToken...", data: "0xa9059cbb..." }, // ERC-20 transfer
];

const userOp = buildUserOp({
sender: "0xSmartAccount...",
nonce: 0n,
calls,
// optional overrides:
// verificationGasLimit, callGasLimit, preVerificationGas,
// maxFeePerGas, maxPriorityFeePerGas, initCode, paymasterAndData
});
  • Single callEXEC_MODE_SINGLE + encodePacked(target, value, data)
  • BatchEXEC_MODE_BATCH + abi.encode(Execution[])
  • Default gas: verificationGas=200k, callGas=200k, preVerification=60k, maxPriority=1.5 gwei, maxFee=30 gwei

Returns: PackedUserOperation


getUserOpHash(userOp, entryPoint, chainId)

Compute the userOpHash matching the EntryPoint's on-chain implementation.

import { getUserOpHash, ENTRY_POINT_V07 } from "@urblock/connect-core";

const hash = getUserOpHash(userOp, ENTRY_POINT_V07, 11155111);
// hash: `0x${string}` — sign this to authorize the UserOp

getNonce(params)

Read the current nonce from the EntryPoint contract.

import { getNonce } from "@urblock/connect-core";

const nonce = await getNonce({
rpcUrl: "https://rpc.sepolia.org",
sender: "0xSmartAccount...",
key: 0n, // optional: nonce key (upper 192 bits = validator selector)
});

encodeECDSASignature(signerId, signature)

Pass-through for raw ECDSA signatures (65-byte r+s+v).

import { encodeECDSASignature } from "@urblock/connect-core";

const encoded = encodeECDSASignature(signerId, rawECDSASig);

Module Management (ERC-7579)

Encode calldata for installing/uninstalling modules on Kernel v3.1 smart accounts.

encodeInstallModule(moduleType, moduleAddress, initData)

import { encodeInstallModule } from "@urblock/connect-core";

// Module types: 1=Validator, 2=Executor, 3=Fallback, 4=Hook, 5=Policy, 6=Signer
const callData = encodeInstallModule(1, "0xValidator...", "0xinitData...");

encodeUninstallModule(moduleType, moduleAddress, deInitData)

const callData = encodeUninstallModule(1, "0xValidator...", "0x");

encodeUninstallValidation(validationId, deinitData, hookDeinitData)

// validationId = mode(1 byte) + address(20 bytes) = bytes21
const callData = encodeUninstallValidation("0x01abcdef...", "0x", "0x");

encodeChangeRootValidator(newValidationId, hookAddress, validatorData, hookData)

const callData = encodeChangeRootValidator(
"0x02newValidator...",
"0x0000000000000000000000000000000000000000", // no hook
"0xvalidatorInitData...",
"0x",
);

Key Encoding & Identity

encodeP256KeyData(x, y)

Encode a P-256 (WebAuthn) public key for Kernel's WebAuthnValidator.

import { encodeP256KeyData } from "@urblock/connect-core";

const keyData = encodeP256KeyData(credential.publicKey.x, credential.publicKey.y);
// ABI: abi.encode(uint256 x, uint256 y)

encodeECDSAKeyData(address)

Encode an EOA address for Kernel's ECDSAValidator.

import { encodeECDSAKeyData } from "@urblock/connect-core";

const keyData = encodeECDSAKeyData("0xEOAAddress...");
// ABI: abi.encodePacked(address)

computeSignerId(label)

Compute a stable signer ID from a human-readable label.

import { computeSignerId } from "@urblock/connect-core";

const id = computeSignerId("passkey-base64urlCredentialId");
// keccak256(toBytes(label))

computeSalt(userId, chainId)

Compute a deterministic CREATE2 salt.

import { computeSalt } from "@urblock/connect-core";

const salt = computeSalt("credentialId123", 11155111);
// keccak256(encodePacked(userId, chainId))

SIWE (Sign In With Ethereum — EIP-4361)

createSiweMessage(fields)

Build a compliant EIP-4361 message string.

import { createSiweMessage, generateSiweNonce, type SiweMessageFields } from "@urblock/connect-core";

const fields: SiweMessageFields = {
domain: "myapp.com",
address: "0xSmartAccount...",
uri: "https://myapp.com",
version: "1",
chainId: 11155111,
nonce: generateSiweNonce(),
issuedAt: new Date().toISOString(),
statement: "Sign in to My App",
};

const message = createSiweMessage(fields);

parseSiweMessage(message)

Parse a SIWE message string back into typed fields.

import { parseSiweMessage } from "@urblock/connect-core";

const fields = parseSiweMessage(message);

verifySiweSignature(params)

Verify a SIWE signature. Checks address, domain, chain ID, and expiration.

import { verifySiweSignature } from "@urblock/connect-core";

const fields = await verifySiweSignature({
message,
signature: "0x...",
expectedAddress: "0xSmartAccount...",
expectedDomain: "myapp.com",
expectedChainId: 11155111,
});

generateSiweNonce(length?)

Generate a cryptographically random alphanumeric nonce (default: 16 chars).


EIP-712

getKernelDomain(chainId, accountAddress)

Get the EIP-712 domain for a Kernel v3.1 smart account.

import { getKernelDomain } from "@urblock/connect-core";

const domain = getKernelDomain(11155111, "0xSmartAccount...");
// { name: "Kernel", version: "0.3.1", chainId, verifyingContract }

Recovery Encoding

encodeDoRecovery(params)

Encode calldata for RecoveryAction.doRecovery(validator, newKeyData).

import { encodeDoRecovery } from "@urblock/connect-core";

const callData = encodeDoRecovery({
validatorAddress: "0xWebAuthnValidator...",
newOwnerKeyData: "0xABI-encoded-new-key...",
});

encodeInstallRecoveryAction()

Encode initData for installing the RecoveryAction as a fallback module (type 3).

import { encodeInstallRecoveryAction } from "@urblock/connect-core";

const initData = encodeInstallRecoveryAction();
// selector 0xac39fd0f + no-hook sentinel + delegatecall calltype 0xff

Balance Utilities

getBalance(params)

Fetch native + ERC-20 balances for any address via JSON-RPC.

import { getBalance } from "@urblock/connect-core";

const result = await getBalance({
address: "0xSmartAccount...",
rpcUrl: "https://rpc.sepolia.org",
nativeSymbol: "ETH",
tokenAddresses: ["0xUSDC...", "0xDAI..."],
});

console.log(result.native.formatted); // "1.5"
console.log(result.native.symbol); // "ETH"
result.tokens.forEach((t) => {
console.log(`${t.formatted} ${t.symbol}`);
});

Returns: BalanceResult{ native: NativeBalance, tokens: TokenBalance[] }


ERC-1271 On-Chain Verification

verifySignatureOnChain(params)

Verify a signature on-chain via the smart account's isValidSignature(bytes32, bytes) method (ERC-1271).

import { verifySignatureOnChain, ERC1271_MAGIC_VALUE } from "@urblock/connect-core";

const result = await verifySignatureOnChain({
accountAddress: "0xSmartAccount...",
hash: "0xmessageHash...",
signature: "0xsignature...",
rpcUrl: "https://rpc.sepolia.org",
});

console.log(result.valid); // true if returnValue === 0x1626ba7e

OAuth Browser Helpers

Utilities for loading Google Identity Services and Apple Sign In JS.

renderGoogleIdentityButton(params)

Load the Google GSI script and render a sign-in button.

import { renderGoogleIdentityButton } from "@urblock/connect-core";

await renderGoogleIdentityButton({
clientId: "YOUR_GOOGLE_CLIENT_ID",
element: document.getElementById("google-btn")!,
callback: (response) => {
// response.credential = Google id_token
loginWithOAuth("google", response.credential!);
},
options: { theme: "outline", size: "large" },
});

initializeAppleSignIn(params)

Load and configure Apple Sign In JS.

import { initializeAppleSignIn } from "@urblock/connect-core";

const appleAuth = await initializeAppleSignIn({
clientId: "com.myapp.auth",
redirectURI: "https://myapp.com/callback",
scope: "name email",
usePopup: true,
});

const result = await appleAuth.signIn();
// result.authorization?.id_token = Apple id_token

Constants

ConstantValueDescription
ENTRY_POINT_V07"0x0000000071727De22E5E9d8BAf0edAc6f37da032"ERC-4337 v0.7 EntryPoint
ERC1271_MAGIC_VALUE"0x1626ba7e"Valid signature return value
DEFAULT_PASSKEY_STORAGE_KEY"urblock:passkey"localStorage key
RECOVERY_ACTION_ABIABIdoRecovery(address, bytes)
KERNEL_IS_MODULE_INSTALLED_ABIABIisModuleInstalled(uint256, address, bytes)

Enums

SignerType

enum SignerType {
ECDSA = 0,
P256 = 1,
}

ValidatorType

enum ValidatorType {
ECDSA = 0x01,
WebAuthn = 0x02,
}

Types Reference

TypeDescription
PackedUserOperationERC-4337 v0.7 UserOp (9 fields)
Call{ target, value?, data? }
WebAuthnCredentialPasskey credential with P-256 public key
StoredPasskeyCredentialPersisted passkey (no clientDataJSON)
WebAuthnAssertionAssertion result with DER-parsed r, s
SiweMessageFieldsEIP-4361 structured fields
SignerInfoSigner identity for smart accounts
SessionKeyConfigSession key parameters
RecoveryConfigRecovery guardian configuration
BalanceResult{ native, tokens[] } result
NativeBalance{ raw, formatted, symbol, decimals }
TokenBalance{ address, raw, formatted, symbol, decimals }
KernelDomainEIP-712 domain for Kernel v3.1
DoRecoveryParams{ validatorAddress, newOwnerKeyData }
UserOpBuilderParamsFull UserOp construction params
GetNonceParams{ rpcUrl, sender, key?, entryPoint? }
GetBalanceParams{ address, rpcUrl, nativeSymbol?, tokenAddresses? }
VerifySignatureOnChainParams{ accountAddress, hash, signature, rpcUrl }
CreateAccountParams{ ownerKeyData, validatorType, salt }