Skip to content

Commit

Permalink
added airdrop and balance func
Browse files Browse the repository at this point in the history
  • Loading branch information
NoumaanAhamed committed Aug 30, 2024
1 parent 6eb6870 commit 27b81c8
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 35 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Refer to the [ansi wallet adapter](https://github.com/anza-xyz/wallet-adapter/blob/master/APP.md) for more information.

# React + Vite Using Bun

```sh
Expand All @@ -6,7 +8,7 @@ bun install
bun run dev
```

## Install dependencies
## Install dependencies for solana wallet adapter

```sh
bun add @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets @solana/web3.js
Expand All @@ -18,3 +20,7 @@ bun add @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-
- [ ] Show SOL balances (GET data from the blockchain)
- [ ] Send a transaction (Send a transaction to the blockchain)
- [ ] Sign a message (Verify the ownership of the wallet)

## Flow :

Dapp -> Requests transaction -> Wallet Adapter -> Wallet -> Signs transaction -> Solana Blockchain
113 changes: 85 additions & 28 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,42 +1,99 @@
#root {
max-width: 1280px;
margin: 0 auto;
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}

.app-container {
display: flex;
flex-direction: column;
min-height: 100vh;
}

.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background-color: #1a1a1a;
color: white;
}

.navbar-brand {
font-size: 1.5rem;
font-weight: bold;
}

.navbar-wallet-buttons {
display: flex;
gap: 1rem;
}

.main-content {
flex: 1;
padding: 2rem;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}

.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
.airdrop-container {
max-width: 400px;
width: 100%;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);

.airdrop-container h2 {
margin-bottom: 20px;
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);

.airdrop-container input {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}

.airdrop-container button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
.airdrop-container button:hover {
background-color: #45a049;
}

@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
.airdrop-container button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}

.card {
padding: 2em;
.status {
margin-top: 10px;
padding: 10px;
border-radius: 4px;
}

.read-the-docs {
color: #888;
.status.success {
background-color: #d4edda;
color: #155724;
}

.status.error {
background-color: #f8d7da;
color: #721c24;
}

.loading {
margin-top: 10px;
text-align: center;
color: #666;
}
58 changes: 52 additions & 6 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,60 @@
import './App.css'
import { useMemo } from "react";
import {
ConnectionProvider,
WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import {
WalletModalProvider,
WalletDisconnectButton,
WalletMultiButton,
} from "@solana/wallet-adapter-react-ui";
import { clusterApiUrl } from "@solana/web3.js";

// Default styles that can be overridden by your app
import "@solana/wallet-adapter-react-ui/styles.css";
import AirDrop from "./components/AirDrop";

import "./App.css";
import WalletBalance from "./components/WalletBalance";

function App() {
const network = WalletAdapterNetwork.Devnet;

// Use custom RPC endpoint
const endpoint = useMemo(
() =>
"https://solana-devnet.g.alchemy.com/v2/yU6R0UHZibbX7Q92cpYxmg5dwOe9IcHG",
[]
);

// Fallback to clusterApiUrl if custom endpoint fails
const fallbackEndpoint = useMemo(() => clusterApiUrl(network), [network]);

return (
<>
<div>
Hi there
</div>
<ConnectionProvider endpoint={endpoint || fallbackEndpoint}>
<WalletProvider wallets={[]} autoConnect>
<WalletModalProvider>
<div className="app-container">
<nav className="navbar">
<div className="navbar-brand">Solana Airdrop App</div>
<div className="navbar-wallet-buttons">
<WalletMultiButton />
<WalletDisconnectButton />
</div>
</nav>
<main className="main-content">
<h1>Welcome to MC Solana Airdrop</h1>
<WalletBalance />
<AirDrop />
</main>
</div>
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
</>
)
);
}

export default App
export default App;
78 changes: 78 additions & 0 deletions src/components/AirDrop.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useState } from "react";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";

const AirDrop = () => {
const { connection } = useConnection();
const { publicKey } = useWallet();
const [address, setAddress] = useState("");
const [amount, setAmount] = useState(1);
const [status, setStatus] = useState("");
const [isLoading, setIsLoading] = useState(false);

const handleAirdrop = async () => {
setStatus("");
setIsLoading(true);
try {
let pubKey = publicKey;
if (address) {
pubKey = new PublicKey(address);
} else if (!publicKey) {
throw new Error("Please connect your wallet or enter an address.");
}

// eslint-disable-next-line no-unused-vars
const signature = await connection.requestAirdrop(
pubKey,
amount * LAMPORTS_PER_SOL
);

// await connection.confirmTransaction({
// signature: signature,
// });

setStatus(`Success! Airdropped ${amount} SOL to ${pubKey.toBase58()}`);
} catch (error) {
setStatus(`Error: ${error.message}`);
} finally {
setIsLoading(false);
}
};

return (
<div className="airdrop-container">
<h2>Solana Airdrop</h2>
<input
type="text"
placeholder="Solana address (optional)"
value={address}
onChange={(e) => setAddress(e.target.value)}
disabled={isLoading}
/>
<input
type="number"
placeholder="Amount (SOL)"
value={amount}
onChange={(e) => setAmount(parseFloat(e.target.value))}
min="0.1"
step="0.1"
disabled={isLoading}
/>
<button onClick={handleAirdrop} disabled={isLoading}>
{isLoading ? "Processing..." : "Request Airdrop"}
</button>
{isLoading && (
<div className="loading">Processing airdrop request...</div>
)}
{status && (
<div
className={`status ${status.includes("Error") ? "error" : "success"}`}
>
{status}
</div>
)}
</div>
);
};

export default AirDrop;
43 changes: 43 additions & 0 deletions src/components/WalletBalance.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useState, useEffect } from "react";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";

const WalletBalance = () => {
const { connection } = useConnection();
const { publicKey } = useWallet();
const [balance, setBalance] = useState(null);

useEffect(() => {
const fetchBalance = async () => {
if (!publicKey) {
setBalance(null);
return;
}

try {
const walletBalance = await connection.getBalance(publicKey);
setBalance(walletBalance / LAMPORTS_PER_SOL);
} catch (error) {
console.error("Error fetching balance:", error);
setBalance(null);
}
};

fetchBalance();
// Set up an interval to fetch the balance every 10 seconds
const intervalId = setInterval(fetchBalance, 10000);

// Clean up the interval when the component unmounts
return () => clearInterval(intervalId);
}, [connection, publicKey]);

if (balance === null) {
return <div className="wallet-balance">Wallet not connected</div>;
}

return (
<div className="wallet-balance">Balance: {balance.toFixed(4)} SOL</div>
);
};

export default WalletBalance;

0 comments on commit 27b81c8

Please sign in to comment.