Skip to content

Commit

Permalink
fix: add readme docs for each exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhengYuTay committed Sep 22, 2023
1 parent be78b12 commit fe867d2
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 123 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"@solana/web3.js": "^1.77.3"
},
"prettier": {
"semi": false,
"singleQuote": true,
"semi": true,
"singleQuote": false,
"trailingComma": "es5"
}
}
15 changes: 6 additions & 9 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { UnifiedWalletButton } from '@jup-ag/wallet-adapter'
import React from 'react'
import { UnifiedWalletButton } from "@jup-ag/wallet-adapter";
import React from "react";

const Header = () => {
return (
<div className="lg:fixed top-10 border-b-2 border-b-black/10 pb-2 z-50 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
<div className="border-b-2 border-b-black/10 pb-2 z-50 max-w-5xl w-full items-center justify-between font-mono text-sm flex">
<p className="flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
APU Solana Hands-on
</p>
<div className="flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
{/* <UnifiedWalletButton /> */}
</div>
</div>
)
}
);
};

export default Header
export default Header;
2 changes: 0 additions & 2 deletions src/exercises/0-requestAirdrop.tsx

This file was deleted.

14 changes: 14 additions & 0 deletions src/exercises/1-generate-keypairs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Keypair

## An account keypair used for signing transactions.

- Keypair is essentially a wallet.
- It contains a secret key and a public key.
- Secret key is like password to control your wallet.
- Pulic key is like your email address.

## Function
`Keypair.generate()` is used to generate a random keypair

## Ref
https://solana-labs.github.io/solana-web3.js/classes/Keypair.html
6 changes: 4 additions & 2 deletions src/exercises/1-generate-keypairs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Keypair } from "@solana/web3.js";
import { Dispatch, SetStateAction } from "react";

export const task = "Lesson 1 - Keypair.";

const Exercise1GenerateKeypairs: React.FC<{
keypair: Keypair | null;
setKeypair: Dispatch<SetStateAction<Keypair | null>>;
}> = ({ keypair, setKeypair }) => {
/** Exercise 1, use the Keypair class to generate a Keypair for yourself */
const generateKeypair = () => {
const newKP = Keypair.generate();
setKeypair(newKP);
const keypair = Keypair.generate();
setKeypair(keypair);
};
/** End of exercise 1 */

Expand Down
19 changes: 0 additions & 19 deletions src/exercises/1-getBalance.tsx

This file was deleted.

12 changes: 12 additions & 0 deletions src/exercises/2-airdropping/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Fund your wallet by airdrop. Only in Devnet.

## Why?

- Your wallet need Solana token to sign transaction and interact with programs.
- "Blockchain currency"

## Function
`Connection.requestAirdrop(to, lamports)` is used to request for airdrop.

## Ref
https://solana-labs.github.io/solana-web3.js/classes/Connection.html#requestAirdrop
2 changes: 2 additions & 0 deletions src/exercises/2-airdropping/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Connection, Keypair } from "@solana/web3.js";
import React, { useState } from "react";

export const task = "Lesson 2 - Airdrop. Fund your wallet.";

const Exercise2Airdropping: React.FC<{
keypair: Keypair | null;
connection: Connection;
Expand Down
14 changes: 0 additions & 14 deletions src/exercises/2-getTransactions.tsx

This file was deleted.

14 changes: 14 additions & 0 deletions src/exercises/3-getting-balances/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Remote Procedure Call (RPC)

## Why?

- RPC is the API to interact with the Solana.
- Use RPC to read token balances, sending transactions, reading transaction status, literally get any data that Solana has.
- The `Connection` object is a way for JavaScript to interact with your RPC.

## Function
To get balance:
`Connection.getBalance(pubkey)` is used to request to get SOL balance of a wallet.

## Ref
https://solana-labs.github.io/solana-web3.js/classes/Connection.html
2 changes: 2 additions & 0 deletions src/exercises/3-getting-balances/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Keypair, Connection } from "@solana/web3.js";
import React, { useEffect, useState } from "react";

export const task = "Lesson 3 - Get your wallet balance.";

const Exercise3GettingBalance: React.FC<{
keypair: Keypair | null;
connection: Connection;
Expand Down
16 changes: 16 additions & 0 deletions src/exercises/4-reading-realtime-blocks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# RPC through websocket

## Why?

- Get events realtime from Solana.
- Also using the Connection object, it establish a websocket connection to the RPC.

## Function
`Connection.onRootChange(callback)` is used to get slot changes from RPC.

`Connection.onSignature(signature, callback)` is used to understand the status of a transaction.

## Ref
https://solana-labs.github.io/solana-web3.js/classes/Connection.html#onRootChange

https://solana-labs.github.io/solana-web3.js/classes/Connection.html#onSignature
2 changes: 2 additions & 0 deletions src/exercises/4-reading-realtime-blocks/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Connection } from "@solana/web3.js";
import React, { useEffect, useState } from "react";

export const task = "Lesson 4 - Understanding websocket";

const Exercise4ReadingRealtimeBlocks: React.FC<{
connection: Connection;
}> = ({ connection }) => {
Expand Down
17 changes: 17 additions & 0 deletions src/exercises/5-sending-tokens/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Create and Send Transaction

## Why?

- To write data to the blockchain
- Example: send Solana to someone else, sending NFT, interact with Solana apps.

## Function
`SystemProgram.transfer({ fromPubkey: PublicKey; lamports: number | bigint; toPubkey: PublicKey; })` is used to craft a transaction.

`Connection.sendTransaction(transaction, signers)` is used to send transaction


## Ref
https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendTransaction

https://solana-labs.github.io/solana-web3.js/classes/SystemProgram.html
2 changes: 2 additions & 0 deletions src/exercises/5-sending-tokens/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
} from "@solana/web3.js";
import React, { useState } from "react";

export const task = "Lesson 5 - Create a transaction to send SOL";

const Exercise5SendingTokens: React.FC<{
keypair: Keypair | null;
connection: Connection;
Expand Down
153 changes: 84 additions & 69 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,113 @@
import GithubQR from '@/components/GithubQR'
import Header from '@/components/Header'
import { DEVNET_URL } from '@/constants'
import Exercise1GenerateKeypairs from '@/exercises/1-generate-keypairs'
import Exercise2Airdropping from '@/exercises/2-airdropping'
import Exercise3GettingBalance from '@/exercises/3-getting-balances'
import Exercise4ReadingRealtimeBlocks from '@/exercises/4-reading-realtime-blocks'
import Exercise5SendingTokens from '@/exercises/5-sending-tokens'
import { tasks } from '@/tasks'
import { useLocalStorage } from '@jup-ag/wallet-adapter'
import { Connection, Keypair, PublicKey } from '@solana/web3.js'
import dynamic from 'next/dynamic'
import { Inter } from 'next/font/google'
import { useEffect, useMemo } from 'react'

const inter = Inter({ subsets: ['latin'] })
import GithubQR from "@/components/GithubQR";
import Header from "@/components/Header";
import { DEVNET_URL } from "@/constants";
import Exercise1GenerateKeypairs from "@/exercises/1-generate-keypairs";
import Exercise2Airdropping from "@/exercises/2-airdropping";
import Exercise3GettingBalance from "@/exercises/3-getting-balances";
import Exercise4ReadingRealtimeBlocks from "@/exercises/4-reading-realtime-blocks";
import Exercise5SendingTokens from "@/exercises/5-sending-tokens";
import { tasks } from "@/tasks";
import { useLocalStorage } from "@jup-ag/wallet-adapter";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import dynamic from "next/dynamic";
import { Inter } from "next/font/google";
import { useEffect, useMemo } from "react";

const inter = Inter({ subsets: ["latin"] });

const Separator = () => {
return <div className="border-b my-4 border-b-black/10" />
}
return <div className="border-b my-4 border-b-black/10" />;
};

export const WRAPPED_SOL_MINT = new PublicKey(
'So11111111111111111111111111111111111111112'
)
"So11111111111111111111111111111111111111112"
);

function Home() {
const [keypair, setKeypair] = useLocalStorage<Keypair | null>(
'local-keypair',
"local-keypair",
null
)
);

const [task, setTask] = useLocalStorage('task-index', 0)
const [task, setTask] = useLocalStorage("task-index", 0);

// DO NOT DO THIS IN PRODUCTION
// DO NOT DO THIS IN PRODUCTION, for demo purposes only
useEffect(() => {
if (keypair) {
const sKeys = Uint8Array.from(
Object.values((keypair as any)._keypair.secretKey) as any
)
const regenKeypair = Keypair.fromSecretKey(sKeys)
setKeypair(regenKeypair)
);
const regenKeypair = Keypair.fromSecretKey(sKeys);
setKeypair(regenKeypair);
}
// On startup only
}, [])

const connection = useMemo(() => new Connection(DEVNET_URL, 'confirmed'), [])
}, []);

const connection = useMemo(() => new Connection(DEVNET_URL, "confirmed"), []);

const taskReactNode = useMemo(() => {
return [
<Exercise1GenerateKeypairs
key={0}
keypair={keypair}
setKeypair={setKeypair}
/>,
<Exercise2Airdropping
key={1}
keypair={keypair}
connection={connection}
/>,
<Exercise3GettingBalance
key={2}
keypair={keypair}
connection={connection}
/>,
<Exercise4ReadingRealtimeBlocks key={3} connection={connection} />,
<Exercise5SendingTokens
key={4}
keypair={keypair}
connection={connection}
/>,
];
}, [connection, keypair, setKeypair]);

return (
<main
className={`flex max-w-screen overflow-x-hidden min-h-screen flex-col items-center justify-center p-4 lg:p-24 ${inter.className}`}
>
<Header />

<div className="border rounded-lg p-2 bg-stone-700 flex items-center space-x-3">
<button
disabled={task === 0}
onClick={() => {
setTask((task) => task - 1)
}}
className="backdrop-blur-2xl rounded-xl px-4 py-2 bg-green-500 disabled:opacity-60"
>
Prev task
</button>
<span>{tasks[task]}</span>
<button
disabled={task === tasks.length - 1}
onClick={() => {
setTask((task) => task + 1)
}}
className="backdrop-blur-2xl rounded-xl px-4 py-2 bg-green-500 disabled:opacity-60"
>
Next task
</button>
</div>

<div className="mt-8 flex flex-col justify-center w-full max-w-2xl">
<Exercise1GenerateKeypairs keypair={keypair} setKeypair={setKeypair} />
<Separator />

<Exercise2Airdropping keypair={keypair} connection={connection} />
<Separator />

<Exercise3GettingBalance keypair={keypair} connection={connection} />
<Separator />

<Exercise4ReadingRealtimeBlocks connection={connection} />
<Separator />

<Exercise5SendingTokens keypair={keypair} connection={connection} />
<Separator />
<div className="flex-1">
<div className="border rounded-lg p-2 bg-slate-400 flex items-center space-x-3 mt-5">
<button
disabled={task === 0}
onClick={() => {
setTask((task) => task - 1);
}}
className="backdrop-blur-2xl rounded-xl px-4 py-2 bg-green-500 disabled:opacity-60"
>
Prev task
</button>
<span className="flex-1 text-center ">{tasks[task]}</span>
<button
disabled={task === tasks.length - 1}
onClick={() => {
setTask((task) => task + 1);
}}
className="backdrop-blur-2xl rounded-xl px-4 py-2 bg-green-500 disabled:opacity-60"
>
Next task
</button>
</div>

<div className="mt-8 flex flex-col justify-center w-full max-w-2xl">
{taskReactNode[task]}
</div>
</div>

<GithubQR />
</main>
)
);
}

export default dynamic(() => Promise.resolve(Home), { ssr: false })
export default dynamic(() => Promise.resolve(Home), { ssr: false });
Loading

0 comments on commit fe867d2

Please sign in to comment.