@snekfun/sdk
v1.1.0
Published
Api client of splash protocol
Readme
SnekFun SDK
A comprehensive TypeScript SDK for interacting with the SnekFun trading platform on Cardano blockchain.
🚀 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 Support - Dark/light theme integration
- 📝 Full TypeScript - Complete type safety and IntelliSense support
📦 Installation
npm install @snekfun/sdkyarn add @snekfun/sdk🏁 Quick Start
Login & Basic Operations
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',
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.):
const account = await Account.login({
hosts: hostsConfig,
network: 'mainnet',
wallet: cardanoWallet,
theme: 'dark',
getTotp: async () => prompt('Enter 2FA code:') || '',
});
console.log('Full account access granted');2. Passkey Authentication
WebAuthn-based authentication for password-less login:
// 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',
credentialData: accounts[0],
});
}3. Session Restore
Restore previous session without re-authentication:
const account = await Account.restore({
hosts: hostsConfig,
network: 'mainnet',
wallet: cardanoWallet,
theme: 'dark',
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:
const account = await Account.mobileDeviceLogin({
hosts: hostsConfig,
network: 'mainnet',
wallet: 'mobile',
theme: 'dark',
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:
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:
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:
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:
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:
await account.logout();🛡️ Error Handling
The SDK provides comprehensive error handling with specific error types:
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 failuresAuthInProgressError- Authentication already in progressSessionExpiredError- User session has expiredTwoFAAttemptsExceededError- Too many failed 2FA attempts
Wallet & Operations:
UserDeclinedSignError- User cancelled signing operationWalletAccountError- Wallet account-related errorsWalletApiError- Wallet API communication errorsWalletEnablingError- Wallet enabling/connection errorsInvalidWalletNetworkError- Wallet connected to wrong network
General:
BackendError- Server-side errorsOperationError- General operation failuresStepOperationCancelledError- Multi-step operation cancelledMobileAuthError- 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
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
// Mainnet
const account = await Account.login({
network: 'mainnet',
// ... other params
});
// Preprod (Preview testnet)
const account = await Account.login({
network: 'preprod',
// ... other params
});🎨 Theming
// Dark theme
const account = await Account.login({
theme: 'dark',
// ... other params
});
// Light theme
const account = await Account.login({
theme: 'light',
// ... other params
});📱 Mobile Support
The SDK includes special support for mobile device authentication:
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
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:
yarn docs