2
2
3
3
import { useState } from "react"
4
4
import { motion , AnimatePresence } from "framer-motion"
5
- import { Zap , CheckCircle , Clock , Wallet , Settings , AlertTriangle , Activity , XCircle , Info } from "lucide-react"
5
+ import { Zap , CheckCircle , Clock , Wallet , Settings , AlertTriangle , Activity , XCircle , Info , ExternalLink } from "lucide-react"
6
6
import { Button } from "@/components/ui/button"
7
7
import { Input } from "@/components/ui/input"
8
8
import { Label } from "@/components/ui/label"
@@ -33,7 +33,7 @@ const NFT_CONFIGS: Record<NFTSize, NFTConfig> = {
33
33
} ,
34
34
big : {
35
35
size : "big" ,
36
- minGas : 150000 ,
36
+ minGas : 550000 ,
37
37
description : "Complex NFT with rich metadata and attributes" ,
38
38
} ,
39
39
}
@@ -71,6 +71,78 @@ export default function PythentropyNFTDemo() {
71
71
NFT Minting with Enhanced Callback Status Monitoring
72
72
</ p >
73
73
74
+ { /* What You'll Learn Section */ }
75
+ < div className = "max-w-4xl mx-auto mb-6" >
76
+ < Card className = "bg-gradient-to-r from-blue-50 to-purple-50 dark:from-blue-900/20 dark:to-purple-900/20 border-blue-200 dark:border-blue-800" >
77
+ < CardHeader className = "text-center pb-4" >
78
+ < CardTitle className = "text-2xl text-blue-900 dark:text-blue-100" > 🎓 What You'll Learn</ CardTitle >
79
+ < CardDescription className = "text-blue-800 dark:text-blue-200 text-lg" >
80
+ Understand the complete Pyth Entropy v2 flow from your contract to the provider and back
81
+ </ CardDescription >
82
+ </ CardHeader >
83
+ < CardContent className = "space-y-4" >
84
+ < div className = "grid md:grid-cols-2 gap-6" >
85
+ < div className = "space-y-3" >
86
+ < h3 className = "font-semibold text-blue-900 dark:text-blue-100 text-lg" > 📚 Learning Objectives</ h3 >
87
+ < ul className = "space-y-2 text-sm text-blue-800 dark:text-blue-200" >
88
+ < li className = "flex items-start gap-2" >
89
+ < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
90
+ How your contract requests entropy from Pyth Entropy v2
91
+ </ li >
92
+ < li className = "flex items-start gap-2" >
93
+ < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
94
+ How Entropy processes requests and sends to providers
95
+ </ li >
96
+ < li className = "flex items-start gap-2" >
97
+ < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
98
+ How callbacks return results and handle failures
99
+ </ li >
100
+ </ ul >
101
+ </ div >
102
+ < div className = "space-y-3" >
103
+ < h3 className = "font-semibold text-blue-900 dark:text-blue-100 text-lg" > 🧪 Demo Steps</ h3 >
104
+ < div className = "space-y-3" >
105
+ < div className = "p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg" >
106
+ < div className = "font-medium text-green-800 dark:text-green-200" > Step 1: Success Scenario</ div >
107
+ < div className = "text-sm text-green-700 dark:text-green-300" > Mint a small NFT with default gas to see successful callback</ div >
108
+ </ div >
109
+ < div className = "p-3 bg-orange-50 dark:bg-orange-900/20 border border-orange-200 dark:border-orange-800 rounded-lg" >
110
+ < div className = "font-medium text-orange-800 dark:text-orange-200" > Step 2: Failure Scenario</ div >
111
+ < div className = "text-sm text-orange-700 dark:text-orange-300" > Mint a big NFT with only 10 gas to see callback failure</ div >
112
+ </ div >
113
+ </ div >
114
+ </ div >
115
+ </ div >
116
+
117
+ { /* Base Sepolia Faucet Button */ }
118
+ < div className = "pt-4 border-t border-blue-200 dark:border-blue-800" >
119
+ < div className = "text-center" >
120
+ < p className = "text-sm text-blue-700 dark:text-blue-300 mb-3" >
121
+ 💡 Need testnet ETH to try this demo?
122
+ </ p >
123
+ < Button
124
+ asChild
125
+ className = "bg-orange-500 hover:bg-orange-600 text-white"
126
+ >
127
+ < a
128
+ href = "https://faucet.quicknode.com/base/sepolia"
129
+ target = "_blank"
130
+ rel = "noopener noreferrer"
131
+ className = "inline-flex items-center gap-2"
132
+ >
133
+ 🚰 Get Base Sepolia Testnet ETH
134
+ < ExternalLink className = "w-4 h-4" />
135
+ </ a >
136
+ </ Button >
137
+ < p className = "text-xs text-blue-600 dark:text-blue-400 mt-2" >
138
+ QuickNode faucet provides 0.05 ETH every 12 hours
139
+ </ p >
140
+ </ div >
141
+ </ div >
142
+ </ CardContent >
143
+ </ Card >
144
+ </ div >
145
+
74
146
{ /* Contract Status */ }
75
147
< div className = "max-w-2xl mx-auto mb-4 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg" >
76
148
< div className = "flex justify-between items-center" >
@@ -148,6 +220,44 @@ export default function PythentropyNFTDemo() {
148
220
< CardDescription > Configure your NFT size and gas settings below</ CardDescription >
149
221
</ CardHeader >
150
222
< CardContent className = "space-y-6" >
223
+ { /* Guided Demo Buttons */ }
224
+ < div className = "space-y-3" >
225
+ < Label className = "text-sm font-medium text-gray-700 dark:text-gray-300" > 🎯 Quick Demo Actions</ Label >
226
+ < div className = "grid grid-cols-2 gap-3" >
227
+ < Button
228
+ onClick = { ( ) => {
229
+ setNftSize ( "small" )
230
+ setGasLimit ( "50000" )
231
+ } }
232
+ disabled = { isMinting }
233
+ variant = "outline"
234
+ className = "text-sm h-auto py-3 px-4"
235
+ >
236
+ < div className = "text-left" >
237
+ < div className = "font-medium" > ✅ Success Demo</ div >
238
+ < div className = "text-xs text-gray-500" > Small NFT + 50k gas</ div >
239
+ </ div >
240
+ </ Button >
241
+ < Button
242
+ onClick = { ( ) => {
243
+ setNftSize ( "big" )
244
+ setGasLimit ( "10" )
245
+ } }
246
+ disabled = { isMinting }
247
+ variant = "outline"
248
+ className = "text-sm h-auto py-3 px-4"
249
+ >
250
+ < div className = "text-left" >
251
+ < div className = "font-medium" > ❌ Failure Demo</ div >
252
+ < div className = "text-xs text-gray-500" > Big NFT + 10 gas</ div >
253
+ </ div >
254
+ </ Button >
255
+ </ div >
256
+ < p className = "text-xs text-gray-500 dark:text-gray-400" >
257
+ Click these buttons to quickly set up the recommended demo scenarios
258
+ </ p >
259
+ </ div >
260
+
151
261
< div className = "space-y-2" >
152
262
< Label htmlFor = "nft-size" > NFT Size</ Label >
153
263
< Select value = { nftSize } onValueChange = { handleNFTSizeChange } disabled = { isMinting } >
@@ -230,7 +340,9 @@ export default function PythentropyNFTDemo() {
230
340
< Activity className = "w-5 h-5" />
231
341
Event Details
232
342
</ CardTitle >
233
- < CardDescription > Returned event from Beast Minted</ CardDescription >
343
+ < CardDescription >
344
+ Returned event from Pyth Entropy v2 Contract - This shows the callback result
345
+ </ CardDescription >
234
346
</ CardHeader >
235
347
< CardContent className = "space-y-4" >
236
348
{ callbackCompleted ? (
@@ -245,48 +357,65 @@ export default function PythentropyNFTDemo() {
245
357
</ p >
246
358
</ div >
247
359
360
+ { /* Event Source Info */ }
361
+ < div className = "p-3 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg" >
362
+ < div className = "flex items-center gap-2 text-blue-800 dark:text-blue-200" >
363
+ < Info className = "w-4 h-4" />
364
+ < span className = "font-medium" > Event Source</ span >
365
+ </ div >
366
+ < p className = "text-sm text-blue-700 dark:text-blue-300 mt-1" >
367
+ This event comes from the Pyth Entropy v2 contract, not your NFT contract. It shows the callback execution result.
368
+ </ p >
369
+ </ div >
370
+
248
371
{ revealedEvent && (
249
372
< div className = "space-y-3" >
250
373
< div className = "space-y-2" >
251
374
< Label className = "text-sm font-medium" > Provider Address</ Label >
252
375
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
253
376
{ revealedEvent . args . provider }
254
377
</ div >
378
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > The Fortuna provider that generated the entropy</ p >
255
379
</ div >
256
380
257
381
< div className = "space-y-2" >
258
382
< Label className = "text-sm font-medium" > Caller Address</ Label >
259
383
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
260
384
{ revealedEvent . args . caller }
261
385
</ div >
386
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Your contract address that requested the entropy</ p >
262
387
</ div >
263
388
264
389
< div className = "space-y-2" >
265
390
< Label className = "text-sm font-medium" > Sequence Number</ Label >
266
391
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm" >
267
392
{ revealedEvent . args . sequenceNumber ?. toString ( ) }
268
393
</ div >
394
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Unique identifier for this entropy request</ p >
269
395
</ div >
270
396
271
397
< div className = "space-y-2" >
272
398
< Label className = "text-sm font-medium" > Random Number</ Label >
273
399
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
274
400
{ revealedEvent . args . randomNumber }
275
401
</ div >
402
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > The entropy value generated by the provider</ p >
276
403
</ div >
277
404
278
405
< div className = "space-y-2" >
279
406
< Label className = "text-sm font-medium" > User Contribution</ Label >
280
407
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
281
408
{ revealedEvent . args . userContribution }
282
409
</ div >
410
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Your contribution to the entropy generation</ p >
283
411
</ div >
284
412
285
413
< div className = "space-y-2" >
286
414
< Label className = "text-sm font-medium" > Provider Contribution</ Label >
287
415
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
288
416
{ revealedEvent . args . providerContribution }
289
417
</ div >
418
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Provider's contribution to the entropy generation</ p >
290
419
</ div >
291
420
292
421
< div className = "space-y-2" >
@@ -298,27 +427,36 @@ export default function PythentropyNFTDemo() {
298
427
} `} >
299
428
{ revealedEvent . args . callbackFailed ? 'Failed ❌' : 'Success ✅' }
300
429
</ div >
430
+ < p className = "text-xs text-gray-500 dark:text-gray-400" >
431
+ { revealedEvent . args . callbackFailed
432
+ ? 'Your contract callback failed (likely due to insufficient gas)'
433
+ : 'Your contract callback executed successfully'
434
+ }
435
+ </ p >
301
436
</ div >
302
437
303
438
< div className = "space-y-2" >
304
439
< Label className = "text-sm font-medium" > Callback Return Value</ Label >
305
440
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
306
441
{ revealedEvent . args . callbackReturnValue || '0x' }
307
442
</ div >
443
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Return value from your contract's callback function</ p >
308
444
</ div >
309
445
310
446
< div className = "space-y-2" >
311
447
< Label className = "text-sm font-medium" > Callback Gas Used</ Label >
312
448
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm" >
313
449
{ revealedEvent . args . callbackGasUsed ?. toString ( ) || '0' }
314
450
</ div >
451
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Gas consumed by your contract's callback execution</ p >
315
452
</ div >
316
453
317
454
< div className = "space-y-2" >
318
455
< Label className = "text-sm font-medium" > Extra Args</ Label >
319
456
< div className = "p-2 bg-gray-50 dark:bg-gray-800 rounded border font-mono text-sm break-all" >
320
457
{ revealedEvent . args . extraArgs || '0x' }
321
458
</ div >
459
+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Additional arguments passed to your callback function</ p >
322
460
</ div >
323
461
</ div >
324
462
) }
@@ -378,9 +516,9 @@ export default function PythentropyNFTDemo() {
378
516
< div className = "w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-lg flex items-center justify-center mx-auto mb-3" >
379
517
< Settings className = "w-6 h-6 text-blue-600 dark:text-blue-400" />
380
518
</ div >
381
- < h3 className = "font-semibold mb-2 dark:text-white" > Smart Gas Management </ h3 >
519
+ < h3 className = "font-semibold mb-2 dark:text-white" > Configurable Gas Limits </ h3 >
382
520
< p className = "text-sm text-gray-600 dark:text-gray-300" >
383
- Automatic gas estimation with size-based requirements
521
+ Configurable Gas Limits for Callbacks
384
522
</ p >
385
523
</ div >
386
524
< div className = "text-center" >
@@ -396,75 +534,14 @@ export default function PythentropyNFTDemo() {
396
534
< div className = "w-12 h-12 bg-green-100 dark:bg-green-900/30 rounded-lg flex items-center justify-center mx-auto mb-3" >
397
535
< Activity className = "w-6 h-6 text-green-600 dark:text-green-400" />
398
536
</ div >
399
- < h3 className = "font-semibold mb-2 dark:text-white" > Real-time Event Monitoring </ h3 >
537
+ < h3 className = "font-semibold mb-2 dark:text-white" > Public Entropy Explorer </ h3 >
400
538
< p className = "text-sm text-gray-600 dark:text-gray-300" >
401
- Live event logs showing the complete transaction lifecycle
539
+ Public Entropy Explorer for all Pyth Entropy requests at < a href = "https://entropy-explorer.pyth.network/" target = "_blank" rel = "noopener noreferrer" className = "text-blue-600 dark:text-blue-400 hover:underline" > entropy-explorer.pyth.network </ a >
402
540
</ p >
403
541
</ div >
404
542
</ div >
405
543
</ CardContent >
406
544
</ Card >
407
-
408
- { /* Usage Notes */ }
409
- < Card className = "mt-8" >
410
- < CardHeader >
411
- < CardTitle > How to Use This Demo</ CardTitle >
412
- </ CardHeader >
413
- < CardContent >
414
- < div className = "grid md:grid-cols-2 gap-6" >
415
- < div >
416
- < h3 className = "font-semibold mb-3 text-gray-900 dark:text-white" > Getting Started</ h3 >
417
- < ul className = "space-y-2 text-sm text-gray-600 dark:text-gray-300" >
418
- < li className = "flex items-start gap-2" >
419
- < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
420
- Connect your wallet using the button above (optional for demo)
421
- </ li >
422
- < li className = "flex items-start gap-2" >
423
- < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
424
- Choose between Small or Big NFT to see different gas requirements
425
- </ li >
426
- < li className = "flex items-start gap-2" >
427
- < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
428
- Adjust gas limit to trigger different callback scenarios
429
- </ li >
430
- < li className = "flex items-start gap-2" >
431
- < span className = "w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0" > </ span >
432
- Watch the flow visualization and event logs in real-time
433
- </ li >
434
- </ ul >
435
- </ div >
436
- < div >
437
- < h3 className = "font-semibold mb-3 text-gray-900 dark:text-white" > What You'll Learn</ h3 >
438
- < ul className = "space-y-2 text-sm text-gray-600 dark:text-gray-300" >
439
- < li className = "flex items-start gap-2" >
440
- < span className = "w-2 h-2 bg-green-500 rounded-full mt-2 flex-shrink-0" > </ span >
441
- How Pyth Entropy v2 handles custom gas limits
442
- </ li >
443
- < li className = "flex items-start gap-2" >
444
- < span className = "w-2 h-2 bg-green-500 rounded-full mt-2 flex-shrink-0" > </ span >
445
- Enhanced callback status detection and error handling
446
- </ li >
447
- < li className = "flex items-start gap-2" >
448
- < span className = "w-2 h-2 bg-green-500 rounded-full mt-2 flex-shrink-0" > </ span >
449
- Real-time event monitoring and transaction lifecycle
450
- </ li >
451
- < li className = "flex items-start gap-2" >
452
- < span className = "w-2 h-2 bg-green-500 rounded-full mt-2 flex-shrink-0" > </ span >
453
- Out-of-gas detection and failure reason analysis
454
- </ li >
455
- </ ul >
456
- </ div >
457
- </ div >
458
-
459
- < div className = "mt-6 p-4 bg-gray-50 dark:bg-gray-900 rounded-lg" >
460
- < h4 className = "font-medium text-gray-900 dark:text-white mb-2" > 💡 Pro Tip</ h4 >
461
- < p className = "text-sm text-gray-600 dark:text-gray-300" >
462
- Try setting the gas limit below the minimum requirement for your selected NFT size to see how Entropy v2
463
- detects and reports out-of-gas failures in the callback status.
464
- </ p >
465
- </ div >
466
- </ CardContent >
467
- </ Card >
468
545
</ div >
469
546
</ div >
470
547
)
0 commit comments