Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
795 changes: 743 additions & 52 deletions blinks/package-lock.json

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions blinks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@solana/actions": "^1.6.6",
"@solana/web3.js": "^1.98.2",
"next": "15.3.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.3.3"
"react-dom": "^19.0.0"
},
"devDependencies": {
"typescript": "^5",
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.3.3",
"@eslint/eslintrc": "^3"
"eslint-config-next": "15.3.4",
"tailwindcss": "^4",
"typescript": "^5"
}
}
21 changes: 21 additions & 0 deletions blinks/src/app/actions.json/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ACTIONS_CORS_HEADERS, ActionsJson } from "@solana/actions";

export const GET = async () => {
const payload: ActionsJson = {
rules: [
// map all root level routes to an action
{
pathPattern: "/",
apiPath: "/api/donate/",
},
],
};

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

// DO NOT FORGET TO INCLUDE THE `OPTIONS` HTTP METHOD
// THIS WILL ENSURE CORS WORKS FOR BLINKS
export const OPTIONS = GET;
90 changes: 90 additions & 0 deletions blinks/src/app/api/donate-sol/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
ACTIONS_CORS_HEADERS, // Importing CORS headers for actions
ActionGetResponse, // Type for GET response
ActionPostRequest, // Type for POST request
ActionPostResponse, // Type for POST response
createPostResponse, // Function to create a POST response
} from "@solana/actions";

import {
Connection, // Class for Solana network connection
LAMPORTS_PER_SOL, // Constant for lamports to SOL conversion
PublicKey, // Class for handling public keys
SystemProgram, // System program for basic transactions
Transaction, // Class for creating transactions
clusterApiUrl, // Function to get cluster API URL
} from "@solana/web3.js";

export async function GET(request: Request) {
const url = new URL(request.url); // Parse the request URL
const payload: ActionGetResponse = {
// Define the GET response payload
icon: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS7dPPWr-BRKzBy_Fig0v_snt-_onQj9Pl5xA&s", // Icon URL
title: "Donate to the Rahul", // Title
description: "Support rahul by donating SOL.", // Description
label: "Donate", // Label for the action
links: {
actions: [
{
label: "Donate 0.1 SOL", // Action label
href: `${url.href}?amount=0.1`, // Action URL with amount parameter
},
],
},
};
return Response.json(payload, {
headers: ACTIONS_CORS_HEADERS, // Set CORS headers
});
}

export const OPTIONS = GET; // Allow OPTIONS request to use GET handler

export async function POST(request: Request) {
const body: ActionPostRequest = await request.json(); // Parse the request body
const url = new URL(request.url); // Parse the request URL
const amount = Number(url.searchParams.get("amount")) || 0.1; // Get the amount from query params or default to 0.1
let sender;

try {
sender = new PublicKey(body.account); // Parse the sender public key
} catch (error) {
return Response.json(
{
error: {
message: "Invalid account", // Return error if invalid account
},
},
{
status: 400, // Bad request status
headers: ACTIONS_CORS_HEADERS, // Set CORS headers
}
);
}

const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed"); // Create a connection to the mainnet-beta cluster

const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: sender, // Sender public key
toPubkey: new PublicKey("address"), // Recipient public key
lamports: amount * LAMPORTS_PER_SOL, // Amount to transfer in lamports
})
);
transaction.feePayer = sender; // Set the fee payer
transaction.recentBlockhash = (
await connection.getLatestBlockhash()
).blockhash; // Get the latest blockhash
transaction.lastValidBlockHeight = (
await connection.getLatestBlockhash()
).lastValidBlockHeight; // Get the last valid block height

const payload: ActionPostResponse = await createPostResponse({
fields: {
transaction, // Add the transaction to the response payload
message: "Transaction created", // Success message
},
});
return new Response(JSON.stringify(payload), {
headers: ACTIONS_CORS_HEADERS, // Set CORS headers
});
}
156 changes: 83 additions & 73 deletions blinks/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,102 +2,112 @@ import Image from "next/image";

export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2 tracking-[-.01em]">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
src/app/page.tsx
</code>
.
</li>
<li className="tracking-[-.01em]">
Save and see your changes instantly.
</li>
</ol>

<div className="flex gap-4 items-center flex-col sm:flex-row">
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
Get started by editing&nbsp;
<code className="font-mono font-bold">src/app/page.tsx</code>
</p>
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:size-auto lg:bg-none">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{" "}
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
alt="Vercel Logo"
className="dark:invert"
width={100}
height={24}
priority
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
</div>

<div className="relative z-[-1] flex place-items-center before:absolute before:h-[300px] before:w-full before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 sm:before:w-[480px] sm:after:w-[240px] before:lg:h-[360px]">
<Image
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>

<div className="mb-32 grid text-center lg:mb-0 lg:w-full lg:max-w-5xl lg:grid-cols-4 lg:text-left">
<a
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<h2 className="mb-3 text-2xl font-semibold">
Docs{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-sm opacity-50">
Find in-depth information about Next.js features and API.
</p>
</a>

<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
<h2 className="mb-3 text-2xl font-semibold">
Learn{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-sm opacity-50">
Learn about Next.js in an interactive course with&nbsp;quizzes!
</p>
</a>

<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
<h2 className="mb-3 text-2xl font-semibold">
Templates{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-sm opacity-50">
Explore starter templates for Next.js.
</p>
</a>

<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org →
<h2 className="mb-3 text-2xl font-semibold">
Deploy{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-balance text-sm opacity-50">
Instantly deploy your Next.js site to a shareable URL with Vercel.
</p>
</a>
</footer>
</div>
</div>
</main>
);
}
}
Loading
Loading