@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
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"
| Param | Type | Description |
|---|---|---|
rpId | string | Relying Party ID (your domain) |
rpName | string | Relying Party display name |
userId | string | Unique user identifier |
userName | string | Display name for the credential |
challenge | Uint8Array | (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 call →
EXEC_MODE_SINGLE+encodePacked(target, value, data) - Batch →
EXEC_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
| Constant | Value | Description |
|---|---|---|
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_ABI | ABI | doRecovery(address, bytes) |
KERNEL_IS_MODULE_INSTALLED_ABI | ABI | isModuleInstalled(uint256, address, bytes) |
Enums
SignerType
enum SignerType {
ECDSA = 0,
P256 = 1,
}
ValidatorType
enum ValidatorType {
ECDSA = 0x01,
WebAuthn = 0x02,
}
Types Reference
| Type | Description |
|---|---|
PackedUserOperation | ERC-4337 v0.7 UserOp (9 fields) |
Call | { target, value?, data? } |
WebAuthnCredential | Passkey credential with P-256 public key |
StoredPasskeyCredential | Persisted passkey (no clientDataJSON) |
WebAuthnAssertion | Assertion result with DER-parsed r, s |
SiweMessageFields | EIP-4361 structured fields |
SignerInfo | Signer identity for smart accounts |
SessionKeyConfig | Session key parameters |
RecoveryConfig | Recovery guardian configuration |
BalanceResult | { native, tokens[] } result |
NativeBalance | { raw, formatted, symbol, decimals } |
TokenBalance | { address, raw, formatted, symbol, decimals } |
KernelDomain | EIP-712 domain for Kernel v3.1 |
DoRecoveryParams | { validatorAddress, newOwnerKeyData } |
UserOpBuilderParams | Full UserOp construction params |
GetNonceParams | { rpcUrl, sender, key?, entryPoint? } |
GetBalanceParams | { address, rpcUrl, nativeSymbol?, tokenAddresses? } |
VerifySignatureOnChainParams | { accountAddress, hash, signature, rpcUrl } |
CreateAccountParams | { ownerKeyData, validatorType, salt } |