Skip to main content

Keyban JavaScript SDK

The official JavaScript SDK for Keyban's Wallet as a Service (WaaS). Integrate secure MPC wallets into your JavaScript or Node.js applications with support for multiple blockchains, NFTs, tokens, and advanced features like Digital Product Passports and loyalty programs.

Installation​

npm install @keyban/sdk-base @keyban/types

Quick Start​

import { KeybanClient, Network } from "@keyban/sdk-base";

// Initialize the client
const client = new KeybanClient({
appId: "your-app-id",
network: Network.BaseSepolia,
});

// Get an account
const account = await client.initialize();
console.log("Address:", account.address);

// Transfer native currency
const txHash = await account.transfer(
"0xRecipientAddress",
1_000_000_000_000_000_000n // 1 token in wei
);

Key Features​

  • Multi-Blockchain Support - EVM (Ethereum, Base) and Stellar
  • MPC Security - Non-custodial wallets with threshold signatures
  • NFT & Token Support - ERC-20, ERC-721, ERC-1155, Soroban tokens
  • Digital Product Passports - Claim and manage tokenized products
  • Loyalty Programs - Points, rewards, wallet pass integration
  • GraphQL API - Real-time subscriptions for balances and transfers
  • TypeScript-First - Full type safety with @keyban/types
  • Custom Storage - Flexible client share persistence

Blockchain Support​

FeatureEVM (Ethereum, Base)Stellar
Native Transfers✅ ETH✅ XLM
ERC-20 Tokens✅✅ Soroban
NFTs (ERC-721/1155)✅🚧
Message Signing✅ Hex✅ String[]
Fee Estimation✅ EIP-1559✅
NetworksAnvil, AmoyDevnet, Sepolia, Mainnet

Core Operations​

Initialize Account​

const account = await client.initialize();
console.log({
address: account.address,
publicKey: account.publicKey,
accountId: account.accountId,
});

Sign Message​

// EVM - returns hex string
const signature = await account.signMessage("Hello, Keyban!");

// Stellar - returns base64 string
const signature = await stellarAccount.signMessage("Hello, Keyban!");

Transfer Native Currency​

// Estimate fees first
const fees = await account.estimateTransfer("0xRecipient");
console.log("Estimated fees:", fees);

// Perform transfer
const txHash = await account.transfer(
"0xRecipient",
1_000_000_000_000_000_000n, // Amount in smallest unit (wei)
fees // Optional: use custom fees
);

Transfer ERC-20 Tokens​

const txHash = await account.transferERC20({
contractAddress: "0xTokenContract",
to: "0xRecipient",
value: 1_000_000n, // 1 USDC (6 decimals)
});

Transfer NFTs​

// ERC-721
await account.transferNft({
contractAddress: "0xNftContract",
to: "0xRecipient",
tokenId: "123",
standard: "ERC721",
});

// ERC-1155
await account.transferNft({
contractAddress: "0xNftContract",
to: "0xRecipient",
tokenId: "456",
standard: "ERC1155",
value: 5n, // Transfer 5 copies
});

GraphQL Queries​

The SDK provides pre-built GraphQL documents for querying blockchain data.

Query Token Balances​

import { walletTokenBalancesDocument } from "@keyban/sdk-base/graphql";

const { data } = await client.apolloClient.query({
query: walletTokenBalancesDocument,
variables: {
walletId: account.address,
first: 20,
},
});

console.log("Token balances:", data.wallet.tokenBalances.nodes);

Query NFTs​

import { walletNftsDocument } from "@keyban/sdk-base/graphql";

const { data } = await client.apolloClient.query({
query: walletNftsDocument,
variables: {
walletId: account.address,
first: 20,
},
});

console.log("NFTs:", data.wallet.nftBalances.nodes);

Real-Time Subscriptions​

import { tokenBalancesSubscriptionDocument } from "@keyban/sdk-base/graphql";

const subscription = client.apolloClient.subscribe({
query: tokenBalancesSubscriptionDocument,
variables: { walletId: account.address },
}).subscribe({
next: ({ data }) => {
console.log("Balance updated:", data.tokenBalances);
},
error: (err) => console.error("Subscription error:", err),
});

// Don't forget to unsubscribe when done
subscription.unsubscribe();

Query Transfer History​

import { walletAssetTransfersDocument } from "@keyban/sdk-base/graphql";

const { data } = await client.apolloClient.query({
query: walletAssetTransfersDocument,
variables: {
walletId: account.address,
first: 50,
},
});

console.log("Transaction history:", data.wallet.assetTransfers.nodes);

Digital Product Passports (DPP)​

Claim tokenized products using the DPP service.

// Claim a product with authentication
const result = await client.api.dpp.claim({
productId: "product-uuid",
password: "product-password",
});

// Magic claim (passwordless)
const result = await client.api.dpp.magicClaim({
productId: "product-uuid",
magicToken: "magic-token-uuid",
});

// Get product details
const product = await client.api.dpp.getProduct("product-uuid");
console.log("Product:", product.name, product.status);

Loyalty Programs​

Access loyalty points, rewards, and wallet passes.

// Get loyalty balance
const balance = await client.api.loyalty.getBalance();
console.log("Points:", balance.points);

// Get reward tiers
const tiers = await client.api.loyalty.getRewardTiers();
console.log("Available rewards:", tiers);

// Add to Apple/Google Wallet
const passUrl = await client.api.loyalty.addToWalletPass("google");
window.open(passUrl, "_blank");

Balance Formatting​

import { formatBalance } from "@keyban/sdk-base";

const balance = {
raw: 1_500_000_000_000_000_000n,
decimals: 18,
symbol: "ETH",
isNative: true,
};

const formatted = formatBalance(client, balance);
console.log(formatted); // "1.5 ETH"

Error Handling​

The SDK provides typed errors for precise error handling.

import { SdkError, SdkErrorCode } from "@keyban/sdk-base";

try {
await account.transfer(recipient, amount);
} catch (error) {
if (error instanceof SdkError) {
switch (error.code) {
case SdkErrorCode.InsufficientFunds:
console.error("Not enough balance");
break;
case SdkErrorCode.AddressInvalid:
console.error("Invalid recipient address");
break;
case SdkErrorCode.AmountInvalid:
console.error("Invalid amount");
break;
default:
console.error("SDK error:", error.message);
}
} else {
console.error("Unexpected error:", error);
}
}

Available Error Types​

SdkErrorCode:

  • AddressInvalid - Invalid blockchain address format
  • AmountInvalid - Invalid amount (zero, negative, or exceeds limits)
  • AmountRequired - Amount is required but not provided
  • AmountIrrelevant - Amount provided when not needed
  • RecipientAddressEqualsSender - Cannot send to yourself
  • EstimateGasExecution - Gas estimation failed
  • InsufficientFunds - Insufficient balance
  • InvalidNftStandard - Unsupported NFT standard
  • NftNotFound - NFT not found
  • TokenBalanceNotFound - Token balance not found
  • UnknownTransactionError - Unknown transaction error

Custom Client Share Provider​

Implement custom storage for MPC client shares.

import { ClientShareProvider } from "@keyban/sdk-base";

class MyClientShareProvider implements ClientShareProvider {
async get(key: string): Promise<string | null> {
// Retrieve from your backend
const response = await fetch(`/api/shares/${key}`, {
headers: { Authorization: `Bearer ${userToken}` },
});
return response.ok ? await response.text() : null;
}

async set(key: string, clientShare: string): Promise<void> {
// Store in your backend
await fetch("/api/shares", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${userToken}`,
},
body: JSON.stringify({ key, clientShare }),
});
}
}

// Use custom provider
const client = new KeybanClient({
appId: "your-app-id",
network: Network.BaseSepolia,
clientShareProvider: new MyClientShareProvider(),
});

Security Best Practices​

  • ✅ Protect storage endpoints with authentication
  • ✅ Use per-user keys (not shared keys)
  • ✅ Enable audit logging for access
  • ✅ Never expose client shares in logs or error messages
  • ✅ Consider encryption at rest
  • ✅ Implement key rotation if possible

Authentication & API Services​

The SDK provides access to additional services through client.api:

// Authentication
await client.api.auth.signUp({ email, password });
await client.api.auth.signIn({ email, password });
await client.api.auth.sendOtp({ email });

// Account info
const address = await client.api.account.getAddress();
const accountId = await client.api.account.getAccountId();

// Application info
const app = await client.api.application.getApplication();
console.log("App:", app.name, app.features);

// Signer operations (advanced)
await client.api.signerEcdsa.dkg();
const signature = await client.api.signerEcdsa.sign(message);

Network Configuration​

Fee Units​

NetworkFee UnitDecimalsExample
EVM (Ethereum, Base)gwei920 gwei = 20_000_000_000 wei
Stellarstroop7100 stroops = 0.00001 XLM

Native Currency​

NetworkSymbolDecimals
Ethereum AnvilETH18
Base SepoliaETH18
Base MainnetETH18
StellarXLM7

Development​

# Build the package
npm run build

# Type check
npm run typecheck

# Run tests
npm test

# Lint
npm run lint

Compatibility​

  • Node.js: 18+ recommended
  • Browsers: Modern browsers with ESM support
  • TypeScript: 5.0+ for best type inference
  • Bundlers: Vite, webpack, rollup supported

License​

See the main repository for license information.