Skip to content

Commit a271679

Browse files
authored
Gold Farmers-Entropy example (#9)
1 parent f74a00a commit a271679

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+61343
-0
lines changed

entropy/growing/app/.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

entropy/growing/app/.gitignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
.yarn/install-state.gz
8+
9+
# testing
10+
/coverage
11+
12+
# next.js
13+
/.next/
14+
/out/
15+
16+
# production
17+
/build
18+
19+
# misc
20+
.DS_Store
21+
*.pem
22+
23+
# debug
24+
npm-debug.log*
25+
yarn-debug.log*
26+
yarn-error.log*
27+
28+
# local env files
29+
.env*.local
30+
31+
# vercel
32+
.vercel
33+
34+
# typescript
35+
*.tsbuildinfo
36+
next-env.d.ts

entropy/growing/app/.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"endOfLine": "lf",
3+
"semi": false,
4+
"singleQuote": false,
5+
"tabWidth": 2,
6+
"trailingComma": "es5",
7+
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-tailwindcss"]
8+
}

entropy/growing/app/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Pyth Entropy Example
2+
3+
This Next.js project demonstrates a basic use case of Pyth Entropy by integrating it into a web application to simulate the growth process of NFTs. The application features frontend components and hooks to interact with smart contracts, handle state changes, and respond to events.
4+
5+
## Features
6+
7+
- **Minting NFTs**: Users can mint new NFTs.
8+
- **Growing NFTs**: Users can request to grow their NFTs based on randomness provided by the Pyth network.
9+
- **Event Watching**: The application listens to contract events to update UI accordingly.
10+
11+
## Development Setup
12+
13+
### Prerequisites
14+
15+
- Node.js installed on your machine.
16+
- Bun installed for fast package management.
17+
- Farmiliarity with Next.js, Wagmi.sh, Tailwind, Shad.cn and React Query
18+
19+
### Installation
20+
21+
Clone the repository and install the dependencies:
22+
23+
```bash
24+
bun i
25+
```
26+
27+
### Running the Development Server
28+
29+
To start the development server, run:
30+
31+
```bash
32+
bun dev
33+
```
34+
35+
This will start the server on `http://localhost:3000`, and you can view your application in the browser.
36+
37+
## Acknowledgments
38+
39+
This example of using Pyth Entropy was created by [lualabs.xyz](https://lualabs.xyz).
40+
41+
We hope this starter example inspires you to continue innovating and building creative solutions with NFTs.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"use client"
2+
3+
import { Button } from "@/components/ui/button"
4+
import {
5+
Select,
6+
SelectContent,
7+
SelectItem,
8+
SelectTrigger,
9+
SelectValue,
10+
} from "@/components/ui/select"
11+
import { Loader2 } from "lucide-react"
12+
import { useGrow } from "../hooks/use-grow"
13+
14+
export const Grow = () => {
15+
const {
16+
tokens,
17+
setTokenId,
18+
grow,
19+
isLoading,
20+
info,
21+
tokenId,
22+
isSuccess,
23+
growResult,
24+
reset,
25+
} = useGrow()
26+
27+
return (
28+
<div className="flex flex-col items-center justify-center space-y-4">
29+
{isSuccess && growResult && (
30+
<>
31+
<div>{growResult.growResult}</div>
32+
<Button className="w-full" onClick={reset}>
33+
Continue
34+
</Button>
35+
</>
36+
)}
37+
{isSuccess && !growResult && <Loader2 className="animate-spin" />}
38+
{!isSuccess && !growResult && (
39+
<>
40+
<Select onValueChange={setTokenId}>
41+
<SelectTrigger disabled={isLoading} className="w-full">
42+
<SelectValue placeholder="Select NFT" />
43+
</SelectTrigger>
44+
<SelectContent>
45+
{tokens.map(({ label, value }, index) => {
46+
return (
47+
<SelectItem key={`${index}_${label}`} value={value}>
48+
{label}
49+
</SelectItem>
50+
)
51+
})}
52+
</SelectContent>
53+
</Select>
54+
<Button className="w-full" disabled={isLoading} onClick={grow}>
55+
Grow
56+
</Button>
57+
{tokenId !== "" && (
58+
<div className="text-left">
59+
<div>Level: {info.level}</div>
60+
<div>Status: {info.status}</div>
61+
</div>
62+
)}
63+
{tokenId === "" && <div className="h-[40px]"></div>}
64+
</>
65+
)}
66+
</div>
67+
)
68+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"use client"
2+
3+
import { Button } from "@/components/ui/button"
4+
import { useMint } from "../hooks/use-mint"
5+
6+
export const Mint = () => {
7+
const { mint, isLoading } = useMint()
8+
return (
9+
<Button
10+
className="w-full"
11+
disabled={isLoading}
12+
onClick={mint}
13+
>{`Mint${isLoading ? "ing..." : ""}`}</Button>
14+
)
15+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { NFTGrowtthAddress } from "@/contracts/addresses"
2+
import { useReadNftGrowthNftInfo } from "@/contracts/generated"
3+
import { useMemo } from "react"
4+
5+
export const useGetTokenInfo = (tokenId?: string) => {
6+
const { data: info, refetch } = useReadNftGrowthNftInfo({
7+
address: NFTGrowtthAddress,
8+
args: [BigInt(tokenId!)],
9+
query: {
10+
enabled: tokenId !== "",
11+
},
12+
})
13+
14+
const level = useMemo(() => {
15+
return info?.[0].toString()
16+
}, [info])
17+
18+
const status = useMemo(() => {
19+
if (info?.[1] !== undefined) {
20+
return info?.[1] === 0 ? "Alive" : "Dead"
21+
}
22+
}, [info])
23+
24+
return {
25+
refetch,
26+
info: { level, status },
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { NFTGrowtthAddress } from "@/contracts/addresses"
2+
import { useReadNftGrowthTokensOfOwner } from "@/contracts/generated"
3+
import { useMemo } from "react"
4+
import { blastSepolia } from "viem/chains"
5+
import { useAccount } from "wagmi"
6+
7+
export const useGetTokens = () => {
8+
const { address } = useAccount()
9+
const { data } = useReadNftGrowthTokensOfOwner({
10+
address: NFTGrowtthAddress,
11+
chainId: blastSepolia.id,
12+
args: [address!],
13+
query: {
14+
enabled: !!address,
15+
},
16+
})
17+
18+
const tokens = useMemo(() => {
19+
return (
20+
data?.map((tokenId) => ({
21+
value: tokenId.toString(),
22+
label: `#${tokenId.toString()}`,
23+
})) || []
24+
)
25+
}, [data])
26+
27+
return { tokens }
28+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { NFTGrowtthAddress } from "@/contracts/addresses"
2+
import { useWatchNftGrowthEvent } from "@/contracts/generated"
3+
import { useCallback, useReducer } from "react"
4+
5+
type Result = "Success" | "Failure" | "Death"
6+
7+
export interface GrowResult {
8+
tokenId: string
9+
growResult: Result
10+
}
11+
12+
type State = {
13+
growResult?: GrowResult
14+
}
15+
16+
type Action =
17+
| { type: "SET_NFT_RESULT"; payload: GrowResult }
18+
| { type: "RESET" }
19+
20+
function reducer(state: State, action: Action): State {
21+
switch (action.type) {
22+
case "SET_NFT_RESULT":
23+
return { ...state, growResult: action.payload }
24+
case "RESET":
25+
return {}
26+
default:
27+
return state
28+
}
29+
}
30+
31+
export const useGrowResult = (currentTokenId: string) => {
32+
const [state, dispatch] = useReducer(reducer, {})
33+
34+
const handleGrowEvent = useCallback(
35+
(event: any) => {
36+
const { tokenId, result } = event[0].args
37+
if (
38+
tokenId &&
39+
tokenId.toString() === currentTokenId &&
40+
result !== undefined
41+
) {
42+
dispatch({
43+
type: "SET_NFT_RESULT",
44+
payload: {
45+
tokenId: tokenId.toString(),
46+
growResult: getNFTResult(result),
47+
},
48+
})
49+
}
50+
},
51+
[currentTokenId]
52+
)
53+
54+
useWatchNftGrowthEvent({
55+
address: NFTGrowtthAddress,
56+
onLogs: handleGrowEvent,
57+
})
58+
59+
const resetResult = useCallback(() => dispatch({ type: "RESET" }), [])
60+
61+
return { ...state, resetResult }
62+
}
63+
64+
export const getNFTResult = (result: number): Result => {
65+
switch (result) {
66+
case 0:
67+
return "Success"
68+
case 1:
69+
return "Failure"
70+
default:
71+
return "Death"
72+
}
73+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { NFTGrowtthAddress } from "@/contracts/addresses"
2+
import {
3+
useReadNftGrowthGetGrowFee,
4+
useWriteNftGrowthGrow,
5+
} from "@/contracts/generated"
6+
import { useCallback, useState } from "react"
7+
import { blastSepolia } from "viem/chains"
8+
import { useWaitForTransactionReceipt } from "wagmi"
9+
import * as web3 from "web3"
10+
import { useGetTokenInfo } from "./use-get-token-info"
11+
import { useGetTokens } from "./use-get-tokens"
12+
import { useGrowResult } from "./use-grow-result"
13+
14+
export const useGrow = () => {
15+
const [tokenId, setTokenId] = useState("")
16+
const { tokens } = useGetTokens()
17+
const { resetResult, growResult } = useGrowResult(tokenId)
18+
const { info, refetch } = useGetTokenInfo(tokenId)
19+
20+
const {
21+
data: hash,
22+
writeContract,
23+
isPending,
24+
reset: resetGrow,
25+
isSuccess,
26+
} = useWriteNftGrowthGrow()
27+
const { data: price } = useReadNftGrowthGetGrowFee({
28+
address: NFTGrowtthAddress,
29+
})
30+
31+
const grow = useCallback(() => {
32+
const randomNumber = web3.utils.randomHex(32) as `0x${string}`
33+
writeContract({
34+
address: NFTGrowtthAddress,
35+
chainId: blastSepolia.id,
36+
value: price,
37+
args: [BigInt(tokenId), randomNumber],
38+
})
39+
}, [writeContract, tokenId, price])
40+
41+
const { isLoading } = useWaitForTransactionReceipt({ hash })
42+
43+
const reset = useCallback(() => {
44+
resetResult()
45+
resetGrow()
46+
refetch()
47+
}, [resetResult, resetGrow, refetch])
48+
49+
return {
50+
grow,
51+
isLoading: isPending || isLoading || isSuccess,
52+
setTokenId,
53+
tokens,
54+
info,
55+
tokenId,
56+
growResult,
57+
isSuccess,
58+
reset,
59+
}
60+
}

0 commit comments

Comments
 (0)