diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/.env b/single-factor-auth-web/sfa-web-ton-telegram-example/.env index 761fcabc..6f0ca220 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/.env +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/.env @@ -1,4 +1,2 @@ VITE_SERVER_URL="http://localhost:3000" # server-url -VITE_W3A_VERIFIER_NAME="" # w3a-verifier-name -VITE_W3A_CLIENT_ID="" # w3a-client-id from web3auth dashboard NODE_ENV="development" \ No newline at end of file diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/.env.example b/single-factor-auth-web/sfa-web-ton-telegram-example/.env.example index 0a8173e5..05bd6365 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/.env.example +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/.env.example @@ -1,3 +1,2 @@ VITE_SERVER_URL="" # server-url -VITE_W3A_VERIFIER_NAME="" # w3a-verifier-name -VITE_W3A_CLIENT_ID="" # w3a-client-id from web3auth dashboard \ No newline at end of file +NODE_ENV="" # development (if testing, only then mocking of Telegram MiniApp env will work) \ No newline at end of file diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/README.md b/single-factor-auth-web/sfa-web-ton-telegram-example/README.md index 9ef6835b..7cbd8b0d 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/README.md +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/README.md @@ -3,67 +3,55 @@ [![Web3Auth](https://img.shields.io/badge/Web3Auth-SDK-blue)](https://web3auth.io/docs/sdk/core-kit/sfa-web) [![Web3Auth](https://img.shields.io/badge/Web3Auth-Community-cyan)](https://community.web3auth.io) -[Join our Community Portal](https://community.web3auth.io/) to get support and stay up to date with the latest news and updates. +This example demonstrates how to use Web3Auth with Telegram Login in a React-Vite frontend with an Express backend. The server handles Telegram OAuth and issues JWT tokens for the Web3Auth SDK. -This example demonstrates how to use Web3Auth with Telegram Login in a React Vite frontend. Express is used to create the Telegram OAuth server that issues JWT tokens for the Web3Auth SDK. +Check out our detailed guides to help you build and integrate Web3Auth into your Telegram Mini App: +- [Server-Side Setup Guide](https://web3auth.io/docs/guides/telegram-miniapp-server) - Learn to set up authentication, JWT tokens, and user sessions +- [Client-Side Development Guide](https://web3auth.io/docs/guides/telegram-miniapp-client) - Implement frontend integration with Telegram UI and Web3Auth -## How to Use +## Quick Start Guide -### Download Manually +### Download the Example ```bash -npx degit Web3Auth/web3auth-core-kit-examples/single-factor-auth-web/sfa-web-telegram-example w3a-sfa-web-telegram-example +npx degit Web3Auth/web3auth-core-kit-examples/single-factor-auth-web/sfa-web-ton-telegram-example w3a-sfa-web-ton-telegram-example ``` -### Setup - -1. Create a `.env` file in the `server/api` directory with the following content: +### Server Configuration +1. Create a `.env` file in the `server/api` directory: ```bash -TELEGRAM_BOT_NAME="" # e.g. @your_bot_name -TELEGRAM_BOT_TOKEN="" # e.g. 1234567890:ABCDEF -SERVER_URL="" # e.g. http://localhost:3000 -CLIENT_URL="" # e.g. http://localhost:5173 -JWT_KEY_ID="" # e.g. your_key_id +TELEGRAM_BOT_TOKEN="" # Token provided by BotFather upon bot creation +JWT_KEY_ID="" # Create one using https://web3auth.io/docs/auth-provider-setup/byo-jwt-provider#generate-jwt +APP_URL="" # Your frontend URL (e.g., http://localhost:5173) ``` -2. Create a `.env.local` file in the root directory with the following content: +### Client Configuration +1. Create a `.env.local` file in the root directory: ```bash -VITE_SERVER_URL="" # e.g. http://localhost:3000 -VITE_W3A_VERIFIER_NAME="" # e.g. w3a-telegram-demo -VITE_W3A_CLIENT_ID="" # e.g. your_client_id +VITE_SERVER_URL="" # Your server URL (e.g., http://localhost:3000) ``` -Follow [this Telegram guide](https://web3auth.io/docs/guides/telegram) to follow along. - -Install & Run: +### Installation & Running +Start the server: ```bash cd w3a-example/server npm install -## start server -# server will be running on localhost:8080 -cd api -node index.js -# use ngrok to expose the server to the internet -# ngrok http 3000 -# copy the ngrok url and update the SERVER_URL in the .env file -# also update the telegram bot domain to the ngrok url - +npm run start # Server runs on localhost:3000 +``` -## now, start the client +Start the client: +```bash cd .. npm install -npm run start -# client will be running on localhost:5173 +npm run start # Client runs on localhost:5173 ``` -## Important Links +## Resources -- [Website](https://web3auth.io) -- [Docs](https://web3auth.io/docs) -- [Guides](https://web3auth.io/docs/guides) -- [SDK / API References](https://web3auth.io/docs/sdk) -- [Pricing](https://web3auth.io/pricing.html) +- [Documentation](https://web3auth.io/docs) - [Community Portal](https://community.web3auth.io) + +[Join our Community Portal](https://community.web3auth.io/) to get support and stay up to date with the latest news and updates. \ No newline at end of file diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/.env.example b/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/.env.example index c7a8568c..3444e01a 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/.env.example +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/.env.example @@ -1,5 +1,3 @@ -TELEGRAM_BOT_NAME="" TELEGRAM_BOT_TOKEN="" -SERVER_URL="" -CLIENT_URL="" -JWT_KEY_ID="" \ No newline at end of file +JWT_KEY_ID="" +APP_URL="" \ No newline at end of file diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/telegram.js b/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/telegram.js index fdcb3da1..13ad9869 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/telegram.js +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/server/api/telegram.js @@ -1,3 +1,4 @@ +// Custom Webhook for Telegram Bot for replying to /start command import { Telegraf } from "telegraf"; export default async function handler(req, res) { diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.css b/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.css index 8a4ef1c6..798c686d 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.css +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.css @@ -504,3 +504,20 @@ body { padding: 12px 0; } } + +.swipe-instructions { + font-size: 0.85rem; + font-weight: 500; + text-align: center; + color: var(--text-color); + opacity: 0.8; + margin-bottom: 8px; + background: var(--hover-bg); + padding: 6px 12px; + border-radius: 8px; + transition: opacity 0.3s ease; +} + +.swipe-instructions:hover { + opacity: 1; +} diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.tsx b/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.tsx index 60bd5066..4f627192 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.tsx +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/src/App.tsx @@ -157,17 +157,19 @@ const CopyableContent = ({ content, type, isTouchDevice }: { content: string; ty const ChainSwitcher = ({ selectedChain, onChainSelect, + isLoading, }: { selectedChain: keyof typeof CHAINS; onChainSelect: (chain: keyof typeof CHAINS) => void; + isLoading: boolean; }) => { const { platform } = useLaunchParams() || {}; const isTouchDevice = ["android", "android_x", "ios", "weba"].includes(platform || ""); return isTouchDevice ? ( - + ) : ( - + ); }; @@ -175,9 +177,11 @@ const ChainSwitcher = ({ const TouchChainSwitcher = ({ selectedChain, onChainSelect, + isLoading, }: { selectedChain: keyof typeof CHAINS; onChainSelect: (chain: keyof typeof CHAINS) => void; + isLoading: boolean; }) => { const containerRef = useRef(null); const [touchStart, setTouchStart] = useState(0); @@ -211,11 +215,14 @@ const TouchChainSwitcher = ({ if ("vibrate" in navigator) { navigator.vibrate(50); } - onChainSelect(chain as keyof typeof CHAINS); + if (!isLoading) { + onChainSelect(chain as keyof typeof CHAINS); + } }; return (
+

Swipe to switch chains

void; + isLoading: boolean; }) => { const [isOpen, setIsOpen] = useState(false); const handleSelect = (chain: keyof typeof CHAINS) => { - onChainSelect(chain); - setIsOpen(false); + if (!isLoading) { + onChainSelect(chain); + setIsOpen(false); + } }; return (
-
- +
{userData ? ( diff --git a/single-factor-auth-web/sfa-web-ton-telegram-example/src/RPC/solanaRPC.ts b/single-factor-auth-web/sfa-web-ton-telegram-example/src/RPC/solanaRPC.ts index e61efae0..921162c5 100644 --- a/single-factor-auth-web/sfa-web-ton-telegram-example/src/RPC/solanaRPC.ts +++ b/single-factor-auth-web/sfa-web-ton-telegram-example/src/RPC/solanaRPC.ts @@ -18,14 +18,20 @@ export default class SolanaRPC extends BaseRPC { SolanaRPC.instance = new SolanaRPC(provider); await SolanaRPC.instance.initialize(); } + if (!SolanaRPC.instance.solanaWallet) { + throw new Error("Solana wallet failed to initialize"); + } return SolanaRPC.instance; } private async initialize(): Promise { try { - const privateKey = await this.provider.request({ method: "private_key" }) as string; - if (!privateKey) throw new Error('Private key not found'); - + const privateKey = (await this.provider.request({ method: "private_key" })) as string; + if (!privateKey) throw new Error("Private key not found"); + + const ed25519key = getED25519Key(privateKey).sk.toString("hex"); + if (!ed25519key) throw new Error("Invalid ED25519 key generated"); + this.solanaProvider = new SolanaPrivateKeyProvider({ config: { chainConfig: { @@ -39,8 +45,7 @@ export default class SolanaRPC extends BaseRPC { }, }, }); - - const ed25519key = getED25519Key(privateKey).sk.toString("hex"); + await this.solanaProvider.setupProvider(ed25519key); this.solanaWallet = new SolanaWallet(this.solanaProvider); } catch (error) { @@ -70,11 +75,13 @@ export default class SolanaRPC extends BaseRPC { async getBalance(): Promise> { return this.handleRPCCall(async () => { const address = (await this.getAccounts()).data; - + + if (!address) throw new Error("Failed to retrieve Solana address"); + const publicKey = new PublicKey(address); // Ensure address is valid + const connection = new Connection(this.solanaProvider.config.chainConfig.rpcTarget); - - const balance = await connection.getBalance(new PublicKey(address)); - + + const balance = await connection.getBalance(publicKey); return balance.toString(); }); }