Framework-agnostic core SDK for embarkAI smart accounts — Account Abstraction (ERC-4337) with MPC (TSS) wallet infrastructure.
📖 Full documentation: docs.embarkai.io/core-sdk
- Zero React dependencies — works in Node.js, browsers and edge runtimes
- Server wallets — create and operate backend MPC wallets with a project API key
- Account Abstraction — ERC-4337 (EntryPoint v0.7) UserOperations, batches, parallel nonces, sponsored gas
- Policy-checked signing — TSS recomputes what is signed and enforces the wallet policies set in the Dashboard
- Keyshare backup — encrypted backup to and restore from the embarkAI Share Vault
- Auth — JWT session management for clients, JWKS token validation for backends
- Blockchain read layer — cached viem public client with RPC fallback, multicall batching and log pagination
- Contract encoding helpers — ERC20, ERC721, ERC1155 and arbitrary ABI calls
- Multi-chain — chain parameters are resolved from
chainIdfor every supported network
npm install @embarkai/core viem
# server wallets (DKG and signing) also need the TSS WASM module
npm install dkls23-wasmviem ≥ 2.10 is a peer dependency. dkls23-wasm is an optional peer dependency: it is loaded on first use, and server wallet calls throw if it is not installed.
Get a project API key from the embarkAI Dashboard.
import { createServerWalletManager, MemoryKeyshareStorage } from '@embarkai/core'
const manager = createServerWalletManager({
apiKey: process.env.EMBARK_API_KEY!,
storage: new MemoryKeyshareStorage(), // dev only — use FileKeyshareStorage or your own storage in production
chainId: 2030232745 // Lumia Beam Testnet
})
// Create a wallet (runs DKG with TSS)
const wallet = await manager.createWallet('treasury_main')
console.log('Owner (EOA):', wallet.ownerAddress)
console.log('Smart Account:', wallet.smartAccountAddress)
// Send a UserOperation
const userOpHash = await wallet.sendUserOperation(
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e', // to
'1000000000000000000', // value in wei
'0x', // calldata
'standard' // 'economy' | 'standard' | 'fast'
)
const receipt = await wallet.waitForUserOperationReceipt(userOpHash)
console.log('Tx hash:', receipt.transactionHash, receipt.success)Bundler, RPC, factory, EntryPoint and paymaster are resolved from chainId. Pass bundlerUrl, rpcUrl, factoryAddress, entryPointAddress, paymasterAddress or tssUrl to override them.
| Manager method | Description |
|---|---|
createWallet(id) / getWallet(id) / listWallets() |
Create (DKG) or load wallets |
walletExists(id) / hasKeyshare(id) |
Check the wallet on TSS and the keyshare in local storage |
checkBackupExists(id) / backupToVault(id, password) / restoreFromVault(id, password) |
Share Vault backup and restore |
waitForUserOperationReceipt(hash, { pollIntervalMs, maxPollTimeMs }) |
Poll for a receipt |
ServerWallet method |
Description |
|---|---|
sendUserOperation(to, value, data?, feeType?, nonceKey?) |
Sign and submit a single call; pass a nonceKey to send in parallel |
sendBatchUserOperation([{ to, value, data }], feeType?) |
Atomic multi-call UserOperation |
signMessage(message) |
EIP-191 signature by the owner key |
signTypedData({ domain, types, primaryType, message }) |
EIP-712 signature by the owner key |
signUserOperation({ userOp, userOpHash }) |
Sign a UserOperation without submitting it |
getUserOperationReceipt(hash) / waitForUserOperationReceipt(hash, opts?) |
Receipt lookup and polling |
signMessage and signTypedData produce an owner-key signature; a contract accepts it only if it verifies smart-account signatures (ERC-1271). signDigest with a bare hash is deprecated: TSS accepts it only during the migration and only for wallets without policies.
| Storage | Use |
|---|---|
MemoryKeyshareStorage |
Development only — keyshares are lost on restart |
FileKeyshareStorage from @embarkai/core/clients/node |
AES-encrypted files, Node.js only |
Your own ServerKeyshareStorage |
set, get, has, list (sync or async) over KMS, Vault, a database… |
import { FileKeyshareStorage } from '@embarkai/core/clients/node'
const storage = new FileKeyshareStorage({
storageDir: './data/keyshares',
encryptionPassword: process.env.EMBARK_KEYSHARE_ENCRYPTION_PASSWORD!
})
await storage.init()A lost keyshare cannot be recovered without a backup. Never delete keyshares, and back them up with
backupToVault. → Vault & Key Backup
Every signing request is checked in TSS against the wallet policies configured in the Dashboard. A rejected request throws a typed error before any signing round starts:
import { PolicyViolationError, PolicyUnavailableError, TssRequestError, WalletRevokedError } from '@embarkai/core'
try {
await wallet.sendUserOperation(to, value, data, 'standard')
} catch (error) {
if (error instanceof PolicyViolationError) {
console.log('blocked by policy', error.policyId, error.rule, error.reason)
} else if (error instanceof PolicyUnavailableError) {
console.log('policies could not be read, retry later', error.retryable)
} else if (error instanceof WalletRevokedError) {
console.log('this wallet was revoked in the Dashboard')
} else if (error instanceof TssRequestError) {
console.log(error.status, error.tssCode, error.response?.url) // response snapshot, no request headers
} else {
throw error
}
}Other classes: DigestMismatchError, MissingOperationError; codes in TssErrorCodes.
All helpers are async and return calldata for sendUserOperation:
import { encodeERC20Transfer } from '@embarkai/core'
const data = await encodeERC20Transfer('0xRecipient...', 1000n * 10n ** 18n)
await wallet.sendUserOperation('0xTokenContract...', '0', data, 'standard')encodeContractCall(abi, fn, args), encodeERC20Transfer / Approve / TransferFrom, encodeERC721TransferFrom / SafeTransferFrom / Approve / SetApprovalForAll, encodeERC1155SafeTransferFrom / SafeBatchTransferFrom / SetApprovalForAll, plus ERC20_ABI, ERC721_ABI, ERC1155_ABI.
import { getPublicClient } from '@embarkai/core/read'
import { erc20Abi } from 'viem'
const client = getPublicClient({ chainId: 994873017 })
const balance = await client.readContract({
address: '0xToken...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0xUser...']
})LRU cache (12 s TTL), automatic RPC fallback, multicall batching, paginated getLogs, getTransactionReceipt and waitForTransactionReceipt. Chain helpers: getChainConfig, isChainSupported, getViemChain.
For services that build UserOperations themselves: sendUserOperationRaw(userOp, { chainId }), sendUserOperationWithRetry, getUserOperationReceipt(hash, bundlerUrl), estimateUserOperationGas, createFeeChainContext(chainId), fee helpers (getFeeEstimates, calculateDynamicFees, …) and packUserOperationV07.
Clients — jwtTokenManager keeps the session tokens; ensureFreshSession(), getValidTokens(), fetchWithSession(url, init) (refreshes before the request, retries once on 401), logout() and jwtTokenManager.subscribe(listener) (called when a session starts or ends). In React apps @embarkai/ui-kit configures this for you. → Client Authentication
Backends — validate access tokens against the embarkAI JWKS:
import { EmbarkAIAuthService } from '@embarkai/core/auth/node'
const auth = new EmbarkAIAuthService({ projectId: 'your-project-id' }) // projectId is optional
const result = await auth.verifyToken(token)
if (!result.valid) throw new Error(result.error) // 'expired' | 'wrong_project' | …
console.log(result.user?.userId)With projectId, tokens issued for another project and anything but access tokens are rejected. → Backend Auth Tokens Validation
| Path | Contents |
|---|---|
@embarkai/core |
Everything below except Node-only modules |
@embarkai/core/read |
Public client, chain config helpers |
@embarkai/core/bundler |
UserOperation submission, gas and fee helpers |
@embarkai/core/clients |
ServerWalletManager, ServerWalletClient, TSS errors, Blockscout client |
@embarkai/core/clients/node |
FileKeyshareStorage (Node.js) |
@embarkai/core/auth |
JWT session management |
@embarkai/core/auth/node |
EmbarkAIAuthService (Node.js) |
@embarkai/core/utils |
Contract encoding, ABIs |
| Network | Chain ID | Type |
|---|---|---|
| Lumia Prism | 994873017 | Mainnet (default) |
| BNB Smart Chain | 56 | Mainnet |
| Lumia Beam | 2030232745 | Testnet |
| Lumia Pulsar | 1279885899 | Testnet |
| Ethereum Sepolia | 11155111 | Testnet |
| BSC Testnet | 97 | Testnet |
| Arbitrum Sepolia | 421614 | Testnet |
| Base Sepolia | 84532 | Testnet |
| Package | Description |
|---|---|
| @embarkai/ui-kit | React components and hooks |
| @embarkai/mcp | MCP server for AI agents |
- Documentation
- Changelog
- Issues — Bug reports and feature requests
- Discussions — Questions, ideas, and RFCs
MIT