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

feat:solana gpt wallet #223

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
24 changes: 24 additions & 0 deletions examples/solana-GPT-wallet/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
50 changes: 50 additions & 0 deletions examples/solana-GPT-wallet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```

- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:

```js
// eslint.config.js
import react from 'eslint-plugin-react'

export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
})
```
11 changes: 11 additions & 0 deletions examples/solana-GPT-wallet/components/gptUI.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from "react"

const GptUi: React.FC = () => {
return (
<div>
this is gpt
</div>
)
}

export default GptUi
16 changes: 16 additions & 0 deletions examples/solana-GPT-wallet/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { WalletMultiButton } from "@solana/wallet-adapter-react-ui"
import React from "react"

const Header: React.FC = () => {
return (
<div style={{display:'flex',justifyContent:'space-between',alignItems:'center',padding:'20px 40px'}}>
<span style={{display:'flex',alignItems:'center',justifyContent:'center'}}>
<img src="/solana-logo.png" style={{width:50}} />
<img src="/gpt-logo.webp" style={{width:50}} />
</span>
<WalletMultiButton />
</div>
)
}

export default Header
18 changes: 18 additions & 0 deletions examples/solana-GPT-wallet/components/homePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Header from './header'
import WalletUi from './walletUI'
import GptUi from './gptUI'
import React from "react"

const HomePage: React.FC = () => {
return (
<div>
<Header />
<div style={{display:'flex',padding:'0 40px'}}>
<GptUi />
<WalletUi />
</div>
</div>
)
}

export default HomePage
26 changes: 26 additions & 0 deletions examples/solana-GPT-wallet/components/landingPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { WalletMultiButton } from "@solana/wallet-adapter-react-ui"
import React from "react"

const LandingPage: React.FC = () => {
return (
<div className="landing-page">
<h1>Welcome to SolGPT</h1>
<p>AI merge with the solana blockchain</p>
<p>Connect your wallet to manage assets like never before </p>
<div className="connect-btn">
<sub>connect your wallet</sub>
<WalletMultiButton>
<img src="/solana-logo.png" style={{width:20, marginRight:7}} />
Connect Wallet
</WalletMultiButton>
</div>
<span>Powered by Solana & GPT</span>
<span style={{display:'flex',alignItems:'center',justifyContent:'center'}}>
<img src="/solana-logo.png" style={{width:70}} />
<img src="/gpt-logo.webp" style={{width:70}} />
</span>
</div>
)
}

export default LandingPage
121 changes: 121 additions & 0 deletions examples/solana-GPT-wallet/components/walletUI.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useState, useEffect } from "react"
import { useConnection, useWallet } from '@solana/wallet-adapter-react'
import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'
import { useWalletStore } from '../hooks/useWalletStore'
import axios from "axios"

const DEVNET_USDC_MINT = new PublicKey('4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU')

const WalletUi: React.FC = () => {

const { connection } = useConnection();
const { publicKey, sendTransaction } = useWallet()

const [usdcBalance, setUsdcBalance] = useState<number>(0)
const { balance, setBalance, totalWalletBalance, setTotalWalletBalance, solPrice, setSolPrice } = useWalletStore()

const updateBalance = async () => {
if (!publicKey) return;
try {
const balanceLamports = await connection.getBalance(publicKey);
setBalance(balanceLamports / LAMPORTS_PER_SOL)
} catch (error) {
console.error('Error fetching SOL balance:', error);
}
};

const updateUsdcBalance = async () => {
if (!publicKey) return;
try {
// This returns all your token accounts, filtering by the devnet USDC mint
const tokenAccounts = await connection.getTokenAccountsByOwner(
publicKey,
{ mint: DEVNET_USDC_MINT }
);

if (tokenAccounts.value.length === 0) {
setUsdcBalance(0)
return
}
const accountInfo = tokenAccounts.value[0].account.data;
const rawData = Buffer.from(accountInfo);
const amountBuffer = rawData.subarray(64, 72);
const amountBn = amountBuffer.readBigUInt64LE(0);

// USDC has 6 decimals on devnet
const decimalFactor = 10n ** 6n;
const usdcAmount = Number(amountBn) / Number(decimalFactor);
setUsdcBalance(usdcAmount);
} catch (error) {
console.error('Error fetching USDC balance:', error);
setUsdcBalance(0);
}
};

const totalBalance = async () => {
const url = 'https://api.binance.com/api/v3/ticker/price'
const response = await axios.get(url, {
params: {
symbol: 'SOLUSDC'
},
})
console.log(response.data.price)
try {
const solPriceInUSD = response.data.price
console.log('sol price is ',solPriceInUSD)
console.log('sol balance is ',balance)
setSolPrice(solPriceInUSD)
const totalBal = (balance * solPriceInUSD) + (usdcBalance*1)
setTotalWalletBalance(totalBal)
} catch (error) {
console.error('error is ',error)
}
}

useEffect(()=>{
updateBalance()
updateUsdcBalance()
// totalBalance()
}, [])
useEffect(()=>{
// setTimeout(()=>totalBalance() , 1500)
},[balance])

return (
<div className="wallet-ui">
<button
onClick={() => {
updateBalance()
updateUsdcBalance()
totalBalance()
}}
style={{backgroundColor:'transparent',border:'none'}}
>
<img src="/reload.png" style={{width:30}} />
</button>
<h4>${totalWalletBalance.toFixed(2)}</h4>
<div style={{display:'flex',justifyContent:'space-between',padding:'10px 20px',borderRadius:15,backgroundColor:'rgb(42, 42, 42)',margin:'10px 0'}}>
<div style={{display:'flex',alignItems:'center',gap:10}}>
<img src="/solana-logo.png" style={{width:35,height:35}} />
<div>
<p style={{fontWeight:'700'}}>Solana</p>
<p style={{opacity:'40%'}}>{balance.toFixed(4)} sol</p>
</div>
</div>
<p style={{fontWeight:'700'}}>${balance * solPrice}</p>
</div>
<div style={{display:'flex',justifyContent:'space-between',padding:'10px 20px',borderRadius:15,backgroundColor:'rgb(42, 42, 42)',margin:'10px 0'}}>
<div style={{display:'flex',alignItems:'center',gap:10}}>
<img src="/usdc-logo.png" style={{width:35,height:35}} />
<div>
<p style={{fontWeight:'700'}}>USDC</p>
<p style={{opacity:'40%'}}>{usdcBalance.toFixed(4)} USDC</p>
</div>
</div>
<p style={{fontWeight:'700'}}>${usdcBalance * 1}</p>
</div>
</div>
)
}

export default WalletUi
25 changes: 25 additions & 0 deletions examples/solana-GPT-wallet/contexts/walletContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'
import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'
import { clusterApiUrl } from '@solana/web3.js'
import React, { useMemo } from 'react'

const WalletContext = ({ children } : React.PropsWithChildren )=>{
const network = WalletAdapterNetwork.Devnet

const endpoint = useMemo(() => clusterApiUrl(network), [network])

const wallets = useMemo( () => [], [network] )

return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
{children}
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
)
}

export default WalletContext
28 changes: 28 additions & 0 deletions examples/solana-GPT-wallet/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
19 changes: 19 additions & 0 deletions examples/solana-GPT-wallet/hooks/useWalletStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { create } from 'zustand';

interface WalletStore {
balance: number;
solPrice: number;
totalWalletBalance: number;
setBalance: (balance: number) => void;
setTotalWalletBalance: (totalWalletBalance: number) => void;
setSolPrice: (totalWalletBalance: number) => void;
}

export const useWalletStore = create<WalletStore>((set) => ({
balance: 0,
totalWalletBalance: 0,
solPrice: 0,
setBalance: (balance) => set({ balance }),
setTotalWalletBalance: (totalWalletBalance) => set({ totalWalletBalance }),
setSolPrice: (solPrice) => set({ solPrice })
}))
13 changes: 13 additions & 0 deletions examples/solana-GPT-wallet/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>solGPT</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading