No Seed Phrases.
No Gas Fees.

A Solana wallet powered by passkeys. Authenticate with biometrics, send transactions without gas fees, and swap tokens at the best prices.

Download APK View Source
$SEEDLESS Token
FYt532fCsCuoHd9aaX5QN7pZLUTiSXwEjhBmZijgBAGS

Features

Everything you need for a modern Solana wallet experience.

Passkey Authentication

No seed phrases to write down. Use FaceID, TouchID, or fingerprint to secure your wallet.

Gasless Transactions

Send SOL and tokens without holding any for fees. Kora paymaster sponsors all transactions.

Jupiter Swaps

Best-price token swaps via Jupiter aggregator. Completely gas-free.

Stealth Addresses

Receive payments privately with one-time addresses. Generate Solana Pay QR codes.

Burner Wallets

Disposable identities with zero on-chain link to your main wallet.

X402 Micropayments

Pay-per-view content with HTTP 402 standard. Instant crypto payments.

Documentation

Learn how to build with Seedless Wallet.

Creating a Passkey Wallet

Implement passkey-based wallet authentication using LazorKit SDK in React Native.

Prerequisites

  • Node.js 20+
  • Expo CLI
  • iOS Simulator or Android Emulator

Install Dependencies

npm install @lazorkit/wallet-mobile-adapter @coral-xyz/anchor @solana/web3.js
npm install react-native-get-random-values react-native-url-polyfill buffer
npx expo install expo-crypto expo-web-browser expo-linking

Configure Polyfills

Add polyfills at the top of your entry file:

// index.ts
import 'react-native-get-random-values';
import 'react-native-url-polyfill/auto';
import { Buffer } from 'buffer';
global.Buffer = global.Buffer || Buffer;

Create the Provider

import { LazorKitProvider } from '@lazorkit/wallet-mobile-adapter';

function LazorProvider({ children }) {
  return (
    <LazorKitProvider
      rpcUrl="https://api.devnet.solana.com"
      portalUrl="https://portal.lazor.sh"
      configPaymaster={{
        paymasterUrl: "https://kora.devnet.lazorkit.com",
      }}
    >
      {children}
    </LazorKitProvider>
  );
}

Connect with Passkey

import { useWallet } from '@lazorkit/wallet-mobile-adapter';
import * as Linking from 'expo-linking';

const { connect, isConnecting } = useWallet();

const handleConnect = async () => {
  const redirectUrl = Linking.createURL('callback');
  
  await connect({
    redirectUrl,
    onSuccess: () => console.log('Connected'),
    onFail: (error) => console.error(error),
  });
};

Gasless Transactions

Send SOL transfers without paying transaction fees. The Kora paymaster sponsors the fees.

How It Works

Traditional flow: User pays fee in SOL, then transaction executes.

Gasless flow: User creates transaction, paymaster pays fee, transaction executes.

Send Gasless Transfer

import { useWallet } from '@lazorkit/wallet-mobile-adapter';
import { PublicKey, SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
import * as Linking from 'expo-linking';

const { smartWalletPubkey, signAndSendTransaction } = useWallet();

const handleSend = async (recipient, amount) => {
  const recipientPubkey = new PublicKey(recipient);
  const lamports = parseFloat(amount) * LAMPORTS_PER_SOL;

  const transferInstruction = SystemProgram.transfer({
    fromPubkey: smartWalletPubkey,
    toPubkey: recipientPubkey,
    lamports,
  });

  const redirectUrl = Linking.createURL('sign-callback');

  const signature = await signAndSendTransaction(
    {
      instructions: [transferInstruction],
      transactionOptions: {
        clusterSimulation: 'mainnet',
        // feeToken omitted = gasless
      },
    },
    {
      redirectUrl,
      onSuccess: () => console.log('Sent'),
      onFail: (error) => console.error(error),
    }
  );
};

Pay Fees in USDC (Optional)

const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';

await signAndSendTransaction({
  instructions: [transferInstruction],
  transactionOptions: {
    clusterSimulation: 'mainnet',
    feeToken: USDC_MINT,  // User pays in USDC
  },
});

Jupiter Gasless Swaps

Integrate Jupiter swap aggregator with LazorKit's gasless infrastructure.

The Approach

Use Jupiter's /swap-instructions endpoint to get raw instructions, then pass them through LazorKit's gasless flow.

Get Quote

async function getQuote(inputMint, outputMint, amount) {
  const params = new URLSearchParams({
    inputMint,
    outputMint,
    amount,
    slippageBps: '100',
  });

  const response = await fetch(
    `https://api.jup.ag/swap/v1/quote?${params}`,
    { headers: { 'x-api-key': JUPITER_API_KEY } }
  );

  return response.json();
}

Filter Compute Budget Instructions

Critical for Kora compatibility. Remove Jupiter's compute budget instructions:

const COMPUTE_BUDGET_PROGRAM_ID = 'ComputeBudget111111111111111111111111111111';

function filterComputeBudget(instructions) {
  return instructions.filter(
    ix => !ix.programId.equals(new PublicKey(COMPUTE_BUDGET_PROGRAM_ID))
  );
}

Execute Swap

const { quote, instructions, addressLookupTableAccounts } = 
  await prepareSwap(SOL_MINT, USDC_MINT, amountInLamports, smartWalletPubkey);

await signAndSendTransaction({
  instructions,
  transactionOptions: {
    addressLookupTableAccounts,
    clusterSimulation: 'mainnet',
  },
});

Privacy Features

Implement stealth addresses and burner wallets for private transactions.

Stealth Addresses

Generate one-time receiving addresses derived from a master seed.

import * as SecureStore from 'expo-secure-store';
import * as Crypto from 'expo-crypto';
import { Keypair } from '@solana/web3.js';

async function generateStealthAddress(index) {
  const masterSeed = await getOrCreateMasterSeed();
  
  const input = Buffer.concat([
    Buffer.from(masterSeed, 'hex'),
    Buffer.from('stealth'),
    Buffer.from(index.toString()),
  ]);
  
  const hash = await Crypto.digest(
    Crypto.CryptoDigestAlgorithm.SHA256, 
    input
  );
  
  const keypair = Keypair.fromSeed(new Uint8Array(hash));
  return keypair.publicKey.toBase58();
}

Burner Wallets

Completely isolated identities with no on-chain link.

async function createBurner(label) {
  const keypair = Keypair.generate();
  const id = await generateBurnerId();

  // Store encrypted
  await SecureStore.setItemAsync(
    `burner_${id}`, 
    Buffer.from(keypair.secretKey).toString('base64')
  );

  return {
    id,
    label,
    publicKey: keypair.publicKey.toBase58(),
  };
}

async function destroyBurner(burnerId) {
  await SecureStore.deleteItemAsync(`burner_${burnerId}`);
}

X402 Paywall Integration

Implement pay-per-view content using HTTP 402 micropayments.

How X402 Works

  • Client requests protected resource
  • Server responds: 402 Payment Required
  • Client makes payment on Solana
  • Client retries with X-PAYMENT header
  • Server verifies payment, returns content

Parse Payment Requirements

function parsePaymentRequired(body) {
  if (body.payTo && body.maxAmountRequired) {
    return {
      scheme: body.scheme || 'exact',
      network: 'solana',
      maxAmountRequired: body.maxAmountRequired,
      payTo: body.payTo,
    };
  }
  return null;
}

Pay for Content

async function payForContent(requirements) {
  const paymentInstruction = SystemProgram.transfer({
    fromPubkey: smartWalletPubkey,
    toPubkey: new PublicKey(requirements.payTo),
    lamports: Math.ceil(
      parseFloat(requirements.maxAmountRequired) * LAMPORTS_PER_SOL
    ),
  });

  const signature = await signAndSendTransaction({
    instructions: [paymentInstruction],
    transactionOptions: { clusterSimulation: 'mainnet' },
  });

  return signature;
}

Retry with Proof

async function accessContent(url, signature) {
  const proof = {
    signature,
    network: 'solana',
    payload: {
      timestamp: Date.now(),
    },
  };

  const response = await fetch(url, {
    headers: {
      'X-PAYMENT': btoa(JSON.stringify(proof)),
    },
  });

  return response.json();
}

Tech Stack

React Native
Expo SDK 54
LazorKit SDK
Kora Paymaster
Jupiter Aggregator
Solana Web3.js
TypeScript
SPL Token

Get Started

Download the app or clone the source to build your own.

Download Android APK Clone on GitHub