├── .env.sample
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .npmrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── app
├── airdrop
│ └── page.tsx
├── api
│ ├── files
│ │ └── route.ts
│ └── tokenMints
│ │ └── route.ts
├── create
│ └── page.tsx
├── error.tsx
├── layout.tsx
├── mint
│ └── page.tsx
├── page.tsx
└── providers.tsx
├── components
├── Airdrop
│ └── Airdropcard.tsx
├── Home
│ ├── Benefits.tsx
│ ├── GetStarted.tsx
│ ├── HeroSection.tsx
│ └── MainFeatures.tsx
├── Mint
│ ├── MintTokenModal.tsx
│ ├── TokenCard.tsx
│ └── TokenList.tsx
├── Token
│ ├── TokenCreationSuccessModal.tsx
│ └── TokenForm.tsx
├── footer.tsx
├── icons.tsx
├── navbar.tsx
├── navbar
│ └── NetworkSelector.tsx
├── primitives.ts
└── theme-switch.tsx
├── config
├── fonts.ts
├── site.ts
└── solana.ts
├── models
└── MintAddresses.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── Launchpad.png
├── favicon.ico
├── next.svg
└── vercel.svg
├── styles
└── globals.css
├── tailwind.config.js
├── tsconfig.json
├── types
└── index.ts
└── utils
├── config.ts
└── dbConnect.ts
/.env.sample:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_SOLANA_ENDPOINT=
2 | NEXT_PUBLIC_SOLANA_NETWORK=
3 | MONGODB_URI=
4 | PINATA_JWT=
5 | NEXT_PINATA_GATEWAY_URL=
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | .now/*
2 | *.css
3 | .changeset
4 | dist
5 | esm/*
6 | public/*
7 | tests/*
8 | scripts/*
9 | *.config.js
10 | .DS_Store
11 | node_modules
12 | coverage
13 | .next
14 | build
15 | !.commitlintrc.cjs
16 | !.lintstagedrc.cjs
17 | !jest.config.js
18 | !plopfile.js
19 | !react-shim.js
20 | !tsup.config.ts
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/eslintrc.json",
3 | "env": {
4 | "browser": false,
5 | "es2021": true,
6 | "node": true
7 | },
8 | "extends": [
9 | "plugin:react/recommended",
10 | "plugin:prettier/recommended",
11 | "plugin:react-hooks/recommended",
12 | "plugin:jsx-a11y/recommended",
13 | "plugin:@next/next/recommended"
14 | ],
15 | "plugins": ["react", "unused-imports", "import", "@typescript-eslint", "jsx-a11y", "prettier"],
16 | "parser": "@typescript-eslint/parser",
17 | "parserOptions": {
18 | "ecmaFeatures": {
19 | "jsx": true
20 | },
21 | "ecmaVersion": 12,
22 | "sourceType": "module"
23 | },
24 | "settings": {
25 | "react": {
26 | "version": "detect"
27 | }
28 | },
29 | "rules": {
30 | "no-console": "warn",
31 | "react/prop-types": "off",
32 | "react/jsx-uses-react": "off",
33 | "react/react-in-jsx-scope": "off",
34 | "react-hooks/exhaustive-deps": "off",
35 | "jsx-a11y/click-events-have-key-events": "warn",
36 | "jsx-a11y/interactive-supports-focus": "warn",
37 | "prettier/prettier": "off",
38 | "no-unused-vars": "off",
39 | "unused-imports/no-unused-vars": "off",
40 | "unused-imports/no-unused-imports": "warn",
41 | "@typescript-eslint/no-unused-vars": [
42 | "warn",
43 | {
44 | "args": "after-used",
45 | "ignoreRestSiblings": false,
46 | "argsIgnorePattern": "^_.*?$"
47 | }
48 | ],
49 | "import/order": [
50 | "warn",
51 | {
52 | "groups": [
53 | "type",
54 | "builtin",
55 | "object",
56 | "external",
57 | "internal",
58 | "parent",
59 | "sibling",
60 | "index"
61 | ],
62 | "pathGroups": [
63 | {
64 | "pattern": "~/**",
65 | "group": "external",
66 | "position": "after"
67 | }
68 | ],
69 | "newlines-between": "always"
70 | }
71 | ],
72 | "react/self-closing-comp": "warn",
73 | "react/jsx-sort-props": [
74 | "warn",
75 | {
76 | "callbacksLast": true,
77 | "shorthandFirst": true,
78 | "noSortAlphabetically": false,
79 | "reservedFirst": true
80 | }
81 | ],
82 | "padding-line-between-statements": [
83 | "off",
84 | {"blankLine": "always", "prev": "*", "next": "return"},
85 | {"blankLine": "always", "prev": ["const", "let", "var"], "next": "*"},
86 | {
87 | "blankLine": "any",
88 | "prev": ["const", "let", "var"],
89 | "next": ["const", "let", "var"]
90 | }
91 | ]
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 | .env
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=true
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Next UI
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Solana Token Launchpad 🚀
2 |
3 | 
4 |
5 | A modern, user-friendly platform for creating and managing custom tokens on the Solana blockchain. Launch your own SPL tokens in minutes with a beautiful UI and seamless wallet integration.
6 |
7 | ## ✨ Features
8 |
9 | ### 🎯 Token Creation
10 |
11 | - Create custom SPL tokens with configurable parameters
12 | - Set token name, symbol, and initial supply
13 | - Upload and store token images on IPFS via Pinata
14 | - Automatic mint authority assignment to creator's wallet
15 |
16 | ### 💰 Token Management
17 |
18 | - View all tokens created by your wallet
19 | - Mint additional tokens as needed
20 | - Track token supply and distribution
21 | - Decentralized image storage on IPFS
22 |
23 | ### 🌟 Devnet Integration
24 |
25 | - Request SOL airdrops for testing
26 | - Deploy tokens on Solana Devnet
27 | - Test token functionality before mainnet launch
28 |
29 | ### 🎨 Modern UI/UX
30 |
31 | - Responsive design for all devices
32 | - Dark/Light mode support
33 | - Seamless wallet connection
34 | - Real-time transaction feedback
35 |
36 | ## 🛠 Technology Stack
37 |
38 | ### Blockchain & Web3
39 |
40 | - Solana Web3.js
41 | - SPL Token Program
42 | - Solana Wallet Adapter
43 |
44 | ### Frontend
45 |
46 | - React 18
47 | - TypeScript
48 | - NextUI Components
49 | - TailwindCSS
50 | - Lucide Icons
51 |
52 | ### Storage & Database
53 |
54 | - IPFS via Pinata
55 | - MongoDB Atlas
56 |
57 | ## 📦 Project Structure
58 |
59 | ```
60 | \
61 | ├── app/ # Route Pages
62 | │ ├── airdrop/ # Airdrop page
63 | │ ├── create/ # Create token page
64 | │ ├── mint/ # Mint tokens page
65 | │ └── api/ # backend code
66 | ├── components/ # React components for pages
67 | ├── config/ # siteconfig and backend func
68 | │ ├── solana.ts # Solana integration
69 | │ └── site.ts # Site config
70 | ├── models/ # Mongodb data model
71 | ├── types/ # Typescript types
72 | └── utils/ # util files for connections
73 | ```
74 |
75 | ## 🚀 Getting Started
76 |
77 | ### Prerequisites
78 |
79 | - Node.js 18+
80 | - npm or yarn
81 | - A Solana wallet (e.g., Phantom)
82 | - MongoDB Atlas account
83 | - Pinata account for IPFS
84 |
85 | ### Environment Variables
86 |
87 | Create a `.env` file in the root directory:
88 |
89 | ```env
90 | MONGODB_URI=your_mongodb_uri
91 | MONGODB_URI_MAINNET=your_mongodb_uri_for_mainnet_data
92 | PINATA_JWT=your_pinata_jwt
93 | NEXT_PINATA_GATEWAY_URL=your_pinata_gateway_url
94 | NEXT_PUBLIC_SOLANA_ENDPOINT=your_rpc_node_endpoint
95 | NEXT_PUBLIC_SOLANA_NETWORK=your_network ( "devent" | "mainnet" )
96 | ```
97 |
98 | ### Installation
99 |
100 | 1. Clone the repository:
101 |
102 | ```bash
103 | git clone https://github.com/abhiraj2404/Token_launchpad.git
104 | cd token_launchpad
105 | ```
106 |
107 | 2. Install dependencies:
108 |
109 | ```bash
110 | npm install
111 | ```
112 |
113 | 3. Start the development server:
114 |
115 | ```bash
116 | npm run dev
117 | ```
118 |
119 | 4. Open [http://localhost:3000](http://localhost:3000) in your browser
120 |
121 | ### Building for Production
122 |
123 | ```bash
124 | npm run build
125 | ```
126 |
127 | The build output will be in the `dist` directory.
128 |
129 | ## 📱 Usage
130 |
131 | 1. **Connect Wallet**
132 |
133 | - Click "Connect Wallet" in the navbar
134 | - Select your Solana wallet (e.g., Phantom)
135 | - Approve the connection
136 |
137 | 2. **Get Test SOL**
138 |
139 | - Navigate to the Airdrop page
140 | - Click "Request Airdrop"
141 | - Receive 1 SOL on Devnet
142 |
143 | 3. **Create Token**
144 |
145 | - Go to Create Token page
146 | - Fill in token details
147 | - Upload token image
148 | - Click "Launch Token"
149 |
150 | 4. **Manage Tokens**
151 | - Visit My Tokens page
152 | - View created tokens
153 | - Mint additional supply
154 | - Track token details
155 |
156 | ## 🤝 Contributing
157 |
158 | Contributions are welcome! Please feel free to submit a Pull Request.
159 |
160 | 1. Fork the project
161 | 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
162 | 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
163 | 4. Push to the branch (`git push origin feature/AmazingFeature`)
164 | 5. Open a Pull Request
165 |
166 | ## 📄 License
167 |
168 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
169 |
170 | ## 📧 Creator
171 |
172 | Abhiraj Chauhan - [@abhiraj_2404](https://x.com/abhiraj_2404)
173 |
174 | Project Link - [https://solanatokenlaunchpad.vercel.app](https://solanatokenlaunchpad.vercel.app)
175 |
--------------------------------------------------------------------------------
/app/airdrop/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { AirdropCard } from "@/components/Airdrop/Airdropcard";
3 | import { Card } from "@nextui-org/card";
4 | import { useWallet } from "@solana/wallet-adapter-react";
5 | import React from "react";
6 |
7 | function AirdropPage() {
8 | const { connected } = useWallet();
9 | return (
10 |
11 |
12 |
13 | Get Test SOL
14 |
15 |
16 | Request an airdrop of 1 SOL to test token creation on Solana Devnet.
17 |
18 |
19 |
20 |
21 | {!connected ? (
22 |
26 |
27 | Please connect your wallet to request an airdrop.
28 |
29 |
30 | ) : (
31 |
32 | )}
33 |
34 |
35 | );
36 | }
37 |
38 | export default AirdropPage;
39 |
--------------------------------------------------------------------------------
/app/api/files/route.ts:
--------------------------------------------------------------------------------
1 | import { NextResponse, type NextRequest } from "next/server";
2 | import { pinata } from "@/utils/config";
3 |
4 | export async function POST(request: NextRequest) {
5 | try {
6 | const data = await request.formData();
7 | const file: File | null = data.get("file") as unknown as File;
8 |
9 | const uploadData = await pinata.upload
10 | .file(file).group("51bde156-0d66-483f-976f-8826dfb8624c");
11 |
12 | const url = `https://${process.env.NEXT_PINATA_GATEWAY_URL}/ipfs/${uploadData.IpfsHash}`;
13 |
14 | return NextResponse.json(url, { status: 200 });
15 | } catch (e) {
16 | console.log(e);
17 | return NextResponse.json(
18 | { error: "Internal Server Error" },
19 | { status: 500 }
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/api/tokenMints/route.ts:
--------------------------------------------------------------------------------
1 | import MintAddresses from "@/models/MintAddresses";
2 | import dbConnect from "@/utils/dbConnect";
3 | import { NextRequest, NextResponse } from "next/server";
4 |
5 | // POST Request Handler
6 | export async function POST(request: NextRequest) {
7 | try {
8 | // Connect to the database
9 | await dbConnect();
10 |
11 | // Parse the request body
12 | const { address } = await request.json();
13 |
14 | // Validate the address
15 | if (!address) {
16 | return NextResponse.json(
17 | { error: "Mint address is required" },
18 | { status: 400 }
19 | );
20 | }
21 |
22 | // Check if address already exists
23 | const existingAddress = await MintAddresses.exists({ address });
24 | if (existingAddress) {
25 | return NextResponse.json(
26 | { error: "Mint address already exists" },
27 | { status: 409 }
28 | );
29 | }
30 |
31 | // Create new mint address
32 | const newMintAddress = await MintAddresses.create({ address });
33 |
34 | // Return success response
35 | return NextResponse.json(
36 | {
37 | message: "Mint address added successfully",
38 | address: newMintAddress,
39 | },
40 | { status: 201 }
41 | );
42 | } catch (error) {
43 | console.error("Error adding mint address:", error);
44 | return NextResponse.json(
45 | { error: "Failed to add mint address" },
46 | { status: 500 }
47 | );
48 | }
49 | }
50 |
51 | // GET Request Handler
52 | export async function GET() {
53 | try {
54 | // Connect to the database
55 | await dbConnect();
56 |
57 | // Retrieve all mint addresses
58 | const response = await MintAddresses.find();
59 | const mintAddresses = response.map((doc) => doc.address);
60 | // Return mint addresses
61 | return NextResponse.json(
62 | {
63 | message: "Mint addresses retrieved successfully",
64 | addresses: mintAddresses,
65 | },
66 | { status: 200 }
67 | );
68 | } catch (error) {
69 | console.error("Error retrieving mint addresses:", error);
70 | return NextResponse.json(
71 | { error: "Failed to retrieve mint addresses" },
72 | { status: 500 }
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/create/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import TokenForm from "@/components/Token/TokenForm";
4 | import { Card } from "@nextui-org/card";
5 | import { useWallet } from "@solana/wallet-adapter-react";
6 | import { Coins } from "lucide-react";
7 | import React from "react";
8 |
9 | function CreatetokenPage() {
10 | const { connected } = useWallet();
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 | Create Your Token
20 |
21 |
22 | Fill in the details below to launch your custom token on Solana.
23 |
24 |
25 |
26 |
27 | {!connected ? (
28 |
32 |
33 | Please connect your wallet to create a token
34 |
35 |
36 | ) : (
37 |
38 | )}
39 |
40 |
41 | );
42 | }
43 |
44 | export default CreatetokenPage;
45 |
--------------------------------------------------------------------------------
/app/error.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useEffect } from "react";
4 |
5 | export default function Error({
6 | error,
7 | reset,
8 | }: {
9 | error: Error;
10 | reset: () => void;
11 | }) {
12 | useEffect(() => {
13 | // Log the error to an error reporting service
14 | /* eslint-disable no-console */
15 | console.error(error);
16 | }, [error]);
17 |
18 | return (
19 |
20 |
Something went wrong!
21 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import "@/styles/globals.css";
2 | import { Metadata, Viewport } from "next";
3 | import { Link } from "@nextui-org/link";
4 | import clsx from "clsx";
5 | import { Analytics } from "@vercel/analytics/react";
6 |
7 | import { Providers } from "./providers";
8 |
9 | import { siteConfig } from "@/config/site";
10 | import { fontSans } from "@/config/fonts";
11 | import { Navbar } from "@/components/navbar";
12 | import { Footer } from "@/components/footer";
13 |
14 | export const metadata: Metadata = {
15 | title: {
16 | default: siteConfig.name,
17 | template: `%s - ${siteConfig.name}`,
18 | },
19 | description: siteConfig.description,
20 | icons: {
21 | icon: "/favicon.ico",
22 | },
23 | };
24 |
25 | export const viewport: Viewport = {
26 | themeColor: [
27 | { media: "(prefers-color-scheme: light)", color: "white" },
28 | { media: "(prefers-color-scheme: dark)", color: "black" },
29 | ],
30 | };
31 |
32 | export default function RootLayout({
33 | children,
34 | }: {
35 | children: React.ReactNode;
36 | }) {
37 | return (
38 |
39 |
46 |
47 |
48 |
49 |
50 |
{children}
51 |
52 |
53 |
54 |
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/app/mint/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { TokenList } from "@/components/Mint/TokenList";
4 | import { Card } from "@nextui-org/card";
5 | import { useWallet } from "@solana/wallet-adapter-react";
6 | import React from "react";
7 |
8 | function MintPage() {
9 | const { connected } = useWallet();
10 |
11 | return (
12 |
13 |
14 |
My Tokens
15 |
16 | Manage your launched tokens and mint additional supply.
17 |
18 |
19 |
20 |
21 | {!connected ? (
22 |
26 |
27 | Please connect your wallet to mint tokens.
28 |
29 |
30 | ) : (
31 |
32 | )}
33 |
34 |
35 | );
36 | }
37 |
38 | export default MintPage;
39 |
--------------------------------------------------------------------------------
/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import HeroSection from "@/components/Home/HeroSection";
3 | import { MainFeatures } from "@/components/Home/MainFeatures";
4 | import { GetStarted } from "@/components/Home/GetStarted";
5 | import { Benefits } from "@/components/Home/Benefits";
6 |
7 | export default function Home() {
8 | return (
9 | <>
10 |
11 |
12 |
13 |
14 | {/*
15 |
16 |
17 |
18 |
19 |
Launch Your Solana Token
20 |
21 | Create and deploy your own token on the Solana blockchain in
22 | minutes. Simple, fast, and secure.
23 |
24 |
}
30 | >
31 | Create Token
32 |
33 |
34 |
35 |
36 | }
38 | title="Fast Deployment"
39 | description="Launch your token in seconds with our streamlined process."
40 | />
41 | }
43 | title="Secure"
44 | description="Built on Solana's secure and scalable blockchain infrastructure."
45 | />
46 | }
48 | title="Low Cost"
49 | description="Minimal fees for token creation and transactions."
50 | />
51 | }
53 | title="Low Cost"
54 | description="Minimal fees for token creation and transactions."
55 | />
56 |
57 |
58 |
59 |
60 | Ready to Create Your Token?
61 |
62 |
63 | Join thousands of projects already launched on Solana
64 |
65 |
68 |
69 |
*/}
70 | >
71 | );
72 | }
73 |
--------------------------------------------------------------------------------
/app/providers.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import type { ThemeProviderProps } from "next-themes";
4 | import {
5 | ConnectionProvider,
6 | WalletProvider,
7 | } from "@solana/wallet-adapter-react";
8 | import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
9 | import { UnsafeBurnerWalletAdapter } from "@solana/wallet-adapter-wallets";
10 | import {
11 | WalletModalProvider,
12 | WalletDisconnectButton,
13 | WalletMultiButton,
14 | } from "@solana/wallet-adapter-react-ui";
15 | import { clusterApiUrl } from "@solana/web3.js";
16 |
17 | // Default styles that can be overridden by your app
18 | import "@solana/wallet-adapter-react-ui/styles.css";
19 |
20 | import * as React from "react";
21 | import { NextUIProvider } from "@nextui-org/system";
22 | import { useRouter } from "next/navigation";
23 | import { ThemeProvider as NextThemesProvider } from "next-themes";
24 |
25 | export interface ProvidersProps {
26 | children: React.ReactNode;
27 | themeProps?: ThemeProviderProps;
28 | }
29 |
30 | declare module "@react-types/shared" {
31 | interface RouterConfig {
32 | routerOptions: NonNullable<
33 | Parameters["push"]>[1]
34 | >;
35 | }
36 | }
37 |
38 | export function Providers({ children, themeProps }: ProvidersProps) {
39 | const router = useRouter();
40 | console.log(process.env.NEXT_PUBLIC_SOLANA_ENDPOINT);
41 | return (
42 |
43 |
44 |
45 |
46 | {children}
47 |
48 |
49 |
50 |
51 | );
52 | }
53 |
--------------------------------------------------------------------------------
/components/Airdrop/Airdropcard.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useState } from "react";
4 | import { useWallet } from "@solana/wallet-adapter-react";
5 | import { Loader2 } from "lucide-react";
6 | import { Button } from "@nextui-org/button";
7 | import { getConnection } from "@/config/solana";
8 | import { LAMPORTS_PER_SOL } from "@solana/web3.js";
9 |
10 | export function AirdropCard() {
11 | const { publicKey } = useWallet();
12 | const [isLoading, setIsLoading] = useState(false);
13 |
14 | const handleAirdrop = async () => {
15 | setIsLoading(true);
16 |
17 | if (!publicKey) return;
18 |
19 | try {
20 | const connection = getConnection();
21 | const signature = await connection.requestAirdrop(
22 | publicKey,
23 | LAMPORTS_PER_SOL
24 | );
25 | await connection.confirmTransaction(signature);
26 | alert("Airdrop successful!, check your balance");
27 | } catch (error) {
28 | alert("Failed to request airdrop, some error occured");
29 | }
30 |
31 | setIsLoading(false);
32 | };
33 |
34 | return (
35 |
36 |
37 |
38 |
39 | Your Wallet
40 |
41 |
42 | {publicKey?.toString()}
43 |
44 |
45 |
46 |
47 |
48 |
49 | Amount to receive:
50 |
51 |
1 SOL
52 |
53 |
54 |
62 |
63 |
64 |
65 | );
66 | }
67 |
--------------------------------------------------------------------------------
/components/Home/Benefits.tsx:
--------------------------------------------------------------------------------
1 | import { Card } from "@nextui-org/card";
2 | import { Shield, Zap, Lock, Settings } from "lucide-react";
3 |
4 | export function Benefits() {
5 | return (
6 |
7 |
8 |
9 | Why Choose Our Platform?
10 |
11 |
12 | Built with security and simplicity in mind
13 |
14 |
15 |
16 |
17 | {benefits.map((benefit) => (
18 |
23 |
24 |
25 |
26 | {benefit.icon}
27 |
28 |
29 |
30 |
31 | {benefit.title}
32 |
33 |
{benefit.description}
34 |
35 |
36 |
37 | ))}
38 |
39 |
40 | );
41 | }
42 |
43 | const benefits = [
44 | {
45 | icon: ,
46 | title: "Fast Deployment",
47 | description:
48 | "Launch your token in seconds with our optimized deployment process. No complex setup required.",
49 | },
50 | {
51 | icon: ,
52 | title: "Secure Platform",
53 | description:
54 | "Built on Solana's secure blockchain with industry-standard security practices.",
55 | },
56 | {
57 | icon: ,
58 | title: "Full Control",
59 | description:
60 | "Maintain complete control as the mint authority of your token with no restrictions.",
61 | },
62 | {
63 | icon: ,
64 | title: "Easy Management",
65 | description:
66 | "Intuitive interface to manage your tokens and mint additional supply when needed.",
67 | },
68 | ];
69 |
--------------------------------------------------------------------------------
/components/Home/GetStarted.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@nextui-org/button";
2 | import { Card } from "@nextui-org/card";
3 | import { Link } from "@nextui-org/link";
4 | import { Rocket, Coins } from "lucide-react";
5 |
6 | const selectedNetwork = process.env.NEXT_PUBLIC_SOLANA_NETWORK;
7 |
8 | export function GetStarted() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | Ready to Launch Your Token?
17 |
18 |
19 | Join the growing community of projects on Solana. Create your
20 | token in minutes.
21 |
22 |
23 | }
29 | >
30 | Create Token
31 |
32 | }
39 | >
40 | {selectedNetwork == "devnet" ? "Get Test SOL" : "Mint Tokens"}
41 |
42 |
43 |
44 |
45 |
46 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/components/Home/HeroSection.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@nextui-org/button";
2 | import { Coins, Rocket } from "lucide-react";
3 | import Link from "next/link";
4 | import React from "react";
5 |
6 | const selectedNetwork = process.env.NEXT_PUBLIC_SOLANA_NETWORK;
7 | function HeroSection() {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Token Launchpad
17 |
18 |
19 |
20 | Launch Your Own Solana Token{" "}
21 | in Minutes
22 |
23 |
24 | Create, deploy, and manage your custom token on Solana with our
25 | simple and secure platform.
26 |
27 |
28 | }
34 | >
35 | Create Token
36 |
37 |
46 |
47 |
48 |
49 |

54 |
55 |
56 |
57 |
58 | );
59 | }
60 |
61 | export default HeroSection;
62 |
--------------------------------------------------------------------------------
/components/Home/MainFeatures.tsx:
--------------------------------------------------------------------------------
1 | import { Card } from "@nextui-org/card";
2 | import { Chip } from "@nextui-org/chip";
3 | import { Link } from "@nextui-org/link";
4 | import { Wallet, Plus, Coins, Waves } from "lucide-react";
5 |
6 | const selectedNetwork = process.env.NEXT_PUBLIC_SOLANA_NETWORK;
7 |
8 | export function MainFeatures() {
9 | return (
10 |
11 |
12 |
13 |
14 | Create Your Token in Simple Steps
15 |
16 |
17 | Follow our streamlined process to launch your token
18 |
19 |
20 |
21 |
22 | {/* Connection Lines */}
23 |
24 |
25 |
26 | {features.map((feature, index) => (
27 |
31 | {feature.link ? (
32 |
33 |
34 |
35 | ) : (
36 |
37 | )}
38 |
39 | ))}
40 |
41 |
42 |
43 |
44 | );
45 | }
46 |
47 | interface Feature {
48 | icon: React.ReactNode;
49 | title: string;
50 | description: string;
51 | link?: string;
52 | comingSoon?: boolean;
53 | }
54 |
55 | function FeatureCard({ feature, index }: { feature: Feature; index: number }) {
56 | return (
57 |
61 |
62 |
63 |
{feature.icon}
64 |
65 | {feature.comingSoon && (
66 |
67 | Coming Soon
68 |
69 | )}
70 | {index}
71 |
72 |
73 |
74 | {feature.title}
75 |
76 |
{feature.description}
77 |
78 |
79 | );
80 | }
81 |
82 | const features: Feature[] = [
83 | {
84 | icon: ,
85 | title: selectedNetwork == "devnet" ? "Get Test SOL" : "Connect Wallet",
86 | description:
87 | "Connect your solana wallet to do transactions on the platform.",
88 | link: selectedNetwork == "devnet" ? "/airdrop" : "/",
89 | },
90 | {
91 | icon: ,
92 | title: "Create Tokens",
93 | description:
94 | "Configure your token with custom name, symbol, and initial supply",
95 | link: "/create",
96 | },
97 | {
98 | icon: ,
99 | title: "Manage Tokens",
100 | description: "View your tokens and mint additional supply whenever needed",
101 | link: "/mint",
102 | },
103 | {
104 | icon: ,
105 | title: "Create Liquidity",
106 | description: "Add liquidity pool for your token to enable trading",
107 | comingSoon: true,
108 | },
109 | ];
110 |
--------------------------------------------------------------------------------
/components/Mint/MintTokenModal.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import {
3 | Modal,
4 | ModalContent,
5 | ModalHeader,
6 | ModalBody,
7 | ModalFooter,
8 | } from "@nextui-org/modal";
9 | import { TokenData } from "@/types";
10 | import { Input } from "@nextui-org/input";
11 | import { Button } from "@nextui-org/button";
12 | import { getConnection, mintTo } from "@/config/solana";
13 | import { useWallet } from "@solana/wallet-adapter-react";
14 | import { PublicKey } from "@solana/web3.js";
15 | import { getAssociatedTokenAddress, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
16 |
17 | interface MintTokenModalProps {
18 | isOpen: boolean;
19 | token: TokenData | null;
20 | onClose: () => void;
21 | }
22 |
23 | export function MintTokenModal({
24 | isOpen,
25 | token,
26 | onClose,
27 | }: MintTokenModalProps) {
28 | const [formData, setFormData] = useState({ amount: 0 });
29 | const [isLoading, setIsLoading] = useState(false);
30 | const connection = getConnection();
31 | const wallet = useWallet();
32 | const mint = token ? new PublicKey(token.mint) : null;
33 |
34 | const handleSubmit = async (e: React.FormEvent) => {
35 | e.preventDefault();
36 | if (!token) return;
37 |
38 | if (token.mintAuthority !== wallet.publicKey?.toBase58()) {
39 | alert("You are not the mint authority for this token");
40 | onClose();
41 | return;
42 | }
43 | const mintAmount = formData.amount * Math.pow(10, token.decimals);
44 |
45 | setIsLoading(true);
46 |
47 | try {
48 | if (mint && wallet.publicKey) {
49 | const tokenAccount = await getAssociatedTokenAddress(
50 | mint,
51 | wallet.publicKey,
52 | true,
53 | TOKEN_2022_PROGRAM_ID
54 | );
55 |
56 | await mintTo(
57 | connection,
58 | wallet, // Payer wallet
59 | mint, // Mint address
60 | tokenAccount, // Destination address
61 | wallet.publicKey, // Mint authority
62 | mintAmount // Amount to mint
63 | );
64 | }
65 | alert("Tokens minted successfully");
66 | } catch (error) {
67 | console.error("Error minting tokens:", error);
68 | alert("Error minting tokens");
69 | } finally {
70 | setIsLoading(false);
71 | onClose();
72 | }
73 | };
74 |
75 | if (!token) return null;
76 |
77 | return (
78 |
79 |
80 |
113 |
114 |
115 | );
116 | }
117 |
--------------------------------------------------------------------------------
/components/Mint/TokenCard.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { TokenData } from '@/types';
3 | import { Button } from '@nextui-org/button';
4 | import { Card } from '@nextui-org/card';
5 | import { Tooltip } from '@nextui-org/tooltip';
6 | import { Copy, CheckCircle } from 'lucide-react';
7 | import { useState } from 'react';
8 |
9 | interface TokenCardProps {
10 | token: TokenData;
11 | onMint: () => void;
12 | }
13 |
14 | export default function TokenCard({ token, onMint }: TokenCardProps) {
15 | const [copiedField, setCopiedField] = useState(null);
16 |
17 | const handleCopy = async (value: string, field: string) => {
18 | await navigator.clipboard.writeText(value);
19 | setCopiedField(field);
20 | setTimeout(() => setCopiedField(null), 2000);
21 | };
22 |
23 | return (
24 |
25 |
26 |
27 |
28 |

33 |
34 |
35 |
36 |
37 |
38 |
39 | {token.name} ({token.symbol})
40 |
41 |
42 | Total Supply: {token.totalSupply.toLocaleString()} {token.symbol}
43 |
44 |
45 |
51 |
52 |
53 |
54 |
handleCopy(token.mint, 'mint')}
58 | copied={copiedField === 'mint'}
59 | />
60 | handleCopy(token.mintAuthority, 'mintAuth')}
64 | copied={copiedField === 'mintAuth'}
65 | />
66 | {token.freezeAuthority && (
67 | handleCopy(token.freezeAuthority!, 'freezeAuth')}
71 | copied={copiedField === 'freezeAuth'}
72 | />
73 | )}
74 |
75 | Decimals: {token.decimals}
76 |
77 |
78 |
79 |
80 |
81 |
82 | );
83 | }
84 |
85 |
86 | interface AddressRowProps {
87 | label: string;
88 | value: string;
89 | onCopy: () => void;
90 | copied: boolean;
91 | }
92 |
93 | function AddressRow({ label, value, onCopy, copied }: AddressRowProps) {
94 | return (
95 |
96 |
97 |
98 | {label}:
99 |
100 | {value.slice(0, 16)}...{value.slice(-8)}
101 |
102 |
103 |
104 |
105 |
118 |
119 |
120 | );
121 | }
--------------------------------------------------------------------------------
/components/Mint/TokenList.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { getConnection } from "@/config/solana";
3 | import { TokenData } from "@/types";
4 | import { Spinner } from "@nextui-org/spinner";
5 | import {
6 | getMint,
7 | getTokenMetadata,
8 | TOKEN_2022_PROGRAM_ID,
9 | } from "@solana/spl-token";
10 | import { useWallet } from "@solana/wallet-adapter-react";
11 | import { PublicKey } from "@solana/web3.js";
12 | import { useEffect, useState } from "react";
13 | import { MintTokenModal } from "./MintTokenModal";
14 | import TokenCard from "./TokenCard";
15 |
16 | async function fetchUserTokens(userPublicKey: any): Promise {
17 | const connection = getConnection();
18 | const tokens: TokenData[] = [];
19 | // const data = JSON.parse(JSON.stringify(tokenmint));
20 |
21 | const response = await fetch("/api/tokenMints");
22 | const data = await response.json();
23 | const mintAddresses = data.addresses;
24 | for (const mintAddress of mintAddresses) {
25 | try {
26 | const mintPubkey = new PublicKey(mintAddress);
27 | const metadata = await getTokenMetadata(
28 | connection,
29 | mintPubkey,
30 | "confirmed",
31 | TOKEN_2022_PROGRAM_ID
32 | );
33 | const mintInfo = await getMint(
34 | connection,
35 | mintPubkey,
36 | "confirmed",
37 | TOKEN_2022_PROGRAM_ID
38 | );
39 | const uriResponse = await fetch(metadata?.uri as string);
40 | const uriData = await uriResponse.json();
41 |
42 | if (mintInfo.mintAuthority?.toBase58() == userPublicKey)
43 | tokens.push({
44 | mint: mintAddress,
45 | name: metadata?.name || "Unknown",
46 | symbol: metadata?.symbol || "Unknown",
47 | decimals: mintInfo.decimals,
48 | totalSupply:
49 | Number(mintInfo.supply) / Math.pow(10, mintInfo.decimals),
50 | imageUrl: uriData?.image || "",
51 | mintAuthority: mintInfo.mintAuthority?.toBase58() || "None",
52 | freezeAuthority: metadata?.updateAuthority?.toBase58() || null,
53 | });
54 | } catch (error) {
55 | console.error(`Error fetching token ${mintAddress}:`, error);
56 | }
57 | }
58 |
59 | return tokens;
60 | }
61 |
62 | export function TokenList() {
63 | const wallet = useWallet();
64 | const [tokens, setTokens] = useState([]);
65 | const [selectedToken, setSelectedToken] = useState(null);
66 | const [showMintModal, setShowMintModal] = useState(false);
67 | const [isLoading, setIsLoading] = useState(true);
68 |
69 | useEffect(() => {
70 | async function loadTokens() {
71 | if (wallet.publicKey) {
72 | try {
73 | const userTokens = await fetchUserTokens(wallet.publicKey);
74 | setTokens(userTokens);
75 | } catch (error) {
76 | console.error("Error loading tokens:", error);
77 | } finally {
78 | setIsLoading(false);
79 | }
80 | }
81 | }
82 |
83 | loadTokens();
84 | }, [wallet.publicKey]);
85 |
86 | const handleMint = (token: TokenData) => {
87 | setSelectedToken(token);
88 | setShowMintModal(true);
89 | };
90 |
91 | if (isLoading) {
92 | return (
93 |
94 |
95 |
96 | );
97 | }
98 |
99 | return (
100 |
101 | {tokens
102 | .slice()
103 | .reverse()
104 | .map((token) => (
105 |
handleMint(token)}
109 | />
110 | ))}
111 |
112 | {tokens.length === 0 && (
113 |
114 |
115 | You haven't created any tokens yet.
116 |
117 |
118 | )}
119 |
120 | {
124 | setShowMintModal(false);
125 | setSelectedToken(null);
126 | }}
127 | />
128 |
129 | );
130 | }
131 |
--------------------------------------------------------------------------------
/components/Token/TokenCreationSuccessModal.tsx:
--------------------------------------------------------------------------------
1 | import { TokenMetadata } from "@/types";
2 | import { Button } from "@nextui-org/button";
3 | import { Link } from "@nextui-org/link";
4 | import {
5 | Modal,
6 | ModalContent,
7 | ModalHeader,
8 | ModalBody,
9 | ModalFooter,
10 | } from "@nextui-org/modal";
11 | import { ExternalLink, Copy, CheckCircle } from "lucide-react";
12 | import { useState } from "react";
13 |
14 | interface TokenCreationSuccessProps {
15 | isOpen: boolean;
16 | onClose: () => void;
17 | tokenData: TokenMetadata;
18 | }
19 |
20 | const selectedNetwork = process.env.NEXT_PUBLIC_SOLANA_NETWORK;
21 |
22 | export default function TokenCreationSuccessModal({
23 | isOpen,
24 | onClose,
25 | tokenData,
26 | }: TokenCreationSuccessProps) {
27 | const explorerUrl = `https://explorer.solana.com/address/${tokenData.mint}?cluster=${selectedNetwork == "mainnet" ? "mainnet-beta" : "devnet"}`;
28 | const [copiedField, setCopiedField] = useState(null);
29 |
30 | const handleCopy = async (value: string, field: string) => {
31 | await navigator.clipboard.writeText(value);
32 | setCopiedField(field);
33 | setTimeout(() => setCopiedField(null), 2000);
34 | };
35 |
36 | return (
37 |
48 |
49 |
50 |
51 | Token Created Successfully!
52 |
53 |
54 |
55 |
56 |
57 |
58 | Token Details
59 |
60 |
61 |
62 |
63 | handleCopy(tokenData.mint, "mint")}
67 | copied={copiedField === "mint"}
68 | />
69 |
73 | handleCopy(tokenData.mintAuthority, "authority")
74 | }
75 | copied={copiedField === "authority"}
76 | />
77 |
81 |
85 |
86 |
87 |
88 |
89 |
90 | }
97 | >
98 | View on Explorer
99 |
100 |
103 |
104 |
105 |
106 | );
107 | }
108 |
109 | interface DetailRowProps {
110 | label: string;
111 | value: string;
112 | onCopy?: () => void;
113 | copied?: boolean;
114 | }
115 |
116 | function DetailRow({ label, value, onCopy, copied }: DetailRowProps) {
117 | return (
118 |
119 |
120 | {label}:
121 |
122 |
123 |
124 | {value}
125 |
126 | {onCopy && (
127 |
140 | )}
141 |
142 |
143 | );
144 | }
145 |
--------------------------------------------------------------------------------
/components/Token/TokenForm.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { TokenFormData, TokenMetadata } from "@/types";
4 | import { Button } from "@nextui-org/button";
5 | import { Card } from "@nextui-org/card";
6 | import { Input } from "@nextui-org/input";
7 | import React, { useRef, useState } from "react";
8 | import TokenCreationSuccessModal from "./TokenCreationSuccessModal";
9 | import { createToken, getConnection } from "@/config/solana";
10 | import { useWallet } from "@solana/wallet-adapter-react";
11 | import { Upload } from "lucide-react";
12 |
13 | const initialFormData: TokenFormData = {
14 | name: "",
15 | symbol: "",
16 | decimals: 9,
17 | initialMintAmount: 100,
18 | };
19 |
20 | const dummyTokenMetadata: TokenMetadata = {
21 | mint: "3kH9fZnYqDfPz3x5Qf8mK2fUyUxtjhgHb3Wq7N7s8X4A",
22 | mintAuthority: "B2cN8jTy5XQoQ9Bd7pWV7pJkqD8WRzF5j9p6bHqLn3k4",
23 | name: "DummyToken",
24 | symbol: "DMT",
25 | decimals: 6,
26 | initialMintAmount: 1000000,
27 | };
28 |
29 | function TokenForm() {
30 | const wallet = useWallet();
31 | const [formData, setFormData] = useState(initialFormData);
32 | const [isLoading, setIsLoading] = useState(false);
33 | const [loadingText, setLoadingText] = useState("Launch Token");
34 | const [file, setFile] = useState();
35 | const [imageURL, setImageURL] = useState(null);
36 | const [URI, setURI] = useState(null);
37 | const [tokenData, setTokenData] = useState(null);
38 | const [showSuccess, setShowSuccess] = useState(false);
39 | const [imagePreview, setImagePreview] = useState(null);
40 | const fileInputRef = useRef(null);
41 |
42 | const handleInputChange = (
43 | field: keyof TokenFormData,
44 | value: string | number
45 | ) => {
46 | setFormData((prev) => ({ ...prev, [field]: value }));
47 | };
48 |
49 | const handleImageUpload = (e: React.ChangeEvent) => {
50 | const file = e.target.files?.[0];
51 | if (file) {
52 | setFile(e.target?.files?.[0]);
53 | const reader = new FileReader();
54 | reader.onloadend = () => {
55 | setImagePreview(reader.result as string);
56 | };
57 | reader.readAsDataURL(file);
58 | }
59 | };
60 |
61 | const uploadImageFile = async () => {
62 | try {
63 | if (!file) {
64 | alert("No file selected");
65 | return;
66 | }
67 |
68 | const data = new FormData();
69 | data.set("file", file, formData.name);
70 | const uploadRequest = await fetch("/api/files", {
71 | method: "POST",
72 | body: data,
73 | });
74 | const imageURL = await uploadRequest.json();
75 | setImageURL(imageURL);
76 | return imageURL;
77 | } catch (e) {
78 | console.log(e);
79 | alert("Trouble uploading file");
80 | }
81 | };
82 |
83 | const uploadMetadata = async (metadata: object) => {
84 | try {
85 | const metadataBlob = new Blob([JSON.stringify(metadata)], {
86 | type: "application/json",
87 | });
88 |
89 | const metadataFormData = new FormData();
90 | metadataFormData.set(
91 | "file",
92 | metadataBlob,
93 | `metadata-${formData.name}.json`
94 | );
95 |
96 | const response = await fetch("/api/files", {
97 | method: "POST",
98 | body: metadataFormData,
99 | });
100 |
101 | if (!response.ok) throw new Error("Failed to upload metadata");
102 |
103 | alert("Metadata uploaded successfully!");
104 |
105 | const metadataURI = await response.json();
106 | console.log("Metadata URI in upload metadata function:", metadataURI);
107 | return metadataURI;
108 | } catch (e) {
109 | console.error("Error uploading metadata:", e);
110 | alert("Trouble uploading metadata");
111 | }
112 | };
113 |
114 | const handleSubmit = async (e: React.FormEvent) => {
115 | e.preventDefault();
116 | setIsLoading(true);
117 |
118 | try {
119 | const connection = getConnection();
120 | if (wallet.publicKey) {
121 | const balance = await connection.getBalance(wallet.publicKey);
122 | const balanceInSOL = balance / 1e9;
123 | if (balanceInSOL < 0.01) {
124 | alert(
125 | "Insufficient balance, transactions might fail, please request an airdrop"
126 | );
127 | setIsLoading(false);
128 | return;
129 | }
130 | }
131 | setLoadingText("Uploading metadata files...");
132 | const imageURL = await uploadImageFile();
133 | if (imageURL) {
134 | //metadata upload
135 | const metadata = {
136 | name: formData.name,
137 | symbol: formData.symbol,
138 | image: imageURL,
139 | };
140 | const metadataURI = await uploadMetadata(metadata);
141 | console.log("Metadata URI just before createtoken:", metadataURI);
142 |
143 | //create token
144 | setLoadingText("Creating token...");
145 | const result = await createToken(formData, wallet, metadataURI);
146 |
147 | setLoadingText("Storing to db...");
148 | const response = await fetch("/api/tokenMints", {
149 | method: "POST",
150 | headers: { "Content-Type": "application/json" },
151 | body: JSON.stringify({ address: result.mint }),
152 | });
153 |
154 | const data = await response.json();
155 | if (!response.ok) {
156 | throw new Error(data.error);
157 | }
158 |
159 | setTokenData(result);
160 | }
161 |
162 | setShowSuccess(true);
163 | } catch (error) {
164 | console.error("Error creating token:", error);
165 | } finally {
166 | setIsLoading(false);
167 | }
168 | };
169 |
170 | return (
171 | <>
172 |
173 |
275 |
276 |
277 | {tokenData && (
278 | setShowSuccess(false)}
281 | tokenData={tokenData}
282 | />
283 | )}
284 | >
285 | );
286 | }
287 |
288 | export default TokenForm;
289 |
--------------------------------------------------------------------------------
/components/footer.tsx:
--------------------------------------------------------------------------------
1 | import { siteConfig } from "@/config/site";
2 | import { Coins, Github, Twitter } from "lucide-react";
3 | import Link from "next/link";
4 |
5 | const selectedNetwork = process.env.NEXT_PUBLIC_SOLANA_NETWORK;
6 |
7 | export function Footer() {
8 | return (
9 |
112 | );
113 | }
114 |
--------------------------------------------------------------------------------
/components/icons.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { IconSvgProps } from "@/types";
4 |
5 | export const Logo: React.FC = ({
6 | size = 36,
7 | width,
8 | height,
9 | ...props
10 | }) => (
11 |
25 | );
26 |
27 | export const DiscordIcon: React.FC = ({
28 | size = 24,
29 | width,
30 | height,
31 | ...props
32 | }) => {
33 | return (
34 |
45 | );
46 | };
47 |
48 | export const TwitterIcon: React.FC = ({
49 | size = 24,
50 | width,
51 | height,
52 | ...props
53 | }) => {
54 | return (
55 |
66 | );
67 | };
68 |
69 | export const GithubIcon: React.FC = ({
70 | size = 24,
71 | width,
72 | height,
73 | ...props
74 | }) => {
75 | return (
76 |
89 | );
90 | };
91 |
92 | export const MoonFilledIcon = ({
93 | size = 24,
94 | width,
95 | height,
96 | ...props
97 | }: IconSvgProps) => (
98 |
112 | );
113 |
114 | export const SunFilledIcon = ({
115 | size = 24,
116 | width,
117 | height,
118 | ...props
119 | }: IconSvgProps) => (
120 |
134 | );
135 |
136 | export const HeartFilledIcon = ({
137 | size = 24,
138 | width,
139 | height,
140 | ...props
141 | }: IconSvgProps) => (
142 |
159 | );
160 |
161 | export const SearchIcon = (props: IconSvgProps) => (
162 |
187 | );
188 |
189 | export const NextUILogo: React.FC = (props) => {
190 | const { width, height = 40 } = props;
191 |
192 | return (
193 |
214 | );
215 | };
216 |
--------------------------------------------------------------------------------
/components/navbar.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import {
3 | Navbar as NextUINavbar,
4 | NavbarContent,
5 | NavbarMenu,
6 | NavbarMenuToggle,
7 | NavbarBrand,
8 | NavbarItem,
9 | NavbarMenuItem,
10 | } from "@nextui-org/navbar";
11 | import dynamic from "next/dynamic";
12 | import { Link } from "@nextui-org/link";
13 | import { link as linkStyles } from "@nextui-org/theme";
14 | import NextLink from "next/link";
15 | import clsx from "clsx";
16 |
17 | import { siteConfig } from "@/config/site";
18 | import { ThemeSwitch } from "@/components/theme-switch";
19 | import { GithubIcon } from "@/components/icons";
20 | import { Coins } from "lucide-react";
21 | const WalletMultiButton = dynamic(
22 | () =>
23 | import("@solana/wallet-adapter-react-ui").then(
24 | (mod) => mod.WalletMultiButton
25 | ),
26 | {
27 | ssr: false,
28 | }
29 | );
30 |
31 | import "@solana/wallet-adapter-react-ui/styles.css";
32 | import { NetworkSelector } from "./navbar/NetworkSelector";
33 |
34 | export const Navbar = () => {
35 | return (
36 |
37 |
38 |
39 |
40 |
41 |
42 | Token Launchpad
43 |
44 |
45 |
46 |
47 |
48 | {/* rightmost content */}
49 |
53 |
54 | {siteConfig.navItems.map((item) => (
55 |
56 |
64 | {item.label}
65 |
66 |
67 | ))}
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | {siteConfig.navMenuItems.map((item, index) => (
93 |
94 |
95 | {item.label}
96 |
97 |
98 | ))}
99 |
100 |
101 |
102 |
103 |
104 | );
105 | };
106 |
--------------------------------------------------------------------------------
/components/navbar/NetworkSelector.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@nextui-org/button";
2 | import {
3 | Dropdown,
4 | DropdownItem,
5 | DropdownMenu,
6 | DropdownTrigger,
7 | } from "@nextui-org/dropdown";
8 | import { Network, Globe } from "lucide-react";
9 | import { useState } from "react";
10 |
11 | type NetworkType = "devnet" | "mainnet";
12 |
13 | export function NetworkSelector() {
14 | const [selectedNetwork, setSelectedNetwork] = useState(
15 | process.env.NEXT_PUBLIC_SOLANA_NETWORK as NetworkType
16 | );
17 |
18 | return (
19 |
20 |
21 |
26 | ) : (
27 |
28 | )
29 | }
30 | className="capitalize"
31 | size="sm"
32 | >
33 | {selectedNetwork}
34 |
35 |
36 |
37 | {selectedNetwork == "devnet" ? (
38 |
39 | }
42 | description="Use for testing"
43 | className="text-warning"
44 | >
45 | Devnet
46 |
47 | }
50 | description="Production network"
51 | className="text-success"
52 | href="https://solanatokenlaunchpadmainnet.vercel.app/"
53 | >
54 | Mainnet
55 |
56 |
57 | ) : (
58 |
59 | }
62 | description="Production network"
63 | className="text-success"
64 | >
65 | Mainnet
66 |
67 |
68 | }
71 | description="Use for testing"
72 | className="text-warning"
73 | href="https://solanatokenlaunchpad.vercel.app/"
74 | >
75 | Devnet
76 |
77 |
78 | )}
79 |
80 | );
81 | }
82 |
--------------------------------------------------------------------------------
/components/primitives.ts:
--------------------------------------------------------------------------------
1 | import { tv } from "tailwind-variants";
2 |
3 | export const title = tv({
4 | base: "tracking-tight inline font-semibold",
5 | variants: {
6 | color: {
7 | violet: "from-[#FF1CF7] to-[#b249f8]",
8 | yellow: "from-[#FF705B] to-[#FFB457]",
9 | blue: "from-[#5EA2EF] to-[#0072F5]",
10 | cyan: "from-[#00b7fa] to-[#01cfea]",
11 | green: "from-[#6FEE8D] to-[#17c964]",
12 | pink: "from-[#FF72E1] to-[#F54C7A]",
13 | foreground: "dark:from-[#FFFFFF] dark:to-[#4B4B4B]",
14 | },
15 | size: {
16 | sm: "text-3xl lg:text-4xl",
17 | md: "text-[2.3rem] lg:text-5xl leading-9",
18 | lg: "text-4xl lg:text-6xl",
19 | },
20 | fullWidth: {
21 | true: "w-full block",
22 | },
23 | },
24 | defaultVariants: {
25 | size: "md",
26 | },
27 | compoundVariants: [
28 | {
29 | color: [
30 | "violet",
31 | "yellow",
32 | "blue",
33 | "cyan",
34 | "green",
35 | "pink",
36 | "foreground",
37 | ],
38 | class: "bg-clip-text text-transparent bg-gradient-to-b",
39 | },
40 | ],
41 | });
42 |
43 | export const subtitle = tv({
44 | base: "w-full md:w-1/2 my-2 text-lg lg:text-xl text-default-600 block max-w-full",
45 | variants: {
46 | fullWidth: {
47 | true: "!w-full",
48 | },
49 | },
50 | defaultVariants: {
51 | fullWidth: true,
52 | },
53 | });
54 |
--------------------------------------------------------------------------------
/components/theme-switch.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { FC } from "react";
4 | import { VisuallyHidden } from "@react-aria/visually-hidden";
5 | import { SwitchProps, useSwitch } from "@nextui-org/switch";
6 | import { useTheme } from "next-themes";
7 | import { useIsSSR } from "@react-aria/ssr";
8 | import clsx from "clsx";
9 |
10 | import { SunFilledIcon, MoonFilledIcon } from "@/components/icons";
11 |
12 | export interface ThemeSwitchProps {
13 | className?: string;
14 | classNames?: SwitchProps["classNames"];
15 | }
16 |
17 | export const ThemeSwitch: FC = ({
18 | className,
19 | classNames,
20 | }) => {
21 | const { theme, setTheme } = useTheme();
22 | const isSSR = useIsSSR();
23 |
24 | const onChange = () => {
25 | theme === "light" ? setTheme("dark") : setTheme("light");
26 | };
27 |
28 | const {
29 | Component,
30 | slots,
31 | isSelected,
32 | getBaseProps,
33 | getInputProps,
34 | getWrapperProps,
35 | } = useSwitch({
36 | isSelected: theme === "light" || isSSR,
37 | "aria-label": `Switch to ${theme === "light" || isSSR ? "dark" : "light"} mode`,
38 | onChange,
39 | });
40 |
41 | return (
42 |
51 |
52 |
53 |
54 |
73 | {!isSelected || isSSR ? (
74 |
75 | ) : (
76 |
77 | )}
78 |
79 |
80 | );
81 | };
82 |
--------------------------------------------------------------------------------
/config/fonts.ts:
--------------------------------------------------------------------------------
1 | import { Fira_Code as FontMono, Inter as FontSans } from "next/font/google";
2 |
3 | export const fontSans = FontSans({
4 | subsets: ["latin"],
5 | variable: "--font-sans",
6 | });
7 |
8 | export const fontMono = FontMono({
9 | subsets: ["latin"],
10 | variable: "--font-mono",
11 | });
12 |
--------------------------------------------------------------------------------
/config/site.ts:
--------------------------------------------------------------------------------
1 | export type SiteConfig = typeof siteConfig;
2 |
3 | const selectedNetwork = process.env.NEXT_PUBLIC_SOLANA_NETWORK as
4 | | "devnet"
5 | | "mainnet";
6 |
7 | export const siteConfig = {
8 | name: "Solana Token Launchpad",
9 | description: "Launch your token on the Solana blockchain in minutes.",
10 | navItems: [
11 | {
12 | label: "Home",
13 | href: "/",
14 | },
15 | {
16 | label: "Create Token",
17 | href: "/create",
18 | },
19 | {
20 | label: "My Tokens",
21 | href: "/mint",
22 | },
23 | ...(selectedNetwork == "devnet"
24 | ? [{ label: "Airdrop", href: "/airdrop" }]
25 | : []), // Add 'Airdrop' conditionally
26 | ],
27 | navMenuItems: [
28 | {
29 | label: "Home",
30 | href: "/",
31 | },
32 | {
33 | label: "Create Token",
34 | href: "/create",
35 | },
36 | {
37 | label: "Mint Tokens",
38 | href: "/mint",
39 | },
40 | ...(selectedNetwork == "devnet"
41 | ? [{ label: "Airdrop", href: "/airdrop" }]
42 | : []),
43 | ],
44 | links: {
45 | github: "https://github.com/abhiraj2404/Token_launchpad",
46 | twitter: "https://x.com/abhiraj_2404",
47 | },
48 | };
49 |
--------------------------------------------------------------------------------
/config/solana.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Connection,
3 | Keypair,
4 | PublicKey,
5 | Signer,
6 | SystemProgram,
7 | Transaction,
8 | TransactionSignature,
9 | } from "@solana/web3.js";
10 | import {
11 | ASSOCIATED_TOKEN_PROGRAM_ID,
12 | createAssociatedTokenAccountInstruction,
13 | createInitializeMint2Instruction,
14 | createMintToInstruction,
15 | getAssociatedTokenAddressSync,
16 | getMinimumBalanceForRentExemptMint,
17 | MINT_SIZE,
18 | TOKEN_PROGRAM_ID,
19 | } from "@solana/spl-token";
20 | import {
21 | createInitializeMetadataPointerInstruction,
22 | createInitializeMintInstruction,
23 | ExtensionType,
24 | getMintLen,
25 | LENGTH_SIZE,
26 | TOKEN_2022_PROGRAM_ID,
27 | TYPE_SIZE,
28 | } from "@solana/spl-token";
29 | import {
30 | createInitializeInstruction,
31 | pack,
32 | TokenMetadata,
33 | } from "@solana/spl-token-metadata";
34 | import { TokenFormData, TokenMetadata as TokenMetadataType } from "@/types";
35 |
36 | export const getConnection = () =>
37 | new Connection(process.env.NEXT_PUBLIC_SOLANA_ENDPOINT as string, "confirmed");
38 |
39 | export async function creatingATA(
40 | connection: Connection,
41 | mint: PublicKey,
42 | owner: PublicKey,
43 | wallet: any,
44 | programId = TOKEN_2022_PROGRAM_ID,
45 | associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID,
46 | allowOwnerOffCurve = false
47 | ): Promise {
48 | const associatedToken = getAssociatedTokenAddressSync(
49 | mint,
50 | owner,
51 | allowOwnerOffCurve,
52 | programId,
53 | associatedTokenProgramId
54 | );
55 |
56 | const transaction = new Transaction().add(
57 | createAssociatedTokenAccountInstruction(
58 | owner,
59 | associatedToken,
60 | owner,
61 | mint,
62 | programId,
63 | associatedTokenProgramId
64 | )
65 | );
66 |
67 | transaction.feePayer = owner;
68 | transaction.recentBlockhash = (
69 | await connection.getLatestBlockhash()
70 | ).blockhash;
71 |
72 | await wallet.sendTransaction(transaction, connection);
73 |
74 | return associatedToken;
75 | }
76 |
77 | export async function mintTo(
78 | connection: Connection,
79 | wallet: any, // Wallet object with `sendTransaction` method
80 | mint: PublicKey,
81 | destination: PublicKey,
82 | authority: Signer | PublicKey,
83 | amount: number | bigint,
84 | multiSigners: Signer[] = [],
85 | programId = TOKEN_2022_PROGRAM_ID
86 | ): Promise {
87 | function getSigners(
88 | signerOrMultisig: Signer | PublicKey,
89 | multiSigners: Signer[]
90 | ): [PublicKey, Signer[]] {
91 | return signerOrMultisig instanceof PublicKey
92 | ? [signerOrMultisig, multiSigners]
93 | : [signerOrMultisig.publicKey, [signerOrMultisig]];
94 | }
95 |
96 | const [authorityPublicKey, signers] = getSigners(authority, multiSigners);
97 |
98 | const mintToInstruction = createMintToInstruction(
99 | mint,
100 | destination,
101 | authorityPublicKey,
102 | amount,
103 | multiSigners,
104 | programId
105 | );
106 |
107 | const transaction = new Transaction().add(mintToInstruction);
108 |
109 | // Set the recent blockhash and fee payer
110 | transaction.feePayer = wallet.publicKey;
111 | const { blockhash } = await connection.getLatestBlockhash();
112 | transaction.recentBlockhash = blockhash;
113 |
114 | // Partially sign the transaction if required
115 | if (signers.length > 0) {
116 | transaction.partialSign(...signers);
117 | }
118 |
119 | // Send the transaction using the wallet
120 | return await wallet.sendTransaction(transaction, connection);
121 | }
122 |
123 | export const createToken = async (
124 | { name, symbol, decimals, initialMintAmount }: TokenFormData,
125 | wallet: any,
126 | uri: string | null
127 | ): Promise => {
128 | const connection = getConnection();
129 |
130 | //creating mint account
131 | const mintKeypair = Keypair.generate();
132 | console.log("metadataURI", uri);
133 | //metadata
134 | const metadata: TokenMetadata = {
135 | mint: mintKeypair.publicKey,
136 | name: name,
137 | symbol: symbol,
138 | uri: uri as string,
139 | additionalMetadata: [],
140 | };
141 | const mintLen = getMintLen([ExtensionType.MetadataPointer]);
142 | const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(metadata).length;
143 | const mintLamports = await connection.getMinimumBalanceForRentExemption(
144 | mintLen + metadataLen
145 | );
146 | const mintTransaction = new Transaction().add(
147 | SystemProgram.createAccount({
148 | fromPubkey: wallet.publicKey,
149 | newAccountPubkey: mintKeypair.publicKey,
150 | space: mintLen,
151 | lamports: mintLamports,
152 | programId: TOKEN_2022_PROGRAM_ID,
153 | }),
154 | createInitializeMetadataPointerInstruction(
155 | mintKeypair.publicKey,
156 | wallet.publicKey,
157 | mintKeypair.publicKey,
158 | TOKEN_2022_PROGRAM_ID
159 | ),
160 | createInitializeMintInstruction(
161 | mintKeypair.publicKey,
162 | decimals,
163 | wallet.publicKey,
164 | null,
165 | TOKEN_2022_PROGRAM_ID
166 | ),
167 | createInitializeInstruction({
168 | programId: TOKEN_2022_PROGRAM_ID,
169 | mint: mintKeypair.publicKey,
170 | metadata: mintKeypair.publicKey,
171 | name: metadata.name,
172 | symbol: metadata.symbol,
173 | uri: metadata.uri,
174 | mintAuthority: wallet.publicKey,
175 | updateAuthority: wallet.publicKey,
176 | })
177 | );
178 | mintTransaction.feePayer = wallet.publicKey;
179 | mintTransaction.recentBlockhash = (
180 | await connection.getLatestBlockhash()
181 | ).blockhash;
182 | mintTransaction.partialSign(mintKeypair);
183 |
184 | console.log("mintTransaction", mintTransaction);
185 | await wallet.sendTransaction(mintTransaction, connection);
186 | console.log(`Token mint created at ${mintKeypair.publicKey.toBase58()}`);
187 |
188 | // const lamports = await getMinimumBalanceForRentExemptMint(connection);
189 |
190 | // const transaction = new Transaction().add(
191 | // SystemProgram.createAccount({
192 | // fromPubkey: wallet.publicKey,
193 | // newAccountPubkey: mintKeypair.publicKey,
194 | // space: MINT_SIZE,
195 | // lamports,
196 | // programId: TOKEN_PROGRAM_ID,
197 | // }),
198 | // createInitializeMint2Instruction(
199 | // mintKeypair.publicKey,
200 | // decimals,
201 | // wallet.publicKey,
202 | // wallet.publicKey,
203 | // TOKEN_PROGRAM_ID
204 | // )
205 | // );
206 |
207 | // transaction.feePayer = wallet.publicKey;
208 | // transaction.recentBlockhash = (
209 | // await connection.getLatestBlockhash()
210 | // ).blockhash;
211 | // transaction.partialSign(mintKeypair);
212 |
213 | // await wallet.sendTransaction(transaction, connection);
214 | // console.log(`Token mint created at ${mintKeypair.publicKey.toBase58()}`);
215 |
216 | //creatin associated token account
217 | const tokenAccount = await creatingATA(
218 | connection,
219 | mintKeypair.publicKey,
220 | wallet.publicKey,
221 | wallet
222 | );
223 | console.log(
224 | `Created an account for the owner of the token, here is the account ${tokenAccount.toBase58()}`
225 | );
226 |
227 | //minting tokens
228 |
229 | const mintAmount = initialMintAmount * Math.pow(10, decimals);
230 | await mintTo(
231 | connection,
232 | wallet, // Payer wallet
233 | mintKeypair.publicKey, // Mint address
234 | tokenAccount, // Destination address
235 | wallet.publicKey, // Mint authority
236 | mintAmount // Amount to mint
237 | );
238 |
239 | console.log(`Token mint created at ${mintKeypair.publicKey.toBase58()}`);
240 | console.log(`Minted ${mintAmount} tokens to ${wallet.publicKey.toBase58()}`);
241 |
242 | return {
243 | mint: mintKeypair.publicKey.toBase58(),
244 | mintAuthority: wallet.publicKey.toBase58(),
245 | name,
246 | symbol,
247 | decimals,
248 | initialMintAmount,
249 | };
250 | };
251 |
--------------------------------------------------------------------------------
/models/MintAddresses.ts:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 | import { unique } from "next/dist/build/utils";
3 |
4 | const MintAddressesSchema = new mongoose.Schema({
5 | address: {
6 | type: String,
7 | required: true,
8 | unique: true,
9 | trim: true,
10 | },
11 | });
12 |
13 | const MintAddresses =
14 | mongoose.models.MintAddresses ||
15 | mongoose.model("MintAddresses", MintAddressesSchema);
16 |
17 | export default MintAddresses;
18 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | module.exports = nextConfig;
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-app-template",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev --turbopack",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "eslint . --ext .ts,.tsx -c .eslintrc.json --fix"
10 | },
11 | "dependencies": {
12 | "@nextui-org/button": "2.2.3",
13 | "@nextui-org/card": "^2.2.7",
14 | "@nextui-org/chip": "^2.2.4",
15 | "@nextui-org/code": "2.2.3",
16 | "@nextui-org/dropdown": "^2.3.7",
17 | "@nextui-org/input": "2.4.3",
18 | "@nextui-org/kbd": "2.2.3",
19 | "@nextui-org/link": "2.2.3",
20 | "@nextui-org/listbox": "2.3.3",
21 | "@nextui-org/modal": "^2.2.5",
22 | "@nextui-org/navbar": "2.2.3",
23 | "@nextui-org/snippet": "2.2.4",
24 | "@nextui-org/spinner": "^2.2.4",
25 | "@nextui-org/switch": "2.2.3",
26 | "@nextui-org/system": "2.4.3",
27 | "@nextui-org/theme": "2.4.1",
28 | "@nextui-org/tooltip": "^2.2.5",
29 | "@react-aria/ssr": "3.9.7",
30 | "@react-aria/visually-hidden": "3.8.18",
31 | "@solana/spl-token": "^0.4.9",
32 | "@solana/spl-token-metadata": "^0.1.6",
33 | "@solana/wallet-adapter-base": "^0.9.23",
34 | "@solana/wallet-adapter-react": "^0.15.35",
35 | "@solana/wallet-adapter-react-ui": "^0.9.35",
36 | "@solana/wallet-adapter-wallets": "^0.19.32",
37 | "@solana/web3.js": "^1.98.0",
38 | "@vercel/analytics": "^1.4.1",
39 | "clsx": "2.1.1",
40 | "framer-motion": "11.13.1",
41 | "intl-messageformat": "^10.5.0",
42 | "lucide-react": "^0.468.0",
43 | "mongoose": "^8.9.1",
44 | "next": "15.0.4",
45 | "next-themes": "^0.4.4",
46 | "nextui-cli": "^0.5.0",
47 | "pinata-web3": "^0.5.3",
48 | "react": "18.3.1",
49 | "react-dom": "18.3.1"
50 | },
51 | "devDependencies": {
52 | "@next/eslint-plugin-next": "15.0.4",
53 | "@react-types/shared": "3.25.0",
54 | "@types/node": "20.5.7",
55 | "@types/react": "18.3.3",
56 | "@types/react-dom": "18.3.0",
57 | "@typescript-eslint/eslint-plugin": "8.11.0",
58 | "@typescript-eslint/parser": "8.11.0",
59 | "autoprefixer": "10.4.19",
60 | "eslint": "^8.57.0",
61 | "eslint-config-next": "15.0.4",
62 | "eslint-config-prettier": "9.1.0",
63 | "eslint-plugin-import": "^2.26.0",
64 | "eslint-plugin-jsx-a11y": "^6.4.1",
65 | "eslint-plugin-node": "^11.1.0",
66 | "eslint-plugin-prettier": "5.2.1",
67 | "eslint-plugin-react": "^7.23.2",
68 | "eslint-plugin-react-hooks": "^4.6.0",
69 | "eslint-plugin-unused-imports": "4.1.4",
70 | "postcss": "8.4.49",
71 | "prettier": "3.3.3",
72 | "tailwind-variants": "0.1.20",
73 | "tailwindcss": "3.4.16",
74 | "typescript": "5.6.3"
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/Launchpad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abhiraj2404/Token_launchpad/965d04cfc50de32b0956041115752a4730245fb5/public/Launchpad.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abhiraj2404/Token_launchpad/965d04cfc50de32b0956041115752a4730245fb5/public/favicon.ico
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const { nextui } = require("@nextui-org/theme");
2 |
3 | /** @type {import('tailwindcss').Config} */
4 | module.exports = {
5 | content: [
6 | "./components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./app/**/*.{js,ts,jsx,tsx,mdx}",
8 | "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}",
9 | ],
10 | theme: {
11 | extend: {
12 | fontFamily: {
13 | sans: [ "var(--font-sans)" ],
14 | mono: [ "var(--font-mono)" ],
15 | },
16 | },
17 | },
18 | darkMode: "class",
19 | plugins: [ nextui() ],
20 | }
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "plugins": [
18 | {
19 | "name": "next"
20 | }
21 | ],
22 | "paths": {
23 | "@/*": ["./*"]
24 | }
25 | },
26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
27 | "exclude": ["node_modules"]
28 | }
29 |
--------------------------------------------------------------------------------
/types/index.ts:
--------------------------------------------------------------------------------
1 | import { SVGProps } from "react";
2 |
3 | export type IconSvgProps = SVGProps & {
4 | size?: number;
5 | };
6 |
7 | export interface TokenFormData {
8 | name: string;
9 | symbol: string;
10 | decimals: number;
11 | initialMintAmount: number;
12 | }
13 |
14 | export interface TokenMetadata {
15 | mint: string;
16 | mintAuthority: string;
17 | name: string;
18 | symbol: string;
19 | decimals: number;
20 | initialMintAmount: number;
21 | }
22 |
23 | export interface TokenData {
24 | mint: string;
25 | name: string;
26 | symbol: string;
27 | decimals: number;
28 | totalSupply: number;
29 | imageUrl: string;
30 | mintAuthority: string;
31 | freezeAuthority: string | null;
32 | }
33 |
--------------------------------------------------------------------------------
/utils/config.ts:
--------------------------------------------------------------------------------
1 | "server only";
2 |
3 | import { PinataSDK } from "pinata-web3";
4 |
5 | export const pinata = new PinataSDK({
6 | pinataJwt: `${process.env.PINATA_JWT}`,
7 | pinataGateway: `${process.env.PINATA_GATEWAY_URL}`,
8 | });
9 |
--------------------------------------------------------------------------------
/utils/dbConnect.ts:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | type ConnectionObject = {
4 | isConnected?: number;
5 | };
6 |
7 | const connection: ConnectionObject = {};
8 |
9 | async function dbConnect(): Promise {
10 | if (connection.isConnected) {
11 | console.log("Already connected to database");
12 | return;
13 | }
14 |
15 | try {
16 | const uri =
17 | process.env.NEXT_PUBLIC_SOLANA_NETWORK == "devnet"
18 | ? process.env.MONGODB_URI
19 | : process.env.MONGODB_URI_MAINNET;
20 |
21 | console.log(uri);
22 | const db = await mongoose.connect(uri as string, {});
23 | connection.isConnected = db.connections[0].readyState;
24 | console.log("Connected to MongoDB");
25 | } catch (error) {
26 | console.log("Error connecting to database: ", error);
27 | process.exit(1);
28 | }
29 | }
30 |
31 | export default dbConnect;
32 |
--------------------------------------------------------------------------------