Skip to content

Solana Blinks: How to Turn Any Link into a Crypto Transaction? ⚡

The series of articles on programming on the Solana blockchain continues! My voting application has been finished for a while now, and I’m slowly moving forward!

Imagine reading a post on X (Twitter) and wanting to donate 0.1 SOL to your favorite creator. Instead of copying their address, opening your wallet, setting up the transaction, and waiting – you just click a button directly within the post. Those are Blinks (Blockchain Links).

What Are Blinks, Exactly?

To use a simple analogy: if traditional blockchain is like going to the bank to fill out a transfer slip, a Blink is like a QR code on a cafe bill. Everything is already prepared; you just need to approve it.

How Does It Work Under the Hood?

Blinks rely on Solana Actions. These are API endpoints that return a transaction for the user to sign. When a wallet (like Phantom or Backpack) recognizes a special URL, it “unpacks” it and displays a nice button instead of a plain link.

Solana Blinks illustration

Code Example (TypeScript/Next.js)

Here’s what a simple API endpoint looks like that allows someone to send you a “tip” of 0.1 SOL via a Blink.

TypeScript

import { ActionPostResponse, ACTIONS_CORS_HEADERS, createPostResponse } from "@solana/actions";
import { PublicKey, SystemProgram, Transaction, Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";

// Setting the tip amount
const TIP_AMOUNT_SOL = 0.1;

export const POST = async (req: Request) => {
  const { account } = await req.json();
  const userPubKey = new PublicKey(account);
  const myPubKey = new PublicKey("YOUR_SOLANA_ADDRESS_HERE");
  
  // Connecting to the Solana network (Mainnet or Devnet)
  const connection = new Connection("https://api.mainnet-beta.solana.com");

  // 🚨 WALLET BALANCE CHECK
  const balance = await connection.getBalance(userPubKey);
  const requiredAmount = TIP_AMOUNT_SOL * LAMPORTS_PER_SOL;

  if (balance < requiredAmount) {
    return new Response(
      JSON.stringify({ message: "Oops! You don't have enough SOL for this coffee. ☕" }),
      { status: 400, headers: ACTIONS_CORS_HEADERS }
    );
  }

  // If everything is okay, proceed with the transaction
  const transaction = new Transaction().add(
    SystemProgram.transfer({
      fromPubkey: userPubKey,
      toPubkey: myPubKey,
      lamports: requiredAmount,
    })
  );

  transaction.feePayer = userPubKey;
  const { blockhash } = await connection.getLatestBlockhash();
  transaction.recentBlockhash = blockhash;

  const payload: ActionPostResponse = await createPostResponse({
    fields: {
      transaction,
      message: `You successfully sent ${TIP_AMOUNT_SOL} SOL! Thank you very much! ✨`,
    },
  });

  return Response.json(payload, { headers: ACTIONS_CORS_HEADERS });
};

Detailed Code Explanation:

  • **connection.getBalance(userPubKey)**: This function “calls” Solana and returns the wallet balance in Lamports (the smallest unit, 1 SOL = 10^9 Lamports).
  • Logic condition (**if**): We check if the balance is less than the required amount. If it is, we return status: 400 and a message that the wallet will display to the user.
  • Optimization: This saves the user time because the transaction won’t even be sent to the network if it’s destined to fail.

Implementation Ideas:

This kind of check is crucial for Ticket Sales (to verify if the user has enough money for a ticket) or for Whitelist checks (where instead of the balance, you check if the wallet owns a specific NFT).

Leave a Reply

Your email address will not be published. Required fields are marked *