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: add blockchain interaction with solana #19

Merged
merged 9 commits into from
Dec 19, 2024
Merged
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
1 change: 1 addition & 0 deletions react/react-solana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@reown/appkit": "1.6.0",
"@reown/appkit-adapter-solana": "1.6.0",
"@solana/wallet-adapter-wallets": "^0.19.32",
"@solana/web3.js": "^1.95.8",
"bs58": "^6.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
Expand Down
38 changes: 8 additions & 30 deletions react/react-solana/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions react/react-solana/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ body {
overflow-x: hidden;
}

h2 {
padding-bottom: 10px;
}

body {
color: var(--foreground);
background: var(--background);
Expand Down
19 changes: 17 additions & 2 deletions react/react-solana/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createAppKit } from '@reown/appkit/react'
import { solana, solanaTestnet, solanaDevnet } from '@reown/appkit/networks'
import { useState } from 'react'
import { metadata, projectId, solanaWeb3JsAdapter } from './config'
import { ActionButtonList } from './components/ActionButtonList'
import { InfoList } from './components/InfoList'
Expand All @@ -16,21 +17,35 @@ createAppKit({
})

export function App() {
const [transactionHash, setTransactionHash] = useState<string | undefined>(undefined);
const [signedMsg, setSignedMsg] = useState('');
const [balance, setBalance] = useState('');

const receiveHash = (hash: string) => {
setTransactionHash(hash); // Update the state with the transaction hash
};

const receiveSignedMsg = (signedMsg: string) => {
setSignedMsg(signedMsg); // Update the state with the transaction hash
};

const receivebalance = (balance: string) => {
setBalance(balance)
}

return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<img src="/reown.svg" alt="Reown" style={{ width: '150px', height: '150px' }} />
<h2>Reown AppKit + Solana</h2>
<appkit-button />
<ActionButtonList />
<ActionButtonList sendHash={receiveHash} sendSignMsg={receiveSignedMsg} sendBalance={receivebalance}/>
<div className="advice">
<p>
This projectId only works on localhost. <br/>
Go to <a href="https://cloud.reown.com" target="_blank" className="link-button" rel="Reown Cloud">Reown Cloud</a> to get your own.
</p>
</div>
<InfoList />
<InfoList hash={transactionHash} signedMsg={signedMsg} balance={balance}/>
</div>
)
}
Expand Down
91 changes: 81 additions & 10 deletions react/react-solana/src/components/ActionButtonList.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,72 @@
import { useDisconnect, useAppKit, useAppKitNetwork } from '@reown/appkit/react'
import { useDisconnect, useAppKit, useAppKitNetwork, useAppKitAccount, useAppKitProvider } from '@reown/appkit/react'
import { networks } from '../config'
import type { Provider } from '@reown/appkit-adapter-solana/react'
import { useAppKitConnection } from '@reown/appkit-adapter-solana/react'
import { PublicKey, LAMPORTS_PER_SOL, Transaction, SystemProgram } from "@solana/web3.js";

export const ActionButtonList = () => {
interface ActionButtonListProps {
sendHash: (hash: string ) => void;
sendSignMsg: (hash: string) => void;
sendBalance: (balance: string) => void;
}

export const ActionButtonList = ({ sendHash, sendSignMsg, sendBalance }: ActionButtonListProps) => {
const { disconnect } = useDisconnect();
const { open } = useAppKit();
const { switchNetwork } = useAppKitNetwork();
const { isConnected, address } = useAppKitAccount()
const { connection } = useAppKitConnection();
const { walletProvider } = useAppKitProvider<Provider>('solana')


// function to send a tx
const handleSendTx = async () => {
if (!address || !connection) throw Error('user is disconnected');

const wallet = new PublicKey(address);
if (!wallet) throw Error('wallet provider is not available');

const latestBlockhash = await connection.getLatestBlockhash();

const transaction= new Transaction({
feePayer: wallet,
recentBlockhash: latestBlockhash?.blockhash,
}).add(
SystemProgram.transfer({
fromPubkey: wallet,
toPubkey: new PublicKey(address), // destination address
lamports: 1000,
})
);

const sig = await walletProvider.sendTransaction(transaction, connection)

sendHash(sig);
}

// function to sing a msg
const handleSignMsg = async () => {
if (!walletProvider || !address) throw Error('user is disconnected')

const encodedMessage = new TextEncoder().encode("Hello Reown AppKit!");
const sig = await walletProvider.signMessage(encodedMessage);

const signatureHex = Buffer.from(sig).toString("hex");
sendSignMsg(signatureHex);
}

// function to get the balance
const handleGetBalance = async () => {
if (!address || !connection) throw Error('user is disconnected');

const wallet = new PublicKey(address);
const balance = await connection?.getBalance(wallet);
if (balance !== undefined) {
sendBalance(`${balance / LAMPORTS_PER_SOL} SOL`);
} else {
sendBalance('- SOL');
}
}

const handleDisconnect = async () => {
try {
Expand All @@ -13,11 +75,20 @@ export const ActionButtonList = () => {
console.error("Failed to disconnect:", error);
}
};
return (
<div >
<button onClick={() => open()}>Open</button>
<button onClick={handleDisconnect}>Disconnect</button>
<button onClick={() => switchNetwork(networks[1]) }>Switch</button>
</div>
)
}
return (
<>
{isConnected ? (
<div >
<div >
<button onClick={() => open()}>Open</button>
<button onClick={handleDisconnect}>Disconnect</button>
<button onClick={() => switchNetwork(networks[1]) }>Switch</button>
<button onClick={handleSignMsg}>Sign msg</button>
<button onClick={handleSendTx}>Send tx</button>
<button onClick={handleGetBalance}>Get Balance</button>
</div>
</div>
) : null}
</>
);
}
30 changes: 29 additions & 1 deletion react/react-solana/src/components/InfoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import {
useWalletInfo
} from '@reown/appkit/react'

export const InfoList = () => {
interface InfoListProps {
hash: string | undefined;
signedMsg: string;
balance: string;
}

export const InfoList = ({ hash, signedMsg, balance }: InfoListProps) => {
const { themeMode, themeVariables } = useAppKitTheme();
const state = useAppKitState();
const {address, caipAddress, isConnected, status} = useAppKitAccount();
Expand All @@ -20,6 +26,28 @@ export const InfoList = () => {

return (
< >
{balance && (
<section>
<h2>Balance: {balance}</h2>
</section>
)}
{hash && (
<section>
<h2>Sign Tx</h2>
<pre>
Hash: {hash}<br />
Status: {/* receipt?.status.toString() */}<br />
</pre>
</section>
)}
{signedMsg && (
<section>
<h2>Sign msg</h2>
<pre>
signedMsg: {signedMsg}<br />
</pre>
</section>
)}
<section>
<h2>useAppKit</h2>
<pre>
Expand Down
Loading