Skip to content

Commit a732e91

Browse files
committed
custom rpc
1 parent 8d968b0 commit a732e91

File tree

4 files changed

+173
-13
lines changed

4 files changed

+173
-13
lines changed

entropy/mint-nft/ui/app/page.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ import { Badge } from "@/components/ui/badge"
1111
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
1212
import { Alert, AlertDescription } from "@/components/ui/alert"
1313
import { WalletConnectButton } from "@/components/wallet-connect-button"
14+
import { RPCInput } from "@/components/rpc-input"
1415
import { InteractiveFlowDiagram } from "@/components/interactive-flow-diagram"
1516
import { ThemeToggle } from "@/components/theme-toggle"
1617
import { useEntropyBeasts } from "@/hooks/use-entropy-beasts"
17-
import { useWalletClient } from "wagmi"
18+
import { useWalletClient, useAccount } from "wagmi"
1819

1920
type NFTSize = "small" | "big"
2021

@@ -40,9 +41,11 @@ const NFT_CONFIGS: Record<NFTSize, NFTConfig> = {
4041
export default function PythentropyNFTDemo() {
4142
const [gasLimit, setGasLimit] = useState("50000")
4243
const [nftSize, setNftSize] = useState<NFTSize>("small")
44+
const [rpcUrl, setRpcUrl] = useState("https://base-sepolia.drpc.org")
45+
const { isConnected } = useAccount()
4346

4447
// Real contract hook
45-
const { mint, isMinting, mintSequenceNumber, mintError, isListening, transactionHash, callbackCompleted, revealedEvent } = useEntropyBeasts()
48+
const { mint, isMinting, mintSequenceNumber, mintError, isListening, transactionHash, callbackCompleted, revealedEvent } = useEntropyBeasts(rpcUrl)
4649

4750
const handleNFTSizeChange = (size: NFTSize) => {
4851
setNftSize(size)
@@ -96,6 +99,9 @@ export default function PythentropyNFTDemo() {
9699
<WalletConnectButton />
97100
</div>
98101

102+
{/* RPC Configuration */}
103+
<RPCInput onRPCSet={setRpcUrl} isConnected={isConnected} />
104+
99105
{/* Disclaimer */}
100106
<div className="max-w-2xl mx-auto mb-4">
101107
<Alert className="border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/20">

entropy/mint-nft/ui/components/interactive-flow-diagram.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,17 @@ export function InteractiveFlowDiagram({
3434
if (isRealMinting || hasSequenceNumber) {
3535
switch (step) {
3636
case "entropy-beasts":
37-
if (isRealMinting || hasSequenceNumber) return "active"
37+
// Only active during minting, not after sequence number is received
38+
if (isRealMinting && !hasSequenceNumber) return "active"
3839
return "inactive"
3940

4041
case "pyth-entropy":
41-
if (hasSequenceNumber) return "active"
42+
// Only active when we have sequence number but not listening yet
43+
if (hasSequenceNumber && !isListening) return "active"
4244
return "inactive"
4345

4446
case "provider":
47+
// Only active when we have sequence number but not listening yet
4548
if (hasSequenceNumber && !isListening) return "active"
4649
if (hasSequenceNumber && isListening) return "processing"
4750
return "inactive"
@@ -96,9 +99,12 @@ export function InteractiveFlowDiagram({
9699
if (isRealMinting || hasSequenceNumber) {
97100
switch (arrow) {
98101
case "forward1":
99-
return isRealMinting || hasSequenceNumber
102+
// Request arrow: only active during minting, not after sequence number is received
103+
return isRealMinting && !hasSequenceNumber
100104
case "forward2":
101-
return hasSequenceNumber
105+
// Execute arrow: only active when we have sequence number but not listening yet
106+
// Once listening starts, execute is complete, so arrow should be neutral
107+
return hasSequenceNumber && !isListening
102108
case "callback":
103109
// Only show callback arrow if we have a sequence number, callback is completed, AND callback didn't fail
104110
return hasSequenceNumber && callbackCompleted && revealedEvent && !revealedEvent.args.callbackFailed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
"use client"
2+
3+
import { useState, useEffect } from "react"
4+
import { motion, AnimatePresence } from "framer-motion"
5+
import { Settings, Info, CheckCircle } from "lucide-react"
6+
import { Button } from "@/components/ui/button"
7+
import { Input } from "@/components/ui/input"
8+
import { Label } from "@/components/ui/label"
9+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
10+
import { Alert, AlertDescription } from "@/components/ui/alert"
11+
12+
interface RPCInputProps {
13+
onRPCSet: (rpcUrl: string) => void
14+
isConnected: boolean
15+
}
16+
17+
export function RPCInput({ onRPCSet, isConnected }: RPCInputProps) {
18+
const [rpcUrl, setRpcUrl] = useState("")
19+
const [isExpanded, setIsExpanded] = useState(false)
20+
const [hasCustomRPC, setHasCustomRPC] = useState(false)
21+
22+
useEffect(() => {
23+
// Check if user has already set a custom RPC
24+
const savedRPC = localStorage.getItem("custom_rpc_url")
25+
if (savedRPC) {
26+
setRpcUrl(savedRPC)
27+
setHasCustomRPC(true)
28+
onRPCSet(savedRPC)
29+
}
30+
}, [onRPCSet])
31+
32+
const handleSetRPC = () => {
33+
if (rpcUrl.trim()) {
34+
localStorage.setItem("custom_rpc_url", rpcUrl.trim())
35+
setHasCustomRPC(true)
36+
onRPCSet(rpcUrl.trim())
37+
setIsExpanded(false)
38+
}
39+
}
40+
41+
const handleUsePublicRPC = () => {
42+
localStorage.removeItem("custom_rpc_url")
43+
setHasCustomRPC(false)
44+
const publicRPC = "https://base-sepolia.drpc.org"
45+
setRpcUrl(publicRPC)
46+
onRPCSet(publicRPC)
47+
setIsExpanded(false)
48+
}
49+
50+
if (!isConnected) return null
51+
52+
return (
53+
<AnimatePresence>
54+
<motion.div
55+
initial={{ opacity: 0, y: -20 }}
56+
animate={{ opacity: 1, y: 0 }}
57+
exit={{ opacity: 0, y: -20 }}
58+
transition={{ duration: 0.3 }}
59+
>
60+
<Card className="max-w-md mx-auto mb-6">
61+
<CardHeader className="pb-3">
62+
<CardTitle className="flex items-center gap-2 text-lg">
63+
<Settings className="w-5 h-5" />
64+
RPC Configuration
65+
</CardTitle>
66+
<CardDescription>
67+
{hasCustomRPC ? "Using private RPC for optimal performance" : "Configure your RPC endpoint"}
68+
</CardDescription>
69+
</CardHeader>
70+
<CardContent className="space-y-4">
71+
{hasCustomRPC ? (
72+
<div className="space-y-3">
73+
<div className="p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg">
74+
<div className="flex items-center gap-2 text-green-800 dark:text-green-200">
75+
<CheckCircle className="w-4 h-4" />
76+
<span className="font-medium">Private RPC Active</span>
77+
</div>
78+
<p className="text-sm text-green-700 dark:text-green-300 mt-1">
79+
Using: {rpcUrl.slice(0, 30)}...
80+
</p>
81+
</div>
82+
<div className="flex gap-2">
83+
<Button
84+
onClick={() => setIsExpanded(true)}
85+
variant="outline"
86+
size="sm"
87+
className="flex-1"
88+
>
89+
Change RPC
90+
</Button>
91+
<Button
92+
onClick={handleUsePublicRPC}
93+
variant="outline"
94+
size="sm"
95+
className="flex-1"
96+
>
97+
Use Public RPC
98+
</Button>
99+
</div>
100+
</div>
101+
) : (
102+
<div className="space-y-3">
103+
<Alert className="border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/20">
104+
<Info className="h-4 w-4 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
105+
<AlertDescription className="text-blue-800 dark:text-blue-200 text-left leading-normal">
106+
<strong>Recommended:</strong> Use a private RPC for best performance when reading logs and listening to events.
107+
</AlertDescription>
108+
</Alert>
109+
110+
<div className="space-y-2">
111+
<Label htmlFor="rpc-url">RPC URL</Label>
112+
<Input
113+
id="rpc-url"
114+
value={rpcUrl}
115+
onChange={(e) => setRpcUrl(e.target.value)}
116+
placeholder="https://your-rpc-endpoint.com"
117+
className="font-mono text-sm"
118+
/>
119+
</div>
120+
121+
<div className="flex gap-2">
122+
<Button
123+
onClick={handleSetRPC}
124+
disabled={!rpcUrl.trim()}
125+
className="flex-1"
126+
>
127+
Set RPC
128+
</Button>
129+
<Button
130+
onClick={handleUsePublicRPC}
131+
variant="outline"
132+
className="flex-1"
133+
>
134+
Use Public RPC
135+
</Button>
136+
</div>
137+
138+
<div className="text-xs text-gray-500 dark:text-gray-400 text-center">
139+
Public RPC: base-sepolia.drpc.org
140+
</div>
141+
</div>
142+
)}
143+
</CardContent>
144+
</Card>
145+
</motion.div>
146+
</AnimatePresence>
147+
)
148+
}

entropy/mint-nft/ui/hooks/use-entropy-beasts.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export async function getFeeV2(gasLimit: number, client: WalletClient): Promise<
3030
}
3131
}
3232

33-
export async function mintBeast(gasLimit: number, isBig: boolean, client: WalletClient): Promise<[string | null, bigint, string | null]> {
33+
export async function mintBeast(gasLimit: number, isBig: boolean, client: WalletClient, rpcUrl: string): Promise<[string | null, bigint, string | null]> {
3434
console.log('minting beast', gasLimit, isBig)
3535

3636
if (!client.account) {
@@ -65,7 +65,7 @@ export async function mintBeast(gasLimit: number, isBig: boolean, client: Wallet
6565

6666
const publicClient = createPublicClient({
6767
chain: baseSepolia,
68-
transport: http(process.env.NEXT_PUBLIC_BASE_SEPOLIA_PUBLIC_RPC_URL || "https://base-sepolia.drpc.org"),
68+
transport: http(rpcUrl),
6969
})
7070

7171
await new Promise(resolve => setTimeout(resolve, 2500))
@@ -93,11 +93,11 @@ export async function mintBeast(gasLimit: number, isBig: boolean, client: Wallet
9393
}
9494
}
9595

96-
export async function listenForBeastMinted(sequenceNumber: string, requestTxBlockNumber: bigint, client: WalletClient) {
96+
export async function listenForBeastMinted(sequenceNumber: string, requestTxBlockNumber: bigint, client: WalletClient, rpcUrl: string) {
9797
console.log('listening for beast minted', sequenceNumber, requestTxBlockNumber)
9898
const publicClient = createPublicClient({
9999
chain: baseSepolia,
100-
transport: http(process.env.NEXT_PUBLIC_BASE_SEPOLIA_PUBLIC_RPC_URL || "https://base-sepolia.drpc.org"),
100+
transport: http(rpcUrl),
101101
})
102102

103103
try {
@@ -174,7 +174,7 @@ export async function listenForBeastMinted(sequenceNumber: string, requestTxBloc
174174

175175

176176

177-
export function useEntropyBeasts() {
177+
export function useEntropyBeasts(rpcUrl: string) {
178178
const { data: client } = useWalletClient()
179179
const [isMinting, setIsMinting] = useState(false)
180180
const [mintSequenceNumber, setMintSequenceNumber] = useState<string | null>(null)
@@ -201,7 +201,7 @@ export function useEntropyBeasts() {
201201
}
202202

203203
try {
204-
const [sequenceNumber, requestTxBlockNumber, txHash] = await mintBeast(gasLimit, isBig, client)
204+
const [sequenceNumber, requestTxBlockNumber, txHash] = await mintBeast(gasLimit, isBig, client, rpcUrl)
205205

206206
if (sequenceNumber) {
207207
setMintSequenceNumber(sequenceNumber)
@@ -212,7 +212,7 @@ export function useEntropyBeasts() {
212212
await new Promise(resolve => setTimeout(resolve, 10000))
213213

214214
try {
215-
const result = await listenForBeastMinted(sequenceNumber, requestTxBlockNumber, client)
215+
const result = await listenForBeastMinted(sequenceNumber, requestTxBlockNumber, client, rpcUrl)
216216

217217
console.log('listenForBeastMinted result:', result)
218218
console.log('result.logs.length:', result.logs.length)

0 commit comments

Comments
 (0)