├── .eslintrc.json
├── app
├── favicon.ico
├── fonts
│ ├── GeistVF.woff
│ └── GeistMonoVF.woff
├── globals.css
├── layout.tsx
└── page.tsx
├── next.config.mjs
├── postcss.config.mjs
├── tailwind.config.ts
├── .gitignore
├── tsconfig.json
├── package.json
└── README.md
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["next/core-web-vitals", "next/typescript"]
3 | }
4 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikandr-surkov/Make-TON-Telegram-Mini-App-4/HEAD/app/favicon.ico
--------------------------------------------------------------------------------
/app/fonts/GeistVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikandr-surkov/Make-TON-Telegram-Mini-App-4/HEAD/app/fonts/GeistVF.woff
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/app/fonts/GeistMonoVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikandr-surkov/Make-TON-Telegram-Mini-App-4/HEAD/app/fonts/GeistMonoVF.woff
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | colors: {
12 | background: "var(--background)",
13 | foreground: "var(--foreground)",
14 | },
15 | },
16 | },
17 | plugins: [],
18 | };
19 | export default config;
20 |
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --background: #ffffff;
7 | --foreground: #171717;
8 | }
9 |
10 | @media (prefers-color-scheme: dark) {
11 | :root {
12 | --background: #0a0a0a;
13 | --foreground: #ededed;
14 | }
15 | }
16 |
17 | body {
18 | color: var(--foreground);
19 | background: var(--background);
20 | font-family: Arial, Helvetica, sans-serif;
21 | }
22 |
23 | @layer utilities {
24 | .text-balance {
25 | text-wrap: balance;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.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 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/app/layout.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import "./globals.css";
4 | import { TonConnectUIProvider } from "@tonconnect/ui-react";
5 |
6 | export default function RootLayout({
7 | children,
8 | }: Readonly<{
9 | children: React.ReactNode;
10 | }>) {
11 | return (
12 |
13 |
14 | TON Connect Demo
15 |
16 |
17 |
18 | {children}
19 |
20 |
21 |
22 | );
23 | }
--------------------------------------------------------------------------------
/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 | "@/*": ["./*"]
22 | }
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "23-connect-ton-wallet-github",
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 | "@ton/core": "^0.57.0",
13 | "@tonconnect/sdk": "^3.0.5",
14 | "@tonconnect/ui-react": "^2.0.9",
15 | "next": "14.2.8",
16 | "react": "^18",
17 | "react-dom": "^18"
18 | },
19 | "devDependencies": {
20 | "@types/node": "^20",
21 | "@types/react": "^18",
22 | "@types/react-dom": "^18",
23 | "eslint": "^8",
24 | "eslint-config-next": "14.2.8",
25 | "postcss": "^8",
26 | "tailwindcss": "^3.4.1",
27 | "typescript": "^5"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Make TON Telegram Mini App 4: Connect TON Wallet, Display TON Wallet Address
2 |
3 | Welcome to the fourth guide in the **Make TON Telegram Mini App** series! This project demonstrates how to implement TON wallet connection functionality and display the connected wallet address in a Telegram Mini App using Next.js 14, TypeScript, and the @tonconnect/ui-react library.
4 |
5 | ## Project Overview
6 |
7 | This Telegram Mini App showcases:
8 | - Setting up a Next.js 14 project with TypeScript
9 | - Implementing TON wallet connection using @tonconnect/ui-react
10 | - Managing wallet connection state
11 | - Displaying the connected TON wallet address
12 | - Formatting and truncating the wallet address for better user experience
13 | - Basic TypeScript usage for type safety
14 |
15 | ## Prerequisites
16 |
17 | - Node.js (version 14 or higher)
18 | - npm (comes with Node.js)
19 | - A Telegram account
20 | - A Telegram Bot Token
21 | - GitHub account
22 | - Vercel account
23 |
24 | ## Getting Started
25 |
26 | 1. Clone the repository:
27 | ```
28 | git clone https://github.com/your-username/Make-TON-Telegram-Mini-App-4.git
29 | cd Make-TON-Telegram-Mini-App-4
30 | ```
31 |
32 | 2. Install dependencies:
33 | ```
34 | npm install
35 | ```
36 |
37 | ## Deployment and Usage
38 |
39 | As this is a Telegram Mini App, you can't see the result directly in development mode. Follow these steps to deploy and use the app:
40 |
41 | 1. Push your code to a GitHub repository.
42 | 2. Sign up for a Vercel account if you haven't already.
43 | 3. Connect your GitHub repository to Vercel and deploy the app.
44 | 4. Once deployed, Vercel will provide you with a URL for your app.
45 | 5. Use this URL to set up your Telegram Mini App:
46 | - Go to [@BotFather](https://t.me/BotFather) on Telegram
47 | - Send the command `/newapp` or choose to edit an existing bot
48 | - Follow the prompts to set up your Mini App, using the Vercel URL as the Web App URL
49 | 6. Once set up, you can access your Mini App through Telegram on mobile devices or in the Web version of Telegram.
50 |
51 | ## Project Structure
52 |
53 | - `app/layout.tsx`: Root layout component with TonConnectUIProvider
54 | - `app/page.tsx`: Main page component with wallet connection logic and address display
55 |
56 | ## Key Features
57 |
58 | - TON wallet connection and disconnection
59 | - Display of connected wallet address with proper formatting
60 | - Loading state management
61 | - Responsive design with Tailwind CSS
62 |
63 | ## Note on TonConnect Manifest
64 |
65 | This demo uses a TonConnect manifest hosted on IPFS. In a production application, you should host your own manifest file and update the URL in the `TonConnectUIProvider`.
66 |
67 | ## YouTube Channel
68 |
69 | For video tutorials and more in-depth explanations, check out my YouTube channel:
70 | [Nikandr Surkov](https://www.youtube.com/@NikandrSurkov)
71 |
72 | ## Next Steps
73 |
74 | Stay tuned for the next guide in the **Make TON Telegram Mini App** series, where we'll explore more advanced features and deeper TON blockchain integration!
--------------------------------------------------------------------------------
/app/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { useState, useEffect, useCallback } from 'react';
4 | import { useTonConnectUI } from '@tonconnect/ui-react';
5 | import { Address } from "@ton/core";
6 |
7 | export default function Home() {
8 | const [tonConnectUI] = useTonConnectUI();
9 | const [tonWalletAddress, setTonWalletAddress] = useState(null);
10 | const [isLoading, setIsLoading] = useState(true);
11 |
12 | const handleWalletConnection = useCallback((address: string) => {
13 | setTonWalletAddress(address);
14 | console.log("Wallet connected successfully!");
15 | setIsLoading(false);
16 | }, []);
17 |
18 | const handleWalletDisconnection = useCallback(() => {
19 | setTonWalletAddress(null);
20 | console.log("Wallet disconnected successfully!");
21 | setIsLoading(false);
22 | }, []);
23 |
24 | useEffect(() => {
25 | const checkWalletConnection = async () => {
26 | if (tonConnectUI.account?.address) {
27 | handleWalletConnection(tonConnectUI.account?.address);
28 | } else {
29 | handleWalletDisconnection();
30 | }
31 | };
32 |
33 | checkWalletConnection();
34 |
35 | const unsubscribe = tonConnectUI.onStatusChange((wallet) => {
36 | if (wallet) {
37 | handleWalletConnection(wallet.account.address);
38 | } else {
39 | handleWalletDisconnection();
40 | }
41 | });
42 |
43 | return () => {
44 | unsubscribe();
45 | };
46 | }, [tonConnectUI, handleWalletConnection, handleWalletDisconnection]);
47 |
48 | const handleWalletAction = async () => {
49 | if (tonConnectUI.connected) {
50 | setIsLoading(true);
51 | await tonConnectUI.disconnect();
52 | } else {
53 | await tonConnectUI.openModal();
54 | }
55 | };
56 |
57 | const formatAddress = (address: string) => {
58 | const tempAddress = Address.parse(address).toString();
59 | return `${tempAddress.slice(0, 4)}...${tempAddress.slice(-4)}`;
60 | };
61 |
62 | if (isLoading) {
63 | return (
64 |
65 |
66 | Loading...
67 |
68 |
69 | );
70 | }
71 |
72 | return (
73 |
74 | TON Connect Demo
75 | {tonWalletAddress ? (
76 |
77 |
Connected: {formatAddress(tonWalletAddress)}
78 |
84 |
85 | ) : (
86 |
92 | )}
93 |
94 | );
95 | }
--------------------------------------------------------------------------------