Back

Frictionless and secure UX: the tech stack onboarding millions of users to Solana

A developer’s guide to using Privy and Helius for embedded wallets, gasless transactions, and frictionless onboarding.

Danny B. and Osker Lu

|

Jun 2, 2025

This article was originally published on the Helius blog.

Most consumer-facing crypto apps today rely on external wallets, forcing users to manage seed phrases, navigate multiple redirects, and manually approve every transaction. 

For the everyday user unfamiliar with blockchain, this is an impossible ask. Seed phrases, gas fees, and wallet pop-ups don’t just cause friction — they create drop-off. Meaning apps with great products lose users before they even get started.

Yet it doesn’t have to be this way. In this guide, you’ll learn how to build seamless onchain experiences for Solana using Privy and Helius, enabling gasless transactions, embedded wallets, and instant trading with <20ms latency. We’ll cover how to:

  • Provision self-custodial embedded wallets with simple logins (email, social, SMS), while also supporting external wallets like Phantom, Solflare, Backpack, and more – all from the Privy SDK

  • Enable gasless transactions by sponsoring fees via secure wallets

  • Integrate fiat onramps like MoonPay or Coinbase Pay into your UI

  • Bridge liquidity natively from other chains (EVM → Solana) without friction

  • Build on mobile with seamless onchain UX that feels like Web2

Let’s dive into what it takes to onboard the next millions of users through your Solana app.

Crypto Onboarding in Practice: DeFi and Consumer App Examples

Seamless onboarding isn’t just a nice-to-have; it’s a growth multiplier. Apps that leverage embedded wallets can see 40%+ month-over-month user retention, especially when targeting users new to crypto. 

For most consumers, crypto-native concepts like gas, slippage, priority fees, and tips are unfamiliar and overwhelming. 

To retain users, apps must make their onboarding approachable. That means making it possible for users to interact with stablecoins like USDC or to cover gas fees under the hood through sponsored transactions.

The goal is simple: let users sign, swap, and stake without needing to learn how crypto works.

Pump.fun — Token Launchpad

Pump.fun is one of the fastest-growing trading platforms on Solana, combining embedded wallets with gasless transactions to offer instant, one-tap trading with no pop-ups, approvals or wallet switching required.

Initially built for high-frequency traders, the Advanced experience proved so effective that it was rolled out to all users.

Today, anyone can launch a token and start trading on mobile in seconds. Some users have even transacted millions of dollars through Privy-powered wallets, all without leaving the app.

Jupiter — DEX Aggregator

Jupiter's Quick Account experience showcases how powerful seamless trading can be. Every user, whether signing in via Phantom, Solflare, Backpack, or even just email or X, interacts through Privy’s embedded wallet infrastructure under the hood.

This setup enables instant trades without requiring transaction signing, providing a frictionless and best-price execution path every time.

When users are ready, they can export their keys to external wallets, retaining complete control and avoiding vendor lock-in.

Moonwalk — Walk-to-Earn Mobile App

Moonwalk delivers a frictionless mobile onboarding experience by letting users sign up with email, social, or SMS, just like any other Web2 consumer app.

Behind the scenes, every signup automatically provisions a fully functional embedded wallet using Privy. Users don’t have to worry about seed phrases, wallet extensions, or any crypto-specific setup.

Instead, they just start walking and earning, without ever realizing they’re onchain.

Building Seamless Onchain UX: Native Account Funding

Creating embedded wallets behind the scenes is just the beginning. To truly deliver a seamless app experience, developers must also address account funding and cross-chain liquidity, two of the most common sources of user drop-off. 

Embedded Onramps

The best consumer apps remove friction at every step, including the moment a user needs to fund their wallet.

By embedding fiat on-ramps directly into the app experience, users can purchase SOL or USDC without ever leaving the interface.

Privy’s SDK makes it easy to integrate on-ramp providers like MoonPay and Coinbase Pay, enabling native purchases of Solana assets with just a few clicks.

Native Bridging

Another key unlock is native liquidity bridging. If a user’s Solana wallet is underfunded, developers can configure their Privy wallets to bridge balances from an EVM chain like Ethereum, Base, or Polygon. 

This turns your app into a liquidity sink, pulling assets from wherever your users already are and bringing them directly into your Solana experience. No switching apps. No copying wallet addresses. Just seamless, cross-chain value transfer.

Building Seamless Onchain UX: Setting up Gasless Transactions with Privy and Helius

Beyond account funding and cross-chain bridging, Privy's wallets offer secure key management and are purpose-built for fee payer setups compared to traditional keypairs.

1. Create a Managed Wallet

To set up gasless transactions for your users, you will need to provision a managed wallet that acts as the “fee payer”.

This wallet will handle gas fees on behalf of your users, providing a seamless and cost-free experience for them. 

Once managed wallets are enabled in your Privy Dashboard, you can programmatically create one server-side using the Privy Node.js SDK.

Using the Privy NodeJS SDK:

import { PrivyClient } from '@privy-io/server-sdk';

// Initialize the Privy client

const privy = new PrivyClient({

  apiKey: process.env.PRIVY_API_KEY

});

// Create a new Solana managed wallet

async function createFeePayerWallet() {

  const { id, address, chainType } = await privy.walletApi.create({

    chainType: 'solana',

    policyIds: ['optional_policy_id'],

    idempotencyKey: 'unique_request_identifier'

  });

  console.log(`Created fee payer wallet with ID: ${id}`);

  console.log(`Wallet address: ${address}`);

  return { id, address };

}

// Make sure to fund this wallet with SOL to cover transaction fees

The wallet ID and address will be used in subsequent steps for sponsoring transactions.

2. Implement Sponsored Transactions

Once the managed wallet has been set up and funded, you’re ready to start enabling gasless transactions for the users. 

When a user authenticates, Privy provisions an embedded wallet tied to their login credentials. Users sign transactions as usual, but instead of submitting them directly to the blockchain, the transaction is sent to your backend, where your managed wallet signs and submits it on their behalf.

Note: This guide focuses on Privy's embedded wallets; however, the sponsored transaction pattern is compatible with any Solana wallet. The user signs the transaction, while your server covers the gas fee and handles the broadcast to the network.

This setup unlocks a seamless user experience while keeping users in full control of their keys.

Client-Side Implementation (React with Privy SDK)

import { useSolanaWallets } from '@privy-io/react-auth/solana';

import {

  TransactionMessage,

  PublicKey,

  VersionedTransaction,

  Connection

} from '@solana/web3.js';

async function sendGaslessTransaction(instructions) {

  // Get user's embedded wallet

  const { wallets } = useSolanaWallets();

  const embeddedWallet = wallets.find(wallet => 

    wallet.walletClientType === 'privy'

  );

  if (!embeddedWallet) {

    throw new Error('No embedded wallet found');

  }

  // Connect to Solana via Helius for better performance

  const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=YOUR_HELIUS_API_KEY');

  const { blockhash } = await connection.getLatestBlockhash();

  

  // Set your managed wallet as fee payer

  const feePayerAddress = 'YOUR_PRIVY_SERVER_WALLET_ADDRESS';

  // Build transaction with managed wallet as payer

  const message = new TransactionMessage({

    payerKey: new PublicKey(feePayerAddress),

    recentBlockhash: blockhash,

    instructions

  }).compileToV0Message();

  const transaction = new VersionedTransaction(message);

  // Have user sign the transaction

  const provider = await embeddedWallet.getProvider();

  const serializedMessage = Buffer.from(

    transaction.message.serialize()

  ).toString('base64');

  

  const { signature } = await provider.request({

    method: 'signMessage',

    params: { message: serializedMessage }

  });

  

  // Add user signature

  const userSignature = Buffer.from(signature, 'base64');

  transaction.addSignature(

    new PublicKey(embeddedWallet.address), 

    userSignature

  );

  

  // Send to your backend for fee payer signature

  const serializedTx = Buffer.from(

    transaction.serialize()

  ).toString('base64');

  

  const response = await fetch('/api/sponsor-transaction', {

    method: 'POST',

    headers: { 'Content-Type': 'application/json' },

    body: JSON.stringify({ transaction: serializedTx })

  });

  

  const { transactionHash } = await response.json();

  return transactionHash;

}

Finally, the partially signed transaction is sent from the client to your backend, where it’s verified, signed by the managed wallet, and broadcast to the Solana network.

Backend Implementation (Next.js API Route)

// pages/api/sponsor-transaction.js

import { VersionedTransaction } from '@solana/web3.js';

import { PrivyClient } from '@privy-io/server-sdk';

// Initialize Privy SDK

const privy = new PrivyClient({

  apiKey: process.env.PRIVY_API_KEY

});

// For App Router (Next.js 13+)

export async function POST(request) {

  try {

    const { transaction: serializedTx } = await request.json();

    

    // Deserialize the transaction to verify it (optional)

    const txBuffer = Buffer.from(serializedTx, 'base64');

    const transaction = VersionedTransaction.deserialize(txBuffer);

    

    // Verify the transaction (check fee payer, validate against policies)

    // ...verification logic here...

    

    // Sign AND send with your Privy managed wallet in one step

    const serverWalletId = process.env.PRIVY_SERVER_WALLET_ID;

    const { hash } = await privy.walletApi.solana.signAndSendTransaction({

      walletId: serverWalletId,

      caip2: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', // Mainnet

      transaction: serializedTx,

      rpcUrl: 'https://mainnet.helius-rpc.com/?api-key=YOUR_HELIUS_API_KEY',

      options: {

        maxRetries: 5,

        skipPreflight: true

      }

    });

    

    return Response.json({

      transactionHash: hash,

      message: 'Transaction sent successfully'

    }, { status: 200 });

  } catch (error) {

    console.error('Error processing transaction:', error);

    return Response.json({

      error: 'Failed to process transaction',

      details: error.message

    }, { status: 500 });

  }

}

By combining Privy's secure wallets with Helius's optimized transaction infrastructure, you can deliver a seamless, gasless experience for your users, without compromising on reliability or flexibility. 

The full documentation can be found here.

The Most Flexible Stack for Building Seamless App Experiences

Privy’s modular SDK, along with Helius’ high-performance RPC infrastructure, gives developers a powerful and flexible foundation for building world-class Solana apps. 

Whether you’re starting with a low-level wallet API and bringing your own authentication stack or using Privy for authentication and other advanced features like multi-factor authentication (MFA), embedded onramps, or native bridging, Privy’s stack scales with your product needs. 

Try it out today.

Share this post


RELATED POSTS