Skip to content

Commit

Permalink
Minor UI/UX update to include updated CSS and more functionality plac…
Browse files Browse the repository at this point in the history
…eholders
  • Loading branch information
pindaroso committed Oct 16, 2024
1 parent d530392 commit 7210ead
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 128 deletions.
4 changes: 2 additions & 2 deletions packages/app/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

@layer base {
:root {
--background: 0 0% 95%;
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
Expand Down Expand Up @@ -32,7 +32,7 @@
}

.dark {
--background: 240 0% 8.9%;
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
Expand Down
44 changes: 29 additions & 15 deletions packages/app/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { LAMPORTS_PER_SOL } from '@solana/web3.js'
import { useTheme } from 'next-themes'
import { Sun, Moon } from 'lucide-react'
import toast from 'react-hot-toast'
import Link from 'next/link'

import {
Tooltip,
Expand All @@ -25,13 +26,18 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Button } from '@/components/ui/button'

import { useWalletContext } from '@/components/providers/wallet'
import { formatAddress } from '@/lib/utils'

import AirdropButton from '@/components/buttons/airdrop'
import SendButton from '@/components/buttons/send'
import CreateMintButton from '@/components/buttons/create-mint'
import CreateCounterButton from '@/components/buttons/create-counter'
import IncrementCounterButton from '@/components/buttons/increment-counter'
import { formatAddress } from '@/lib/utils'
import DeleteCounterButton from '@/components/buttons/delete-counter'
import DecrementCounterButton from '@/components/buttons/decrement-counter'
import CalculateCostButton from '@/components/buttons/calculate-cost'

const defaultNetwork =
process.env.NODE_ENV === 'development' ? 'localnet' : 'devnet'
Expand All @@ -48,9 +54,6 @@ export default function Home() {
const [network, setNetwork] = useState(defaultNetwork)
const [networkActive, setNetworkActive] = useState(false)
const [walletConnected, setWalletConnected] = useState(false)
const [route, setRoute] = useState<'cost' | 'counter' | 'mint' | 'faucet'>(
'cost'
)

useEffect(() => {
if (publicKey && !walletConnected) {
Expand Down Expand Up @@ -93,11 +96,13 @@ export default function Home() {
<nav className="p-4">
<div className="flex justify-between items-center">
<div className="flex items-center gap-6 text-zinc-700 dark:text-zinc-300 cursor-pointer">
<h1 className="text-primary text-lg">Solana ZK Starter</h1>
<div onClick={() => setRoute('cost')}>Cost Calculator</div>
<div onClick={() => setRoute('counter')}>Counter Program</div>
<div onClick={() => setRoute('mint')}>Mint</div>
<div onClick={() => setRoute('faucet')}>Faucet</div>
<Link href="/" className="text-primary text-lg">
Solana ZK Starter
</Link>
<Link href="#/cost">Cost Calculator</Link>
<Link href="#/counter">Counter Program</Link>
<Link href="#/mint">Mint</Link>
<Link href="#/faucet">Faucet</Link>
</div>
<div className="flex items-center">
{publicKey ? (
Expand Down Expand Up @@ -217,24 +222,33 @@ export default function Home() {
</nav>
<main className="flex-grow">
<div className="flex flex-col max-w-md mx-auto p-4 gap-2">
{route === 'cost' && (
<div className="flex flex-col mt-2 text-center">Coming Soon</div>
{window.location.hash === '#/cost' && (
<CalculateCostButton className="flex flex-col mt-2" />
)}
{route === 'faucet' && (
{window.location.hash === '#/faucet' && (
<AirdropButton className="flex flex-col mt-2" />
)}
{route === 'mint' && (
{window.location.hash === '#/mint' && (
<>
<SendButton className="flex flex-col mt-2" />
<CreateMintButton className="flex flex-col mt-2" />
<SendButton className="flex flex-col mt-2" />
</>
)}
{route === 'counter' && (
{window.location.hash === '#/counter' && (
<>
<CreateCounterButton className="flex flex-col mt-2" />
<IncrementCounterButton className="flex flex-col mt-2" />
<DecrementCounterButton className="flex flex-col mt-2" />
<DeleteCounterButton className="flex flex-col mt-2" />
</>
)}
{window.location.hash === '' && (
<div className="flex flex-col mt-2">
<h1 className="text-primary text-xl text-center">
Solana ZK Starter
</h1>
</div>
)}
</div>
</main>
<footer className="p-4">
Expand Down
34 changes: 34 additions & 0 deletions packages/app/src/components/buttons/calculate-cost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useWallet } from '@solana/wallet-adapter-react'
import { FC, useCallback } from 'react'
import { WalletNotConnectedError } from '@solana/wallet-adapter-base'
import toast from 'react-hot-toast'

import { useWalletContext } from '@/components/providers/wallet'
import { Button } from '@/components/ui/button'

export const CalculateCostButton: FC<{ className?: string }> = ({
className,
}) => {
const { publicKey } = useWallet()
const { endpoint } = useWalletContext()

const onClick = useCallback(async () => {
if (!publicKey) throw new WalletNotConnectedError()

try {
// TODO: Implement
toast.error('Not Implemented')
} catch (error: any) {
console.error(error)
toast.error(`Increment Failed: ${error.message}`)
}
}, [publicKey, endpoint])

return (
<Button onClick={onClick} disabled={!publicKey} className={className}>
Upload File
</Button>
)
}

export default CalculateCostButton
186 changes: 94 additions & 92 deletions packages/app/src/components/buttons/create-counter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,98 +55,100 @@ export const CreateCounterButton: FC<{ className?: string }> = ({
if (!wallet) throw new WalletNotConnectedError()
if (!program) throw new ProgramNotInitializedError()

try {
// TODO: Adapt for devnet, testnet and mainnet
const rpc = createRpc()

const { addressTree, addressQueue, nullifierQueue } =
defaultTestStateTreeAccounts()

const seed = deriveAddressSeed(
[Buffer.from('counter'), wallet.publicKey.toBuffer()],
program.programId
)
const address = await deriveAddress(seed, addressTree)
const compressedAccount = createCompressedAccount(
wallet.publicKey,
bn(10),
undefined,
[10]
)

const selectedAccounts: CompressedAccountWithMerkleContext[] = [
{
...compressedAccount,
readOnly: true,
merkleTree: addressTree,
nullifierQueue,
hash: [bn(address.toBytes()).toNumber()],
leafIndex: 0,
},
]

/*
* ERROR: Failed to get ValidityProof for compressed accounts 36439686636752871256271152024530679660001424812964160093210165672697738154: Record Not Found: Leaf nodes not found for hashes. Got 0 hashes. Expected 1.
*/
const { compressedProof, rootIndices } = await rpc.getValidityProof(
selectedAccounts.map(({ hash }) => bn(hash[0])),
[bn(address.toBytes())]
)

// TODO: Add input?
const inputs: Buffer[] = []

// TODO: Use LUT to get indices?
const merkleContext = {
merkleTreePubkeyIndex: 0,
nullifierQueuePubkeyIndex: 0,
leafIndex: 0,
queueIndex: null,
}
const addressMerkleContext = {
addressMerkleTreePubkeyIndex: 0,
addressQueuePubkeyIndex: 0,
}
const merkleTreeRootIndex = 0
const addressMerkleTreeRootIndex = rootIndices[0]

const [registeredProgramPda] = PublicKey.findProgramAddressSync(
[LightSystemProgram.programId.toBuffer()],
new PublicKey(accountCompressionProgram)
)

const [accountCompressionAuthority] = PublicKey.findProgramAddressSync(
[Buffer.from('cpi_authority')],
new PublicKey(LightSystemProgram.programId)
)

const tx = await program.methods
.create(
inputs,
compressedProof,
merkleContext,
merkleTreeRootIndex,
addressMerkleContext,
addressMerkleTreeRootIndex
)
.accounts({
signer: wallet.publicKey,
lightSystemProgram: LightSystemProgram.programId,
accountCompressionProgram,
accountCompressionAuthority,
registeredProgramPda,
noopProgram,
selfProgram: program.programId,
cpiSigner: wallet.publicKey,
systemProgram: SystemProgram.programId,
})
.rpc()

toast.success(`Tx Success: ${tx}`)
} catch (error: any) {
console.error(error)
toast.error(`Creation Failed: ${error.message}`)
}
toast.error('Not Implemented')

//try {
// // TODO: Adapt for devnet, testnet and mainnet
// const rpc = createRpc()

// const { addressTree, addressQueue, nullifierQueue } =
// defaultTestStateTreeAccounts()

// const seed = deriveAddressSeed(
// [Buffer.from('counter'), wallet.publicKey.toBuffer()],
// program.programId
// )
// const address = await deriveAddress(seed, addressTree)
// const compressedAccount = createCompressedAccount(
// wallet.publicKey,
// bn(10),
// undefined,
// [10]
// )

// const selectedAccounts: CompressedAccountWithMerkleContext[] = [
// {
// ...compressedAccount,
// readOnly: true,
// merkleTree: addressTree,
// nullifierQueue,
// hash: [bn(address.toBytes()).toNumber()],
// leafIndex: 0,
// },
// ]

// /*
// * ERROR: Failed to get ValidityProof for compressed accounts 36439686636752871256271152024530679660001424812964160093210165672697738154: Record Not Found: Leaf nodes not found for hashes. Got 0 hashes. Expected 1.
// */
// const { compressedProof, rootIndices } = await rpc.getValidityProof(
// selectedAccounts.map(({ hash }) => bn(hash[0])),
// [bn(address.toBytes())]
// )

// // TODO: Add input?
// const inputs: Buffer[] = []

// // TODO: Use LUT to get indices?
// const merkleContext = {
// merkleTreePubkeyIndex: 0,
// nullifierQueuePubkeyIndex: 0,
// leafIndex: 0,
// queueIndex: null,
// }
// const addressMerkleContext = {
// addressMerkleTreePubkeyIndex: 0,
// addressQueuePubkeyIndex: 0,
// }
// const merkleTreeRootIndex = 0
// const addressMerkleTreeRootIndex = rootIndices[0]

// const [registeredProgramPda] = PublicKey.findProgramAddressSync(
// [LightSystemProgram.programId.toBuffer()],
// new PublicKey(accountCompressionProgram)
// )

// const [accountCompressionAuthority] = PublicKey.findProgramAddressSync(
// [Buffer.from('cpi_authority')],
// new PublicKey(LightSystemProgram.programId)
// )

// const tx = await program.methods
// .create(
// inputs,
// compressedProof,
// merkleContext,
// merkleTreeRootIndex,
// addressMerkleContext,
// addressMerkleTreeRootIndex
// )
// .accounts({
// signer: wallet.publicKey,
// lightSystemProgram: LightSystemProgram.programId,
// accountCompressionProgram,
// accountCompressionAuthority,
// registeredProgramPda,
// noopProgram,
// selfProgram: program.programId,
// cpiSigner: wallet.publicKey,
// systemProgram: SystemProgram.programId,
// })
// .rpc()

// toast.success(`Tx Success: ${tx}`)
//} catch (error: any) {
// console.error(error)
// toast.error(`Creation Failed: ${error.message}`)
//}
}, [wallet, endpoint, program])

return (
Expand Down
34 changes: 34 additions & 0 deletions packages/app/src/components/buttons/decrement-counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useWallet } from '@solana/wallet-adapter-react'
import { FC, useCallback } from 'react'
import { WalletNotConnectedError } from '@solana/wallet-adapter-base'
import toast from 'react-hot-toast'

import { useWalletContext } from '@/components/providers/wallet'
import { Button } from '@/components/ui/button'

export const DecrementCounterButton: FC<{ className?: string }> = ({
className,
}) => {
const { publicKey } = useWallet()
const { endpoint } = useWalletContext()

const onClick = useCallback(async () => {
if (!publicKey) throw new WalletNotConnectedError()

try {
// TODO: Implement
toast.error('Not Implemented')
} catch (error: any) {
console.error(error)
toast.error(`Increment Failed: ${error.message}`)
}
}, [publicKey, endpoint])

return (
<Button onClick={onClick} disabled={!publicKey} className={className}>
Decrement Counter
</Button>
)
}

export default DecrementCounterButton
Loading

0 comments on commit 7210ead

Please sign in to comment.