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.PolygonAmoy,
});

// 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, Polygon), Starknet, 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, Polygon)StarknetStellar
Native Transfers✅ ETH, POL✅ STRK✅ XLM
ERC-20 Tokens🚧✅ Soroban
NFTs (ERC-721/1155)🚧🚧
Message Signing✅ Hex✅ String[]✅ Base64
Fee Estimation✅ EIP-1559✅ Stroops
NetworksAnvil, AmoyDevnet, Sepolia, MainnetQuickstart, Testnet, 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!");

// Starknet - returns string array
const signatures = await starknetAccount.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({
productSheetId: "sheet-uuid",
password: "product-password",
});

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

// Get product sheet details
const sheet = await client.api.dpp.getProductSheet("sheet-uuid");
console.log("Product:", sheet.name, sheet.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, SdkErrorTypes } from "@keyban/sdk-base";

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

Available Error Types

SdkErrorTypes:

  • 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
  • UnknownIframeApiError - Unknown API communication error

Other Error Classes:

  • CryptoError - Cryptographic operations (encrypt, decrypt, key import)
  • JwtError - Token parsing/validation
  • IFrameApiError - IFrame communication errors

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.PolygonAmoy,
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, Polygon)gwei920 gwei = 20_000_000_000 wei
StarknetFRI181 FRI = 1_000_000_000_000_000_000
Stellarstroop7100 stroops = 0.00001 XLM

Native Currency

NetworkSymbolDecimals
Ethereum AnvilETH18
Polygon AmoyPOL18
StarknetSTRK18
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.