@keyban/sdk-base
Version:
Keyban Javascript SDK provides core functionalities for the MPC wallet solution, supporting web and Node.js apps with TypeScript, custom storage, and Ethereum blockchain integration.
427 lines (328 loc) • 11 kB
Markdown
# 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
```bash
npm install /sdk-base @keyban/types
```
## Quick Start
```typescript
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 `/types`
- **Custom Storage** - Flexible client share persistence
## Blockchain Support
| Feature | EVM (Ethereum, Polygon) | Starknet | Stellar |
|---------|------------------------|----------|---------|
| Native Transfers | ✅ ETH, POL | ✅ STRK | ✅ XLM |
| ERC-20 Tokens | ✅ | 🚧 | ✅ Soroban |
| NFTs (ERC-721/1155) | ✅ | 🚧 | 🚧 |
| Message Signing | ✅ Hex | ✅ String[] | ✅ Base64 |
| Fee Estimation | ✅ EIP-1559 | ✅ | ✅ Stroops |
| Networks | Anvil, Amoy | Devnet, Sepolia, Mainnet | Quickstart, Testnet, Mainnet |
## Core Operations
### Initialize Account
```typescript
const account = await client.initialize();
console.log({
address: account.address,
publicKey: account.publicKey,
accountId: account.accountId,
});
```
### Sign Message
```typescript
// 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
```typescript
// 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
```typescript
const txHash = await account.transferERC20({
contractAddress: "0xTokenContract",
to: "0xRecipient",
value: 1_000_000n, // 1 USDC (6 decimals)
});
```
### Transfer NFTs
```typescript
// 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
```typescript
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
```typescript
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
```typescript
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
```typescript
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.
```typescript
// 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.
```typescript
// 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
```typescript
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.
```typescript
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.
```typescript
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`:
```typescript
// 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
| Network | Fee Unit | Decimals | Example |
|---------|----------|----------|---------|
| EVM (Ethereum, Polygon) | gwei | 9 | 20 gwei = 20_000_000_000 wei |
| Starknet | FRI | 18 | 1 FRI = 1_000_000_000_000_000_000 |
| Stellar | stroop | 7 | 100 stroops = 0.00001 XLM |
### Native Currency
| Network | Symbol | Decimals |
|---------|--------|----------|
| Ethereum Anvil | ETH | 18 |
| Polygon Amoy | POL | 18 |
| Starknet | STRK | 18 |
| Stellar | XLM | 7 |
## Development
```bash
# 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
## Related Packages
- **[/types](https://docs.keyban.io/api/types/)** - Shared TypeScript types and Zod schemas
- **[/sdk-react](https://docs.keyban.io/api/sdk-react/)** - React hooks and components
- **[API Documentation](https://docs.keyban.io/api/sdk-base/)** - Full TypeDoc reference
## License
See the [main repository](https://github.com/keyban-io/dap) for license information.