NestJS library for Soroban contract interaction: transaction building, simulation, fee estimation, signing, and submission. The frontend and third-party integrators use this instead of calling Soroban directly.
Stack: NestJS, TypeScript, Stellar SDK. Published as @tikka/sdk.
Consumers: Frontend (client), third-party developers.
Compatibility: @tikka/sdk follows Semantic Versioning. Breaking changes are preceded by a documented deprecation window — see DEPRECATION.md.
Choose the full SDK when you need NestJS modules, dependency injection, wallet services, or the higher-level contract helpers that assume the framework runtime. Choose the light build when you need a browser-friendly entry point for low-level RPC access and lightweight types without the NestJS overhead.
| Build | Import path | Includes | Excludes | Measured size |
|---|---|---|---|---|
| Full | @tikka/sdk |
all runtime modules, wallet adapters, contract services, and CLI helpers | — | build output is available from the package entry point |
| Read-only | @tikka/sdk/read |
the read-oriented helpers and types used by the CLI and lightweight consumers | write/create helpers | currently measured at 219 bytes gzipped in the workspace build output |
| Light | @tikka/sdk/dist/light/index.light |
lightweight RPC client, raffle/network types, and shared helpers | NestJS modules, decorators, DI providers, and high-level services | currently measured at 183 bytes gzipped in the workspace build output |
The light bundle is intended for browser and mobile integrations where bundle size matters most. Services must be instantiated manually, and NestJS module wiring is not available in this entry point.
Every public entry point and its runtime compatibility. Use this table when choosing an import path or planning bundler polyfills.
| Module / entry | Browser | Node | Notes |
|---|---|---|---|
@tikka/sdk (full) |
✅ | ✅ | NestJS modules (RaffleModule, TicketModule, etc.) target server-side DI; instantiate service classes directly in browser apps. Bundler required (buffer, crypto, stream polyfills may be needed). |
@tikka/sdk/read |
✅ | ✅ | Recommended for dashboards and SSR. No wallet or signing code bundled. |
@tikka/sdk/write |
✅ | ✅ | Write path: wallet adapters, ContractService, TransactionLifecycle, domain write services. Re-exports @tikka/sdk/read. |
Light build (@tikka/sdk/dist/light/index.light) |
✅ | ✅ | Smallest bundle; manual instantiation only. No NestJS, wallet adapters, or CLI. |
RpcService |
✅ | ✅ | Uses fetch; pass fetchClient in React Native or custom environments. |
HorizonService |
✅ | ✅ | Same fetch-based pattern as RpcService. |
MockRpcService |
✅ | ✅ | In-memory mock for tests, Storybook, and offline dev. |
NetworkModule (NestJS) |
✅ | Requires NestJS runtime; use plain RpcService / HorizonService in browser. |
|
ContractService |
✅ | ✅ | Simulate/build/submit; signing delegated to a WalletAdapter. |
TransactionLifecycle |
✅ | ✅ | Four-phase invoke flow; needs a wallet adapter for the sign step. |
ReadOnlyRaffleService |
✅ | ✅ | Query-only; no wallet required. |
ReadOnlyUserService |
✅ | ✅ | Query-only; no wallet required. |
RaffleService (write) |
✅ | ✅ | Create/cancel need a browser wallet or MockWalletAdapter. Read methods work without signing. |
TicketService |
✅ | ✅ | Buy/refund need a wallet adapter; queries are simulate-only. |
UserService (write) |
✅ | ✅ | Participation queries are read-only; no wallet for reads. |
AdminService |
✅ | ✅ | Admin writes need a wallet; reads are simulate-only. |
RaffleModule / TicketModule / UserModule / AdminModule |
✅ | NestJS DI wrappers; prefer direct service classes in browser bundles. | |
FeeEstimatorService |
✅ | ✅ | RPC simulation only; no wallet or Node APIs. |
FeeEstimatorModule (NestJS) |
✅ | NestJS DI wrapper around FeeEstimatorService. |
|
buildChallenge / verifyResponse (SEP-10) |
✅ | Uses Node crypto.randomBytes; provide a crypto polyfill in browser or run server-side only. |
|
FreighterAdapter |
✅ | ❌ | Requires Freighter extension or @stellar/freighter-api. |
XBullAdapter |
✅ | ❌ | Requires xBull extension. |
AlbedoAdapter |
✅ | ❌ | Popup-based; requires @albedo-link/intent. |
LobstrAdapter |
✅ | ❌ | Requires LOBSTR extension. |
RabetAdapter |
✅ | ❌ | Requires Rabet extension (window.rabet). |
MockWalletAdapter |
✅ | ✅ | For tests, Storybook, and examples without a real wallet. |
Utils (errors, validation, formatting, retry, BigNumber) |
✅ | ✅ | Pure utilities; no environment-specific APIs. |
CLI (tikka / bin/tikka.cjs) |
❌ | ✅ | Node-only; uses commander, inquirer, and filesystem. |
Legend: ✅ supported ·
Common polyfills for browser bundlers (Vite, Webpack, esbuild): buffer, crypto (for SEP-10 and Stellar SDK), and stream when your toolchain requires them. React Native consumers should pass an explicit fetchClient to RpcService (see React Native Notes below).
- Customizable RpcService: Support for custom fetch clients, headers, and automatic failover across multiple nodes.
- Automatic RPC Retries: Built-in retry with exponential backoff for transient 429/5xx/timeout errors, with per-call opt-out.
- Contract Interaction: Type-safe transaction building and simulation for Soroban contracts.
- Wallet Integration: Unified
WalletAdapterinterface supporting Freighter, xBull, and Albedo. - Local Mocking Utilities:
MockWalletAdapterandMockRpcServicefor Storybook, UI tests, and offline development. - Modular Design: Domain-specific modules for Raffles, Tickets, and Users.
Consumers that only need to query raffle data (public dashboards, SSR pages, analytics) can import from the read-only sub-path. This avoids bundling wallet adapters and signing code, producing a significantly smaller bundle.
import { ReadOnlyRaffleService, ReadOnlyUserService, RpcService, resolveNetworkConfig } from '@tikka/sdk/read';
const networkConfig = resolveNetworkConfig('mainnet');
const rpcService = new RpcService(networkConfig);
const raffleService = new ReadOnlyRaffleService(rpcService, networkConfig);
const userService = new ReadOnlyUserService(rpcService, networkConfig);
// List all raffle IDs
const { value: allIds } = await raffleService.getAll();
// Fetch a single raffle
const { value: raffle } = await raffleService.getById(42);
// User participation profile
const { value: profile } = await userService.getProfile('GBIQ4VH3...');
// User raffle ID history
const { value: history } = await userService.getHistory('GBIQ4VH3...');| Export | Description |
|---|---|
ReadOnlyRaffleService |
getAll() — all raffle IDs; getById(id) — single raffle data |
ReadOnlyUserService |
getProfile(addr) — participation stats; getHistory(addr) — raffle IDs |
RpcService |
Soroban RPC client (simulate, getLedger) |
HorizonService |
Horizon account/fee queries |
resolveNetworkConfig, NetworkConfig |
Network configuration helpers |
ContractFn, RaffleStatus |
Contract constants |
ContractResponse |
Shared response envelope type |
| Read-only types | RaffleData, UserParticipation, AssetDescriptor, etc. |
| Utils | Formatting, validation, errors, retry, BigNumber |
The read-only bundle intentionally excludes all signing-related code:
ContractService(requires wallet + TransactionBuilder)TransactionLifecycle(requires wallet + signing)- All wallet adapters (Freighter, xBull, Albedo, LOBSTR, Rabet)
FeeEstimatorServicesep10auth helpers- Write-side service classes (
RaffleService,TicketService) - NestJS modules
cd sdk
pnpm run build:read # outputs to dist/read/The SDK keeps browser-facing entry points small. Contributors whose PRs grow these bundles should know the limit and how to remediate before merging.
Budgets are defined in sdk/package.json under the "size-limit" key. Sizes are
minified + gzipped, with NestJS / Stellar / RxJS peer-style dependencies
ignored so the check measures first-party SDK code (what consumers pay for on
top of deps they already ship).
| Entry | Build output | Budget | Typical size (approx.) |
|---|---|---|---|
@tikka/sdk/read |
dist/read/index.read.js |
50 kB gzip | ~7 kB |
Light SDK (index.light) |
dist/light/index.light.js |
25 kB gzip | ~3 kB |
The light entry also has a historical soft target of < 50 kB gzip documented in
LIGHT_VERSION.md; the 25 kB limit above is the
enforced budget based on current measured size with headroom for growth.
The full NestJS entry (@tikka/sdk) is not size-gated — prefer @tikka/sdk/read
or the light entry for browser/mobile consumers.
cd sdk
pnpm install
# Build the entries under test (required before size-check)
pnpm run build:read
pnpm run build:light
# Enforced budgets (fails the process if over limit)
pnpm run size-check
# Legacy helper: prints the raw byte length of dist/light/index.light.js only
# (no budget assertion — useful for a quick local sanity check on Windows)
pnpm run size-check:legacyCI currently runs SDK lint/test/build/docs; run size-check locally (or in a
PR follow-up job) whenever you change SDK public exports, network/RPC code, or
anything imported by the read/light entry points.
- Confirm you rebuilt:
pnpm run build:readand/orpnpm run build:light. - Re-run
pnpm run size-checkand note which entry exceeded its budget. - Audit imports on the failing entry:
- Prefer
@tikka/sdk/reador the light entry over the full@tikka/sdkbarrel. - Do not pull wallet adapters, signing, SEP-10, fee estimation, or NestJS modules into the read/light graphs.
- Avoid new heavy dependencies in files reachable from
index.read.ts/index.light.ts.
- Prefer
- Split write-only helpers behind the main or
./writeentry so tree-shaking can drop them from read/light consumers. - If the growth is intentional and justified, update the matching
"limit"inpackage.json"size-limit"in the same PR and explain why in the PR body.
Edit the "size-limit" array in sdk/package.json, keep "gzip": true, and
leave peer-style packages in "ignore" unless you intentionally want them
counted. After changing a limit, run the build + size-check commands above and
document the rationale in the PR.
src/network/— Customizable Soroban RPC and Horizon services.src/contract/— Core transaction logic and Soroban bindings.src/wallet/— Multi-wallet adapter system.src/modules/— Feature modules (Raffle, Ticket, User).src/utils/— Shared utilities for formatting, validation, and error handling.bin/tikka.cjs— Developer CLI for network testing and contract interaction.
The Tikka SDK includes a command-line interface for smoke testing, network configuration, and contract interaction.
After building the SDK:
npm run build
npm run cli -- --help-n, --network <type>— Target network:testnet(default) ormainnet-j, --json— Output results in JSON format (useful for scripting)--help— Show help for a command--version— Show CLI version
These commands don't require wallet signing and are safe for smoke testing:
Verify CLI configuration and SDK initialization.
tikka config-check # Check on testnet
tikka -n mainnet config-check # Check on mainnet
tikka config-check --json # Output as JSONGet estimated fees for a transaction.
tikka fee-quote CONTRACT_ABC123
tikka fee-quote CONTRACT_ABC123 --function transfer
tikka fee-quote CONTRACT_ABC123 --json
tikka -n mainnet fee-quote CONTRACT_ABC123Read contract data or state.
tikka read CONTRACT_ABC123
tikka read CONTRACT_ABC123 --key account_balance
tikka read CONTRACT_ABC123 --json
tikka -n mainnet read CONTRACT_ABC123List active raffles on the network.
tikka list # List on testnet
tikka list --limit 20 # Limit results
tikka list --json # Output as JSON
tikka -n mainnet list # List on mainnetGet contract status and network information.
tikka info # Get info on testnet
tikka info --json # Output as JSON
tikka -n mainnet info # Get info on mainnetThese commands require wallet integration for signing transactions:
Create a new raffle (interactive).
tikka create # Guided setup on testnet
tikka -n mainnet create # Guided setup on mainnetPurchase raffle tickets (interactive).
tikka buy # Purchase on testnet
tikka -n mainnet buy # Purchase on mainnet# Smoke test network configuration
cd sdk
npm run build
npm run cli -- config-check
# Get fee estimate for a contract (testnet)
npm run cli -- fee-quote CBVG2R3YLEDVGIQKHY6K2HGX55CPJMK5QX2YQE7WALLVIQG5IHVIGISQ
# Query contract state on mainnet
npm run cli -- -n mainnet read CBVG2R3YLEDVGIQKHY6K2HGX55CPJMK5QX2YQE7WALLVIQG5IHVIGISQ --json
# List raffles as JSON for automation
npm run cli -- list --json > raffles.json
# Get help for a specific command
npm run cli -- fee-quote --helpAll commands support the --json flag for machine-readable output:
# Output as JSON
$ tikka config-check --json
{
"version": "0.1.0",
"network": "testnet",
"rpcAvailable": true,
"contractAvailable": true,
"status": "OK"
}
# Errors also format as JSON
$ tikka fee-quote INVALID --json
{
"error": "Invalid contract ID"
}The CLI provides safe error messages that don't leak sensitive information:
- Read-only commands fail gracefully with helpful error messages
- Interactive commands confirm before executing wallet operations
- JSON output includes error details in structured format
- Invalid commands suggest the help flag for usage information
Full TypeDoc reference is auto-generated and hosted on GitHub Pages: crackedstudio.github.io/tikka
To build locally:
npm run docs # generates sdk/docs/
npm run docs:watch # rebuilds on file changeThe SDK includes SEP-10 helpers for building and verifying Stellar web authentication challenges.
import { buildChallenge } from '@tikka/sdk';
import { Networks } from '@stellar/stellar-sdk';
const challengeXdr = buildChallenge({
serverSecret: process.env.SEP10_SERVER_SECRET!,
clientAccount: clientPublicKey,
anchorDomain: 'example.com',
webAuthDomain: 'auth.example.com',
timeout: 300,
networkPassphrase: Networks.TESTNET,
});
return { xdr: challengeXdr };import { Sep10VerificationError, Sep10VerificationErrorCode, verifyResponse } from '@tikka/sdk';
import { Networks } from '@stellar/stellar-sdk';
const verifiedClient = await verifyResponse({
signedChallenge: responseXdr,
serverAccount: serverPublicKey,
clientAccount: clientPublicKey,
anchorDomain: 'example.com',
networkPassphrase: Networks.TESTNET,
nonceValidator: async (nonceBase64) => {
const key = `sep10:nonce:${nonceBase64}`;
const added = await redis.set(key, '1', { NX: true, EX: 300 });
return added === 'OK';
},
});
console.log('Authenticated client:', verifiedClient);try {
await verifyResponse(...);
} catch (err) {
if (err instanceof Sep10VerificationError) {
if (err.code === Sep10VerificationErrorCode.ChallengeExpired) {
// prompt client to request a new challenge
}
}
throw err;
}The docs are organized by module: Raffle · Ticket · Wallet · User · Network · Utils.
All SDK errors extend TikkaSdkError and carry a stable code property for predictable handling:
| Code | Class | When thrown |
|---|---|---|
NetworkError |
NetworkError |
All RPC endpoints unreachable, no fetch implementation |
TIMEOUT |
RpcTimeoutError |
RPC request exceeded timeout |
RATE_LIMIT |
RateLimitError |
RPC node returned 429 |
UNAVAILABLE |
UnavailableError |
RPC node returned 502/503/504 |
INVALID_RESPONSE |
InvalidResponseError |
Malformed or unparseable RPC response |
TRANSACTION_REJECTED |
TransactionRejectedError |
Network explicitly rejected submitted transaction |
SUBMISSION_FAILED |
TikkaSdkError (generic) |
Transaction submission failed (fallback) |
SimulationFailed |
TikkaSdkError (generic) |
Transaction simulation failed |
CONTRACT_FAILURE |
ContractFailureError |
Contract execution returned an error |
CONTRACT_ERROR |
TikkaSdkError (generic) |
General contract error |
AUTH_ERROR |
AuthError |
Authentication / SEP-10 verification failure |
UNAUTHORIZED |
UnauthorizedError |
Caller lacks permission for admin-only operation |
INSUFFICIENT_FUNDS |
InsufficientFundsError |
Caller's balance is too low |
UserRejected |
TikkaSdkError (generic) |
User cancelled the wallet prompt |
WALLET_NOT_CONNECTED |
TikkaSdkError (generic) |
Wallet not connected |
WALLET_NOT_INSTALLED |
TikkaSdkError (generic) |
No wallet extension detected |
INVALID_PARAMS |
TikkaSdkError (generic) |
Invalid function parameters |
VALIDATION_ERROR |
TikkaSdkError (generic) |
Input validation failure |
RAFFLE_NOT_FOUND |
RaffleNotFoundError |
Raffle ID does not exist on-chain |
RAFFLE_ENDED |
RaffleEndedError |
Raffle is in DRAWING/FINALIZED/CANCELLED state |
RAFFLE_FULL |
RaffleFullError |
Raffle has sold its maximum tickets |
EXTERNAL_CONTRACT_ERROR |
TikkaSdkError (generic) |
Cross-contract call failed |
UNKNOWN |
TikkaSdkError (generic) |
Catch-all for unexpected errors |
try {
await contractService.buyTicket(raffleId, quantity);
} catch (err) {
if (err instanceof NetworkError) {
// All RPC endpoints are down
} else if (err instanceof TransactionRejectedError) {
// Network rejected the submission
} else if (err instanceof InsufficientFundsError) {
// Top up before retrying
} else if (err instanceof AuthError) {
// Re-authenticate
} else if (err instanceof TikkaSdkError) {
// Fallback: check err.code
switch (err.code) {
case TikkaSdkErrorCode.RateLimit:
case TikkaSdkErrorCode.Timeout:
// Retry with backoff
}
}
}Full ecosystem spec: ../docs/ARCHITECTURE.md (section 2 — tikka-sdk).
All runnable examples live in examples/. They use MockWalletAdapter so they compile and run without a browser wallet — swap it for FreighterAdapter or another adapter when you need real signing.
Setup:
cp examples/.env.example examples/.env
# fill in TIKKA_PUBLIC_KEY and any other vars you needType-check all examples (no network required):
npm run examples:checkEnd-to-end walkthrough: bootstrap → create raffle → buy tickets → read state.
| Env var | Required | Default | Description |
|---|---|---|---|
TIKKA_NETWORK |
no | testnet |
testnet | mainnet | standalone |
TIKKA_PUBLIC_KEY |
no | mock key | Stellar G… address |
TIKKA_NETWORK=testnet npx ts-node examples/quickstart.tsCreate a new raffle on-chain with configurable price, asset, and duration.
| Env var | Required | Default | Description |
|---|---|---|---|
TIKKA_NETWORK |
no | testnet |
Network |
TIKKA_PUBLIC_KEY |
yes | — | Signer address |
TIKKA_TICKET_PRICE |
no | 1 |
Amount per ticket |
TIKKA_ASSET_CODE |
no | XLM |
Asset code |
TIKKA_ASSET_ISSUER |
no | "" |
Issuer for non-native assets |
TIKKA_MAX_TICKETS |
no | 50 |
Max tickets available |
TIKKA_DURATION_HOURS |
no | 24 |
Hours until raffle closes |
TIKKA_METADATA_CID |
no | "" |
IPFS CID for metadata |
TIKKA_PUBLIC_KEY=G... npx ts-node examples/create-raffle.ts
# USDC example:
TIKKA_ASSET_CODE=USDC TIKKA_ASSET_ISSUER=GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN \
TIKKA_PUBLIC_KEY=G... npx ts-node examples/create-raffle.tsPurchase tickets for an existing raffle, with pre-flight status checks.
| Env var | Required | Default | Description |
|---|---|---|---|
TIKKA_NETWORK |
no | testnet |
Network |
TIKKA_PUBLIC_KEY |
yes | — | Buyer address |
TIKKA_RAFFLE_ID |
yes | — | Numeric raffle ID |
TIKKA_QUANTITY |
no | 1 |
Number of tickets |
TIKKA_PUBLIC_KEY=G... TIKKA_RAFFLE_ID=1 npx ts-node examples/buy-tickets.tsPoll Soroban contract events (RaffleCreated, TicketPurchased, RaffleFinalized) with optional raffle filter. Runs until Ctrl+C.
Network required — connects to the Soroban RPC to stream events.
| Env var | Required | Default | Description |
|---|---|---|---|
TIKKA_NETWORK |
no | testnet |
Network |
TIKKA_RAFFLE_ID |
no | all | Filter events for one raffle |
TIKKA_POLL_MS |
no | 5000 |
Polling interval (ms) |
TIKKA_CONTRACT_ID |
no | built-in | Override contract address |
TIKKA_NETWORK=testnet npx ts-node examples/listen-events.ts
# filter to raffle #1:
TIKKA_RAFFLE_ID=1 npx ts-node examples/listen-events.tsCold-wallet / air-gapped signing flow. Step 1 builds an unsigned XDR; Step 3 submits a pre-signed XDR. Useful for multisig and hardware wallets.
Network required — Step 1 calls
simulateTransaction; Step 3 submits to the network.
| Env var | Required | Default | Description |
|---|---|---|---|
TIKKA_NETWORK |
no | testnet |
Network |
TIKKA_PUBLIC_KEY |
yes | — | Source account address |
TIKKA_SIGNED_XDR |
no | — | Provide to skip to Step 3 (submit) |
# Step 1 — build unsigned XDR:
TIKKA_PUBLIC_KEY=G... npx ts-node examples/offline-signing.ts
# Step 3 — submit after signing offline:
TIKKA_PUBLIC_KEY=G... TIKKA_SIGNED_XDR=<xdr> npx ts-node examples/offline-signing.tsBrowser-wallet integration demos. These require a browser environment (Albedo opens a popup; Rabet needs the extension installed).
Browser + wallet required — not runnable via
ts-nodein a plain terminal.
Minimal custom WalletAdapter implementation (local keypair stand-in). Documents the integrator contract and compiles via npm run examples:check.
npm run example:custom-walletThe SDK provides a unified interface for multiple Stellar wallets. All adapters implement the same WalletAdapter interface with getPublicKey() and signTransaction(xdr) methods.
Implementing a custom wallet? See the full integrator contract — methods, expected errors, and signing flow — in
WALLET_ADAPTER.md, plus the runnableexamples/custom-wallet.ts.
| Wallet | Installation | Notes |
|---|---|---|
| Freighter | Browser extension | Most popular, requires extension |
| xBull | Browser extension / PWA | Mobile-friendly |
| Albedo | Web-based | No extension required, popup-based |
| LOBSTR | Browser extension | Large user base |
| Rabet | Browser extension | Lightweight, open-source |
| Custom | Your bridge / custody / HSM | Extend WalletAdapter — see docs above |
Albedo is a web-based wallet that doesn't require browser extensions. It opens a popup window for authentication and transaction signing, making it ideal for users who prefer not to install extensions.
Key Features:
- No browser extension required
- Works in any modern browser
- Popup-based authentication
- Supports message signing for SIWS (Sign In With Stellar)
- Network switching support
Installation:
npm install @albedo-link/intentBasic Usage:
import { AlbedoAdapter } from '@tikka/sdk';
import { Networks } from '@stellar/stellar-sdk';
// Create adapter with network configuration
const adapter = new AlbedoAdapter({
networkPassphrase: Networks.TESTNET
});
// Check availability (always true in browser)
if (adapter.isAvailable()) {
// Get public key (opens Albedo popup)
const publicKey = await adapter.getPublicKey();
console.log('User public key:', publicKey);
// Sign transaction (opens Albedo popup)
const { signedXdr } = await adapter.signTransaction(xdr, {
networkPassphrase: Networks.TESTNET
});
// Sign message for authentication
const signature = await adapter.signMessage('Sign in to MyApp');
}Advanced Usage:
// Specify which account should sign (for multi-account users)
const { signedXdr } = await adapter.signTransaction(xdr, {
networkPassphrase: Networks.TESTNET,
accountToSign: 'GBQW4KLMRXIMSDWBEWX4AWQKWYW7R3E7SFPSHTUDTFFT22NNUC6COL72'
});
// Get configured network
const network = await adapter.getNetwork();
console.log('Network:', network);Error Handling:
import { TikkaSdkError, TikkaSdkErrorCode } from '@tikka/sdk';
try {
const publicKey = await adapter.getPublicKey();
} catch (err) {
if (err instanceof TikkaSdkError) {
switch (err.code) {
case TikkaSdkErrorCode.UserRejected:
console.log('User cancelled the request');
break;
case TikkaSdkErrorCode.WalletNotInstalled:
console.log('@albedo-link/intent package not installed');
break;
default:
console.log('Unknown error:', err.message);
}
}
}Complete Example: See examples/albedo-wallet.ts for a full working example.
Rabet is a lightweight, open-source browser extension wallet for Stellar. It provides a simple and secure way to manage Stellar assets and interact with dApps.
Key Features:
- Lightweight browser extension
- Open-source and community-driven
- Simple and intuitive interface
- Supports transaction signing
- Network switching support
Installation:
Rabet doesn't require an npm package - it uses the global window.rabet object injected by the browser extension.
Basic Usage:
import { RabetAdapter } from '@tikka/sdk';
import { Networks } from '@stellar/stellar-sdk';
// Create adapter with network configuration
const adapter = new RabetAdapter({
networkPassphrase: Networks.TESTNET
});
// Check if Rabet extension is installed
if (adapter.isAvailable()) {
// Get public key (prompts user to connect)
const publicKey = await adapter.getPublicKey();
console.log('User public key:', publicKey);
// Sign transaction
const { signedXdr } = await adapter.signTransaction(xdr, {
networkPassphrase: Networks.TESTNET
});
}Advanced Usage:
// Use different network
const { signedXdr } = await adapter.signTransaction(xdr, {
networkPassphrase: Networks.PUBLIC
});
// Get configured network
const network = await adapter.getNetwork();
console.log('Network:', network);Error Handling:
import { TikkaSdkError, TikkaSdkErrorCode } from '@tikka/sdk';
try {
const publicKey = await adapter.getPublicKey();
} catch (err) {
if (err instanceof TikkaSdkError) {
switch (err.code) {
case TikkaSdkErrorCode.UserRejected:
console.log('User cancelled the request');
break;
case TikkaSdkErrorCode.WalletNotInstalled:
console.log('Rabet extension not installed. Get it at https://rabet.io');
break;
default:
console.log('Unknown error:', err.message);
}
}
}Important Notes:
- Rabet requires a network passphrase for transaction signing
- Message signing is not supported by Rabet
- Users must have the Rabet browser extension installed from rabet.io
import { FreighterAdapter, XBullAdapter, AlbedoAdapter, LobstrAdapter, RabetAdapter } from '@tikka/sdk';
// Create adapter instance
const adapter = new FreighterAdapter({
networkPassphrase: Networks.TESTNET
});
// Check availability
if (adapter.isAvailable()) {
// Get public key
const publicKey = await adapter.getPublicKey();
// Sign transaction
const { signedXdr } = await adapter.signTransaction(xdr, {
networkPassphrase: Networks.TESTNET
});
}Extend WalletAdapter to plug in hardware signers, custody APIs, or any other Stellar wallet:
import {
WalletAdapter,
WalletName,
SignTransactionResult,
WalletCapabilities,
TikkaSdkError,
TikkaSdkErrorCode,
} from '@tikka/sdk';
class MyWalletAdapter extends WalletAdapter {
readonly name = WalletName.Custom; // or any string id
isAvailable(): boolean {
return typeof (globalThis as any).myWallet !== 'undefined';
}
async getPublicKey(): Promise<string> {
if (!this.isAvailable()) {
throw new TikkaSdkError(
TikkaSdkErrorCode.WalletNotInstalled,
'MyWallet is not installed',
);
}
return (globalThis as any).myWallet.getPublicKey();
}
async signTransaction(
xdr: string,
opts?: { networkPassphrase?: string; accountToSign?: string },
): Promise<SignTransactionResult> {
const networkPassphrase =
opts?.networkPassphrase ?? this.options.networkPassphrase;
const signedXdr = await (globalThis as any).myWallet.signTx(xdr, {
networkPassphrase,
accountToSign: opts?.accountToSign,
});
return { signedXdr };
}
getCapabilities(): WalletCapabilities {
return {
supportsGetPublicKey: true,
supportsSignTransaction: true,
supportsSignMessage: false,
supportsGetNetwork: false,
};
}
}Full contract (methods, error codes, signing flow): WALLET_ADAPTER.md.
Runnable demo: examples/custom-wallet.ts (npm run example:custom-wallet).
You can select adapters by name or auto-detect available wallets:
const adapters = {
freighter: new FreighterAdapter(),
xbull: new XBullAdapter(),
albedo: new AlbedoAdapter(),
lobstr: new LobstrAdapter(),
};
// Check which are available
const availableAdapters = Object.entries(adapters)
.filter(([, adapter]) => adapter.isAvailable())
.map(([name]) => name);
// Auto-select first available
const selectedAdapter = availableAdapters[0] ? adapters[availableAdapters[0]] : null;- Provide a fetch implementation explicitly when needed:
new RpcService(networkConfig, { endpoint, fetchClient: fetch })
- Wallet adapters that rely on browser extension globals are not available in React Native; use app-native signing or the mock adapter for local prototyping.
- Ensure required polyfills are present in your RN app entrypoint (
buffer,crypto, andstreamwhen your environment requires them).