Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check Balance Task Done #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,583 changes: 1,886 additions & 697 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
},
"dependencies": {
"@solana/web3.js": "^1.95.2",
"axios": "^1.7.4",
"bip39": "^3.1.0",
"ed25519-hd-key": "^1.3.0",
"ethers": "^6.13.2",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tweetnacl": "^1.0.3",
Expand All @@ -25,11 +27,14 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20",
"eslint": "^9.9.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"postcss": "^8.4.41",
"tailwindcss": "^3.4.10",
"vite": "^5.4.1"
}
}
6 changes: 6 additions & 0 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
48 changes: 31 additions & 17 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
import { useState } from 'react'
import './App.css'
import { useState } from 'react';
import './App.css';
import { generateMnemonic } from "bip39";
import { SolanaWallet } from './SolanaWallet';
import { EthWallet } from './EthWallet';
import { SolanaWallet } from './components/SolanaWallet';
import EthWallet from './components/EthWallet';

function App() {
const [mnemonic, setMnemonic] = useState("");

const generateSeedPhrase = () => {
const newMnemonic = generateMnemonic();
setMnemonic(newMnemonic);
};

return (
<>
<input type="text" value={mnemonic}></input>
<button onClick={async function() {
const mn = generateMnemonic();
setMnemonic(mn)
}}>
Create Seed Phrase
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold text-center mb-8">Create Seed Phrase</h1>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={generateSeedPhrase}>
Generate Seed Phrase
</button>

{mnemonic && <SolanaWallet mnemonic={mnemonic} />}
{mnemonic && <EthWallet mnemonic={mnemonic} />}
</>
)
{mnemonic && (
<div className="mt-8">
<p className="text-lg font-semibold">Your Seed Phrase:</p>
<pre className="bg-gray-900 p-4 rounded-lg">{mnemonic}</pre>
</div>
)}
{mnemonic && (
<div className="mt-8">
<h2 className="text-2xl font-semibold">Choose a Wallet:</h2>
<div className="flex flex-col space-y-4 mt-4">
<SolanaWallet mnemonic={mnemonic} />
<EthWallet mnemonic={mnemonic} />
</div>
</div>
)}
</div>
);
}

export default App
export default App;
29 changes: 0 additions & 29 deletions src/EthWallet.jsx

This file was deleted.

27 changes: 0 additions & 27 deletions src/SolanaWallet.jsx

This file was deleted.

81 changes: 81 additions & 0 deletions src/components/EthWallet.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useState } from 'react';
import { mnemonicToSeed } from 'bip39';
import { Wallet, HDNodeWallet } from 'ethers';
import axios from 'axios';
import PropTypes from 'prop-types';

const EthWallet = ({ mnemonic }) => {
const [currentIndex, setCurrentIndex] = useState(0);
const [addresses, setAddresses] = useState([]);
const [currentBalance, setCurrentBalance] = useState({});

const addEthWallet = async () => {
// eslint-disable-next-line no-unused-vars
const seed = await mnemonicToSeed(mnemonic);
const derivationPath = `m/44'/60'/${currentIndex}'/0'`;
const hdNode = HDNodeWallet.fromSeed(seed);
const child = hdNode.derivePath(derivationPath);
const privateKey = child.privateKey;
const wallet = new Wallet(privateKey);
setCurrentIndex(currentIndex + 1);
setAddresses([...addresses, wallet.address]);
};

const checkBalance = async (address) => {
try {
const alchemyUrl = 'https://eth-mainnet.g.alchemy.com/v2/fwB2uvS6ehmDVwz6CDPZ7EBK5mR9dcK1';
const body = {
jsonrpc: '2.0',
id: 1,
method: 'eth_getBalance',
params: [address, 'latest'],
};

const response = await axios.post(alchemyUrl, body);

if (response.data.error) {
console.error('Error fetching balance:', response.data.error);
alert("ERROR OCCURED: " + response.data.error)
} else {
const hexBalance = response.data.result;
const balance = parseInt(hexBalance.toString(), 16).toString();
console.log(`Balance for address ${address}:`, balance);
setCurrentBalance((prevBalances) => ({
...prevBalances,
[address]: balance,
}));
}
} catch (error) {
console.error('Error fetching balance:', error);
}
};

return (
<div>
<button onClick={addEthWallet}>Add ETH wallet</button>

{addresses.map((address, index) => (
<div key={index} className="text-2xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-indigo-300 to-blue-900 hover:from-slate-200 hover:to-slate-500 transition-all duration-300 flex items-center">
Eth - {address}
<span className="ml-4 mt-4">
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 text-base hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded"
onClick={() => checkBalance(address)}
>
Check Balance
</button>
<span className="ml-4 mt-4" id="currentBalance">
Current Balance = {currentBalance[address] || ''}
</span>
</span>
</div>
))}
</div>
);
};

EthWallet.propTypes = {
mnemonic: PropTypes.string.isRequired,
};

export default EthWallet;
70 changes: 70 additions & 0 deletions src/components/SolanaWallet.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useState } from "react";
import PropTypes from "prop-types";
import { mnemonicToSeed } from "bip39";
import { derivePath } from "ed25519-hd-key";
import { Keypair } from "@solana/web3.js";
import nacl from "tweetnacl";
import axios from 'axios';


export function SolanaWallet({ mnemonic }) {
const [currentIndex, setCurrentIndex] = useState(0);
const [addresses, setAddresses] = useState([]);
const [currentBalance, setCurrentBalance] = useState({});


const checkBalance = async (address) => {
try {
const alchemyUrl = 'https://solana-mainnet.g.alchemy.com/v2/fwB2uvS6ehmDVwz6CDPZ7EBK5mR9dcK1';
const body = {
jsonrpc: "2.0",
id: 1,
method: "getBalance",
params: [address]
}

const response = await axios.post(alchemyUrl, body);

if (response.data.error) {
console.error('Error fetching balance:', response.data.error);
alert("ERROR OCCURED: " + response.data.error)
} else {
const balance = response.data.result.value;
// console.log(response)
console.log(`Balance for address ${address}:`, balance);
setCurrentBalance((prevBalances) => ({
...prevBalances,
[address]: balance.toString(),
}));
}
} catch (error) {
console.error('Error fetching balance:', error);
}
}
return <div>
<button onClick={async function () {
const seed = await mnemonicToSeed(mnemonic);
const path = `m/44'/501'/${currentIndex}'/0'`;
const derivedSeed = derivePath(path, seed.toString("hex")).key;
const secret = nacl.sign.keyPair.fromSeed(derivedSeed).secretKey;
const keypair = Keypair.fromSecretKey(secret);
setCurrentIndex(currentIndex + 1);
setAddresses([...addresses, keypair.publicKey]);
}}>
Add SOL wallet
</button>
{addresses.map((address, index) => <div key={index} className="text-2xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-indigo-300 to-blue-900 hover:from-slate-200 hover:to-slate-500 transition-all duration-300 flex items-center">
{address.toBase58()}
<span className="ml-4 mt-4">
<button onClick={() => checkBalance(address)} className="bg-transparent hover:bg-blue-500 text-blue-700 text-base hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded">Check Balance</button>
<span className="ml-2 mt-2" id="currentBalance">
Current Balance = {currentBalance[address] || ''}
</span>
</span>
</div>)}
</div>
}

SolanaWallet.propTypes = {
mnemonic: PropTypes.string.isRequired,
};
11 changes: 10 additions & 1 deletion src/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
Expand All @@ -18,6 +22,7 @@ a {
color: #646cff;
text-decoration: inherit;
}

a:hover {
color: #535bf2;
}
Expand Down Expand Up @@ -46,9 +51,11 @@ button {
cursor: pointer;
transition: border-color 0.25s;
}

button:hover {
border-color: #646cff;
}

button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
Expand All @@ -59,10 +66,12 @@ button:focus-visible {
color: #213547;
background-color: #ffffff;
}

a:hover {
color: #747bff;
}

button {
background-color: #f9f9f9;
}
}
}
12 changes: 12 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}

Loading