├── .env ├── .env.example ├── src ├── app │ ├── favicon.ico │ ├── fonts │ │ ├── GeistVF.woff │ │ └── GeistMonoVF.woff │ ├── layout.tsx │ ├── globals.css │ └── page.tsx ├── styles │ └── button.ts ├── components │ ├── Footer.tsx │ ├── Feature.tsx │ ├── Partners.tsx │ ├── Navbar.tsx │ ├── Pricing.tsx │ ├── Upload.tsx │ ├── Statistics.tsx │ └── Hero.tsx ├── provider │ └── SuiWalletProvider.tsx ├── util │ ├── axios.ts │ └── fasautil.ts └── api │ └── api.ts ├── public ├── assets │ ├── img │ │ ├── sui.png │ │ ├── lord.png │ │ ├── lord.webp │ │ ├── sui-bg.webp │ │ ├── hero-back.png │ │ ├── hero-back.webp │ │ ├── modal-back.png │ │ ├── Monitor the onchain, multiply profits.png │ │ ├── partner-1.svg │ │ ├── partner-5.svg │ │ ├── partner-3.svg │ │ ├── partner-2.svg │ │ └── partner-4.svg │ └── logo.svg └── font │ └── neopixel-regular.otf ├── next.config.mjs ├── postcss.config.mjs ├── next-env.d.ts ├── tsconfig.json ├── package.json ├── tailwind.config.ts └── README.md /.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_API_URL= 2 | NEXT_PUBLIC_PACKAGEID= 3 | NEXT_PUBLIC_TREASURY= 4 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_API_URL= 2 | NEXT_PUBLIC_PACKAGEID= 3 | NEXT_PUBLIC_TREASURY= -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /public/assets/img/sui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/sui.png -------------------------------------------------------------------------------- /public/assets/img/lord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/lord.png -------------------------------------------------------------------------------- /public/assets/img/lord.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/lord.webp -------------------------------------------------------------------------------- /src/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/src/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /public/assets/img/sui-bg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/sui-bg.webp -------------------------------------------------------------------------------- /src/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/src/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /public/assets/img/hero-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/hero-back.png -------------------------------------------------------------------------------- /public/assets/img/hero-back.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/hero-back.webp -------------------------------------------------------------------------------- /public/assets/img/modal-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/modal-back.png -------------------------------------------------------------------------------- /public/font/neopixel-regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/font/neopixel-regular.otf -------------------------------------------------------------------------------- /src/styles/button.ts: -------------------------------------------------------------------------------- 1 | export const button = { 2 | default: "bg-primary hover:bg-blue-700 rounded-lg active:scale-95 duration-100" 3 | } -------------------------------------------------------------------------------- /public/assets/img/Monitor the onchain, multiply profits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/Sui-nft-launchpad/HEAD/public/assets/img/Monitor the onchain, multiply profits.png -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | // components/Footer.tsx 2 | const Footer = () => { 3 | return ( 4 |
5 |

© 2024 Monitor

6 |
7 |
8 |
9 | ); 10 | }; 11 | 12 | export default Footer; 13 | -------------------------------------------------------------------------------- /src/provider/SuiWalletProvider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { WalletProvider } from "@suiet/wallet-kit"; 4 | 5 | interface SuiWalletProviderProps { 6 | children: React.ReactNode; 7 | } 8 | 9 | const SuiWalletProvider = (pros: SuiWalletProviderProps) => { 10 | return ( 11 | <> 12 | {pros.children} 13 | 14 | ); 15 | }; 16 | 17 | export default SuiWalletProvider; -------------------------------------------------------------------------------- /src/components/Feature.tsx: -------------------------------------------------------------------------------- 1 | // components/Feature.tsx 2 | type FeatureProps = { 3 | title: string; 4 | description: string; 5 | icon: string; // URL to icon 6 | }; 7 | 8 | const Feature: React.FC = ({ title, description, icon }) => { 9 | return ( 10 |
11 | {title} 12 |
13 |

{title}

14 |

{description}

15 |
16 |
17 | ); 18 | }; 19 | 20 | export default Feature; 21 | -------------------------------------------------------------------------------- /src/components/Partners.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | const Partner = () => { 4 | return ( 5 |
6 |
7 | {new Array(5).fill(" ").map((item: any, idx: number) => ( 8 | {`partner 9 | ))} 10 |
11 |

our partners

12 |
13 | ); 14 | }; 15 | 16 | export default Partner; -------------------------------------------------------------------------------- /src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { button } from "@/styles/button"; 3 | import Image from "next/image"; 4 | 5 | import { 6 | addressEllipsis, 7 | ConnectButton, 8 | ErrorCode, 9 | formatSUI, 10 | SuiChainId, 11 | useAccountBalance, 12 | useWallet, 13 | } from "@suiet/wallet-kit"; 14 | 15 | const Navbar = () => { 16 | return ( 17 | 21 | ); 22 | }; 23 | 24 | export default Navbar; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monitor", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@mysten/sui": "^1.12.0", 13 | "@nextui-org/react": "^2.4.8", 14 | "@suiet/wallet-kit": "^0.3.2", 15 | "@types/nprogress": "^0.2.3", 16 | "@types/papaparse": "^5.3.14", 17 | "axios": "^1.7.2", 18 | "framer-motion": "^11.11.9", 19 | "next": "14.2.4", 20 | "nprogress": "^0.2.0", 21 | "papaparse": "^5.4.1", 22 | "react": "^18", 23 | "react-countdown": "^2.3.6", 24 | "react-dom": "^18", 25 | "sweetalert2": "^11.14.3" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "^20", 29 | "@types/react": "^18", 30 | "@types/react-dom": "^18", 31 | "postcss": "^8", 32 | "tailwindcss": "^3.4.1", 33 | "typescript": "^5" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import localFont from "next/font/local"; 3 | import "./globals.css"; 4 | import SuiWalletProvider from "@/provider/SuiWalletProvider"; 5 | import "@suiet/wallet-kit/style.css"; 6 | import { NextUIProvider } from "@nextui-org/react"; 7 | 8 | const geistSans = localFont({ 9 | src: "./fonts/GeistVF.woff", 10 | variable: "--font-geist-sans", 11 | weight: "100 900", 12 | }); 13 | const geistMono = localFont({ 14 | src: "./fonts/GeistMonoVF.woff", 15 | variable: "--font-geist-mono", 16 | weight: "100 900", 17 | }); 18 | 19 | export const metadata: Metadata = { 20 | title: "Sui Fashion", 21 | description: "Generated by Sui Fashion", 22 | }; 23 | export default function RootLayout({ 24 | children, 25 | }: Readonly<{ 26 | children: React.ReactNode; 27 | }>) { 28 | return ( 29 | 30 | 33 | 34 | {children} 35 | 36 | 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | const {nextui} = require("@nextui-org/react"); 3 | 4 | const config: Config = { 5 | content: [ 6 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 8 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 9 | "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}", 10 | ], 11 | theme: { 12 | extend: { 13 | fontFamily: { 14 | 'neopixel': ['neopixel', 'sans-serif'], 15 | }, 16 | colors: { 17 | background: "var(--background)", 18 | foreground: "var(--foreground)", 19 | primary: { 20 | DEFAULT: "#0087ff", 21 | 100:"#0058ff" 22 | }, 23 | dark:{ 24 | DEFAULT:"#171717" 25 | } 26 | }, 27 | scale: { 28 | '101': '1.01', 29 | '99': '0.99', 30 | }, 31 | backgroundImage: { 32 | 'hero': "url('/assets/img/hero-back.png')", 33 | 'sui': "url('/assets/img/sui.png')", 34 | 'modal': "url('/assets/img/modal-back.png')", 35 | } 36 | }, 37 | }, 38 | plugins: [nextui()] 39 | }; 40 | export default config; 41 | -------------------------------------------------------------------------------- /src/components/Pricing.tsx: -------------------------------------------------------------------------------- 1 | // components/Pricing.tsx 2 | const Pricing = () => { 3 | return ( 4 |
5 |
6 |

Free

7 |

Basic plan with limited features

8 |

$0/month

9 | 10 |
11 |
12 |

Standard

13 |

Best for individuals

14 |

$99/month

15 | 16 |
17 |
18 |

Premium

19 |

Best for large teams

20 |

$199/month

21 | 22 |
23 |
24 | ); 25 | }; 26 | 27 | export default Pricing; 28 | -------------------------------------------------------------------------------- /src/util/axios.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import NProgress from 'nprogress'; 3 | 4 | NProgress.configure({ showSpinner: false }); 5 | 6 | const axiosInstance = axios.create({ 7 | // baseURL: 'https://api.theruneguardians.com/', // Replace with your API base URL 8 | timeout: 250000, // Timeout after 5 seconds 9 | headers: { 10 | 'Content-Type': 'application/json', 11 | }, 12 | }); 13 | 14 | axiosInstance.interceptors.request.use( 15 | (config) => { 16 | NProgress.start(); 17 | return config; 18 | }, 19 | (error) => { 20 | NProgress.done(); 21 | return Promise.reject(error); 22 | } 23 | ); 24 | 25 | axiosInstance.interceptors.response.use( 26 | (response) => { 27 | NProgress.done(); 28 | return response; 29 | }, 30 | (error) => { 31 | NProgress.done(); 32 | return Promise.reject(error); 33 | } 34 | ); 35 | 36 | 37 | axiosInstance.interceptors.request.use( 38 | (config) => { 39 | const token = localStorage.getItem('jwt'); 40 | if (token) { 41 | config.headers.Authorization = `Bearer ${token}`; 42 | } 43 | return config; 44 | }, 45 | ); 46 | 47 | axiosInstance.interceptors.response.use(function (response) { 48 | return response; 49 | }, function (error) { 50 | if (error.response.status === 403 || error.response.status === 404 || error.response.status === 401) { 51 | // FasaToast({ title: "Error", content: "Your session expired.", type: "error" }) 52 | // remove old cache 53 | // localStorage.clear() 54 | 55 | // localStorage.removeItem("jwt") 56 | // localStorage.removeItem("user-data") 57 | // localStorage.removeItem("wallet-session") 58 | // window.location.href = "/"; 59 | } 60 | return Promise.reject(error); 61 | }); 62 | 63 | export const ERR_BAD_REQUEST = "ERR_BAD_REQUEST" 64 | 65 | export default axiosInstance; -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | @font-face { 7 | font-family: 'neopixel'; 8 | font-style: normal; 9 | font-weight: 400; 10 | font-display: swap; 11 | src: url('/font/neopixel-regular.otf') format('otf'); 12 | } 13 | } 14 | 15 | :root { 16 | --background: #ffffff; 17 | --foreground: #171717; 18 | } 19 | 20 | @media (prefers-color-scheme: dark) { 21 | :root { 22 | --background: #0a0a0a; 23 | --foreground: #ededed; 24 | } 25 | } 26 | 27 | body { 28 | color: var(--foreground); 29 | background: var(--background); 30 | font-family: Arial, Helvetica, sans-serif; 31 | } 32 | 33 | @layer utilities { 34 | .text-balance { 35 | text-wrap: balance; 36 | } 37 | } 38 | 39 | 40 | 41 | /* styles/nprogress.css */ 42 | #nprogress .bar { 43 | background: rgb(7, 132, 250); 44 | position: fixed; 45 | z-index: 1031; 46 | top: 0; 47 | left: 0; 48 | width: 100%; 49 | height: 4px; 50 | } 51 | 52 | #nprogress .peg { 53 | display: block; 54 | position: absolute; 55 | right: 0px; 56 | width: 100px; 57 | height: 100%; 58 | box-shadow: 0 0 10px rgb(7, 104, 250), 0 0 5px rgb(7, 132, 250); 59 | opacity: 1.0; 60 | transform: rotate(3deg) translate(0px, -4px); 61 | } 62 | 63 | #nprogress .spinner { 64 | display: block; 65 | position: fixed; 66 | z-index: 1031; 67 | top: 50%; 68 | left: 50%; 69 | margin-left: -22px; 70 | margin-top: -22px; 71 | } 72 | 73 | #nprogress .spinner-icon { 74 | width: 40px; 75 | height: 40px; 76 | box-sizing: border-box; 77 | border: solid 2px transparent; 78 | border-top-color: rgb(7, 104, 250); 79 | border-left-color: rgb(7, 132, 250); 80 | border-radius: 50%; 81 | animation: nprogress-spinner 400ms linear infinite; 82 | } 83 | 84 | @keyframes nprogress-spinner { 85 | 0% { 86 | transform: rotate(0deg); 87 | } 88 | 89 | 100% { 90 | transform: rotate(360deg); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NFT Mint Launchpad on Su 2 | 3 | This is a mint launchpad designed to mint unique NFTs, featuring whitelist access for early adopters. Whitelisted users can mint a limited number of NFTs at a reduced price, ensuring an exclusive and fair minting process. 4 | 5 | ## 📚 Features 6 | 7 | - Built an interactive and responsive NFT minting platform using Next.js for the front end and Express.js for the back end. 8 | - Developed smart contracts in Move language, ensuring security and efficiency on the Sui blockchain. 9 | - Verified user eligibility for whitelist privileges, including lower minting costs and restricted token minting limits. 10 | - Randomly generated and assigned unique image traits during the minting process, ensuring every NFT is distinct. 11 | - Integrated with multiple wallet providers to enhance user accessibility and streamline transactions. 12 | - Ensured users hold 10+ SUI in their wallets before allowing transactions, adding a layer of validation. 13 | - Implemented Chart.js for a user-friendly interface to track NFT traits and wallet activity. 14 | 15 | ## 🛠️ Technology Used 16 | 17 | - Frontend: Next.js, Chart.js 18 | - Backend: Express.js, Node.js 19 | - Smart Contracts: Move (Sui blockchain) 20 | - Wallets: Sui-compatible wallets (e.g., Sui Wallet, Ethos) 21 | - Blockchain: Sui blockchain 22 | 23 | ## 🚀 How to Use 24 | 25 | ### 1. Setup 26 | 27 | - Clone the repository and install dependencies: 28 | git clone https://github.com/0xalberto/Sui-nft-launchpad.git 29 | cd nft-launchpad 30 | npm install 31 | 32 | ### 2. Run the Platform 33 | 34 | - Start the development server: 35 | npm run dev 36 | 37 | ### 3 Minting 38 | - Connect your wallet and ensure you hold 10+ SUI. 39 | - If you are on the whitelist, enjoy reduced minting fees and mint your NFTs. 40 | 41 | 42 | ### ✉ Connect With Me: 43 | 44 | [![Twitter Badge](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/0xalberto1) 45 | [![Mail Badge](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:super1114dev@gmail.com) 46 | [![Telegram Badge](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/soladity) 47 | -------------------------------------------------------------------------------- /src/components/Upload.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { useState } from 'react'; 3 | import Papa from 'papaparse'; 4 | import { Input } from '@nextui-org/react'; 5 | // import { uploadWL } from '@/api/api'; 6 | 7 | // components/Upload.tsx 8 | const Upload = () => { 9 | 10 | const [csvData, setCsvData] = useState([]); 11 | const [name, setName] = useState("") 12 | const [type, setType] = useState("") 13 | const [price, setPrice] = useState("") 14 | const [limit, setLimit] = useState("") 15 | 16 | const handleFileUpload = (event: React.ChangeEvent) => { 17 | const file = event.target.files?.[0]; 18 | 19 | if (file) { 20 | Papa.parse(file, { 21 | header: true, // Convert CSV to JSON with headers 22 | skipEmptyLines: true, 23 | complete: (results) => { 24 | setCsvData(results.data); 25 | }, 26 | }); 27 | } 28 | }; 29 | 30 | const handleSubmit = async () => { 31 | // const response = await uploadWL(csvData, name, type, price, limit) 32 | // console.log("response", response) 33 | }; 34 | 35 | return ( 36 |
37 |

Upload CSV File

38 |
39 | 48 | 49 |
50 | } 51 | onValueChange={setLimit} 52 | /> 53 | 63 | 64 | 65 | } 66 | /> 67 | 77 | SUI 78 | 79 | } 80 | /> 81 | 82 | 83 | 84 |
85 | ); 86 | }; 87 | 88 | export default Upload; 89 | -------------------------------------------------------------------------------- /src/api/api.ts: -------------------------------------------------------------------------------- 1 | import axiosInstance from "@/util/axios" 2 | 3 | export const checkWL = async (address: string) => { 4 | try { 5 | const response = await axiosInstance.post(`${process.env.NEXT_PUBLIC_API_URL}api/wl/check`, { 6 | address: address 7 | }) 8 | if (response.status === 403) { 9 | return { 10 | success: false, 11 | error: 403 12 | } 13 | } 14 | else { 15 | return response.data 16 | } 17 | } 18 | catch (error) { 19 | return { 20 | success: false, 21 | error: error 22 | } 23 | } 24 | } 25 | 26 | export const checkMintStatus = async () => { 27 | try { 28 | const response = await axiosInstance.post(`${process.env.NEXT_PUBLIC_API_URL}api/art/status`) 29 | 30 | if (response.status === 403) { 31 | return { 32 | success: false, 33 | error: 403 34 | } 35 | } 36 | else { 37 | return response.data 38 | } 39 | } 40 | catch (error) { 41 | return { 42 | success: false, 43 | error: error 44 | } 45 | } 46 | } 47 | 48 | 49 | export const getArts = async (address: string, count: number) => { 50 | try { 51 | const response = await axiosInstance.post(`${process.env.NEXT_PUBLIC_API_URL}api/art/getarts`, { address, count }) 52 | 53 | if (response.status === 403) { 54 | return { 55 | success: false, 56 | error: 403 57 | } 58 | } 59 | else { 60 | return response.data 61 | } 62 | } 63 | catch (error:any) { 64 | console.log("error!!!!") 65 | return { 66 | success: false, 67 | error: error.response.data 68 | } 69 | } 70 | } 71 | 72 | export const restoreArts = async (arts: any) => { 73 | try { 74 | const response = await axiosInstance.post(`${process.env.NEXT_PUBLIC_API_URL}api/art/restore`, { arts }) 75 | 76 | if (response.status === 403) { 77 | return { 78 | success: false, 79 | error: 403 80 | } 81 | } 82 | else { 83 | return response.data 84 | } 85 | } 86 | catch (error) { 87 | return { 88 | success: false, 89 | error: error 90 | } 91 | } 92 | } 93 | 94 | // export const uploadWL = async (data: any[], name: string, type: string, price: string, limit: string) => { 95 | // try { 96 | // const response = await axiosInstance.post(`${process.env.NEXT_PUBLIC_API_URL}api/wl/bulk-add`, { 97 | // data: data, 98 | // name: name, 99 | // type: type, 100 | // price: price, 101 | // limit: limit 102 | // }) 103 | 104 | // if (response.status === 403) { 105 | // return { 106 | // success: false, 107 | // error: 403 108 | // } 109 | // } 110 | // else { 111 | // return response.data 112 | // } 113 | // } 114 | // catch (error) { 115 | // return { 116 | // success: false, 117 | // error: error 118 | // } 119 | // } 120 | // } 121 | 122 | -------------------------------------------------------------------------------- /src/components/Statistics.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { IUserInfo } from "@/app/page"; 3 | import { useContext, useEffect, useState } from "react"; 4 | 5 | // components/Statistics.tsx 6 | const Statistics = () => { 7 | 8 | const [userInfo, setUserInfo] = useState() 9 | 10 | 11 | return ( 12 |
13 |

Whitelists

14 |
15 |
16 |
17 |
18 |

Team

19 |
20 |
21 |

SUI 0

22 |

33 Mint / Wallet

23 |
24 |
25 |
26 |
27 |
28 |
29 |

Dead y00t x BMB

30 |
31 |
32 |

SUI 0

33 |

1 Mint / Wallet

34 |

35 |
36 |
37 |
38 |
39 |
40 |
41 |

Early X

42 |
43 |
44 |

SUI 5.55

45 |

1 Mint / Wallet

46 |

47 |
48 |
49 |
50 |
51 |
52 |
53 |

Main

54 |
55 |
56 |

SUI 7.77

57 |

3 Mint / Wallet

58 |

59 |
60 |
61 |
62 |
63 |
64 |
65 |

Normal

66 |
67 |
68 |

SUI 11.11

69 |

10 Mint / Wallet

70 |

71 |
72 |
73 |
74 |
75 |
76 | ); 77 | }; 78 | 79 | export default Statistics; 80 | -------------------------------------------------------------------------------- /public/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/util/fasautil.ts: -------------------------------------------------------------------------------- 1 | export const calculateSum = (obj: any, field: any) => obj 2 | .map((items: any) => items.attributes[field]) 3 | .reduce((prev: any, curr: any) => prev + curr, 0); 4 | 5 | export const generateRandomString = (length: number) => { 6 | let result = ''; 7 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 8 | const charactersLength = characters.length; 9 | let counter = 0; 10 | while (counter < length) { 11 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 12 | counter += 1; 13 | } 14 | return result; 15 | } 16 | 17 | export const truncateText = (string: string | undefined, length: number) => { 18 | if (string) { 19 | // First 5 characters 20 | let firstFive = string.substring(0, 5); 21 | // Last 6 characters 22 | let lastSix = string.slice(-6); 23 | return `${firstFive}...${lastSix}` 24 | } 25 | return false 26 | } 27 | 28 | export const disconnectWallet = () => { 29 | // localStorage.clear() 30 | localStorage.removeItem("jwt") 31 | localStorage.removeItem("user-data") 32 | localStorage.removeItem("wallet-session") 33 | } 34 | 35 | export const msToTime = (duration: number) => { 36 | var milliseconds = Math.floor((duration % 1000) / 100), 37 | seconds = Math.floor((duration / 1000) % 60), 38 | minutes = Math.floor((duration / (1000 * 60)) % 60), 39 | hours = Math.floor((duration / (1000 * 60 * 60)) % 24); 40 | 41 | const newhours = (hours < 10) ? "0" + hours : hours; 42 | const newminutes = (minutes < 10) ? "0" + minutes : minutes; 43 | const newseconds = (seconds < 10) ? "0" + seconds : seconds; 44 | 45 | return newhours + ":" + newminutes + ":" + newseconds; 46 | } 47 | 48 | export const currentTime = () => { 49 | let date = new Date(); 50 | let now_utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 51 | date.getUTCDate(), date.getUTCHours(), 52 | date.getUTCMinutes(), date.getUTCSeconds()); 53 | return now_utc 54 | } 55 | 56 | export const numberWithCommas = (x: number | undefined) => { 57 | if (x) { 58 | return x.toString().replace(/\B(?=(\df{3})+(?!\d))/g, ","); 59 | } else return 0; 60 | } 61 | 62 | export const toDateString = (dateString: string) => { 63 | const date = new Date(dateString); 64 | const year = date.getUTCFullYear(); 65 | const month = String(date.getUTCMonth() + 1).padStart(2, '0'); 66 | const day = String(date.getUTCDate()).padStart(2, '0'); 67 | const hours = String(date.getUTCHours()).padStart(2, '0'); 68 | const minutes = String(date.getUTCMinutes()).padStart(2, '0'); 69 | 70 | const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}`; 71 | return formattedDate 72 | } 73 | 74 | export const getNextPoint = (level: number) => { 75 | const q = 1.1; 76 | const factor = 100 / (q - 1); 77 | const levelPoint = Math.round((Math.pow(q, level) - 1) * factor); 78 | return levelPoint; // In case the point exceeds the calculated levelPoint for i < 200 79 | }; 80 | 81 | export const filterAndCountItems = (arr: any, minimize: boolean): any => { 82 | const counts: { [key: string]: number } = {}; 83 | const rowIds: { [key: string]: Array } = {}; 84 | // Count occurrences of each _id 85 | arr.forEach((item: any, idx: number) => { 86 | if (counts[item.itemID._id]) { 87 | counts[item.itemID._id]++; 88 | if (rowIds[item.itemID._id]) { 89 | rowIds[item.itemID._id].push(item._id) 90 | } 91 | else { 92 | rowIds[item.itemID._id] = [item._id] 93 | } 94 | } else { 95 | counts[item.itemID._id] = 1; 96 | rowIds[item.itemID._id] = [item._id] 97 | } 98 | }); 99 | // Create the filtered array with counts 100 | let filtered; 101 | if (minimize) { 102 | filtered = Object.keys(counts).map(_id => ({ 103 | _id, 104 | userAddress: arr.find((item: any) => item.itemID._id === _id)?.userAddress || '', 105 | itemName: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemName || '', 106 | itemURL: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemURL || '', 107 | itemTRGPrice: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemTRGPrice || '', 108 | itemType: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemType, 109 | itemTRGMPrice: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemTRGMPrice || '', 110 | itemBoostTime: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemBoostTime || '', 111 | itemBoostPoint: arr.find((item: any) => item.itemID._id === _id)?.itemID.itemBoostPoint || 0, 112 | listTRGPrice: arr.find((item: any) => item.itemID._id === _id)?.listTRGPrice || 0, 113 | listflag: arr.find((item: any) => item.itemID._id === _id)?.listflag || 0, 114 | count: counts[_id], 115 | rowIds: rowIds[_id] 116 | })); 117 | } 118 | else { 119 | filtered = arr.map((item: any) => ({ 120 | _id: item._id, 121 | userAddress: item.userAddress, 122 | itemName: item.itemID.itemName || '', 123 | itemURL: item.itemID.itemURL || '', 124 | itemTRGPrice: item.itemID.itemTRGPrice || '', 125 | itemType: item.itemID.itemType, 126 | itemTRGMPrice: item.itemID.itemTRGMPrice || '', 127 | itemBoostTime: item.itemID.itemBoostTime || '', 128 | itemBoostPoint: item.itemID.itemBoostPoint || 0, 129 | listTRGPrice: item.listTRGPrice || 0, 130 | listflag: item.listflag || 0, 131 | count: 1, 132 | rowIds: [item._id] 133 | })); 134 | } 135 | 136 | 137 | return filtered; 138 | } 139 | 140 | export const updateGuideStatus = (status: any) => { 141 | localStorage.setItem("guide", JSON.stringify(status)) 142 | } 143 | 144 | export const getGuideStatus = () => { 145 | const status = localStorage.getItem("guide") 146 | if (!status) { 147 | const defaultStatus = { 148 | isNew: true, 149 | status: [ 150 | { 151 | page: "heartland", 152 | step: 0, 153 | completed: false 154 | }, 155 | { 156 | page: "marketplace", 157 | step: 1, 158 | completed: false 159 | }, 160 | { 161 | page: "profile", 162 | step: 1, 163 | completed: false 164 | }, 165 | { 166 | page: "mine", 167 | step: 0, 168 | completed: false 169 | }, 170 | { 171 | page: "game", 172 | step: 0, 173 | completed: false 174 | }, 175 | ] 176 | } 177 | localStorage.setItem('guide', JSON.stringify(defaultStatus)) 178 | return defaultStatus 179 | } 180 | else { 181 | return JSON.parse(status) 182 | } 183 | } -------------------------------------------------------------------------------- /src/components/Hero.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import Image from "next/image"; 3 | import Swal from 'sweetalert2' 4 | import { checkMintStatus, checkWL } from "@/api/api"; 5 | import { button } from "@/styles/button"; 6 | import { Transaction } from "@mysten/sui/transactions"; 7 | import { Input, Progress } from "@nextui-org/react"; 8 | import { ConnectionStatus, SuiChainId, useAccountBalance, useWallet } from "@suiet/wallet-kit"; 9 | import { useContext, useEffect, useMemo, useState } from "react"; 10 | import { IUserInfo } from "@/app/page"; 11 | 12 | 13 | 14 | // components/Hero.tsx 15 | const Hero = () => { 16 | 17 | // const { userInfo, setUserInfo } = useContext(ConnectionStatusContext) 18 | const [userInfo, setUserInfo] = useState() 19 | const [mintCount, setMintCount] = useState("0") 20 | const [totalMintCount, setTotalMintCount] = useState(0) 21 | const sampleNft = new Map([ 22 | [ 23 | "sui:devnet", 24 | "0xe146dbd6d33d7227700328a9421c58ed34546f998acdc42a1d05b4818b49faa2::nft::mint", 25 | ], 26 | [ 27 | "sui:testnet", 28 | "0xfb78d3c42533a414451990c14a5b77af7ed4037bd46bb79e192d8550f65699a7::nft::mint", 29 | ], 30 | [ 31 | "sui:mainnet", 32 | "0x5b45da03d42b064f5e051741b6fed3b29eb817c7923b83b92f37a1d2abf4fbab::nft::mint", 33 | ], 34 | ]); 35 | 36 | const wallet = useWallet(); 37 | const { balance } = useAccountBalance(); 38 | const nftContractAddr = useMemo(() => { 39 | if (!wallet.chain) return ""; 40 | wallet.account?.publicKey 41 | return sampleNft.get(wallet.chain.id) ?? ""; 42 | }, [wallet]); 43 | 44 | function uint8arrayToHex(value: Uint8Array | undefined) { 45 | if (!value) return ""; 46 | // @ts-ignore 47 | return value.toString("hex"); 48 | } 49 | 50 | async function handleExecuteMoveCall(target: string | undefined) { 51 | if (!target) return; 52 | 53 | try { 54 | if (userInfo) { 55 | const tx = new Transaction(); 56 | tx.moveCall({ 57 | target: target as any, 58 | arguments: [ 59 | tx.pure.string("Suiet NFT"), 60 | tx.pure.string( 61 | "Qmf1JH64fDWRAWr11XknKoaqyY1RiXst6JiGBJmVY7gzei/katana2.png" 62 | ), 63 | ], 64 | }); 65 | // tx.setGasPrice(3300000) 66 | tx.setGasBudget(userInfo?.price * parseInt(mintCount)) 67 | const resData = await wallet.signAndExecuteTransaction({ 68 | transaction: tx, 69 | }); 70 | console.log("executeMoveCall success", resData); 71 | alert("executeMoveCall succeeded (see response in the console)"); 72 | Swal.fire({ 73 | title: "Success!", 74 | text: `Collection Minted`, 75 | icon: "success" 76 | }) 77 | } 78 | else{ 79 | Swal.fire({ 80 | title: "Error", 81 | text: `Failed to getting user info. Please connect wallet again`, 82 | icon: "error" 83 | }) 84 | } 85 | } catch (e) { 86 | Swal.fire({ 87 | title: "Error", 88 | text: `Transaction failed`, 89 | icon: "error" 90 | }) 91 | } 92 | } 93 | 94 | // async function handleSignMsg() { 95 | // if (!wallet.account) return; 96 | // try { 97 | // const msg = "Hello world!"; 98 | // const msgBytes = new TextEncoder().encode(msg); 99 | // const result = await wallet.signPersonalMessage({ 100 | // message: msgBytes, 101 | // }); 102 | // const verifyResult = await wallet.verifySignedMessage( 103 | // result, 104 | // wallet.account.publicKey 105 | // ); 106 | // console.log("verify signedMessage", verifyResult); 107 | // if (!verifyResult) { 108 | // alert(`signMessage succeed, but verify signedMessage failed`); 109 | // } else { 110 | // alert(`signMessage succeed, and verify signedMessage succeed!`); 111 | // } 112 | // } catch (e) { 113 | // console.error("signMessage failed", e); 114 | // alert("signMessage failed (see response in the console)"); 115 | // } 116 | // } 117 | 118 | const chainName = (chainId: string | undefined) => { 119 | switch (chainId) { 120 | case SuiChainId.MAIN_NET: 121 | return "Mainnet"; 122 | case SuiChainId.TEST_NET: 123 | return "Testnet"; 124 | case SuiChainId.DEV_NET: 125 | return "Devnet"; 126 | default: 127 | return "Unknown"; 128 | } 129 | }; 130 | 131 | 132 | // async function getContractState(objectId: string) { 133 | // try { 134 | // // Fetch the contract state from the Sui network 135 | // const contractState = await provider.getObject({ 136 | // id: objectId, 137 | // options: { showContent: true }, 138 | // }); 139 | 140 | // console.log("Contract State:", contractState); 141 | // return contractState; 142 | // } catch (error) { 143 | // console.error("Error fetching contract state:", error); 144 | // } 145 | // } 146 | 147 | 148 | useEffect(() => { 149 | if (userInfo && (userInfo?.mintlimit - userInfo?.mintcount) < parseInt(mintCount)) { 150 | Swal.fire({ 151 | title: "Mint Limit reached", 152 | text: `There is mint limit. Only ${userInfo.mintlimit - userInfo.mintcount} available`, 153 | icon: "info" 154 | }); 155 | setMintCount((userInfo.mintlimit - userInfo.mintcount).toString()) 156 | } 157 | }, [mintCount]) 158 | 159 | useEffect(() => { 160 | const fetchData = async () => { 161 | const result = await checkWL(wallet.address!!) 162 | if (result) { 163 | setUserInfo(result.data) 164 | } 165 | } 166 | if (wallet.address && !userInfo) { 167 | fetchData() 168 | } 169 | }, [wallet]) 170 | 171 | useEffect(() => { 172 | 173 | const fetchData = async () => { 174 | const result = await checkMintStatus() 175 | if (result?.data?.mintCount) { 176 | setTotalMintCount(result.data.mintCount) 177 | } 178 | } 179 | fetchData() 180 | }, []) 181 | 182 | return ( 183 |
184 |
185 |

Hero image

186 |
187 |
188 |
189 | 204 |

{`${totalMintCount} / 3333`}

205 |
206 |
207 |

208 | SUI LODS 209 |

210 |
211 |

212 | Sui Fasions is a collection of 3,333 generative pfpNFT milady derivatives from the Society #VibesOrDie. 213 |

214 | Sui Fashion 215 |

216 | {userInfo?.type ? userInfo?.type === "No" ? "Not in WL" : `${userInfo?.type}` : ""} 217 |

218 |

Mint Count

219 | 229 | 230 |
231 | } 232 | endContent={ 233 |
234 | {(mintCount === '0' || !userInfo) ? 0 : parseInt(mintCount) * userInfo?.price} 235 |
236 | } 237 | /> 238 | {(userInfo && (userInfo.mintlimit - userInfo.mintcount > 0)) && } 239 | 240 |
241 | ); 242 | }; 243 | 244 | export default Hero; 245 | -------------------------------------------------------------------------------- /public/assets/img/partner-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/assets/img/partner-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/assets/img/partner-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/assets/img/partner-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { checkMintStatus, checkWL, getArts, restoreArts } from "@/api/api"; 3 | import Footer from "@/components/Footer"; 4 | import Navbar from "@/components/Navbar"; 5 | import { coinWithBalance, Transaction } from "@mysten/sui/transactions"; 6 | import { SuiChainId, useAccountBalance, useWallet } from "@suiet/wallet-kit"; 7 | import { useEffect, useMemo, useState } from "react"; 8 | import Swal from "sweetalert2"; 9 | import { Input, Progress, Spinner } from "@nextui-org/react"; 10 | import Image from "next/image"; 11 | import { button } from "@/styles/button"; 12 | import { getFullnodeUrl, SuiClient } from "@mysten/sui/client"; 13 | import { truncateText } from "@/util/fasautil"; 14 | import Countdown from "react-countdown"; 15 | 16 | 17 | export interface IUserInfo { 18 | address: string; 19 | mintcount: number; 20 | mintlimit: number; 21 | price: number; 22 | status: number; 23 | type: string; 24 | } 25 | 26 | const Home = () => { 27 | // const { userInfo, setUserInfo } = useContext(ConnectionStatusContext) 28 | const [userInfo, setUserInfo] = useState() 29 | const [mintCount, setMintCount] = useState("1") 30 | const [totalMintCount, setTotalMintCount] = useState(0) 31 | const [loading, setLoading] = useState(false) 32 | const [stage, setStage] = useState(undefined) 33 | const [timer, setTimer] = useState() 34 | const sampleNft = new Map([ 35 | [ 36 | "sui:devnet", 37 | `${process.env.NEXT_PUBLIC_PACKAGEID}::nft::mint`, 38 | ], 39 | [ 40 | "sui:testnet", 41 | `${process.env.NEXT_PUBLIC_PACKAGEID}::nft::mint`, 42 | ], 43 | [ 44 | "sui:mainnet", 45 | `${process.env.NEXT_PUBLIC_PACKAGEID}::nft::mint`, 46 | ], 47 | ]); 48 | 49 | const wallet = useWallet(); 50 | const { balance } = useAccountBalance(); 51 | const nftContractAddr = useMemo(() => { 52 | if (!wallet.chain) return ""; 53 | wallet.account?.publicKey 54 | return sampleNft.get(wallet.chain.id) ?? ""; 55 | }, [wallet]); 56 | 57 | const Toast = Swal.mixin({ 58 | toast: true, 59 | position: "top-end", 60 | showConfirmButton: false, 61 | timer: 3000, 62 | timerProgressBar: true, 63 | didOpen: (toast) => { 64 | toast.onmouseenter = Swal.stopTimer; 65 | toast.onmouseleave = Swal.resumeTimer; 66 | } 67 | }); 68 | 69 | 70 | function uint8arrayToHex(value: Uint8Array | undefined) { 71 | if (!value) return ""; 72 | // @ts-ignore 73 | return value.toString("hex"); 74 | } 75 | 76 | async function getCoinIds(address: string, coinType: string = '0x2::sui::SUI') { 77 | try { 78 | const client = new SuiClient({ 79 | url: process.env.NEXT_PUBLIC_RPC ? process.env.NEXT_PUBLIC_RPC : getFullnodeUrl('mainnet'), // Use the appropriate network 80 | }); 81 | // Query to get all coins of the specific type 82 | const coins = await client.getCoins({ 83 | owner: address, 84 | coinType: coinType, 85 | }); 86 | const sortedCoins = coins.data.sort((a: any, b: any) => b.balance - a.balance); 87 | 88 | console.log("coins", sortedCoins) 89 | 90 | // Extract and return the coin IDs 91 | const coinIds = sortedCoins.map((coin) => coin.coinObjectId); 92 | return coinIds; 93 | } catch (error) { 94 | console.error('Error fetching coin IDs:', error); 95 | return []; 96 | } 97 | } 98 | 99 | async function handleExecuteMoveCall(target: string | undefined) { 100 | if (!target) return; 101 | let pendingArts: any 102 | fetchMintStatus() 103 | try { 104 | if (userInfo && wallet.address) { 105 | setLoading(true) 106 | if (timer) 107 | clearTimeout(timer) 108 | const result = await getArts(wallet.address, parseInt(mintCount)) 109 | if (result?.success === false) { 110 | Swal.fire({ 111 | title: "Mint Limit", 112 | text: result.error.message, 113 | icon: "error" 114 | }) 115 | setLoading(false) 116 | return 117 | } 118 | pendingArts = result.data.arts 119 | const tx = new Transaction(); 120 | const client = new SuiClient({ 121 | url: process.env.NEXT_PUBLIC_RPC ? process.env.NEXT_PUBLIC_RPC : getFullnodeUrl('mainnet'), // Use the appropriate network 122 | }); 123 | // Query to get all coins of the specific type 124 | const coinid = await getCoinIds(wallet.address) 125 | 126 | // if (coinid.length === 1) { 127 | // Swal.fire({ 128 | // title: "Info", 129 | // text: `You have only one Coin Object, Let's divide it to two and mint again`, 130 | // icon: "info" 131 | // }) 132 | // const [coins] = tx.splitCoins(tx.gas, [tx.pure.u64(100000000)]); 133 | // tx.transferObjects([coins], tx.pure.address(wallet?.address)); 134 | // const resultdata = await signAndExecuteTransaction(wallet, tx, undefined) 135 | // return 136 | // } 137 | 138 | console.log("clinid", coinid) 139 | // const coinsToPay = (await client.getAllCoins({ owner: wallet?.address + '' }))?.data as any; 140 | // const CoinObj = coinsToPay.coinObjectId; 141 | 142 | // console.log("CoinObj", coinsToPay) 143 | 144 | // const newcoins2 = tx.splitCoins(tx.gas, [tx.pure(300000000)]); 145 | 146 | 147 | let nameBuffer = ["name"] 148 | let valueBuffer = ["value"] 149 | for (const att of pendingArts.attributes) { 150 | nameBuffer.push(att.trait_type) 151 | valueBuffer.push(att.value) 152 | } 153 | // const newcoins1 = tx.splitCoins(tx.gas, [tx.pure.u32(3000000000)]); 154 | // // const newcoins2 = tx.splitCoins(tx.gas, [tx.pure(300000000)]); 155 | // tx.transferObjects( 156 | // [ 157 | // newcoins1, 158 | // // newcoins2 159 | // ], 160 | // tx.pure.address(wallet.address), 161 | // ); 162 | 163 | // const buff = { 164 | // objectId: coinsToPay[0].coinObjectId, 165 | // version: coinsToPay[0].version, 166 | // digest: coinsToPay[0].digest 167 | // } 168 | // const coinbuff = [] 169 | // coinbuff.push(buff) 170 | // tx.setGasPayment(coinbuff); 171 | // tx.setGasBudget(100000000); 172 | // console.log("spilit", coins) 173 | // tx.transferObjects([coinWithBalance({ balance: 100, useGasCoin: true })], wallet.address); 174 | 175 | const [staking_contract_coin_object] = tx.splitCoins(tx.gas, [tx.pure.u64(userInfo.price > 0 ? userInfo.price * 1000000000 : 10000000)]); 176 | 177 | tx.moveCall({ 178 | target: target as any, 179 | arguments: [ 180 | tx.object(process.env.NEXT_PUBLIC_TREASURY ? process.env.NEXT_PUBLIC_TREASURY : "0x2585efbfefc26ac4c0eb76bd4404347e97df9990f15aa17d6f6a1c6d88f5ace8"), 181 | tx.object(staking_contract_coin_object), 182 | tx.object("0x6"), 183 | tx.pure.string(pendingArts.name), 184 | tx.pure.string(`QmcDxxA2N5KgC8XPAEAPUEhAVRQKhMGEEWyzPudeSBMVzy/Sui Lord %23${pendingArts.index}.png`), 185 | tx.pure.string(pendingArts.description), 186 | tx.pure.vector('string', nameBuffer), 187 | tx.pure.vector('string', valueBuffer), 188 | ], 189 | }); 190 | tx.transferObjects([staking_contract_coin_object], tx.pure.address(wallet.address)); 191 | // tx.setGasPayment(coinbuff) 192 | // tx.setGasPrice(1000000) 193 | tx.setGasBudget(10000000) 194 | // tx.setGasPrice(1000000) 195 | const resultdata = await signAndExecuteTransaction(wallet, tx, pendingArts) 196 | } 197 | else { 198 | Swal.fire({ 199 | title: "Error", 200 | text: `Failed to getting user info. Please connect wallet again`, 201 | icon: "error" 202 | }) 203 | } 204 | } catch (e) { 205 | console.log("Error", e) 206 | Swal.fire({ 207 | title: "Error", 208 | text: `Transaction failed`, 209 | icon: "error" 210 | }).then(async () => { 211 | setLoading(false) 212 | const result = await restoreArts(pendingArts) 213 | console.log("restore result", result) 214 | }) 215 | } 216 | } 217 | 218 | async function signAndExecuteTransaction(wallet: any, tx: any, pendingArts: any) { 219 | try { 220 | const response = await wallet.signAndExecuteTransaction({ 221 | transaction: tx, 222 | }); 223 | 224 | console.log("transaction response", response) 225 | // Check the transaction status 226 | if (!response.effects) { 227 | setLoading(false) 228 | console.error('Transaction failed:', response); 229 | Swal.fire({ 230 | title: "Error!", 231 | text: `Transaction failed`, 232 | icon: "error" 233 | }) 234 | if (pendingArts !== undefined) { 235 | const result = await restoreArts(pendingArts) 236 | console.log("restore result", result) 237 | } 238 | // Handle failure case here (e.g., show error message) 239 | return "error" 240 | } else { 241 | console.log('Transaction successful:', response); 242 | // Perform additional success operations here (e.g., update UI, database) 243 | Swal.fire({ 244 | title: "Transaction sent!", 245 | icon: "info" 246 | }) 247 | if (timer) 248 | clearTimeout(timer) 249 | setTimer(setTimeout(() => { 250 | fetchMintStatus() 251 | setLoading(false) 252 | }, 10000)) 253 | return "success" 254 | } 255 | } catch (error) { 256 | console.error('Error during transaction:', error); 257 | setLoading(false) 258 | // Handle errors that may occur during the signing or execution process 259 | Swal.fire({ 260 | title: "Error!", 261 | text: `Transaction failed ${error}`, 262 | icon: "error" 263 | }) 264 | if (pendingArts !== undefined) { 265 | const result = await restoreArts(pendingArts) 266 | console.log("restore result", result) 267 | } 268 | return "error" 269 | } 270 | } 271 | 272 | // async function handleSignMsg() { 273 | // if (!wallet.account) return; 274 | // try { 275 | // const msg = "Hello world!"; 276 | // const msgBytes = new TextEncoder().encode(msg); 277 | // const result = await wallet.signPersonalMessage({ 278 | // message: msgBytes, 279 | // }); 280 | // const verifyResult = await wallet.verifySignedMessage( 281 | // result, 282 | // wallet.account.publicKey 283 | // ); 284 | // console.log("verify signedMessage", verifyResult); 285 | // if (!verifyResult) { 286 | // alert(`signMessage succeed, but verify signedMessage failed`); 287 | // } else { 288 | // alert(`signMessage succeed, and verify signedMessage succeed!`); 289 | // } 290 | // } catch (e) { 291 | // console.error("signMessage failed", e); 292 | // alert("signMessage failed (see response in the console)"); 293 | // } 294 | // } 295 | 296 | const chainName = (chainId: string | undefined) => { 297 | switch (chainId) { 298 | case SuiChainId.MAIN_NET: 299 | return "Mainnet"; 300 | case SuiChainId.TEST_NET: 301 | return "Testnet"; 302 | case SuiChainId.DEV_NET: 303 | return "Devnet"; 304 | default: 305 | return "Unknown"; 306 | } 307 | }; 308 | 309 | 310 | useEffect(() => { 311 | if (userInfo && (userInfo?.mintlimit - userInfo?.mintcount) < parseInt(mintCount)) { 312 | Swal.fire({ 313 | title: "Mint Limit reached", 314 | text: `There is mint limit. Only ${userInfo.mintlimit - userInfo.mintcount} available`, 315 | icon: "info" 316 | }); 317 | setMintCount((userInfo.mintlimit - userInfo.mintcount).toString()) 318 | } 319 | }, [mintCount]) 320 | 321 | 322 | const fetchUserInfo = async () => { 323 | const result = await checkWL(wallet.address!!) 324 | console.log("result", result) 325 | if (result) { 326 | console.log("should set userinfo") 327 | setUserInfo(result.data) 328 | } 329 | } 330 | 331 | useEffect(() => { 332 | if (wallet.address) { 333 | fetchUserInfo() 334 | } 335 | }, [wallet]) 336 | 337 | 338 | const fetchMintStatus = async () => { 339 | const result = await checkMintStatus() 340 | if (result?.data) { 341 | setTotalMintCount(result.data.mintCount) 342 | setStage(result.data.stage) 343 | } 344 | else { 345 | Toast.fire({ 346 | icon: "error", 347 | title: "Connecting server failed!" 348 | }); 349 | } 350 | } 351 | 352 | useEffect(() => { 353 | fetchMintStatus() 354 | }, []) 355 | 356 | useEffect(() => { 357 | // Create a new EventSource 358 | const eventSource = new EventSource(`${process.env.NEXT_PUBLIC_API_URL}api/events`); // Adjust the path to match your SSE endpoint 359 | // Event listener for incoming messages 360 | 361 | eventSource.onmessage = (event) => { 362 | console.log("event", event.data) 363 | try { 364 | const data = JSON.parse(event.data) 365 | if (data?.totalminted) { 366 | setTotalMintCount(data.totalminted) 367 | setStage(data.stage) 368 | if (data.newMint.owner === wallet.address) { 369 | setLoading(false) 370 | } 371 | Toast.fire({ 372 | icon: "success", 373 | title: `${data.newMint.name} minted by ${truncateText(data.newMint.owner, 10)}` 374 | }); 375 | } 376 | } 377 | catch (error) { 378 | console.log("Error", error) 379 | } 380 | // setMessages((prevMessages) => [...prevMessages, event.data]); 381 | }; 382 | 383 | // Handle connection errors 384 | eventSource.onerror = (error) => { 385 | console.error('SSE connection error:', error); 386 | eventSource.close(); // Close the connection on error 387 | }; 388 | 389 | // Cleanup function to close the connection when the component unmounts 390 | return () => { 391 | eventSource.close(); 392 | }; 393 | }, [wallet]); 394 | 395 | useEffect(() => { 396 | console.log("userInfo", userInfo) 397 | }, [userInfo]) 398 | 399 | useEffect(() => { 400 | console.log("mintcount", mintCount) 401 | }, [mintCount]) 402 | 403 | return ( 404 |
405 | {/*
*/} 406 | 407 |
408 |
409 |

Hero image

410 |
411 |
412 | {/*
*/} 413 | {stage !== undefined &&
414 | {stage.stage === "No start yet" ?
415 |

Mint begins in

416 | 417 |
: 418 |
419 | 434 |

{`${totalMintCount} / 3333`}

435 |
} 436 |
} 437 |
438 |

439 | SUI Fashion 440 |

441 | {stage !== undefined &&
442 |

443 | {stage.stage !== "No start yet" ? `We are in ${stage?.stage}` : `Comming Soon`} 444 |

445 | {stage.stage !== "No start yet" &&

{stage.price} SUI / Mint

} 446 |
447 | } 448 |
449 |

450 | Collection of 3,333 generative pfpNFT milady derivatives from the Society #VibesOrDie. 451 |

452 | Sui Fashion 453 |

454 | {userInfo?.type ? userInfo?.type === "No" ? "Not in WL" : `${userInfo?.type}` : ""} 455 |

456 |

Mint Count

457 | 467 | 468 |
469 | } 470 | endContent={ 471 |
472 | {(mintCount === '0' || !userInfo) ? 0 : parseInt(mintCount) * userInfo?.price} 473 |
474 | } 475 | /> 476 | {userInfo && stage?.stage !== "No start yet" && (loading ? : )} 477 |
478 |
479 | {/* */} 480 |
481 |

Whitelists

482 |
483 |
484 |
485 |
486 |

Team

487 |
488 |
489 |

SUI 0

490 |

33 Mint / Wallet

491 |
492 |
493 |
494 | {/*
495 |
496 |
497 |

Dead y00t x BMB

498 |
499 |
500 |

SUI 0

501 |

1 Mint / Wallet

502 |

503 |
504 |
505 |
*/} 506 |
507 |
508 |
509 |

Early X

510 |
511 |
512 |

SUI 5.55

513 |

1 Mint / Wallet

514 |

515 |
516 |
517 |
518 |
519 |
520 |
521 |

Main

522 |
523 |
524 |

SUI 7.77

525 |

3 Mint / Wallet

526 |

527 |
528 |
529 |
530 |
531 |
532 |
533 |

Normal

534 |
535 |
536 |

SUI 11.11

537 |

10 Mint / Wallet

538 |

539 |
540 |
541 |
542 |
543 |
544 | {/* */} 545 |
546 |
547 | ); 548 | }; 549 | 550 | export default Home; 551 | -------------------------------------------------------------------------------- /public/assets/img/partner-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------