npm package: @snekfun/sdk
Description: Api client of splash protocol
Latest version: 1.1.4

# SnekFun SDK

A comprehensive TypeScript SDK for interacting with the SnekFun trading platform on Cardano blockchain.

[![npm version](https://badge.fury.io/js/@snekfun/sdk.svg)](https://badge.fury.io/js/@snekfun/sdk)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.6+-blue.svg)](https://www.typescriptlang.org/)
[![License](https://img.shields.io/npm/l/@snekfun/sdk.svg)](https://github.com/snekfun/sdk/blob/main/LICENSE)

## 🚀 Features

- **🔐 Secure Wallet Integration** - Support for CIP-30 wallets and passkey authentication
- **📱 Cross-Platform** - Works in browsers and mobile environments
- **🔒 Advanced Security** - Iframe-based isolation, anomaly detection, and session management
- **💱 Trading Operations** - Complete trading workflow with multi-step validation
- **🔑 Key Management** - Secure seed container export and temporary key pair generation
- **📊 Account Management** - Profile, security settings, and wallet operations
- **🎨 Theme & Localization** - Dark/light theme and UI language support
- **📝 Full TypeScript** - Complete type safety and IntelliSense support

## 📦 Installation

```bash
npm install @snekfun/sdk
```

```bash
yarn add @snekfun/sdk
```

## 🏁 Quick Start

### Login & Basic Operations

```typescript
import { Account, AssetInfo } from '@snekfun/sdk';

const hostsConfig = {
  apiUrl: 'https://api.snekfun.com',
  walletUrl: 'https://wallet.snekfun.com',
  balanceUrl: 'https://balance.snekfun.com',
  uTxOMonitorUrl: 'https://utxo.snekfun.com',
  submitUrl: 'https://submit.snekfun.com',
  builderUrl: 'https://builder.snekfun.com',
  avatarUploadUrl: 'https://avatar.snekfun.com',
  ipfsUrl: 'https://ipfs.snekfun.com',
};

// Login with CIP-30 wallet
const account = await Account.login({
  hosts: hostsConfig,
  network: 'mainnet',
  wallet: cardanoWallet, // Your CIP-30 wallet instance
  theme: 'dark',
  language: 'en', // UI language for wallet components
  getTotp: async () => prompt('Enter 2FA code:') || '',
});

console.log('Login successful!');

// Get wallet balance
const balance = await account.wallet.getBalance();
console.log('ADA Balance:', balance.get(AssetInfo.ada)?.amount);

// Sign a transaction
const signedTx = await account.wallet.signTx('84a400818258...');
console.log('Transaction signed:', signedTx);

// Logout when done
await account.logout();
```

## 🔧 Core Components

### Authentication Methods

The SDK supports multiple authentication approaches depending on your use case:

#### 1. CIP-30 Wallet Login

Full account access with CIP-30 compatible wallet (Eternl, Vespr, Lace, etc.):

```typescript
const account = await Account.login({
  hosts: hostsConfig,
  network: 'mainnet',
  wallet: cardanoWallet,
  theme: 'dark',
  language: 'en',
  getTotp: async () => prompt('Enter 2FA code:') || '',
});

console.log('Full account access granted');
```

#### 2. Passkey Authentication

WebAuthn-based authentication for password-less login:

```typescript
// Check passkey support in browser
const isSupported = await Account.isPasskeySupported();

if (isSupported) {
  // Get available passkey credentials
  const accounts = await Account.getAvailableAccounts();

  // Login with stored passkey
  const account = await Account.passkeyLogin({
    hosts: hostsConfig,
    network: 'mainnet',
    wallet: cardanoWallet, // Still needs wallet for transactions
    theme: 'dark',
    language: 'en',
    credentialData: accounts[0],
  });
}
```

#### 3. Session Restore

Restore previous session without re-authentication:

```typescript
const account = await Account.restore({
  hosts: hostsConfig,
  network: 'mainnet',
  wallet: cardanoWallet,
  theme: 'dark',
  language: 'en',
  profile: savedProfile, // Optional: previously saved profile
  seedContainer: savedSeedContainer, // Optional: encrypted seed
  sessionContainer: savedSessionContainer, // Optional: session data
});
```

#### 4. Mobile Device Login

Authenticate mobile devices using QR code or pairing:

```typescript
const account = await Account.mobileDeviceLogin({
  hosts: hostsConfig,
  network: 'mainnet',
  wallet: 'mobile',
  theme: 'dark',
  language: 'en',
  loginSessionUUID: 'uuid-from-qr',
  secret: 'shared-secret',
  onAuthInit: (params) => {
    console.log('Mobile auth initialized');
  },
});
```

### Account Sections

After login, access specialized functionality through account sections:

#### Profile Management

Manage user profile, avatars, and metadata:

```typescript
const account = await Account.login(params);

// Get current profile
const profile = account.profile.snapshot();
console.log('Username:', profile.name);
console.log('Avatar:', profile.avatar);

// Subscribe to profile changes
const unsubscribe = account.profile.subscribe((newProfile) => {
  console.log('Profile updated:', newProfile);
});

// Edit profile
const logoFile = document.querySelector('input[type="file"]').files[0];
await account.profile.editProfile({
  username: 'new_username',
  bio: 'Updated biography',
  appConfig: {
    preferredCurrency: 'ada',
    slippage: '30',
  },
  logo: logoFile, // File from input
});

// Trigger profile update
await account.profile.updateProfile();

// Cleanup subscription
unsubscribe();
```

#### Security Management

Manage passkeys, 2FA, and security settings:

```typescript
const account = await Account.login(params);
const security = account.security;

// Check if passkey is supported
if (AccountSecurity.isPasskeySupported()) {
  // Enable passkey authentication
  await security.enablePasskey({ deviceName: 'My Authenticator' });
  console.log('Passkey enabled');

  // Check if passkey is currently enabled
  const passkeyEnabled = await security.isPasskeyEnabled();
  console.log('Passkey enabled:', passkeyEnabled);
}

// Enable two-factor authentication (2FA)
await security.enable2FA(async (initData) => {
  // Display QR code from initData.qr to user
  const totpCode = await getUserTotpCode(initData);

  return {
    getCode: async () => totpCode,
    onSuccess: () => console.log('2FA enabled successfully'),
    onAttemptError: (error) => console.log('Invalid code, retry'),
    onError: (error) => console.log('Setup failed'),
  };
});

// Reset 2FA if user lost access to authenticator
try {
  await security.reset2FA();
  console.log('2FA has been reset');
} catch (error) {
  console.error('2FA is not enabled or reset failed');
}

// Reset passkey for this device
await security.resetPasskey();
console.log('Passkey disabled on this device');

// Revoke all active sessions
await security.revokeAccess();
console.log('All sessions revoked, user logged out');
```

#### Wallet Operations

Execute trading operations, deposits, and withdrawals:

```typescript
const account = await Account.login(params);
const wallet = account.wallet;

// Get balance
const balance = await wallet.getBalance();
const adaAmount = balance.get(AssetInfo.ada)?.amount;
console.log('ADA Balance:', adaAmount);

// Get wallet information
const walletInfo = await wallet.getWalletInfo();
console.log('Wallet address:', walletInfo.address);

// Sign arbitrary data
const message = new TextEncoder().encode('Hello, Cardano!');
const signature = await wallet.signData(message);
console.log('Signature:', signature);

// Sign a transaction
const cbor = '84a400818258...'; // CBOR hex
const signedTx = await wallet.signTransaction(cbor);
console.log('Signed transaction:', signedTx);

// Sign and submit transaction in one call
const txHash = await wallet.signAndSubmitTransaction(cbor);
console.log('Transaction submitted:', txHash);

// Submit already signed transaction
const txHashOnly = await wallet.submitTransaction(cbor);
console.log('Transaction hash:', txHashOnly);

// Deposit operation (transfer to trading account)
const depositTx = await wallet.deposit({
  amount: '100000000', // Lovelace
  hooks: {
    onSuccess: ({ stage, result }) => {
      console.log('Deposit stage:', stage, result);
    },
    onError: ({ stage, error }) => {
      console.error('Deposit failed at', stage, error);
    },
  },
});
console.log('Deposit transaction hash:', depositTx.hash);

// Withdrawal operation (transfer from trading account)
const withdrawTx = await wallet.withdraw({
  amount: '50000000',
  hooks: {
    onSuccess: ({ stage, result }) => {
      console.log('Withdrawal stage:', stage);
    },
    onError: ({ stage, error }) => {
      console.error('Withdrawal failed at', stage);
    },
  },
});
console.log('Withdrawal transaction hash:', withdrawTx.hash);

// Trading operation
const tradeTx = await wallet.trade({
  side: 'BUY', // or 'SELL'
  assetId: 'asset_id_hex',
  amount: 100000000n,
  slippage: 0.05,
  hooks: {
    onSuccess: ({ stage, result }) => {
      console.log('Trade stage:', stage);
    },
    onError: ({ stage, error }) => {
      console.error('Trade failed at', stage);
    },
  },
});
console.log('Trade transaction hash:', tradeTx.hash);

// Launch new token
const logoFile = document.querySelector('input[type="file"]').files[0];
const launchTx = await wallet.launch({
  name: 'My Token',
  ticker: 'MYTKN',
  description: 'A great new token',
  assetType: 'FT', // or 'NFT'
  launchType: 'public', // or 'private'
  initialDeposit: { amount: BigInt('1000000') },
  logo: logoFile,
  twitter: 'https://twitter.com/mytoken',
  discord: 'https://discord.gg/mytoken',
  telegram: 'https://t.me/mytoken',
  website: 'https://mytoken.io',
  hooks: {
    onSuccess: ({ stage, result }) => {
      console.log('Token launch stage:', stage);
    },
    onError: ({ stage, error }) => {
      console.error('Token launch failed at', stage);
    },
  },
});
console.log('Token launch transaction hash:', launchTx.hash);
```

#### Funding Wallet _(CIP-30 only)_

Access funding wallet operations. **Available only on CIP-30 authenticated devices**:

```typescript
const account = await Account.login(params); // Must use CIP-30 wallet
const fundingWallet = account.fundingWallet;

// Get wallet address
const address = await fundingWallet.getAddress();
console.log('Funding wallet address:', address.payment.hash);

// Get comprehensive address information
const addressesInfo = await fundingWallet.getAddressesInfo();
console.log('Change address:', addressesInfo.changeAddress);
console.log('Public key hashes:', Array.from(addressesInfo.pkhs));

// Check balance
const balance = await fundingWallet.getBalance();
console.log('ADA Balance:', balance.get(AssetInfo.ada)?.amount);

// Get UTxOs for building transactions
const utxos = await fundingWallet.getUTxOs();
console.log('Available UTxOs:', utxos.length);

// Sign transaction
const cbor = '84a400818258...'; // CBOR hex
const signedCbor = await fundingWallet.signTx(cbor);
console.log('Signed transaction');

// Sign arbitrary data
const message = '48656c6c6f'; // Hex string
const signature = await fundingWallet.signData(message);
console.log('Signature:', signature.signature);

// Verify wallet consistency (useful for session restoration)
try {
  await fundingWallet.compareFundingWallet(savedWalletPkh);
  console.log('Current wallet matches saved wallet');
} catch (error) {
  console.log('Different wallet detected');
}
```

### Cleanup

Always logout when done to clean up sessions:

```typescript
await account.logout();
```

## 🛡️ Error Handling

The SDK provides comprehensive error handling with specific error types:

```typescript
import { SFError } from '@snekfun/sdk';

try {
  const account = await Account.login(params);
} catch (error) {
  if (SFError.AuthError.is(error)) {
    console.log('Authentication failed:', error.message);
  } else if (SFError.UserDeclinedSignError.is(error)) {
    console.log('User cancelled the operation');
  } else if (SFError.SessionExpiredError.is(error)) {
    console.log('Session expired, please login again');
  } else if (SFError.BackendError.is(error)) {
    console.log('Server error:', error.message);
  }
}
```

### Available Error Types

**Authentication & Session:**

- `AuthError` - Authentication failures
- `AuthInProgressError` - Authentication already in progress
- `SessionExpiredError` - User session has expired
- `TwoFAAttemptsExceededError` - Too many failed 2FA attempts

**Wallet & Operations:**

- `UserDeclinedSignError` - User cancelled signing operation
- `WalletAccountError` - Wallet account-related errors
- `WalletApiError` - Wallet API communication errors
- `WalletEnablingError` - Wallet enabling/connection errors
- `InvalidWalletNetworkError` - Wallet connected to wrong network

**General:**

- `BackendError` - Server-side errors
- `OperationError` - General operation failures
- `StepOperationCancelledError` - Multi-step operation cancelled
- `MobileAuthError` - Mobile authentication errors

## 🔐 Security Considerations

This SDK manages sensitive cryptographic operations and private key material. To ensure secure deployment:

- **Content Security Policy (CSP)**: Configure strict CSP policies to prevent XSS attacks
- **HTTPS Only**: Always use HTTPS in production
- **Iframe Isolation**: The SDK uses iframe-based wallet isolation for enhanced security
- **Session Management**: Sessions are automatically managed with expiration and anomaly detection
- **Key Storage**: Private keys are never exposed to the main application thread

For production deployments, ensure your application environment adheres to these security best practices.

## 🔧 Configuration

### Host Configuration

```typescript
const hostsConfig = {
  apiUrl: 'https://api.snekfun.com', // Wallet API URL
  walletUrl: 'https://wallet.snekfun.com', // Wallet web application URL
  balanceUrl: 'https://balance.snekfun.com',
  uTxOMonitorUrl: 'https://utxo.snekfun.com',
  submitUrl: 'https://submit.snekfun.com',
  builderUrl: 'https://builder.snekfun.com',
  avatarUploadUrl: 'https://avatar.snekfun.com',
  ipfsUrl: 'https://ipfs.snekfun.com',
};
```

### Network Support

```typescript
// Mainnet
const account = await Account.login({
  network: 'mainnet',
  language: 'en',
  // ... other params
});

// Preprod (Preview testnet)
const account = await Account.login({
  network: 'preprod',
  language: 'en',
  // ... other params
});
```

## 🎨 Theming & Localization

### Theme

```typescript
// Dark theme
const account = await Account.login({
  theme: 'dark',
  // ... other params
});

// Light theme
const account = await Account.login({
  theme: 'light',
  // ... other params
});
```

### Language

The `language` parameter controls the UI language of wallet components. It accepts any string value matching your application's locale (e.g. `'en'`, `'ja'`, `'es'`).

```typescript
import { Language } from '@snekfun/sdk';

// Set wallet UI language
const account = await Account.login({
  theme: 'dark',
  language: 'en', // UI language for wallet interface
  // ... other params
});
```

The `Language` type is exported from the SDK and can be used for type-safe language handling in your application:

```typescript
import type { Language } from '@snekfun/sdk';

function getPreferredLanguage(): Language {
  return navigator.language.split('-')[0]; // e.g. 'en', 'ja', 'es'
}

const account = await Account.login({
  theme: 'dark',
  language: getPreferredLanguage(),
  // ... other params
});
```

## 📱 Mobile Support

The SDK includes special support for mobile device authentication:

```typescript
const account = await Account.login(params);

// Initiate mobile device authentication
const { complete, cancel } = account.mobileAuth((event) => {
  if (event.state === 'pending') {
    // Display QR code from event.data.uuid and secret to mobile device
    displayQRCode(event.data.uuid, event.data.secret);
    console.log('QR code valid until:', event.data.validUntil);
  } else if (event.state === 'registered') {
    // Device registered, waiting for user confirmation
    console.log('Device registered, awaiting confirmation');
  } else if (event.state === 'completed') {
    // Authentication completed
    console.log('Mobile authentication completed');
  }
});

// Wait for mobile device to register
const completeAuth = await complete;

// User confirms authentication on mobile device
// Then complete the process
try {
  await completeAuth();
  console.log('Mobile authentication successful');
} catch (error) {
  console.error('Mobile authentication failed:', error);
}

// Or cancel the authentication flow
cancel();
```

## 🧪 Testing

```bash
cd packages/snekfun-sdk

# Run tests with yarn
yarn test

# Run tests with jest directly
jest
```

## 📚 API Documentation

Generate documentation locally from the monorepo root:

```bash
yarn docs
```