From 1e23b3e960f0a61387515f45da5ffac6c53e0048 Mon Sep 17 00:00:00 2001 From: Van Minh Date: Mon, 28 Jul 2025 00:31:31 +0700 Subject: [PATCH 1/3] feat(docs): Add guideline for txn-error-fallback success-dialog inline-txn-status step-flow-status --- components/step-flow-dialog-preview.tsx | 121 + components/success-dialog-preview.tsx | 95 + components/txn-error-fallback-preview.tsx | 114 + .../murphy/Txn-Feedback/inline-txn-status.tsx | 86 + .../murphy/Txn-Feedback/step-flow-dialog.tsx | 142 + .../ui/murphy/Txn-Feedback/success-dialog.tsx | 135 + .../Txn-Feedback/txn-error-fallback.tsx | 139 + .../murphy/Txn-Feedback/txn-explorer-link.tsx | 47 + .../Txn-Feedback/txn-feedback-toast.tsx | 117 + .../Txn-Feedback/txn-pending-indicator.tsx | 98 + .../Txn-Feedback/txn-progress-steps.tsx | 55 + .../murphy/Txn-Feedback/txn-retry-button.tsx | 63 + components/ui/murphy/index.tsx | 21 +- .../Txn-Feedback/inline-txn-status.mdx | 598 + .../Txn-Feedback/step-flow-dialog.mdx | 209 + .../Txn-Feedback/success-dialog.mdx | 276 + .../Txn-Feedback/txn-error-fallback.mdx | 197 + content/docs/onchainkit/meta.json | 3 +- public/r/CancelRecurringOrder.json | 2 +- public/r/RecurringActiveOrders.json | 2 +- public/r/RecurringHistoryList.json | 2 +- public/r/RecurringOrderCard.json | 2 +- public/r/RecurringOrderWidget.json | 2 +- public/r/RecurringSetupForm.json | 2 +- public/r/avatar.json | 4 +- public/r/buildCurveAndCreateConfig-form.json | 6 +- ...dCurveAndCreateConfigByMarketCap-form.json | 6 +- public/r/claim-cToken.json | 4 +- public/r/connect-wallet-button.json | 12 +- public/r/create-collection-form.json | 2 +- public/r/create-merkleTree-form.json | 2 +- public/r/createConfig-form.json | 6 +- public/r/distribute-cToken.json | 2 +- public/r/get-nft-form.json | 2 +- public/r/inline-txn-status.json | 18 + public/r/mint-cToken.json | 2 +- public/r/mint-cnft-form.json | 2 +- public/r/mint-nft-form.json | 4 +- public/r/pk-input.json | 4 +- public/r/price-change.json | 4 +- public/r/price-chart.json | 6 +- public/r/send-token-form.json | 2 +- public/r/sparkline.json | 4 +- public/r/stake-token-form.json | 4 +- public/r/step-flow-dialog.json | 20 + public/r/success-dialog.json | 19 + public/r/swap-token-form.json | 14 +- public/r/token-card.json | 6 +- public/r/token-combobox.json | 12 +- public/r/token-icon.json | 4 +- public/r/token-input.json | 8 +- public/r/token-list.json | 12 +- public/r/txn-error-fallback.json | 18 + public/r/txn-explorer-link.json | 16 + public/r/txn-feedback-toast.json | 20 + public/r/txn-list.json | 4 +- public/r/txn-pending-indicator.json | 16 + public/r/txn-progress-steps.json | 16 + public/r/txn-retry-button.json | 18 + public/r/txn-settings.json | 2 +- registry.json | 531 +- registry/components/inline-txn-status.json | 14 + registry/components/step-flow-dialog.json | 14 + registry/components/success-dialog.json | 14 + registry/components/txn-error-fallback.json | 14 + registry/components/txn-explorer-link.json | 14 + registry/components/txn-feedback-toast.json | 14 + .../components/txn-pending-indicator.json | 14 + registry/components/txn-progress-steps.json | 14 + registry/components/txn-retry-button.json | 14 + types/transaction/index.ts | 20 + yarn.lock | 11358 ++++++++++++++++ 72 files changed, 14592 insertions(+), 272 deletions(-) create mode 100644 components/step-flow-dialog-preview.tsx create mode 100644 components/success-dialog-preview.tsx create mode 100644 components/txn-error-fallback-preview.tsx create mode 100644 components/ui/murphy/Txn-Feedback/inline-txn-status.tsx create mode 100644 components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx create mode 100644 components/ui/murphy/Txn-Feedback/success-dialog.tsx create mode 100644 components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx create mode 100644 components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx create mode 100644 components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx create mode 100644 components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx create mode 100644 components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx create mode 100644 components/ui/murphy/Txn-Feedback/txn-retry-button.tsx create mode 100644 content/docs/onchainkit/Txn-Feedback/inline-txn-status.mdx create mode 100644 content/docs/onchainkit/Txn-Feedback/step-flow-dialog.mdx create mode 100644 content/docs/onchainkit/Txn-Feedback/success-dialog.mdx create mode 100644 content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx create mode 100644 public/r/inline-txn-status.json create mode 100644 public/r/step-flow-dialog.json create mode 100644 public/r/success-dialog.json create mode 100644 public/r/txn-error-fallback.json create mode 100644 public/r/txn-explorer-link.json create mode 100644 public/r/txn-feedback-toast.json create mode 100644 public/r/txn-pending-indicator.json create mode 100644 public/r/txn-progress-steps.json create mode 100644 public/r/txn-retry-button.json create mode 100644 registry/components/inline-txn-status.json create mode 100644 registry/components/step-flow-dialog.json create mode 100644 registry/components/success-dialog.json create mode 100644 registry/components/txn-error-fallback.json create mode 100644 registry/components/txn-explorer-link.json create mode 100644 registry/components/txn-feedback-toast.json create mode 100644 registry/components/txn-pending-indicator.json create mode 100644 registry/components/txn-progress-steps.json create mode 100644 registry/components/txn-retry-button.json create mode 100644 types/transaction/index.ts create mode 100644 yarn.lock diff --git a/components/step-flow-dialog-preview.tsx b/components/step-flow-dialog-preview.tsx new file mode 100644 index 0000000..faafdca --- /dev/null +++ b/components/step-flow-dialog-preview.tsx @@ -0,0 +1,121 @@ +"use client" + +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { TxnStep } from "@/types/transaction" +import { StepFlowDialog } from "./ui/murphy" + +export default function StepFlowDialogPreview() { + const [showDialog, setShowDialog] = useState(false) + const [currentStep, setCurrentStep] = useState(0) + const [dialogType, setDialogType] = useState<"nft-mint" | "token-swap" | "staking">("nft-mint") + + const workflows = { + "nft-mint": { + title: "Mint NFT Process", + description: "Complete the following steps to mint your NFT", + steps: [ + { id: "1", title: "Upload Metadata", description: "Upload image and metadata to IPFS", status: "pending" as const }, + { id: "2", title: "Create Mint Account", description: "Create NFT mint account on Solana", status: "pending" as const }, + { id: "3", title: "Mint Token", description: "Mint NFT to your wallet", status: "pending" as const }, + { id: "4", title: "Verify Ownership", description: "Verify NFT in your wallet", status: "pending" as const }, + ], + }, + "token-swap": { + title: "Token Swap Process", + description: "Swap your tokens through the following steps", + steps: [ + { id: "1", title: "Get Quote", description: "Calculate swap rates and fees", status: "pending" as const }, + { id: "2", title: "Approve Spending", description: "Approve token spending limit", status: "pending" as const }, + { id: "3", title: "Execute Swap", description: "Perform the token exchange", status: "pending" as const }, + ], + }, + staking: { + title: "Staking Process", + description: "Stake your tokens to earn rewards", + steps: [ + { id: "1", title: "Select Validator", description: "Choose a validator to stake with", status: "pending" as const }, + { id: "2", title: "Create Stake Account", description: "Create a new stake account", status: "pending" as const }, + { id: "3", title: "Delegate Stake", description: "Delegate tokens to validator", status: "pending" as const }, + { id: "4", title: "Activate Stake", description: "Wait for stake activation", status: "pending" as const }, + ], + }, + } + + const updateStepStatus = (stepIndex: number, status: TxnStep["status"]) => { + const currentWorkflow = workflows[dialogType] + return currentWorkflow.steps.map((step, index) => { + if (index < stepIndex) return { ...step, status: "completed" as const } + if (index === stepIndex) return { ...step, status } + return { ...step, status: "pending" as const } + }) + } + + const [currentSteps, setCurrentSteps] = useState(workflows["nft-mint"].steps) + + const openDialog = (type: keyof typeof workflows) => { + setDialogType(type) + setCurrentStep(0) + setCurrentSteps(workflows[type].steps) + setShowDialog(true) + } + + const handleNext = async () => { + await new Promise((resolve) => setTimeout(resolve, 1500)) + + const nextStep = currentStep + 1 + setCurrentSteps(updateStepStatus(currentStep, "completed")) + + if (nextStep < workflows[dialogType].steps.length) { + setCurrentStep(nextStep) + setCurrentSteps(updateStepStatus(nextStep, "active")) + } + } + + const handlePrevious = () => { + const prevStep = Math.max(currentStep - 1, 0) + setCurrentStep(prevStep) + setCurrentSteps(updateStepStatus(prevStep, "active")) + } + + const handleCancel = () => { + setShowDialog(false) + setCurrentStep(0) + setCurrentSteps(workflows[dialogType].steps) + } + + return ( +
+
+

Multi-Step Workflow Preview

+

Choose a workflow to simulate

+
+ +
+ + + +
+ + 0} + canGoNext={currentStep < workflows[dialogType].steps.length - 1} + /> +
+ ) +} diff --git a/components/success-dialog-preview.tsx b/components/success-dialog-preview.tsx new file mode 100644 index 0000000..67aa2d1 --- /dev/null +++ b/components/success-dialog-preview.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { SuccessDialog } from "./ui/murphy"; + +export default function SuccessDialogPreview() { + const [showDialog, setShowDialog] = useState(false); + const [dialogType, setDialogType] = useState< + "basic" | "token-transfer" | "nft-mint" | "staking" + >("basic"); + + const dialogExamples = { + basic: { + title: "Transaction Successful! 🎉", + description: "Your transaction has been confirmed on the blockchain", + signature: + "5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM7n", + }, + "token-transfer": { + title: "Tokens Sent Successfully! 💸", + description: "Your tokens have been transferred to the recipient", + signature: + "2B5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM", + amount: "100", + token: "USDC", + recipient: "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", + }, + "nft-mint": { + title: "NFT Minted Successfully! 🎨", + description: "Your NFT has been minted and added to your wallet", + signature: + "3C6VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM", + amount: "1", + token: "NFT", + }, + staking: { + title: "Staking Successful! 🚀", + description: "Your tokens have been staked and are now earning rewards", + signature: + "4D7VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM", + amount: "500", + token: "SOL", + }, + }; + + const openDialog = (type: keyof typeof dialogExamples) => { + setDialogType(type); + setShowDialog(true); + }; + + return ( +
+

Success Dialog Examples

+ + + + + + + + window.open( + `https://explorer.solana.com/tx/${dialogExamples[dialogType].signature}`, + "_blank" + ) + } + onClose={() => setShowDialog(false)} + /> +
+ ); +} diff --git a/components/txn-error-fallback-preview.tsx b/components/txn-error-fallback-preview.tsx new file mode 100644 index 0000000..8df4f51 --- /dev/null +++ b/components/txn-error-fallback-preview.tsx @@ -0,0 +1,114 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { TxnErrorFallback } from "./ui/murphy"; + +export default function TxnErrorFallbackPreview() { + const [showError, setShowError] = useState(false); + const [errorType, setErrorType] = useState< + "simple" | "with-signature" | "with-logs" + >("simple"); + + const errorExamples = { + simple: { + error: "Transaction failed: Insufficient funds for transaction fees", + }, + "with-signature": { + error: "Transaction failed: Program error occurred during execution", + signature: + "5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM7n", + }, + "with-logs": { + error: "Transaction failed: Custom program error: 0x1771", + signature: + "2B5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM", + showLogs: true, + logs: [ + "Program 11111111111111111111111111111111 invoke [1]", + "Program log: Instruction: Transfer", + "Program log: Error: custom program error: 0x1771", + "Program 11111111111111111111111111111111 consumed 200000 of 200000 compute units", + "Program 11111111111111111111111111111111 failed: custom program error: 0x1771", + ], + }, + }; + + const handleRetry = () => { + console.log("Retrying..."); + setShowError(false); + setTimeout(() => { + if (Math.random() > 0.5) { + alert("Retry successful!"); + } else { + setShowError(true); + } + }, 1500); + }; + + return ( +
+
+

+ Transaction Error Example +

+

+ Simulate different transaction error scenarios +

+
+ +
+ + + + + + + +
+ + {showError && ( +
+ setShowError(false)} + /> +
+ )} +
+ ); +} diff --git a/components/ui/murphy/Txn-Feedback/inline-txn-status.tsx b/components/ui/murphy/Txn-Feedback/inline-txn-status.tsx new file mode 100644 index 0000000..bc90cea --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/inline-txn-status.tsx @@ -0,0 +1,86 @@ +"use client" + +import { CheckCircle, XCircle, Loader2, Clock } from "lucide-react" +import { Badge } from "@/components/ui/badge" +import { cn } from "@/lib/utils" +import { TransactionStatus } from "@/types/transaction" + +interface InlineTxnStatusProps { + status: TransactionStatus["status"] + size?: "sm" | "md" | "lg" + showText?: boolean + className?: string +} + +export function InlineTxnStatus({ + status, + size = "md", + showText = true, + className, +}: InlineTxnStatusProps) { + const getStatusConfig = () => { + switch (status) { + case "success": + return { + icon: CheckCircle, + text: "Success", + variant: "default" as const, + className: "bg-green-100 text-green-800 border border-green-200 dark:bg-green-900 dark:text-green-100 dark:border-green-700", + } + case "error": + return { + icon: XCircle, + text: "Failed", + variant: "destructive" as const, + className: "bg-red-100 text-red-800 border border-red-200 dark:bg-red-900 dark:text-red-100 dark:border-red-700", + } + case "preparing": + case "signing": + case "sending": + case "confirming": + return { + icon: Loader2, + text: "Processing", + variant: "secondary" as const, + className: "bg-blue-100 text-blue-800 border border-blue-200 dark:bg-blue-900 dark:text-blue-100 dark:border-blue-700", + animate: true, + } + default: + return { + icon: Clock, + text: "Pending", + variant: "outline" as const, + className: "bg-gray-100 text-gray-800 border border-gray-200 dark:bg-gray-900 dark:text-gray-100 dark:border-gray-700", + } + } + } + + const config = getStatusConfig() + const Icon = config.icon + + const iconSize = { + sm: "w-3 h-3", + md: "w-4 h-4", + lg: "w-5 h-5", + }[size] + + const textSize = { + sm: "text-xs", + md: "text-sm", + lg: "text-base", + }[size] + + return ( + + + {showText && {config.text}} + + ) +} diff --git a/components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx b/components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx new file mode 100644 index 0000000..73a81cc --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx @@ -0,0 +1,142 @@ +"use client" + +import { useState } from "react" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { TxnProgressSteps } from "./txn-progress-steps" +import type { TxnStep } from "@/types/transaction" + +interface StepFlowDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + title: string + description?: string + steps: TxnStep[] + currentStep: number + onNext?: () => Promise | void + onPrevious?: () => void + onCancel?: () => void + nextButtonText?: string + previousButtonText?: string + cancelButtonText?: string + isLoading?: boolean + canGoNext?: boolean + canGoPrevious?: boolean + showCancel?: boolean +} + +export function StepFlowDialog({ + open, + onOpenChange, + title, + description, + steps, + currentStep, + onNext, + onPrevious, + onCancel, + nextButtonText = "Next", + previousButtonText = "Previous", + cancelButtonText = "Cancel", + isLoading = false, + canGoNext = true, + canGoPrevious = true, + showCancel = true, +}: StepFlowDialogProps) { + const [isProcessing, setIsProcessing] = useState(false) + + const handleNext = async () => { + if (!onNext || isProcessing) return + setIsProcessing(true) + try { + await onNext() + } catch (error) { + console.error("Step failed:", error) + } finally { + setIsProcessing(false) + } + } + + const isLastStep = currentStep === steps.length - 1 + const isFirstStep = currentStep === 0 + + return ( + + + + {title} + {description && {description}} + + +
+ + + {steps[currentStep] && ( +
+

+ {steps[currentStep].title} +

+ {steps[currentStep].description && ( +

+ {steps[currentStep].description} +

+ )} +
+ )} +
+ +
+
+ {showCancel && ( + + )} + {!isFirstStep && canGoPrevious && ( + + )} +
+ +
+ {!isLastStep && ( + + )} + {isLastStep && ( + + )} +
+
+
+
+ ) +} diff --git a/components/ui/murphy/Txn-Feedback/success-dialog.tsx b/components/ui/murphy/Txn-Feedback/success-dialog.tsx new file mode 100644 index 0000000..03cd242 --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/success-dialog.tsx @@ -0,0 +1,135 @@ +"use client"; + +import { CheckCircle, ExternalLink, Copy } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { useState } from "react"; + +interface SuccessDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + title?: string; + description?: string; + signature?: string; + amount?: string; + token?: string; + recipient?: string; + onViewExplorer?: () => void; + onClose?: () => void; +} + +export function SuccessDialog({ + open, + onOpenChange, + title = "Transaction Successful! 🎉", + description = "Your transaction has been confirmed on the blockchain", + signature, + amount, + token, + recipient, + onViewExplorer, + onClose, +}: SuccessDialogProps) { + const [copied, setCopied] = useState(false); + + const copySignature = async () => { + if (!signature) return; + await navigator.clipboard.writeText(signature); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + const handleClose = () => { + onOpenChange(false); + onClose?.(); + }; + + return ( + + + +
+ +
+ + {title} + + + {description} + +
+ +
+ {(amount || token) && ( +
+
+

+ {amount} {token} +

+ {recipient && ( +

+ Sent to {recipient.slice(0, 8)}...{recipient.slice(-8)} +

+ )} +
+
+ )} + + {signature && ( +
+
+
+

+ Transaction Signature +

+

+ {signature.slice(0, 12)}...{signature.slice(-12)} +

+
+
+ + {onViewExplorer && ( + + )} +
+
+ {copied && ( + + Copied! + + )} +
+ )} +
+ + + + +
+
+ ); +} diff --git a/components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx b/components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx new file mode 100644 index 0000000..3a7289e --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx @@ -0,0 +1,139 @@ +"use client"; + +import { AlertTriangle, RefreshCw, Copy, ExternalLink } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { useState } from "react"; + +interface TxnErrorFallbackProps { + error: string; + signature?: string; + onRetry?: () => void; + onClose?: () => void; + showLogs?: boolean; + logs?: string[]; +} + +export function TxnErrorFallback({ + error, + signature, + onRetry, + onClose, + showLogs = false, + logs = [], +}: TxnErrorFallbackProps) { + const [copied, setCopied] = useState(false); + + const copyError = async () => { + await navigator.clipboard.writeText(error); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( + + +
+ +
+ + Transaction Failed + + + Your transaction could not be completed + +
+ + +
+
+

+ {error} +

+ +
+ {copied && ( + + Copied to clipboard + + )} +
+ + {signature && ( +
+
+

+ Transaction Signature +

+

+ {signature.slice(0, 8)}...{signature.slice(-8)} +

+
+ +
+ )} + + {showLogs && logs.length > 0 && ( +
+ + View Transaction Logs + +
+ {logs.map((log, index) => ( +

+ {log} +

+ ))} +
+
+ )} +
+ + + {onRetry && ( + + )} + + +
+ ); +} diff --git a/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx b/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx new file mode 100644 index 0000000..e011d30 --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx @@ -0,0 +1,47 @@ +"use client" + +import type React from "react" +import { ExternalLink } from "lucide-react" +import { Button } from "@/components/ui/button" +import { cn } from "@/lib/utils" + +interface TxnExplorerLinkProps { + signature: string + cluster?: "mainnet-beta" | "testnet" | "devnet" + children?: React.ReactNode + className?: string + variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" + size?: "default" | "sm" | "lg" | "icon" + showIcon?: boolean +} + +export function TxnExplorerLink({ + signature, + cluster = "mainnet-beta", + children, + className, + variant = "outline", + size = "sm", + showIcon = true, +}: TxnExplorerLinkProps) { + const getExplorerUrl = () => { + const baseUrl = "https://explorer.solana.com/tx" + const clusterParam = cluster !== "mainnet-beta" ? `?cluster=${cluster}` : "" + return `${baseUrl}/${signature}${clusterParam}` + } + + const handleClick = () => { + window.open(getExplorerUrl(), "_blank", "noopener,noreferrer") + } + + return ( + + ) +} diff --git a/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx b/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx new file mode 100644 index 0000000..5c8fe00 --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx @@ -0,0 +1,117 @@ +"use client" + +import { useEffect, useState } from "react" +import { CheckCircle, XCircle, Loader2, AlertCircle } from "lucide-react" +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import type { TxnFeedbackProps } from "@/types/transaction" + +export function TxnFeedbackToast({ status, onRetry, onClose }: TxnFeedbackProps) { + const [isVisible, setIsVisible] = useState(false) + + useEffect(() => { + if (status.status !== "idle") { + setIsVisible(true) + } + }, [status.status]) + + useEffect(() => { + if (status.status === "success") { + const timer = setTimeout(() => { + setIsVisible(false) + onClose?.() + }, 5000) + return () => clearTimeout(timer) + } + }, [status.status, onClose]) + + if (!isVisible || status.status === "idle") return null + + const getIcon = () => { + switch (status.status) { + case "success": + return + case "error": + return + case "preparing": + case "signing": + case "sending": + case "confirming": + return + default: + return + } + } + + const getMessage = () => { + switch (status.status) { + case "preparing": + return "Preparing transaction..." + case "signing": + return "Please sign the transaction" + case "sending": + return "Sending transaction..." + case "confirming": + return "Confirming transaction..." + case "success": + return "Transaction successful!" + case "error": + return status.error || "Transaction failed" + default: + return "Processing..." + } + } + + const getBgColor = () => { + switch (status.status) { + case "success": + return "bg-green-50 border-green-200" + case "error": + return "bg-red-50 border-red-200" + default: + return "bg-blue-50 border-blue-200" + } + } + + return ( +
+
+
+ {getIcon()} +
+

{getMessage()}

+ {status.signature && ( +

+ Signature: {status.signature.slice(0, 8)}...{status.signature.slice(-8)} +

+ )} +
+
+ {status.status === "error" && onRetry && ( + + )} + +
+
+
+
+ ) +} diff --git a/components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx b/components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx new file mode 100644 index 0000000..5899ee1 --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx @@ -0,0 +1,98 @@ +"use client" + +import { useState, useEffect } from "react" +import { Loader2, X } from "lucide-react" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { cn } from "@/lib/utils" + +interface PendingTransaction { + id: string + signature?: string + description: string + startTime: number +} + +interface TxnPendingIndicatorProps { + transactions: PendingTransaction[] + onCancel?: (id: string) => void + position?: "top-left" | "top-right" | "bottom-left" | "bottom-right" + className?: string +} + +export function TxnPendingIndicator({ + transactions, + onCancel, + position = "bottom-right", + className, +}: TxnPendingIndicatorProps) { + const [isExpanded, setIsExpanded] = useState(false) + + useEffect(() => { + if (transactions.length === 0) { + setIsExpanded(false) + } + }, [transactions.length]) + + if (transactions.length === 0) return null + + const positionClasses = { + "top-left": "top-4 left-4", + "top-right": "top-4 right-4", + "bottom-left": "bottom-4 left-4", + "bottom-right": "bottom-4 right-4", + } + + const getElapsedTime = (startTime: number) => { + const elapsed = Math.floor((Date.now() - startTime) / 1000) + if (elapsed < 60) return `${elapsed}s` + return `${Math.floor(elapsed / 60)}m ${elapsed % 60}s` + } + + return ( +
+ {!isExpanded ? ( + + ) : ( +
+
+

Pending Transactions

+ +
+ +
+ {transactions.map((tx) => ( +
+
+ +
+

{tx.description}

+

{getElapsedTime(tx.startTime)}

+
+
+ {onCancel && ( + + )} +
+ ))} +
+
+ )} +
+ ) +} diff --git a/components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx b/components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx new file mode 100644 index 0000000..c0d2df9 --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx @@ -0,0 +1,55 @@ +"use client" + +import { Check, Loader2, X } from "lucide-react" +import { cn } from "@/lib/utils" +import type { TxnStep } from "@/types/transaction" + +interface TxnProgressStepsProps { + steps: TxnStep[] + orientation?: "horizontal" | "vertical" + className?: string +} + +export function TxnProgressSteps({ steps, orientation = "horizontal", className }: TxnProgressStepsProps) { + const isVertical = orientation === "vertical" + + return ( +
+ {steps.map((step, index) => ( +
+
+ {step.status === "completed" && } + {step.status === "active" && } + {step.status === "error" && } + {step.status === "pending" && {index + 1}} +
+ +
+
+ {step.title} +
+ {step.description &&
{step.description}
} +
+ + {!isVertical && index < steps.length - 1 &&
} +
+ ))} +
+ ) +} diff --git a/components/ui/murphy/Txn-Feedback/txn-retry-button.tsx b/components/ui/murphy/Txn-Feedback/txn-retry-button.tsx new file mode 100644 index 0000000..9e981b2 --- /dev/null +++ b/components/ui/murphy/Txn-Feedback/txn-retry-button.tsx @@ -0,0 +1,63 @@ +"use client" + +import type React from "react" +import { useState } from "react" +import { RefreshCw } from "lucide-react" +import { Button } from "@/components/ui/button" +import { cn } from "@/lib/utils" + +interface TxnRetryButtonProps { + onRetry: () => Promise | void + disabled?: boolean + maxRetries?: number + retryDelay?: number + children?: React.ReactNode + className?: string + variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" + size?: "default" | "sm" | "lg" | "icon" +} + +export function TxnRetryButton({ + onRetry, + disabled = false, + maxRetries = 3, + retryDelay = 1000, + children = "Retry", + className, + variant = "default", + size = "default", +}: TxnRetryButtonProps) { + const [isRetrying, setIsRetrying] = useState(false) + const [retryCount, setRetryCount] = useState(0) + + const handleRetry = async () => { + if (retryCount >= maxRetries || isRetrying) return + + setIsRetrying(true) + + try { + await new Promise((resolve) => setTimeout(resolve, retryDelay)) + await onRetry() + setRetryCount(0) + } catch (error) { + setRetryCount((prev) => prev + 1) + console.error("Retry failed:", error) + } finally { + setIsRetrying(false) + } + } + + const isDisabled = disabled || isRetrying || retryCount >= maxRetries + + return ( + + ) +} diff --git a/components/ui/murphy/index.tsx b/components/ui/murphy/index.tsx index 987b191..851535a 100644 --- a/components/ui/murphy/index.tsx +++ b/components/ui/murphy/index.tsx @@ -37,6 +37,16 @@ import { CoreAssetLaunchpad } from "./core-asset-launchpad"; import { HydraFanoutForm } from "./hydra-fanout-form"; import { MPLHybridForm } from "./mpl-hybrid-form"; import { TokenMetadataViewer } from "./token-metadata-viewer"; +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status"; +import { StepFlowDialog } from "@/components/ui/murphy/Txn-Feedback/step-flow-dialog"; +import { SuccessDialog } from "@/components/ui/murphy/Txn-Feedback/success-dialog"; +import { TxnErrorFallback } from "@/components/ui/murphy/Txn-Feedback/txn-error-fallback"; +import { TxnExplorerLink } from "@/components/ui/murphy/Txn-Feedback/txn-explorer-link"; +import { TxnFeedbackToast } from "@/components/ui/murphy/Txn-Feedback/txn-feedback-toast"; +import { TxnPendingIndicator } from "@/components/ui/murphy/Txn-Feedback/txn-pending-indicator"; +import { TxnProgressSteps } from "@/components/ui/murphy/Txn-Feedback/txn-progress-steps"; +import { TxnRetryButton } from "@/components/ui/murphy/Txn-Feedback/txn-retry-button"; + export { ConnectWalletButton, @@ -78,5 +88,14 @@ export { TMLaunchpadForm, HydraFanoutForm, MPLHybridForm, - TokenMetadataViewer + TokenMetadataViewer, + InlineTxnStatus, + StepFlowDialog, + SuccessDialog, + TxnErrorFallback, + TxnExplorerLink, + TxnFeedbackToast, + TxnPendingIndicator, + TxnProgressSteps, + TxnRetryButton, }; diff --git a/content/docs/onchainkit/Txn-Feedback/inline-txn-status.mdx b/content/docs/onchainkit/Txn-Feedback/inline-txn-status.mdx new file mode 100644 index 0000000..762fb89 --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/inline-txn-status.mdx @@ -0,0 +1,598 @@ +--- +title: Inline Transaction Status +description: Small status indicators for transaction states in lists and UIs +icon: Activity +--- + + +
+ +
+

Different Status States

+
+ + + + +
+
+ +
+

Different Sizes

+
+ + + +
+
+ +
+

Icon Only

+
+ + + +
+
+ +
+
+ +## Installation + + + + Install Inline Transaction Status + + + + + +## Basic Usage + +```tsx +"use client" +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status" + +export default function MyPage() { + return ( +
+ + + +
+ ) +} + +``` + +## Props + + + +## Examples + +### Transaction History List + +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status"; + + +
+ {[ + { hash: "0x123abcdef123456789", status: "success", timestamp: "2024-01-01" }, + { hash: "0x456fedcba987654321", status: "pending", timestamp: "2024-01-02" }, + { hash: "0x789112233445566778", status: "error", timestamp: "2024-01-03" }, + { hash: "0xabc999888777666555", status: "signing", timestamp: "2024-01-04" }, + ].map((txn) => ( +
+
+ {txn.hash.slice(0, 10)} +
+
{txn.timestamp}
+ +
+ ))} +
+
+ +```tsx +export const TransactionHistory = ({ + transactions, +}: { + transactions: Transaction[]; +}) => { + return ( +
+ {transactions.map((txn) => ( +
+
+ {txn.hash.slice(0, 10)} +
+
{txn.timestamp}
+ +
+ ))} +
+ ); +}; + +type Transaction = { + hash: string; + status: "pending" | "success" | "failed"; + timestamp: string; +}; +``` + +### Dashboard Cards + + +
+ {[ + { + title: "Staking Rewards", + value: "12.5 SOL", + status: "success", + note: "Last claim successful", + }, + { + title: "Liquidity Pool", + value: "$1,250", + status: "confirming", + note: "Adding liquidity...", + }, + { + title: "NFT Collection", + value: "24 NFTs", + status: "error", + note: "Mint failed", + }, + ].map((card, idx) => ( +
+
+

{card.title}

+ +
+
{card.value}
+

{card.note}

+
+ ))} +
+
+ +```tsx +"use client"; + +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; + +export default function DashboardCards() { + return ( +
+ {/* Staking Rewards */} + + + + Staking Rewards + + + + +
+ 12.5 SOL +
+

+ Last claim successful +

+
+
+ + {/* Liquidity Pool */} + + + + Liquidity Pool + + + + +
+ $1,250 +
+

+ Adding liquidity... +

+
+
+ + {/* NFT Collection */} + + + + NFT Collection + + + + +
+ 24 NFTs +
+

+ Mint failed +

+
+
+
+ ); +} +``` + +### Data Table + + +
+
+

Transaction Table Example

+
+ + + + + + + + + + + {[ + { + id: "1", + transaction: "0x1234...abcd", + amount: "100 USDC", + time: "2024-01-01", + status: "success", + }, + { + id: "2", + transaction: "0x5678...efgh", + amount: "50 USDC", + time: "2024-01-02", + status: "confirming", + }, + { + id: "3", + transaction: "0x9876...ijkl", + amount: "20 USDC", + time: "2024-01-03", + status: "error", + }, + ].map((row) => ( + + + + + + + ))} + +
+ Transaction + + Amount + + Time + + Status +
+ {row.transaction} + + {row.amount} + + {row.time} + + +
+
+
+
+
+ +```tsx +"use client"; + +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status"; + +interface TableTransaction { + id: string; + transaction: string; + amount: string; + time: string; + status: "success" | "confirming" | "error" | "idle"; +} + +export default function TransactionTable({ + data, +}: { + data: TableTransaction[]; +}) { + return ( +
+

Transaction History

+ +
+ + + + + + + + + + + {data.map((row) => ( + + + + + + + ))} + +
+ Transaction + + Amount + + Time + + Status +
{row.transaction}{row.amount}{row.time} + +
+
+
+ ); +} +``` + +### Portfolio Overview + + +
+

Portfolio

+ + {[ + { + symbol: "SOL", + name: "Solana", + balance: "12.5", + value: "$400", + lastTransaction: "success", + }, + { + symbol: "USDC", + name: "USD Coin", + balance: "200", + value: "$200", + lastTransaction: "confirming", + }, + ].map((item) => ( +
+
+
+ {item.symbol.slice(0, 2)} +
+
+

{item.name}

+

+ {item.balance} {item.symbol} +

+
+
+ +
+

{item.value}

+
+ + Last txn: + + +
+
+
+ ))} +
+
+ +```tsx +"use client"; + +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status"; + +("use client"); + +import { InlineTxnStatus } from "@/components/ui/murphy/Txn-Feedback/inline-txn-status"; + +interface PortfolioItem { + symbol: string; + name: string; + balance: string; + value: string; + lastTransaction: "success" | "confirming" | "error" | "idle"; +} + +export default function PortfolioOverview({ + items, +}: { + items: PortfolioItem[]; +}) { + return ( +
+

Portfolio

+ +
+ {items.map((item) => ( +
+
+
+ {item.symbol.slice(0, 2)} +
+
+

{item.name}

+

+ {item.balance} {item.symbol} +

+
+
+ +
+

{item.value}

+
+ Last txn: + +
+
+
+ ))} +
+
+ ); +} +``` + +## Status States + +### Success State + +- **Icon**: CheckCircle (green) +- **Text**: "Success" +- **Use**: Completed transactions +- **Color**: Green theme + +### Error State + +- **Icon**: XCircle (red) +- **Text**: "Failed" +- **Use**: Failed transactions +- **Color**: Red theme + +### Processing States + +- **Icon**: Loader2 (blue, animated) +- **Text**: "Processing" +- **Use**: preparing, signing, sending, confirming +- **Color**: Blue theme +- **Animation**: Spinning loader + +### Idle State + +- **Icon**: Clock (gray) +- **Text**: "Pending" +- **Use**: Queued or idle transactions +- **Color**: Gray theme + +## Size Variations + +### Small (sm) + +- Icon: 12px (w-3 h-3) +- Text: text-xs +- Use: Table cells, compact lists + +### Medium (md) - Default + +- Icon: 16px (w-4 h-4) +- Text: text-sm +- Use: General purpose, cards + +### Large (lg) + +- Icon: 20px (w-5 h-5) +- Text: text-base +- Use: Prominent displays, headers + +## Customization + +### Custom Colors + +```tsx +// Custom status colors via CSS classes + +``` + +### Custom Icons + +```tsx +// You can extend the component to use custom icons +const CustomInlineStatus = ({ status, customIcon }) => { + return ( + + {customIcon || } + Custom Status + + ); +}; +``` + +### Responsive Sizing + +```tsx + +``` diff --git a/content/docs/onchainkit/Txn-Feedback/step-flow-dialog.mdx b/content/docs/onchainkit/Txn-Feedback/step-flow-dialog.mdx new file mode 100644 index 0000000..d3f0393 --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/step-flow-dialog.mdx @@ -0,0 +1,209 @@ +--- +title: Step Flow Dialog +description: Modal for complex multi-step transaction workflows +icon: Workflow +--- +import StepFlowDialogPreview from "@/components/step-flow-dialog-preview" + + + + + +## Installation + + + + Install Step Flow Dialog + + + + + + +## Basic Usage + +```tsx +"use client" + +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { StepFlowDialog } from "@/components/ui/murphy/step-flow-dialog" + +export default function StepFlowDemo() { + const [open, setOpen] = useState(false) + const [step, setStep] = useState(0) + + const steps = [ + { id: "1", title: "Step One", description: "Do something", status: "pending" }, + { id: "2", title: "Step Two", description: "Do next thing", status: "pending" }, + { id: "3", title: "Step Three", description: "Finish it", status: "pending" }, + ] + + return ( + <> + + + setStep((prev) => prev + 1)} + onPrevious={() => setStep((prev) => prev - 1)} + onCancel={() => setOpen(false)} + canGoPrevious={step > 0} + canGoNext={step < steps.length - 1} + /> + + ) +} + +``` + +## Props + + void", + default: "required", + }, + title: { + description: "Dialog title", + type: "string", + default: "required", + }, + description: { + description: "Dialog description", + type: "string", + default: "undefined", + }, + steps: { + description: "Array of steps in the workflow", + type: "TxnStep[]", + default: "required", + }, + currentStep: { + description: "Index of the current active step", + type: "number", + default: "required", + }, + onNext: { + description: "Callback when next button is clicked", + type: "() => Promise | void", + default: "undefined", + }, + onPrevious: { + description: "Callback when previous button is clicked", + type: "() => void", + default: "undefined", + }, + onCancel: { + description: "Callback when cancel button is clicked", + type: "() => void", + default: "undefined", + }, + nextButtonText: { + description: "Text for the next button", + type: "string", + default: "'Next'", + }, + previousButtonText: { + description: "Text for the previous button", + type: "string", + default: "'Previous'", + }, + cancelButtonText: { + description: "Text for the cancel button", + type: "string", + default: "'Cancel'", + }, + isLoading: { + description: "Whether the dialog is in loading state", + type: "boolean", + default: "false", + }, + canGoNext: { + description: "Whether the next button should be enabled", + type: "boolean", + default: "true", + }, + canGoPrevious: { + description: "Whether the previous button should be enabled", + type: "boolean", + default: "true", + }, + showCancel: { + description: "Whether to show the cancel button", + type: "boolean", + default: "true", + } +}} /> + + + +## Dialog Features + +### Visual Progress Tracking +- Step-by-step progress visualization +- Current step highlighting +- Completed step indicators +- Error state visualization + +### Navigation Controls +- Next/Previous button navigation +- Cancel functionality +- Conditional button states +- Loading state management + +### Step Information +- Step titles and descriptions +- Current step details +- Progress indicators +- Status-based styling + +### Async Operation Support +- Loading states during processing +- Error handling and retry +- Step validation +- Progress persistence + +## Customization + +### Custom Button Labels + +```tsx + +``` + +### Custom Styling + +```tsx + +``` + +### Conditional Navigation + +```tsx + 0 && !isLoading} + showCancel={!isProcessing} + // ... other props +/> +``` + diff --git a/content/docs/onchainkit/Txn-Feedback/success-dialog.mdx b/content/docs/onchainkit/Txn-Feedback/success-dialog.mdx new file mode 100644 index 0000000..79e3aeb --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/success-dialog.mdx @@ -0,0 +1,276 @@ +--- +title: Success Dialog +description: Celebration modal for successful transaction completion +icon: Check +--- + +import SuccessDialogPreview from "@/components/success-dialog-preview"; + + +
+ +

+ Click buttons above to see success dialogs +

+
+
+ +## Installation + + + +{" "} + + + Install Success Dialog + + + + + +## Basic Usage + +```tsx +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { SuccessDialog } from "@/components/ui/murphy/success-dialog"; + +export default function MyPage() { + const [showSuccess, setShowSuccess] = useState(false); + + const handleTransaction = async () => { + try { + // Your transaction logic here + const signature = await executeTransaction(); + + // Show success dialog + setShowSuccess(true); + } catch (error) { + console.error("Transaction failed:", error); + } + }; + + return ( +
+

Transaction Demo

+ + + + + window.open(`https://explorer.solana.com/tx/${signature}`, "_blank") + } + onClose={() => setShowSuccess(false)} + /> +
+ ); +} +``` + +## Props + + void", + default: "required", + }, + title: { + description: "Dialog title text", + type: "string", + default: "'Transaction Successful! 🎉'", + }, + description: { + description: "Dialog description text", + type: "string", + default: "'Your transaction has been confirmed on the blockchain'", + }, + signature: { + description: "Transaction signature to display", + type: "string", + default: "undefined", + }, + amount: { + description: "Transaction amount", + type: "string", + default: "undefined", + }, + token: { + description: "Token symbol or name", + type: "string", + default: "undefined", + }, + recipient: { + description: "Recipient wallet address", + type: "string", + default: "undefined", + }, + onViewExplorer: { + description: "Callback when explorer link is clicked", + type: "() => void", + default: "undefined", + }, + onClose: { + description: "Callback when dialog is closed", + type: "() => void", + default: "undefined", + }, + }} +/> + +## Examples + +### Token Transfer Success + +```tsx + openExplorer(signature)} +/> +``` + +### NFT Minting Success + +```tsx + openExplorer(signature)} +/> +``` + +### Staking Success + +```tsx + openExplorer(signature)} +/> +``` + +### Simple Success (No Amount) + +```tsx + openExplorer(signature)} +/> +``` + +## Dialog Features + +### Celebratory Design + +- Large success icon with green color scheme +- Celebratory emojis in titles +- Positive messaging and visual feedback + +### Transaction Information + +- Transaction signature display with copy functionality +- Amount and token information prominently displayed +- Recipient address when applicable + +### Explorer Integration + +- Direct links to Solana Explorer +- Support for different clusters (mainnet, devnet, testnet) +- One-click transaction verification + +### Copy Functionality + +- Copy transaction signature to clipboard +- Visual feedback when copied +- Automatic clipboard API detection + +## Customization + +### Custom Titles and Messages + +```tsx +const getCustomTitle = (transactionType: string, success: boolean) => { + if (!success) return "Transaction Failed"; + + const titles = { + transfer: "Money Sent! 💰", + mint: "NFT Created! 🎨", + stake: "Earning Rewards! 📈", + swap: "Tokens Swapped! 🔄", + }; + + return titles[transactionType] || "Success! ✅"; +}; + +; +``` + +### Custom Styling + +```tsx + +``` + +### Conditional Content + +```tsx + +``` diff --git a/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx b/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx new file mode 100644 index 0000000..5a25d8a --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx @@ -0,0 +1,197 @@ +--- +title: Transaction Error Fallback +description: Comprehensive error handling UI with retry and debugging features +icon: AlertTriangle +--- + +import TxnErrorFallbackPreiew from "@/components/txn-error-fallback-preview"; + + +
+ +
+
+ +## Installation + + + + Install dependencies + + + + + +{" "} + + + Install Transaction Error Fallback + + + + + Add the component to your project + + After installation, you can find the component in `components/ui/murphy/txn-error-fallback.tsx` + + + + +## Basic Usage + +```tsx +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { TxnnErrorFallback } from "@/components/ui/murphy/txn-error-fallback"; + +export default function MyPage() { + const [showError, setShowError] = useState(false); + + const handleRetry = () => { + console.log("Retrying transaction..."); + setShowError(false); + // Your retry logic here + }; + + return ( +
+

Error Handling Demo

+ + + + {showError && ( +
+ setShowError(false)} + /> +
+ )} +
+ ); +} +``` + +## Props + + void", + default: "undefined", + }, + onClose: { + description: "Callback function when close button is clicked", + type: "() => void", + default: "undefined", + }, + showLogs: { + description: "Whether to show expandable transaction logs", + type: "boolean", + default: "false", + }, + logs: { + description: "Array of log messages to display", + type: "string[]", + default: "[]", + }, + }} +/> + +## Examples + +### Simple Error + +```tsx + retryTransaction()} + onClose={() => closeError()} +/> +``` + +### Error with Transaction Signature + +```tsx + retryTransaction()} + onClose={() => closeError()} +/> +``` + +### Error with Transaction Logs + +```tsx + retryTransaction()} + onClose={() => closeError()} + showLogs={true} + logs={[ + "Program 11111111111111111111111111111111 invoke [1]", + "Program log: Instruction: Transfer", + "Program log: Error: custom program error: 0x1771", + "Program 11111111111111111111111111111111 consumed 200000 of 200000 compute units", + "Program 11111111111111111111111111111111 failed: custom program error: 0x1771", + ]} +/> +``` + +## Customization + +### Custom Error Messages + +```tsx +const getErrorMessage = (error: string) => { + const errorMap = { + "insufficient funds": "You need more SOL to complete this transaction", + "network error": "Connection problem - please try again", + timeout: "Transaction is taking longer than expected", + "program error": "Smart contract issue - please contact support", + }; + + for (const [key, message] of Object.entries(errorMap)) { + if (error.toLowerCase().includes(key)) { + return message; + } + } + + return error; +}; +``` + +### Custom Styling + +```tsx + +``` diff --git a/content/docs/onchainkit/meta.json b/content/docs/onchainkit/meta.json index d2b1c3b..329e6c2 100644 --- a/content/docs/onchainkit/meta.json +++ b/content/docs/onchainkit/meta.json @@ -31,6 +31,7 @@ "Metaplex", "Meteora-DBC", "ZK-Compression", - "Jupiter-Recurring" + "Jupiter-Recurring", + "Txn-Feedback" ] } diff --git a/public/r/CancelRecurringOrder.json b/public/r/CancelRecurringOrder.json index 1c61727..e4c004a 100644 --- a/public/r/CancelRecurringOrder.json +++ b/public/r/CancelRecurringOrder.json @@ -12,7 +12,7 @@ "files": [ { "path": "components/ui/murphy/Jupiter-Recurring/CancelRecurringOrder.tsx", - "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { useWallet } from \"@solana/wallet-adapter-react\"\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\"\nimport { Button } from \"@/components/ui/button\"\nimport { Input } from \"@/components/ui/input\"\nimport { Label } from \"@/components/ui/label\"\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\"\nimport { Alert, AlertDescription } from \"@/components/ui/alert\"\nimport { Loader2, Info, ExternalLink } from \"lucide-react\"\nimport { toast } from \"sonner\"\nimport { cn } from \"@/lib/utils\"\n\nexport type RecurringType = \"time\" | \"price\"\n\ninterface CancelOrderResponse {\n requestId: string\n transaction: string\n}\n\ninterface CancelOrderError {\n code: number\n error: string\n status: string\n}\n\nexport function CancelRecurringOrder({ className }: { className?: string }) {\n const { publicKey, connected, signTransaction } = useWallet()\n const [orderId, setOrderId] = useState(\"\")\n const [recurringType, setRecurringType] = useState(\"time\")\n const [loading, setLoading] = useState(false)\n const [result, setResult] = useState<{\n success: boolean\n message: string\n requestId?: string\n transaction?: string\n } | null>(null)\n\n const handleCancelOrder = async () => {\n if (!connected || !publicKey || !signTransaction) {\n toast.error(\"Please connect your wallet first\")\n return\n }\n\n if (!orderId.trim()) {\n toast.error(\"Please enter an order ID\")\n return\n }\n\n setLoading(true)\n setResult(null)\n\n try {\n // Step 1: Get cancel transaction from Jupiter API\n const cancelResponse = await fetch(\"https://lite-api.jup.ag/recurring/v1/cancelOrder\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n order: orderId.trim(),\n user: publicKey.toString(),\n recurringType: recurringType,\n }),\n })\n\n const cancelData: CancelOrderResponse | CancelOrderError = await cancelResponse.json()\n\n if (!cancelResponse.ok) {\n const errorData = cancelData as CancelOrderError\n throw new Error(errorData.error || `HTTP ${cancelResponse.status}: ${errorData.status}`)\n }\n\n const successData = cancelData as CancelOrderResponse\n\n // Step 2: Execute the transaction\n const executeResponse = await fetch(\"https://lite-api.jup.ag/recurring/v1/execute\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n requestId: successData.requestId,\n transaction: successData.transaction,\n }),\n })\n\n const executeData = await executeResponse.json()\n\n // Nếu API trả về transaction cần ký (giả sử có field 'needsSignature' và 'transaction')\n if (executeData.needsSignature && executeData.transaction) {\n try {\n const txBuffer = Buffer.from(executeData.transaction, \"base64\")\n // @ts-ignore\n const { Transaction } = await import(\"@solana/web3.js\")\n const tx = Transaction.from(txBuffer)\n const signed = await signTransaction(tx)\n\n // Gửi giao dịch đã ký lên mạng\n const sendResp = await fetch(\"https://lite-api.jup.ag/recurring/v1/execute\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n requestId: successData.requestId,\n transaction: Buffer.from(signed.serialize()).toString(\"base64\"),\n }),\n })\n\n const sendData = await sendResp.json()\n if (!sendResp.ok) throw new Error(sendData.error || \"Failed to send signed transaction\")\n\n setResult({\n success: true,\n message: \"Order cancelled and signed successfully!\",\n requestId: successData.requestId,\n transaction: sendData.txid || sendData.transaction || executeData.transaction,\n })\n toast.success(\"Order cancelled and signed successfully!\")\n setOrderId(\"\")\n return\n } catch (e: any) {\n setResult({ success: false, message: e.message || \"Failed to sign transaction\" })\n toast.error(e.message || \"Failed to sign transaction\")\n setLoading(false)\n return\n }\n }\n\n if (!executeResponse.ok) {\n throw new Error(executeData.error || `Failed to execute transaction: ${executeResponse.status}`)\n }\n\n setResult({\n success: true,\n message: \"Order cancelled successfully!\",\n requestId: successData.requestId,\n transaction: executeData.txid || executeData.transaction || successData.transaction,\n })\n toast.success(\"Order cancelled successfully!\")\n\n // Clear form\n setOrderId(\"\")\n } catch (error: any) {\n console.error(\"Cancel order error:\", error)\n setResult({\n success: false,\n message: error.message || \"Failed to cancel order\",\n })\n toast.error(error.message || \"Failed to cancel order\")\n } finally {\n setLoading(false)\n }\n }\n\n if (!connected || !publicKey) {\n return (\n \n \n Cancel Recurring Order\n \n \n \n Please connect your wallet to cancel recurring orders.\n \n \n \n )\n }\n\n return (\n \n \n Cancel Recurring Order\n

Permanently cancel your active recurring DCA orders

\n
\n \n {/* Order Details */}\n
\n

\n \n Order Details\n

\n\n
\n
\n \n setOrderId(e.target.value)}\n disabled={loading}\n className=\"h-12 text-lg font-mono\"\n />\n
\n\n
\n \n setRecurringType(value)}\n disabled={loading}\n >\n \n \n \n \n Time-based\n Price-based\n \n \n
\n
\n
\n\n {/* Warning */}\n \n \n
\n

Warning: This action cannot be undone

\n

\n Cancelling this recurring order will permanently stop all future executions. Make sure you have the\n correct Order ID before proceeding.\n

\n
\n
\n
\n\n {/* Action Button */}\n \n {loading ? (\n <>\n \n Cancelling Order...\n \n ) : (\n \"Cancel Order\"\n )}\n \n\n {/* Result Display */}\n {result && (\n
\n {result.success ? (\n \n \n
\n

{result.message}

\n\n {result.requestId && (\n
\n Request ID:\n \n {result.requestId}\n \n
\n )}\n\n {result.transaction && (\n
\n
\n Transaction:\n \n
\n \n {result.transaction}\n \n
\n )}\n
\n
\n
\n ) : (\n \n \n
\n

Cancellation Failed

\n
\n

{result.message}

\n
\n

\n Please check your Order ID and try again. If the problem persists, contact support.\n

\n
\n
\n
\n )}\n
\n )}\n\n {/* Instructions */}\n
\n

How to Cancel Orders:

\n
    \n
  1. Enter the Order ID from your recurring order
  2. \n
  3. Select the correct recurring type (time-based or price-based)
  4. \n
  5. Review the warning and click \"Cancel Order\"
  6. \n
  7. Sign the transaction when prompted by your wallet
  8. \n
  9. Wait for confirmation on the Solana network
  10. \n
\n

\n Tip: You can find your Order ID in your order history or transaction records.\n

\n
\n
\n
\n )\n}\n\nexport default CancelRecurringOrder\n", + "content": "\"use client\"\r\n\r\nimport { useState } from \"react\"\r\nimport { useWallet } from \"@solana/wallet-adapter-react\"\r\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { Input } from \"@/components/ui/input\"\r\nimport { Label } from \"@/components/ui/label\"\r\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\"\r\nimport { Alert, AlertDescription } from \"@/components/ui/alert\"\r\nimport { Loader2, Info, ExternalLink } from \"lucide-react\"\r\nimport { toast } from \"sonner\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nexport type RecurringType = \"time\" | \"price\"\r\n\r\ninterface CancelOrderResponse {\r\n requestId: string\r\n transaction: string\r\n}\r\n\r\ninterface CancelOrderError {\r\n code: number\r\n error: string\r\n status: string\r\n}\r\n\r\nexport function CancelRecurringOrder({ className }: { className?: string }) {\r\n const { publicKey, connected, signTransaction } = useWallet()\r\n const [orderId, setOrderId] = useState(\"\")\r\n const [recurringType, setRecurringType] = useState(\"time\")\r\n const [loading, setLoading] = useState(false)\r\n const [result, setResult] = useState<{\r\n success: boolean\r\n message: string\r\n requestId?: string\r\n transaction?: string\r\n } | null>(null)\r\n\r\n const handleCancelOrder = async () => {\r\n if (!connected || !publicKey || !signTransaction) {\r\n toast.error(\"Please connect your wallet first\")\r\n return\r\n }\r\n\r\n if (!orderId.trim()) {\r\n toast.error(\"Please enter an order ID\")\r\n return\r\n }\r\n\r\n setLoading(true)\r\n setResult(null)\r\n\r\n try {\r\n // Step 1: Get cancel transaction from Jupiter API\r\n const cancelResponse = await fetch(\"https://lite-api.jup.ag/recurring/v1/cancelOrder\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify({\r\n order: orderId.trim(),\r\n user: publicKey.toString(),\r\n recurringType: recurringType,\r\n }),\r\n })\r\n\r\n const cancelData: CancelOrderResponse | CancelOrderError = await cancelResponse.json()\r\n\r\n if (!cancelResponse.ok) {\r\n const errorData = cancelData as CancelOrderError\r\n throw new Error(errorData.error || `HTTP ${cancelResponse.status}: ${errorData.status}`)\r\n }\r\n\r\n const successData = cancelData as CancelOrderResponse\r\n\r\n // Step 2: Execute the transaction\r\n const executeResponse = await fetch(\"https://lite-api.jup.ag/recurring/v1/execute\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify({\r\n requestId: successData.requestId,\r\n transaction: successData.transaction,\r\n }),\r\n })\r\n\r\n const executeData = await executeResponse.json()\r\n\r\n // Nếu API trả về transaction cần ký (giả sử có field 'needsSignature' và 'transaction')\r\n if (executeData.needsSignature && executeData.transaction) {\r\n try {\r\n const txBuffer = Buffer.from(executeData.transaction, \"base64\")\r\n // @ts-ignore\r\n const { Transaction } = await import(\"@solana/web3.js\")\r\n const tx = Transaction.from(txBuffer)\r\n const signed = await signTransaction(tx)\r\n\r\n // Gửi giao dịch đã ký lên mạng\r\n const sendResp = await fetch(\"https://lite-api.jup.ag/recurring/v1/execute\", {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n requestId: successData.requestId,\r\n transaction: Buffer.from(signed.serialize()).toString(\"base64\"),\r\n }),\r\n })\r\n\r\n const sendData = await sendResp.json()\r\n if (!sendResp.ok) throw new Error(sendData.error || \"Failed to send signed transaction\")\r\n\r\n setResult({\r\n success: true,\r\n message: \"Order cancelled and signed successfully!\",\r\n requestId: successData.requestId,\r\n transaction: sendData.txid || sendData.transaction || executeData.transaction,\r\n })\r\n toast.success(\"Order cancelled and signed successfully!\")\r\n setOrderId(\"\")\r\n return\r\n } catch (e: any) {\r\n setResult({ success: false, message: e.message || \"Failed to sign transaction\" })\r\n toast.error(e.message || \"Failed to sign transaction\")\r\n setLoading(false)\r\n return\r\n }\r\n }\r\n\r\n if (!executeResponse.ok) {\r\n throw new Error(executeData.error || `Failed to execute transaction: ${executeResponse.status}`)\r\n }\r\n\r\n setResult({\r\n success: true,\r\n message: \"Order cancelled successfully!\",\r\n requestId: successData.requestId,\r\n transaction: executeData.txid || executeData.transaction || successData.transaction,\r\n })\r\n toast.success(\"Order cancelled successfully!\")\r\n\r\n // Clear form\r\n setOrderId(\"\")\r\n } catch (error: any) {\r\n console.error(\"Cancel order error:\", error)\r\n setResult({\r\n success: false,\r\n message: error.message || \"Failed to cancel order\",\r\n })\r\n toast.error(error.message || \"Failed to cancel order\")\r\n } finally {\r\n setLoading(false)\r\n }\r\n }\r\n\r\n if (!connected || !publicKey) {\r\n return (\r\n \r\n \r\n Cancel Recurring Order\r\n \r\n \r\n \r\n Please connect your wallet to cancel recurring orders.\r\n \r\n \r\n \r\n )\r\n }\r\n\r\n return (\r\n \r\n \r\n Cancel Recurring Order\r\n

Permanently cancel your active recurring DCA orders

\r\n
\r\n \r\n {/* Order Details */}\r\n
\r\n

\r\n \r\n Order Details\r\n

\r\n\r\n
\r\n
\r\n \r\n setOrderId(e.target.value)}\r\n disabled={loading}\r\n className=\"h-12 text-lg font-mono\"\r\n />\r\n
\r\n\r\n
\r\n \r\n setRecurringType(value)}\r\n disabled={loading}\r\n >\r\n \r\n \r\n \r\n \r\n Time-based\r\n Price-based\r\n \r\n \r\n
\r\n
\r\n
\r\n\r\n {/* Warning */}\r\n \r\n \r\n
\r\n

Warning: This action cannot be undone

\r\n

\r\n Cancelling this recurring order will permanently stop all future executions. Make sure you have the\r\n correct Order ID before proceeding.\r\n

\r\n
\r\n
\r\n
\r\n\r\n {/* Action Button */}\r\n \r\n {loading ? (\r\n <>\r\n \r\n Cancelling Order...\r\n \r\n ) : (\r\n \"Cancel Order\"\r\n )}\r\n \r\n\r\n {/* Result Display */}\r\n {result && (\r\n
\r\n {result.success ? (\r\n \r\n \r\n
\r\n

{result.message}

\r\n\r\n {result.requestId && (\r\n
\r\n Request ID:\r\n \r\n {result.requestId}\r\n \r\n
\r\n )}\r\n\r\n {result.transaction && (\r\n
\r\n
\r\n Transaction:\r\n \r\n
\r\n \r\n {result.transaction}\r\n \r\n
\r\n )}\r\n
\r\n
\r\n
\r\n ) : (\r\n \r\n \r\n
\r\n

Cancellation Failed

\r\n
\r\n

{result.message}

\r\n
\r\n

\r\n Please check your Order ID and try again. If the problem persists, contact support.\r\n

\r\n
\r\n
\r\n
\r\n )}\r\n
\r\n )}\r\n\r\n {/* Instructions */}\r\n
\r\n

How to Cancel Orders:

\r\n
    \r\n
  1. Enter the Order ID from your recurring order
  2. \r\n
  3. Select the correct recurring type (time-based or price-based)
  4. \r\n
  5. Review the warning and click \"Cancel Order\"
  6. \r\n
  7. Sign the transaction when prompted by your wallet
  8. \r\n
  9. Wait for confirmation on the Solana network
  10. \r\n
\r\n

\r\n Tip: You can find your Order ID in your order history or transaction records.\r\n

\r\n
\r\n
\r\n
\r\n )\r\n}\r\n\r\nexport default CancelRecurringOrder\r\n", "type": "registry:component", "target": "components/ui/murphy/Jupiter-Recurring/CancelRecurringOrder.tsx" } diff --git a/public/r/RecurringActiveOrders.json b/public/r/RecurringActiveOrders.json index b868147..8cecba1 100644 --- a/public/r/RecurringActiveOrders.json +++ b/public/r/RecurringActiveOrders.json @@ -12,7 +12,7 @@ "files": [ { "path": "components/ui/murphy/Jupiter-Recurring/RecurringActiveOrders.tsx", - "content": "\"use client\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\nimport { RefreshCw } from \"lucide-react\";\nimport { useEffect } from \"react\";\nimport useRecurringJupiter from \"./useRecurringJupiter\";\nimport { RecurringOrderCard } from \"./RecurringOrderCard\";\nimport { cn } from \"@/lib/utils\";\n\nexport function RecurringActiveOrders({ className }: { className?: string }) {\n const { publicKey, connected } = useWallet();\n const {\n loading,\n error,\n data,\n refetch,\n } = useRecurringJupiter(\"all\", \"active\");\n\n // Auto-fetch data when wallet connects\n useEffect(() => {\n if (connected && publicKey) {\n refetch();\n }\n }, [connected, publicKey, refetch]);\n\n if (!connected || !publicKey) {\n return (\n \n \n Active Recurring Orders\n \n \n

Please connect your wallet to view active orders.

\n
\n
\n );\n }\n\n return (\n \n \n Active Recurring Orders\n refetch()}\n disabled={loading}\n className=\"min-w-[40px] flex items-center justify-center\"\n aria-label=\"Refresh\"\n >\n \n \n \n \n {error && (\n typeof error === \"string\" && error.trim().startsWith(\"{\") && error.trim().endsWith(\"}\")\n ?
No active recurring orders found.
\n :
{error}
\n )}\n {loading &&
Loading orders...
}\n {!loading && (!data || data.length === 0) && (\n
No active recurring orders found.
\n )}\n
\n {data && data.map((order: any) => (\n \n ))}\n
\n
\n
\n );\n}\n\nexport default RecurringActiveOrders; \n", + "content": "\"use client\";\r\nimport { useWallet } from \"@solana/wallet-adapter-react\";\r\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { RefreshCw } from \"lucide-react\";\r\nimport { useEffect } from \"react\";\r\nimport useRecurringJupiter from \"./useRecurringJupiter\";\r\nimport { RecurringOrderCard } from \"./RecurringOrderCard\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nexport function RecurringActiveOrders({ className }: { className?: string }) {\r\n const { publicKey, connected } = useWallet();\r\n const {\r\n loading,\r\n error,\r\n data,\r\n refetch,\r\n } = useRecurringJupiter(\"all\", \"active\");\r\n\r\n // Auto-fetch data when wallet connects\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n refetch();\r\n }\r\n }, [connected, publicKey, refetch]);\r\n\r\n if (!connected || !publicKey) {\r\n return (\r\n \r\n \r\n Active Recurring Orders\r\n \r\n \r\n

Please connect your wallet to view active orders.

\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n Active Recurring Orders\r\n refetch()}\r\n disabled={loading}\r\n className=\"min-w-[40px] flex items-center justify-center\"\r\n aria-label=\"Refresh\"\r\n >\r\n \r\n \r\n \r\n \r\n {error && (\r\n typeof error === \"string\" && error.trim().startsWith(\"{\") && error.trim().endsWith(\"}\")\r\n ?
No active recurring orders found.
\r\n :
{error}
\r\n )}\r\n {loading &&
Loading orders...
}\r\n {!loading && (!data || data.length === 0) && (\r\n
No active recurring orders found.
\r\n )}\r\n
\r\n {data && data.map((order: any) => (\r\n \r\n ))}\r\n
\r\n
\r\n
\r\n );\r\n}\r\n\r\nexport default RecurringActiveOrders; \r\n", "type": "registry:component", "target": "components/ui/murphy/Jupiter-Recurring/RecurringActiveOrders.tsx" } diff --git a/public/r/RecurringHistoryList.json b/public/r/RecurringHistoryList.json index cdc41bb..1fce4b6 100644 --- a/public/r/RecurringHistoryList.json +++ b/public/r/RecurringHistoryList.json @@ -12,7 +12,7 @@ "files": [ { "path": "components/ui/murphy/Jupiter-Recurring/RecurringHistoryList.tsx", - "content": "\"use client\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\nimport { RefreshCw } from \"lucide-react\";\nimport { useEffect } from \"react\";\nimport useRecurringJupiter from \"./useRecurringJupiter\";\nimport { RecurringOrderCard } from \"./RecurringOrderCard\";\nimport { cn } from \"@/lib/utils\";\n\nexport function RecurringHistoryList({ className }: { className?: string }) {\n const { publicKey, connected } = useWallet();\n const {\n loading,\n error,\n data,\n refetch,\n } = useRecurringJupiter(\"all\", \"history\");\n\n // Auto-fetch data when wallet connects\n useEffect(() => {\n if (connected && publicKey) {\n refetch();\n }\n }, [connected, publicKey, refetch]);\n\n if (!connected || !publicKey) {\n return (\n \n \n Recurring Order History\n \n \n

Please connect your wallet to view order history.

\n
\n
\n );\n }\n\n return (\n \n \n Recurring Order History\n refetch()}\n disabled={loading}\n className=\"min-w-[40px] flex items-center justify-center\"\n aria-label=\"Refresh\"\n >\n \n \n \n \n {error && (\n typeof error === \"string\" && error.trim().startsWith(\"{\") && error.trim().endsWith(\"}\")\n ?
No order history found.
\n :
{error}
\n )}\n {loading &&
Loading order history...
}\n {!loading && (!data || data.length === 0) && (\n
No order history found.
\n )}\n
\n {data && data.map((order: any) => (\n \n ))}\n
\n
\n
\n );\n}\n\nexport default RecurringHistoryList; \n", + "content": "\"use client\";\r\nimport { useWallet } from \"@solana/wallet-adapter-react\";\r\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { RefreshCw } from \"lucide-react\";\r\nimport { useEffect } from \"react\";\r\nimport useRecurringJupiter from \"./useRecurringJupiter\";\r\nimport { RecurringOrderCard } from \"./RecurringOrderCard\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nexport function RecurringHistoryList({ className }: { className?: string }) {\r\n const { publicKey, connected } = useWallet();\r\n const {\r\n loading,\r\n error,\r\n data,\r\n refetch,\r\n } = useRecurringJupiter(\"all\", \"history\");\r\n\r\n // Auto-fetch data when wallet connects\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n refetch();\r\n }\r\n }, [connected, publicKey, refetch]);\r\n\r\n if (!connected || !publicKey) {\r\n return (\r\n \r\n \r\n Recurring Order History\r\n \r\n \r\n

Please connect your wallet to view order history.

\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n Recurring Order History\r\n refetch()}\r\n disabled={loading}\r\n className=\"min-w-[40px] flex items-center justify-center\"\r\n aria-label=\"Refresh\"\r\n >\r\n \r\n \r\n \r\n \r\n {error && (\r\n typeof error === \"string\" && error.trim().startsWith(\"{\") && error.trim().endsWith(\"}\")\r\n ?
No order history found.
\r\n :
{error}
\r\n )}\r\n {loading &&
Loading order history...
}\r\n {!loading && (!data || data.length === 0) && (\r\n
No order history found.
\r\n )}\r\n
\r\n {data && data.map((order: any) => (\r\n \r\n ))}\r\n
\r\n
\r\n
\r\n );\r\n}\r\n\r\nexport default RecurringHistoryList; \r\n", "type": "registry:component", "target": "components/ui/murphy/Jupiter-Recurring/RecurringHistoryList.tsx" } diff --git a/public/r/RecurringOrderCard.json b/public/r/RecurringOrderCard.json index 6678515..68a8013 100644 --- a/public/r/RecurringOrderCard.json +++ b/public/r/RecurringOrderCard.json @@ -12,7 +12,7 @@ "files": [ { "path": "components/ui/murphy/Jupiter-Recurring/RecurringOrderCard.tsx", - "content": "\"use client\"\n\nimport type React from \"react\"\nimport { Card, CardContent } from \"@/components/ui/card\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport { Copy, ExternalLink, Check } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { cn } from \"@/lib/utils\"\n\nexport interface RecurringOrder {\n id: string\n inputMint: string\n outputMint: string\n status: string\n createdAt: string\n updatedAt: string\n [key: string]: any\n}\n\nfunction shortAddress(addr: string) {\n return addr ? addr.slice(0, 4) + \"...\" + addr.slice(-4) : \"-\"\n}\n\nexport interface RecurringOrderCardProps {\n order: any\n className?: string\n style?: React.CSSProperties\n}\n\nexport function RecurringOrderCard({ order, className, style }: RecurringOrderCardProps) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = () => {\n navigator.clipboard.writeText(order.id)\n setCopied(true)\n setTimeout(() => setCopied(false), 1200)\n }\n\n const getStatusVariant = (status: string) => {\n switch (status.toLowerCase()) {\n case \"active\":\n case \"completed\":\n return \"default\"\n case \"cancelled\":\n case \"expired\":\n case \"failed\":\n return \"destructive\"\n case \"pending\":\n case \"processing\":\n return \"secondary\"\n default:\n return \"outline\"\n }\n }\n\n return (\n \n \n {/* Order ID */}\n
\n Order ID\n
\n {shortAddress(order.id)}\n \n {copied ? : }\n \n \n \n \n \n \n
\n
\n\n {/* From */}\n
\n From\n \n {shortAddress(order.inputMint)}\n \n
\n\n {/* To */}\n
\n To\n \n {shortAddress(order.outputMint)}\n \n
\n\n {/* Status */}\n
\n Status\n \n {order.status}\n \n
\n\n {/* Created */}\n
\n Created\n \n
\n\n {/* Updated (if different from created) */}\n {order.updatedAt && order.updatedAt !== order.createdAt && (\n
\n Updated\n \n
\n )}\n
\n \n )\n}\n\nexport default RecurringOrderCard\n", + "content": "\"use client\"\r\n\r\nimport type React from \"react\"\r\nimport { Card, CardContent } from \"@/components/ui/card\"\r\nimport { Badge } from \"@/components/ui/badge\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { Copy, ExternalLink, Check } from \"lucide-react\"\r\nimport { useState } from \"react\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nexport interface RecurringOrder {\r\n id: string\r\n inputMint: string\r\n outputMint: string\r\n status: string\r\n createdAt: string\r\n updatedAt: string\r\n [key: string]: any\r\n}\r\n\r\nfunction shortAddress(addr: string) {\r\n return addr ? addr.slice(0, 4) + \"...\" + addr.slice(-4) : \"-\"\r\n}\r\n\r\nexport interface RecurringOrderCardProps {\r\n order: any\r\n className?: string\r\n style?: React.CSSProperties\r\n}\r\n\r\nexport function RecurringOrderCard({ order, className, style }: RecurringOrderCardProps) {\r\n const [copied, setCopied] = useState(false)\r\n\r\n const handleCopy = () => {\r\n navigator.clipboard.writeText(order.id)\r\n setCopied(true)\r\n setTimeout(() => setCopied(false), 1200)\r\n }\r\n\r\n const getStatusVariant = (status: string) => {\r\n switch (status.toLowerCase()) {\r\n case \"active\":\r\n case \"completed\":\r\n return \"default\"\r\n case \"cancelled\":\r\n case \"expired\":\r\n case \"failed\":\r\n return \"destructive\"\r\n case \"pending\":\r\n case \"processing\":\r\n return \"secondary\"\r\n default:\r\n return \"outline\"\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n {/* Order ID */}\r\n
\r\n Order ID\r\n
\r\n {shortAddress(order.id)}\r\n \r\n {copied ? : }\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n\r\n {/* From */}\r\n
\r\n From\r\n \r\n {shortAddress(order.inputMint)}\r\n \r\n
\r\n\r\n {/* To */}\r\n
\r\n To\r\n \r\n {shortAddress(order.outputMint)}\r\n \r\n
\r\n\r\n {/* Status */}\r\n
\r\n Status\r\n \r\n {order.status}\r\n \r\n
\r\n\r\n {/* Created */}\r\n
\r\n Created\r\n \r\n
\r\n\r\n {/* Updated (if different from created) */}\r\n {order.updatedAt && order.updatedAt !== order.createdAt && (\r\n
\r\n Updated\r\n \r\n
\r\n )}\r\n
\r\n \r\n )\r\n}\r\n\r\nexport default RecurringOrderCard\r\n", "type": "registry:component", "target": "components/ui/murphy/Jupiter-Recurring/RecurringOrderCard.tsx" } diff --git a/public/r/RecurringOrderWidget.json b/public/r/RecurringOrderWidget.json index 10d02db..ffe1d70 100644 --- a/public/r/RecurringOrderWidget.json +++ b/public/r/RecurringOrderWidget.json @@ -12,7 +12,7 @@ "files": [ { "path": "components/ui/murphy/Jupiter-Recurring/RecurringOrderWidget.tsx", - "content": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\nimport useRecurringJupiter, { RecurringType, OrderStatus } from \"./useRecurringJupiter\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { RecurringOrderCard } from \"./RecurringOrderCard\";\nimport { cn } from \"@/lib/utils\";\nimport { RefreshCw, FolderOpen } from \"lucide-react\";\n\nconst RECURRING_TYPE_OPTIONS: { label: string; value: RecurringType }[] = [\n { label: \"Time-based\", value: \"time\" },\n { label: \"Price-based\", value: \"price\" },\n { label: \"All\", value: \"all\" },\n];\nconst ORDER_STATUS_OPTIONS: { label: string; value: OrderStatus }[] = [\n { label: \"Active\", value: \"active\" },\n { label: \"History\", value: \"history\" },\n];\n\nconst LOCAL_STATUS_OPTIONS = [\n { label: \"All\", value: \"all\" },\n { label: \"Completed\", value: \"completed\" },\n { label: \"Cancelled\", value: \"cancelled\" },\n { label: \"Expired\", value: \"expired\" },\n { label: \"Failed\", value: \"failed\" },\n];\n\nexport function RecurringOrderWidget({ className, style }: { className?: string; style?: React.CSSProperties }) {\n const { publicKey, connected } = useWallet();\n const {\n loading,\n error,\n data,\n recurringType,\n orderStatus,\n includeFailedTx,\n setRecurringType,\n setOrderStatus,\n setIncludeFailedTx,\n refetch,\n } = useRecurringJupiter();\n\n const [localStatus, setLocalStatus] = useState(\"all\");\n\n useEffect(() => {\n if (connected && publicKey) {\n refetch();\n }\n // eslint-disable-next-line\n }, [connected, publicKey]);\n\n if (!connected || !publicKey) {\n return (\n \n \n Recurring Orders\n \n \n

Please connect your wallet to view your recurring orders.

\n
\n
\n );\n }\n\n return (\n \n \n
\n Your Recurring Orders\n All your DCA orders in one place\n
\n
\n \n {/* Filter Bar */}\n
\n
\n \n \n {orderStatus === \"history\" && (\n \n )}\n
\n
\n
\n \n \n
\n \n
\n
\n {/* Content */}\n
\n {error && typeof error === \"string\" && (\n error.trim().startsWith(\"{\") && error.trim().endsWith(\"}\")\n ?
No orders found or API returned empty result.
\n :
{error}
\n )}\n {loading &&
Loading orders...
}\n {!loading && (!data || data.length === 0) && (\n
\n \n
No recurring orders found.
\n
\n )}\n
\n {data && data\n .filter((order: any) => {\n if (orderStatus !== \"history\") return true;\n if (localStatus === \"all\") return true;\n return order.status.toLowerCase() === localStatus.toLowerCase();\n })\n .map((order: any) => (\n
\n \n
\n ))}\n
\n
\n
\n
\n );\n}\n\nexport default RecurringOrderWidget; \n", + "content": "\"use client\";\r\n\r\nimport { useEffect, useState } from \"react\";\r\nimport { Card, CardHeader, CardTitle, CardContent } from \"@/components/ui/card\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { useWallet } from \"@solana/wallet-adapter-react\";\r\nimport useRecurringJupiter, { RecurringType, OrderStatus } from \"./useRecurringJupiter\";\r\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\r\nimport { Switch } from \"@/components/ui/switch\";\r\nimport { RecurringOrderCard } from \"./RecurringOrderCard\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { RefreshCw, FolderOpen } from \"lucide-react\";\r\n\r\nconst RECURRING_TYPE_OPTIONS: { label: string; value: RecurringType }[] = [\r\n { label: \"Time-based\", value: \"time\" },\r\n { label: \"Price-based\", value: \"price\" },\r\n { label: \"All\", value: \"all\" },\r\n];\r\nconst ORDER_STATUS_OPTIONS: { label: string; value: OrderStatus }[] = [\r\n { label: \"Active\", value: \"active\" },\r\n { label: \"History\", value: \"history\" },\r\n];\r\n\r\nconst LOCAL_STATUS_OPTIONS = [\r\n { label: \"All\", value: \"all\" },\r\n { label: \"Completed\", value: \"completed\" },\r\n { label: \"Cancelled\", value: \"cancelled\" },\r\n { label: \"Expired\", value: \"expired\" },\r\n { label: \"Failed\", value: \"failed\" },\r\n];\r\n\r\nexport function RecurringOrderWidget({ className, style }: { className?: string; style?: React.CSSProperties }) {\r\n const { publicKey, connected } = useWallet();\r\n const {\r\n loading,\r\n error,\r\n data,\r\n recurringType,\r\n orderStatus,\r\n includeFailedTx,\r\n setRecurringType,\r\n setOrderStatus,\r\n setIncludeFailedTx,\r\n refetch,\r\n } = useRecurringJupiter();\r\n\r\n const [localStatus, setLocalStatus] = useState(\"all\");\r\n\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n refetch();\r\n }\r\n // eslint-disable-next-line\r\n }, [connected, publicKey]);\r\n\r\n if (!connected || !publicKey) {\r\n return (\r\n \r\n \r\n Recurring Orders\r\n \r\n \r\n

Please connect your wallet to view your recurring orders.

\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n
\r\n Your Recurring Orders\r\n All your DCA orders in one place\r\n
\r\n
\r\n \r\n {/* Filter Bar */}\r\n
\r\n
\r\n \r\n \r\n {orderStatus === \"history\" && (\r\n \r\n )}\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n {/* Content */}\r\n
\r\n {error && typeof error === \"string\" && (\r\n error.trim().startsWith(\"{\") && error.trim().endsWith(\"}\")\r\n ?
No orders found or API returned empty result.
\r\n :
{error}
\r\n )}\r\n {loading &&
Loading orders...
}\r\n {!loading && (!data || data.length === 0) && (\r\n
\r\n \r\n
No recurring orders found.
\r\n
\r\n )}\r\n
\r\n {data && data\r\n .filter((order: any) => {\r\n if (orderStatus !== \"history\") return true;\r\n if (localStatus === \"all\") return true;\r\n return order.status.toLowerCase() === localStatus.toLowerCase();\r\n })\r\n .map((order: any) => (\r\n
\r\n \r\n
\r\n ))}\r\n
\r\n
\r\n
\r\n
\r\n );\r\n}\r\n\r\nexport default RecurringOrderWidget; \r\n", "type": "registry:component", "target": "components/ui/murphy/Jupiter-Recurring/RecurringOrderWidget.tsx" } diff --git a/public/r/RecurringSetupForm.json b/public/r/RecurringSetupForm.json index 524723c..c3fddba 100644 --- a/public/r/RecurringSetupForm.json +++ b/public/r/RecurringSetupForm.json @@ -12,7 +12,7 @@ "files": [ { "path": "components/ui/murphy/Jupiter-Recurring/RecurringSetupForm.tsx", - "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { useForm } from \"react-hook-form\"\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\"\nimport { PublicKey } from \"@solana/web3.js\"\nimport { toast } from \"sonner\"\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\"\nimport { Input } from \"@/components/ui/input\"\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectGroup } from \"@/components/ui/select\"\nimport { Button } from \"@/components/ui/button\"\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\"\nimport { Alert, AlertDescription } from \"@/components/ui/alert\"\nimport { ExternalLink, CheckCircle, AlertCircle, Clock, Hash, DollarSign } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\n// Mock TOKENS constant for demo\nconst TOKENS = {\n SOL: new PublicKey(\"So11111111111111111111111111111111111111112\"),\n USDC: new PublicKey(\"EPjFWdd5AufqSSLUs2wyz9G1spG496EEefCcxyBmCEjz\"),\n USDT: new PublicKey(\"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\"),\n}\n\nexport type RecurringSetupFormValues = {\n inputMint: string\n outputMint: string\n inAmount: number | undefined\n numberOfOrders: number\n interval: number // seconds\n minPrice?: number | null\n maxPrice?: number | null\n startAt?: number | null\n}\n\nconst SUPPORTED_TOKENS = [\n { symbol: \"SOL\", mint: TOKENS.SOL.toString() },\n { symbol: \"USDC\", mint: TOKENS.USDC.toString() },\n { symbol: \"USDT\", mint: TOKENS.USDT.toString() },\n]\n\nconst INTERVAL_PRESETS = [\n { label: \"1 Hour\", value: 3600 },\n { label: \"6 Hours\", value: 21600 },\n { label: \"1 Day\", value: 86400 },\n { label: \"1 Week\", value: 604800 },\n]\n\nexport function RecurringSetupForm({\n onOrderCreated,\n className,\n}: {\n onOrderCreated?: (orderId: string) => void\n className?: string\n}) {\n const { publicKey, connected, signTransaction } = useWallet()\n const { connection } = useConnection()\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [success, setSuccess] = useState(null)\n const [error, setError] = useState(null)\n\n const form = useForm({\n defaultValues: {\n inputMint: SUPPORTED_TOKENS[1].mint, // USDC\n outputMint: SUPPORTED_TOKENS[0].mint, // SOL\n inAmount: undefined,\n numberOfOrders: 2,\n interval: 86400, // 1 day\n minPrice: null,\n maxPrice: null,\n startAt: null,\n },\n mode: \"onSubmit\",\n })\n\n // Only render after wallet is connected\n if (!connected || !publicKey) {\n return (\n \n \n Setup Recurring DCA Order\n \n \n \n \n Please connect your wallet to continue.\n \n \n \n )\n }\n\n // Handle submit\n const onSubmit = async (values: RecurringSetupFormValues) => {\n setIsSubmitting(true)\n setError(null)\n setSuccess(null)\n\n try {\n // Validate\n if (!values.inAmount || values.inAmount <= 0) throw new Error(\"Amount must be greater than 0\")\n if (values.inputMint === values.outputMint) throw new Error(\"Input and output tokens must be different\")\n if (!publicKey) throw new Error(\"Wallet not connected\")\n\n // Prepare payload for Jupiter Recurring API\n // Convert amount to raw (assume 6 decimals for USDC/USDT, 9 for SOL)\n const decimals = values.inputMint === TOKENS.SOL.toString() ? 9 : 6\n const inAmountRaw = Math.floor((values.inAmount || 0) * Math.pow(10, decimals))\n\n const payload = {\n user: publicKey.toString(),\n inputMint: values.inputMint,\n outputMint: values.outputMint,\n params: {\n time: {\n inAmount: inAmountRaw,\n numberOfOrders: values.numberOfOrders,\n interval: values.interval,\n minPrice: values.minPrice || null,\n maxPrice: values.maxPrice || null,\n startAt: values.startAt || null,\n },\n },\n }\n\n // Simulate API call for demo\n await new Promise((resolve) => setTimeout(resolve, 2000))\n const mockTxId = \"5j7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9\"\n\n setSuccess(mockTxId)\n toast.success(\"Recurring DCA order created!\", { description: `Tx: ${mockTxId}` })\n if (onOrderCreated) onOrderCreated(mockTxId)\n } catch (e: any) {\n setError(e.message || \"Unknown error\")\n toast.error(\"Failed to create recurring order\", { description: e.message })\n } finally {\n setIsSubmitting(false)\n }\n }\n\n const selectedInputToken = SUPPORTED_TOKENS.find((t) => t.mint === form.watch(\"inputMint\"))\n const selectedOutputToken = SUPPORTED_TOKENS.find((t) => t.mint === form.watch(\"outputMint\"))\n\n return (\n \n \n Setup Recurring DCA Order\n

Automate your dollar-cost averaging strategy with recurring orders

\n
\n \n
\n \n {/* Token Selection */}\n
\n (\n \n From Token\n \n \n \n \n \n )}\n />\n\n (\n \n To Token\n \n \n \n \n \n )}\n />\n
\n\n {/* Order Configuration */}\n
\n

\n \n Order Configuration\n

\n
\n (\n \n Amount per Order\n \n \n \n \n \n )}\n />\n\n (\n \n Number of Orders\n \n \n \n \n \n )}\n />\n
\n
\n\n {/* Timing Configuration */}\n
\n

\n \n Timing\n

\n\n {/* Interval Presets */}\n
\n Interval Presets\n
\n {INTERVAL_PRESETS.map((preset) => (\n form.setValue(\"interval\", preset.value)}\n disabled={isSubmitting}\n >\n {preset.label}\n \n ))}\n
\n
\n\n (\n \n Custom Interval (seconds)\n \n \n \n \n \n )}\n />\n
\n\n {/* Order Summary */}\n
\n

\n \n Order Summary\n

\n
\n
\n Total Amount:\n

\n {((form.watch(\"inAmount\") || 0) * form.watch(\"numberOfOrders\")).toLocaleString()}{\" \"}\n {selectedInputToken?.symbol}\n

\n
\n
\n Frequency:\n

\n Every {Math.floor(form.watch(\"interval\") / 3600)}h{\" \"}\n {Math.floor((form.watch(\"interval\") % 3600) / 60)}m\n

\n
\n
\n Duration:\n

\n ~{Math.floor((form.watch(\"interval\") * form.watch(\"numberOfOrders\")) / 86400)} days\n

\n
\n
\n
\n\n \n\n {success && (\n \n \n \n
\n Order created successfully!\n \n
\n \n {success}\n \n
\n
\n )}\n\n {error && (\n \n \n {error}\n \n )}\n
\n \n
\n
\n )\n}\n\nexport default RecurringSetupForm\n", + "content": "\"use client\"\r\n\r\nimport { useState } from \"react\"\r\nimport { useForm } from \"react-hook-form\"\r\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\"\r\nimport { PublicKey } from \"@solana/web3.js\"\r\nimport { toast } from \"sonner\"\r\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\"\r\nimport { Input } from \"@/components/ui/input\"\r\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectGroup } from \"@/components/ui/select\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\"\r\nimport { Alert, AlertDescription } from \"@/components/ui/alert\"\r\nimport { ExternalLink, CheckCircle, AlertCircle, Clock, Hash, DollarSign } from \"lucide-react\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\n// Mock TOKENS constant for demo\r\nconst TOKENS = {\r\n SOL: new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n USDC: new PublicKey(\"EPjFWdd5AufqSSLUs2wyz9G1spG496EEefCcxyBmCEjz\"),\r\n USDT: new PublicKey(\"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\"),\r\n}\r\n\r\nexport type RecurringSetupFormValues = {\r\n inputMint: string\r\n outputMint: string\r\n inAmount: number | undefined\r\n numberOfOrders: number\r\n interval: number // seconds\r\n minPrice?: number | null\r\n maxPrice?: number | null\r\n startAt?: number | null\r\n}\r\n\r\nconst SUPPORTED_TOKENS = [\r\n { symbol: \"SOL\", mint: TOKENS.SOL.toString() },\r\n { symbol: \"USDC\", mint: TOKENS.USDC.toString() },\r\n { symbol: \"USDT\", mint: TOKENS.USDT.toString() },\r\n]\r\n\r\nconst INTERVAL_PRESETS = [\r\n { label: \"1 Hour\", value: 3600 },\r\n { label: \"6 Hours\", value: 21600 },\r\n { label: \"1 Day\", value: 86400 },\r\n { label: \"1 Week\", value: 604800 },\r\n]\r\n\r\nexport function RecurringSetupForm({\r\n onOrderCreated,\r\n className,\r\n}: {\r\n onOrderCreated?: (orderId: string) => void\r\n className?: string\r\n}) {\r\n const { publicKey, connected, signTransaction } = useWallet()\r\n const { connection } = useConnection()\r\n const [isSubmitting, setIsSubmitting] = useState(false)\r\n const [success, setSuccess] = useState(null)\r\n const [error, setError] = useState(null)\r\n\r\n const form = useForm({\r\n defaultValues: {\r\n inputMint: SUPPORTED_TOKENS[1].mint, // USDC\r\n outputMint: SUPPORTED_TOKENS[0].mint, // SOL\r\n inAmount: undefined,\r\n numberOfOrders: 2,\r\n interval: 86400, // 1 day\r\n minPrice: null,\r\n maxPrice: null,\r\n startAt: null,\r\n },\r\n mode: \"onSubmit\",\r\n })\r\n\r\n // Only render after wallet is connected\r\n if (!connected || !publicKey) {\r\n return (\r\n \r\n \r\n Setup Recurring DCA Order\r\n \r\n \r\n \r\n \r\n Please connect your wallet to continue.\r\n \r\n \r\n \r\n )\r\n }\r\n\r\n // Handle submit\r\n const onSubmit = async (values: RecurringSetupFormValues) => {\r\n setIsSubmitting(true)\r\n setError(null)\r\n setSuccess(null)\r\n\r\n try {\r\n // Validate\r\n if (!values.inAmount || values.inAmount <= 0) throw new Error(\"Amount must be greater than 0\")\r\n if (values.inputMint === values.outputMint) throw new Error(\"Input and output tokens must be different\")\r\n if (!publicKey) throw new Error(\"Wallet not connected\")\r\n\r\n // Prepare payload for Jupiter Recurring API\r\n // Convert amount to raw (assume 6 decimals for USDC/USDT, 9 for SOL)\r\n const decimals = values.inputMint === TOKENS.SOL.toString() ? 9 : 6\r\n const inAmountRaw = Math.floor((values.inAmount || 0) * Math.pow(10, decimals))\r\n\r\n const payload = {\r\n user: publicKey.toString(),\r\n inputMint: values.inputMint,\r\n outputMint: values.outputMint,\r\n params: {\r\n time: {\r\n inAmount: inAmountRaw,\r\n numberOfOrders: values.numberOfOrders,\r\n interval: values.interval,\r\n minPrice: values.minPrice || null,\r\n maxPrice: values.maxPrice || null,\r\n startAt: values.startAt || null,\r\n },\r\n },\r\n }\r\n\r\n // Simulate API call for demo\r\n await new Promise((resolve) => setTimeout(resolve, 2000))\r\n const mockTxId = \"5j7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9\"\r\n\r\n setSuccess(mockTxId)\r\n toast.success(\"Recurring DCA order created!\", { description: `Tx: ${mockTxId}` })\r\n if (onOrderCreated) onOrderCreated(mockTxId)\r\n } catch (e: any) {\r\n setError(e.message || \"Unknown error\")\r\n toast.error(\"Failed to create recurring order\", { description: e.message })\r\n } finally {\r\n setIsSubmitting(false)\r\n }\r\n }\r\n\r\n const selectedInputToken = SUPPORTED_TOKENS.find((t) => t.mint === form.watch(\"inputMint\"))\r\n const selectedOutputToken = SUPPORTED_TOKENS.find((t) => t.mint === form.watch(\"outputMint\"))\r\n\r\n return (\r\n \r\n \r\n Setup Recurring DCA Order\r\n

Automate your dollar-cost averaging strategy with recurring orders

\r\n
\r\n \r\n
\r\n \r\n {/* Token Selection */}\r\n
\r\n (\r\n \r\n From Token\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n To Token\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n\r\n {/* Order Configuration */}\r\n
\r\n

\r\n \r\n Order Configuration\r\n

\r\n
\r\n (\r\n \r\n Amount per Order\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Number of Orders\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n
\r\n\r\n {/* Timing Configuration */}\r\n
\r\n

\r\n \r\n Timing\r\n

\r\n\r\n {/* Interval Presets */}\r\n
\r\n Interval Presets\r\n
\r\n {INTERVAL_PRESETS.map((preset) => (\r\n form.setValue(\"interval\", preset.value)}\r\n disabled={isSubmitting}\r\n >\r\n {preset.label}\r\n \r\n ))}\r\n
\r\n
\r\n\r\n (\r\n \r\n Custom Interval (seconds)\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n\r\n {/* Order Summary */}\r\n
\r\n

\r\n \r\n Order Summary\r\n

\r\n
\r\n
\r\n Total Amount:\r\n

\r\n {((form.watch(\"inAmount\") || 0) * form.watch(\"numberOfOrders\")).toLocaleString()}{\" \"}\r\n {selectedInputToken?.symbol}\r\n

\r\n
\r\n
\r\n Frequency:\r\n

\r\n Every {Math.floor(form.watch(\"interval\") / 3600)}h{\" \"}\r\n {Math.floor((form.watch(\"interval\") % 3600) / 60)}m\r\n

\r\n
\r\n
\r\n Duration:\r\n

\r\n ~{Math.floor((form.watch(\"interval\") * form.watch(\"numberOfOrders\")) / 86400)} days\r\n

\r\n
\r\n
\r\n
\r\n\r\n \r\n\r\n {success && (\r\n \r\n \r\n \r\n
\r\n Order created successfully!\r\n \r\n
\r\n \r\n {success}\r\n \r\n
\r\n
\r\n )}\r\n\r\n {error && (\r\n \r\n \r\n {error}\r\n \r\n )}\r\n
\r\n \r\n
\r\n
\r\n )\r\n}\r\n\r\nexport default RecurringSetupForm\r\n", "type": "registry:component", "target": "components/ui/murphy/Jupiter-Recurring/RecurringSetupForm.tsx" } diff --git a/public/r/avatar.json b/public/r/avatar.json index 3d4fefd..cf30a0d 100644 --- a/public/r/avatar.json +++ b/public/r/avatar.json @@ -10,13 +10,13 @@ "files": [ { "path": "components/ui/murphy/avatar.tsx", - "content": "import React from \"react\";\n\nimport { PublicKey } from \"@solana/web3.js\";\nimport { minidenticon } from \"minidenticons\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype AvatarProps = {\n address: PublicKey;\n size?: number;\n className?: string;\n alt?: string;\n};\n\nconst Avatar = ({ address, size = 48, className, alt }: AvatarProps) => {\n const pubkeyStr = typeof address ==\"string\" ? address: address.toBase58();\n\n const identicon = React.useMemo(() => {\n if (!pubkeyStr) return \"\";\n return (\n \"data:image/svg+xml;utf8,\" +\n encodeURIComponent(minidenticon(pubkeyStr, 90, 50))\n );\n }, [pubkeyStr]);\n\n return (\n \n \n
\n );\n};\n\nexport { Avatar };", + "content": "import React from \"react\";\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { minidenticon } from \"minidenticons\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\ntype AvatarProps = {\r\n address: PublicKey;\r\n size?: number;\r\n className?: string;\r\n alt?: string;\r\n};\r\n\r\nconst Avatar = ({ address, size = 48, className, alt }: AvatarProps) => {\r\n const pubkeyStr = typeof address ==\"string\" ? address: address.toBase58();\r\n\r\n const identicon = React.useMemo(() => {\r\n if (!pubkeyStr) return \"\";\r\n return (\r\n \"data:image/svg+xml;utf8,\" +\r\n encodeURIComponent(minidenticon(pubkeyStr, 90, 50))\r\n );\r\n }, [pubkeyStr]);\r\n\r\n return (\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport { Avatar };", "type": "registry:component", "target": "components/ui/murphy/avatar.tsx" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" } diff --git a/public/r/buildCurveAndCreateConfig-form.json b/public/r/buildCurveAndCreateConfig-form.json index 4574acb..3b359b4 100644 --- a/public/r/buildCurveAndCreateConfig-form.json +++ b/public/r/buildCurveAndCreateConfig-form.json @@ -23,19 +23,19 @@ "files": [ { "path": "components/ui/murphy/buildCurveAndCreateConfig-form.tsx", - "content": "'use client';\n\nimport { useState, useEffect, useContext } from 'react';\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle, Settings } from \"lucide-react\";\nimport { PublicKey, Transaction, Keypair, SystemProgram, TransactionInstruction } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\nimport { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk';\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { Slider } from \"@/components/ui/slider\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\ninterface BuildCurveResult {\n config: string;\n signature: string;\n}\n\ntype FormValues = {\n totalTokenSupply: number;\n percentageSupplyOnMigration: number;\n migrationQuoteThreshold: number;\n migrationOption: number;\n tokenBaseDecimal: number;\n tokenQuoteDecimal: number;\n amountPerPeriod: string;\n cliffDuration: string;\n frequency: string;\n numberOfPeriod: string;\n cliffUnlockAmount: string;\n feeClaimer: string;\n leftoverReceiver: string;\n quoteMint: string;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate token supply\n if (!data.totalTokenSupply) {\n errors.totalTokenSupply = {\n type: \"required\",\n message: \"Total token supply is required\",\n };\n } else if (data.totalTokenSupply <= 0) {\n errors.totalTokenSupply = {\n type: \"min\",\n message: \"Supply must be greater than 0\",\n };\n }\n\n // Validate percentageSupplyOnMigration\n if (data.percentageSupplyOnMigration === undefined || data.percentageSupplyOnMigration === null) {\n errors.percentageSupplyOnMigration = {\n type: \"required\",\n message: \"Percentage supply on migration is required\",\n };\n } else if (data.percentageSupplyOnMigration < 0 || data.percentageSupplyOnMigration > 100) {\n errors.percentageSupplyOnMigration = {\n type: \"range\",\n message: \"Percentage must be between 0 and 100\",\n };\n }\n\n // Validate migrationQuoteThreshold\n if (!data.migrationQuoteThreshold) {\n errors.migrationQuoteThreshold = {\n type: \"required\",\n message: \"Migration quote threshold is required\",\n };\n }\n\n // Validate decimals\n if (data.tokenBaseDecimal === undefined || data.tokenBaseDecimal === null) {\n errors.tokenBaseDecimal = {\n type: \"required\",\n message: \"Base token decimal is required\",\n };\n } else if (data.tokenBaseDecimal < 0 || data.tokenBaseDecimal > 18) {\n errors.tokenBaseDecimal = {\n type: \"range\",\n message: \"Decimal must be between 0 and 18\",\n };\n }\n\n if (data.tokenQuoteDecimal === undefined || data.tokenQuoteDecimal === null) {\n errors.tokenQuoteDecimal = {\n type: \"required\",\n message: \"Quote token decimal is required\",\n };\n } else if (data.tokenQuoteDecimal < 0 || data.tokenQuoteDecimal > 18) {\n errors.tokenQuoteDecimal = {\n type: \"range\",\n message: \"Decimal must be between 0 and 18\",\n };\n }\n\n // Validate address fields\n if (!data.feeClaimer) {\n errors.feeClaimer = {\n type: \"required\",\n message: \"Fee claimer address is required\",\n };\n } else {\n try {\n new PublicKey(data.feeClaimer);\n } catch (e) {\n errors.feeClaimer = {\n type: \"invalid\",\n message: \"Invalid Solana address\",\n };\n }\n }\n\n if (!data.leftoverReceiver) {\n errors.leftoverReceiver = {\n type: \"required\",\n message: \"Leftover receiver address is required\",\n };\n } else {\n try {\n new PublicKey(data.leftoverReceiver);\n } catch (e) {\n errors.leftoverReceiver = {\n type: \"invalid\",\n message: \"Invalid Solana address\",\n };\n }\n }\n\n if (!data.quoteMint) {\n errors.quoteMint = {\n type: \"required\",\n message: \"Quote mint address is required\",\n };\n } else {\n try {\n new PublicKey(data.quoteMint);\n } catch (e) {\n errors.quoteMint = {\n type: \"invalid\",\n message: \"Invalid Solana address\",\n };\n }\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport default function BuildCurveAndCreateConfigForm({ onConfigCreated }: { onConfigCreated?: (configAddress: string) => void }) {\n const { connection } = useConnection();\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\n \n const [isSubmitting, setIsSubmitting] = useState(false);\n const [result, setResult] = useState(null);\n const [currentStage, setCurrentStage] = useState<'input' | 'confirming' | 'success' | 'error'>('input');\n const [error, setError] = useState('');\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState('devnet');\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n totalTokenSupply: 1000000000,\n percentageSupplyOnMigration: 10,\n migrationQuoteThreshold: 100,\n migrationOption: 0,\n tokenBaseDecimal: 9,\n tokenQuoteDecimal: 9,\n amountPerPeriod: \"0\",\n cliffDuration: \"0\",\n frequency: \"0\",\n numberOfPeriod: \"0\",\n cliffUnlockAmount: \"0\",\n feeClaimer: \"\",\n leftoverReceiver: \"\",\n quoteMint: \"So11111111111111111111111111111111111111112\",\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Only render after the component is mounted on the client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n // Auto-fill wallet address fields when wallet connects\n useEffect(() => {\n if (connected && publicKey) {\n form.setValue(\"feeClaimer\", publicKey.toString());\n form.setValue(\"leftoverReceiver\", publicKey.toString());\n }\n }, [connected, publicKey, form]);\n\n const onSubmit = async (values: FormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error('Please connect your wallet');\n return;\n }\n\n try {\n setIsSubmitting(true);\n setCurrentStage('confirming');\n setError('');\n\n toast.loading(\"Creating configuration...\", {\n id: \"build-curve\"\n });\n \n try {\n // Initialize DBC client\n const client = new DynamicBondingCurveClient(connection);\n \n // Create a simple demo transaction\n const transaction = new Transaction();\n \n // Get the latest blockhash\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.lastValidBlockHeight = lastValidBlockHeight;\n transaction.feePayer = publicKey;\n \n // Add a simple instruction - a memo recording the creation time\n transaction.add(\n new TransactionInstruction({\n keys: [\n {\n pubkey: publicKey,\n isSigner: true,\n isWritable: true,\n }\n ],\n programId: new PublicKey(\"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"),\n data: Buffer.from(`Create Curve Config: ${new Date().toISOString()}`, \"utf-8\")\n })\n );\n \n // Send transaction to the network\n const signature = await wallet.adapter.sendTransaction(transaction, connection);\n \n // Wait for confirmation with new syntax\n await connection.confirmTransaction({\n blockhash,\n lastValidBlockHeight,\n signature\n });\n \n // Save result\n const configAddress = publicKey.toString(); // Use wallet address as config address (demo)\n setResult({\n config: configAddress,\n signature: signature\n });\n \n // Call callback if provided\n if (onConfigCreated) {\n onConfigCreated(configAddress);\n }\n \n setCurrentStage('success');\n \n toast.success(\"Configuration created successfully!\", {\n id: \"build-curve\",\n description: `Config: ${configAddress.slice(0, 8)}...${configAddress.slice(-4)}`\n });\n } catch (transactionError: any) {\n console.error(\"Transaction error:\", transactionError);\n throw transactionError;\n }\n \n } catch (err: any) {\n console.error(\"Error creating configuration:\", err);\n \n setCurrentStage('error');\n setError(err.message || 'An unknown error occurred');\n \n // Check if user canceled/rejected the transaction\n if (err.message && (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))) {\n toast.error(\"Transaction was canceled\", {\n id: \"build-curve\",\n description: \"You canceled the transaction\"\n });\n } else {\n toast.error(\"Unable to create configuration\", {\n id: \"build-curve\",\n description: err.message\n });\n \n // If transaction failed due to connection error, try switching to another RPC endpoint\n if (err.message?.includes('failed to fetch') || \n err.message?.includes('timeout') || \n err.message?.includes('429') ||\n err.message?.includes('503')) {\n switchToNextEndpoint();\n }\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const viewConfig = () => {\n if (result?.config) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\n window.open(`${baseUrl}${result.config}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setCurrentStage('input');\n setError('');\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

Configuration Created!

\n \n
\n
Configuration Address:
\n
\n {result?.config}\n
\n
\n \n
\n
Transaction Signature:
\n
\n {result?.signature}\n
\n
\n \n
\n \n \n \n
\n \n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Configuration Creation Failed

\n

{error || 'An error occurred during configuration creation.'}

\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Confirming

\n

Please wait while your transaction is being processed...

\n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n
\n

Token Configuration

\n
\n (\n \n Total Token Supply\n \n \n \n \n \n )}\n />\n \n (\n \n Percentage Supply on Migration\n \n \n \n \n \n )}\n />\n \n (\n \n Migration Quote Threshold\n \n \n \n \n \n )}\n />\n \n (\n \n Migration Option\n \n \n \n \n \n )}\n />\n \n (\n \n Base Token Decimal\n \n \n \n \n \n )}\n />\n \n (\n \n Quote Token Decimal\n \n \n \n \n \n )}\n />\n
\n
\n \n
\n

Vesting Parameters

\n
\n (\n \n Amount Per Period\n \n \n \n \n \n )}\n />\n \n (\n \n Cliff Duration from Migration\n \n \n \n \n \n )}\n />\n \n (\n \n Frequency\n \n \n \n \n \n )}\n />\n \n (\n \n Number of Periods\n \n \n \n \n \n )}\n />\n \n (\n \n Cliff Unlock Amount\n \n \n \n \n \n )}\n />\n
\n
\n \n
\n

Addresses

\n
\n (\n \n Fee Claimer Address\n \n \n \n \n \n )}\n />\n \n (\n \n Leftover Receiver Address\n \n \n \n \n \n )}\n />\n \n (\n \n Quote Mint Address\n \n \n \n \n \n )}\n />\n
\n
\n \n
\n
\n
\n Network\n \n {network}\n \n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Creating...\n \n ) : \"Create Configuration\"}\n \n )}\n
\n
\n
\n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'confirming':\n return renderConfirming();\n default:\n return renderForm();\n }\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n Create Curve Configuration\n Build a constant product configuration with custom parameters\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n Create Curve Configuration\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Build a constant product configuration with custom parameters\n \n \n {renderStageContent()}\n \n \n );\n}\n", + "content": "'use client';\r\n\r\nimport { useState, useEffect, useContext } from 'react';\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle, Settings } from \"lucide-react\";\r\nimport { PublicKey, Transaction, Keypair, SystemProgram, TransactionInstruction } from \"@solana/web3.js\";\r\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\r\nimport { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk';\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/ui/popover\";\r\nimport { Slider } from \"@/components/ui/slider\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\ninterface BuildCurveResult {\r\n config: string;\r\n signature: string;\r\n}\r\n\r\ntype FormValues = {\r\n totalTokenSupply: number;\r\n percentageSupplyOnMigration: number;\r\n migrationQuoteThreshold: number;\r\n migrationOption: number;\r\n tokenBaseDecimal: number;\r\n tokenQuoteDecimal: number;\r\n amountPerPeriod: string;\r\n cliffDuration: string;\r\n frequency: string;\r\n numberOfPeriod: string;\r\n cliffUnlockAmount: string;\r\n feeClaimer: string;\r\n leftoverReceiver: string;\r\n quoteMint: string;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate token supply\r\n if (!data.totalTokenSupply) {\r\n errors.totalTokenSupply = {\r\n type: \"required\",\r\n message: \"Total token supply is required\",\r\n };\r\n } else if (data.totalTokenSupply <= 0) {\r\n errors.totalTokenSupply = {\r\n type: \"min\",\r\n message: \"Supply must be greater than 0\",\r\n };\r\n }\r\n\r\n // Validate percentageSupplyOnMigration\r\n if (data.percentageSupplyOnMigration === undefined || data.percentageSupplyOnMigration === null) {\r\n errors.percentageSupplyOnMigration = {\r\n type: \"required\",\r\n message: \"Percentage supply on migration is required\",\r\n };\r\n } else if (data.percentageSupplyOnMigration < 0 || data.percentageSupplyOnMigration > 100) {\r\n errors.percentageSupplyOnMigration = {\r\n type: \"range\",\r\n message: \"Percentage must be between 0 and 100\",\r\n };\r\n }\r\n\r\n // Validate migrationQuoteThreshold\r\n if (!data.migrationQuoteThreshold) {\r\n errors.migrationQuoteThreshold = {\r\n type: \"required\",\r\n message: \"Migration quote threshold is required\",\r\n };\r\n }\r\n\r\n // Validate decimals\r\n if (data.tokenBaseDecimal === undefined || data.tokenBaseDecimal === null) {\r\n errors.tokenBaseDecimal = {\r\n type: \"required\",\r\n message: \"Base token decimal is required\",\r\n };\r\n } else if (data.tokenBaseDecimal < 0 || data.tokenBaseDecimal > 18) {\r\n errors.tokenBaseDecimal = {\r\n type: \"range\",\r\n message: \"Decimal must be between 0 and 18\",\r\n };\r\n }\r\n\r\n if (data.tokenQuoteDecimal === undefined || data.tokenQuoteDecimal === null) {\r\n errors.tokenQuoteDecimal = {\r\n type: \"required\",\r\n message: \"Quote token decimal is required\",\r\n };\r\n } else if (data.tokenQuoteDecimal < 0 || data.tokenQuoteDecimal > 18) {\r\n errors.tokenQuoteDecimal = {\r\n type: \"range\",\r\n message: \"Decimal must be between 0 and 18\",\r\n };\r\n }\r\n\r\n // Validate address fields\r\n if (!data.feeClaimer) {\r\n errors.feeClaimer = {\r\n type: \"required\",\r\n message: \"Fee claimer address is required\",\r\n };\r\n } else {\r\n try {\r\n new PublicKey(data.feeClaimer);\r\n } catch (e) {\r\n errors.feeClaimer = {\r\n type: \"invalid\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n }\r\n\r\n if (!data.leftoverReceiver) {\r\n errors.leftoverReceiver = {\r\n type: \"required\",\r\n message: \"Leftover receiver address is required\",\r\n };\r\n } else {\r\n try {\r\n new PublicKey(data.leftoverReceiver);\r\n } catch (e) {\r\n errors.leftoverReceiver = {\r\n type: \"invalid\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n }\r\n\r\n if (!data.quoteMint) {\r\n errors.quoteMint = {\r\n type: \"required\",\r\n message: \"Quote mint address is required\",\r\n };\r\n } else {\r\n try {\r\n new PublicKey(data.quoteMint);\r\n } catch (e) {\r\n errors.quoteMint = {\r\n type: \"invalid\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport default function BuildCurveAndCreateConfigForm({ onConfigCreated }: { onConfigCreated?: (configAddress: string) => void }) {\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\r\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\r\n \r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [result, setResult] = useState(null);\r\n const [currentStage, setCurrentStage] = useState<'input' | 'confirming' | 'success' | 'error'>('input');\r\n const [error, setError] = useState('');\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState('devnet');\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n totalTokenSupply: 1000000000,\r\n percentageSupplyOnMigration: 10,\r\n migrationQuoteThreshold: 100,\r\n migrationOption: 0,\r\n tokenBaseDecimal: 9,\r\n tokenQuoteDecimal: 9,\r\n amountPerPeriod: \"0\",\r\n cliffDuration: \"0\",\r\n frequency: \"0\",\r\n numberOfPeriod: \"0\",\r\n cliffUnlockAmount: \"0\",\r\n feeClaimer: \"\",\r\n leftoverReceiver: \"\",\r\n quoteMint: \"So11111111111111111111111111111111111111112\",\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Only render after the component is mounted on the client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n // Auto-fill wallet address fields when wallet connects\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n form.setValue(\"feeClaimer\", publicKey.toString());\r\n form.setValue(\"leftoverReceiver\", publicKey.toString());\r\n }\r\n }, [connected, publicKey, form]);\r\n\r\n const onSubmit = async (values: FormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error('Please connect your wallet');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setCurrentStage('confirming');\r\n setError('');\r\n\r\n toast.loading(\"Creating configuration...\", {\r\n id: \"build-curve\"\r\n });\r\n \r\n try {\r\n // Initialize DBC client\r\n const client = new DynamicBondingCurveClient(connection);\r\n \r\n // Create a simple demo transaction\r\n const transaction = new Transaction();\r\n \r\n // Get the latest blockhash\r\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\r\n transaction.recentBlockhash = blockhash;\r\n transaction.lastValidBlockHeight = lastValidBlockHeight;\r\n transaction.feePayer = publicKey;\r\n \r\n // Add a simple instruction - a memo recording the creation time\r\n transaction.add(\r\n new TransactionInstruction({\r\n keys: [\r\n {\r\n pubkey: publicKey,\r\n isSigner: true,\r\n isWritable: true,\r\n }\r\n ],\r\n programId: new PublicKey(\"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\"),\r\n data: Buffer.from(`Create Curve Config: ${new Date().toISOString()}`, \"utf-8\")\r\n })\r\n );\r\n \r\n // Send transaction to the network\r\n const signature = await wallet.adapter.sendTransaction(transaction, connection);\r\n \r\n // Wait for confirmation with new syntax\r\n await connection.confirmTransaction({\r\n blockhash,\r\n lastValidBlockHeight,\r\n signature\r\n });\r\n \r\n // Save result\r\n const configAddress = publicKey.toString(); // Use wallet address as config address (demo)\r\n setResult({\r\n config: configAddress,\r\n signature: signature\r\n });\r\n \r\n // Call callback if provided\r\n if (onConfigCreated) {\r\n onConfigCreated(configAddress);\r\n }\r\n \r\n setCurrentStage('success');\r\n \r\n toast.success(\"Configuration created successfully!\", {\r\n id: \"build-curve\",\r\n description: `Config: ${configAddress.slice(0, 8)}...${configAddress.slice(-4)}`\r\n });\r\n } catch (transactionError: any) {\r\n console.error(\"Transaction error:\", transactionError);\r\n throw transactionError;\r\n }\r\n \r\n } catch (err: any) {\r\n console.error(\"Error creating configuration:\", err);\r\n \r\n setCurrentStage('error');\r\n setError(err.message || 'An unknown error occurred');\r\n \r\n // Check if user canceled/rejected the transaction\r\n if (err.message && (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))) {\r\n toast.error(\"Transaction was canceled\", {\r\n id: \"build-curve\",\r\n description: \"You canceled the transaction\"\r\n });\r\n } else {\r\n toast.error(\"Unable to create configuration\", {\r\n id: \"build-curve\",\r\n description: err.message\r\n });\r\n \r\n // If transaction failed due to connection error, try switching to another RPC endpoint\r\n if (err.message?.includes('failed to fetch') || \r\n err.message?.includes('timeout') || \r\n err.message?.includes('429') ||\r\n err.message?.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\r\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const viewConfig = () => {\r\n if (result?.config) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\r\n window.open(`${baseUrl}${result.config}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setCurrentStage('input');\r\n setError('');\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

Configuration Created!

\r\n \r\n
\r\n
Configuration Address:
\r\n
\r\n {result?.config}\r\n
\r\n
\r\n \r\n
\r\n
Transaction Signature:
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Configuration Creation Failed

\r\n

{error || 'An error occurred during configuration creation.'}

\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Confirming

\r\n

Please wait while your transaction is being processed...

\r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n
\r\n

Token Configuration

\r\n
\r\n (\r\n \r\n Total Token Supply\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Percentage Supply on Migration\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Migration Quote Threshold\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Migration Option\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Base Token Decimal\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Quote Token Decimal\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n
\r\n \r\n
\r\n

Vesting Parameters

\r\n
\r\n (\r\n \r\n Amount Per Period\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Cliff Duration from Migration\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Frequency\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Number of Periods\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Cliff Unlock Amount\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n
\r\n \r\n
\r\n

Addresses

\r\n
\r\n (\r\n \r\n Fee Claimer Address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Leftover Receiver Address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n \r\n (\r\n \r\n Quote Mint Address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating...\r\n \r\n ) : \"Create Configuration\"}\r\n \r\n )}\r\n
\r\n
\r\n
\r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'confirming':\r\n return renderConfirming();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create Curve Configuration\r\n Build a constant product configuration with custom parameters\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Create Curve Configuration\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Build a constant product configuration with custom parameters\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/buildCurveAndCreateConfig-form.tsx" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" } diff --git a/public/r/buildCurveAndCreateConfigByMarketCap-form.json b/public/r/buildCurveAndCreateConfigByMarketCap-form.json index 27845c4..2176e00 100644 --- a/public/r/buildCurveAndCreateConfigByMarketCap-form.json +++ b/public/r/buildCurveAndCreateConfigByMarketCap-form.json @@ -23,19 +23,19 @@ "files": [ { "path": "components/ui/murphy/buildCurveAndCreateConfigByMarketCap-form.tsx", - "content": "\"use client\";\n\nimport { useState, useEffect, useContext } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle, Settings } from \"lucide-react\";\nimport { PublicKey, Keypair } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from \"@solana/wallet-adapter-react\";\nimport { DynamicBondingCurveClient } from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport BN from \"bn.js\";\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\nenum FeeSchedulerMode {\n Linear = 0,\n}\n\ninterface BuildCurveResult {\n config: string;\n signature: string;\n}\n\ntype FormValues = {\n // Các tham số của buildCurveByMarketCapParam\n totalTokenSupply: number;\n initialMarketCap: number;\n migrationMarketCap: number;\n migrationOption: number;\n tokenBaseDecimal: number;\n tokenQuoteDecimal: number;\n\n // Tham số của feeSchedulerParam\n numberOfPeriod: number;\n reductionFactor: number;\n periodFrequency: number;\n feeSchedulerMode: number;\n\n // Các thông số khác\n baseFeeBps: number;\n dynamicFeeEnabled: boolean;\n activationType: number;\n collectFeeMode: number;\n migrationFeeOption: number;\n tokenType: number;\n\n // Phân phối LP\n partnerLpPercentage: number;\n creatorLpPercentage: number;\n partnerLockedLpPercentage: number;\n creatorLockedLpPercentage: number;\n\n // Địa chỉ\n feeClaimer: string;\n leftoverReceiver: string;\n quoteMint: string;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate totalTokenSupply\n if (!data.totalTokenSupply) {\n errors.totalTokenSupply = {\n type: \"required\",\n message: \"Total token supply is required\",\n };\n } else if (data.totalTokenSupply <= 0) {\n errors.totalTokenSupply = {\n type: \"min\",\n message: \"Total token supply must be greater than 0\",\n };\n }\n\n // Validate initialMarketCap\n if (!data.initialMarketCap) {\n errors.initialMarketCap = {\n type: \"required\",\n message: \"Initial market cap is required\",\n };\n } else if (data.initialMarketCap <= 0) {\n errors.initialMarketCap = {\n type: \"min\",\n message: \"Initial market cap must be greater than 0\",\n };\n }\n\n // Validate migrationMarketCap\n if (!data.migrationMarketCap) {\n errors.migrationMarketCap = {\n type: \"required\",\n message: \"Migration market cap is required\",\n };\n } else if (data.migrationMarketCap <= 0) {\n errors.migrationMarketCap = {\n type: \"min\",\n message: \"Migration market cap must be greater than 0\",\n };\n }\n\n // Validate tokenBaseDecimal\n if (data.tokenBaseDecimal === undefined || data.tokenBaseDecimal === null) {\n errors.tokenBaseDecimal = {\n type: \"required\",\n message: \"Token base decimal is required\",\n };\n } else if (data.tokenBaseDecimal < 0 || data.tokenBaseDecimal > 18) {\n errors.tokenBaseDecimal = {\n type: \"range\",\n message: \"Token base decimal must be between 0 and 18\",\n };\n }\n\n // Validate tokenQuoteDecimal\n if (data.tokenQuoteDecimal === undefined || data.tokenQuoteDecimal === null) {\n errors.tokenQuoteDecimal = {\n type: \"required\",\n message: \"Token quote decimal is required\",\n };\n } else if (data.tokenQuoteDecimal < 0 || data.tokenQuoteDecimal > 18) {\n errors.tokenQuoteDecimal = {\n type: \"range\",\n message: \"Token quote decimal must be between 0 and 18\",\n };\n }\n\n // Validate address fields\n const validateAddress = (field: string, name: string) => {\n if (!data[field]) {\n errors[field] = {\n type: \"required\",\n message: `${name} is required`,\n };\n } else {\n try {\n new PublicKey(data[field]);\n } catch (e) {\n errors[field] = {\n type: \"invalid\",\n message: \"Invalid Solana address\",\n };\n }\n }\n };\n\n validateAddress(\"feeClaimer\", \"Fee claimer address\");\n validateAddress(\"leftoverReceiver\", \"Leftover receiver address\");\n validateAddress(\"quoteMint\", \"Quote mint address\");\n\n // Validate LP percentages\n const validatePercentage = (field: string, name: string) => {\n if (\n data[field] === undefined ||\n data[field] === null ||\n data[field] === \"\"\n ) {\n errors[field] = {\n type: \"required\",\n message: `${name} is required`,\n };\n } else if (Number(data[field]) < 0 || Number(data[field]) > 100) {\n errors[field] = {\n type: \"range\",\n message: `${name} must be between 0 and 100%`,\n };\n }\n };\n\n validatePercentage(\"partnerLpPercentage\", \"Partner LP percentage\");\n validatePercentage(\"creatorLpPercentage\", \"Creator LP percentage\");\n validatePercentage(\n \"partnerLockedLpPercentage\",\n \"Partner locked LP percentage\"\n );\n validatePercentage(\n \"creatorLockedLpPercentage\",\n \"Creator locked LP percentage\"\n );\n\n // Validate that percentages sum to 100\n const totalPercentage =\n Number(data.partnerLpPercentage || 0) +\n Number(data.creatorLpPercentage || 0) +\n Number(data.partnerLockedLpPercentage || 0) +\n Number(data.creatorLockedLpPercentage || 0);\n\n if (totalPercentage !== 100) {\n errors.partnerLpPercentage = {\n type: \"validate\",\n message: \"Total LP percentage must be 100%\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport default function BuildCurveAndCreateConfigByMarketCapForm({\n onConfigCreated,\n}: {\n onConfigCreated?: (configAddress: string) => void;\n}) {\n const { connection } = useConnection();\n const { publicKey, connected, wallet } = useWallet();\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\n\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [result, setResult] = useState(null);\n const [currentStage, setCurrentStage] = useState<\n \"input\" | \"confirming\" | \"success\" | \"error\"\n >(\"input\");\n const [error, setError] = useState(\"\");\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState(\"devnet\");\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n totalTokenSupply: 1000000000,\n initialMarketCap: 98,\n migrationMarketCap: 3200,\n migrationOption: 0,\n tokenBaseDecimal: 9,\n tokenQuoteDecimal: 9,\n\n numberOfPeriod: 0,\n reductionFactor: 0,\n periodFrequency: 0,\n feeSchedulerMode: FeeSchedulerMode.Linear,\n\n baseFeeBps: 2500000,\n dynamicFeeEnabled: false,\n activationType: 0,\n collectFeeMode: 0,\n migrationFeeOption: 0,\n tokenType: 0,\n\n partnerLpPercentage: 25,\n creatorLpPercentage: 25,\n partnerLockedLpPercentage: 25,\n creatorLockedLpPercentage: 25,\n\n feeClaimer: \"\",\n leftoverReceiver: \"\",\n quoteMint: \"So11111111111111111111111111111111111111112\", // SOL by default\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Chỉ render sau khi component được mount trên client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Cập nhật trạng thái network khi endpoint thay đổi\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes(\"devnet\") ? \"devnet\" : \"mainnet\");\n }\n }, [endpoint]);\n\n // Tự động điền địa chỉ ví khi ví kết nối\n useEffect(() => {\n if (connected && publicKey) {\n form.setValue(\"feeClaimer\", publicKey.toString());\n form.setValue(\"leftoverReceiver\", publicKey.toString());\n }\n }, [connected, publicKey, form]);\n\n // Xử lý khi form được gửi đi\n const onSubmit = async (values: FormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error(\"Please connect your wallet\");\n return;\n }\n\n try {\n setIsSubmitting(true);\n setCurrentStage(\"confirming\");\n setError(\"\");\n\n toast.loading(\"Creating configuration...\", {\n id: \"build-curve-market-cap\",\n });\n\n try {\n // Khởi tạo DBC client\n const client = new DynamicBondingCurveClient(connection);\n\n // Tạo keypair mới cho config\n const configKeypair = Keypair.generate();\n\n // Tạo các tham số cho hàm buildCurveAndCreateConfigByMarketCap\n const params = {\n buildCurveByMarketCapParam: {\n totalTokenSupply: values.totalTokenSupply,\n initialMarketCap: values.initialMarketCap,\n migrationMarketCap: values.migrationMarketCap,\n migrationOption: values.migrationOption,\n tokenBaseDecimal: values.tokenBaseDecimal,\n tokenQuoteDecimal: values.tokenQuoteDecimal,\n feeSchedulerParam: {\n numberOfPeriod: values.numberOfPeriod,\n reductionFactor: values.reductionFactor,\n periodFrequency: values.periodFrequency,\n feeSchedulerMode: values.feeSchedulerMode,\n },\n baseFeeBps: values.baseFeeBps,\n dynamicFeeEnabled: values.dynamicFeeEnabled,\n activationType: values.activationType,\n collectFeeMode: values.collectFeeMode,\n migrationFeeOption: values.migrationFeeOption,\n tokenType: values.tokenType,\n lockedVesting: {\n amountPerPeriod: new BN(\"0\"),\n cliffDurationFromMigrationTime: new BN(\"0\"),\n frequency: new BN(\"0\"),\n numberOfPeriod: new BN(\"0\"),\n cliffUnlockAmount: new BN(\"0\"),\n },\n partnerLpPercentage: values.partnerLpPercentage,\n creatorLpPercentage: values.creatorLpPercentage,\n partnerLockedLpPercentage: values.partnerLockedLpPercentage,\n creatorLockedLpPercentage: values.creatorLockedLpPercentage,\n },\n feeClaimer: new PublicKey(values.feeClaimer),\n leftoverReceiver: new PublicKey(values.leftoverReceiver),\n payer: publicKey,\n quoteMint: new PublicKey(values.quoteMint),\n config: configKeypair.publicKey,\n };\n\n // Tạo transaction\n const transaction =\n await client.partners.buildCurveAndCreateConfigByMarketCap(params);\n\n // Lấy blockhash gần nhất\n const { blockhash, lastValidBlockHeight } =\n await connection.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.lastValidBlockHeight = lastValidBlockHeight;\n\n // Đặt feePayer cho transaction\n transaction.feePayer = publicKey;\n\n // Ký giao dịch với configKeypair\n transaction.partialSign(configKeypair);\n\n // Gửi và ký giao dịch\n const signature = await wallet.adapter.sendTransaction(\n transaction,\n connection\n );\n\n // Đợi xác nhận\n await connection.confirmTransaction({\n blockhash,\n lastValidBlockHeight,\n signature,\n });\n\n // Lưu kết quả\n const configAddress = configKeypair.publicKey.toString();\n setResult({\n config: configAddress,\n signature: signature,\n });\n\n // Gọi callback nếu được cung cấp\n if (onConfigCreated) {\n onConfigCreated(configAddress);\n }\n\n setCurrentStage(\"success\");\n\n toast.success(\"Configuration created successfully!\", {\n id: \"build-curve-market-cap\",\n description: `Config: ${configAddress.slice(\n 0,\n 8\n )}...${configAddress.slice(-8)}`,\n });\n } catch (transactionError: any) {\n console.error(\"Transaction error: \", transactionError);\n throw transactionError;\n }\n } catch (err: any) {\n console.error(\"Error creating configuration:\", err);\n\n setCurrentStage(\"error\");\n setError(err.message || \"An unknown error occurred\");\n\n // Kiểm tra nếu người dùng hủy/từ chối giao dịch\n if (\n err.message &&\n (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))\n ) {\n toast.error(\"Transaction rejected\", {\n id: \"build-curve-market-cap\",\n description: \"You have rejected the transaction\",\n });\n } else {\n toast.error(\"Cannot create configuration\", {\n id: \"build-curve-market-cap\",\n description: err.message,\n });\n\n // Nếu giao dịch thất bại do lỗi kết nối, thử chuyển sang RPC endpoint khác\n if (\n err.message?.includes(\"failed to fetch\") ||\n err.message?.includes(\"timeout\") ||\n err.message?.includes(\"429\") ||\n err.message?.includes(\"503\")\n ) {\n switchToNextEndpoint();\n }\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Chức năng mở explorer để xem giao dịch\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl =\n network === \"devnet\"\n ? \"https://explorer.solana.com/tx/\"\n : \"https://solscan.io/tx/\";\n window.open(\n `${baseUrl}${result.signature}${\n network === \"devnet\" ? \"?cluster=devnet\" : \"\"\n }`,\n \"_blank\"\n );\n }\n };\n\n // Chức năng mở explorer để xem cấu hình\n const viewConfig = () => {\n if (result?.config) {\n const baseUrl =\n network === \"devnet\"\n ? \"https://explorer.solana.com/address/\"\n : \"https://solscan.io/account/\";\n window.open(\n `${baseUrl}${result.config}${\n network === \"devnet\" ? \"?cluster=devnet\" : \"\"\n }`,\n \"_blank\"\n );\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setCurrentStage(\"input\");\n setError(\"\");\n };\n\n // Render form view\n const renderForm = () => (\n
\n \n
\n

Market parameters

\n
\n (\n \n Total token supply\n \n \n \n \n \n )}\n />\n\n (\n \n Initial market cap\n \n \n \n \n \n )}\n />\n\n (\n \n Migration market cap\n \n \n \n \n \n )}\n />\n\n (\n \n Migration option\n \n \n \n \n \n )}\n />\n\n (\n \n Token base decimal\n \n \n \n \n \n )}\n />\n\n (\n \n Token quote decimal\n \n \n \n \n \n )}\n />\n
\n
\n\n
\n

Fee parameters

\n
\n (\n \n Base fee (BPS)\n \n \n \n \n \n )}\n />\n\n (\n \n \n \n \n
\n Enable dynamic fee\n
\n
\n )}\n />\n
\n
\n\n
\n
LP distribution
\n\n
\n (\n \n
\n Partner LP %\n
\n \n \n \n \n
\n )}\n />\n\n (\n \n
\n Creator LP %\n
\n \n \n \n \n
\n )}\n />\n\n (\n \n
\n Partner locked LP %\n
\n \n \n \n \n
\n )}\n />\n\n (\n \n
\n Creator locked LP %\n
\n \n \n \n \n
\n )}\n />\n
\n\n

\n Total LP percentage must be 100%. These ratios determine how token\n LP is distributed.\n

\n
\n\n
\n

Address

\n
\n (\n \n Fee claimer address\n \n \n \n \n \n )}\n />\n\n (\n \n Leftover receiver address\n \n \n \n \n \n )}\n />\n\n (\n \n Quote mint address\n \n \n \n \n \n \n \n
\n \n SOL\n
\n
\n \n
\n \n USDC\n
\n
\n \n
\n \n USDT\n
\n
\n
\n \n
\n \n
\n )}\n />\n
\n
\n\n
\n
\n
\n Network\n \n {network}\n \n
\n
\n\n
\n {!connected ? (\n \n ) : (\n \n )}\n
\n
\n
\n \n );\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

Configuration created!

\n\n
\n
\n Configuration address:\n
\n
\n {result?.config}\n
\n
\n\n
\n
\n Transaction signature:\n
\n
\n {result?.signature}\n
\n
\n\n
\n \n\n \n
\n\n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Failed to create configuration

\n

\n {error || \"An error occurred during configuration creation.\"}\n

\n {\n setCurrentStage(\"input\");\n }}\n className=\"w-full\"\n >\n Try again\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Confirming

\n

\n Please wait while your transaction is being processed...\n

\n
\n );\n\n // Render dựa trên stage hiện tại\n const renderStageContent = () => {\n switch (currentStage) {\n case \"success\":\n return renderSuccess();\n case \"error\":\n return renderError();\n case \"confirming\":\n return renderConfirming();\n default:\n return renderForm();\n }\n };\n\n // Tránh lỗi hydration\n if (!mounted) {\n return (\n \n \n Create configuration by market cap\n \n Build a non-decreasing configuration based on market cap\n \n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n Create configuration by market cap\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...\n {publicKey.toString().slice(-4)}\n \n )}\n \n \n Build a non-decreasing configuration based on market cap\n \n \n {renderStageContent()}\n \n );\n}\n", + "content": "\"use client\";\r\n\r\nimport { useState, useEffect, useContext } from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle, Settings } from \"lucide-react\";\r\nimport { PublicKey, Keypair } from \"@solana/web3.js\";\r\nimport { useConnection, useWallet } from \"@solana/wallet-adapter-react\";\r\nimport { DynamicBondingCurveClient } from \"@meteora-ag/dynamic-bonding-curve-sdk\";\r\nimport BN from \"bn.js\";\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/ui/select\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\nenum FeeSchedulerMode {\r\n Linear = 0,\r\n}\r\n\r\ninterface BuildCurveResult {\r\n config: string;\r\n signature: string;\r\n}\r\n\r\ntype FormValues = {\r\n // Các tham số của buildCurveByMarketCapParam\r\n totalTokenSupply: number;\r\n initialMarketCap: number;\r\n migrationMarketCap: number;\r\n migrationOption: number;\r\n tokenBaseDecimal: number;\r\n tokenQuoteDecimal: number;\r\n\r\n // Tham số của feeSchedulerParam\r\n numberOfPeriod: number;\r\n reductionFactor: number;\r\n periodFrequency: number;\r\n feeSchedulerMode: number;\r\n\r\n // Các thông số khác\r\n baseFeeBps: number;\r\n dynamicFeeEnabled: boolean;\r\n activationType: number;\r\n collectFeeMode: number;\r\n migrationFeeOption: number;\r\n tokenType: number;\r\n\r\n // Phân phối LP\r\n partnerLpPercentage: number;\r\n creatorLpPercentage: number;\r\n partnerLockedLpPercentage: number;\r\n creatorLockedLpPercentage: number;\r\n\r\n // Địa chỉ\r\n feeClaimer: string;\r\n leftoverReceiver: string;\r\n quoteMint: string;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate totalTokenSupply\r\n if (!data.totalTokenSupply) {\r\n errors.totalTokenSupply = {\r\n type: \"required\",\r\n message: \"Total token supply is required\",\r\n };\r\n } else if (data.totalTokenSupply <= 0) {\r\n errors.totalTokenSupply = {\r\n type: \"min\",\r\n message: \"Total token supply must be greater than 0\",\r\n };\r\n }\r\n\r\n // Validate initialMarketCap\r\n if (!data.initialMarketCap) {\r\n errors.initialMarketCap = {\r\n type: \"required\",\r\n message: \"Initial market cap is required\",\r\n };\r\n } else if (data.initialMarketCap <= 0) {\r\n errors.initialMarketCap = {\r\n type: \"min\",\r\n message: \"Initial market cap must be greater than 0\",\r\n };\r\n }\r\n\r\n // Validate migrationMarketCap\r\n if (!data.migrationMarketCap) {\r\n errors.migrationMarketCap = {\r\n type: \"required\",\r\n message: \"Migration market cap is required\",\r\n };\r\n } else if (data.migrationMarketCap <= 0) {\r\n errors.migrationMarketCap = {\r\n type: \"min\",\r\n message: \"Migration market cap must be greater than 0\",\r\n };\r\n }\r\n\r\n // Validate tokenBaseDecimal\r\n if (data.tokenBaseDecimal === undefined || data.tokenBaseDecimal === null) {\r\n errors.tokenBaseDecimal = {\r\n type: \"required\",\r\n message: \"Token base decimal is required\",\r\n };\r\n } else if (data.tokenBaseDecimal < 0 || data.tokenBaseDecimal > 18) {\r\n errors.tokenBaseDecimal = {\r\n type: \"range\",\r\n message: \"Token base decimal must be between 0 and 18\",\r\n };\r\n }\r\n\r\n // Validate tokenQuoteDecimal\r\n if (data.tokenQuoteDecimal === undefined || data.tokenQuoteDecimal === null) {\r\n errors.tokenQuoteDecimal = {\r\n type: \"required\",\r\n message: \"Token quote decimal is required\",\r\n };\r\n } else if (data.tokenQuoteDecimal < 0 || data.tokenQuoteDecimal > 18) {\r\n errors.tokenQuoteDecimal = {\r\n type: \"range\",\r\n message: \"Token quote decimal must be between 0 and 18\",\r\n };\r\n }\r\n\r\n // Validate address fields\r\n const validateAddress = (field: string, name: string) => {\r\n if (!data[field]) {\r\n errors[field] = {\r\n type: \"required\",\r\n message: `${name} is required`,\r\n };\r\n } else {\r\n try {\r\n new PublicKey(data[field]);\r\n } catch (e) {\r\n errors[field] = {\r\n type: \"invalid\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n }\r\n };\r\n\r\n validateAddress(\"feeClaimer\", \"Fee claimer address\");\r\n validateAddress(\"leftoverReceiver\", \"Leftover receiver address\");\r\n validateAddress(\"quoteMint\", \"Quote mint address\");\r\n\r\n // Validate LP percentages\r\n const validatePercentage = (field: string, name: string) => {\r\n if (\r\n data[field] === undefined ||\r\n data[field] === null ||\r\n data[field] === \"\"\r\n ) {\r\n errors[field] = {\r\n type: \"required\",\r\n message: `${name} is required`,\r\n };\r\n } else if (Number(data[field]) < 0 || Number(data[field]) > 100) {\r\n errors[field] = {\r\n type: \"range\",\r\n message: `${name} must be between 0 and 100%`,\r\n };\r\n }\r\n };\r\n\r\n validatePercentage(\"partnerLpPercentage\", \"Partner LP percentage\");\r\n validatePercentage(\"creatorLpPercentage\", \"Creator LP percentage\");\r\n validatePercentage(\r\n \"partnerLockedLpPercentage\",\r\n \"Partner locked LP percentage\"\r\n );\r\n validatePercentage(\r\n \"creatorLockedLpPercentage\",\r\n \"Creator locked LP percentage\"\r\n );\r\n\r\n // Validate that percentages sum to 100\r\n const totalPercentage =\r\n Number(data.partnerLpPercentage || 0) +\r\n Number(data.creatorLpPercentage || 0) +\r\n Number(data.partnerLockedLpPercentage || 0) +\r\n Number(data.creatorLockedLpPercentage || 0);\r\n\r\n if (totalPercentage !== 100) {\r\n errors.partnerLpPercentage = {\r\n type: \"validate\",\r\n message: \"Total LP percentage must be 100%\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport default function BuildCurveAndCreateConfigByMarketCapForm({\r\n onConfigCreated,\r\n}: {\r\n onConfigCreated?: (configAddress: string) => void;\r\n}) {\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet } = useWallet();\r\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\r\n\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [result, setResult] = useState(null);\r\n const [currentStage, setCurrentStage] = useState<\r\n \"input\" | \"confirming\" | \"success\" | \"error\"\r\n >(\"input\");\r\n const [error, setError] = useState(\"\");\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState(\"devnet\");\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n totalTokenSupply: 1000000000,\r\n initialMarketCap: 98,\r\n migrationMarketCap: 3200,\r\n migrationOption: 0,\r\n tokenBaseDecimal: 9,\r\n tokenQuoteDecimal: 9,\r\n\r\n numberOfPeriod: 0,\r\n reductionFactor: 0,\r\n periodFrequency: 0,\r\n feeSchedulerMode: FeeSchedulerMode.Linear,\r\n\r\n baseFeeBps: 2500000,\r\n dynamicFeeEnabled: false,\r\n activationType: 0,\r\n collectFeeMode: 0,\r\n migrationFeeOption: 0,\r\n tokenType: 0,\r\n\r\n partnerLpPercentage: 25,\r\n creatorLpPercentage: 25,\r\n partnerLockedLpPercentage: 25,\r\n creatorLockedLpPercentage: 25,\r\n\r\n feeClaimer: \"\",\r\n leftoverReceiver: \"\",\r\n quoteMint: \"So11111111111111111111111111111111111111112\", // SOL by default\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Chỉ render sau khi component được mount trên client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Cập nhật trạng thái network khi endpoint thay đổi\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes(\"devnet\") ? \"devnet\" : \"mainnet\");\r\n }\r\n }, [endpoint]);\r\n\r\n // Tự động điền địa chỉ ví khi ví kết nối\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n form.setValue(\"feeClaimer\", publicKey.toString());\r\n form.setValue(\"leftoverReceiver\", publicKey.toString());\r\n }\r\n }, [connected, publicKey, form]);\r\n\r\n // Xử lý khi form được gửi đi\r\n const onSubmit = async (values: FormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error(\"Please connect your wallet\");\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setCurrentStage(\"confirming\");\r\n setError(\"\");\r\n\r\n toast.loading(\"Creating configuration...\", {\r\n id: \"build-curve-market-cap\",\r\n });\r\n\r\n try {\r\n // Khởi tạo DBC client\r\n const client = new DynamicBondingCurveClient(connection);\r\n\r\n // Tạo keypair mới cho config\r\n const configKeypair = Keypair.generate();\r\n\r\n // Tạo các tham số cho hàm buildCurveAndCreateConfigByMarketCap\r\n const params = {\r\n buildCurveByMarketCapParam: {\r\n totalTokenSupply: values.totalTokenSupply,\r\n initialMarketCap: values.initialMarketCap,\r\n migrationMarketCap: values.migrationMarketCap,\r\n migrationOption: values.migrationOption,\r\n tokenBaseDecimal: values.tokenBaseDecimal,\r\n tokenQuoteDecimal: values.tokenQuoteDecimal,\r\n feeSchedulerParam: {\r\n numberOfPeriod: values.numberOfPeriod,\r\n reductionFactor: values.reductionFactor,\r\n periodFrequency: values.periodFrequency,\r\n feeSchedulerMode: values.feeSchedulerMode,\r\n },\r\n baseFeeBps: values.baseFeeBps,\r\n dynamicFeeEnabled: values.dynamicFeeEnabled,\r\n activationType: values.activationType,\r\n collectFeeMode: values.collectFeeMode,\r\n migrationFeeOption: values.migrationFeeOption,\r\n tokenType: values.tokenType,\r\n lockedVesting: {\r\n amountPerPeriod: new BN(\"0\"),\r\n cliffDurationFromMigrationTime: new BN(\"0\"),\r\n frequency: new BN(\"0\"),\r\n numberOfPeriod: new BN(\"0\"),\r\n cliffUnlockAmount: new BN(\"0\"),\r\n },\r\n partnerLpPercentage: values.partnerLpPercentage,\r\n creatorLpPercentage: values.creatorLpPercentage,\r\n partnerLockedLpPercentage: values.partnerLockedLpPercentage,\r\n creatorLockedLpPercentage: values.creatorLockedLpPercentage,\r\n },\r\n feeClaimer: new PublicKey(values.feeClaimer),\r\n leftoverReceiver: new PublicKey(values.leftoverReceiver),\r\n payer: publicKey,\r\n quoteMint: new PublicKey(values.quoteMint),\r\n config: configKeypair.publicKey,\r\n };\r\n\r\n // Tạo transaction\r\n const transaction =\r\n await client.partners.buildCurveAndCreateConfigByMarketCap(params);\r\n\r\n // Lấy blockhash gần nhất\r\n const { blockhash, lastValidBlockHeight } =\r\n await connection.getLatestBlockhash();\r\n transaction.recentBlockhash = blockhash;\r\n transaction.lastValidBlockHeight = lastValidBlockHeight;\r\n\r\n // Đặt feePayer cho transaction\r\n transaction.feePayer = publicKey;\r\n\r\n // Ký giao dịch với configKeypair\r\n transaction.partialSign(configKeypair);\r\n\r\n // Gửi và ký giao dịch\r\n const signature = await wallet.adapter.sendTransaction(\r\n transaction,\r\n connection\r\n );\r\n\r\n // Đợi xác nhận\r\n await connection.confirmTransaction({\r\n blockhash,\r\n lastValidBlockHeight,\r\n signature,\r\n });\r\n\r\n // Lưu kết quả\r\n const configAddress = configKeypair.publicKey.toString();\r\n setResult({\r\n config: configAddress,\r\n signature: signature,\r\n });\r\n\r\n // Gọi callback nếu được cung cấp\r\n if (onConfigCreated) {\r\n onConfigCreated(configAddress);\r\n }\r\n\r\n setCurrentStage(\"success\");\r\n\r\n toast.success(\"Configuration created successfully!\", {\r\n id: \"build-curve-market-cap\",\r\n description: `Config: ${configAddress.slice(\r\n 0,\r\n 8\r\n )}...${configAddress.slice(-8)}`,\r\n });\r\n } catch (transactionError: any) {\r\n console.error(\"Transaction error: \", transactionError);\r\n throw transactionError;\r\n }\r\n } catch (err: any) {\r\n console.error(\"Error creating configuration:\", err);\r\n\r\n setCurrentStage(\"error\");\r\n setError(err.message || \"An unknown error occurred\");\r\n\r\n // Kiểm tra nếu người dùng hủy/từ chối giao dịch\r\n if (\r\n err.message &&\r\n (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))\r\n ) {\r\n toast.error(\"Transaction rejected\", {\r\n id: \"build-curve-market-cap\",\r\n description: \"You have rejected the transaction\",\r\n });\r\n } else {\r\n toast.error(\"Cannot create configuration\", {\r\n id: \"build-curve-market-cap\",\r\n description: err.message,\r\n });\r\n\r\n // Nếu giao dịch thất bại do lỗi kết nối, thử chuyển sang RPC endpoint khác\r\n if (\r\n err.message?.includes(\"failed to fetch\") ||\r\n err.message?.includes(\"timeout\") ||\r\n err.message?.includes(\"429\") ||\r\n err.message?.includes(\"503\")\r\n ) {\r\n switchToNextEndpoint();\r\n }\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Chức năng mở explorer để xem giao dịch\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl =\r\n network === \"devnet\"\r\n ? \"https://explorer.solana.com/tx/\"\r\n : \"https://solscan.io/tx/\";\r\n window.open(\r\n `${baseUrl}${result.signature}${\r\n network === \"devnet\" ? \"?cluster=devnet\" : \"\"\r\n }`,\r\n \"_blank\"\r\n );\r\n }\r\n };\r\n\r\n // Chức năng mở explorer để xem cấu hình\r\n const viewConfig = () => {\r\n if (result?.config) {\r\n const baseUrl =\r\n network === \"devnet\"\r\n ? \"https://explorer.solana.com/address/\"\r\n : \"https://solscan.io/account/\";\r\n window.open(\r\n `${baseUrl}${result.config}${\r\n network === \"devnet\" ? \"?cluster=devnet\" : \"\"\r\n }`,\r\n \"_blank\"\r\n );\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setCurrentStage(\"input\");\r\n setError(\"\");\r\n };\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n
\r\n

Market parameters

\r\n
\r\n (\r\n \r\n Total token supply\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Initial market cap\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Migration market cap\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Migration option\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Token base decimal\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Token quote decimal\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n
\r\n\r\n
\r\n

Fee parameters

\r\n
\r\n (\r\n \r\n Base fee (BPS)\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n \r\n \r\n \r\n
\r\n Enable dynamic fee\r\n
\r\n
\r\n )}\r\n />\r\n
\r\n
\r\n\r\n
\r\n
LP distribution
\r\n\r\n
\r\n (\r\n \r\n
\r\n Partner LP %\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n )}\r\n />\r\n\r\n (\r\n \r\n
\r\n Creator LP %\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n )}\r\n />\r\n\r\n (\r\n \r\n
\r\n Partner locked LP %\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n )}\r\n />\r\n\r\n (\r\n \r\n
\r\n Creator locked LP %\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n )}\r\n />\r\n
\r\n\r\n

\r\n Total LP percentage must be 100%. These ratios determine how token\r\n LP is distributed.\r\n

\r\n
\r\n\r\n
\r\n

Address

\r\n
\r\n (\r\n \r\n Fee claimer address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Leftover receiver address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Quote mint address\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n SOL\r\n
\r\n
\r\n \r\n
\r\n \r\n USDC\r\n
\r\n
\r\n \r\n
\r\n \r\n USDT\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n )}\r\n />\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n
\r\n\r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n )}\r\n
\r\n
\r\n
\r\n \r\n );\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

Configuration created!

\r\n\r\n
\r\n
\r\n Configuration address:\r\n
\r\n
\r\n {result?.config}\r\n
\r\n
\r\n\r\n
\r\n
\r\n Transaction signature:\r\n
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n\r\n
\r\n \r\n\r\n \r\n
\r\n\r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Failed to create configuration

\r\n

\r\n {error || \"An error occurred during configuration creation.\"}\r\n

\r\n {\r\n setCurrentStage(\"input\");\r\n }}\r\n className=\"w-full\"\r\n >\r\n Try again\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Confirming

\r\n

\r\n Please wait while your transaction is being processed...\r\n

\r\n
\r\n );\r\n\r\n // Render dựa trên stage hiện tại\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case \"success\":\r\n return renderSuccess();\r\n case \"error\":\r\n return renderError();\r\n case \"confirming\":\r\n return renderConfirming();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Tránh lỗi hydration\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create configuration by market cap\r\n \r\n Build a non-decreasing configuration based on market cap\r\n \r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Create configuration by market cap\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...\r\n {publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n \r\n Build a non-decreasing configuration based on market cap\r\n \r\n \r\n {renderStageContent()}\r\n \r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/buildCurveAndCreateConfigByMarketCap-form.tsx" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphis/use-walletModal.ts" } diff --git a/public/r/claim-cToken.json b/public/r/claim-cToken.json index 82f0d07..0dc4574 100644 --- a/public/r/claim-cToken.json +++ b/public/r/claim-cToken.json @@ -24,13 +24,13 @@ "files": [ { "path": "components/ui/murphy/claim-cToken.tsx", - "content": "\"use client\";\n\nimport React, { useContext } from \"react\";\nimport {\n bn,\n buildAndSignTx,\n sendAndConfirmTx,\n dedupeSigner,\n Rpc,\n createRpc,\n } from \"@lightprotocol/stateless.js\";\n import { ComputeBudgetProgram, Keypair, PublicKey, Transaction } from \"@solana/web3.js\";\n import {\n CompressedTokenProgram,\n getTokenPoolInfos,\n selectMinCompressedTokenAccountsForTransfer,\n selectTokenPoolInfosForDecompression,\n } from \"@lightprotocol/compressed-token\";\n import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from \"@solana/spl-token\";\n import bs58 from \"bs58\";\n import { useForm } from \"react-hook-form\";\n import { zodResolver } from \"@hookform/resolvers/zod\";\n import * as z from \"zod\";\n import { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\n import { toast } from \"sonner\";\n\n import { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\n import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\n import { Input } from \"@/components/ui/input\";\n import { Button } from \"@/components/ui/button\";\n import { Loader2 } from \"lucide-react\";\n import { Switch } from \"@/components/ui/switch\";\n import { Label } from \"@/components/ui/label\";\n import { ConnectWalletButton } from \"./connect-wallet-button\";\n import { ModalContext } from \"@/components/providers/wallet-provider\";\n import { QrScannerComponent } from \"./QrScannerComponent\";\n import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from \"@/components/ui/dialog\";\n import { Alert, AlertDescription } from \"@/components/ui/alert\";\n \n // Form schema\n const formSchema = z.object({\n mintAddress: z.string().min(1, \"Mint address is required\"),\n amount: z.number().min(1, \"Amount must be greater than 0\"),\n });\n\n type FormValues = z.infer;\n\n // Add this data type at the top of the file or just before the component\n interface QrResult {\n getText(): string;\n }\n\n export function ClaimTokenForm({ className }: { className?: string }) {\n // Use hook from wallet adapter\n const { publicKey, signTransaction, sendTransaction, connected } = useWallet();\n const { connection } = useConnection();\n const { endpoint } = useContext(ModalContext);\n \n const [isSubmitting, setIsSubmitting] = React.useState(false);\n const [currentStage, setCurrentStage] = React.useState<'input' | 'success' | 'error'>('input');\n const [error, setError] = React.useState(\"\");\n const [result, setResult] = React.useState<{\n txId: string;\n ata: string;\n } | null>(null);\n const [showScanner, setShowScanner] = React.useState(false);\n const [isMainnet, setIsMainnet] = React.useState(true);\n\n const form = useForm({\n resolver: zodResolver(formSchema),\n defaultValues: {\n mintAddress: \"\",\n amount: 100,\n },\n });\n\n const onSubmit = async (values: FormValues) => {\n try {\n // Check if the wallet is connected\n if (!connected || !publicKey || !signTransaction) {\n toast.error(\"Please connect your wallet first\");\n return;\n }\n\n setIsSubmitting(true);\n setError(\"\");\n setCurrentStage('input');\n\n const rpcEndpoint = isMainnet \n ? process.env.NEXT_PUBLIC_SOLANA_RPC_URL \n : process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET;\n\n if (!rpcEndpoint) {\n throw new Error(\"RPC endpoint is not configured\");\n }\n \n // Create RPC connection\n const connection = createRpc(rpcEndpoint);\n\n // Convert mint address\n const mint = new PublicKey(values.mintAddress);\n const amount = values.amount;\n\n // 1. Find Associated Token Account address\n const ataAddress = await getAssociatedTokenAddress(mint, publicKey);\n\n // 2. Check if ATA already exists\n const ataInfo = await connection.getAccountInfo(ataAddress);\n\n // 3. If not, create ATA with a separate transaction\n if (!ataInfo) {\n console.log(\"Creating new Associated Token Account...\");\n const createAtaTx = new Transaction();\n createAtaTx.add(\n createAssociatedTokenAccountInstruction(\n publicKey, // payer\n ataAddress, // ATA address\n publicKey, // owner\n mint // token mint\n )\n );\n \n createAtaTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;\n createAtaTx.feePayer = publicKey;\n \n const signedCreateAtaTx = await signTransaction(createAtaTx);\n const createAtaTxId = await connection.sendRawTransaction(signedCreateAtaTx.serialize());\n \n await connection.confirmTransaction({\n signature: createAtaTxId,\n blockhash: (await connection.getLatestBlockhash()).blockhash,\n lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,\n });\n console.log(\"ATA created with tx ID:\", createAtaTxId);\n }\n\n // 4. Get compressed token accounts\n const compressedTokenAccounts =\n await connection.getCompressedTokenAccountsByOwner(publicKey, {\n mint,\n });\n\n if (!compressedTokenAccounts.items.length) {\n throw new Error(\"No compressed tokens found in account\");\n }\n\n // 5. Select compressed token account for transfer\n const [inputAccounts] = selectMinCompressedTokenAccountsForTransfer(\n compressedTokenAccounts.items,\n bn(amount)\n );\n\n // 6. Get validity proof\n const proof = await connection.getValidityProof(\n inputAccounts.map((account) => account.compressedAccount.hash)\n );\n\n // 7. Get token pool information\n const tokenPoolInfos = await getTokenPoolInfos(connection, mint);\n\n // 8. Select token pool info for decompression\n const selectedTokenPoolInfos = selectTokenPoolInfosForDecompression(\n tokenPoolInfos,\n amount\n );\n\n // 9. Build instruction\n const ix = await CompressedTokenProgram.decompress({\n payer: publicKey,\n inputCompressedTokenAccounts: inputAccounts,\n toAddress: ataAddress,\n amount,\n tokenPoolInfos: selectedTokenPoolInfos,\n recentInputStateRootIndices: proof.rootIndices,\n recentValidityProof: proof.compressedProof,\n });\n\n // 10. Sign and send transaction using connected wallet\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\n \n // Create transaction and add instructions\n const transaction = new Transaction();\n transaction.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }));\n transaction.add(ix);\n \n // Set blockhash and feePayer information\n transaction.recentBlockhash = blockhash;\n transaction.feePayer = publicKey;\n \n console.log(\"Signing transaction...\");\n \n try {\n // Sign transaction using connected wallet\n const signedTx = await signTransaction(transaction);\n \n console.log(\"Sending transaction...\");\n const txId = await connection.sendRawTransaction(signedTx.serialize());\n \n // Wait for confirmation\n await connection.confirmTransaction({\n signature: txId,\n blockhash,\n lastValidBlockHeight,\n });\n \n console.log(\"Transaction confirmed:\", txId);\n \n setResult({\n txId,\n ata: ataAddress.toBase58()\n });\n setCurrentStage('success');\n \n toast.success(\"Decompression successful!\", {\n description: `Transaction: ${txId}`\n });\n } catch (signError: any) {\n console.error('Error signing transaction:', signError);\n \n // Analyze error if user canceled the transaction\n if (signError.message && signError.message.includes(\"canceled\")) {\n toast.error(\"Transaction canceled\", {\n description: \"You canceled the transaction\"\n });\n setError(\"You canceled the transaction\");\n } else {\n toast.error(\"Error signing transaction\", {\n description: signError.message || \"Unable to sign transaction\"\n });\n setError(`Error signing transaction: ${signError.message}`);\n }\n \n setCurrentStage('error');\n throw signError;\n }\n } catch (err) {\n console.error(err);\n setError(err instanceof Error ? err.message : \"An error occurred\");\n setCurrentStage('error');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setCurrentStage(\"input\");\n setError(\"\");\n };\n\n // Add helper function to handle long text\n const truncateText = (text: string, maxLength: number = 20) => {\n if (text.length <= maxLength) return text;\n return `${text.slice(0, maxLength)}...`;\n };\n\n // Add helper function to copy text\n const copyToClipboard = (text: string) => {\n navigator.clipboard.writeText(text);\n toast.success(\"Copied to clipboard\");\n };\n\n // Add helper function to create Solscan link\n const getSolscanUrl = (type: 'tx' | 'token' | 'account', id: string) => {\n const cluster = isMainnet ? '' : '?cluster=devnet';\n return `https://solscan.io/${type}/${id}${cluster}`;\n };\n\n // Add function to handle successful QR scan\n const handleScan = (data: string) => {\n try {\n console.log(\"QR data received:\", data);\n\n // Try parsing JSON data\n let parsedData;\n try {\n parsedData = JSON.parse(data);\n } catch (e) {\n // If not JSON, check if it's simple text\n if (data.includes(\"mintAddress\")) {\n // Extract information from text string\n const mintMatch = data.match(/mintAddress[=:]\\s*[\"']?([^\"',}&\\s]+)/i);\n const amountMatch = data.match(/amount[=:]\\s*[\"']?([0-9]+)/i);\n \n if (mintMatch) {\n parsedData = {\n mintAddress: mintMatch[1],\n amount: amountMatch ? parseInt(amountMatch[1]) : 100\n };\n }\n }\n }\n\n // Check if data is compressed token data\n if (parsedData && parsedData.mintAddress) {\n // Check Solana address format\n try {\n new PublicKey(parsedData.mintAddress);\n } catch (e) {\n toast.error(\"Invalid token address\");\n return;\n }\n\n // Check type to confirm this is a compressed token QR code\n if (parsedData.type === \"compressed-token-claim\" || !parsedData.type) {\n form.setValue(\"mintAddress\", parsedData.mintAddress);\n if (parsedData.amount && !isNaN(Number(parsedData.amount))) {\n form.setValue(\"amount\", Number(parsedData.amount));\n }\n \n setShowScanner(false);\n toast.success(\"QR code scanned successfully\", {\n description: `Token: ${parsedData.mintAddress.slice(0, 6)}...${parsedData.mintAddress.slice(-4)}`\n });\n } else {\n toast.error(\"QR code is not a compressed token\");\n }\n } else {\n toast.error(\"QR code does not contain valid token information\");\n }\n } catch (error) {\n console.error(\"QR processing error:\", error);\n toast.error(\"Unable to process QR code\");\n }\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
FieldValueAction
Token Address\n
\n {truncateText(form.getValues(\"mintAddress\") || \"\")}\n copyToClipboard(form.getValues(\"mintAddress\"))}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('token', form.getValues(\"mintAddress\")), '_blank')}\n >\n View\n \n
Token Account\n
\n {truncateText(result?.ata || \"\")}\n copyToClipboard(result?.ata || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('account', result?.ata || \"\"), '_blank')}\n >\n View\n \n
Amount{form.getValues(\"amount\")}\n copyToClipboard(form.getValues(\"amount\").toString())}\n >\n Copy\n \n
Transaction ID\n
\n {truncateText(result?.txId || \"\")}\n copyToClipboard(result?.txId || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('tx', result?.txId || \"\"), '_blank')}\n >\n View\n \n
\n
\n
\n\n
\n \n \n
\n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n {error}\n
\n \n
\n );\n\n // Render input form\n const renderInputForm = () => (\n
\n \n
\n
\n \n
\n Devnet\n \n Mainnet\n
\n
\n

\n Select the network you want to use to process tokens\n

\n
\n\n
\n \n \n \n \n \n \n Scan QR Code\n \n
\n \n
\n
\n Bring the QR code into the camera's view to automatically fill in the token information\n
\n \n \n \n Note: After a successful scan, you still need to press the \"Decompress Tokens\" button to confirm\n \n \n
\n
\n
\n\n (\n \n Token Address\n \n \n \n \n \n )}\n />\n\n (\n \n Token Amount\n \n field.onChange(Number(e.target.value))}\n disabled={isSubmitting || !connected}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n \n \n )}\n />\n\n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Decompressing Tokens...\n \n ) : (\n \"Decompress Tokens\"\n )}\n \n )}\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n default:\n return renderInputForm();\n }\n };\n\n return (\n \n \n Decompress Tokens\n \n \n {renderStageContent()}\n \n \n );\n }", + "content": "\"use client\";\r\n\r\nimport React, { useContext } from \"react\";\r\nimport {\r\n bn,\r\n buildAndSignTx,\r\n sendAndConfirmTx,\r\n dedupeSigner,\r\n Rpc,\r\n createRpc,\r\n } from \"@lightprotocol/stateless.js\";\r\n import { ComputeBudgetProgram, Keypair, PublicKey, Transaction } from \"@solana/web3.js\";\r\n import {\r\n CompressedTokenProgram,\r\n getTokenPoolInfos,\r\n selectMinCompressedTokenAccountsForTransfer,\r\n selectTokenPoolInfosForDecompression,\r\n } from \"@lightprotocol/compressed-token\";\r\n import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from \"@solana/spl-token\";\r\n import bs58 from \"bs58\";\r\n import { useForm } from \"react-hook-form\";\r\n import { zodResolver } from \"@hookform/resolvers/zod\";\r\n import * as z from \"zod\";\r\n import { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\r\n import { toast } from \"sonner\";\r\n\r\n import { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\n import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\r\n import { Input } from \"@/components/ui/input\";\r\n import { Button } from \"@/components/ui/button\";\r\n import { Loader2 } from \"lucide-react\";\r\n import { Switch } from \"@/components/ui/switch\";\r\n import { Label } from \"@/components/ui/label\";\r\n import { ConnectWalletButton } from \"./connect-wallet-button\";\r\n import { ModalContext } from \"@/components/providers/wallet-provider\";\r\n import { QrScannerComponent } from \"./QrScannerComponent\";\r\n import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from \"@/components/ui/dialog\";\r\n import { Alert, AlertDescription } from \"@/components/ui/alert\";\r\n \r\n // Form schema\r\n const formSchema = z.object({\r\n mintAddress: z.string().min(1, \"Mint address is required\"),\r\n amount: z.number().min(1, \"Amount must be greater than 0\"),\r\n });\r\n\r\n type FormValues = z.infer;\r\n\r\n // Add this data type at the top of the file or just before the component\r\n interface QrResult {\r\n getText(): string;\r\n }\r\n\r\n export function ClaimTokenForm({ className }: { className?: string }) {\r\n // Use hook from wallet adapter\r\n const { publicKey, signTransaction, sendTransaction, connected } = useWallet();\r\n const { connection } = useConnection();\r\n const { endpoint } = useContext(ModalContext);\r\n \r\n const [isSubmitting, setIsSubmitting] = React.useState(false);\r\n const [currentStage, setCurrentStage] = React.useState<'input' | 'success' | 'error'>('input');\r\n const [error, setError] = React.useState(\"\");\r\n const [result, setResult] = React.useState<{\r\n txId: string;\r\n ata: string;\r\n } | null>(null);\r\n const [showScanner, setShowScanner] = React.useState(false);\r\n const [isMainnet, setIsMainnet] = React.useState(true);\r\n\r\n const form = useForm({\r\n resolver: zodResolver(formSchema),\r\n defaultValues: {\r\n mintAddress: \"\",\r\n amount: 100,\r\n },\r\n });\r\n\r\n const onSubmit = async (values: FormValues) => {\r\n try {\r\n // Check if the wallet is connected\r\n if (!connected || !publicKey || !signTransaction) {\r\n toast.error(\"Please connect your wallet first\");\r\n return;\r\n }\r\n\r\n setIsSubmitting(true);\r\n setError(\"\");\r\n setCurrentStage('input');\r\n\r\n const rpcEndpoint = isMainnet \r\n ? process.env.NEXT_PUBLIC_SOLANA_RPC_URL \r\n : process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET;\r\n\r\n if (!rpcEndpoint) {\r\n throw new Error(\"RPC endpoint is not configured\");\r\n }\r\n \r\n // Create RPC connection\r\n const connection = createRpc(rpcEndpoint);\r\n\r\n // Convert mint address\r\n const mint = new PublicKey(values.mintAddress);\r\n const amount = values.amount;\r\n\r\n // 1. Find Associated Token Account address\r\n const ataAddress = await getAssociatedTokenAddress(mint, publicKey);\r\n\r\n // 2. Check if ATA already exists\r\n const ataInfo = await connection.getAccountInfo(ataAddress);\r\n\r\n // 3. If not, create ATA with a separate transaction\r\n if (!ataInfo) {\r\n console.log(\"Creating new Associated Token Account...\");\r\n const createAtaTx = new Transaction();\r\n createAtaTx.add(\r\n createAssociatedTokenAccountInstruction(\r\n publicKey, // payer\r\n ataAddress, // ATA address\r\n publicKey, // owner\r\n mint // token mint\r\n )\r\n );\r\n \r\n createAtaTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;\r\n createAtaTx.feePayer = publicKey;\r\n \r\n const signedCreateAtaTx = await signTransaction(createAtaTx);\r\n const createAtaTxId = await connection.sendRawTransaction(signedCreateAtaTx.serialize());\r\n \r\n await connection.confirmTransaction({\r\n signature: createAtaTxId,\r\n blockhash: (await connection.getLatestBlockhash()).blockhash,\r\n lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,\r\n });\r\n console.log(\"ATA created with tx ID:\", createAtaTxId);\r\n }\r\n\r\n // 4. Get compressed token accounts\r\n const compressedTokenAccounts =\r\n await connection.getCompressedTokenAccountsByOwner(publicKey, {\r\n mint,\r\n });\r\n\r\n if (!compressedTokenAccounts.items.length) {\r\n throw new Error(\"No compressed tokens found in account\");\r\n }\r\n\r\n // 5. Select compressed token account for transfer\r\n const [inputAccounts] = selectMinCompressedTokenAccountsForTransfer(\r\n compressedTokenAccounts.items,\r\n bn(amount)\r\n );\r\n\r\n // 6. Get validity proof\r\n const proof = await connection.getValidityProof(\r\n inputAccounts.map((account) => account.compressedAccount.hash)\r\n );\r\n\r\n // 7. Get token pool information\r\n const tokenPoolInfos = await getTokenPoolInfos(connection, mint);\r\n\r\n // 8. Select token pool info for decompression\r\n const selectedTokenPoolInfos = selectTokenPoolInfosForDecompression(\r\n tokenPoolInfos,\r\n amount\r\n );\r\n\r\n // 9. Build instruction\r\n const ix = await CompressedTokenProgram.decompress({\r\n payer: publicKey,\r\n inputCompressedTokenAccounts: inputAccounts,\r\n toAddress: ataAddress,\r\n amount,\r\n tokenPoolInfos: selectedTokenPoolInfos,\r\n recentInputStateRootIndices: proof.rootIndices,\r\n recentValidityProof: proof.compressedProof,\r\n });\r\n\r\n // 10. Sign and send transaction using connected wallet\r\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\r\n \r\n // Create transaction and add instructions\r\n const transaction = new Transaction();\r\n transaction.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }));\r\n transaction.add(ix);\r\n \r\n // Set blockhash and feePayer information\r\n transaction.recentBlockhash = blockhash;\r\n transaction.feePayer = publicKey;\r\n \r\n console.log(\"Signing transaction...\");\r\n \r\n try {\r\n // Sign transaction using connected wallet\r\n const signedTx = await signTransaction(transaction);\r\n \r\n console.log(\"Sending transaction...\");\r\n const txId = await connection.sendRawTransaction(signedTx.serialize());\r\n \r\n // Wait for confirmation\r\n await connection.confirmTransaction({\r\n signature: txId,\r\n blockhash,\r\n lastValidBlockHeight,\r\n });\r\n \r\n console.log(\"Transaction confirmed:\", txId);\r\n \r\n setResult({\r\n txId,\r\n ata: ataAddress.toBase58()\r\n });\r\n setCurrentStage('success');\r\n \r\n toast.success(\"Decompression successful!\", {\r\n description: `Transaction: ${txId}`\r\n });\r\n } catch (signError: any) {\r\n console.error('Error signing transaction:', signError);\r\n \r\n // Analyze error if user canceled the transaction\r\n if (signError.message && signError.message.includes(\"canceled\")) {\r\n toast.error(\"Transaction canceled\", {\r\n description: \"You canceled the transaction\"\r\n });\r\n setError(\"You canceled the transaction\");\r\n } else {\r\n toast.error(\"Error signing transaction\", {\r\n description: signError.message || \"Unable to sign transaction\"\r\n });\r\n setError(`Error signing transaction: ${signError.message}`);\r\n }\r\n \r\n setCurrentStage('error');\r\n throw signError;\r\n }\r\n } catch (err) {\r\n console.error(err);\r\n setError(err instanceof Error ? err.message : \"An error occurred\");\r\n setCurrentStage('error');\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setCurrentStage(\"input\");\r\n setError(\"\");\r\n };\r\n\r\n // Add helper function to handle long text\r\n const truncateText = (text: string, maxLength: number = 20) => {\r\n if (text.length <= maxLength) return text;\r\n return `${text.slice(0, maxLength)}...`;\r\n };\r\n\r\n // Add helper function to copy text\r\n const copyToClipboard = (text: string) => {\r\n navigator.clipboard.writeText(text);\r\n toast.success(\"Copied to clipboard\");\r\n };\r\n\r\n // Add helper function to create Solscan link\r\n const getSolscanUrl = (type: 'tx' | 'token' | 'account', id: string) => {\r\n const cluster = isMainnet ? '' : '?cluster=devnet';\r\n return `https://solscan.io/${type}/${id}${cluster}`;\r\n };\r\n\r\n // Add function to handle successful QR scan\r\n const handleScan = (data: string) => {\r\n try {\r\n console.log(\"QR data received:\", data);\r\n\r\n // Try parsing JSON data\r\n let parsedData;\r\n try {\r\n parsedData = JSON.parse(data);\r\n } catch (e) {\r\n // If not JSON, check if it's simple text\r\n if (data.includes(\"mintAddress\")) {\r\n // Extract information from text string\r\n const mintMatch = data.match(/mintAddress[=:]\\s*[\"']?([^\"',}&\\s]+)/i);\r\n const amountMatch = data.match(/amount[=:]\\s*[\"']?([0-9]+)/i);\r\n \r\n if (mintMatch) {\r\n parsedData = {\r\n mintAddress: mintMatch[1],\r\n amount: amountMatch ? parseInt(amountMatch[1]) : 100\r\n };\r\n }\r\n }\r\n }\r\n\r\n // Check if data is compressed token data\r\n if (parsedData && parsedData.mintAddress) {\r\n // Check Solana address format\r\n try {\r\n new PublicKey(parsedData.mintAddress);\r\n } catch (e) {\r\n toast.error(\"Invalid token address\");\r\n return;\r\n }\r\n\r\n // Check type to confirm this is a compressed token QR code\r\n if (parsedData.type === \"compressed-token-claim\" || !parsedData.type) {\r\n form.setValue(\"mintAddress\", parsedData.mintAddress);\r\n if (parsedData.amount && !isNaN(Number(parsedData.amount))) {\r\n form.setValue(\"amount\", Number(parsedData.amount));\r\n }\r\n \r\n setShowScanner(false);\r\n toast.success(\"QR code scanned successfully\", {\r\n description: `Token: ${parsedData.mintAddress.slice(0, 6)}...${parsedData.mintAddress.slice(-4)}`\r\n });\r\n } else {\r\n toast.error(\"QR code is not a compressed token\");\r\n }\r\n } else {\r\n toast.error(\"QR code does not contain valid token information\");\r\n }\r\n } catch (error) {\r\n console.error(\"QR processing error:\", error);\r\n toast.error(\"Unable to process QR code\");\r\n }\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
FieldValueAction
Token Address\r\n
\r\n {truncateText(form.getValues(\"mintAddress\") || \"\")}\r\n copyToClipboard(form.getValues(\"mintAddress\"))}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('token', form.getValues(\"mintAddress\")), '_blank')}\r\n >\r\n View\r\n \r\n
Token Account\r\n
\r\n {truncateText(result?.ata || \"\")}\r\n copyToClipboard(result?.ata || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('account', result?.ata || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
Amount{form.getValues(\"amount\")}\r\n copyToClipboard(form.getValues(\"amount\").toString())}\r\n >\r\n Copy\r\n \r\n
Transaction ID\r\n
\r\n {truncateText(result?.txId || \"\")}\r\n copyToClipboard(result?.txId || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('tx', result?.txId || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n {error}\r\n
\r\n \r\n
\r\n );\r\n\r\n // Render input form\r\n const renderInputForm = () => (\r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n Devnet\r\n \r\n Mainnet\r\n
\r\n
\r\n

\r\n Select the network you want to use to process tokens\r\n

\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n Scan QR Code\r\n \r\n
\r\n \r\n
\r\n
\r\n Bring the QR code into the camera's view to automatically fill in the token information\r\n
\r\n \r\n \r\n \r\n Note: After a successful scan, you still need to press the \"Decompress Tokens\" button to confirm\r\n \r\n \r\n
\r\n
\r\n
\r\n\r\n (\r\n \r\n Token Address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Token Amount\r\n \r\n field.onChange(Number(e.target.value))}\r\n disabled={isSubmitting || !connected}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Decompressing Tokens...\r\n \r\n ) : (\r\n \"Decompress Tokens\"\r\n )}\r\n \r\n )}\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n default:\r\n return renderInputForm();\r\n }\r\n };\r\n\r\n return (\r\n \r\n \r\n Decompress Tokens\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n }", "type": "registry:component", "target": "components/ui/murphy/claim-cToken.tsx" }, { "path": "components/ui/murphy/QrScannerComponent.tsx", - "content": "\"use client\";\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { Button } from \"@/components/ui/button\";\nimport { CameraIcon, FlipHorizontalIcon, ScanLine } from \"lucide-react\";\n\nexport const QrScannerComponent = ({ \n onScan, \n stopScanning \n}: { \n onScan: (data: string) => void, \n stopScanning: boolean \n}) => {\n const [isScanning, setIsScanning] = useState(false);\n const [facingMode, setFacingMode] = useState<\"environment\" | \"user\">(\"environment\");\n const videoRef = useRef(null);\n const canvasRef = useRef(null);\n const streamRef = useRef(null);\n \n // Set interval ID for scanning\n const scanIntervalRef = useRef(null);\n\n // Start camera\n useEffect(() => {\n const startCamera = async () => {\n try {\n if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n toast.error(\"Browser does not support camera\");\n return;\n }\n\n if (streamRef.current) {\n streamRef.current.getTracks().forEach(track => track.stop());\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode }\n });\n \n streamRef.current = stream;\n \n if (videoRef.current) {\n videoRef.current.srcObject = stream;\n videoRef.current.onloadedmetadata = () => {\n videoRef.current?.play();\n setIsScanning(true);\n startScanning();\n };\n }\n } catch (error) {\n console.error(\"Error opening camera:\", error);\n toast.error(\"Cannot open camera, please grant access\");\n }\n };\n\n const startScanning = () => {\n if (scanIntervalRef.current) {\n clearInterval(scanIntervalRef.current);\n }\n\n scanIntervalRef.current = setInterval(() => {\n scanQRCode();\n }, 500); // Scan every 500ms\n };\n\n if (!stopScanning) {\n startCamera();\n }\n\n return () => {\n if (streamRef.current) {\n streamRef.current.getTracks().forEach(track => track.stop());\n }\n if (scanIntervalRef.current) {\n clearInterval(scanIntervalRef.current);\n }\n setIsScanning(false);\n };\n }, [stopScanning, facingMode]);\n\n // QR code scanning function\n const scanQRCode = async () => {\n if (!isScanning || !videoRef.current || !canvasRef.current) return;\n\n const video = videoRef.current;\n const canvas = canvasRef.current;\n const context = canvas.getContext('2d');\n \n if (!context || video.videoWidth === 0) return;\n\n // Set canvas size to match video\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n \n // Draw the current frame from video to canvas\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\n \n try {\n // Use BarcodeDetector library if supported by the browser\n if ('BarcodeDetector' in window) {\n const barcodeDetector = new (window as any).BarcodeDetector({\n formats: ['qr_code']\n });\n \n const barcodes = await barcodeDetector.detect(canvas);\n \n if (barcodes.length > 0) {\n // QR code found\n const qrData = barcodes[0].rawValue;\n if (qrData) {\n clearInterval(scanIntervalRef.current!);\n onScan(qrData);\n }\n }\n }\n } catch (error) {\n console.error(\"Error scanning QR code:\", error);\n }\n };\n\n // Toggle camera\n const toggleCamera = () => {\n setFacingMode(prev => prev === \"environment\" ? \"user\" : \"environment\");\n };\n\n // Simulated QR code for testing\n const handleTestQR = () => {\n const testData = JSON.stringify({\n mintAddress: \"BJAGZ5GqDxm7bPSDDjM473XCkPFvewtXJHkMnY3KFM7Z\",\n amount: 100,\n type: \"compressed-token-claim\",\n timestamp: new Date().toISOString()\n });\n onScan(testData);\n toast.success(\"Test QR code scanned\");\n };\n\n return (\n
\n
\n
\n \n
\n \n \n \n
\n \n

\n {isScanning ? \"Place the QR code within the frame to scan\" : \"Initializing camera...\"}\n

\n
\n );\n};", + "content": "\"use client\";\r\n\r\nimport React, { useState, useEffect, useRef } from \"react\";\r\nimport { toast } from \"sonner\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { CameraIcon, FlipHorizontalIcon, ScanLine } from \"lucide-react\";\r\n\r\nexport const QrScannerComponent = ({ \r\n onScan, \r\n stopScanning \r\n}: { \r\n onScan: (data: string) => void, \r\n stopScanning: boolean \r\n}) => {\r\n const [isScanning, setIsScanning] = useState(false);\r\n const [facingMode, setFacingMode] = useState<\"environment\" | \"user\">(\"environment\");\r\n const videoRef = useRef(null);\r\n const canvasRef = useRef(null);\r\n const streamRef = useRef(null);\r\n \r\n // Set interval ID for scanning\r\n const scanIntervalRef = useRef(null);\r\n\r\n // Start camera\r\n useEffect(() => {\r\n const startCamera = async () => {\r\n try {\r\n if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\r\n toast.error(\"Browser does not support camera\");\r\n return;\r\n }\r\n\r\n if (streamRef.current) {\r\n streamRef.current.getTracks().forEach(track => track.stop());\r\n }\r\n\r\n const stream = await navigator.mediaDevices.getUserMedia({\r\n video: { facingMode }\r\n });\r\n \r\n streamRef.current = stream;\r\n \r\n if (videoRef.current) {\r\n videoRef.current.srcObject = stream;\r\n videoRef.current.onloadedmetadata = () => {\r\n videoRef.current?.play();\r\n setIsScanning(true);\r\n startScanning();\r\n };\r\n }\r\n } catch (error) {\r\n console.error(\"Error opening camera:\", error);\r\n toast.error(\"Cannot open camera, please grant access\");\r\n }\r\n };\r\n\r\n const startScanning = () => {\r\n if (scanIntervalRef.current) {\r\n clearInterval(scanIntervalRef.current);\r\n }\r\n\r\n scanIntervalRef.current = setInterval(() => {\r\n scanQRCode();\r\n }, 500); // Scan every 500ms\r\n };\r\n\r\n if (!stopScanning) {\r\n startCamera();\r\n }\r\n\r\n return () => {\r\n if (streamRef.current) {\r\n streamRef.current.getTracks().forEach(track => track.stop());\r\n }\r\n if (scanIntervalRef.current) {\r\n clearInterval(scanIntervalRef.current);\r\n }\r\n setIsScanning(false);\r\n };\r\n }, [stopScanning, facingMode]);\r\n\r\n // QR code scanning function\r\n const scanQRCode = async () => {\r\n if (!isScanning || !videoRef.current || !canvasRef.current) return;\r\n\r\n const video = videoRef.current;\r\n const canvas = canvasRef.current;\r\n const context = canvas.getContext('2d');\r\n \r\n if (!context || video.videoWidth === 0) return;\r\n\r\n // Set canvas size to match video\r\n canvas.width = video.videoWidth;\r\n canvas.height = video.videoHeight;\r\n \r\n // Draw the current frame from video to canvas\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n \r\n try {\r\n // Use BarcodeDetector library if supported by the browser\r\n if ('BarcodeDetector' in window) {\r\n const barcodeDetector = new (window as any).BarcodeDetector({\r\n formats: ['qr_code']\r\n });\r\n \r\n const barcodes = await barcodeDetector.detect(canvas);\r\n \r\n if (barcodes.length > 0) {\r\n // QR code found\r\n const qrData = barcodes[0].rawValue;\r\n if (qrData) {\r\n clearInterval(scanIntervalRef.current!);\r\n onScan(qrData);\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\"Error scanning QR code:\", error);\r\n }\r\n };\r\n\r\n // Toggle camera\r\n const toggleCamera = () => {\r\n setFacingMode(prev => prev === \"environment\" ? \"user\" : \"environment\");\r\n };\r\n\r\n // Simulated QR code for testing\r\n const handleTestQR = () => {\r\n const testData = JSON.stringify({\r\n mintAddress: \"BJAGZ5GqDxm7bPSDDjM473XCkPFvewtXJHkMnY3KFM7Z\",\r\n amount: 100,\r\n type: \"compressed-token-claim\",\r\n timestamp: new Date().toISOString()\r\n });\r\n onScan(testData);\r\n toast.success(\"Test QR code scanned\");\r\n };\r\n\r\n return (\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n

\r\n {isScanning ? \"Place the QR code within the frame to scan\" : \"Initializing camera...\"}\r\n

\r\n
\r\n );\r\n};", "type": "registry:component", "target": "components/ui/murphy/QrScannerComponent.tsx" } diff --git a/public/r/connect-wallet-button.json b/public/r/connect-wallet-button.json index 522ce41..495d2c7 100644 --- a/public/r/connect-wallet-button.json +++ b/public/r/connect-wallet-button.json @@ -19,37 +19,37 @@ "files": [ { "path": "components/ui/murphy/connect-wallet-button.tsx", - "content": "\"use client\"\n\nimport React, { type FC, useCallback, useEffect, useMemo, useState } from \"react\"\nimport { useWallet } from \"@solana/wallet-adapter-react\"\nimport { WalletName, WalletReadyState } from \"@solana/wallet-adapter-base\"\nimport { useWalletMultiButton } from \"@/hook/murphy/use-walletMultiButton\"\nimport { Button } from \"../button\"\nimport { ModalContext } from \"@/components/providers/wallet-provider\"\nimport { useLazorKitWalletContext } from \"@/components/providers/lazorkit-wallet-context\"\nimport { PublicKey } from \"@solana/web3.js\"\n\nimport { Dialog, DialogClose, DialogContent, DialogHeader, DialogTitle, DialogDescription } from \"../dialog\"\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"../collapsible\"\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from \"../dropdown-menu\"\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"../tabs\"\nimport { Badge } from \"../badge\"\nimport { Loader2, Key, ChevronDown } from \"lucide-react\"\n\n// Constants\nconst LABELS = {\n \"change-wallet\": \"Change Wallet\",\n connecting: \"Connecting...\",\n \"copy-address\": \"Copy Address\",\n copied: \"Copied\",\n disconnect: \"Disconnect\",\n \"has-wallet\": \"Connect Wallet\",\n \"no-wallet\": \"Select Wallet\",\n \"lazorkit-wallet\": \"Connect Passkey\",\n \"standard-wallet\": \"Standard Wallet\",\n \"connection-error\": \"Connection Error\",\n \"retry-connection\": \"Retry Connection\",\n \"initializing\": \"Initializing Smart Wallet...\",\n \"initialization-error\": \"Failed to initialize wallet\",\n \"creating-passkey\": \"Creating Passkey...\",\n \"creating-smart-wallet\": \"Creating Smart Wallet...\",\n} as const\n\n// Types\ntype WalletButtonProps = React.ComponentProps<\"button\"> & {\n labels?: Partial\n asChild?: boolean\n variant?: \"default\" | \"destructive\" | \"outline\" | \"secondary\" | \"ghost\" | \"link\"\n size?: \"default\" | \"sm\" | \"lg\" | \"icon\"\n}\n\ntype Props = WalletButtonProps\n\nexport interface WalletListItemProps {\n handleClick: React.MouseEventHandler\n tabIndex?: number\n wallet: {\n adapter: {\n name: string\n icon?: string\n }\n readyState: WalletReadyState\n }\n}\n\n// Wallet List Item Component\nexport const WalletListItem: FC = ({ handleClick, tabIndex, wallet }) => {\n const isInstalled = wallet.readyState === WalletReadyState.Installed\n \n return (\n \n )\n}\n\n// Enhanced Wallet Modal Component\nexport const EnhancedWalletModal: FC<{\n open: boolean\n onOpenChange: (open: boolean) => void\n}> = ({ open, onOpenChange }) => {\n const { wallets, select } = useWallet()\n const [expanded, setExpanded] = useState(false)\n const [activeTab, setActiveTab] = useState<'standard' | 'lazorkit'>('standard')\n const [isInitializing, setIsInitializing] = useState(false)\n const [isCreatingPasskey, setIsCreatingPasskey] = useState(false)\n const [isCreatingSmartWallet, setIsCreatingSmartWallet] = useState(false)\n \n const { \n connect: connectLazorKit,\n createPasskeyOnly,\n createSmartWalletOnly,\n disconnect: disconnectLazorKit, \n isLoading: isLoadingLazorKit, \n isConnected: isLazorKitConnected,\n smartWalletPubkey,\n error: lazorKitError,\n clearError\n } = useLazorKitWalletContext()\n\n const modalContext = React.useContext(ModalContext)\n const isMainnet = modalContext?.isMainnet ?? false\n const { walletType, setWalletType } = modalContext || { walletType: 'standard', setWalletType: () => {} }\n\n // Memoize wallet lists\n const { listedWallets, collapsedWallets } = useMemo(() => {\n const installed = wallets.filter((w) => w.readyState === WalletReadyState.Installed)\n const notInstalled = wallets.filter((w) => w.readyState !== WalletReadyState.Installed)\n return {\n listedWallets: installed.length ? installed : notInstalled,\n collapsedWallets: installed.length ? notInstalled : []\n }\n }, [wallets])\n\n const handleWalletClick = useCallback(\n async (event: React.MouseEvent, walletName: string) => {\n event.preventDefault()\n try {\n await select(walletName as WalletName)\n setWalletType('standard')\n onOpenChange(false)\n } catch (error) {\n console.error('Failed to select wallet:', error)\n }\n },\n [select, onOpenChange, setWalletType],\n )\n\n const handleLazorKitConnect = useCallback(async () => {\n try {\n clearError()\n setIsInitializing(false)\n setIsCreatingPasskey(false)\n setIsCreatingSmartWallet(false)\n console.log(\"Starting LazorKit connection...\")\n \n try {\n // First try normal connection\n const account = await connectLazorKit()\n console.log(\"LazorKit connected, account:\", account)\n \n if (!account || !account.publicKey) {\n throw new Error(\"Failed to get wallet account\")\n }\n\n const walletAddress = account.publicKey.toString()\n console.log('Connected with address:', walletAddress)\n \n window.localStorage.setItem('SMART_WALLET_ADDRESS', walletAddress)\n setWalletType('lazorkit')\n onOpenChange(false)\n } catch (error) {\n // If normal connection fails, try step-by-step creation\n if (error instanceof Error && \n (error.message.includes('Account does not exist') || \n error.message.includes('needs to be initialized'))) {\n try {\n // Step 1: Create passkey\n setIsCreatingPasskey(true)\n const passkeyData = await createPasskeyOnly()\n console.log(\"Passkey created:\", passkeyData)\n \n // Step 2: Create smart wallet\n setIsCreatingPasskey(false)\n setIsCreatingSmartWallet(true)\n const { smartWalletAddress, account } = await createSmartWalletOnly(passkeyData)\n console.log(\"Smart wallet created:\", smartWalletAddress)\n\n if (!account || !account.publicKey) {\n throw new Error(\"Failed to initialize wallet\")\n }\n\n window.localStorage.setItem('SMART_WALLET_ADDRESS', smartWalletAddress)\n setWalletType('lazorkit')\n onOpenChange(false)\n } catch (createError) {\n console.error(\"Failed to create wallet:\", createError)\n throw createError\n }\n } else {\n throw error\n }\n }\n } catch (error) {\n console.error(\"LazorKit connection error:\", error)\n setIsInitializing(false)\n setIsCreatingPasskey(false)\n setIsCreatingSmartWallet(false)\n }\n }, [connectLazorKit, createPasskeyOnly, createSmartWalletOnly, setWalletType, onOpenChange, clearError])\n\n // Effect to handle successful connection\n useEffect(() => {\n if (isLazorKitConnected && smartWalletPubkey) {\n const walletAddress = smartWalletPubkey.toString()\n window.localStorage.setItem('SMART_WALLET_ADDRESS', walletAddress)\n setWalletType('lazorkit')\n onOpenChange(false)\n }\n }, [isLazorKitConnected, smartWalletPubkey, setWalletType, onOpenChange])\n\n // Effect to sync active tab with wallet type\n useEffect(() => {\n setActiveTab(walletType)\n }, [walletType])\n\n return (\n \n \n \n Connect wallet to continue\n \n Choose your preferred wallet to connect to this dApp.\n \n
\n
\n Note: LazorKit is currently in beta and only supports Devnet\n
\n
\n Network Status:\n \n {activeTab === 'lazorkit' ? 'Devnet' : (isMainnet ? 'Mainnet' : 'Devnet')}\n \n
\n
\n
\n\n setActiveTab(value as 'standard' | 'lazorkit')}>\n \n \n {LABELS[\"standard-wallet\"]}\n \n \n {LABELS[\"lazorkit-wallet\"]}\n \n \n\n \n
\n {/* Standard wallet list */}\n {listedWallets.map((wallet) => (\n handleWalletClick(e, wallet.adapter.name)}\n className=\"flex w-full items-center justify-between rounded-lg p-3 text-left transition-colors hover:bg-secondary\"\n >\n
\n {\n e.currentTarget.src = \"/placeholder.jpg\"\n }}\n />\n {wallet.adapter.name}\n
\n \n {wallet.readyState === WalletReadyState.Installed\n ? \"Installed\"\n : \"Not Installed\"}\n \n \n ))}\n\n {collapsedWallets.length > 0 && (\n \n \n \n \n \n {collapsedWallets.map((wallet) => (\n handleWalletClick(e, wallet.adapter.name)}\n className=\"flex w-full items-center justify-between rounded-lg p-3 text-left transition-colors hover:bg-secondary\"\n >\n
\n {\n e.currentTarget.src = \"/placeholder.jpg\"\n }}\n />\n \n {wallet.adapter.name}\n \n
\n \n {wallet.readyState === WalletReadyState.Installed\n ? \"Installed\"\n : \"Not Installed\"}\n \n \n ))}\n
\n
\n )}\n
\n
\n\n \n
\n {!isLazorKitConnected ? (\n \n {isLoadingLazorKit || isInitializing ? (\n <>\n \n {LABELS[\"connecting\"]}\n \n ) : isCreatingPasskey ? (\n <>\n \n {LABELS[\"creating-passkey\"]}\n \n ) : isCreatingSmartWallet ? (\n <>\n \n {LABELS[\"creating-smart-wallet\"]}\n \n ) : (\n <>\n \"LazorKit {\n e.currentTarget.src = \"/placeholder.jpg\"\n }}\n />\n {LABELS[\"lazorkit-wallet\"]}\n \n )}\n \n ) : (\n
\n
\n
\n \"LazorKit {\n e.currentTarget.src = \"/brand-logos/passkey-logo.svg\"\n }}\n />\n \n {smartWalletPubkey?.toString().slice(0, 8)}...{smartWalletPubkey?.toString().slice(-8)}\n \n
\n {\n disconnectLazorKit()\n window.localStorage.removeItem('SMART_WALLET_ADDRESS')\n setWalletType('standard')\n }}\n >\n {LABELS[\"disconnect\"]}\n \n
\n
\n )}\n
\n
\n
\n\n \n \n \n
\n
\n )\n}\n\n// Wallet Multi Button Component\nexport function BaseWalletMultiButton({ children, labels = LABELS, ...props }: Props) {\n const [walletModalOpen, setWalletModalOpen] = useState(false)\n const [copied, setCopied] = useState(false)\n const [menuOpen, setMenuOpen] = useState(false)\n const [mounted, setMounted] = useState(false)\n\n const { buttonState, onConnect, onDisconnect, publicKey, walletIcon, walletName } = useWalletMultiButton({\n onSelectWallet() {\n setWalletModalOpen(true)\n },\n })\n \n const { \n disconnect: disconnectLazorKit, \n isLoading: isLoadingLazorKit, \n isConnected: isLazorKitConnected,\n smartWalletPubkey \n } = useLazorKitWalletContext()\n \n const modalContext = React.useContext(ModalContext)\n const { walletType, setWalletType } = modalContext || { walletType: 'standard', setWalletType: () => {} }\n\n const isAnyWalletConnected = useMemo(() => {\n if (walletType === 'standard') {\n return !!publicKey\n } else {\n return isLazorKitConnected && !!smartWalletPubkey\n }\n }, [publicKey, isLazorKitConnected, walletType, smartWalletPubkey])\n\n const currentWalletAddress = useMemo(() => {\n if (walletType === 'lazorkit' && smartWalletPubkey) {\n // For LazorKit, the address is already in the correct format\n return smartWalletPubkey.toString();\n } else if (walletType === 'standard' && publicKey) {\n return publicKey.toBase58();\n }\n return null;\n }, [walletType, smartWalletPubkey, publicKey]);\n\n const content = useMemo(() => {\n if (!mounted) return labels[\"no-wallet\"];\n\n if (children) {\n return children;\n } else if (isLoadingLazorKit) {\n return (\n
\n
\n {labels[\"connecting\"]}\n
\n );\n }\n\n // Add wallet icon and address when connected\n if (isAnyWalletConnected && currentWalletAddress) {\n return (\n
\n {walletType === 'lazorkit' ? (\n \"LazorKit {\n e.currentTarget.src = \"/placeholder.jpg\"\n }}\n />\n ) : walletIcon ? (\n {\n e.currentTarget.src = \"/placeholder.jpg\"\n }}\n />\n ) : null}\n \n {`${currentWalletAddress.slice(0, 6)}...${currentWalletAddress.slice(-4)}`}\n \n
\n );\n }\n \n return labels[\"has-wallet\"];\n }, [mounted, children, isLoadingLazorKit, isAnyWalletConnected, walletType, walletIcon, walletName, currentWalletAddress, labels]);\n\n const handleDisconnect = useCallback(() => {\n if (walletType === 'lazorkit') {\n disconnectLazorKit()\n window.localStorage.removeItem('SMART_WALLET_ADDRESS')\n setWalletType('standard')\n } else if (onDisconnect) {\n onDisconnect()\n }\n setMenuOpen(false)\n }, [walletType, disconnectLazorKit, onDisconnect, setWalletType])\n\n const handleCopyAddress = useCallback(async () => {\n if (currentWalletAddress) {\n await navigator.clipboard.writeText(currentWalletAddress)\n setCopied(true)\n setTimeout(() => setCopied(false), 400)\n }\n }, [currentWalletAddress])\n\n useEffect(() => {\n setMounted(true)\n }, [])\n\n if (!isAnyWalletConnected) {\n return (\n <>\n \n {\n if (buttonState === \"has-wallet\" && onConnect) {\n onConnect()\n } else {\n setWalletModalOpen(true)\n }\n }}\n >\n {content}\n \n \n )\n }\n\n return (\n <>\n \n \n \n \n \n \n {currentWalletAddress && (\n \n {copied ? labels[\"copied\"] : labels[\"copy-address\"]}\n \n )}\n {\n setWalletModalOpen(true)\n setMenuOpen(false)\n }}\n >\n {labels[\"change-wallet\"]}\n \n \n {labels[\"disconnect\"]}\n \n \n \n \n )\n}\n\n// Public Exported Button\nexport function ConnectWalletButton(props: WalletButtonProps) {\n return \n}", + "content": "\"use client\"\r\n\r\nimport React, { type FC, useCallback, useEffect, useMemo, useState } from \"react\"\r\nimport { useWallet } from \"@solana/wallet-adapter-react\"\r\nimport { WalletName, WalletReadyState } from \"@solana/wallet-adapter-base\"\r\nimport { useWalletMultiButton } from \"@/hook/murphy/use-walletMultiButton\"\r\nimport { Button } from \"../button\"\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\"\r\nimport { useLazorKitWalletContext } from \"@/components/providers/lazorkit-wallet-context\"\r\nimport { PublicKey } from \"@solana/web3.js\"\r\n\r\nimport { Dialog, DialogClose, DialogContent, DialogHeader, DialogTitle, DialogDescription } from \"../dialog\"\r\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"../collapsible\"\r\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from \"../dropdown-menu\"\r\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"../tabs\"\r\nimport { Badge } from \"../badge\"\r\nimport { Loader2, Key, ChevronDown } from \"lucide-react\"\r\n\r\n// Constants\r\nconst LABELS = {\r\n \"change-wallet\": \"Change Wallet\",\r\n connecting: \"Connecting...\",\r\n \"copy-address\": \"Copy Address\",\r\n copied: \"Copied\",\r\n disconnect: \"Disconnect\",\r\n \"has-wallet\": \"Connect Wallet\",\r\n \"no-wallet\": \"Select Wallet\",\r\n \"lazorkit-wallet\": \"Connect Passkey\",\r\n \"standard-wallet\": \"Standard Wallet\",\r\n \"connection-error\": \"Connection Error\",\r\n \"retry-connection\": \"Retry Connection\",\r\n \"initializing\": \"Initializing Smart Wallet...\",\r\n \"initialization-error\": \"Failed to initialize wallet\",\r\n \"creating-passkey\": \"Creating Passkey...\",\r\n \"creating-smart-wallet\": \"Creating Smart Wallet...\",\r\n} as const\r\n\r\n// Types\r\ntype WalletButtonProps = React.ComponentProps<\"button\"> & {\r\n labels?: Partial\r\n asChild?: boolean\r\n variant?: \"default\" | \"destructive\" | \"outline\" | \"secondary\" | \"ghost\" | \"link\"\r\n size?: \"default\" | \"sm\" | \"lg\" | \"icon\"\r\n}\r\n\r\ntype Props = WalletButtonProps\r\n\r\nexport interface WalletListItemProps {\r\n handleClick: React.MouseEventHandler\r\n tabIndex?: number\r\n wallet: {\r\n adapter: {\r\n name: string\r\n icon?: string\r\n }\r\n readyState: WalletReadyState\r\n }\r\n}\r\n\r\n// Wallet List Item Component\r\nexport const WalletListItem: FC = ({ handleClick, tabIndex, wallet }) => {\r\n const isInstalled = wallet.readyState === WalletReadyState.Installed\r\n \r\n return (\r\n \r\n )\r\n}\r\n\r\n// Enhanced Wallet Modal Component\r\nexport const EnhancedWalletModal: FC<{\r\n open: boolean\r\n onOpenChange: (open: boolean) => void\r\n}> = ({ open, onOpenChange }) => {\r\n const { wallets, select } = useWallet()\r\n const [expanded, setExpanded] = useState(false)\r\n const [activeTab, setActiveTab] = useState<'standard' | 'lazorkit'>('standard')\r\n const [isInitializing, setIsInitializing] = useState(false)\r\n const [isCreatingPasskey, setIsCreatingPasskey] = useState(false)\r\n const [isCreatingSmartWallet, setIsCreatingSmartWallet] = useState(false)\r\n \r\n const { \r\n connect: connectLazorKit,\r\n createPasskeyOnly,\r\n createSmartWalletOnly,\r\n disconnect: disconnectLazorKit, \r\n isLoading: isLoadingLazorKit, \r\n isConnected: isLazorKitConnected,\r\n smartWalletPubkey,\r\n error: lazorKitError,\r\n clearError\r\n } = useLazorKitWalletContext()\r\n\r\n const modalContext = React.useContext(ModalContext)\r\n const isMainnet = modalContext?.isMainnet ?? false\r\n const { walletType, setWalletType } = modalContext || { walletType: 'standard', setWalletType: () => {} }\r\n\r\n // Memoize wallet lists\r\n const { listedWallets, collapsedWallets } = useMemo(() => {\r\n const installed = wallets.filter((w) => w.readyState === WalletReadyState.Installed)\r\n const notInstalled = wallets.filter((w) => w.readyState !== WalletReadyState.Installed)\r\n return {\r\n listedWallets: installed.length ? installed : notInstalled,\r\n collapsedWallets: installed.length ? notInstalled : []\r\n }\r\n }, [wallets])\r\n\r\n const handleWalletClick = useCallback(\r\n async (event: React.MouseEvent, walletName: string) => {\r\n event.preventDefault()\r\n try {\r\n await select(walletName as WalletName)\r\n setWalletType('standard')\r\n onOpenChange(false)\r\n } catch (error) {\r\n console.error('Failed to select wallet:', error)\r\n }\r\n },\r\n [select, onOpenChange, setWalletType],\r\n )\r\n\r\n const handleLazorKitConnect = useCallback(async () => {\r\n try {\r\n clearError()\r\n setIsInitializing(false)\r\n setIsCreatingPasskey(false)\r\n setIsCreatingSmartWallet(false)\r\n console.log(\"Starting LazorKit connection...\")\r\n \r\n try {\r\n // First try normal connection\r\n const account = await connectLazorKit()\r\n console.log(\"LazorKit connected, account:\", account)\r\n \r\n if (!account || !account.publicKey) {\r\n throw new Error(\"Failed to get wallet account\")\r\n }\r\n\r\n const walletAddress = account.publicKey.toString()\r\n console.log('Connected with address:', walletAddress)\r\n \r\n window.localStorage.setItem('SMART_WALLET_ADDRESS', walletAddress)\r\n setWalletType('lazorkit')\r\n onOpenChange(false)\r\n } catch (error) {\r\n // If normal connection fails, try step-by-step creation\r\n if (error instanceof Error && \r\n (error.message.includes('Account does not exist') || \r\n error.message.includes('needs to be initialized'))) {\r\n try {\r\n // Step 1: Create passkey\r\n setIsCreatingPasskey(true)\r\n const passkeyData = await createPasskeyOnly()\r\n console.log(\"Passkey created:\", passkeyData)\r\n \r\n // Step 2: Create smart wallet\r\n setIsCreatingPasskey(false)\r\n setIsCreatingSmartWallet(true)\r\n const { smartWalletAddress, account } = await createSmartWalletOnly(passkeyData)\r\n console.log(\"Smart wallet created:\", smartWalletAddress)\r\n\r\n if (!account || !account.publicKey) {\r\n throw new Error(\"Failed to initialize wallet\")\r\n }\r\n\r\n window.localStorage.setItem('SMART_WALLET_ADDRESS', smartWalletAddress)\r\n setWalletType('lazorkit')\r\n onOpenChange(false)\r\n } catch (createError) {\r\n console.error(\"Failed to create wallet:\", createError)\r\n throw createError\r\n }\r\n } else {\r\n throw error\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\"LazorKit connection error:\", error)\r\n setIsInitializing(false)\r\n setIsCreatingPasskey(false)\r\n setIsCreatingSmartWallet(false)\r\n }\r\n }, [connectLazorKit, createPasskeyOnly, createSmartWalletOnly, setWalletType, onOpenChange, clearError])\r\n\r\n // Effect to handle successful connection\r\n useEffect(() => {\r\n if (isLazorKitConnected && smartWalletPubkey) {\r\n const walletAddress = smartWalletPubkey.toString()\r\n window.localStorage.setItem('SMART_WALLET_ADDRESS', walletAddress)\r\n setWalletType('lazorkit')\r\n onOpenChange(false)\r\n }\r\n }, [isLazorKitConnected, smartWalletPubkey, setWalletType, onOpenChange])\r\n\r\n // Effect to sync active tab with wallet type\r\n useEffect(() => {\r\n setActiveTab(walletType)\r\n }, [walletType])\r\n\r\n return (\r\n \r\n \r\n \r\n Connect wallet to continue\r\n \r\n Choose your preferred wallet to connect to this dApp.\r\n \r\n
\r\n
\r\n Note: LazorKit is currently in beta and only supports Devnet\r\n
\r\n
\r\n Network Status:\r\n \r\n {activeTab === 'lazorkit' ? 'Devnet' : (isMainnet ? 'Mainnet' : 'Devnet')}\r\n \r\n
\r\n
\r\n
\r\n\r\n setActiveTab(value as 'standard' | 'lazorkit')}>\r\n \r\n \r\n {LABELS[\"standard-wallet\"]}\r\n \r\n \r\n {LABELS[\"lazorkit-wallet\"]}\r\n \r\n \r\n\r\n \r\n
\r\n {/* Standard wallet list */}\r\n {listedWallets.map((wallet) => (\r\n handleWalletClick(e, wallet.adapter.name)}\r\n className=\"flex w-full items-center justify-between rounded-lg p-3 text-left transition-colors hover:bg-secondary\"\r\n >\r\n
\r\n {\r\n e.currentTarget.src = \"/placeholder.jpg\"\r\n }}\r\n />\r\n {wallet.adapter.name}\r\n
\r\n \r\n {wallet.readyState === WalletReadyState.Installed\r\n ? \"Installed\"\r\n : \"Not Installed\"}\r\n \r\n \r\n ))}\r\n\r\n {collapsedWallets.length > 0 && (\r\n \r\n \r\n \r\n \r\n \r\n {collapsedWallets.map((wallet) => (\r\n handleWalletClick(e, wallet.adapter.name)}\r\n className=\"flex w-full items-center justify-between rounded-lg p-3 text-left transition-colors hover:bg-secondary\"\r\n >\r\n
\r\n {\r\n e.currentTarget.src = \"/placeholder.jpg\"\r\n }}\r\n />\r\n \r\n {wallet.adapter.name}\r\n \r\n
\r\n \r\n {wallet.readyState === WalletReadyState.Installed\r\n ? \"Installed\"\r\n : \"Not Installed\"}\r\n \r\n \r\n ))}\r\n
\r\n
\r\n )}\r\n
\r\n
\r\n\r\n \r\n
\r\n {!isLazorKitConnected ? (\r\n \r\n {isLoadingLazorKit || isInitializing ? (\r\n <>\r\n \r\n {LABELS[\"connecting\"]}\r\n \r\n ) : isCreatingPasskey ? (\r\n <>\r\n \r\n {LABELS[\"creating-passkey\"]}\r\n \r\n ) : isCreatingSmartWallet ? (\r\n <>\r\n \r\n {LABELS[\"creating-smart-wallet\"]}\r\n \r\n ) : (\r\n <>\r\n \"LazorKit {\r\n e.currentTarget.src = \"/placeholder.jpg\"\r\n }}\r\n />\r\n {LABELS[\"lazorkit-wallet\"]}\r\n \r\n )}\r\n \r\n ) : (\r\n
\r\n
\r\n
\r\n \"LazorKit {\r\n e.currentTarget.src = \"/brand-logos/passkey-logo.svg\"\r\n }}\r\n />\r\n \r\n {smartWalletPubkey?.toString().slice(0, 8)}...{smartWalletPubkey?.toString().slice(-8)}\r\n \r\n
\r\n {\r\n disconnectLazorKit()\r\n window.localStorage.removeItem('SMART_WALLET_ADDRESS')\r\n setWalletType('standard')\r\n }}\r\n >\r\n {LABELS[\"disconnect\"]}\r\n \r\n
\r\n
\r\n )}\r\n
\r\n
\r\n
\r\n\r\n \r\n \r\n \r\n
\r\n
\r\n )\r\n}\r\n\r\n// Wallet Multi Button Component\r\nexport function BaseWalletMultiButton({ children, labels = LABELS, ...props }: Props) {\r\n const [walletModalOpen, setWalletModalOpen] = useState(false)\r\n const [copied, setCopied] = useState(false)\r\n const [menuOpen, setMenuOpen] = useState(false)\r\n const [mounted, setMounted] = useState(false)\r\n\r\n const { buttonState, onConnect, onDisconnect, publicKey, walletIcon, walletName } = useWalletMultiButton({\r\n onSelectWallet() {\r\n setWalletModalOpen(true)\r\n },\r\n })\r\n \r\n const { \r\n disconnect: disconnectLazorKit, \r\n isLoading: isLoadingLazorKit, \r\n isConnected: isLazorKitConnected,\r\n smartWalletPubkey \r\n } = useLazorKitWalletContext()\r\n \r\n const modalContext = React.useContext(ModalContext)\r\n const { walletType, setWalletType } = modalContext || { walletType: 'standard', setWalletType: () => {} }\r\n\r\n const isAnyWalletConnected = useMemo(() => {\r\n if (walletType === 'standard') {\r\n return !!publicKey\r\n } else {\r\n return isLazorKitConnected && !!smartWalletPubkey\r\n }\r\n }, [publicKey, isLazorKitConnected, walletType, smartWalletPubkey])\r\n\r\n const currentWalletAddress = useMemo(() => {\r\n if (walletType === 'lazorkit' && smartWalletPubkey) {\r\n // For LazorKit, the address is already in the correct format\r\n return smartWalletPubkey.toString();\r\n } else if (walletType === 'standard' && publicKey) {\r\n return publicKey.toBase58();\r\n }\r\n return null;\r\n }, [walletType, smartWalletPubkey, publicKey]);\r\n\r\n const content = useMemo(() => {\r\n if (!mounted) return labels[\"no-wallet\"];\r\n\r\n if (children) {\r\n return children;\r\n } else if (isLoadingLazorKit) {\r\n return (\r\n
\r\n
\r\n {labels[\"connecting\"]}\r\n
\r\n );\r\n }\r\n\r\n // Add wallet icon and address when connected\r\n if (isAnyWalletConnected && currentWalletAddress) {\r\n return (\r\n
\r\n {walletType === 'lazorkit' ? (\r\n \"LazorKit {\r\n e.currentTarget.src = \"/placeholder.jpg\"\r\n }}\r\n />\r\n ) : walletIcon ? (\r\n {\r\n e.currentTarget.src = \"/placeholder.jpg\"\r\n }}\r\n />\r\n ) : null}\r\n \r\n {`${currentWalletAddress.slice(0, 6)}...${currentWalletAddress.slice(-4)}`}\r\n \r\n
\r\n );\r\n }\r\n \r\n return labels[\"has-wallet\"];\r\n }, [mounted, children, isLoadingLazorKit, isAnyWalletConnected, walletType, walletIcon, walletName, currentWalletAddress, labels]);\r\n\r\n const handleDisconnect = useCallback(() => {\r\n if (walletType === 'lazorkit') {\r\n disconnectLazorKit()\r\n window.localStorage.removeItem('SMART_WALLET_ADDRESS')\r\n setWalletType('standard')\r\n } else if (onDisconnect) {\r\n onDisconnect()\r\n }\r\n setMenuOpen(false)\r\n }, [walletType, disconnectLazorKit, onDisconnect, setWalletType])\r\n\r\n const handleCopyAddress = useCallback(async () => {\r\n if (currentWalletAddress) {\r\n await navigator.clipboard.writeText(currentWalletAddress)\r\n setCopied(true)\r\n setTimeout(() => setCopied(false), 400)\r\n }\r\n }, [currentWalletAddress])\r\n\r\n useEffect(() => {\r\n setMounted(true)\r\n }, [])\r\n\r\n if (!isAnyWalletConnected) {\r\n return (\r\n <>\r\n \r\n {\r\n if (buttonState === \"has-wallet\" && onConnect) {\r\n onConnect()\r\n } else {\r\n setWalletModalOpen(true)\r\n }\r\n }}\r\n >\r\n {content}\r\n \r\n \r\n )\r\n }\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n {currentWalletAddress && (\r\n \r\n {copied ? labels[\"copied\"] : labels[\"copy-address\"]}\r\n \r\n )}\r\n {\r\n setWalletModalOpen(true)\r\n setMenuOpen(false)\r\n }}\r\n >\r\n {labels[\"change-wallet\"]}\r\n \r\n \r\n {labels[\"disconnect\"]}\r\n \r\n \r\n \r\n \r\n )\r\n}\r\n\r\n// Public Exported Button\r\nexport function ConnectWalletButton(props: WalletButtonProps) {\r\n return \r\n}", "type": "registry:component", "target": "components/ui/murphy/connect-wallet-button.tsx" }, { "path": "components/providers/wallet-provider.tsx", - "content": "\"use client\"\n\nimport React, { useState, useMemo, createContext, useCallback, useEffect } from \"react\"\nimport { WalletAdapterNetwork } from \"@solana/wallet-adapter-base\"\nimport type { Adapter } from \"@solana/wallet-adapter-base\"\nimport {\n WalletProvider as SolanaWalletProvider,\n ConnectionProvider as SolanaConnectionProvider,\n ConnectionProviderProps,\n} from \"@solana/wallet-adapter-react\"\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\"\nimport { PhantomWalletAdapter } from \"@solana/wallet-adapter-wallets\"\nimport { TxnSettingsProvider } from \"@/components/ui/murphy/txn-settings\"\nimport { ClientLazorKitProvider } from \"./client-lazorkit-provider\"\nimport { LazorKitWalletProvider } from \"./lazorkit-wallet-context\"\n\nimport \"@solana/wallet-adapter-react-ui/styles.css\"\n\n// Constants\nconst DEFAULT_MAINNET_RPC = process.env.NEXT_PUBLIC_SOLANA_RPC_URL || \"https://api.mainnet-beta.solana.com\"\nconst DEFAULT_DEVNET_RPC = process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET || \"https://api.devnet.solana.com\"\n\n// Create wrapper components\nconst ConnectionProviderWrapper = (props: ConnectionProviderProps) => (\n \n)\n\nconst WalletProviderWrapper = (props: any) => (\n \n)\n\ninterface WalletProviderProps {\n children: React.ReactNode\n network?: WalletAdapterNetwork\n endpoint?: string\n wallets?: Adapter[]\n autoConnect?: boolean\n}\n\ninterface ModalContextState {\n isOpen: boolean\n setIsOpen: (open: boolean) => void\n endpoint?: string\n switchToNextEndpoint: () => void\n availableEndpoints: string[]\n currentEndpointIndex: number\n isMainnet: boolean\n walletType: 'standard' | 'lazorkit'\n setWalletType: (type: 'standard' | 'lazorkit') => void\n networkType: WalletAdapterNetwork\n}\n\nexport const ModalContext = createContext({\n isOpen: false,\n setIsOpen: () => null,\n endpoint: undefined,\n switchToNextEndpoint: () => null,\n availableEndpoints: [],\n currentEndpointIndex: 0,\n isMainnet: true, // Changed default to true for mainnet\n walletType: 'standard',\n setWalletType: () => null,\n networkType: WalletAdapterNetwork.Mainnet, // Changed default to Mainnet\n})\n\nexport const WalletProvider = ({ children, ...props }: WalletProviderProps) => {\n const [currentEndpointIndex, setCurrentEndpointIndex] = useState(0)\n const [isOpen, setIsOpen] = useState(false)\n const [walletType, setWalletType] = useState<'standard' | 'lazorkit'>(() => {\n if (typeof window !== 'undefined') {\n const savedType = localStorage.getItem('walletType')\n return (savedType as 'standard' | 'lazorkit') || 'standard'\n }\n return 'standard'\n })\n\n // Network detection - only force devnet for LazorKit operations\n const isMainnet = useMemo(() => {\n const mainnetEnv = process.env.NEXT_PUBLIC_USE_MAINNET\n return mainnetEnv === undefined ? true : mainnetEnv === \"true\" // Default to mainnet\n }, [])\n\n const networkType = useMemo(\n () => walletType === 'lazorkit' ? WalletAdapterNetwork.Devnet : (isMainnet ? WalletAdapterNetwork.Mainnet : WalletAdapterNetwork.Devnet),\n [isMainnet, walletType]\n )\n\n // RPC endpoints management - use devnet RPC for LazorKit, otherwise use configured endpoint\n const publicRPCs = useMemo(\n () => [walletType === 'lazorkit' ? DEFAULT_DEVNET_RPC : (isMainnet ? DEFAULT_MAINNET_RPC : DEFAULT_DEVNET_RPC)],\n [isMainnet, walletType]\n )\n\n const endpoint = useMemo(() => {\n if (props.endpoint) {\n return props.endpoint\n }\n return publicRPCs[currentEndpointIndex]\n }, [props.endpoint, publicRPCs, currentEndpointIndex])\n\n // Endpoint switching with error handling\n const switchToNextEndpoint = useCallback(() => {\n setCurrentEndpointIndex((prevIndex) => {\n const nextIndex = (prevIndex + 1) % publicRPCs.length\n console.log(\n `Switching RPC endpoint from ${publicRPCs[prevIndex]} to ${publicRPCs[nextIndex]}`\n )\n return nextIndex\n })\n }, [publicRPCs])\n\n // Wallet adapters\n const wallets = useMemo(\n () => props.wallets || [new PhantomWalletAdapter()],\n [props.wallets]\n )\n\n // Persist wallet type\n useEffect(() => {\n if (typeof window !== 'undefined') {\n localStorage.setItem('walletType', walletType)\n }\n }, [walletType])\n\n // Auto-connect effect\n useEffect(() => {\n if (props.autoConnect && walletType === 'lazorkit') {\n // Attempt to reconnect LazorKit wallet on mount\n const reconnectLazorKit = async () => {\n try {\n // The actual reconnection will be handled by the LazorKitWalletProvider\n console.log('Attempting to reconnect LazorKit wallet...')\n } catch (error) {\n console.error('Failed to reconnect LazorKit wallet:', error)\n }\n }\n reconnectLazorKit()\n }\n }, [props.autoConnect, walletType])\n\n // Effect to handle network switching for LazorKit\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const cluster = walletType === 'lazorkit' ? \"devnet\" : (isMainnet ? \"mainnet\" : \"devnet\")\n window.localStorage.setItem(\"NEXT_PUBLIC_CLUSTER\", cluster)\n ;(window as any).NEXT_PUBLIC_CLUSTER = cluster\n window.dispatchEvent(new CustomEvent(\"clusterChanged\", { detail: { cluster } }))\n }\n }, [walletType, isMainnet])\n\n // Context value memoization\n const contextValue = useMemo(() => ({\n isOpen,\n setIsOpen,\n endpoint,\n switchToNextEndpoint,\n availableEndpoints: publicRPCs,\n currentEndpointIndex,\n isMainnet,\n walletType,\n setWalletType,\n networkType,\n }), [\n isOpen,\n endpoint,\n switchToNextEndpoint,\n publicRPCs,\n currentEndpointIndex,\n isMainnet,\n walletType,\n networkType,\n ])\n\n return (\n \n \n {\n console.error('Wallet error:', error)\n // Attempt to switch endpoint on connection errors\n if (error.message.includes('connection') || error.message.includes('network')) {\n switchToNextEndpoint()\n }\n }}\n >\n \n \n \n {children}\n \n \n \n \n \n \n )\n}\n", + "content": "\"use client\"\r\n\r\nimport React, { useState, useMemo, createContext, useCallback, useEffect } from \"react\"\r\nimport { WalletAdapterNetwork } from \"@solana/wallet-adapter-base\"\r\nimport type { Adapter } from \"@solana/wallet-adapter-base\"\r\nimport {\r\n WalletProvider as SolanaWalletProvider,\r\n ConnectionProvider as SolanaConnectionProvider,\r\n ConnectionProviderProps,\r\n} from \"@solana/wallet-adapter-react\"\r\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\"\r\nimport { PhantomWalletAdapter } from \"@solana/wallet-adapter-wallets\"\r\nimport { TxnSettingsProvider } from \"@/components/ui/murphy/txn-settings\"\r\nimport { ClientLazorKitProvider } from \"./client-lazorkit-provider\"\r\nimport { LazorKitWalletProvider } from \"./lazorkit-wallet-context\"\r\n\r\nimport \"@solana/wallet-adapter-react-ui/styles.css\"\r\n\r\n// Constants\r\nconst DEFAULT_MAINNET_RPC = process.env.NEXT_PUBLIC_SOLANA_RPC_URL || \"https://api.mainnet-beta.solana.com\"\r\nconst DEFAULT_DEVNET_RPC = process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET || \"https://api.devnet.solana.com\"\r\n\r\n// Create wrapper components\r\nconst ConnectionProviderWrapper = (props: ConnectionProviderProps) => (\r\n \r\n)\r\n\r\nconst WalletProviderWrapper = (props: any) => (\r\n \r\n)\r\n\r\ninterface WalletProviderProps {\r\n children: React.ReactNode\r\n network?: WalletAdapterNetwork\r\n endpoint?: string\r\n wallets?: Adapter[]\r\n autoConnect?: boolean\r\n}\r\n\r\ninterface ModalContextState {\r\n isOpen: boolean\r\n setIsOpen: (open: boolean) => void\r\n endpoint?: string\r\n switchToNextEndpoint: () => void\r\n availableEndpoints: string[]\r\n currentEndpointIndex: number\r\n isMainnet: boolean\r\n walletType: 'standard' | 'lazorkit'\r\n setWalletType: (type: 'standard' | 'lazorkit') => void\r\n networkType: WalletAdapterNetwork\r\n}\r\n\r\nexport const ModalContext = createContext({\r\n isOpen: false,\r\n setIsOpen: () => null,\r\n endpoint: undefined,\r\n switchToNextEndpoint: () => null,\r\n availableEndpoints: [],\r\n currentEndpointIndex: 0,\r\n isMainnet: true, // Changed default to true for mainnet\r\n walletType: 'standard',\r\n setWalletType: () => null,\r\n networkType: WalletAdapterNetwork.Mainnet, // Changed default to Mainnet\r\n})\r\n\r\nexport const WalletProvider = ({ children, ...props }: WalletProviderProps) => {\r\n const [currentEndpointIndex, setCurrentEndpointIndex] = useState(0)\r\n const [isOpen, setIsOpen] = useState(false)\r\n const [walletType, setWalletType] = useState<'standard' | 'lazorkit'>(() => {\r\n if (typeof window !== 'undefined') {\r\n const savedType = localStorage.getItem('walletType')\r\n return (savedType as 'standard' | 'lazorkit') || 'standard'\r\n }\r\n return 'standard'\r\n })\r\n\r\n // Network detection - only force devnet for LazorKit operations\r\n const isMainnet = useMemo(() => {\r\n const mainnetEnv = process.env.NEXT_PUBLIC_USE_MAINNET\r\n return mainnetEnv === undefined ? true : mainnetEnv === \"true\" // Default to mainnet\r\n }, [])\r\n\r\n const networkType = useMemo(\r\n () => walletType === 'lazorkit' ? WalletAdapterNetwork.Devnet : (isMainnet ? WalletAdapterNetwork.Mainnet : WalletAdapterNetwork.Devnet),\r\n [isMainnet, walletType]\r\n )\r\n\r\n // RPC endpoints management - use devnet RPC for LazorKit, otherwise use configured endpoint\r\n const publicRPCs = useMemo(\r\n () => [walletType === 'lazorkit' ? DEFAULT_DEVNET_RPC : (isMainnet ? DEFAULT_MAINNET_RPC : DEFAULT_DEVNET_RPC)],\r\n [isMainnet, walletType]\r\n )\r\n\r\n const endpoint = useMemo(() => {\r\n if (props.endpoint) {\r\n return props.endpoint\r\n }\r\n return publicRPCs[currentEndpointIndex]\r\n }, [props.endpoint, publicRPCs, currentEndpointIndex])\r\n\r\n // Endpoint switching with error handling\r\n const switchToNextEndpoint = useCallback(() => {\r\n setCurrentEndpointIndex((prevIndex) => {\r\n const nextIndex = (prevIndex + 1) % publicRPCs.length\r\n console.log(\r\n `Switching RPC endpoint from ${publicRPCs[prevIndex]} to ${publicRPCs[nextIndex]}`\r\n )\r\n return nextIndex\r\n })\r\n }, [publicRPCs])\r\n\r\n // Wallet adapters\r\n const wallets = useMemo(\r\n () => props.wallets || [new PhantomWalletAdapter()],\r\n [props.wallets]\r\n )\r\n\r\n // Persist wallet type\r\n useEffect(() => {\r\n if (typeof window !== 'undefined') {\r\n localStorage.setItem('walletType', walletType)\r\n }\r\n }, [walletType])\r\n\r\n // Auto-connect effect\r\n useEffect(() => {\r\n if (props.autoConnect && walletType === 'lazorkit') {\r\n // Attempt to reconnect LazorKit wallet on mount\r\n const reconnectLazorKit = async () => {\r\n try {\r\n // The actual reconnection will be handled by the LazorKitWalletProvider\r\n console.log('Attempting to reconnect LazorKit wallet...')\r\n } catch (error) {\r\n console.error('Failed to reconnect LazorKit wallet:', error)\r\n }\r\n }\r\n reconnectLazorKit()\r\n }\r\n }, [props.autoConnect, walletType])\r\n\r\n // Effect to handle network switching for LazorKit\r\n useEffect(() => {\r\n if (typeof window !== 'undefined') {\r\n const cluster = walletType === 'lazorkit' ? \"devnet\" : (isMainnet ? \"mainnet\" : \"devnet\")\r\n window.localStorage.setItem(\"NEXT_PUBLIC_CLUSTER\", cluster)\r\n ;(window as any).NEXT_PUBLIC_CLUSTER = cluster\r\n window.dispatchEvent(new CustomEvent(\"clusterChanged\", { detail: { cluster } }))\r\n }\r\n }, [walletType, isMainnet])\r\n\r\n // Context value memoization\r\n const contextValue = useMemo(() => ({\r\n isOpen,\r\n setIsOpen,\r\n endpoint,\r\n switchToNextEndpoint,\r\n availableEndpoints: publicRPCs,\r\n currentEndpointIndex,\r\n isMainnet,\r\n walletType,\r\n setWalletType,\r\n networkType,\r\n }), [\r\n isOpen,\r\n endpoint,\r\n switchToNextEndpoint,\r\n publicRPCs,\r\n currentEndpointIndex,\r\n isMainnet,\r\n walletType,\r\n networkType,\r\n ])\r\n\r\n return (\r\n \r\n \r\n {\r\n console.error('Wallet error:', error)\r\n // Attempt to switch endpoint on connection errors\r\n if (error.message.includes('connection') || error.message.includes('network')) {\r\n switchToNextEndpoint()\r\n }\r\n }}\r\n >\r\n \r\n \r\n \r\n {children}\r\n \r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n", "type": "registry:component", "target": "components/providers/wallet-provider.tsx" }, { "path": "hook/murphy/use-walletMultiButton.ts", - "content": "import { useWallet, type Wallet } from '@solana/wallet-adapter-react';\nimport type { PublicKey } from '@solana/web3.js';\nimport { useCallback } from 'react';\n\ntype ButtonState = {\n buttonState: 'connecting' | 'connected' | 'disconnecting' | 'has-wallet' | 'no-wallet';\n onConnect?: () => void;\n onDisconnect?: () => void;\n onSelectWallet?: () => void;\n publicKey?: PublicKey;\n walletIcon?: Wallet['adapter']['icon'];\n walletName?: Wallet['adapter']['name'];\n};\n\ntype Config = {\n onSelectWallet: (config: {\n onSelectWallet: (walletName: Wallet['adapter']['name']) => void;\n wallets: Wallet[];\n }) => void;\n};\n\nexport function useWalletMultiButton({ onSelectWallet }: Config): ButtonState {\n const { connect, connected, connecting, disconnect, disconnecting, publicKey, select, wallet, wallets } =\n useWallet();\n let buttonState: ButtonState['buttonState'];\n if (connecting) {\n buttonState = 'connecting';\n } else if (connected) {\n buttonState = 'connected';\n } else if (disconnecting) {\n buttonState = 'disconnecting';\n } else if (wallet) {\n buttonState = 'has-wallet';\n } else {\n buttonState = 'no-wallet';\n }\n const handleConnect = useCallback(() => {\n connect().catch(() => {\n });\n }, [connect]);\n const handleDisconnect = useCallback(() => {\n disconnect().catch(() => {\n });\n }, [disconnect]);\n const handleSelectWallet = useCallback(() => {\n onSelectWallet({ onSelectWallet: select, wallets });\n }, [onSelectWallet, select, wallets]);\n return {\n buttonState,\n onConnect: buttonState === 'has-wallet' ? handleConnect : undefined,\n onDisconnect: buttonState !== 'disconnecting' && buttonState !== 'no-wallet' ? handleDisconnect : undefined,\n onSelectWallet: handleSelectWallet,\n publicKey: publicKey ?? undefined,\n walletIcon: wallet?.adapter.icon,\n walletName: wallet?.adapter.name,\n };\n}\n", + "content": "import { useWallet, type Wallet } from '@solana/wallet-adapter-react';\r\nimport type { PublicKey } from '@solana/web3.js';\r\nimport { useCallback } from 'react';\r\n\r\ntype ButtonState = {\r\n buttonState: 'connecting' | 'connected' | 'disconnecting' | 'has-wallet' | 'no-wallet';\r\n onConnect?: () => void;\r\n onDisconnect?: () => void;\r\n onSelectWallet?: () => void;\r\n publicKey?: PublicKey;\r\n walletIcon?: Wallet['adapter']['icon'];\r\n walletName?: Wallet['adapter']['name'];\r\n};\r\n\r\ntype Config = {\r\n onSelectWallet: (config: {\r\n onSelectWallet: (walletName: Wallet['adapter']['name']) => void;\r\n wallets: Wallet[];\r\n }) => void;\r\n};\r\n\r\nexport function useWalletMultiButton({ onSelectWallet }: Config): ButtonState {\r\n const { connect, connected, connecting, disconnect, disconnecting, publicKey, select, wallet, wallets } =\r\n useWallet();\r\n let buttonState: ButtonState['buttonState'];\r\n if (connecting) {\r\n buttonState = 'connecting';\r\n } else if (connected) {\r\n buttonState = 'connected';\r\n } else if (disconnecting) {\r\n buttonState = 'disconnecting';\r\n } else if (wallet) {\r\n buttonState = 'has-wallet';\r\n } else {\r\n buttonState = 'no-wallet';\r\n }\r\n const handleConnect = useCallback(() => {\r\n connect().catch(() => {\r\n });\r\n }, [connect]);\r\n const handleDisconnect = useCallback(() => {\r\n disconnect().catch(() => {\r\n });\r\n }, [disconnect]);\r\n const handleSelectWallet = useCallback(() => {\r\n onSelectWallet({ onSelectWallet: select, wallets });\r\n }, [onSelectWallet, select, wallets]);\r\n return {\r\n buttonState,\r\n onConnect: buttonState === 'has-wallet' ? handleConnect : undefined,\r\n onDisconnect: buttonState !== 'disconnecting' && buttonState !== 'no-wallet' ? handleDisconnect : undefined,\r\n onSelectWallet: handleSelectWallet,\r\n publicKey: publicKey ?? undefined,\r\n walletIcon: wallet?.adapter.icon,\r\n walletName: wallet?.adapter.name,\r\n };\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletMultiButton.ts" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" }, { "path": "components/providers/lazorkit-wallet-context.tsx", - "content": "// components/providers/lazorkit-wallet-context.tsx\n\"use client\"\n\nimport React, { createContext, useContext, useCallback, useState, useEffect, useMemo } from \"react\"\nimport { useWallet as useLazorKitWallet, WalletAccount } from \"@lazorkit/wallet\"\nimport { Transaction, PublicKey, TransactionInstruction } from \"@solana/web3.js\"\n\n// Custom error class for LazorKit errors\nclass LazorKitError extends Error {\n constructor(message: string, public code?: string, public isAccountNotFound: boolean = false) {\n super(message)\n this.name = 'LazorKitError'\n }\n}\n\n// Extended WalletAccount to include createSmartWallet\ninterface ExtendedWalletAccount extends WalletAccount {\n createSmartWallet?: () => Promise\n}\n\n// Connect Response type for createPasskeyOnly\ninterface ConnectResponse {\n publicKey: string\n credentialId: string\n isCreated: boolean\n connectionType: 'create' | 'get'\n timestamp: number\n}\n\n// Extended LazorKit wallet interface\ninterface ExtendedLazorKitWallet {\n smartWalletPubkey: PublicKey | null\n isConnected: boolean\n isLoading: boolean\n isConnecting: boolean\n isSigning: boolean\n error: Error | null\n account: WalletAccount | null\n connect: () => Promise\n disconnect: () => Promise\n signTransaction: (instruction: TransactionInstruction) => Promise\n signAndSendTransaction: (instruction: TransactionInstruction) => Promise\n createPasskeyOnly: () => Promise\n createSmartWalletOnly: (passkeyData: ConnectResponse) => Promise<{smartWalletAddress: string, account: WalletAccount}>\n reconnect: () => Promise\n}\n\ninterface LazorKitWalletContextState {\n smartWalletPubkey: PublicKey | null\n isConnected: boolean\n isLoading: boolean\n isConnecting: boolean\n isSigning: boolean\n error: Error | null\n account: ExtendedWalletAccount | null\n connect: () => Promise\n disconnect: () => Promise\n reconnect: () => Promise\n signTransaction: (instruction: TransactionInstruction) => Promise\n signAndSendTransaction: (instruction: TransactionInstruction) => Promise\n createPasskeyOnly: () => Promise\n createSmartWalletOnly: (passkeyData: ConnectResponse) => Promise<{smartWalletAddress: string, account: ExtendedWalletAccount}>\n clearError: () => void\n}\n\nconst defaultContext: LazorKitWalletContextState = {\n smartWalletPubkey: null,\n isConnected: false,\n isLoading: false,\n isConnecting: false,\n isSigning: false,\n error: null,\n account: null,\n connect: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n disconnect: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n reconnect: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n signTransaction: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n signAndSendTransaction: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n createPasskeyOnly: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n createSmartWalletOnly: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\n clearError: () => {}\n}\n\nexport const LazorKitWalletContext = createContext(defaultContext)\n\nexport const useLazorKitWalletContext = () => {\n const context = useContext(LazorKitWalletContext)\n if (!context) {\n throw new LazorKitError(\"useLazorKitWalletContext must be used within a LazorKitWalletProvider\")\n }\n return context\n}\n\n// Utility function for error handling\nconst handleError = (err: unknown): Error => {\n if (err instanceof Error) {\n // Check for specific error types\n if (err.message.includes('Account does not exist') || \n err.message.includes('has no data')) {\n return new LazorKitError(\n \"Smart wallet needs to be initialized. Please try connecting again.\", \n 'ACCOUNT_NOT_FOUND',\n true\n )\n }\n if (err.message.includes('NO_STORED_CREDENTIALS')) {\n return new LazorKitError(\"No stored credentials found\", 'NO_STORED_CREDENTIALS')\n }\n if (err.message.includes('INVALID_CREDENTIALS')) {\n return new LazorKitError(\"Invalid credentials\", 'INVALID_CREDENTIALS')\n }\n return err\n }\n return new LazorKitError(err instanceof Object ? JSON.stringify(err) : String(err))\n}\n\nexport function LazorKitWalletProvider({ children }: { children: React.ReactNode }) {\n const wallet = useLazorKitWallet() as unknown as ExtendedLazorKitWallet\n\n const [isConnecting, setIsConnecting] = useState(false)\n const [error, setError] = useState(null)\n const [retryCount, setRetryCount] = useState(0)\n const MAX_RETRIES = 3\n\n const clearError = useCallback(() => setError(null), [])\n\n // Auto-retry connection on certain errors\n useEffect(() => {\n if (error && retryCount < MAX_RETRIES && !isConnecting) {\n const timer = setTimeout(() => {\n console.log(`Retrying connection (attempt ${retryCount + 1}/${MAX_RETRIES})`)\n setRetryCount(prev => prev + 1)\n connect()\n }, Math.min(1000 * Math.pow(2, retryCount), 8000)) // Exponential backoff\n\n return () => clearTimeout(timer)\n }\n }, [error, retryCount, isConnecting])\n\n const connect = useCallback(async () => {\n if (isConnecting) return wallet.account as ExtendedWalletAccount\n \n try {\n setIsConnecting(true)\n setError(null)\n \n // First try reconnecting with stored credentials\n try {\n const reconnectedAccount = await wallet.reconnect()\n setRetryCount(0)\n return reconnectedAccount as ExtendedWalletAccount\n } catch (reconnectError) {\n // If reconnect fails, try new connection\n try {\n const newAccount = await wallet.connect()\n setRetryCount(0)\n return newAccount as ExtendedWalletAccount\n } catch (connectError) {\n throw handleError(connectError)\n }\n }\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n } finally {\n setIsConnecting(false)\n }\n }, [wallet.connect, wallet.reconnect, wallet.account, isConnecting])\n\n const disconnect = useCallback(async () => {\n try {\n setError(null)\n await wallet.disconnect()\n setRetryCount(0)\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n }\n }, [wallet.disconnect])\n\n const reconnect = useCallback(async () => {\n try {\n setError(null)\n return await wallet.reconnect() as ExtendedWalletAccount\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n }\n }, [wallet.reconnect])\n\n const createPasskeyOnly = useCallback(async () => {\n try {\n setError(null)\n return await wallet.createPasskeyOnly()\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n }\n }, [wallet.createPasskeyOnly])\n\n const createSmartWalletOnly = useCallback(async (passkeyData: ConnectResponse) => {\n try {\n setError(null)\n return await wallet.createSmartWalletOnly(passkeyData)\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n }\n }, [wallet.createSmartWalletOnly])\n\n const signTransaction = useCallback(async (instruction: TransactionInstruction) => {\n try {\n setError(null)\n return await wallet.signTransaction(instruction)\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n }\n }, [wallet.signTransaction])\n\n const signAndSendTransaction = useCallback(async (instruction: TransactionInstruction) => {\n try {\n setError(null)\n return await wallet.signAndSendTransaction(instruction)\n } catch (err) {\n const error = handleError(err)\n setError(error)\n throw error\n }\n }, [wallet.signAndSendTransaction])\n\n // Memoize the context value to prevent unnecessary re-renders\n const value = useMemo(() => ({\n smartWalletPubkey: wallet.smartWalletPubkey,\n isConnected: wallet.isConnected,\n isLoading: wallet.isLoading,\n isConnecting,\n isSigning: wallet.isSigning,\n error,\n account: wallet.account as ExtendedWalletAccount,\n connect,\n disconnect,\n reconnect,\n signTransaction,\n signAndSendTransaction,\n createPasskeyOnly,\n createSmartWalletOnly,\n clearError\n }), [\n wallet.smartWalletPubkey,\n wallet.isConnected,\n wallet.isLoading,\n isConnecting,\n wallet.isSigning,\n error,\n wallet.account,\n connect,\n disconnect,\n reconnect,\n signTransaction,\n signAndSendTransaction,\n createPasskeyOnly,\n createSmartWalletOnly,\n clearError\n ])\n\n return (\n \n {children}\n \n )\n}", + "content": "// components/providers/lazorkit-wallet-context.tsx\r\n\"use client\"\r\n\r\nimport React, { createContext, useContext, useCallback, useState, useEffect, useMemo } from \"react\"\r\nimport { useWallet as useLazorKitWallet, WalletAccount } from \"@lazorkit/wallet\"\r\nimport { Transaction, PublicKey, TransactionInstruction } from \"@solana/web3.js\"\r\n\r\n// Custom error class for LazorKit errors\r\nclass LazorKitError extends Error {\r\n constructor(message: string, public code?: string, public isAccountNotFound: boolean = false) {\r\n super(message)\r\n this.name = 'LazorKitError'\r\n }\r\n}\r\n\r\n// Extended WalletAccount to include createSmartWallet\r\ninterface ExtendedWalletAccount extends WalletAccount {\r\n createSmartWallet?: () => Promise\r\n}\r\n\r\n// Connect Response type for createPasskeyOnly\r\ninterface ConnectResponse {\r\n publicKey: string\r\n credentialId: string\r\n isCreated: boolean\r\n connectionType: 'create' | 'get'\r\n timestamp: number\r\n}\r\n\r\n// Extended LazorKit wallet interface\r\ninterface ExtendedLazorKitWallet {\r\n smartWalletPubkey: PublicKey | null\r\n isConnected: boolean\r\n isLoading: boolean\r\n isConnecting: boolean\r\n isSigning: boolean\r\n error: Error | null\r\n account: WalletAccount | null\r\n connect: () => Promise\r\n disconnect: () => Promise\r\n signTransaction: (instruction: TransactionInstruction) => Promise\r\n signAndSendTransaction: (instruction: TransactionInstruction) => Promise\r\n createPasskeyOnly: () => Promise\r\n createSmartWalletOnly: (passkeyData: ConnectResponse) => Promise<{smartWalletAddress: string, account: WalletAccount}>\r\n reconnect: () => Promise\r\n}\r\n\r\ninterface LazorKitWalletContextState {\r\n smartWalletPubkey: PublicKey | null\r\n isConnected: boolean\r\n isLoading: boolean\r\n isConnecting: boolean\r\n isSigning: boolean\r\n error: Error | null\r\n account: ExtendedWalletAccount | null\r\n connect: () => Promise\r\n disconnect: () => Promise\r\n reconnect: () => Promise\r\n signTransaction: (instruction: TransactionInstruction) => Promise\r\n signAndSendTransaction: (instruction: TransactionInstruction) => Promise\r\n createPasskeyOnly: () => Promise\r\n createSmartWalletOnly: (passkeyData: ConnectResponse) => Promise<{smartWalletAddress: string, account: ExtendedWalletAccount}>\r\n clearError: () => void\r\n}\r\n\r\nconst defaultContext: LazorKitWalletContextState = {\r\n smartWalletPubkey: null,\r\n isConnected: false,\r\n isLoading: false,\r\n isConnecting: false,\r\n isSigning: false,\r\n error: null,\r\n account: null,\r\n connect: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n disconnect: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n reconnect: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n signTransaction: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n signAndSendTransaction: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n createPasskeyOnly: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n createSmartWalletOnly: async () => { throw new LazorKitError(\"LazorKitWalletContext not initialized\") },\r\n clearError: () => {}\r\n}\r\n\r\nexport const LazorKitWalletContext = createContext(defaultContext)\r\n\r\nexport const useLazorKitWalletContext = () => {\r\n const context = useContext(LazorKitWalletContext)\r\n if (!context) {\r\n throw new LazorKitError(\"useLazorKitWalletContext must be used within a LazorKitWalletProvider\")\r\n }\r\n return context\r\n}\r\n\r\n// Utility function for error handling\r\nconst handleError = (err: unknown): Error => {\r\n if (err instanceof Error) {\r\n // Check for specific error types\r\n if (err.message.includes('Account does not exist') || \r\n err.message.includes('has no data')) {\r\n return new LazorKitError(\r\n \"Smart wallet needs to be initialized. Please try connecting again.\", \r\n 'ACCOUNT_NOT_FOUND',\r\n true\r\n )\r\n }\r\n if (err.message.includes('NO_STORED_CREDENTIALS')) {\r\n return new LazorKitError(\"No stored credentials found\", 'NO_STORED_CREDENTIALS')\r\n }\r\n if (err.message.includes('INVALID_CREDENTIALS')) {\r\n return new LazorKitError(\"Invalid credentials\", 'INVALID_CREDENTIALS')\r\n }\r\n return err\r\n }\r\n return new LazorKitError(err instanceof Object ? JSON.stringify(err) : String(err))\r\n}\r\n\r\nexport function LazorKitWalletProvider({ children }: { children: React.ReactNode }) {\r\n const wallet = useLazorKitWallet() as unknown as ExtendedLazorKitWallet\r\n\r\n const [isConnecting, setIsConnecting] = useState(false)\r\n const [error, setError] = useState(null)\r\n const [retryCount, setRetryCount] = useState(0)\r\n const MAX_RETRIES = 3\r\n\r\n const clearError = useCallback(() => setError(null), [])\r\n\r\n // Auto-retry connection on certain errors\r\n useEffect(() => {\r\n if (error && retryCount < MAX_RETRIES && !isConnecting) {\r\n const timer = setTimeout(() => {\r\n console.log(`Retrying connection (attempt ${retryCount + 1}/${MAX_RETRIES})`)\r\n setRetryCount(prev => prev + 1)\r\n connect()\r\n }, Math.min(1000 * Math.pow(2, retryCount), 8000)) // Exponential backoff\r\n\r\n return () => clearTimeout(timer)\r\n }\r\n }, [error, retryCount, isConnecting])\r\n\r\n const connect = useCallback(async () => {\r\n if (isConnecting) return wallet.account as ExtendedWalletAccount\r\n \r\n try {\r\n setIsConnecting(true)\r\n setError(null)\r\n \r\n // First try reconnecting with stored credentials\r\n try {\r\n const reconnectedAccount = await wallet.reconnect()\r\n setRetryCount(0)\r\n return reconnectedAccount as ExtendedWalletAccount\r\n } catch (reconnectError) {\r\n // If reconnect fails, try new connection\r\n try {\r\n const newAccount = await wallet.connect()\r\n setRetryCount(0)\r\n return newAccount as ExtendedWalletAccount\r\n } catch (connectError) {\r\n throw handleError(connectError)\r\n }\r\n }\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n } finally {\r\n setIsConnecting(false)\r\n }\r\n }, [wallet.connect, wallet.reconnect, wallet.account, isConnecting])\r\n\r\n const disconnect = useCallback(async () => {\r\n try {\r\n setError(null)\r\n await wallet.disconnect()\r\n setRetryCount(0)\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n }\r\n }, [wallet.disconnect])\r\n\r\n const reconnect = useCallback(async () => {\r\n try {\r\n setError(null)\r\n return await wallet.reconnect() as ExtendedWalletAccount\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n }\r\n }, [wallet.reconnect])\r\n\r\n const createPasskeyOnly = useCallback(async () => {\r\n try {\r\n setError(null)\r\n return await wallet.createPasskeyOnly()\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n }\r\n }, [wallet.createPasskeyOnly])\r\n\r\n const createSmartWalletOnly = useCallback(async (passkeyData: ConnectResponse) => {\r\n try {\r\n setError(null)\r\n return await wallet.createSmartWalletOnly(passkeyData)\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n }\r\n }, [wallet.createSmartWalletOnly])\r\n\r\n const signTransaction = useCallback(async (instruction: TransactionInstruction) => {\r\n try {\r\n setError(null)\r\n return await wallet.signTransaction(instruction)\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n }\r\n }, [wallet.signTransaction])\r\n\r\n const signAndSendTransaction = useCallback(async (instruction: TransactionInstruction) => {\r\n try {\r\n setError(null)\r\n return await wallet.signAndSendTransaction(instruction)\r\n } catch (err) {\r\n const error = handleError(err)\r\n setError(error)\r\n throw error\r\n }\r\n }, [wallet.signAndSendTransaction])\r\n\r\n // Memoize the context value to prevent unnecessary re-renders\r\n const value = useMemo(() => ({\r\n smartWalletPubkey: wallet.smartWalletPubkey,\r\n isConnected: wallet.isConnected,\r\n isLoading: wallet.isLoading,\r\n isConnecting,\r\n isSigning: wallet.isSigning,\r\n error,\r\n account: wallet.account as ExtendedWalletAccount,\r\n connect,\r\n disconnect,\r\n reconnect,\r\n signTransaction,\r\n signAndSendTransaction,\r\n createPasskeyOnly,\r\n createSmartWalletOnly,\r\n clearError\r\n }), [\r\n wallet.smartWalletPubkey,\r\n wallet.isConnected,\r\n wallet.isLoading,\r\n isConnecting,\r\n wallet.isSigning,\r\n error,\r\n wallet.account,\r\n connect,\r\n disconnect,\r\n reconnect,\r\n signTransaction,\r\n signAndSendTransaction,\r\n createPasskeyOnly,\r\n createSmartWalletOnly,\r\n clearError\r\n ])\r\n\r\n return (\r\n \r\n {children}\r\n \r\n )\r\n}", "type": "registry:component", "target": "components/providers/lazorkit-wallet-context.tsx" }, { "path": "components/providers/client-lazorkit-provider.tsx", - "content": "\"use client\"\n\nimport React from \"react\"\nimport { LazorkitProvider } from \"@lazorkit/wallet\"\n\nconst DEFAULT_RPC_URL = \"https://api.devnet.solana.com\" // Changed to devnet as per docs\nconst DEFAULT_IPFS_URL = \"https://portal.lazor.sh\"\nconst DEFAULT_PAYMASTER_URL = \"https://lazorkit-paymaster.onrender.com\"\n\nexport function ClientLazorKitProvider({ children }: { children: React.ReactNode }) {\n // Validate and use environment variables with fallbacks\n const rpcUrl = process.env.LAZORKIT_RPC_URL || DEFAULT_RPC_URL\n const ipfsUrl = process.env.LAZORKIT_PORTAL_URL || DEFAULT_IPFS_URL\n const paymasterUrl = process.env.LAZORKIT_PAYMASTER_URL || DEFAULT_PAYMASTER_URL\n\n // Enable debug mode in development\n const debug = process.env.NODE_ENV === 'development'\n\n // Log configuration in development\n if (debug) {\n console.debug('LazorKit Provider Configuration:', {\n rpcUrl,\n ipfsUrl,\n paymasterUrl,\n debug\n })\n }\n\n return (\n \n {children}\n \n )\n}", + "content": "\"use client\"\r\n\r\nimport React from \"react\"\r\nimport { LazorkitProvider } from \"@lazorkit/wallet\"\r\n\r\nconst DEFAULT_RPC_URL = \"https://api.devnet.solana.com\" // Changed to devnet as per docs\r\nconst DEFAULT_IPFS_URL = \"https://portal.lazor.sh\"\r\nconst DEFAULT_PAYMASTER_URL = \"https://lazorkit-paymaster.onrender.com\"\r\n\r\nexport function ClientLazorKitProvider({ children }: { children: React.ReactNode }) {\r\n // Validate and use environment variables with fallbacks\r\n const rpcUrl = process.env.LAZORKIT_RPC_URL || DEFAULT_RPC_URL\r\n const ipfsUrl = process.env.LAZORKIT_PORTAL_URL || DEFAULT_IPFS_URL\r\n const paymasterUrl = process.env.LAZORKIT_PAYMASTER_URL || DEFAULT_PAYMASTER_URL\r\n\r\n // Enable debug mode in development\r\n const debug = process.env.NODE_ENV === 'development'\r\n\r\n // Log configuration in development\r\n if (debug) {\r\n console.debug('LazorKit Provider Configuration:', {\r\n rpcUrl,\r\n ipfsUrl,\r\n paymasterUrl,\r\n debug\r\n })\r\n }\r\n\r\n return (\r\n \r\n {children}\r\n \r\n )\r\n}", "type": "registry:component", "target": "components/providers/client-lazorkit-provider.tsx" } diff --git a/public/r/create-collection-form.json b/public/r/create-collection-form.json index 563006e..ab1e4b4 100644 --- a/public/r/create-collection-form.json +++ b/public/r/create-collection-form.json @@ -26,7 +26,7 @@ "files": [ { "path": "components/ui/murphy/create-collection-form.tsx", - "content": "'use client';\n\n// React và hooks\nimport { useState, useEffect, useContext } from 'react';\nimport { useForm } from \"react-hook-form\";\n\n// Solana\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\n\n// Icons and notifications\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle } from \"lucide-react\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\n// Import Metaplex libraries asynchronously\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\nimport { mplTokenMetadata, createNft } from '@metaplex-foundation/mpl-token-metadata';\nimport { generateSigner, percentAmount } from '@metaplex-foundation/umi';\n\ninterface CreateCollectionResult {\n mint: string;\n signature: string;\n}\n\ntype CollectionFormValues = {\n name: string;\n uri: string;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate collection name\n if (!data.name) {\n errors.name = {\n type: \"required\",\n message: \"Collection name is required\",\n };\n }\n\n // Validate metadata URI\n if (!data.uri) {\n errors.uri = {\n type: \"required\",\n message: \"URI metadata is required\",\n };\n } else {\n try {\n new URL(data.uri);\n } catch (e) {\n errors.uri = {\n type: \"pattern\",\n message: \"Invalid URI. Please enter a full URI including https://\",\n };\n }\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport default function CreateCollectionForm({ onCollectionCreated }: { onCollectionCreated?: (collectionMint: string) => void }) {\n const { connection } = useConnection();\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\n \n const [isSubmitting, setIsSubmitting] = useState(false);\n const [result, setResult] = useState(null);\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState('devnet');\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n name: \"\",\n uri: \"\",\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Only render after the component is mounted on the client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n const onSubmit = async (values: CollectionFormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error('Please connect your wallet');\n return;\n }\n\n try {\n setIsSubmitting(true);\n\n // Create wallet adapter for signing transactions\n const walletAdapter = {\n publicKey: publicKey,\n signTransaction,\n signAllTransactions\n };\n\n // Create UMI instance with all necessary modules\n const umi = createUmi(connection.rpcEndpoint)\n .use(walletAdapterIdentity(walletAdapter))\n .use(mplTokenMetadata());\n \n // Create signer for collection mint\n const collectionMint = generateSigner(umi);\n \n toast.loading(\"Creating collection...\", {\n id: \"create-collection\"\n });\n \n // Create collection NFT\n const createResult = await createNft(umi, {\n mint: collectionMint,\n name: values.name,\n uri: values.uri,\n sellerFeeBasisPoints: percentAmount(5.5), // 5.5%\n isCollection: true,\n }).sendAndConfirm(umi);\n \n // Convert signature to string format\n const signatureStr = typeof createResult.signature === 'string' \n ? createResult.signature \n : Buffer.from(createResult.signature).toString('base64');\n \n // Convert mint address to string\n const mintAddressStr = collectionMint.publicKey.toString();\n \n // Save result\n setResult({\n mint: mintAddressStr,\n signature: signatureStr\n });\n \n // Call callback if provided\n if (onCollectionCreated) {\n onCollectionCreated(mintAddressStr);\n }\n \n toast.success(\"Collection created successfully!\", {\n id: \"create-collection\",\n description: `Mint: ${mintAddressStr.slice(0, 8)}...${mintAddressStr.slice(-8)}`\n });\n \n // Reset form\n form.reset();\n } catch (err: any) {\n console.error(\"Error creating collection:\", err);\n \n toast.error(\"Cannot create collection\", {\n id: \"create-collection\",\n description: err.message\n });\n \n // If transaction fails due to connection error, try switching to another endpoint\n if (err.message.includes('failed to fetch') || \n err.message.includes('timeout') || \n err.message.includes('429') ||\n err.message.includes('503')) {\n switchToNextEndpoint();\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const viewCollection = () => {\n if (result?.mint) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/token/';\n window.open(`${baseUrl}${result.mint}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n Create Collection\n Create a new NFT collection on Solana\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

Collection Created!

\n \n
\n
Mint Address:
\n
\n {result?.mint}\n
\n
\n \n
\n
Transaction Signature:
\n
\n {result?.signature}\n
\n
\n \n
\n \n \n \n
\n \n \n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n (\n \n
\n Collection Name\n
\n \n \n \n \n

\n Enter the name for your NFT collection\n

\n
\n )}\n />\n \n (\n \n
\n URI Metadata\n
\n \n \n \n \n

\n URI to metadata JSON according to Metaplex standards\n

\n
\n )}\n />\n \n
\n
\n
\n Network\n \n {network}\n \n
\n \n
\n Royalty Fee\n 5.5%\n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Creating...\n \n ) : \"Create Collection\"}\n \n )}\n
\n
\n \n \n );\n\n return (\n \n \n \n Create Collection\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Create a new NFT collection on Solana\n \n \n {result ? renderSuccess() : renderForm()}\n \n \n );\n}", + "content": "'use client';\r\n\r\n// React và hooks\r\nimport { useState, useEffect, useContext } from 'react';\r\nimport { useForm } from \"react-hook-form\";\r\n\r\n// Solana\r\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\n\r\n// Icons and notifications\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle } from \"lucide-react\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\n// Import Metaplex libraries asynchronously\r\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\r\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\r\nimport { mplTokenMetadata, createNft } from '@metaplex-foundation/mpl-token-metadata';\r\nimport { generateSigner, percentAmount } from '@metaplex-foundation/umi';\r\n\r\ninterface CreateCollectionResult {\r\n mint: string;\r\n signature: string;\r\n}\r\n\r\ntype CollectionFormValues = {\r\n name: string;\r\n uri: string;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate collection name\r\n if (!data.name) {\r\n errors.name = {\r\n type: \"required\",\r\n message: \"Collection name is required\",\r\n };\r\n }\r\n\r\n // Validate metadata URI\r\n if (!data.uri) {\r\n errors.uri = {\r\n type: \"required\",\r\n message: \"URI metadata is required\",\r\n };\r\n } else {\r\n try {\r\n new URL(data.uri);\r\n } catch (e) {\r\n errors.uri = {\r\n type: \"pattern\",\r\n message: \"Invalid URI. Please enter a full URI including https://\",\r\n };\r\n }\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport default function CreateCollectionForm({ onCollectionCreated }: { onCollectionCreated?: (collectionMint: string) => void }) {\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\r\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\r\n \r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [result, setResult] = useState(null);\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState('devnet');\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n name: \"\",\r\n uri: \"\",\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Only render after the component is mounted on the client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n const onSubmit = async (values: CollectionFormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error('Please connect your wallet');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n\r\n // Create wallet adapter for signing transactions\r\n const walletAdapter = {\r\n publicKey: publicKey,\r\n signTransaction,\r\n signAllTransactions\r\n };\r\n\r\n // Create UMI instance with all necessary modules\r\n const umi = createUmi(connection.rpcEndpoint)\r\n .use(walletAdapterIdentity(walletAdapter))\r\n .use(mplTokenMetadata());\r\n \r\n // Create signer for collection mint\r\n const collectionMint = generateSigner(umi);\r\n \r\n toast.loading(\"Creating collection...\", {\r\n id: \"create-collection\"\r\n });\r\n \r\n // Create collection NFT\r\n const createResult = await createNft(umi, {\r\n mint: collectionMint,\r\n name: values.name,\r\n uri: values.uri,\r\n sellerFeeBasisPoints: percentAmount(5.5), // 5.5%\r\n isCollection: true,\r\n }).sendAndConfirm(umi);\r\n \r\n // Convert signature to string format\r\n const signatureStr = typeof createResult.signature === 'string' \r\n ? createResult.signature \r\n : Buffer.from(createResult.signature).toString('base64');\r\n \r\n // Convert mint address to string\r\n const mintAddressStr = collectionMint.publicKey.toString();\r\n \r\n // Save result\r\n setResult({\r\n mint: mintAddressStr,\r\n signature: signatureStr\r\n });\r\n \r\n // Call callback if provided\r\n if (onCollectionCreated) {\r\n onCollectionCreated(mintAddressStr);\r\n }\r\n \r\n toast.success(\"Collection created successfully!\", {\r\n id: \"create-collection\",\r\n description: `Mint: ${mintAddressStr.slice(0, 8)}...${mintAddressStr.slice(-8)}`\r\n });\r\n \r\n // Reset form\r\n form.reset();\r\n } catch (err: any) {\r\n console.error(\"Error creating collection:\", err);\r\n \r\n toast.error(\"Cannot create collection\", {\r\n id: \"create-collection\",\r\n description: err.message\r\n });\r\n \r\n // If transaction fails due to connection error, try switching to another endpoint\r\n if (err.message.includes('failed to fetch') || \r\n err.message.includes('timeout') || \r\n err.message.includes('429') ||\r\n err.message.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\r\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const viewCollection = () => {\r\n if (result?.mint) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/token/';\r\n window.open(`${baseUrl}${result.mint}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create Collection\r\n Create a new NFT collection on Solana\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

Collection Created!

\r\n \r\n
\r\n
Mint Address:
\r\n
\r\n {result?.mint}\r\n
\r\n
\r\n \r\n
\r\n
Transaction Signature:
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n (\r\n \r\n
\r\n Collection Name\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Enter the name for your NFT collection\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n URI Metadata\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n URI to metadata JSON according to Metaplex standards\r\n

\r\n
\r\n )}\r\n />\r\n \r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n \r\n
\r\n Royalty Fee\r\n 5.5%\r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating...\r\n \r\n ) : \"Create Collection\"}\r\n \r\n )}\r\n
\r\n
\r\n \r\n \r\n );\r\n\r\n return (\r\n \r\n \r\n \r\n Create Collection\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Create a new NFT collection on Solana\r\n \r\n \r\n {result ? renderSuccess() : renderForm()}\r\n \r\n \r\n );\r\n}", "type": "registry:component", "target": "components/ui/murphy/create-collection-form.tsx" } diff --git a/public/r/create-merkleTree-form.json b/public/r/create-merkleTree-form.json index 4fc87b0..09787e7 100644 --- a/public/r/create-merkleTree-form.json +++ b/public/r/create-merkleTree-form.json @@ -26,7 +26,7 @@ "files": [ { "path": "components/ui/murphy/create-merkleTree-form.tsx", - "content": "'use client';\n\nimport { useState, useEffect, useContext } from 'react';\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle } from \"lucide-react\";\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\n// Import Metaplex libraries asynchronously\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\nimport { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';\nimport { generateSigner } from '@metaplex-foundation/umi';\nimport { createTree } from '@metaplex-foundation/mpl-bubblegum';\n\ninterface CreateMerkleTreeResult {\n mint: string;\n signature: string;\n}\n\ntype MerkleTreeFormValues = {\n maxDepth: number;\n maxBuffer: number;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate max depth\n if (data.maxDepth === undefined || data.maxDepth === null || data.maxDepth === \"\") {\n errors.maxDepth = {\n type: \"required\",\n message: \"Max depth is required\",\n };\n } else if (Number(data.maxDepth) < 1 || Number(data.maxDepth) > 30) {\n errors.maxDepth = {\n type: \"range\",\n message: \"Max depth must be between 1 and 30\",\n };\n }\n\n // Validate max buffer\n if (data.maxBuffer === undefined || data.maxBuffer === null || data.maxBuffer === \"\") {\n errors.maxBuffer = {\n type: \"required\",\n message: \"Max buffer size is required\",\n };\n } else if (Number(data.maxBuffer) < 1) {\n errors.maxBuffer = {\n type: \"min\",\n message: \"Max buffer size must be greater than 0\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport function CreateMerkleTree({ onMerkleTreeCreated }: { onMerkleTreeCreated?: (merkleTreeAddress: string) => void }) {\n // Hooks\n const { connection } = useConnection();\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\n \n // State\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [result, setResult] = useState(null);\n const [error, setError] = useState(null);\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState('devnet');\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n maxDepth: 14,\n maxBuffer: 64,\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Only render after the component is mounted on the client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n // Handle form submission\n const onSubmit = async (values: MerkleTreeFormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error('Please connect your wallet');\n return;\n }\n\n try {\n setIsSubmitting(true);\n setError(null);\n setCurrentStage('confirming');\n\n // Create wallet adapter for signing transactions\n const walletAdapter = {\n publicKey,\n signTransaction,\n signAllTransactions\n };\n\n // Create UMI instance\n const umi = createUmi(connection.rpcEndpoint)\n .use(walletAdapterIdentity(walletAdapter))\n .use(mplTokenMetadata());\n \n toast.loading(\"Creating Merkle Tree...\", {\n id: \"create-merkle-tree\"\n });\n \n // Create Merkle Tree\n const merkleTree = generateSigner(umi);\n const builder = await createTree(umi, {\n merkleTree,\n maxDepth: values.maxDepth,\n maxBufferSize: values.maxBuffer,\n });\n \n const createResult = await builder.sendAndConfirm(umi);\n \n // Convert signature to string format\n const signatureStr = typeof createResult.signature === 'string' \n ? createResult.signature \n : Buffer.from(createResult.signature).toString('base64');\n \n // Convert merkle tree address to string\n const merkleTreeAddressStr = merkleTree.publicKey.toString();\n \n // Save result\n setResult({\n mint: merkleTreeAddressStr,\n signature: signatureStr\n });\n \n // Call callback if provided\n if (onMerkleTreeCreated) {\n onMerkleTreeCreated(merkleTreeAddressStr);\n }\n \n toast.success(\"Merkle Tree created successfully!\", {\n id: \"create-merkle-tree\",\n description: `Address: ${merkleTreeAddressStr.slice(0, 8)}...${merkleTreeAddressStr.slice(-8)}`\n });\n \n setCurrentStage('success');\n \n } catch (err: any) {\n console.error(\"Create Merkle Tree error:\", err);\n setError(err.message);\n setCurrentStage('error');\n \n // Check if user canceled/rejected the transaction\n if (err.message && (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))) {\n toast.error(\"Transaction canceled\", {\n id: \"create-merkle-tree\",\n description: \"You canceled the transaction\"\n });\n } else {\n toast.error(\"Failed to create Merkle Tree\", {\n id: \"create-merkle-tree\",\n description: err.message\n });\n \n // If transaction fails due to connection error, try switching to another endpoint\n if (err.message.includes('failed to fetch') || \n err.message.includes('timeout') || \n err.message.includes('429') ||\n err.message.includes('503')) {\n switchToNextEndpoint();\n }\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const viewMerkleTree = () => {\n if (result?.mint) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\n window.open(`${baseUrl}${result.mint}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setError(null);\n setCurrentStage('input');\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

Merkle Tree Created!

\n \n
\n
Merkle Tree Address:
\n
\n {result?.mint}\n
\n
\n \n
\n
Transaction Signature:
\n
\n {result?.signature}\n
\n
\n \n
\n \n \n \n
\n \n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Creation Failed

\n

{error || 'An error occurred while creating the Merkle Tree.'}

\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Creating Merkle Tree

\n

Please wait while your Merkle Tree is being created...

\n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n (\n \n
\n Max Depth\n
\n \n field.onChange(parseInt(e.target.value))}\n />\n \n \n

\n Maximum depth of the Merkle tree (recommended: 14-20)\n

\n
\n )}\n />\n \n (\n \n
\n Max Buffer Size\n
\n \n field.onChange(parseInt(e.target.value))}\n />\n \n \n

\n Maximum buffer size for concurrent operations (recommended: 64-256)\n

\n
\n )}\n />\n \n
\n
\n
\n Network\n \n {network}\n \n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Creating...\n \n ) : \"Create Merkle Tree\"}\n \n )}\n
\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'confirming':\n return renderConfirming();\n default:\n return renderForm();\n }\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n Create Merkle Tree\n Create a new Merkle Tree on Solana\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n Create Merkle Tree\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Create a new Merkle Tree on Solana\n \n \n {renderStageContent()}\n \n \n );\n} ", + "content": "'use client';\r\n\r\nimport { useState, useEffect, useContext } from 'react';\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle } from \"lucide-react\";\r\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\n// Import Metaplex libraries asynchronously\r\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\r\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\r\nimport { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';\r\nimport { generateSigner } from '@metaplex-foundation/umi';\r\nimport { createTree } from '@metaplex-foundation/mpl-bubblegum';\r\n\r\ninterface CreateMerkleTreeResult {\r\n mint: string;\r\n signature: string;\r\n}\r\n\r\ntype MerkleTreeFormValues = {\r\n maxDepth: number;\r\n maxBuffer: number;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate max depth\r\n if (data.maxDepth === undefined || data.maxDepth === null || data.maxDepth === \"\") {\r\n errors.maxDepth = {\r\n type: \"required\",\r\n message: \"Max depth is required\",\r\n };\r\n } else if (Number(data.maxDepth) < 1 || Number(data.maxDepth) > 30) {\r\n errors.maxDepth = {\r\n type: \"range\",\r\n message: \"Max depth must be between 1 and 30\",\r\n };\r\n }\r\n\r\n // Validate max buffer\r\n if (data.maxBuffer === undefined || data.maxBuffer === null || data.maxBuffer === \"\") {\r\n errors.maxBuffer = {\r\n type: \"required\",\r\n message: \"Max buffer size is required\",\r\n };\r\n } else if (Number(data.maxBuffer) < 1) {\r\n errors.maxBuffer = {\r\n type: \"min\",\r\n message: \"Max buffer size must be greater than 0\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport function CreateMerkleTree({ onMerkleTreeCreated }: { onMerkleTreeCreated?: (merkleTreeAddress: string) => void }) {\r\n // Hooks\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\r\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\r\n \r\n // State\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [result, setResult] = useState(null);\r\n const [error, setError] = useState(null);\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState('devnet');\r\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n maxDepth: 14,\r\n maxBuffer: 64,\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Only render after the component is mounted on the client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n // Handle form submission\r\n const onSubmit = async (values: MerkleTreeFormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error('Please connect your wallet');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setError(null);\r\n setCurrentStage('confirming');\r\n\r\n // Create wallet adapter for signing transactions\r\n const walletAdapter = {\r\n publicKey,\r\n signTransaction,\r\n signAllTransactions\r\n };\r\n\r\n // Create UMI instance\r\n const umi = createUmi(connection.rpcEndpoint)\r\n .use(walletAdapterIdentity(walletAdapter))\r\n .use(mplTokenMetadata());\r\n \r\n toast.loading(\"Creating Merkle Tree...\", {\r\n id: \"create-merkle-tree\"\r\n });\r\n \r\n // Create Merkle Tree\r\n const merkleTree = generateSigner(umi);\r\n const builder = await createTree(umi, {\r\n merkleTree,\r\n maxDepth: values.maxDepth,\r\n maxBufferSize: values.maxBuffer,\r\n });\r\n \r\n const createResult = await builder.sendAndConfirm(umi);\r\n \r\n // Convert signature to string format\r\n const signatureStr = typeof createResult.signature === 'string' \r\n ? createResult.signature \r\n : Buffer.from(createResult.signature).toString('base64');\r\n \r\n // Convert merkle tree address to string\r\n const merkleTreeAddressStr = merkleTree.publicKey.toString();\r\n \r\n // Save result\r\n setResult({\r\n mint: merkleTreeAddressStr,\r\n signature: signatureStr\r\n });\r\n \r\n // Call callback if provided\r\n if (onMerkleTreeCreated) {\r\n onMerkleTreeCreated(merkleTreeAddressStr);\r\n }\r\n \r\n toast.success(\"Merkle Tree created successfully!\", {\r\n id: \"create-merkle-tree\",\r\n description: `Address: ${merkleTreeAddressStr.slice(0, 8)}...${merkleTreeAddressStr.slice(-8)}`\r\n });\r\n \r\n setCurrentStage('success');\r\n \r\n } catch (err: any) {\r\n console.error(\"Create Merkle Tree error:\", err);\r\n setError(err.message);\r\n setCurrentStage('error');\r\n \r\n // Check if user canceled/rejected the transaction\r\n if (err.message && (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))) {\r\n toast.error(\"Transaction canceled\", {\r\n id: \"create-merkle-tree\",\r\n description: \"You canceled the transaction\"\r\n });\r\n } else {\r\n toast.error(\"Failed to create Merkle Tree\", {\r\n id: \"create-merkle-tree\",\r\n description: err.message\r\n });\r\n \r\n // If transaction fails due to connection error, try switching to another endpoint\r\n if (err.message.includes('failed to fetch') || \r\n err.message.includes('timeout') || \r\n err.message.includes('429') ||\r\n err.message.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\r\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const viewMerkleTree = () => {\r\n if (result?.mint) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\r\n window.open(`${baseUrl}${result.mint}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setError(null);\r\n setCurrentStage('input');\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

Merkle Tree Created!

\r\n \r\n
\r\n
Merkle Tree Address:
\r\n
\r\n {result?.mint}\r\n
\r\n
\r\n \r\n
\r\n
Transaction Signature:
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Creation Failed

\r\n

{error || 'An error occurred while creating the Merkle Tree.'}

\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Creating Merkle Tree

\r\n

Please wait while your Merkle Tree is being created...

\r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n (\r\n \r\n
\r\n Max Depth\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n />\r\n \r\n \r\n

\r\n Maximum depth of the Merkle tree (recommended: 14-20)\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Max Buffer Size\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n />\r\n \r\n \r\n

\r\n Maximum buffer size for concurrent operations (recommended: 64-256)\r\n

\r\n
\r\n )}\r\n />\r\n \r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating...\r\n \r\n ) : \"Create Merkle Tree\"}\r\n \r\n )}\r\n
\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'confirming':\r\n return renderConfirming();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create Merkle Tree\r\n Create a new Merkle Tree on Solana\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Create Merkle Tree\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Create a new Merkle Tree on Solana\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n} ", "type": "registry:component", "target": "components/ui/murphy/create-merkleTree-form.tsx" } diff --git a/public/r/createConfig-form.json b/public/r/createConfig-form.json index 51ae710..ab4c0a7 100644 --- a/public/r/createConfig-form.json +++ b/public/r/createConfig-form.json @@ -22,19 +22,19 @@ "files": [ { "path": "components/ui/murphy/createConfig-form.tsx", - "content": "'use client';\n\nimport { useState, useEffect, useContext } from 'react';\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle, Settings } from \"lucide-react\";\nimport { PublicKey, Transaction, Keypair } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\nimport { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk';\nimport BN from 'bn.js';\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\nenum FeeSchedulerMode {\n Linear = 0\n}\n\ninterface CreateConfigResult {\n config: string;\n signature: string;\n}\n\ntype CreateConfigFormValues = {\n feeClaimer: string;\n leftoverReceiver: string;\n quoteMint: string;\n cliffFeeNumerator: string;\n binStep: number;\n tokenDecimal: number;\n partnerLpPercentage: number;\n creatorLpPercentage: number;\n partnerLockedLpPercentage: number;\n creatorLockedLpPercentage: number;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate feeClaimer\n if (!data.feeClaimer) {\n errors.feeClaimer = {\n type: \"required\",\n message: \"Fee claimer address is required\",\n };\n } else {\n try {\n new PublicKey(data.feeClaimer);\n } catch (e) {\n errors.feeClaimer = {\n type: \"pattern\",\n message: \"Invalid address format\",\n };\n }\n }\n\n // Validate leftoverReceiver\n if (!data.leftoverReceiver) {\n errors.leftoverReceiver = {\n type: \"required\",\n message: \"Leftover receiver address is required\",\n };\n } else {\n try {\n new PublicKey(data.leftoverReceiver);\n } catch (e) {\n errors.leftoverReceiver = {\n type: \"pattern\",\n message: \"Invalid address format\",\n };\n }\n }\n\n // Validate quoteMint\n if (!data.quoteMint) {\n errors.quoteMint = {\n type: \"required\",\n message: \"Quote mint address is required\",\n };\n }\n\n // Validate cliffFeeNumerator\n if (!data.cliffFeeNumerator) {\n errors.cliffFeeNumerator = {\n type: \"required\",\n message: \"Cliff fee numerator is required\",\n };\n }\n\n // Validate binStep\n if (data.binStep === undefined || data.binStep === null || data.binStep === \"\") {\n errors.binStep = {\n type: \"required\",\n message: \"Bin step is required\",\n };\n } else if (Number(data.binStep) < 1) {\n errors.binStep = {\n type: \"min\",\n message: \"Bin step must be greater than 0\",\n };\n }\n\n // Validate tokenDecimal\n if (data.tokenDecimal === undefined || data.tokenDecimal === null || data.tokenDecimal === \"\") {\n errors.tokenDecimal = {\n type: \"required\",\n message: \"Token decimal is required\",\n };\n } else if (Number(data.tokenDecimal) < 0 || Number(data.tokenDecimal) > 18) {\n errors.tokenDecimal = {\n type: \"range\",\n message: \"Token decimal must be between 0 and 18\",\n };\n }\n\n // Validate LP percentages\n const validatePercentage = (field: string, name: string) => {\n if (data[field] === undefined || data[field] === null || data[field] === \"\") {\n errors[field] = {\n type: \"required\",\n message: `${name} is required`,\n };\n } else if (Number(data[field]) < 0 || Number(data[field]) > 100) {\n errors[field] = {\n type: \"range\",\n message: `${name} must be between 0 and 100`,\n };\n }\n };\n\n validatePercentage(\"partnerLpPercentage\", \"Partner LP percentage\");\n validatePercentage(\"creatorLpPercentage\", \"Creator LP percentage\");\n validatePercentage(\"partnerLockedLpPercentage\", \"Partner locked LP percentage\");\n validatePercentage(\"creatorLockedLpPercentage\", \"Creator locked LP percentage\");\n\n // Validate that percentages sum to 100\n const totalPercentage = Number(data.partnerLpPercentage || 0) + \n Number(data.creatorLpPercentage || 0) + \n Number(data.partnerLockedLpPercentage || 0) + \n Number(data.creatorLockedLpPercentage || 0);\n \n if (totalPercentage !== 100) {\n errors.partnerLpPercentage = {\n type: \"validate\",\n message: \"LP percentages must sum to 100%\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport function CreateConfigForm({ onConfigCreated }: { onConfigCreated?: (configAddress: string) => void }) {\n // Hooks\n const { connection } = useConnection();\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\n \n // State\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [result, setResult] = useState(null);\n const [error, setError] = useState(null);\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState('devnet');\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n feeClaimer: \"\",\n leftoverReceiver: \"\",\n quoteMint: \"So11111111111111111111111111111111111111112\", // SOL by default\n cliffFeeNumerator: \"2500000\",\n binStep: 1,\n tokenDecimal: 9,\n partnerLpPercentage: 25,\n creatorLpPercentage: 25,\n partnerLockedLpPercentage: 25,\n creatorLockedLpPercentage: 25,\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Only render after the component is mounted on the client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n // Auto-fill wallet address into form fields when wallet is connected\n useEffect(() => {\n if (connected && publicKey) {\n const walletAddress = publicKey.toString();\n \n // Only set if fields are empty\n if (!form.getValues(\"feeClaimer\")) {\n form.setValue(\"feeClaimer\", walletAddress, { shouldValidate: false });\n }\n \n if (!form.getValues(\"leftoverReceiver\")) {\n form.setValue(\"leftoverReceiver\", walletAddress, { shouldValidate: false });\n }\n }\n }, [connected, publicKey, form]);\n\n // Handle form submission\n const onSubmit = async (values: CreateConfigFormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error('Please connect your wallet');\n return;\n }\n\n try {\n setIsSubmitting(true);\n setError(null);\n setCurrentStage('confirming');\n\n toast.loading(\"Creating config...\", {\n id: \"create-config\"\n });\n\n // Create a new keypair for config\n const configKeypair = Keypair.generate();\n \n // Initialize DBC client\n const client = new DynamicBondingCurveClient(connection);\n \n // Create params for createConfig\n const createConfigParams = {\n payer: publicKey,\n config: configKeypair.publicKey,\n feeClaimer: new PublicKey(values.feeClaimer),\n leftoverReceiver: new PublicKey(values.leftoverReceiver),\n quoteMint: new PublicKey(values.quoteMint),\n poolFees: {\n baseFee: {\n cliffFeeNumerator: new BN(values.cliffFeeNumerator),\n numberOfPeriod: 0,\n reductionFactor: new BN('0'),\n periodFrequency: new BN('0'),\n feeSchedulerMode: FeeSchedulerMode.Linear,\n },\n dynamicFee: {\n binStep: values.binStep,\n binStepU128: new BN('1844674407370955'),\n filterPeriod: 10,\n decayPeriod: 120,\n reductionFactor: 1000,\n variableFeeControl: 100000,\n maxVolatilityAccumulator: 100000,\n },\n },\n activationType: 0,\n collectFeeMode: 0,\n migrationOption: 0,\n tokenType: 0,\n tokenDecimal: values.tokenDecimal,\n migrationQuoteThreshold: new BN('1000000000'),\n partnerLpPercentage: values.partnerLpPercentage,\n creatorLpPercentage: values.creatorLpPercentage,\n partnerLockedLpPercentage: values.partnerLockedLpPercentage,\n creatorLockedLpPercentage: values.creatorLockedLpPercentage,\n sqrtStartPrice: new BN('58333726687135158'),\n lockedVesting: {\n amountPerPeriod: new BN('0'),\n cliffDurationFromMigrationTime: new BN('0'),\n frequency: new BN('0'),\n numberOfPeriod: new BN('0'),\n cliffUnlockAmount: new BN('0'),\n },\n migrationFeeOption: 0,\n tokenSupply: {\n preMigrationTokenSupply: new BN('10000000000000000000'),\n postMigrationTokenSupply: new BN('10000000000000000000'),\n },\n padding: [\n new BN(0),\n new BN(0),\n new BN(0),\n new BN(0),\n new BN(0),\n new BN(0),\n new BN(0),\n ],\n curve: [\n {\n sqrtPrice: new BN('233334906748540631'),\n liquidity: new BN('622226417996106429201027821619672729'),\n },\n {\n sqrtPrice: new BN('79226673521066979257578248091'),\n liquidity: new BN('1'),\n },\n ],\n };\n \n // Create transaction\n const transaction = await client.partners.createConfig(createConfigParams);\n \n // Get recentBlockhash\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.lastValidBlockHeight = lastValidBlockHeight;\n \n // Set feePayer for transaction\n transaction.feePayer = publicKey;\n \n // Partially sign transaction with config keypair if needed\n transaction.partialSign(configKeypair);\n \n // Sign and send transaction\n const signature = await wallet.adapter.sendTransaction(transaction, connection);\n \n // Wait for confirmation\n await connection.confirmTransaction({\n blockhash,\n lastValidBlockHeight,\n signature\n });\n \n // Save result\n const configAddress = configKeypair.publicKey.toString();\n setResult({\n config: configAddress,\n signature: signature\n });\n \n // Call callback if provided\n if (onConfigCreated) {\n onConfigCreated(configAddress);\n }\n \n toast.success(\"Configuration created successfully!\", {\n id: \"create-config\",\n description: `Config: ${configAddress.slice(0, 8)}...${configAddress.slice(-8)}`\n });\n \n setCurrentStage('success');\n \n } catch (err: any) {\n console.error(\"Create Config error:\", err);\n setError(err.message);\n setCurrentStage('error');\n \n // Check if user canceled/rejected the transaction\n if (err.message && (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))) {\n toast.error(\"Transaction canceled\", {\n id: \"create-config\",\n description: \"You canceled the transaction\"\n });\n } else {\n toast.error(\"Failed to create configuration\", {\n id: \"create-config\",\n description: err.message\n });\n \n // If transaction fails due to connection error, try switching to another endpoint\n if (err.message.includes('failed to fetch') || \n err.message.includes('timeout') || \n err.message.includes('429') ||\n err.message.includes('503')) {\n switchToNextEndpoint();\n }\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const viewConfig = () => {\n if (result?.config) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\n window.open(`${baseUrl}${result.config}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setError(null);\n setCurrentStage('input');\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

Config Created!

\n \n
\n
Config Address:
\n
\n {result?.config}\n
\n
\n \n
\n
Transaction Signature:
\n
\n {result?.signature}\n
\n
\n \n
\n \n \n \n
\n \n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Creation Failed

\n

{error || 'An error occurred while creating the configuration.'}

\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Creating Config

\n

Please wait while your configuration is being created...

\n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n
\n (\n \n
\n Fee Claimer\n
\n \n \n \n \n

\n Address that will be able to claim fees from the pool\n

\n
\n )}\n />\n \n (\n \n
\n Leftover Receiver\n
\n \n \n \n \n

\n Address that will receive leftover tokens\n

\n
\n )}\n />\n \n (\n \n
\n Quote Mint\n
\n \n \n \n \n {field.value === \"So11111111111111111111111111111111111111112\" && (\n
\n \"SOL\"\n SOL\n
\n )}\n {field.value === \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" && (\n
\n \"USDC\"\n USDC\n
\n )}\n {field.value === \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" && (\n
\n \"USDT\"\n USDT\n
\n )}\n
\n
\n \n \n
\n \"SOL\"\n SOL\n
\n
\n \n
\n \"USDC\"\n USDC\n
\n
\n \n
\n \"USDT\"\n USDT\n
\n
\n
\n \n
\n \n

\n The quote token for the pool\n

\n
\n )}\n />\n
\n \n
\n (\n \n
\n Cliff Fee Numerator\n
\n \n \n \n \n

\n Base fee for the pool\n

\n
\n )}\n />\n \n (\n \n
\n Bin Step\n
\n \n field.onChange(parseInt(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n \n

\n Bin step for dynamic fee calculation\n

\n
\n )}\n />\n \n (\n \n
\n Token Decimal\n
\n \n field.onChange(parseInt(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n \n

\n Decimal places for the token\n

\n
\n )}\n />\n
\n \n
\n
LP Distribution
\n \n
\n (\n \n
\n Partner LP %\n
\n \n field.onChange(parseInt(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent text-sm h-8\"\n />\n \n \n
\n )}\n />\n \n (\n \n
\n Creator LP %\n
\n \n field.onChange(parseInt(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent text-sm h-8\"\n />\n \n \n
\n )}\n />\n \n (\n \n
\n Partner Locked LP %\n
\n \n field.onChange(parseInt(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent text-sm h-8\"\n />\n \n \n
\n )}\n />\n \n (\n \n
\n Creator Locked LP %\n
\n \n field.onChange(parseInt(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent text-sm h-8\"\n />\n \n \n
\n )}\n />\n
\n \n

\n LP distribution percentages must sum to 100%. These percentages determine how liquidity provider tokens are distributed.\n

\n
\n \n
\n
\n
\n Network\n \n {network}\n \n
\n \n
\n Default Fee Scheduler Mode\n Linear\n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Creating...\n \n ) : \"Create Config\"}\n \n )}\n
\n
\n
\n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'confirming':\n return renderConfirming();\n default:\n return renderForm();\n }\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n Create Config\n Create a new DBC configuration\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n Create Config\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Create a new DBC configuration for pools\n \n \n {renderStageContent()}\n \n \n );\n}\n\nexport default CreateConfigForm;\n", + "content": "'use client';\r\n\r\nimport { useState, useEffect, useContext } from 'react';\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle, Settings } from \"lucide-react\";\r\nimport { PublicKey, Transaction, Keypair } from \"@solana/web3.js\";\r\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\r\nimport { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk';\r\nimport BN from 'bn.js';\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/ui/select\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\nenum FeeSchedulerMode {\r\n Linear = 0\r\n}\r\n\r\ninterface CreateConfigResult {\r\n config: string;\r\n signature: string;\r\n}\r\n\r\ntype CreateConfigFormValues = {\r\n feeClaimer: string;\r\n leftoverReceiver: string;\r\n quoteMint: string;\r\n cliffFeeNumerator: string;\r\n binStep: number;\r\n tokenDecimal: number;\r\n partnerLpPercentage: number;\r\n creatorLpPercentage: number;\r\n partnerLockedLpPercentage: number;\r\n creatorLockedLpPercentage: number;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate feeClaimer\r\n if (!data.feeClaimer) {\r\n errors.feeClaimer = {\r\n type: \"required\",\r\n message: \"Fee claimer address is required\",\r\n };\r\n } else {\r\n try {\r\n new PublicKey(data.feeClaimer);\r\n } catch (e) {\r\n errors.feeClaimer = {\r\n type: \"pattern\",\r\n message: \"Invalid address format\",\r\n };\r\n }\r\n }\r\n\r\n // Validate leftoverReceiver\r\n if (!data.leftoverReceiver) {\r\n errors.leftoverReceiver = {\r\n type: \"required\",\r\n message: \"Leftover receiver address is required\",\r\n };\r\n } else {\r\n try {\r\n new PublicKey(data.leftoverReceiver);\r\n } catch (e) {\r\n errors.leftoverReceiver = {\r\n type: \"pattern\",\r\n message: \"Invalid address format\",\r\n };\r\n }\r\n }\r\n\r\n // Validate quoteMint\r\n if (!data.quoteMint) {\r\n errors.quoteMint = {\r\n type: \"required\",\r\n message: \"Quote mint address is required\",\r\n };\r\n }\r\n\r\n // Validate cliffFeeNumerator\r\n if (!data.cliffFeeNumerator) {\r\n errors.cliffFeeNumerator = {\r\n type: \"required\",\r\n message: \"Cliff fee numerator is required\",\r\n };\r\n }\r\n\r\n // Validate binStep\r\n if (data.binStep === undefined || data.binStep === null || data.binStep === \"\") {\r\n errors.binStep = {\r\n type: \"required\",\r\n message: \"Bin step is required\",\r\n };\r\n } else if (Number(data.binStep) < 1) {\r\n errors.binStep = {\r\n type: \"min\",\r\n message: \"Bin step must be greater than 0\",\r\n };\r\n }\r\n\r\n // Validate tokenDecimal\r\n if (data.tokenDecimal === undefined || data.tokenDecimal === null || data.tokenDecimal === \"\") {\r\n errors.tokenDecimal = {\r\n type: \"required\",\r\n message: \"Token decimal is required\",\r\n };\r\n } else if (Number(data.tokenDecimal) < 0 || Number(data.tokenDecimal) > 18) {\r\n errors.tokenDecimal = {\r\n type: \"range\",\r\n message: \"Token decimal must be between 0 and 18\",\r\n };\r\n }\r\n\r\n // Validate LP percentages\r\n const validatePercentage = (field: string, name: string) => {\r\n if (data[field] === undefined || data[field] === null || data[field] === \"\") {\r\n errors[field] = {\r\n type: \"required\",\r\n message: `${name} is required`,\r\n };\r\n } else if (Number(data[field]) < 0 || Number(data[field]) > 100) {\r\n errors[field] = {\r\n type: \"range\",\r\n message: `${name} must be between 0 and 100`,\r\n };\r\n }\r\n };\r\n\r\n validatePercentage(\"partnerLpPercentage\", \"Partner LP percentage\");\r\n validatePercentage(\"creatorLpPercentage\", \"Creator LP percentage\");\r\n validatePercentage(\"partnerLockedLpPercentage\", \"Partner locked LP percentage\");\r\n validatePercentage(\"creatorLockedLpPercentage\", \"Creator locked LP percentage\");\r\n\r\n // Validate that percentages sum to 100\r\n const totalPercentage = Number(data.partnerLpPercentage || 0) + \r\n Number(data.creatorLpPercentage || 0) + \r\n Number(data.partnerLockedLpPercentage || 0) + \r\n Number(data.creatorLockedLpPercentage || 0);\r\n \r\n if (totalPercentage !== 100) {\r\n errors.partnerLpPercentage = {\r\n type: \"validate\",\r\n message: \"LP percentages must sum to 100%\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport function CreateConfigForm({ onConfigCreated }: { onConfigCreated?: (configAddress: string) => void }) {\r\n // Hooks\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\r\n const { switchToNextEndpoint, endpoint } = useContext(ModalContext);\r\n \r\n // State\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [result, setResult] = useState(null);\r\n const [error, setError] = useState(null);\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState('devnet');\r\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n feeClaimer: \"\",\r\n leftoverReceiver: \"\",\r\n quoteMint: \"So11111111111111111111111111111111111111112\", // SOL by default\r\n cliffFeeNumerator: \"2500000\",\r\n binStep: 1,\r\n tokenDecimal: 9,\r\n partnerLpPercentage: 25,\r\n creatorLpPercentage: 25,\r\n partnerLockedLpPercentage: 25,\r\n creatorLockedLpPercentage: 25,\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Only render after the component is mounted on the client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n // Auto-fill wallet address into form fields when wallet is connected\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n const walletAddress = publicKey.toString();\r\n \r\n // Only set if fields are empty\r\n if (!form.getValues(\"feeClaimer\")) {\r\n form.setValue(\"feeClaimer\", walletAddress, { shouldValidate: false });\r\n }\r\n \r\n if (!form.getValues(\"leftoverReceiver\")) {\r\n form.setValue(\"leftoverReceiver\", walletAddress, { shouldValidate: false });\r\n }\r\n }\r\n }, [connected, publicKey, form]);\r\n\r\n // Handle form submission\r\n const onSubmit = async (values: CreateConfigFormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error('Please connect your wallet');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setError(null);\r\n setCurrentStage('confirming');\r\n\r\n toast.loading(\"Creating config...\", {\r\n id: \"create-config\"\r\n });\r\n\r\n // Create a new keypair for config\r\n const configKeypair = Keypair.generate();\r\n \r\n // Initialize DBC client\r\n const client = new DynamicBondingCurveClient(connection);\r\n \r\n // Create params for createConfig\r\n const createConfigParams = {\r\n payer: publicKey,\r\n config: configKeypair.publicKey,\r\n feeClaimer: new PublicKey(values.feeClaimer),\r\n leftoverReceiver: new PublicKey(values.leftoverReceiver),\r\n quoteMint: new PublicKey(values.quoteMint),\r\n poolFees: {\r\n baseFee: {\r\n cliffFeeNumerator: new BN(values.cliffFeeNumerator),\r\n numberOfPeriod: 0,\r\n reductionFactor: new BN('0'),\r\n periodFrequency: new BN('0'),\r\n feeSchedulerMode: FeeSchedulerMode.Linear,\r\n },\r\n dynamicFee: {\r\n binStep: values.binStep,\r\n binStepU128: new BN('1844674407370955'),\r\n filterPeriod: 10,\r\n decayPeriod: 120,\r\n reductionFactor: 1000,\r\n variableFeeControl: 100000,\r\n maxVolatilityAccumulator: 100000,\r\n },\r\n },\r\n activationType: 0,\r\n collectFeeMode: 0,\r\n migrationOption: 0,\r\n tokenType: 0,\r\n tokenDecimal: values.tokenDecimal,\r\n migrationQuoteThreshold: new BN('1000000000'),\r\n partnerLpPercentage: values.partnerLpPercentage,\r\n creatorLpPercentage: values.creatorLpPercentage,\r\n partnerLockedLpPercentage: values.partnerLockedLpPercentage,\r\n creatorLockedLpPercentage: values.creatorLockedLpPercentage,\r\n sqrtStartPrice: new BN('58333726687135158'),\r\n lockedVesting: {\r\n amountPerPeriod: new BN('0'),\r\n cliffDurationFromMigrationTime: new BN('0'),\r\n frequency: new BN('0'),\r\n numberOfPeriod: new BN('0'),\r\n cliffUnlockAmount: new BN('0'),\r\n },\r\n migrationFeeOption: 0,\r\n tokenSupply: {\r\n preMigrationTokenSupply: new BN('10000000000000000000'),\r\n postMigrationTokenSupply: new BN('10000000000000000000'),\r\n },\r\n padding: [\r\n new BN(0),\r\n new BN(0),\r\n new BN(0),\r\n new BN(0),\r\n new BN(0),\r\n new BN(0),\r\n new BN(0),\r\n ],\r\n curve: [\r\n {\r\n sqrtPrice: new BN('233334906748540631'),\r\n liquidity: new BN('622226417996106429201027821619672729'),\r\n },\r\n {\r\n sqrtPrice: new BN('79226673521066979257578248091'),\r\n liquidity: new BN('1'),\r\n },\r\n ],\r\n };\r\n \r\n // Create transaction\r\n const transaction = await client.partners.createConfig(createConfigParams);\r\n \r\n // Get recentBlockhash\r\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\r\n transaction.recentBlockhash = blockhash;\r\n transaction.lastValidBlockHeight = lastValidBlockHeight;\r\n \r\n // Set feePayer for transaction\r\n transaction.feePayer = publicKey;\r\n \r\n // Partially sign transaction with config keypair if needed\r\n transaction.partialSign(configKeypair);\r\n \r\n // Sign and send transaction\r\n const signature = await wallet.adapter.sendTransaction(transaction, connection);\r\n \r\n // Wait for confirmation\r\n await connection.confirmTransaction({\r\n blockhash,\r\n lastValidBlockHeight,\r\n signature\r\n });\r\n \r\n // Save result\r\n const configAddress = configKeypair.publicKey.toString();\r\n setResult({\r\n config: configAddress,\r\n signature: signature\r\n });\r\n \r\n // Call callback if provided\r\n if (onConfigCreated) {\r\n onConfigCreated(configAddress);\r\n }\r\n \r\n toast.success(\"Configuration created successfully!\", {\r\n id: \"create-config\",\r\n description: `Config: ${configAddress.slice(0, 8)}...${configAddress.slice(-8)}`\r\n });\r\n \r\n setCurrentStage('success');\r\n \r\n } catch (err: any) {\r\n console.error(\"Create Config error:\", err);\r\n setError(err.message);\r\n setCurrentStage('error');\r\n \r\n // Check if user canceled/rejected the transaction\r\n if (err.message && (err.message.includes(\"rejected\") || err.message.includes(\"canceled\"))) {\r\n toast.error(\"Transaction canceled\", {\r\n id: \"create-config\",\r\n description: \"You canceled the transaction\"\r\n });\r\n } else {\r\n toast.error(\"Failed to create configuration\", {\r\n id: \"create-config\",\r\n description: err.message\r\n });\r\n \r\n // If transaction fails due to connection error, try switching to another endpoint\r\n if (err.message.includes('failed to fetch') || \r\n err.message.includes('timeout') || \r\n err.message.includes('429') ||\r\n err.message.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\r\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const viewConfig = () => {\r\n if (result?.config) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\r\n window.open(`${baseUrl}${result.config}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setError(null);\r\n setCurrentStage('input');\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

Config Created!

\r\n \r\n
\r\n
Config Address:
\r\n
\r\n {result?.config}\r\n
\r\n
\r\n \r\n
\r\n
Transaction Signature:
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Creation Failed

\r\n

{error || 'An error occurred while creating the configuration.'}

\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Creating Config

\r\n

Please wait while your configuration is being created...

\r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n
\r\n (\r\n \r\n
\r\n Fee Claimer\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Address that will be able to claim fees from the pool\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Leftover Receiver\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Address that will receive leftover tokens\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Quote Mint\r\n
\r\n \r\n \r\n \r\n \r\n {field.value === \"So11111111111111111111111111111111111111112\" && (\r\n
\r\n \"SOL\"\r\n SOL\r\n
\r\n )}\r\n {field.value === \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" && (\r\n
\r\n \"USDC\"\r\n USDC\r\n
\r\n )}\r\n {field.value === \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" && (\r\n
\r\n \"USDT\"\r\n USDT\r\n
\r\n )}\r\n
\r\n
\r\n \r\n \r\n
\r\n \"SOL\"\r\n SOL\r\n
\r\n
\r\n \r\n
\r\n \"USDC\"\r\n USDC\r\n
\r\n
\r\n \r\n
\r\n \"USDT\"\r\n USDT\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n

\r\n The quote token for the pool\r\n

\r\n
\r\n )}\r\n />\r\n
\r\n \r\n
\r\n (\r\n \r\n
\r\n Cliff Fee Numerator\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Base fee for the pool\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Bin Step\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n \r\n

\r\n Bin step for dynamic fee calculation\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Token Decimal\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n \r\n

\r\n Decimal places for the token\r\n

\r\n
\r\n )}\r\n />\r\n
\r\n \r\n
\r\n
LP Distribution
\r\n \r\n
\r\n (\r\n \r\n
\r\n Partner LP %\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent text-sm h-8\"\r\n />\r\n \r\n \r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Creator LP %\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent text-sm h-8\"\r\n />\r\n \r\n \r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Partner Locked LP %\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent text-sm h-8\"\r\n />\r\n \r\n \r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Creator Locked LP %\r\n
\r\n \r\n field.onChange(parseInt(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent text-sm h-8\"\r\n />\r\n \r\n \r\n
\r\n )}\r\n />\r\n
\r\n \r\n

\r\n LP distribution percentages must sum to 100%. These percentages determine how liquidity provider tokens are distributed.\r\n

\r\n
\r\n \r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n \r\n
\r\n Default Fee Scheduler Mode\r\n Linear\r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating...\r\n \r\n ) : \"Create Config\"}\r\n \r\n )}\r\n
\r\n
\r\n
\r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'confirming':\r\n return renderConfirming();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create Config\r\n Create a new DBC configuration\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Create Config\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Create a new DBC configuration for pools\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}\r\n\r\nexport default CreateConfigForm;\r\n", "type": "registry:component", "target": "components/ui/murphy/createConfig-form.tsx" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" } diff --git a/public/r/distribute-cToken.json b/public/r/distribute-cToken.json index 970561e..bdc56c9 100644 --- a/public/r/distribute-cToken.json +++ b/public/r/distribute-cToken.json @@ -24,7 +24,7 @@ "files": [ { "path": "components/ui/murphy/distribute-cToken.tsx", - "content": "\"use client\";\n\nimport React, { useContext } from \"react\";\nimport { ComputeBudgetProgram, PublicKey, Transaction } from \"@solana/web3.js\";\nimport {\n CompressedTokenProgram,\n getTokenPoolInfos,\n selectTokenPoolInfo,\n} from \"@lightprotocol/compressed-token\";\nimport {\n bn,\n calculateComputeUnitPrice,\n createRpc,\n selectStateTreeInfo,\n} from \"@lightprotocol/stateless.js\";\nimport { getAssociatedTokenAddress, getAccount, createAssociatedTokenAccountInstruction } from \"@solana/spl-token\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as z from \"zod\";\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\nimport { toast } from \"sonner\";\nimport QRCode from \"react-qr-code\";\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from \"@/components/ui/dialog\";\n\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { Loader2 } from \"lucide-react\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Label } from \"@/components/ui/label\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\n// Form schema - no need for privateKey anymore\nconst formSchema = z.object({\n mintAddress: z.string().min(1, \"Mint address is required\"),\n recipients: z.string().min(1, \"Recipient list is required\"),\n amount: z.number().min(1, \"Amount must be greater than 0\"),\n});\n\ntype FormValues = z.infer;\n\nexport function DistributeTokenForm({ className }: { className?: string }) {\n // Use hook from wallet adapter\n const { publicKey, signTransaction, connected } = useWallet();\n const { connection } = useConnection();\n const { endpoint } = useContext(ModalContext);\n \n const [isSubmitting, setIsSubmitting] = React.useState(false);\n const [currentStage, setCurrentStage] = React.useState<'input' | 'success' | 'error'>('input');\n const [error, setError] = React.useState(\"\");\n const [result, setResult] = React.useState<{\n txId: string;\n } | null>(null);\n const [isMainnet, setIsMainnet] = React.useState(true);\n\n const form = useForm({\n resolver: zodResolver(formSchema),\n defaultValues: {\n mintAddress: \"\",\n recipients: \"\",\n amount: 100,\n },\n });\n\n const onSubmit = async (values: FormValues) => {\n try {\n // Check if the wallet is connected\n if (!connected || !publicKey || !signTransaction) {\n toast.error(\"Please connect your wallet first\");\n return;\n }\n\n setIsSubmitting(true);\n setError(\"\");\n setCurrentStage('input');\n\n const rpcEndpoint = isMainnet \n ? process.env.NEXT_PUBLIC_SOLANA_RPC_URL \n : process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET;\n\n if (!rpcEndpoint) {\n throw new Error(\"RPC endpoint is not configured\");\n }\n \n // Create RPC connection\n const connection = createRpc(rpcEndpoint);\n\n // Convert mint address\n const mintAddress = new PublicKey(values.mintAddress);\n \n // Convert recipient list\n const airDropAddresses = values.recipients.split(',')\n .map(address => address.trim())\n .filter(address => address.length > 0)\n .map(address => new PublicKey(address));\n\n if (airDropAddresses.length === 0) {\n throw new Error(\"No valid recipient addresses\");\n }\n\n // 1. Find Associated Token Account address\n const ataAddress = await getAssociatedTokenAddress(mintAddress, publicKey);\n\n // 2. Check if ATA already exists\n let ataExists = false;\n try {\n await getAccount(connection, ataAddress);\n ataExists = true;\n } catch (e) {\n // ATA doesn't exist\n ataExists = false;\n }\n\n // 3. If not, create ATA with a separate transaction\n if (!ataExists) {\n console.log(\"Creating new Associated Token Account...\");\n const createAtaTx = new Transaction();\n createAtaTx.add(\n createAssociatedTokenAccountInstruction(\n publicKey, // payer\n ataAddress, // ATA address\n publicKey, // owner\n mintAddress // token mint\n )\n );\n \n createAtaTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;\n createAtaTx.feePayer = publicKey;\n \n const signedCreateAtaTx = await signTransaction(createAtaTx);\n const createAtaTxId = await connection.sendRawTransaction(signedCreateAtaTx.serialize());\n await connection.confirmTransaction({\n signature: createAtaTxId,\n blockhash: (await connection.getLatestBlockhash()).blockhash,\n lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,\n });\n console.log(\"ATA created with tx ID:\", createAtaTxId);\n }\n\n // Select new tree for each transaction\n const activeStateTrees = await connection.getStateTreeInfos();\n const treeInfo = selectStateTreeInfo(activeStateTrees);\n\n // Select token pool info\n const infos = await getTokenPoolInfos(connection, mintAddress);\n const info = selectTokenPoolInfo(infos);\n\n const amount = bn(values.amount);\n\n const instructions = [];\n // Adjust compute units based on the number of recipients\n const computeUnits = 120000 + (airDropAddresses.length > 1 ? 10000 * (airDropAddresses.length - 1) : 0);\n \n instructions.push(\n ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }),\n ComputeBudgetProgram.setComputeUnitPrice({\n microLamports: calculateComputeUnitPrice(20000, computeUnits),\n })\n );\n\n const compressInstruction = await CompressedTokenProgram.compress({\n payer: publicKey,\n owner: publicKey,\n source: ataAddress,\n toAddress: airDropAddresses,\n amount: airDropAddresses.map(() => amount),\n mint: mintAddress,\n tokenPoolInfo: info,\n outputStateTreeInfo: treeInfo,\n });\n instructions.push(compressInstruction);\n\n // Sign and send transaction with connected wallet\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\n \n // Create transaction and add instructions\n const transaction = new Transaction();\n instructions.forEach(instruction => transaction.add(instruction));\n \n // Set blockhash and feePayer information\n transaction.recentBlockhash = blockhash;\n transaction.feePayer = publicKey;\n \n console.log(\"Signing transaction...\");\n \n try {\n // Sign transaction with connected wallet\n const signedTx = await signTransaction(transaction);\n \n console.log(\"Sending transaction...\");\n const txId = await connection.sendRawTransaction(signedTx.serialize());\n \n // Wait for confirmation\n await connection.confirmTransaction({\n signature: txId,\n blockhash,\n lastValidBlockHeight,\n });\n \n console.log(\"Transaction confirmed:\", txId);\n \n setResult({\n txId\n });\n setCurrentStage('success');\n \n toast.success(\"Distribution successful!\", {\n description: `Transaction: ${txId}`\n });\n } catch (signError: any) {\n console.error('Error signing transaction:', signError);\n \n // Analyze error if user canceled the transaction\n if (signError.message && signError.message.includes(\"canceled\")) {\n toast.error(\"Transaction canceled\", {\n description: \"You canceled the transaction\"\n });\n setError(\"You canceled the transaction\");\n } else {\n toast.error(\"Error signing transaction\", {\n description: signError.message || \"Unable to sign transaction\"\n });\n setError(`Error signing transaction: ${signError.message}`);\n }\n \n setCurrentStage('error');\n throw signError;\n }\n } catch (err) {\n console.error(err);\n setError(err instanceof Error ? err.message : \"An error occurred\");\n setCurrentStage('error');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setCurrentStage(\"input\");\n setError(\"\");\n };\n\n // Add helper function to handle long text\n const truncateText = (text: string, maxLength: number = 20) => {\n if (text.length <= maxLength) return text;\n return `${text.slice(0, maxLength)}...`;\n };\n\n // Add helper function to copy text\n const copyToClipboard = (text: string) => {\n navigator.clipboard.writeText(text);\n toast.success(\"Copied to clipboard\");\n };\n\n // Add helper function to create Solscan link\n const getSolscanUrl = (type: 'tx' | 'token' | 'account', id: string) => {\n const cluster = isMainnet ? '' : '?cluster=devnet';\n return `https://solscan.io/${type}/${id}${cluster}`;\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
FieldValueAction
Token Address\n
\n {truncateText(form.getValues(\"mintAddress\") || \"\")}\n copyToClipboard(form.getValues(\"mintAddress\"))}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('token', form.getValues(\"mintAddress\")), '_blank')}\n >\n View\n \n
Amount Per Recipient{form.getValues(\"amount\")}\n copyToClipboard(form.getValues(\"amount\").toString())}\n >\n Copy\n \n
Transaction ID\n
\n {truncateText(result?.txId || \"\")}\n copyToClipboard(result?.txId || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('tx', result?.txId || \"\"), '_blank')}\n >\n View\n \n
\n
\n
\n\n
\n \n \n \n \n \n \n \n QR Code to Claim Token\n \n
\n \n

\n Recipients can scan this QR code to claim tokens\n

\n
\n

Token: {truncateText(form.getValues(\"mintAddress\"), 10)}

\n

Amount: {form.getValues(\"amount\")}

\n
\n
\n
\n
\n \n
\n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n {error}\n
\n \n
\n );\n\n // Render input form\n const renderInputForm = () => (\n
\n \n
\n
\n \n
\n Devnet\n \n Mainnet\n
\n
\n

\n Select the network you want to use for token processing\n

\n
\n\n (\n \n Token Address\n \n \n \n \n \n )}\n />\n\n (\n \n Recipients\n \n \n \n \n \n )}\n />\n\n (\n \n Token Amount (per recipient)\n \n field.onChange(Number(e.target.value))}\n disabled={isSubmitting || !connected}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n \n \n )}\n />\n\n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Distributing Tokens...\n \n ) : (\n \"Distribute Tokens\"\n )}\n \n )}\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n default:\n return renderInputForm();\n }\n };\n\n return (\n \n \n Compressed Token Distribution\n \n \n {renderStageContent()}\n \n \n );\n}\n", + "content": "\"use client\";\r\n\r\nimport React, { useContext } from \"react\";\r\nimport { ComputeBudgetProgram, PublicKey, Transaction } from \"@solana/web3.js\";\r\nimport {\r\n CompressedTokenProgram,\r\n getTokenPoolInfos,\r\n selectTokenPoolInfo,\r\n} from \"@lightprotocol/compressed-token\";\r\nimport {\r\n bn,\r\n calculateComputeUnitPrice,\r\n createRpc,\r\n selectStateTreeInfo,\r\n} from \"@lightprotocol/stateless.js\";\r\nimport { getAssociatedTokenAddress, getAccount, createAssociatedTokenAccountInstruction } from \"@solana/spl-token\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport * as z from \"zod\";\r\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\r\nimport { toast } from \"sonner\";\r\nimport QRCode from \"react-qr-code\";\r\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from \"@/components/ui/dialog\";\r\n\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Loader2 } from \"lucide-react\";\r\nimport { Textarea } from \"@/components/ui/textarea\";\r\nimport { Switch } from \"@/components/ui/switch\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\n// Form schema - no need for privateKey anymore\r\nconst formSchema = z.object({\r\n mintAddress: z.string().min(1, \"Mint address is required\"),\r\n recipients: z.string().min(1, \"Recipient list is required\"),\r\n amount: z.number().min(1, \"Amount must be greater than 0\"),\r\n});\r\n\r\ntype FormValues = z.infer;\r\n\r\nexport function DistributeTokenForm({ className }: { className?: string }) {\r\n // Use hook from wallet adapter\r\n const { publicKey, signTransaction, connected } = useWallet();\r\n const { connection } = useConnection();\r\n const { endpoint } = useContext(ModalContext);\r\n \r\n const [isSubmitting, setIsSubmitting] = React.useState(false);\r\n const [currentStage, setCurrentStage] = React.useState<'input' | 'success' | 'error'>('input');\r\n const [error, setError] = React.useState(\"\");\r\n const [result, setResult] = React.useState<{\r\n txId: string;\r\n } | null>(null);\r\n const [isMainnet, setIsMainnet] = React.useState(true);\r\n\r\n const form = useForm({\r\n resolver: zodResolver(formSchema),\r\n defaultValues: {\r\n mintAddress: \"\",\r\n recipients: \"\",\r\n amount: 100,\r\n },\r\n });\r\n\r\n const onSubmit = async (values: FormValues) => {\r\n try {\r\n // Check if the wallet is connected\r\n if (!connected || !publicKey || !signTransaction) {\r\n toast.error(\"Please connect your wallet first\");\r\n return;\r\n }\r\n\r\n setIsSubmitting(true);\r\n setError(\"\");\r\n setCurrentStage('input');\r\n\r\n const rpcEndpoint = isMainnet \r\n ? process.env.NEXT_PUBLIC_SOLANA_RPC_URL \r\n : process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET;\r\n\r\n if (!rpcEndpoint) {\r\n throw new Error(\"RPC endpoint is not configured\");\r\n }\r\n \r\n // Create RPC connection\r\n const connection = createRpc(rpcEndpoint);\r\n\r\n // Convert mint address\r\n const mintAddress = new PublicKey(values.mintAddress);\r\n \r\n // Convert recipient list\r\n const airDropAddresses = values.recipients.split(',')\r\n .map(address => address.trim())\r\n .filter(address => address.length > 0)\r\n .map(address => new PublicKey(address));\r\n\r\n if (airDropAddresses.length === 0) {\r\n throw new Error(\"No valid recipient addresses\");\r\n }\r\n\r\n // 1. Find Associated Token Account address\r\n const ataAddress = await getAssociatedTokenAddress(mintAddress, publicKey);\r\n\r\n // 2. Check if ATA already exists\r\n let ataExists = false;\r\n try {\r\n await getAccount(connection, ataAddress);\r\n ataExists = true;\r\n } catch (e) {\r\n // ATA doesn't exist\r\n ataExists = false;\r\n }\r\n\r\n // 3. If not, create ATA with a separate transaction\r\n if (!ataExists) {\r\n console.log(\"Creating new Associated Token Account...\");\r\n const createAtaTx = new Transaction();\r\n createAtaTx.add(\r\n createAssociatedTokenAccountInstruction(\r\n publicKey, // payer\r\n ataAddress, // ATA address\r\n publicKey, // owner\r\n mintAddress // token mint\r\n )\r\n );\r\n \r\n createAtaTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;\r\n createAtaTx.feePayer = publicKey;\r\n \r\n const signedCreateAtaTx = await signTransaction(createAtaTx);\r\n const createAtaTxId = await connection.sendRawTransaction(signedCreateAtaTx.serialize());\r\n await connection.confirmTransaction({\r\n signature: createAtaTxId,\r\n blockhash: (await connection.getLatestBlockhash()).blockhash,\r\n lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,\r\n });\r\n console.log(\"ATA created with tx ID:\", createAtaTxId);\r\n }\r\n\r\n // Select new tree for each transaction\r\n const activeStateTrees = await connection.getStateTreeInfos();\r\n const treeInfo = selectStateTreeInfo(activeStateTrees);\r\n\r\n // Select token pool info\r\n const infos = await getTokenPoolInfos(connection, mintAddress);\r\n const info = selectTokenPoolInfo(infos);\r\n\r\n const amount = bn(values.amount);\r\n\r\n const instructions = [];\r\n // Adjust compute units based on the number of recipients\r\n const computeUnits = 120000 + (airDropAddresses.length > 1 ? 10000 * (airDropAddresses.length - 1) : 0);\r\n \r\n instructions.push(\r\n ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }),\r\n ComputeBudgetProgram.setComputeUnitPrice({\r\n microLamports: calculateComputeUnitPrice(20000, computeUnits),\r\n })\r\n );\r\n\r\n const compressInstruction = await CompressedTokenProgram.compress({\r\n payer: publicKey,\r\n owner: publicKey,\r\n source: ataAddress,\r\n toAddress: airDropAddresses,\r\n amount: airDropAddresses.map(() => amount),\r\n mint: mintAddress,\r\n tokenPoolInfo: info,\r\n outputStateTreeInfo: treeInfo,\r\n });\r\n instructions.push(compressInstruction);\r\n\r\n // Sign and send transaction with connected wallet\r\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();\r\n \r\n // Create transaction and add instructions\r\n const transaction = new Transaction();\r\n instructions.forEach(instruction => transaction.add(instruction));\r\n \r\n // Set blockhash and feePayer information\r\n transaction.recentBlockhash = blockhash;\r\n transaction.feePayer = publicKey;\r\n \r\n console.log(\"Signing transaction...\");\r\n \r\n try {\r\n // Sign transaction with connected wallet\r\n const signedTx = await signTransaction(transaction);\r\n \r\n console.log(\"Sending transaction...\");\r\n const txId = await connection.sendRawTransaction(signedTx.serialize());\r\n \r\n // Wait for confirmation\r\n await connection.confirmTransaction({\r\n signature: txId,\r\n blockhash,\r\n lastValidBlockHeight,\r\n });\r\n \r\n console.log(\"Transaction confirmed:\", txId);\r\n \r\n setResult({\r\n txId\r\n });\r\n setCurrentStage('success');\r\n \r\n toast.success(\"Distribution successful!\", {\r\n description: `Transaction: ${txId}`\r\n });\r\n } catch (signError: any) {\r\n console.error('Error signing transaction:', signError);\r\n \r\n // Analyze error if user canceled the transaction\r\n if (signError.message && signError.message.includes(\"canceled\")) {\r\n toast.error(\"Transaction canceled\", {\r\n description: \"You canceled the transaction\"\r\n });\r\n setError(\"You canceled the transaction\");\r\n } else {\r\n toast.error(\"Error signing transaction\", {\r\n description: signError.message || \"Unable to sign transaction\"\r\n });\r\n setError(`Error signing transaction: ${signError.message}`);\r\n }\r\n \r\n setCurrentStage('error');\r\n throw signError;\r\n }\r\n } catch (err) {\r\n console.error(err);\r\n setError(err instanceof Error ? err.message : \"An error occurred\");\r\n setCurrentStage('error');\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setCurrentStage(\"input\");\r\n setError(\"\");\r\n };\r\n\r\n // Add helper function to handle long text\r\n const truncateText = (text: string, maxLength: number = 20) => {\r\n if (text.length <= maxLength) return text;\r\n return `${text.slice(0, maxLength)}...`;\r\n };\r\n\r\n // Add helper function to copy text\r\n const copyToClipboard = (text: string) => {\r\n navigator.clipboard.writeText(text);\r\n toast.success(\"Copied to clipboard\");\r\n };\r\n\r\n // Add helper function to create Solscan link\r\n const getSolscanUrl = (type: 'tx' | 'token' | 'account', id: string) => {\r\n const cluster = isMainnet ? '' : '?cluster=devnet';\r\n return `https://solscan.io/${type}/${id}${cluster}`;\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
FieldValueAction
Token Address\r\n
\r\n {truncateText(form.getValues(\"mintAddress\") || \"\")}\r\n copyToClipboard(form.getValues(\"mintAddress\"))}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('token', form.getValues(\"mintAddress\")), '_blank')}\r\n >\r\n View\r\n \r\n
Amount Per Recipient{form.getValues(\"amount\")}\r\n copyToClipboard(form.getValues(\"amount\").toString())}\r\n >\r\n Copy\r\n \r\n
Transaction ID\r\n
\r\n {truncateText(result?.txId || \"\")}\r\n copyToClipboard(result?.txId || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('tx', result?.txId || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n QR Code to Claim Token\r\n \r\n
\r\n \r\n

\r\n Recipients can scan this QR code to claim tokens\r\n

\r\n
\r\n

Token: {truncateText(form.getValues(\"mintAddress\"), 10)}

\r\n

Amount: {form.getValues(\"amount\")}

\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n {error}\r\n
\r\n \r\n
\r\n );\r\n\r\n // Render input form\r\n const renderInputForm = () => (\r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n Devnet\r\n \r\n Mainnet\r\n
\r\n
\r\n

\r\n Select the network you want to use for token processing\r\n

\r\n
\r\n\r\n (\r\n \r\n Token Address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Recipients\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Token Amount (per recipient)\r\n \r\n field.onChange(Number(e.target.value))}\r\n disabled={isSubmitting || !connected}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Distributing Tokens...\r\n \r\n ) : (\r\n \"Distribute Tokens\"\r\n )}\r\n \r\n )}\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n default:\r\n return renderInputForm();\r\n }\r\n };\r\n\r\n return (\r\n \r\n \r\n Compressed Token Distribution\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/distribute-cToken.tsx" } diff --git a/public/r/get-nft-form.json b/public/r/get-nft-form.json index 7148f1d..9b808a4 100644 --- a/public/r/get-nft-form.json +++ b/public/r/get-nft-form.json @@ -22,7 +22,7 @@ "files": [ { "path": "components/ui/murphy/get-nft-form.tsx", - "content": "'use client';\n\nimport { useState, useContext, useEffect } from 'react';\nimport { Connection, PublicKey } from '@solana/web3.js';\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\nimport { useForm } from \"react-hook-form\";\nimport { ModalContext } from '@/components/providers/wallet-provider';\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, Search, RefreshCw } from \"lucide-react\";\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\n\nexport async function getNFT(\n connection: Connection,\n assetId: string\n) {\n try {\n const response = await connection.getAccountInfo(new PublicKey(assetId));\n \n if (!response) {\n throw new Error('NFT not found');\n }\n \n return {\n address: assetId,\n data: response.data,\n lamports: response.lamports,\n owner: response.owner.toBase58()\n };\n } catch (error: any) {\n console.error(\"Get NFT error:\", error);\n throw new Error(`Unable to retrieve NFT information: ${error.message}`);\n }\n}\n\n// Type for NFT form values\ntype NFTFormValues = {\n nftAddress: string;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate NFT address\n if (!data.nftAddress) {\n errors.nftAddress = {\n type: \"required\",\n message: \"NFT address is required\",\n };\n }\n\n try {\n // Validate address format\n if (data.nftAddress) {\n new PublicKey(data.nftAddress);\n }\n } catch (err) {\n errors.nftAddress = {\n type: \"pattern\",\n message: \"Invalid Solana address\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport function GetNFT({ className }: { className?: string }) {\n // Hooks\n const { connection } = useConnection();\n const { connected, publicKey } = useWallet();\n const { endpoint, switchToNextEndpoint } = useContext(ModalContext);\n \n // State\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [nftData, setNftData] = useState(null);\n const [nftMetadata, setNftMetadata] = useState(null);\n const [isLoadingMetadata, setIsLoadingMetadata] = useState(false);\n const [error, setError] = useState(null);\n const [mounted, setMounted] = useState(false);\n const [ownedNfts, setOwnedNfts] = useState([]);\n const [isLoadingOwned, setIsLoadingOwned] = useState(false);\n const [currentStage, setCurrentStage] = useState('input'); // input, loading, success, error\n const [network, setNetwork] = useState('devnet');\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n nftAddress: \"\",\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n // Load user's NFT list when wallet is connected\n useEffect(() => {\n if (connected && publicKey) {\n fetchOwnedNFTs();\n } else {\n setOwnedNfts([]);\n }\n }, [connected, publicKey]);\n\n // Fetch metadata when NFT data is loaded\n useEffect(() => {\n const uri = nftData ? extractUriFromBuffer(nftData) : null;\n \n if (uri) {\n fetchMetadata(uri);\n } else if (nftData && nftData.address === \"Gno3oKzAFbGZQio8bCsmjfooRmYBezbVuWHnVDtZdLd3\") {\n // Fallback for specific NFT if URI extraction fails\n const hardcodedUri = \"https://r3qqzpk2ur7p46ud3xg4pyfm4pz6ko2g4bewsyxs3pwjepuaafta.arweave.net/juEMvVqkfv56g93Nx-Cs4_PlO0bgSWli8tvskj6AAWY\";\n fetchMetadata(hardcodedUri);\n } else {\n setNftMetadata(null);\n }\n }, [nftData]);\n\n const extractUriFromBuffer = (data: any) => {\n try {\n if (!data || !data.data) {\n return null;\n }\n \n // Determine data format\n let bufferData;\n \n if (data.data instanceof Uint8Array) {\n // Case 1: data.data is a direct Uint8Array\n bufferData = Array.from(data.data);\n } else if (data.data.type === \"Buffer\" && Array.isArray(data.data.data)) {\n // Case 2: data.data is an object with type \"Buffer\" and data array\n bufferData = data.data.data;\n } else {\n return null;\n }\n \n // Find the start position of the URI (look for \"https://\")\n let startIndex = -1;\n for (let i = 0; i < bufferData.length - 7; i++) {\n if (\n bufferData[i] === 104 && // h\n bufferData[i + 1] === 116 && // t\n bufferData[i + 2] === 116 && // t\n bufferData[i + 3] === 112 && // p\n bufferData[i + 4] === 115 && // s\n bufferData[i + 5] === 58 && // :\n bufferData[i + 6] === 47 && // /\n bufferData[i + 7] === 47 // /\n ) {\n startIndex = i;\n break;\n }\n }\n \n if (startIndex === -1) {\n return null;\n }\n \n // Read URI until null terminator\n let uri = '';\n for (let i = startIndex; i < bufferData.length; i++) {\n if (bufferData[i] === 0) {\n break;\n }\n uri += String.fromCharCode(bufferData[i]);\n }\n \n return uri;\n } catch (error) {\n return null;\n }\n };\n\n const fetchMetadata = async (uri: string) => {\n try {\n setIsLoadingMetadata(true);\n \n const response = await fetch(uri, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n },\n mode: 'cors'\n });\n \n if (!response.ok) {\n throw new Error(`Failed to load metadata: ${response.status}`);\n }\n \n const metadata = await response.json();\n setNftMetadata(metadata);\n } catch (err: any) {\n // Fallback for CORS issues\n if (err.message.includes('CORS') || err.message.includes('Failed to fetch')) {\n try {\n // Hardcoded fallback for known NFT\n const hardcodedMetadata = {\n name: \"Arcium Citadel Apprentice\",\n description: \"The Arcium Citadel Apprentice NFT represents your completion of initiation into Arcium, and is your key to accessing the next fortresses, expanded contribution possibilities and more!\",\n image: \"https://arweave.net/-TIRVUsz0dh0e-GKibNitmhkUsygUiz1OW-OQ-noSqM\"\n };\n setNftMetadata(hardcodedMetadata);\n return;\n } catch (fallbackErr) {\n // Fallback failed\n }\n }\n \n setError(`Error loading metadata: ${err.message}`);\n } finally {\n setIsLoadingMetadata(false);\n }\n };\n\n const fetchOwnedNFTs = async () => {\n if (!publicKey) return;\n \n try {\n setIsLoadingOwned(true);\n \n // Make API call or use Metaplex library to get the list of NFTs\n // Example: const nfts = await getOwnedNFTs(publicKey);\n // setOwnedNfts(nfts);\n \n } catch (err) {\n console.error(\"Error loading NFTs:\", err);\n } finally {\n setIsLoadingOwned(false);\n }\n };\n\n const onSubmit = async (values: NFTFormValues) => {\n if (!values.nftAddress) {\n toast.error('Please enter NFT address');\n return;\n }\n\n try {\n setIsSubmitting(true);\n setError(null);\n setNftData(null);\n setCurrentStage('loading');\n\n const data = await getNFT(connection, values.nftAddress);\n setNftData(data);\n setCurrentStage('success');\n } catch (err: any) {\n console.error(\"Get NFT error:\", err);\n setError(err.message);\n setCurrentStage('error');\n \n toast.error(\"Failed to fetch NFT\", {\n description: err.message\n });\n \n // If query fails due to connection error, try switching to another endpoint\n if (err.message.includes('failed to fetch') || \n err.message.includes('timeout') || \n err.message.includes('429') ||\n err.message.includes('503')) {\n switchToNextEndpoint();\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n \n const viewInExplorer = () => {\n if (nftData?.address) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/token/';\n window.open(`${baseUrl}${nftData.address}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const resetForm = () => {\n form.reset();\n setNftData(null);\n setNftMetadata(null);\n setError(null);\n setCurrentStage('input');\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n {isLoadingMetadata ? (\n
\n \n

Loading NFT metadata...

\n
\n ) : (\n <>\n
\n {nftMetadata?.image ? (\n
\n {nftMetadata.name {\n e.currentTarget.src = \"https://via.placeholder.com/300?text=Image+Not+Available\";\n }} \n />\n
\n ) : (\n
\n

No image available

\n
\n )}\n \n

{nftMetadata?.name || \"NFT\"}

\n \n {nftMetadata?.description && (\n

\n {nftMetadata.description.length > 140 \n ? `${nftMetadata.description.substring(0, 140)}...` \n : nftMetadata.description}\n

\n )}\n
\n \n
\n
\n
\n Address\n {nftData.address}\n
\n \n
\n Owner\n {nftData.owner}\n
\n \n
\n Balance\n {nftData.lamports / 1000000000} SOL\n
\n \n
\n Data Size\n {nftData.data?.length || 0} bytes\n
\n
\n
\n \n
\n \n \n \n
\n \n )}\n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

NFT Not Found

\n

{error || 'Unable to retrieve NFT information. Please check the address and try again.'}

\n \n
\n );\n\n // Render loading view\n const renderLoading = () => (\n
\n
\n \n
\n

Fetching NFT

\n

Please wait while we retrieve the NFT information...

\n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n (\n \n
\n NFT Address\n
\n \n \n \n \n

\n Enter the mint address of the NFT to view detailed information\n

\n
\n )}\n />\n \n
\n
\n
\n Network\n \n {network}\n \n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Searching...\n \n ) : \"View NFT\"}\n \n )}\n
\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'loading':\n return renderLoading();\n default:\n return renderForm();\n }\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n View NFT\n Lookup and display information of NFTs on Solana\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n View NFT Information\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Lookup and display information of NFTs on Solana\n \n \n {renderStageContent()}\n \n \n );\n}", + "content": "'use client';\r\n\r\nimport { useState, useContext, useEffect } from 'react';\r\nimport { Connection, PublicKey } from '@solana/web3.js';\r\nimport { useConnection, useWallet } from '@solana/wallet-adapter-react';\r\nimport { useForm } from \"react-hook-form\";\r\nimport { ModalContext } from '@/components/providers/wallet-provider';\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, Search, RefreshCw } from \"lucide-react\";\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\n\r\nexport async function getNFT(\r\n connection: Connection,\r\n assetId: string\r\n) {\r\n try {\r\n const response = await connection.getAccountInfo(new PublicKey(assetId));\r\n \r\n if (!response) {\r\n throw new Error('NFT not found');\r\n }\r\n \r\n return {\r\n address: assetId,\r\n data: response.data,\r\n lamports: response.lamports,\r\n owner: response.owner.toBase58()\r\n };\r\n } catch (error: any) {\r\n console.error(\"Get NFT error:\", error);\r\n throw new Error(`Unable to retrieve NFT information: ${error.message}`);\r\n }\r\n}\r\n\r\n// Type for NFT form values\r\ntype NFTFormValues = {\r\n nftAddress: string;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate NFT address\r\n if (!data.nftAddress) {\r\n errors.nftAddress = {\r\n type: \"required\",\r\n message: \"NFT address is required\",\r\n };\r\n }\r\n\r\n try {\r\n // Validate address format\r\n if (data.nftAddress) {\r\n new PublicKey(data.nftAddress);\r\n }\r\n } catch (err) {\r\n errors.nftAddress = {\r\n type: \"pattern\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport function GetNFT({ className }: { className?: string }) {\r\n // Hooks\r\n const { connection } = useConnection();\r\n const { connected, publicKey } = useWallet();\r\n const { endpoint, switchToNextEndpoint } = useContext(ModalContext);\r\n \r\n // State\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [nftData, setNftData] = useState(null);\r\n const [nftMetadata, setNftMetadata] = useState(null);\r\n const [isLoadingMetadata, setIsLoadingMetadata] = useState(false);\r\n const [error, setError] = useState(null);\r\n const [mounted, setMounted] = useState(false);\r\n const [ownedNfts, setOwnedNfts] = useState([]);\r\n const [isLoadingOwned, setIsLoadingOwned] = useState(false);\r\n const [currentStage, setCurrentStage] = useState('input'); // input, loading, success, error\r\n const [network, setNetwork] = useState('devnet');\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n nftAddress: \"\",\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n // Load user's NFT list when wallet is connected\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n fetchOwnedNFTs();\r\n } else {\r\n setOwnedNfts([]);\r\n }\r\n }, [connected, publicKey]);\r\n\r\n // Fetch metadata when NFT data is loaded\r\n useEffect(() => {\r\n const uri = nftData ? extractUriFromBuffer(nftData) : null;\r\n \r\n if (uri) {\r\n fetchMetadata(uri);\r\n } else if (nftData && nftData.address === \"Gno3oKzAFbGZQio8bCsmjfooRmYBezbVuWHnVDtZdLd3\") {\r\n // Fallback for specific NFT if URI extraction fails\r\n const hardcodedUri = \"https://r3qqzpk2ur7p46ud3xg4pyfm4pz6ko2g4bewsyxs3pwjepuaafta.arweave.net/juEMvVqkfv56g93Nx-Cs4_PlO0bgSWli8tvskj6AAWY\";\r\n fetchMetadata(hardcodedUri);\r\n } else {\r\n setNftMetadata(null);\r\n }\r\n }, [nftData]);\r\n\r\n const extractUriFromBuffer = (data: any) => {\r\n try {\r\n if (!data || !data.data) {\r\n return null;\r\n }\r\n \r\n // Determine data format\r\n let bufferData;\r\n \r\n if (data.data instanceof Uint8Array) {\r\n // Case 1: data.data is a direct Uint8Array\r\n bufferData = Array.from(data.data);\r\n } else if (data.data.type === \"Buffer\" && Array.isArray(data.data.data)) {\r\n // Case 2: data.data is an object with type \"Buffer\" and data array\r\n bufferData = data.data.data;\r\n } else {\r\n return null;\r\n }\r\n \r\n // Find the start position of the URI (look for \"https://\")\r\n let startIndex = -1;\r\n for (let i = 0; i < bufferData.length - 7; i++) {\r\n if (\r\n bufferData[i] === 104 && // h\r\n bufferData[i + 1] === 116 && // t\r\n bufferData[i + 2] === 116 && // t\r\n bufferData[i + 3] === 112 && // p\r\n bufferData[i + 4] === 115 && // s\r\n bufferData[i + 5] === 58 && // :\r\n bufferData[i + 6] === 47 && // /\r\n bufferData[i + 7] === 47 // /\r\n ) {\r\n startIndex = i;\r\n break;\r\n }\r\n }\r\n \r\n if (startIndex === -1) {\r\n return null;\r\n }\r\n \r\n // Read URI until null terminator\r\n let uri = '';\r\n for (let i = startIndex; i < bufferData.length; i++) {\r\n if (bufferData[i] === 0) {\r\n break;\r\n }\r\n uri += String.fromCharCode(bufferData[i]);\r\n }\r\n \r\n return uri;\r\n } catch (error) {\r\n return null;\r\n }\r\n };\r\n\r\n const fetchMetadata = async (uri: string) => {\r\n try {\r\n setIsLoadingMetadata(true);\r\n \r\n const response = await fetch(uri, {\r\n method: 'GET',\r\n headers: {\r\n 'Accept': 'application/json',\r\n },\r\n mode: 'cors'\r\n });\r\n \r\n if (!response.ok) {\r\n throw new Error(`Failed to load metadata: ${response.status}`);\r\n }\r\n \r\n const metadata = await response.json();\r\n setNftMetadata(metadata);\r\n } catch (err: any) {\r\n // Fallback for CORS issues\r\n if (err.message.includes('CORS') || err.message.includes('Failed to fetch')) {\r\n try {\r\n // Hardcoded fallback for known NFT\r\n const hardcodedMetadata = {\r\n name: \"Arcium Citadel Apprentice\",\r\n description: \"The Arcium Citadel Apprentice NFT represents your completion of initiation into Arcium, and is your key to accessing the next fortresses, expanded contribution possibilities and more!\",\r\n image: \"https://arweave.net/-TIRVUsz0dh0e-GKibNitmhkUsygUiz1OW-OQ-noSqM\"\r\n };\r\n setNftMetadata(hardcodedMetadata);\r\n return;\r\n } catch (fallbackErr) {\r\n // Fallback failed\r\n }\r\n }\r\n \r\n setError(`Error loading metadata: ${err.message}`);\r\n } finally {\r\n setIsLoadingMetadata(false);\r\n }\r\n };\r\n\r\n const fetchOwnedNFTs = async () => {\r\n if (!publicKey) return;\r\n \r\n try {\r\n setIsLoadingOwned(true);\r\n \r\n // Make API call or use Metaplex library to get the list of NFTs\r\n // Example: const nfts = await getOwnedNFTs(publicKey);\r\n // setOwnedNfts(nfts);\r\n \r\n } catch (err) {\r\n console.error(\"Error loading NFTs:\", err);\r\n } finally {\r\n setIsLoadingOwned(false);\r\n }\r\n };\r\n\r\n const onSubmit = async (values: NFTFormValues) => {\r\n if (!values.nftAddress) {\r\n toast.error('Please enter NFT address');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setError(null);\r\n setNftData(null);\r\n setCurrentStage('loading');\r\n\r\n const data = await getNFT(connection, values.nftAddress);\r\n setNftData(data);\r\n setCurrentStage('success');\r\n } catch (err: any) {\r\n console.error(\"Get NFT error:\", err);\r\n setError(err.message);\r\n setCurrentStage('error');\r\n \r\n toast.error(\"Failed to fetch NFT\", {\r\n description: err.message\r\n });\r\n \r\n // If query fails due to connection error, try switching to another endpoint\r\n if (err.message.includes('failed to fetch') || \r\n err.message.includes('timeout') || \r\n err.message.includes('429') ||\r\n err.message.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n \r\n const viewInExplorer = () => {\r\n if (nftData?.address) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/token/';\r\n window.open(`${baseUrl}${nftData.address}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const resetForm = () => {\r\n form.reset();\r\n setNftData(null);\r\n setNftMetadata(null);\r\n setError(null);\r\n setCurrentStage('input');\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n {isLoadingMetadata ? (\r\n
\r\n \r\n

Loading NFT metadata...

\r\n
\r\n ) : (\r\n <>\r\n
\r\n {nftMetadata?.image ? (\r\n
\r\n {nftMetadata.name {\r\n e.currentTarget.src = \"https://via.placeholder.com/300?text=Image+Not+Available\";\r\n }} \r\n />\r\n
\r\n ) : (\r\n
\r\n

No image available

\r\n
\r\n )}\r\n \r\n

{nftMetadata?.name || \"NFT\"}

\r\n \r\n {nftMetadata?.description && (\r\n

\r\n {nftMetadata.description.length > 140 \r\n ? `${nftMetadata.description.substring(0, 140)}...` \r\n : nftMetadata.description}\r\n

\r\n )}\r\n
\r\n \r\n
\r\n
\r\n
\r\n Address\r\n {nftData.address}\r\n
\r\n \r\n
\r\n Owner\r\n {nftData.owner}\r\n
\r\n \r\n
\r\n Balance\r\n {nftData.lamports / 1000000000} SOL\r\n
\r\n \r\n
\r\n Data Size\r\n {nftData.data?.length || 0} bytes\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n )}\r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

NFT Not Found

\r\n

{error || 'Unable to retrieve NFT information. Please check the address and try again.'}

\r\n \r\n
\r\n );\r\n\r\n // Render loading view\r\n const renderLoading = () => (\r\n
\r\n
\r\n \r\n
\r\n

Fetching NFT

\r\n

Please wait while we retrieve the NFT information...

\r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n (\r\n \r\n
\r\n NFT Address\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Enter the mint address of the NFT to view detailed information\r\n

\r\n
\r\n )}\r\n />\r\n \r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Searching...\r\n \r\n ) : \"View NFT\"}\r\n \r\n )}\r\n
\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'loading':\r\n return renderLoading();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n View NFT\r\n Lookup and display information of NFTs on Solana\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n View NFT Information\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Lookup and display information of NFTs on Solana\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}", "type": "registry:component", "target": "components/ui/murphy/get-nft-form.tsx" } diff --git a/public/r/inline-txn-status.json b/public/r/inline-txn-status.json new file mode 100644 index 0000000..b4f3e18 --- /dev/null +++ b/public/r/inline-txn-status.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "inline-txn-status", + "type": "registry:block", + "title": "Inline icon or badge to show transaction status (loading, success, error).", + "dependencies": [ + "lucide-react" + ], + "registryDependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/inline-txn-status.tsx", + "content": "\"use client\"\r\n\r\nimport { CheckCircle, XCircle, Loader2, Clock } from \"lucide-react\"\r\nimport { Badge } from \"@/components/ui/badge\"\r\nimport { cn } from \"@/lib/utils\"\r\nimport { TransactionStatus } from \"@/types/transaction\"\r\n\r\ninterface InlineTxnStatusProps {\r\n status: TransactionStatus[\"status\"]\r\n size?: \"sm\" | \"md\" | \"lg\"\r\n showText?: boolean\r\n className?: string\r\n}\r\n\r\nexport function InlineTxnStatus({\r\n status,\r\n size = \"md\",\r\n showText = true,\r\n className,\r\n}: InlineTxnStatusProps) {\r\n const getStatusConfig = () => {\r\n switch (status) {\r\n case \"success\":\r\n return {\r\n icon: CheckCircle,\r\n text: \"Success\",\r\n variant: \"default\" as const,\r\n className: \"bg-green-100 text-green-800 border border-green-200 dark:bg-green-900 dark:text-green-100 dark:border-green-700\",\r\n }\r\n case \"error\":\r\n return {\r\n icon: XCircle,\r\n text: \"Failed\",\r\n variant: \"destructive\" as const,\r\n className: \"bg-red-100 text-red-800 border border-red-200 dark:bg-red-900 dark:text-red-100 dark:border-red-700\",\r\n }\r\n case \"preparing\":\r\n case \"signing\":\r\n case \"sending\":\r\n case \"confirming\":\r\n return {\r\n icon: Loader2,\r\n text: \"Processing\",\r\n variant: \"secondary\" as const,\r\n className: \"bg-blue-100 text-blue-800 border border-blue-200 dark:bg-blue-900 dark:text-blue-100 dark:border-blue-700\",\r\n animate: true,\r\n }\r\n default:\r\n return {\r\n icon: Clock,\r\n text: \"Pending\",\r\n variant: \"outline\" as const,\r\n className: \"bg-gray-100 text-gray-800 border border-gray-200 dark:bg-gray-900 dark:text-gray-100 dark:border-gray-700\",\r\n }\r\n }\r\n }\r\n\r\n const config = getStatusConfig()\r\n const Icon = config.icon\r\n\r\n const iconSize = {\r\n sm: \"w-3 h-3\",\r\n md: \"w-4 h-4\",\r\n lg: \"w-5 h-5\",\r\n }[size]\r\n\r\n const textSize = {\r\n sm: \"text-xs\",\r\n md: \"text-sm\",\r\n lg: \"text-base\",\r\n }[size]\r\n\r\n return (\r\n \r\n \r\n {showText && {config.text}}\r\n \r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/inline-txn-status.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/mint-cToken.json b/public/r/mint-cToken.json index f80637e..2771019 100644 --- a/public/r/mint-cToken.json +++ b/public/r/mint-cToken.json @@ -24,7 +24,7 @@ "files": [ { "path": "components/ui/murphy/mint-cToken.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport { Keypair, PublicKey, Signer, Transaction, sendAndConfirmTransaction, SystemProgram } from '@solana/web3.js';\nimport { createRpc } from '@lightprotocol/stateless.js';\nimport {\n createMint,\n getOrCreateAssociatedTokenAccount,\n mintTo,\n} from \"@solana/spl-token\";\nimport { createTokenPool } from '@lightprotocol/compressed-token';\nimport { \n createMetadataAccountV3,\n MPL_TOKEN_METADATA_PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID,\n mplTokenMetadata,\n} from '@metaplex-foundation/mpl-token-metadata';\nimport { createSignerFromKeypair, publicKey } from '@metaplex-foundation/umi';\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\nimport { web3JsRpc } from '@metaplex-foundation/umi-rpc-web3js';\nimport bs58 from \"bs58\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as z from \"zod\";\n\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { Loader2, Upload } from \"lucide-react\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Label } from \"@/components/ui/label\";\n\n// Form schema\nconst formSchema = z.object({\n privateKey: z.string().min(1, \"Private key is required\"),\n tokenName: z.string().min(1, \"Token name is required\"),\n tokenSymbol: z.string().min(1, \"Token symbol is required\").max(10, \"Symbol must be less than 10 characters\"),\n tokenDecimals: z.number().min(0).max(9, \"Decimals must be between 0 and 9\"),\n tokenSupply: z.number().min(1, \"Supply must be greater than 0\"),\n tokenDescription: z.string().optional(),\n tokenImage: z.string().optional(),\n tokenUri: z.string().optional(),\n});\n\ntype FormValues = z.infer;\n\nexport function MintTokenForm() {\n const [isSubmitting, setIsSubmitting] = React.useState(false);\n const [currentStage, setCurrentStage] = React.useState<'input' | 'success' | 'error'>('input');\n const [error, setError] = React.useState(\"\");\n const [isMainnet, setIsMainnet] = React.useState(false);\n const [result, setResult] = React.useState<{\n mint: string;\n poolTxId: string;\n ata: string;\n mintToTxId: string;\n metadataTxId: string;\n } | null>(null);\n const [imagePreview, setImagePreview] = React.useState(\"\");\n\n const form = useForm({\n resolver: zodResolver(formSchema),\n defaultValues: {\n privateKey: \"\",\n tokenName: \"\",\n tokenSymbol: \"\",\n tokenDecimals: 9,\n tokenSupply: 1000000000,\n tokenDescription: \"\",\n tokenImage: \"\",\n tokenUri: \"\",\n },\n });\n\n const handleImageChange = (e: React.ChangeEvent) => {\n const file = e.target.files?.[0];\n if (file) {\n const reader = new FileReader();\n reader.onloadend = () => {\n const base64String = reader.result as string;\n setImagePreview(base64String);\n form.setValue(\"tokenImage\", base64String);\n };\n reader.readAsDataURL(file);\n }\n };\n\n const createMetadata = async (\n connection: any,\n payer: Keypair,\n mint: PublicKey,\n metadata: {\n name: string;\n symbol: string;\n uri: string;\n }\n ) => {\n const metadataProgramId = new PublicKey(TOKEN_METADATA_PROGRAM_ID);\n const [metadataAddress] = PublicKey.findProgramAddressSync(\n [\n Buffer.from('metadata'),\n metadataProgramId.toBytes(),\n mint.toBytes(),\n ],\n metadataProgramId\n );\n\n // Create a Umi instance\n const umi = createUmi(connection.rpcEndpoint)\n .use(web3JsRpc(connection))\n .use(mplTokenMetadata());\n\n // Create a signeridentity from the payer Keypair\n const signerIdentity = createSignerFromKeypair(umi, { \n publicKey: publicKey(payer.publicKey.toBase58()),\n secretKey: payer.secretKey \n });\n umi.use({\n install(umiContext) {\n umiContext.identity = signerIdentity;\n umiContext.payer = signerIdentity;\n }\n });\n\n const umiMintPublicKey = publicKey(mint.toBase58());\n const umiMetadataPda = publicKey(metadataAddress.toBase58());\n const umiSystemProgram = publicKey(SystemProgram.programId.toBase58());\n\n const createMetadataInstructionBuilder = createMetadataAccountV3(\n umi, \n {\n metadata: umiMetadataPda,\n mint: umiMintPublicKey,\n mintAuthority: signerIdentity, \n payer: signerIdentity, \n updateAuthority: signerIdentity, \n systemProgram: umiSystemProgram,\n \n data: {\n name: metadata.name,\n symbol: metadata.symbol,\n uri: metadata.uri,\n sellerFeeBasisPoints: 0,\n creators: null,\n collection: null,\n uses: null,\n },\n isMutable: true,\n collectionDetails: null,\n }\n );\n\n const { signature } = await createMetadataInstructionBuilder.sendAndConfirm(umi, {\n confirm: { commitment: 'confirmed' }\n });\n \n // The signature from Umi is a Uint8Array, convert to base58 string for consistency\n return bs58.encode(signature); \n };\n\n const onSubmit = async (values: FormValues) => {\n try {\n setIsSubmitting(true);\n setError(\"\");\n\n const rpcEndpoint = isMainnet \n ? process.env.NEXT_PUBLIC_SOLANA_RPC_URL \n : process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET;\n\n if (!rpcEndpoint) {\n throw new Error(\"RPC endpoint not configured\");\n }\n\n // Create keypair from private key\n const PAYER = Keypair.fromSecretKey(bs58.decode(values.privateKey));\n \n // Create RPC connection\n const connection = createRpc(rpcEndpoint);\n\n // Create mint\n const mint = await createMint(\n connection,\n PAYER,\n PAYER.publicKey,\n null,\n values.tokenDecimals\n );\n\n // Create metadata\n const metadataTxId = await createMetadata(\n connection,\n PAYER,\n mint,\n {\n name: values.tokenName,\n symbol: values.tokenSymbol,\n uri: values.tokenUri || \"\",\n }\n );\n\n // Register mint for compression\n const poolTxId = await createTokenPool(connection, PAYER, mint);\n\n // Create associated token account\n const ata = await getOrCreateAssociatedTokenAccount(\n connection,\n PAYER,\n mint,\n PAYER.publicKey\n );\n\n // Calculate supply with decimals\n const supply = values.tokenSupply * Math.pow(10, values.tokenDecimals);\n\n // Mint tokens\n const mintToTxId = await mintTo(\n connection,\n PAYER,\n mint,\n ata.address,\n PAYER.publicKey,\n supply\n );\n\n setResult({\n mint: mint.toBase58(),\n poolTxId,\n ata: ata.address.toBase58(),\n mintToTxId,\n metadataTxId,\n });\n setCurrentStage('success');\n } catch (err) {\n console.error(err);\n setError(err instanceof Error ? err.message : \"An error occurred\");\n setCurrentStage('error');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setCurrentStage(\"input\");\n setError(\"\");\n setImagePreview(\"\");\n };\n\n // Add helper function to handle long text\n const truncateText = (text: string, maxLength: number = 20) => {\n if (text.length <= maxLength) return text;\n return `${text.slice(0, maxLength)}...`;\n };\n\n // Add helper function to copy text\n const copyToClipboard = (text: string) => {\n navigator.clipboard.writeText(text);\n };\n\n // Add helper function to create Solscan link\n const getSolscanUrl = (type: 'tx' | 'token' | 'account', id: string) => {\n const cluster = isMainnet ? '' : '?cluster=devnet';\n return `https://solscan.io/${type}/${id}${cluster}`;\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
FieldValueAction
Token Name{form.getValues(\"tokenName\")}\n copyToClipboard(form.getValues(\"tokenName\"))}\n >\n Copy\n \n
Token Symbol{form.getValues(\"tokenSymbol\")}\n copyToClipboard(form.getValues(\"tokenSymbol\"))}\n >\n Copy\n \n
Mint Address\n
\n {truncateText(result?.mint || \"\")}\n copyToClipboard(result?.mint || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('token', result?.mint || \"\"), '_blank')}\n >\n View\n \n
Pool Transaction\n
\n {truncateText(result?.poolTxId || \"\")}\n copyToClipboard(result?.poolTxId || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('tx', result?.poolTxId || \"\"), '_blank')}\n >\n View\n \n
Token Account\n
\n {truncateText(result?.ata || \"\")}\n copyToClipboard(result?.ata || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('account', result?.ata || \"\"), '_blank')}\n >\n View\n \n
Mint Transaction\n
\n {truncateText(result?.mintToTxId || \"\")}\n copyToClipboard(result?.mintToTxId || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('tx', result?.mintToTxId || \"\"), '_blank')}\n >\n View\n \n
Metadata Transaction\n
\n {truncateText(result?.metadataTxId || \"\")}\n copyToClipboard(result?.metadataTxId || \"\")}\n >\n Copy\n \n
\n
\n window.open(getSolscanUrl('tx', result?.metadataTxId || \"\"), '_blank')}\n >\n View\n \n
\n
\n
\n\n
\n \n \n
\n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n {error}\n
\n \n
\n );\n\n // Render input form\n const renderInputForm = () => (\n
\n \n
\n
\n \n
\n Devnet\n \n Mainnet\n
\n
\n

\n Select network to create token on\n

\n
\n\n
\n (\n \n Token Name\n \n \n \n \n \n )}\n />\n\n (\n \n Token Symbol\n \n \n \n \n \n )}\n />\n
\n\n
\n (\n \n Decimals\n \n field.onChange(Number(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n \n \n )}\n />\n\n (\n \n Total Supply\n \n field.onChange(Number(e.target.value))}\n disabled={isSubmitting}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n \n \n )}\n />\n
\n\n (\n \n Description\n \n \n \n \n \n )}\n />\n\n (\n \n Token Image\n \n
\n \n \n \n Upload Image\n \n {imagePreview && (\n \n )}\n
\n
\n \n
\n )}\n />\n\n (\n \n Token URI\n \n \n \n \n \n )}\n />\n\n (\n \n Private Key\n \n \n \n \n
\n ⚠️ Warning: Do not use your main wallet containing large amounts of money. Create a new wallet or use a separate wallet for this purpose to ensure asset safety.\n
\n
\n )}\n />\n\n \n {isSubmitting ? (\n <>\n \n Creating Token on {isMainnet ? \"Mainnet\" : \"Devnet\"}...\n \n ) : (\n `Create Token on ${isMainnet ? \"Mainnet\" : \"Devnet\"}`\n )}\n \n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n default:\n return renderInputForm();\n }\n };\n\n return (\n \n \n Create Compressed Token\n \n \n {renderStageContent()}\n \n \n );\n}", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\nimport { Keypair, PublicKey, Signer, Transaction, sendAndConfirmTransaction, SystemProgram } from '@solana/web3.js';\r\nimport { createRpc } from '@lightprotocol/stateless.js';\r\nimport {\r\n createMint,\r\n getOrCreateAssociatedTokenAccount,\r\n mintTo,\r\n} from \"@solana/spl-token\";\r\nimport { createTokenPool } from '@lightprotocol/compressed-token';\r\nimport { \r\n createMetadataAccountV3,\r\n MPL_TOKEN_METADATA_PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID,\r\n mplTokenMetadata,\r\n} from '@metaplex-foundation/mpl-token-metadata';\r\nimport { createSignerFromKeypair, publicKey } from '@metaplex-foundation/umi';\r\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\r\nimport { web3JsRpc } from '@metaplex-foundation/umi-rpc-web3js';\r\nimport bs58 from \"bs58\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport * as z from \"zod\";\r\n\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Loader2, Upload } from \"lucide-react\";\r\nimport { Textarea } from \"@/components/ui/textarea\";\r\nimport { Switch } from \"@/components/ui/switch\";\r\nimport { Label } from \"@/components/ui/label\";\r\n\r\n// Form schema\r\nconst formSchema = z.object({\r\n privateKey: z.string().min(1, \"Private key is required\"),\r\n tokenName: z.string().min(1, \"Token name is required\"),\r\n tokenSymbol: z.string().min(1, \"Token symbol is required\").max(10, \"Symbol must be less than 10 characters\"),\r\n tokenDecimals: z.number().min(0).max(9, \"Decimals must be between 0 and 9\"),\r\n tokenSupply: z.number().min(1, \"Supply must be greater than 0\"),\r\n tokenDescription: z.string().optional(),\r\n tokenImage: z.string().optional(),\r\n tokenUri: z.string().optional(),\r\n});\r\n\r\ntype FormValues = z.infer;\r\n\r\nexport function MintTokenForm() {\r\n const [isSubmitting, setIsSubmitting] = React.useState(false);\r\n const [currentStage, setCurrentStage] = React.useState<'input' | 'success' | 'error'>('input');\r\n const [error, setError] = React.useState(\"\");\r\n const [isMainnet, setIsMainnet] = React.useState(false);\r\n const [result, setResult] = React.useState<{\r\n mint: string;\r\n poolTxId: string;\r\n ata: string;\r\n mintToTxId: string;\r\n metadataTxId: string;\r\n } | null>(null);\r\n const [imagePreview, setImagePreview] = React.useState(\"\");\r\n\r\n const form = useForm({\r\n resolver: zodResolver(formSchema),\r\n defaultValues: {\r\n privateKey: \"\",\r\n tokenName: \"\",\r\n tokenSymbol: \"\",\r\n tokenDecimals: 9,\r\n tokenSupply: 1000000000,\r\n tokenDescription: \"\",\r\n tokenImage: \"\",\r\n tokenUri: \"\",\r\n },\r\n });\r\n\r\n const handleImageChange = (e: React.ChangeEvent) => {\r\n const file = e.target.files?.[0];\r\n if (file) {\r\n const reader = new FileReader();\r\n reader.onloadend = () => {\r\n const base64String = reader.result as string;\r\n setImagePreview(base64String);\r\n form.setValue(\"tokenImage\", base64String);\r\n };\r\n reader.readAsDataURL(file);\r\n }\r\n };\r\n\r\n const createMetadata = async (\r\n connection: any,\r\n payer: Keypair,\r\n mint: PublicKey,\r\n metadata: {\r\n name: string;\r\n symbol: string;\r\n uri: string;\r\n }\r\n ) => {\r\n const metadataProgramId = new PublicKey(TOKEN_METADATA_PROGRAM_ID);\r\n const [metadataAddress] = PublicKey.findProgramAddressSync(\r\n [\r\n Buffer.from('metadata'),\r\n metadataProgramId.toBytes(),\r\n mint.toBytes(),\r\n ],\r\n metadataProgramId\r\n );\r\n\r\n // Create a Umi instance\r\n const umi = createUmi(connection.rpcEndpoint)\r\n .use(web3JsRpc(connection))\r\n .use(mplTokenMetadata());\r\n\r\n // Create a signeridentity from the payer Keypair\r\n const signerIdentity = createSignerFromKeypair(umi, { \r\n publicKey: publicKey(payer.publicKey.toBase58()),\r\n secretKey: payer.secretKey \r\n });\r\n umi.use({\r\n install(umiContext) {\r\n umiContext.identity = signerIdentity;\r\n umiContext.payer = signerIdentity;\r\n }\r\n });\r\n\r\n const umiMintPublicKey = publicKey(mint.toBase58());\r\n const umiMetadataPda = publicKey(metadataAddress.toBase58());\r\n const umiSystemProgram = publicKey(SystemProgram.programId.toBase58());\r\n\r\n const createMetadataInstructionBuilder = createMetadataAccountV3(\r\n umi, \r\n {\r\n metadata: umiMetadataPda,\r\n mint: umiMintPublicKey,\r\n mintAuthority: signerIdentity, \r\n payer: signerIdentity, \r\n updateAuthority: signerIdentity, \r\n systemProgram: umiSystemProgram,\r\n \r\n data: {\r\n name: metadata.name,\r\n symbol: metadata.symbol,\r\n uri: metadata.uri,\r\n sellerFeeBasisPoints: 0,\r\n creators: null,\r\n collection: null,\r\n uses: null,\r\n },\r\n isMutable: true,\r\n collectionDetails: null,\r\n }\r\n );\r\n\r\n const { signature } = await createMetadataInstructionBuilder.sendAndConfirm(umi, {\r\n confirm: { commitment: 'confirmed' }\r\n });\r\n \r\n // The signature from Umi is a Uint8Array, convert to base58 string for consistency\r\n return bs58.encode(signature); \r\n };\r\n\r\n const onSubmit = async (values: FormValues) => {\r\n try {\r\n setIsSubmitting(true);\r\n setError(\"\");\r\n\r\n const rpcEndpoint = isMainnet \r\n ? process.env.NEXT_PUBLIC_SOLANA_RPC_URL \r\n : process.env.NEXT_PUBLIC_SOLANA_RPC_URL_DEVNET;\r\n\r\n if (!rpcEndpoint) {\r\n throw new Error(\"RPC endpoint not configured\");\r\n }\r\n\r\n // Create keypair from private key\r\n const PAYER = Keypair.fromSecretKey(bs58.decode(values.privateKey));\r\n \r\n // Create RPC connection\r\n const connection = createRpc(rpcEndpoint);\r\n\r\n // Create mint\r\n const mint = await createMint(\r\n connection,\r\n PAYER,\r\n PAYER.publicKey,\r\n null,\r\n values.tokenDecimals\r\n );\r\n\r\n // Create metadata\r\n const metadataTxId = await createMetadata(\r\n connection,\r\n PAYER,\r\n mint,\r\n {\r\n name: values.tokenName,\r\n symbol: values.tokenSymbol,\r\n uri: values.tokenUri || \"\",\r\n }\r\n );\r\n\r\n // Register mint for compression\r\n const poolTxId = await createTokenPool(connection, PAYER, mint);\r\n\r\n // Create associated token account\r\n const ata = await getOrCreateAssociatedTokenAccount(\r\n connection,\r\n PAYER,\r\n mint,\r\n PAYER.publicKey\r\n );\r\n\r\n // Calculate supply with decimals\r\n const supply = values.tokenSupply * Math.pow(10, values.tokenDecimals);\r\n\r\n // Mint tokens\r\n const mintToTxId = await mintTo(\r\n connection,\r\n PAYER,\r\n mint,\r\n ata.address,\r\n PAYER.publicKey,\r\n supply\r\n );\r\n\r\n setResult({\r\n mint: mint.toBase58(),\r\n poolTxId,\r\n ata: ata.address.toBase58(),\r\n mintToTxId,\r\n metadataTxId,\r\n });\r\n setCurrentStage('success');\r\n } catch (err) {\r\n console.error(err);\r\n setError(err instanceof Error ? err.message : \"An error occurred\");\r\n setCurrentStage('error');\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setCurrentStage(\"input\");\r\n setError(\"\");\r\n setImagePreview(\"\");\r\n };\r\n\r\n // Add helper function to handle long text\r\n const truncateText = (text: string, maxLength: number = 20) => {\r\n if (text.length <= maxLength) return text;\r\n return `${text.slice(0, maxLength)}...`;\r\n };\r\n\r\n // Add helper function to copy text\r\n const copyToClipboard = (text: string) => {\r\n navigator.clipboard.writeText(text);\r\n };\r\n\r\n // Add helper function to create Solscan link\r\n const getSolscanUrl = (type: 'tx' | 'token' | 'account', id: string) => {\r\n const cluster = isMainnet ? '' : '?cluster=devnet';\r\n return `https://solscan.io/${type}/${id}${cluster}`;\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
FieldValueAction
Token Name{form.getValues(\"tokenName\")}\r\n copyToClipboard(form.getValues(\"tokenName\"))}\r\n >\r\n Copy\r\n \r\n
Token Symbol{form.getValues(\"tokenSymbol\")}\r\n copyToClipboard(form.getValues(\"tokenSymbol\"))}\r\n >\r\n Copy\r\n \r\n
Mint Address\r\n
\r\n {truncateText(result?.mint || \"\")}\r\n copyToClipboard(result?.mint || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('token', result?.mint || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
Pool Transaction\r\n
\r\n {truncateText(result?.poolTxId || \"\")}\r\n copyToClipboard(result?.poolTxId || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('tx', result?.poolTxId || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
Token Account\r\n
\r\n {truncateText(result?.ata || \"\")}\r\n copyToClipboard(result?.ata || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('account', result?.ata || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
Mint Transaction\r\n
\r\n {truncateText(result?.mintToTxId || \"\")}\r\n copyToClipboard(result?.mintToTxId || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('tx', result?.mintToTxId || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
Metadata Transaction\r\n
\r\n {truncateText(result?.metadataTxId || \"\")}\r\n copyToClipboard(result?.metadataTxId || \"\")}\r\n >\r\n Copy\r\n \r\n
\r\n
\r\n window.open(getSolscanUrl('tx', result?.metadataTxId || \"\"), '_blank')}\r\n >\r\n View\r\n \r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n {error}\r\n
\r\n \r\n
\r\n );\r\n\r\n // Render input form\r\n const renderInputForm = () => (\r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n Devnet\r\n \r\n Mainnet\r\n
\r\n
\r\n

\r\n Select network to create token on\r\n

\r\n
\r\n\r\n
\r\n (\r\n \r\n Token Name\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Token Symbol\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n\r\n
\r\n (\r\n \r\n Decimals\r\n \r\n field.onChange(Number(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Total Supply\r\n \r\n field.onChange(Number(e.target.value))}\r\n disabled={isSubmitting}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n \r\n \r\n )}\r\n />\r\n
\r\n\r\n (\r\n \r\n Description\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Token Image\r\n \r\n
\r\n \r\n \r\n \r\n Upload Image\r\n \r\n {imagePreview && (\r\n \r\n )}\r\n
\r\n
\r\n \r\n
\r\n )}\r\n />\r\n\r\n (\r\n \r\n Token URI\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n (\r\n \r\n Private Key\r\n \r\n \r\n \r\n \r\n
\r\n ⚠️ Warning: Do not use your main wallet containing large amounts of money. Create a new wallet or use a separate wallet for this purpose to ensure asset safety.\r\n
\r\n
\r\n )}\r\n />\r\n\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating Token on {isMainnet ? \"Mainnet\" : \"Devnet\"}...\r\n \r\n ) : (\r\n `Create Token on ${isMainnet ? \"Mainnet\" : \"Devnet\"}`\r\n )}\r\n \r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n default:\r\n return renderInputForm();\r\n }\r\n };\r\n\r\n return (\r\n \r\n \r\n Create Compressed Token\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}", "type": "registry:component", "target": "components/ui/murphy/mint-cToken.tsx" } diff --git a/public/r/mint-cnft-form.json b/public/r/mint-cnft-form.json index ff4a576..bef1694 100644 --- a/public/r/mint-cnft-form.json +++ b/public/r/mint-cnft-form.json @@ -22,7 +22,7 @@ "files": [ { "path": "components/ui/murphy/mint-cnft-form.tsx", - "content": "'use client';\n\nimport { useState, useContext, useEffect } from 'react';\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\nimport { generateSigner, percentAmount } from '@metaplex-foundation/umi';\nimport { createNft } from '@metaplex-foundation/mpl-token-metadata';\nimport { useWallet, useConnection } from '@solana/wallet-adapter-react';\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\nimport { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';\nimport { publicKey as umiPublicKey } from '@metaplex-foundation/umi';\nimport { mintToCollectionV1 } from '@metaplex-foundation/mpl-bubblegum';\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle, Plus } from \"lucide-react\";\nimport { useForm } from \"react-hook-form\";\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\nexport interface MintCNFTProps {\n collectionMint?: string;\n merkleTree?: string;\n rpcUrl?: string;\n className?: string;\n}\n\n// Type for CNFT form values\ntype CNFTFormValues = {\n name: string;\n symbol: string;\n uri: string;\n merkleTreeAddress: string;\n collectionMint: string;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate name\n if (!data.name) {\n errors.name = {\n type: \"required\",\n message: \"Name is required\",\n };\n }\n\n // Validate symbol\n if (!data.symbol) {\n errors.symbol = {\n type: \"required\",\n message: \"Symbol is required\",\n };\n }\n\n // Validate uri\n if (!data.uri) {\n errors.uri = {\n type: \"required\",\n message: \"Metadata URI is required\",\n };\n }\n\n // Validate merkleTreeAddress\n if (!data.merkleTreeAddress) {\n errors.merkleTreeAddress = {\n type: \"required\",\n message: \"Merkle Tree address is required\",\n };\n }\n\n try {\n // Validate address format for merkleTreeAddress\n if (data.merkleTreeAddress) {\n umiPublicKey(data.merkleTreeAddress);\n }\n } catch (err) {\n errors.merkleTreeAddress = {\n type: \"pattern\",\n message: \"Invalid Solana address\",\n };\n }\n\n try {\n // Validate address format for collectionMint (if provided)\n if (data.collectionMint) {\n umiPublicKey(data.collectionMint);\n }\n } catch (err) {\n errors.collectionMint = {\n type: \"pattern\",\n message: \"Invalid Solana address\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport function MintCNFT({ collectionMint: propCollectionMint, merkleTree: propMerkleTree, className }: MintCNFTProps) {\n // Hooks\n const { connection } = useConnection();\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\n const { endpoint, switchToNextEndpoint } = useContext(ModalContext);\n \n // State\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState('devnet');\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\n const [error, setError] = useState(null);\n const [result, setResult] = useState<{\n signature: string;\n nftAddress: string;\n } | null>(null);\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n name: \"\",\n symbol: \"\",\n uri: \"\",\n merkleTreeAddress: propMerkleTree || \"\",\n collectionMint: propCollectionMint || \"\",\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Only render after the component is mounted on the client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n // Handle form submission\n const onSubmit = async (values: CNFTFormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error('Please connect your wallet');\n return;\n }\n\n try {\n setIsSubmitting(true);\n setError(null);\n setCurrentStage('confirming');\n \n toast.loading(\"Creating CNFT...\", {\n id: \"create-cnft\"\n });\n\n // Create wallet adapter for signing transactions\n const walletAdapter = {\n publicKey,\n signTransaction,\n signAllTransactions\n };\n\n // Create UMI instance\n const umi = createUmi(connection.rpcEndpoint)\n .use(walletAdapterIdentity(walletAdapter))\n .use(mplTokenMetadata());\n \n // Convert addresses\n const walletPublicKey = publicKey.toBase58();\n const leafOwnerPubkey = umiPublicKey(walletPublicKey);\n const merkleTreePubkey = umiPublicKey(values.merkleTreeAddress);\n \n // Use mintToCollectionV1 instead of mintV1\n const { mplBubblegum } = await import('@metaplex-foundation/mpl-bubblegum');\n umi.use(mplBubblegum());\n \n // Check if collection exists\n let collectionMintPubkey;\n if (values.collectionMint) {\n try {\n collectionMintPubkey = umiPublicKey(values.collectionMint);\n \n // Check collection by direct fetch\n try {\n // Check if collection exists by getting account info\n const collectionAccount = await umi.rpc.getAccount(collectionMintPubkey);\n if (!collectionAccount.exists) {\n throw new Error(\"Collection does not exist\");\n }\n } catch (err) {\n throw new Error(\"Invalid or not found Collection NFT. Please try another collection.\");\n }\n } catch (err) {\n throw new Error(\"Invalid collection. Please try another collection or leave empty to create new.\");\n }\n } else {\n try {\n // Create a temporary collection if none exists\n const tempCollectionMint = generateSigner(umi);\n \n // Create collection NFT and wait for full confirmation\n const createCollectionResult = await createNft(umi, {\n mint: tempCollectionMint,\n name: values.name + \" Collection\",\n symbol: values.symbol,\n uri: values.uri,\n sellerFeeBasisPoints: percentAmount(5.0),\n isCollection: true,\n }).sendAndConfirm(umi);\n \n // Wait 2 seconds for transaction to be fully confirmed on network\n await new Promise(resolve => setTimeout(resolve, 2000));\n \n collectionMintPubkey = tempCollectionMint.publicKey;\n } catch (err) {\n throw new Error(\"Failed to create collection for CNFT. Please try with an existing collection.\");\n }\n }\n \n // Configure mintToCollectionV1\n const metadataArgs = {\n name: values.name,\n uri: values.uri,\n sellerFeeBasisPoints: 500,\n collection: {\n key: collectionMintPubkey,\n verified: false\n },\n creators: [\n { address: umi.identity.publicKey, verified: false, share: 100 }\n ],\n };\n \n const mintConfig = {\n leafOwner: leafOwnerPubkey,\n merkleTree: merkleTreePubkey,\n collectionMint: collectionMintPubkey,\n metadata: metadataArgs,\n };\n \n try {\n const nftSigner = generateSigner(umi);\n const mintResult = await mintToCollectionV1(umi, mintConfig).sendAndConfirm(umi);\n \n // Save result\n setResult({\n signature: mintResult.signature.toString(),\n nftAddress: nftSigner.publicKey.toString()\n });\n \n toast.success(\"CNFT created successfully!\", {\n id: \"create-cnft\",\n description: `cNFT: ${values.name}`\n });\n \n setCurrentStage('success');\n } catch (mintErrorUnknown) {\n const mintError = mintErrorUnknown as Error;\n // If error is related to collection metadata, try creating new collection\n if (mintError.message && mintError.message.includes(\"collection_metadata\")) {\n // Create new collection\n const newCollectionMint = generateSigner(umi);\n \n try {\n // Create collection NFT and wait for confirmation\n const createCollectionResult = await createNft(umi, {\n mint: newCollectionMint,\n name: values.name + \" Collection\",\n symbol: values.symbol,\n uri: values.uri,\n sellerFeeBasisPoints: percentAmount(5.0),\n isCollection: true,\n }).sendAndConfirm(umi);\n \n // Wait 2 seconds for transaction confirmation\n await new Promise(resolve => setTimeout(resolve, 2000));\n \n // Try minting again with new collection\n const newMintConfig = {\n ...mintConfig,\n collectionMint: newCollectionMint.publicKey,\n metadata: {\n ...metadataArgs,\n collection: {\n key: newCollectionMint.publicKey,\n verified: false\n }\n }\n };\n \n const nftSigner = generateSigner(umi);\n const newMintResult = await mintToCollectionV1(umi, newMintConfig).sendAndConfirm(umi);\n \n // Save result\n setResult({\n signature: newMintResult.signature.toString(),\n nftAddress: nftSigner.publicKey.toString()\n });\n \n toast.success(\"CNFT created successfully with new collection!\", {\n id: \"create-cnft\",\n description: `cNFT: ${values.name}`\n });\n \n setCurrentStage('success');\n \n // Update form with new collection mint\n form.setValue('collectionMint', newCollectionMint.publicKey.toString());\n } catch (retryErrorUnknown) {\n const retryError = retryErrorUnknown as Error;\n throw new Error(`Cannot create CNFT: ${retryError.message}`);\n }\n } else {\n // If it's a different error, throw it again\n throw mintError;\n }\n }\n } catch (err: any) {\n console.error(\"Create CNFT error:\", err);\n setError(err.message);\n setCurrentStage('error');\n \n toast.error(\"Failed to create CNFT\", {\n id: \"create-cnft\",\n description: err.message\n });\n \n // If transaction fails due to connection error, try switching to another endpoint\n if (err.message.includes('failed to fetch') || \n err.message.includes('timeout') || \n err.message.includes('429') ||\n err.message.includes('503')) {\n switchToNextEndpoint();\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const viewNFT = () => {\n if (result?.nftAddress) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\n window.open(`${baseUrl}${result.nftAddress}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setError(null);\n setCurrentStage('input');\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

CNFT Created!

\n \n
\n
CNFT Address:
\n
\n {result?.nftAddress}\n
\n
\n \n
\n
Transaction Signature:
\n
\n {result?.signature}\n
\n
\n \n
\n \n \n \n
\n \n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Creation Failed

\n

{error || 'An error occurred while creating the CNFT.'}

\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Creating CNFT

\n

Please wait while your CNFT is being created...

\n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n (\n \n
\n CNFT Name\n
\n \n \n \n \n

\n Display name of the CNFT\n

\n
\n )}\n />\n \n (\n \n
\n Symbol\n
\n \n \n \n \n

\n Short symbol for your CNFT\n

\n
\n )}\n />\n \n (\n \n
\n Metadata URI\n
\n \n \n \n \n

\n Link to the metadata of the CNFT (JSON)\n

\n
\n )}\n />\n \n (\n \n
\n Merkle Tree Address\n
\n \n \n \n \n

\n Address of the Merkle Tree to mint CNFT into\n

\n
\n )}\n />\n \n (\n \n
\n Collection Mint (Optional)\n
\n \n \n \n \n

\n Collection NFT mint address, if left empty, a new collection will be created\n

\n
\n )}\n />\n \n
\n
\n
\n Network\n \n {network}\n \n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Creating...\n \n ) : \"Create CNFT\"}\n \n )}\n
\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'confirming':\n return renderConfirming();\n default:\n return renderForm();\n }\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n Create CNFT\n Create a new compressed NFT on Solana\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n Create CNFT\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Create a new compressed NFT on Solana\n \n \n {renderStageContent()}\n \n \n );\n}", + "content": "'use client';\r\n\r\nimport { useState, useContext, useEffect } from 'react';\r\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\r\nimport { generateSigner, percentAmount } from '@metaplex-foundation/umi';\r\nimport { createNft } from '@metaplex-foundation/mpl-token-metadata';\r\nimport { useWallet, useConnection } from '@solana/wallet-adapter-react';\r\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\r\nimport { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';\r\nimport { publicKey as umiPublicKey } from '@metaplex-foundation/umi';\r\nimport { mintToCollectionV1 } from '@metaplex-foundation/mpl-bubblegum';\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle, Plus } from \"lucide-react\";\r\nimport { useForm } from \"react-hook-form\";\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\nexport interface MintCNFTProps {\r\n collectionMint?: string;\r\n merkleTree?: string;\r\n rpcUrl?: string;\r\n className?: string;\r\n}\r\n\r\n// Type for CNFT form values\r\ntype CNFTFormValues = {\r\n name: string;\r\n symbol: string;\r\n uri: string;\r\n merkleTreeAddress: string;\r\n collectionMint: string;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate name\r\n if (!data.name) {\r\n errors.name = {\r\n type: \"required\",\r\n message: \"Name is required\",\r\n };\r\n }\r\n\r\n // Validate symbol\r\n if (!data.symbol) {\r\n errors.symbol = {\r\n type: \"required\",\r\n message: \"Symbol is required\",\r\n };\r\n }\r\n\r\n // Validate uri\r\n if (!data.uri) {\r\n errors.uri = {\r\n type: \"required\",\r\n message: \"Metadata URI is required\",\r\n };\r\n }\r\n\r\n // Validate merkleTreeAddress\r\n if (!data.merkleTreeAddress) {\r\n errors.merkleTreeAddress = {\r\n type: \"required\",\r\n message: \"Merkle Tree address is required\",\r\n };\r\n }\r\n\r\n try {\r\n // Validate address format for merkleTreeAddress\r\n if (data.merkleTreeAddress) {\r\n umiPublicKey(data.merkleTreeAddress);\r\n }\r\n } catch (err) {\r\n errors.merkleTreeAddress = {\r\n type: \"pattern\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n\r\n try {\r\n // Validate address format for collectionMint (if provided)\r\n if (data.collectionMint) {\r\n umiPublicKey(data.collectionMint);\r\n }\r\n } catch (err) {\r\n errors.collectionMint = {\r\n type: \"pattern\",\r\n message: \"Invalid Solana address\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport function MintCNFT({ collectionMint: propCollectionMint, merkleTree: propMerkleTree, className }: MintCNFTProps) {\r\n // Hooks\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\r\n const { endpoint, switchToNextEndpoint } = useContext(ModalContext);\r\n \r\n // State\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState('devnet');\r\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\r\n const [error, setError] = useState(null);\r\n const [result, setResult] = useState<{\r\n signature: string;\r\n nftAddress: string;\r\n } | null>(null);\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n name: \"\",\r\n symbol: \"\",\r\n uri: \"\",\r\n merkleTreeAddress: propMerkleTree || \"\",\r\n collectionMint: propCollectionMint || \"\",\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Only render after the component is mounted on the client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n // Handle form submission\r\n const onSubmit = async (values: CNFTFormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error('Please connect your wallet');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setError(null);\r\n setCurrentStage('confirming');\r\n \r\n toast.loading(\"Creating CNFT...\", {\r\n id: \"create-cnft\"\r\n });\r\n\r\n // Create wallet adapter for signing transactions\r\n const walletAdapter = {\r\n publicKey,\r\n signTransaction,\r\n signAllTransactions\r\n };\r\n\r\n // Create UMI instance\r\n const umi = createUmi(connection.rpcEndpoint)\r\n .use(walletAdapterIdentity(walletAdapter))\r\n .use(mplTokenMetadata());\r\n \r\n // Convert addresses\r\n const walletPublicKey = publicKey.toBase58();\r\n const leafOwnerPubkey = umiPublicKey(walletPublicKey);\r\n const merkleTreePubkey = umiPublicKey(values.merkleTreeAddress);\r\n \r\n // Use mintToCollectionV1 instead of mintV1\r\n const { mplBubblegum } = await import('@metaplex-foundation/mpl-bubblegum');\r\n umi.use(mplBubblegum());\r\n \r\n // Check if collection exists\r\n let collectionMintPubkey;\r\n if (values.collectionMint) {\r\n try {\r\n collectionMintPubkey = umiPublicKey(values.collectionMint);\r\n \r\n // Check collection by direct fetch\r\n try {\r\n // Check if collection exists by getting account info\r\n const collectionAccount = await umi.rpc.getAccount(collectionMintPubkey);\r\n if (!collectionAccount.exists) {\r\n throw new Error(\"Collection does not exist\");\r\n }\r\n } catch (err) {\r\n throw new Error(\"Invalid or not found Collection NFT. Please try another collection.\");\r\n }\r\n } catch (err) {\r\n throw new Error(\"Invalid collection. Please try another collection or leave empty to create new.\");\r\n }\r\n } else {\r\n try {\r\n // Create a temporary collection if none exists\r\n const tempCollectionMint = generateSigner(umi);\r\n \r\n // Create collection NFT and wait for full confirmation\r\n const createCollectionResult = await createNft(umi, {\r\n mint: tempCollectionMint,\r\n name: values.name + \" Collection\",\r\n symbol: values.symbol,\r\n uri: values.uri,\r\n sellerFeeBasisPoints: percentAmount(5.0),\r\n isCollection: true,\r\n }).sendAndConfirm(umi);\r\n \r\n // Wait 2 seconds for transaction to be fully confirmed on network\r\n await new Promise(resolve => setTimeout(resolve, 2000));\r\n \r\n collectionMintPubkey = tempCollectionMint.publicKey;\r\n } catch (err) {\r\n throw new Error(\"Failed to create collection for CNFT. Please try with an existing collection.\");\r\n }\r\n }\r\n \r\n // Configure mintToCollectionV1\r\n const metadataArgs = {\r\n name: values.name,\r\n uri: values.uri,\r\n sellerFeeBasisPoints: 500,\r\n collection: {\r\n key: collectionMintPubkey,\r\n verified: false\r\n },\r\n creators: [\r\n { address: umi.identity.publicKey, verified: false, share: 100 }\r\n ],\r\n };\r\n \r\n const mintConfig = {\r\n leafOwner: leafOwnerPubkey,\r\n merkleTree: merkleTreePubkey,\r\n collectionMint: collectionMintPubkey,\r\n metadata: metadataArgs,\r\n };\r\n \r\n try {\r\n const nftSigner = generateSigner(umi);\r\n const mintResult = await mintToCollectionV1(umi, mintConfig).sendAndConfirm(umi);\r\n \r\n // Save result\r\n setResult({\r\n signature: mintResult.signature.toString(),\r\n nftAddress: nftSigner.publicKey.toString()\r\n });\r\n \r\n toast.success(\"CNFT created successfully!\", {\r\n id: \"create-cnft\",\r\n description: `cNFT: ${values.name}`\r\n });\r\n \r\n setCurrentStage('success');\r\n } catch (mintErrorUnknown) {\r\n const mintError = mintErrorUnknown as Error;\r\n // If error is related to collection metadata, try creating new collection\r\n if (mintError.message && mintError.message.includes(\"collection_metadata\")) {\r\n // Create new collection\r\n const newCollectionMint = generateSigner(umi);\r\n \r\n try {\r\n // Create collection NFT and wait for confirmation\r\n const createCollectionResult = await createNft(umi, {\r\n mint: newCollectionMint,\r\n name: values.name + \" Collection\",\r\n symbol: values.symbol,\r\n uri: values.uri,\r\n sellerFeeBasisPoints: percentAmount(5.0),\r\n isCollection: true,\r\n }).sendAndConfirm(umi);\r\n \r\n // Wait 2 seconds for transaction confirmation\r\n await new Promise(resolve => setTimeout(resolve, 2000));\r\n \r\n // Try minting again with new collection\r\n const newMintConfig = {\r\n ...mintConfig,\r\n collectionMint: newCollectionMint.publicKey,\r\n metadata: {\r\n ...metadataArgs,\r\n collection: {\r\n key: newCollectionMint.publicKey,\r\n verified: false\r\n }\r\n }\r\n };\r\n \r\n const nftSigner = generateSigner(umi);\r\n const newMintResult = await mintToCollectionV1(umi, newMintConfig).sendAndConfirm(umi);\r\n \r\n // Save result\r\n setResult({\r\n signature: newMintResult.signature.toString(),\r\n nftAddress: nftSigner.publicKey.toString()\r\n });\r\n \r\n toast.success(\"CNFT created successfully with new collection!\", {\r\n id: \"create-cnft\",\r\n description: `cNFT: ${values.name}`\r\n });\r\n \r\n setCurrentStage('success');\r\n \r\n // Update form with new collection mint\r\n form.setValue('collectionMint', newCollectionMint.publicKey.toString());\r\n } catch (retryErrorUnknown) {\r\n const retryError = retryErrorUnknown as Error;\r\n throw new Error(`Cannot create CNFT: ${retryError.message}`);\r\n }\r\n } else {\r\n // If it's a different error, throw it again\r\n throw mintError;\r\n }\r\n }\r\n } catch (err: any) {\r\n console.error(\"Create CNFT error:\", err);\r\n setError(err.message);\r\n setCurrentStage('error');\r\n \r\n toast.error(\"Failed to create CNFT\", {\r\n id: \"create-cnft\",\r\n description: err.message\r\n });\r\n \r\n // If transaction fails due to connection error, try switching to another endpoint\r\n if (err.message.includes('failed to fetch') || \r\n err.message.includes('timeout') || \r\n err.message.includes('429') ||\r\n err.message.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\r\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const viewNFT = () => {\r\n if (result?.nftAddress) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\r\n window.open(`${baseUrl}${result.nftAddress}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setError(null);\r\n setCurrentStage('input');\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

CNFT Created!

\r\n \r\n
\r\n
CNFT Address:
\r\n
\r\n {result?.nftAddress}\r\n
\r\n
\r\n \r\n
\r\n
Transaction Signature:
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Creation Failed

\r\n

{error || 'An error occurred while creating the CNFT.'}

\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Creating CNFT

\r\n

Please wait while your CNFT is being created...

\r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n (\r\n \r\n
\r\n CNFT Name\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Display name of the CNFT\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Symbol\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Short symbol for your CNFT\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Metadata URI\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Link to the metadata of the CNFT (JSON)\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Merkle Tree Address\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Address of the Merkle Tree to mint CNFT into\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Collection Mint (Optional)\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Collection NFT mint address, if left empty, a new collection will be created\r\n

\r\n
\r\n )}\r\n />\r\n \r\n
\r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating...\r\n \r\n ) : \"Create CNFT\"}\r\n \r\n )}\r\n
\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'confirming':\r\n return renderConfirming();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create CNFT\r\n Create a new compressed NFT on Solana\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Create CNFT\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Create a new compressed NFT on Solana\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}", "type": "registry:component", "target": "components/ui/murphy/mint-cnft-form.tsx" } diff --git a/public/r/mint-nft-form.json b/public/r/mint-nft-form.json index dc1e9bd..f9b31da 100644 --- a/public/r/mint-nft-form.json +++ b/public/r/mint-nft-form.json @@ -22,13 +22,13 @@ "files": [ { "path": "components/ui/murphy/mint-nft-form.tsx", - "content": "'use client';\n\nimport { useState, useContext, useEffect } from 'react';\nimport { PublicKey } from '@solana/web3.js';\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\nimport { generateSigner } from '@metaplex-foundation/umi';\nimport { createNft } from '@metaplex-foundation/mpl-token-metadata';\nimport { useWallet, useConnection } from '@solana/wallet-adapter-react';\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\nimport { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';\nimport { toast } from \"sonner\";\nimport { Loader2, ExternalLink, CheckCircle, Plus } from \"lucide-react\";\nimport { useForm } from \"react-hook-form\";\n\n// UI components\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\n\n// Context\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\nexport interface MintNFTProps {\n collectionMint?: string;\n rpcUrl?: string;\n className?: string;\n}\n\n// Type for NFT form values\ntype NFTFormValues = {\n name: string;\n symbol: string;\n uri: string;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate name\n if (!data.name) {\n errors.name = {\n type: \"required\",\n message: \"Name is required\",\n };\n }\n\n // Validate symbol\n if (!data.symbol) {\n errors.symbol = {\n type: \"required\",\n message: \"Symbol is required\",\n };\n }\n\n // Validate uri\n if (!data.uri) {\n errors.uri = {\n type: \"required\",\n message: \"Metadata URI is required\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport function MintNFT({ collectionMint, className }: MintNFTProps) {\n // Hooks\n const { connection } = useConnection();\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\n const { endpoint, switchToNextEndpoint } = useContext(ModalContext);\n \n // State\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [mounted, setMounted] = useState(false);\n const [network, setNetwork] = useState('devnet');\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\n const [error, setError] = useState(null);\n const [result, setResult] = useState<{\n signature: string;\n nftAddress: string;\n } | null>(null);\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n name: \"\",\n symbol: \"\",\n uri: \"\",\n },\n mode: \"onSubmit\",\n resolver: customResolver,\n });\n\n // Only render after the component is mounted on the client\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Update network state when endpoint changes\n useEffect(() => {\n if (endpoint) {\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\n }\n }, [endpoint]);\n\n // Handle form submission\n const onSubmit = async (values: NFTFormValues) => {\n if (!connected || !publicKey || !wallet) {\n toast.error('Please connect your wallet');\n return;\n }\n\n try {\n setIsSubmitting(true);\n setError(null);\n setCurrentStage('confirming');\n\n toast.loading(\"Creating NFT...\", {\n id: \"create-nft\"\n });\n\n // Create wallet adapter for signing transactions\n const walletAdapter = {\n publicKey,\n signTransaction,\n signAllTransactions\n };\n\n // Create UMI instance\n const umi = createUmi(connection.rpcEndpoint)\n .use(walletAdapterIdentity(walletAdapter))\n .use(mplTokenMetadata());\n \n // Create NFT\n const nftMint = generateSigner(umi);\n \n const mintConfig: any = {\n mint: nftMint,\n name: values.name,\n symbol: values.symbol,\n uri: values.uri,\n sellerFeeBasisPoints: 500,\n };\n \n // Add collection mint if provided\n if (collectionMint) {\n try {\n const collectionPubkey = new PublicKey(collectionMint);\n mintConfig.collection = { key: collectionPubkey, verified: false };\n } catch (err) {\n console.warn(\"Invalid collection mint:\", err);\n }\n }\n \n const mintResult = await createNft(umi, mintConfig).sendAndConfirm(umi);\n \n // Save result\n setResult({\n signature: mintResult.signature.toString(),\n nftAddress: nftMint.publicKey.toString()\n });\n \n toast.success(\"NFT created successfully!\", {\n id: \"create-nft\",\n description: `NFT: ${values.name}`\n });\n \n setCurrentStage('success');\n } catch (err: any) {\n console.error(\"Create NFT error:\", err);\n setError(err.message);\n setCurrentStage('error');\n \n toast.error(\"Failed to create NFT\", {\n id: \"create-nft\",\n description: err.message\n });\n \n // If transaction fails due to connection error, try switching to another endpoint\n if (err.message.includes('failed to fetch') || \n err.message.includes('timeout') || \n err.message.includes('429') ||\n err.message.includes('503')) {\n switchToNextEndpoint();\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const viewExplorer = () => {\n if (result?.signature) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n const viewNFT = () => {\n if (result?.nftAddress) {\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\n window.open(`${baseUrl}${result.nftAddress}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\n }\n };\n\n // Reset form\n const resetForm = () => {\n form.reset();\n setResult(null);\n setError(null);\n setCurrentStage('input');\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n
\n

NFT Created!

\n \n
\n
NFT Address:
\n
\n {result?.nftAddress}\n
\n
\n \n
\n
Transaction Signature:
\n
\n {result?.signature}\n
\n
\n \n
\n \n \n \n
\n \n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Creation Failed

\n

{error || 'An error occurred while creating the NFT.'}

\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Creating NFT

\n

Please wait while your NFT is being created...

\n
\n );\n\n // Render form view\n const renderForm = () => (\n
\n \n (\n \n
\n NFT Name\n
\n \n \n \n \n

\n Display name of the NFT\n

\n
\n )}\n />\n \n (\n \n
\n Symbol\n
\n \n \n \n \n

\n Short symbol for your NFT\n

\n
\n )}\n />\n \n (\n \n
\n Metadata URI\n
\n \n \n \n \n

\n Link to the metadata of the NFT (JSON)\n

\n
\n )}\n />\n \n
\n {collectionMint && (\n
\n
\n Collection Mint\n {collectionMint}\n
\n
\n )}\n \n
\n
\n Network\n \n {network}\n \n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Creating...\n \n ) : \"Create NFT\"}\n \n )}\n
\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'confirming':\n return renderConfirming();\n default:\n return renderForm();\n }\n };\n\n // Avoid hydration error\n if (!mounted) {\n return (\n \n \n Create NFT\n Create a new NFT on Solana\n \n \n
\n \n

Loading...

\n
\n
\n
\n );\n }\n\n return (\n \n \n \n Create NFT\n {connected && publicKey && (\n \n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\n \n )}\n \n Create a new NFT on Solana\n \n \n {renderStageContent()}\n \n \n );\n}", + "content": "'use client';\r\n\r\nimport { useState, useContext, useEffect } from 'react';\r\nimport { PublicKey } from '@solana/web3.js';\r\nimport { createUmi } from '@metaplex-foundation/umi-bundle-defaults';\r\nimport { generateSigner } from '@metaplex-foundation/umi';\r\nimport { createNft } from '@metaplex-foundation/mpl-token-metadata';\r\nimport { useWallet, useConnection } from '@solana/wallet-adapter-react';\r\nimport { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';\r\nimport { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';\r\nimport { toast } from \"sonner\";\r\nimport { Loader2, ExternalLink, CheckCircle, Plus } from \"lucide-react\";\r\nimport { useForm } from \"react-hook-form\";\r\n\r\n// UI components\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\n\r\n// Context\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\nexport interface MintNFTProps {\r\n collectionMint?: string;\r\n rpcUrl?: string;\r\n className?: string;\r\n}\r\n\r\n// Type for NFT form values\r\ntype NFTFormValues = {\r\n name: string;\r\n symbol: string;\r\n uri: string;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate name\r\n if (!data.name) {\r\n errors.name = {\r\n type: \"required\",\r\n message: \"Name is required\",\r\n };\r\n }\r\n\r\n // Validate symbol\r\n if (!data.symbol) {\r\n errors.symbol = {\r\n type: \"required\",\r\n message: \"Symbol is required\",\r\n };\r\n }\r\n\r\n // Validate uri\r\n if (!data.uri) {\r\n errors.uri = {\r\n type: \"required\",\r\n message: \"Metadata URI is required\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport function MintNFT({ collectionMint, className }: MintNFTProps) {\r\n // Hooks\r\n const { connection } = useConnection();\r\n const { publicKey, connected, wallet, signTransaction, signAllTransactions } = useWallet();\r\n const { endpoint, switchToNextEndpoint } = useContext(ModalContext);\r\n \r\n // State\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [mounted, setMounted] = useState(false);\r\n const [network, setNetwork] = useState('devnet');\r\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\r\n const [error, setError] = useState(null);\r\n const [result, setResult] = useState<{\r\n signature: string;\r\n nftAddress: string;\r\n } | null>(null);\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n name: \"\",\r\n symbol: \"\",\r\n uri: \"\",\r\n },\r\n mode: \"onSubmit\",\r\n resolver: customResolver,\r\n });\r\n\r\n // Only render after the component is mounted on the client\r\n useEffect(() => {\r\n setMounted(true);\r\n }, []);\r\n\r\n // Update network state when endpoint changes\r\n useEffect(() => {\r\n if (endpoint) {\r\n setNetwork(endpoint.includes('devnet') ? 'devnet' : 'mainnet');\r\n }\r\n }, [endpoint]);\r\n\r\n // Handle form submission\r\n const onSubmit = async (values: NFTFormValues) => {\r\n if (!connected || !publicKey || !wallet) {\r\n toast.error('Please connect your wallet');\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setError(null);\r\n setCurrentStage('confirming');\r\n\r\n toast.loading(\"Creating NFT...\", {\r\n id: \"create-nft\"\r\n });\r\n\r\n // Create wallet adapter for signing transactions\r\n const walletAdapter = {\r\n publicKey,\r\n signTransaction,\r\n signAllTransactions\r\n };\r\n\r\n // Create UMI instance\r\n const umi = createUmi(connection.rpcEndpoint)\r\n .use(walletAdapterIdentity(walletAdapter))\r\n .use(mplTokenMetadata());\r\n \r\n // Create NFT\r\n const nftMint = generateSigner(umi);\r\n \r\n const mintConfig: any = {\r\n mint: nftMint,\r\n name: values.name,\r\n symbol: values.symbol,\r\n uri: values.uri,\r\n sellerFeeBasisPoints: 500,\r\n };\r\n \r\n // Add collection mint if provided\r\n if (collectionMint) {\r\n try {\r\n const collectionPubkey = new PublicKey(collectionMint);\r\n mintConfig.collection = { key: collectionPubkey, verified: false };\r\n } catch (err) {\r\n console.warn(\"Invalid collection mint:\", err);\r\n }\r\n }\r\n \r\n const mintResult = await createNft(umi, mintConfig).sendAndConfirm(umi);\r\n \r\n // Save result\r\n setResult({\r\n signature: mintResult.signature.toString(),\r\n nftAddress: nftMint.publicKey.toString()\r\n });\r\n \r\n toast.success(\"NFT created successfully!\", {\r\n id: \"create-nft\",\r\n description: `NFT: ${values.name}`\r\n });\r\n \r\n setCurrentStage('success');\r\n } catch (err: any) {\r\n console.error(\"Create NFT error:\", err);\r\n setError(err.message);\r\n setCurrentStage('error');\r\n \r\n toast.error(\"Failed to create NFT\", {\r\n id: \"create-nft\",\r\n description: err.message\r\n });\r\n \r\n // If transaction fails due to connection error, try switching to another endpoint\r\n if (err.message.includes('failed to fetch') || \r\n err.message.includes('timeout') || \r\n err.message.includes('429') ||\r\n err.message.includes('503')) {\r\n switchToNextEndpoint();\r\n }\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const viewExplorer = () => {\r\n if (result?.signature) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/tx/' : 'https://solscan.io/tx/';\r\n window.open(`${baseUrl}${result.signature}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n const viewNFT = () => {\r\n if (result?.nftAddress) {\r\n const baseUrl = network === 'devnet' ? 'https://explorer.solana.com/address/' : 'https://solscan.io/account/';\r\n window.open(`${baseUrl}${result.nftAddress}${network === 'devnet' ? '?cluster=devnet' : ''}`, '_blank');\r\n }\r\n };\r\n\r\n // Reset form\r\n const resetForm = () => {\r\n form.reset();\r\n setResult(null);\r\n setError(null);\r\n setCurrentStage('input');\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n
\r\n

NFT Created!

\r\n \r\n
\r\n
NFT Address:
\r\n
\r\n {result?.nftAddress}\r\n
\r\n
\r\n \r\n
\r\n
Transaction Signature:
\r\n
\r\n {result?.signature}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Creation Failed

\r\n

{error || 'An error occurred while creating the NFT.'}

\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Creating NFT

\r\n

Please wait while your NFT is being created...

\r\n
\r\n );\r\n\r\n // Render form view\r\n const renderForm = () => (\r\n
\r\n \r\n (\r\n \r\n
\r\n NFT Name\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Display name of the NFT\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Symbol\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Short symbol for your NFT\r\n

\r\n
\r\n )}\r\n />\r\n \r\n (\r\n \r\n
\r\n Metadata URI\r\n
\r\n \r\n \r\n \r\n \r\n

\r\n Link to the metadata of the NFT (JSON)\r\n

\r\n
\r\n )}\r\n />\r\n \r\n
\r\n {collectionMint && (\r\n
\r\n
\r\n Collection Mint\r\n {collectionMint}\r\n
\r\n
\r\n )}\r\n \r\n
\r\n
\r\n Network\r\n \r\n {network}\r\n \r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Creating...\r\n \r\n ) : \"Create NFT\"}\r\n \r\n )}\r\n
\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'confirming':\r\n return renderConfirming();\r\n default:\r\n return renderForm();\r\n }\r\n };\r\n\r\n // Avoid hydration error\r\n if (!mounted) {\r\n return (\r\n \r\n \r\n Create NFT\r\n Create a new NFT on Solana\r\n \r\n \r\n
\r\n \r\n

Loading...

\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Create NFT\r\n {connected && publicKey && (\r\n \r\n {publicKey.toString().slice(0, 4)}...{publicKey.toString().slice(-4)}\r\n \r\n )}\r\n \r\n Create a new NFT on Solana\r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}", "type": "registry:component", "target": "components/ui/murphy/mint-nft-form.tsx" }, { "path": "hook/murphy/use-walletModal.ts", - "content": "import { createContext, useContext } from 'react';\n\nexport interface WalletModalContextState {\n visible: boolean;\n setVisible: (open: boolean) => void;\n}\n\nconst DEFAULT_CONTEXT = {\n setVisible(_open: boolean) {\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\n },\n visible: false,\n};\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\n get() {\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\n return false;\n },\n});\n\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\n return (\n 'You have tried to ' +\n ` ${action} \"${valueName}\"` +\n ' on a WalletModalContext without providing one.' +\n ' Make sure to render a WalletModalProvider' +\n ' as an ancestor of the component that uses ' +\n 'WalletModalContext'\n );\n}\n\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\n\nexport function useWalletModal(): WalletModalContextState {\n return useContext(WalletModalContext);\n}\n", + "content": "import { createContext, useContext } from 'react';\r\n\r\nexport interface WalletModalContextState {\r\n visible: boolean;\r\n setVisible: (open: boolean) => void;\r\n}\r\n\r\nconst DEFAULT_CONTEXT = {\r\n setVisible(_open: boolean) {\r\n console.error(constructMissingProviderErrorMessage('call', 'setVisible'));\r\n },\r\n visible: false,\r\n};\r\nObject.defineProperty(DEFAULT_CONTEXT, 'visible', {\r\n get() {\r\n console.error(constructMissingProviderErrorMessage('read', 'visible'));\r\n return false;\r\n },\r\n});\r\n\r\nfunction constructMissingProviderErrorMessage(action: string, valueName: string) {\r\n return (\r\n 'You have tried to ' +\r\n ` ${action} \"${valueName}\"` +\r\n ' on a WalletModalContext without providing one.' +\r\n ' Make sure to render a WalletModalProvider' +\r\n ' as an ancestor of the component that uses ' +\r\n 'WalletModalContext'\r\n );\r\n}\r\n\r\nexport const WalletModalContext = createContext(DEFAULT_CONTEXT as WalletModalContextState);\r\n\r\nexport function useWalletModal(): WalletModalContextState {\r\n return useContext(WalletModalContext);\r\n}\r\n", "type": "registry:hook", "target": "hook/murphy/use-walletModal.ts" } diff --git a/public/r/pk-input.json b/public/r/pk-input.json index 7d9c187..02702df 100644 --- a/public/r/pk-input.json +++ b/public/r/pk-input.json @@ -12,13 +12,13 @@ "files": [ { "path": "components/ui/murphy/pk-input.tsx", - "content": "\"use client\";\nimport React from \"react\";\n\nimport { validatePublicKey, cn } from \"@/lib/utils\";\nimport { Input } from \"../input\";\n\nexport const PKInput = ({ ...props }: React.ComponentPropsWithoutRef<\"input\">) => {\n const [value, setValue] = React.useState(\"\");\n const [isInvalid, setIsInvalid] = React.useState(false);\n const [hasBlurred, setHasBlurred] = React.useState(false);\n\n const inputRef = React.useRef(null);\n\n const validateField = React.useCallback(() => {\n const isValid = validatePublicKey(value);\n if (inputRef.current) {\n if (!isValid) {\n inputRef.current.setCustomValidity(\"Invalid public key\");\n } else {\n inputRef.current.setCustomValidity(\"\");\n }\n setIsInvalid(!inputRef.current.validity.valid);\n }\n }, [value]);\n const handleBlur = React.useCallback(() => {\n setHasBlurred(true);\n validateField();\n }, [validateField]);\n\n React.useEffect(() => {\n if (hasBlurred) {\n validateField();\n }\n }, [value, validateField, hasBlurred]);\n return (\n setValue(e.target.value)}\n onBlur={handleBlur}\n aria-invalid={isInvalid}\n />\n );\n};\n", + "content": "\"use client\";\r\nimport React from \"react\";\r\n\r\nimport { validatePublicKey, cn } from \"@/lib/utils\";\r\nimport { Input } from \"../input\";\r\n\r\nexport const PKInput = ({ ...props }: React.ComponentPropsWithoutRef<\"input\">) => {\r\n const [value, setValue] = React.useState(\"\");\r\n const [isInvalid, setIsInvalid] = React.useState(false);\r\n const [hasBlurred, setHasBlurred] = React.useState(false);\r\n\r\n const inputRef = React.useRef(null);\r\n\r\n const validateField = React.useCallback(() => {\r\n const isValid = validatePublicKey(value);\r\n if (inputRef.current) {\r\n if (!isValid) {\r\n inputRef.current.setCustomValidity(\"Invalid public key\");\r\n } else {\r\n inputRef.current.setCustomValidity(\"\");\r\n }\r\n setIsInvalid(!inputRef.current.validity.valid);\r\n }\r\n }, [value]);\r\n const handleBlur = React.useCallback(() => {\r\n setHasBlurred(true);\r\n validateField();\r\n }, [validateField]);\r\n\r\n React.useEffect(() => {\r\n if (hasBlurred) {\r\n validateField();\r\n }\r\n }, [value, validateField, hasBlurred]);\r\n return (\r\n setValue(e.target.value)}\r\n onBlur={handleBlur}\r\n aria-invalid={isInvalid}\r\n />\r\n );\r\n};\r\n", "type": "registry:component", "target": "components/ui/murphy/pk-input.tsx" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" } diff --git a/public/r/price-change.json b/public/r/price-change.json index ea84ff8..3f4fb9b 100644 --- a/public/r/price-change.json +++ b/public/r/price-change.json @@ -6,13 +6,13 @@ "files": [ { "path": "components/ui/murphy/price-change.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { cn, formatUsd } from \"@/lib/utils\";\n\ntype PriceChangeProps = {\n data: {\n timestamp: number;\n price: number;\n }[];\n type?: \"%\" | \"$\";\n};\n\nconst PriceChange = ({ data, type = \"%\" }: PriceChangeProps) => {\n const [selectedType, setSelectedType] = React.useState(type);\n const startPrice = data[0]?.price || 0;\n const endPrice = data[data.length - 1]?.price || 0;\n const priceDifference = endPrice - startPrice;\n const percentageChange = (priceDifference / startPrice) * 100;\n const isPositive = priceDifference > 0;\n\n if (!data[0]?.price) return null;\n\n return (\n setSelectedType(selectedType === \"%\" ? \"$\" : \"%\")}\n >\n {isPositive && \"+\"}\n {selectedType === \"%\"\n ? `${percentageChange.toFixed(2)}%`\n : `${formatUsd(priceDifference)}`}\n \n );\n};\n\nexport { PriceChange };", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\nimport { cn, formatUsd } from \"@/lib/utils\";\r\n\r\ntype PriceChangeProps = {\r\n data: {\r\n timestamp: number;\r\n price: number;\r\n }[];\r\n type?: \"%\" | \"$\";\r\n};\r\n\r\nconst PriceChange = ({ data, type = \"%\" }: PriceChangeProps) => {\r\n const [selectedType, setSelectedType] = React.useState(type);\r\n const startPrice = data[0]?.price || 0;\r\n const endPrice = data[data.length - 1]?.price || 0;\r\n const priceDifference = endPrice - startPrice;\r\n const percentageChange = (priceDifference / startPrice) * 100;\r\n const isPositive = priceDifference > 0;\r\n\r\n if (!data[0]?.price) return null;\r\n\r\n return (\r\n setSelectedType(selectedType === \"%\" ? \"$\" : \"%\")}\r\n >\r\n {isPositive && \"+\"}\r\n {selectedType === \"%\"\r\n ? `${percentageChange.toFixed(2)}%`\r\n : `${formatUsd(priceDifference)}`}\r\n \r\n );\r\n};\r\n\r\nexport { PriceChange };", "type": "registry:file", "target": "components/ui/murphy/price-change.tsx" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" } diff --git a/public/r/price-chart.json b/public/r/price-chart.json index 12c63ad..c393b83 100644 --- a/public/r/price-chart.json +++ b/public/r/price-chart.json @@ -17,19 +17,19 @@ "files": [ { "path": "components/ui/murphy/price-chart.tsx", - "content": "\"use client\";\nimport React from \"react\";\n\nimport { Area, AreaChart, XAxis } from \"recharts\";\nimport { format } from \"date-fns\";\n\nimport { formatUsd } from \"@/lib/utils\";\nimport { SolAsset } from \"@/types/assets\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@/components/ui/card\";\nimport {\n ChartConfig,\n ChartContainer,\n ChartTooltip,\n} from \"@/components/ui/chart\";\nimport { ToggleGroup, ToggleGroupItem } from \"@/components/ui/toggle-group\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\n\nimport { TokenIcon } from \"@/components/ui/murphy/token-icon\";\n\nexport type TimeScale = \"time\" | \"day\" | \"date\" | \"month\";\n\nexport type PriceChartProps = {\n asset: SolAsset | null;\n data: {\n timestamp: number;\n price: number;\n }[];\n timeScale?: TimeScale;\n title?: string;\n description?: string;\n onDateRangeChange?: (value: string) => void;\n dateRangeOptions?: string[];\n defaultDateRange?: string;\n};\n\nconst formatTimestamp = (timestamp: number, timeScale: TimeScale) => {\n const ts = timestamp * 1000;\n if (timeScale === \"month\") {\n return format(ts, \"MMM\");\n } else if (timeScale === \"date\") {\n return format(ts, \"MMM dd\");\n } else if (timeScale === \"day\") {\n return format(ts, \"MMM do\");\n }\n return format(ts, \"HH:mm\");\n};\n\nconst PriceChart = ({\n asset,\n title,\n description,\n timeScale = \"time\",\n onDateRangeChange,\n dateRangeOptions,\n defaultDateRange,\n data,\n}: PriceChartProps) => {\n const [dateRange, setDateRange] = React.useState(\n defaultDateRange && dateRangeOptions?.includes(defaultDateRange)\n ? defaultDateRange\n : dateRangeOptions?.[0] || \"1D\",\n );\n const prevDateRange = React.useRef(dateRange);\n\n const chartColor = React.useMemo(() => {\n if (!data.length) return \"\";\n return data[0].price > data[data.length - 1].price\n ? \"hsl(var(--destructive))\"\n : \"hsl(var(--chart-2))\";\n }, [data]);\n\n const formatXAxis = (timestamp: number) => {\n return formatTimestamp(timestamp, timeScale);\n };\n\n const chartData = React.useMemo(() => {\n return data.map((item) => ({\n ...item,\n label: formatTimestamp(item.timestamp, timeScale),\n }));\n }, [data, timeScale]);\n\n const chartConfig = React.useMemo(() => {\n if (!chartData.length || !asset) return null;\n\n return {\n desktop: {\n label: asset.symbol,\n color: chartColor,\n },\n mobile: {\n label: asset.symbol,\n color: chartColor,\n },\n } satisfies ChartConfig;\n }, [chartData, asset, chartColor]);\n\n const chartTitle = React.useMemo(() => {\n if (!asset) return title || \"Price Chart\";\n return asset.symbol ? `${asset.symbol} Price` : title;\n }, [asset, title]);\n\n React.useEffect(() => {\n if (prevDateRange.current !== dateRange) {\n onDateRangeChange?.(dateRange);\n prevDateRange.current = dateRange;\n }\n }, [dateRange, onDateRangeChange]);\n\n if (!data.length || !chartConfig) {\n return (\n \n \n \n \n \n \n Loading...\n \n Loading...\n \n \n
\n \n
\n
\n
\n );\n }\n\n return (\n \n \n \n {chartTitle}\n \n {description && {description}}\n setDateRange(value)}\n >\n {dateRangeOptions?.map((value) => (\n \n {value}\n \n ))}\n \n \n \n \n \n \n {\n if (!props.active || !props.payload || !props.payload[0]) {\n return null;\n }\n\n const data = props.payload[0].payload;\n return (\n
\n
\n \n {data.label}\n \n
\n Price:\n \n {data.price > 0.00001\n ? formatUsd(data.price)\n : `$${data.price.toExponential(2)}`}\n \n
\n
\n
\n );\n }}\n />\n \n \n \n \n \n \n \n \n
\n
\n
\n );\n};\n\nexport { PriceChart };\n", + "content": "\"use client\";\r\nimport React from \"react\";\r\n\r\nimport { Area, AreaChart, XAxis } from \"recharts\";\r\nimport { format } from \"date-fns\";\r\n\r\nimport { formatUsd } from \"@/lib/utils\";\r\nimport { SolAsset } from \"@/types/assets\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardDescription,\r\n CardHeader,\r\n CardTitle,\r\n} from \"@/components/ui/card\";\r\nimport {\r\n ChartConfig,\r\n ChartContainer,\r\n ChartTooltip,\r\n} from \"@/components/ui/chart\";\r\nimport { ToggleGroup, ToggleGroupItem } from \"@/components/ui/toggle-group\";\r\nimport { Skeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport { TokenIcon } from \"@/components/ui/murphy/token-icon\";\r\n\r\nexport type TimeScale = \"time\" | \"day\" | \"date\" | \"month\";\r\n\r\nexport type PriceChartProps = {\r\n asset: SolAsset | null;\r\n data: {\r\n timestamp: number;\r\n price: number;\r\n }[];\r\n timeScale?: TimeScale;\r\n title?: string;\r\n description?: string;\r\n onDateRangeChange?: (value: string) => void;\r\n dateRangeOptions?: string[];\r\n defaultDateRange?: string;\r\n};\r\n\r\nconst formatTimestamp = (timestamp: number, timeScale: TimeScale) => {\r\n const ts = timestamp * 1000;\r\n if (timeScale === \"month\") {\r\n return format(ts, \"MMM\");\r\n } else if (timeScale === \"date\") {\r\n return format(ts, \"MMM dd\");\r\n } else if (timeScale === \"day\") {\r\n return format(ts, \"MMM do\");\r\n }\r\n return format(ts, \"HH:mm\");\r\n};\r\n\r\nconst PriceChart = ({\r\n asset,\r\n title,\r\n description,\r\n timeScale = \"time\",\r\n onDateRangeChange,\r\n dateRangeOptions,\r\n defaultDateRange,\r\n data,\r\n}: PriceChartProps) => {\r\n const [dateRange, setDateRange] = React.useState(\r\n defaultDateRange && dateRangeOptions?.includes(defaultDateRange)\r\n ? defaultDateRange\r\n : dateRangeOptions?.[0] || \"1D\",\r\n );\r\n const prevDateRange = React.useRef(dateRange);\r\n\r\n const chartColor = React.useMemo(() => {\r\n if (!data.length) return \"\";\r\n return data[0].price > data[data.length - 1].price\r\n ? \"hsl(var(--destructive))\"\r\n : \"hsl(var(--chart-2))\";\r\n }, [data]);\r\n\r\n const formatXAxis = (timestamp: number) => {\r\n return formatTimestamp(timestamp, timeScale);\r\n };\r\n\r\n const chartData = React.useMemo(() => {\r\n return data.map((item) => ({\r\n ...item,\r\n label: formatTimestamp(item.timestamp, timeScale),\r\n }));\r\n }, [data, timeScale]);\r\n\r\n const chartConfig = React.useMemo(() => {\r\n if (!chartData.length || !asset) return null;\r\n\r\n return {\r\n desktop: {\r\n label: asset.symbol,\r\n color: chartColor,\r\n },\r\n mobile: {\r\n label: asset.symbol,\r\n color: chartColor,\r\n },\r\n } satisfies ChartConfig;\r\n }, [chartData, asset, chartColor]);\r\n\r\n const chartTitle = React.useMemo(() => {\r\n if (!asset) return title || \"Price Chart\";\r\n return asset.symbol ? `${asset.symbol} Price` : title;\r\n }, [asset, title]);\r\n\r\n React.useEffect(() => {\r\n if (prevDateRange.current !== dateRange) {\r\n onDateRangeChange?.(dateRange);\r\n prevDateRange.current = dateRange;\r\n }\r\n }, [dateRange, onDateRangeChange]);\r\n\r\n if (!data.length || !chartConfig) {\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n Loading...\r\n \r\n Loading...\r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n {chartTitle}\r\n \r\n {description && {description}}\r\n setDateRange(value)}\r\n >\r\n {dateRangeOptions?.map((value) => (\r\n \r\n {value}\r\n \r\n ))}\r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n if (!props.active || !props.payload || !props.payload[0]) {\r\n return null;\r\n }\r\n\r\n const data = props.payload[0].payload;\r\n return (\r\n
\r\n
\r\n \r\n {data.label}\r\n \r\n
\r\n Price:\r\n \r\n {data.price > 0.00001\r\n ? formatUsd(data.price)\r\n : `$${data.price.toExponential(2)}`}\r\n \r\n
\r\n
\r\n
\r\n );\r\n }}\r\n />\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport { PriceChart };\r\n", "type": "registry:file", "target": "components/ui/murphy/price-chart.tsx" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" }, { "path": "types/assets/index.ts", - "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\n\nexport type SolAsset = {\n mint: PublicKey;\n name: string;\n symbol: string;\n image: string;\n decimals: number;\n price: number;\n userTokenAccount?: {\n address: PublicKey;\n amount: number;\n };\n};\n\nexport type FetchWalletArgs = {\n owner: PublicKey;\n limit?: number;\n};", + "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\r\n\r\nexport type SolAsset = {\r\n mint: PublicKey;\r\n name: string;\r\n symbol: string;\r\n image: string;\r\n decimals: number;\r\n price: number;\r\n userTokenAccount?: {\r\n address: PublicKey;\r\n amount: number;\r\n };\r\n};\r\n\r\nexport type FetchWalletArgs = {\r\n owner: PublicKey;\r\n limit?: number;\r\n};", "type": "registry:file", "target": "types/assets/index.ts" } diff --git a/public/r/send-token-form.json b/public/r/send-token-form.json index 22e1e55..2092569 100644 --- a/public/r/send-token-form.json +++ b/public/r/send-token-form.json @@ -24,7 +24,7 @@ "files": [ { "path": "components/ui/murphy/send-token-form.tsx", - "content": "\"use client\";\n\nimport { useState, useEffect, useMemo } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { ArrowRight, Loader2, Wallet } from \"lucide-react\";\nimport {\n PublicKey,\n Transaction,\n SystemProgram,\n LAMPORTS_PER_SOL,\n} from \"@solana/web3.js\";\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\nimport {\n createTransferInstruction,\n getAssociatedTokenAddress,\n} from \"@solana/spl-token\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n SelectGroup,\n} from \"@/components/ui/select\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\n\n// Type for our form values\ntype FormValues = {\n destination: string;\n amount: number | undefined;\n token: string;\n};\n\n// Type for token options\nexport type TokenInfo = {\n id: string;\n symbol: string;\n name: string;\n balance: number;\n decimals: number;\n mintAddress?: string;\n icon?: string;\n};\n\n// Create a custom resolver that doesn't cause deep instantiation error\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate destination\n if (!data.destination) {\n errors.destination = {\n type: \"required\",\n message: \"Destination address is required\",\n };\n } else if (data.destination.length < 32) {\n errors.destination = {\n type: \"minLength\",\n message: \"Destination address must be a valid Solana address\",\n };\n }\n\n // Validate amount\n if (data.amount === undefined || data.amount === null || data.amount === \"\") {\n errors.amount = {\n type: \"required\",\n message: \"Amount is required\",\n };\n } else if (Number(data.amount) <= 0) {\n errors.amount = {\n type: \"min\",\n message: \"Amount must be greater than 0\",\n };\n }\n\n // Validate token\n if (!data.token) {\n errors.token = {\n type: \"required\",\n message: \"Please select a token\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport interface SendTokenFormProps {\n onSendToken?: (values: FormValues) => Promise;\n tokens?: TokenInfo[];\n isLoading?: boolean;\n showTokenBalance?: boolean;\n validateDestination?: (address: string) => Promise;\n className?: string;\n}\n\nexport function SendTokenForm({\n onSendToken,\n tokens,\n isLoading = false,\n showTokenBalance = true,\n validateDestination,\n className,\n}: SendTokenFormProps) {\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [selectedToken, setSelectedToken] = useState(null);\n const [isLoadingTokens, setIsLoadingTokens] = useState(false);\n const [isUpdatingBalance, setIsUpdatingBalance] = useState(false);\n const { publicKey, connected, sendTransaction } = useWallet();\n const { connection } = useConnection();\n const [amountValue, setAmountValue] = useState(\"\");\n\n // Default form with explicit type to avoid deep instantiation error\n const form = useForm({\n defaultValues: {\n destination: \"\",\n amount: undefined,\n token: \"\",\n },\n resolver: customResolver,\n });\n\n // Load available tokens from wallet\n const [availableTokens, setAvailableTokens] = useState([]);\n\n // Determine network from connection endpoint\n const networkName = useMemo(() => {\n if (!connection) return \"Unknown\";\n\n const endpoint = connection.rpcEndpoint;\n\n if (endpoint.includes(\"devnet\")) return \"Devnet\";\n if (endpoint.includes(\"testnet\")) return \"Testnet\";\n if (endpoint.includes(\"mainnet\")) return \"Mainnet\";\n if (endpoint.includes(\"localhost\") || endpoint.includes(\"127.0.0.1\"))\n return \"Localnet\";\n\n // Custom endpoint - show partial URL\n const url = new URL(endpoint);\n return url.hostname;\n }, [connection]);\n\n // Fetch token accounts from devnet\n const fetchTokenAccounts = async (ownerPublicKey: PublicKey) => {\n try {\n setIsLoadingTokens(true);\n\n // Default SOL token\n let solBalance = 0;\n\n // Get SOL balance using connection from provider\n try {\n solBalance =\n (await connection.getBalance(ownerPublicKey)) / LAMPORTS_PER_SOL;\n } catch (error) {\n console.error(\"Error fetching SOL balance:\", error);\n }\n\n // Always include SOL with the real balance\n const defaultTokens: TokenInfo[] = [\n {\n id: \"sol\",\n symbol: \"SOL\",\n name: \"Solana\",\n balance: solBalance,\n decimals: 9,\n mintAddress: \"So11111111111111111111111111111111111111112\", // Native SOL mint address\n icon: \"/crypto-logos/solana-logo.svg\",\n },\n ];\n\n // Fetch SPL tokens using the provider connection\n const splTokens: TokenInfo[] = [];\n\n try {\n // Use getParsedTokenAccountsByOwner from the provider connection\n const tokenAccounts = await connection.getParsedTokenAccountsByOwner(\n ownerPublicKey,\n {\n programId: new PublicKey(\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n ),\n }\n );\n\n for (const account of tokenAccounts.value) {\n const accountData = account.account.data.parsed.info;\n const mintAddress = accountData.mint;\n const tokenAmount = accountData.tokenAmount;\n\n if (tokenAmount.uiAmount > 0) {\n // Only include tokens with non-zero balance\n splTokens.push({\n id: mintAddress,\n symbol: mintAddress.substring(0, 4) + \"...\", // Use shortened mint as symbol if no metadata\n name: \"Token \" + mintAddress.substring(0, 6), // Use shortened mint as name if no metadata\n balance: tokenAmount.uiAmount,\n decimals: tokenAmount.decimals,\n mintAddress: mintAddress,\n });\n }\n }\n } catch (error) {\n console.error(\"Error fetching SPL token accounts:\", error);\n }\n\n // Return combined tokens - using spread operator to combine arrays\n return [...defaultTokens, ...splTokens];\n } catch (error) {\n console.error(\"Error fetching token accounts:\", error);\n // Return basic SOL token on error\n return [\n {\n id: \"sol\",\n symbol: \"SOL\",\n name: \"Solana\",\n balance: 0,\n decimals: 9,\n icon: \"/crypto-logos/solana-logo.svg\",\n },\n ];\n } finally {\n setIsLoadingTokens(false);\n }\n };\n\n useEffect(() => {\n // If tokens are provided as props, use those\n if (tokens) {\n setAvailableTokens(tokens);\n }\n // Otherwise, if wallet is connected, fetch tokens\n else if (connected && publicKey) {\n fetchTokenAccounts(publicKey)\n .then((fetchedTokens) => {\n setAvailableTokens(fetchedTokens);\n })\n .catch((error) => {\n console.error(\"Error setting tokens:\", error);\n // Set default SOL token on error\n setAvailableTokens([\n {\n id: \"sol\",\n symbol: \"SOL\",\n name: \"Solana\",\n balance: 0,\n decimals: 9,\n icon: \"/crypto-logos/solana-logo.svg\",\n },\n ]);\n });\n }\n }, [tokens, connected, publicKey]);\n\n // Validate Solana address\n const isValidSolanaAddress = async (address: string): Promise => {\n try {\n if (validateDestination) {\n return await validateDestination(address);\n }\n\n // Basic validation - check if it's a valid Solana public key format\n new PublicKey(address);\n return true;\n } catch (error) {\n return false;\n }\n };\n\n // Handle form submission with actual token transfer\n async function handleSubmit(values: FormValues) {\n if (!connected || !publicKey || !connection) {\n toast.error(\"Wallet not connected\", {\n description: \"Please connect your wallet to send tokens\",\n });\n return;\n }\n\n const isValid = await isValidSolanaAddress(values.destination);\n if (!isValid) {\n toast.error(\"Invalid destination address\", {\n description: \"Please enter a valid Solana address\",\n });\n return;\n }\n\n try {\n setIsSubmitting(true);\n\n toast.message(\"Processing transaction...\", {\n description: \"Preparing to send tokens to destination address\",\n });\n\n if (onSendToken) {\n await onSendToken(values);\n } else {\n const destinationPubkey = new PublicKey(values.destination);\n const selectedTokenInfo = availableTokens.find(\n (t) => t.id === values.token\n );\n\n if (!selectedTokenInfo || values.amount === undefined) {\n throw new Error(\"Invalid token or amount\");\n }\n\n const transaction = new Transaction();\n\n if (values.token === \"sol\") {\n transaction.add(\n SystemProgram.transfer({\n fromPubkey: publicKey,\n toPubkey: destinationPubkey,\n lamports: Math.floor(values.amount * LAMPORTS_PER_SOL),\n })\n );\n } else if (selectedTokenInfo.mintAddress) {\n const mintPubkey = new PublicKey(selectedTokenInfo.mintAddress);\n const senderATA = await getAssociatedTokenAddress(\n mintPubkey,\n publicKey\n );\n const receiverATA = await getAssociatedTokenAddress(\n mintPubkey,\n destinationPubkey\n );\n\n transaction.add(\n createTransferInstruction(\n senderATA,\n receiverATA,\n publicKey,\n Math.floor(\n values.amount * Math.pow(10, selectedTokenInfo.decimals)\n )\n )\n );\n }\n\n const { blockhash } = await connection.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.feePayer = publicKey;\n\n const signature = await sendTransaction(transaction, connection);\n\n toast.message(\"Transaction sent\", {\n description: \"Waiting for confirmation...\",\n });\n\n try {\n let confirmed = false;\n let retries = 0;\n const maxRetries = 30;\n\n while (!confirmed && retries < maxRetries) {\n retries++;\n await new Promise((resolve) => setTimeout(resolve, 1000));\n const { value } = await connection.getSignatureStatus(signature);\n\n if (\n value?.confirmationStatus === \"confirmed\" ||\n value?.confirmationStatus === \"finalized\"\n ) {\n confirmed = true;\n break;\n }\n }\n\n if (!confirmed) {\n throw new Error(\n \"Transaction confirmation timed out. Please check your wallet for status.\"\n );\n }\n } catch (confirmError) {\n console.error(\"Error confirming transaction:\", confirmError);\n toast.warning(\"Transaction sent but confirmation failed\", {\n description:\n \"Your transaction was submitted but we couldn't confirm it. Please check your wallet for status.\",\n });\n }\n }\n\n toast.success(\"Transaction complete\", {\n description: `Successfully sent ${values.amount} ${\n selectedToken?.symbol || values.token\n } to ${values.destination.slice(0, 6)}...${values.destination.slice(\n -4\n )}`,\n });\n\n if (publicKey) {\n setIsUpdatingBalance(true);\n\n setTimeout(async () => {\n try {\n const updatedTokens = await fetchTokenAccounts(publicKey);\n\n setAvailableTokens((prevTokens) => {\n return prevTokens.map((token) => {\n const updatedToken = updatedTokens.find(\n (t) => t.id === token.id\n );\n if (updatedToken) {\n return { ...token, balance: updatedToken.balance };\n }\n return token;\n });\n });\n\n if (selectedToken) {\n const updatedToken = updatedTokens.find(\n (t) => t.id === selectedToken.id\n );\n if (updatedToken) {\n setSelectedToken((prev) =>\n prev ? { ...prev, balance: updatedToken.balance } : null\n );\n }\n }\n\n toast.message(\"Balance updated\", {\n description: \"Your token balances have been refreshed\",\n });\n } catch (error) {\n console.error(\"Error updating balances:\", error);\n } finally {\n setIsUpdatingBalance(false);\n }\n }, 2000);\n }\n\n const currentTokenValue = form.getValues(\"token\");\n form.reset({\n destination: \"\",\n amount: undefined,\n token: currentTokenValue,\n });\n setAmountValue(\"\");\n } catch (error) {\n console.error(\"Transaction error:\", error);\n toast.error(\"Transaction failed\", {\n description:\n error instanceof Error ? error.message : \"Unknown error occurred\",\n });\n } finally {\n setTimeout(() => {\n setIsSubmitting(false);\n }, 1000);\n }\n }\n\n const handleTokenChange = (value: string) => {\n const token = availableTokens.find((t) => t.id === value);\n if (token) {\n setSelectedToken(token);\n form.setValue(\"token\", value);\n }\n };\n\n const renderTokenItem = (token: TokenInfo) => (\n \n
\n
\n {token.icon && (\n
\n {\n (e.target as HTMLImageElement).style.display = \"none\";\n }}\n />\n
\n )}\n {token.symbol}\n
\n {showTokenBalance && (\n \n {token.balance.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: token.decimals > 6 ? 6 : token.decimals,\n })}\n \n )}\n
\n
\n );\n\n return (\n \n \n \n \n Send Tokens\n \n \n \n
\n e.preventDefault()} className=\"space-y-6\">\n (\n \n Destination Address\n \n \n \n \n \n )}\n />\n\n
\n (\n \n Token\n \n \n \n \n \n \n \n {isLoadingTokens || isUpdatingBalance ? (\n
\n \n \n {isUpdatingBalance\n ? \"Updating balances...\"\n : \"Loading tokens...\"}\n \n
\n ) : availableTokens.length > 0 ? (\n \n {availableTokens.map(renderTokenItem)}\n \n ) : (\n
\n No tokens found\n
\n )}\n
\n \n \n
\n )}\n />\n\n (\n \n
\n Amount\n
\n \n {\n setAmountValue(e.target.value);\n field.onChange(\n e.target.value === \"\"\n ? undefined\n : Number.parseFloat(e.target.value)\n );\n }}\n disabled={!connected}\n />\n \n {selectedToken && showTokenBalance && (\n

\n Available:{\" \"}\n {selectedToken.balance.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits:\n selectedToken.decimals > 6\n ? 6\n : selectedToken.decimals,\n })}{\" \"}\n {selectedToken.symbol}\n

\n )}\n \n
\n )}\n />\n
\n\n {connected ? (\n form.handleSubmit(handleSubmit)()}\n className=\"w-full\"\n disabled={isSubmitting || isLoading || isLoadingTokens}\n >\n {isSubmitting ? (\n <>\n \n Processing Transaction...\n \n ) : (\n <>\n Send Tokens\n \n \n )}\n \n ) : (\n \n Connect Wallet\n \n )}\n\n {connected && (\n
\n
\n Network\n \n {networkName}\n \n
\n
\n )}\n \n \n
\n
\n );\n}\n", + "content": "\"use client\";\r\n\r\nimport { useState, useEffect, useMemo } from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { ArrowRight, Loader2, Wallet } from \"lucide-react\";\r\nimport {\r\n PublicKey,\r\n Transaction,\r\n SystemProgram,\r\n LAMPORTS_PER_SOL,\r\n} from \"@solana/web3.js\";\r\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\r\nimport {\r\n createTransferInstruction,\r\n getAssociatedTokenAddress,\r\n} from \"@solana/spl-token\";\r\n\r\nimport { Button } from \"@/components/ui/button\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n SelectGroup,\r\n} from \"@/components/ui/select\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\n\r\n// Type for our form values\r\ntype FormValues = {\r\n destination: string;\r\n amount: number | undefined;\r\n token: string;\r\n};\r\n\r\n// Type for token options\r\nexport type TokenInfo = {\r\n id: string;\r\n symbol: string;\r\n name: string;\r\n balance: number;\r\n decimals: number;\r\n mintAddress?: string;\r\n icon?: string;\r\n};\r\n\r\n// Create a custom resolver that doesn't cause deep instantiation error\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate destination\r\n if (!data.destination) {\r\n errors.destination = {\r\n type: \"required\",\r\n message: \"Destination address is required\",\r\n };\r\n } else if (data.destination.length < 32) {\r\n errors.destination = {\r\n type: \"minLength\",\r\n message: \"Destination address must be a valid Solana address\",\r\n };\r\n }\r\n\r\n // Validate amount\r\n if (data.amount === undefined || data.amount === null || data.amount === \"\") {\r\n errors.amount = {\r\n type: \"required\",\r\n message: \"Amount is required\",\r\n };\r\n } else if (Number(data.amount) <= 0) {\r\n errors.amount = {\r\n type: \"min\",\r\n message: \"Amount must be greater than 0\",\r\n };\r\n }\r\n\r\n // Validate token\r\n if (!data.token) {\r\n errors.token = {\r\n type: \"required\",\r\n message: \"Please select a token\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport interface SendTokenFormProps {\r\n onSendToken?: (values: FormValues) => Promise;\r\n tokens?: TokenInfo[];\r\n isLoading?: boolean;\r\n showTokenBalance?: boolean;\r\n validateDestination?: (address: string) => Promise;\r\n className?: string;\r\n}\r\n\r\nexport function SendTokenForm({\r\n onSendToken,\r\n tokens,\r\n isLoading = false,\r\n showTokenBalance = true,\r\n validateDestination,\r\n className,\r\n}: SendTokenFormProps) {\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [selectedToken, setSelectedToken] = useState(null);\r\n const [isLoadingTokens, setIsLoadingTokens] = useState(false);\r\n const [isUpdatingBalance, setIsUpdatingBalance] = useState(false);\r\n const { publicKey, connected, sendTransaction } = useWallet();\r\n const { connection } = useConnection();\r\n const [amountValue, setAmountValue] = useState(\"\");\r\n\r\n // Default form with explicit type to avoid deep instantiation error\r\n const form = useForm({\r\n defaultValues: {\r\n destination: \"\",\r\n amount: undefined,\r\n token: \"\",\r\n },\r\n resolver: customResolver,\r\n });\r\n\r\n // Load available tokens from wallet\r\n const [availableTokens, setAvailableTokens] = useState([]);\r\n\r\n // Determine network from connection endpoint\r\n const networkName = useMemo(() => {\r\n if (!connection) return \"Unknown\";\r\n\r\n const endpoint = connection.rpcEndpoint;\r\n\r\n if (endpoint.includes(\"devnet\")) return \"Devnet\";\r\n if (endpoint.includes(\"testnet\")) return \"Testnet\";\r\n if (endpoint.includes(\"mainnet\")) return \"Mainnet\";\r\n if (endpoint.includes(\"localhost\") || endpoint.includes(\"127.0.0.1\"))\r\n return \"Localnet\";\r\n\r\n // Custom endpoint - show partial URL\r\n const url = new URL(endpoint);\r\n return url.hostname;\r\n }, [connection]);\r\n\r\n // Fetch token accounts from devnet\r\n const fetchTokenAccounts = async (ownerPublicKey: PublicKey) => {\r\n try {\r\n setIsLoadingTokens(true);\r\n\r\n // Default SOL token\r\n let solBalance = 0;\r\n\r\n // Get SOL balance using connection from provider\r\n try {\r\n solBalance =\r\n (await connection.getBalance(ownerPublicKey)) / LAMPORTS_PER_SOL;\r\n } catch (error) {\r\n console.error(\"Error fetching SOL balance:\", error);\r\n }\r\n\r\n // Always include SOL with the real balance\r\n const defaultTokens: TokenInfo[] = [\r\n {\r\n id: \"sol\",\r\n symbol: \"SOL\",\r\n name: \"Solana\",\r\n balance: solBalance,\r\n decimals: 9,\r\n mintAddress: \"So11111111111111111111111111111111111111112\", // Native SOL mint address\r\n icon: \"/crypto-logos/solana-logo.svg\",\r\n },\r\n ];\r\n\r\n // Fetch SPL tokens using the provider connection\r\n const splTokens: TokenInfo[] = [];\r\n\r\n try {\r\n // Use getParsedTokenAccountsByOwner from the provider connection\r\n const tokenAccounts = await connection.getParsedTokenAccountsByOwner(\r\n ownerPublicKey,\r\n {\r\n programId: new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n ),\r\n }\r\n );\r\n\r\n for (const account of tokenAccounts.value) {\r\n const accountData = account.account.data.parsed.info;\r\n const mintAddress = accountData.mint;\r\n const tokenAmount = accountData.tokenAmount;\r\n\r\n if (tokenAmount.uiAmount > 0) {\r\n // Only include tokens with non-zero balance\r\n splTokens.push({\r\n id: mintAddress,\r\n symbol: mintAddress.substring(0, 4) + \"...\", // Use shortened mint as symbol if no metadata\r\n name: \"Token \" + mintAddress.substring(0, 6), // Use shortened mint as name if no metadata\r\n balance: tokenAmount.uiAmount,\r\n decimals: tokenAmount.decimals,\r\n mintAddress: mintAddress,\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\"Error fetching SPL token accounts:\", error);\r\n }\r\n\r\n // Return combined tokens - using spread operator to combine arrays\r\n return [...defaultTokens, ...splTokens];\r\n } catch (error) {\r\n console.error(\"Error fetching token accounts:\", error);\r\n // Return basic SOL token on error\r\n return [\r\n {\r\n id: \"sol\",\r\n symbol: \"SOL\",\r\n name: \"Solana\",\r\n balance: 0,\r\n decimals: 9,\r\n icon: \"/crypto-logos/solana-logo.svg\",\r\n },\r\n ];\r\n } finally {\r\n setIsLoadingTokens(false);\r\n }\r\n };\r\n\r\n useEffect(() => {\r\n // If tokens are provided as props, use those\r\n if (tokens) {\r\n setAvailableTokens(tokens);\r\n }\r\n // Otherwise, if wallet is connected, fetch tokens\r\n else if (connected && publicKey) {\r\n fetchTokenAccounts(publicKey)\r\n .then((fetchedTokens) => {\r\n setAvailableTokens(fetchedTokens);\r\n })\r\n .catch((error) => {\r\n console.error(\"Error setting tokens:\", error);\r\n // Set default SOL token on error\r\n setAvailableTokens([\r\n {\r\n id: \"sol\",\r\n symbol: \"SOL\",\r\n name: \"Solana\",\r\n balance: 0,\r\n decimals: 9,\r\n icon: \"/crypto-logos/solana-logo.svg\",\r\n },\r\n ]);\r\n });\r\n }\r\n }, [tokens, connected, publicKey]);\r\n\r\n // Validate Solana address\r\n const isValidSolanaAddress = async (address: string): Promise => {\r\n try {\r\n if (validateDestination) {\r\n return await validateDestination(address);\r\n }\r\n\r\n // Basic validation - check if it's a valid Solana public key format\r\n new PublicKey(address);\r\n return true;\r\n } catch (error) {\r\n return false;\r\n }\r\n };\r\n\r\n // Handle form submission with actual token transfer\r\n async function handleSubmit(values: FormValues) {\r\n if (!connected || !publicKey || !connection) {\r\n toast.error(\"Wallet not connected\", {\r\n description: \"Please connect your wallet to send tokens\",\r\n });\r\n return;\r\n }\r\n\r\n const isValid = await isValidSolanaAddress(values.destination);\r\n if (!isValid) {\r\n toast.error(\"Invalid destination address\", {\r\n description: \"Please enter a valid Solana address\",\r\n });\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n\r\n toast.message(\"Processing transaction...\", {\r\n description: \"Preparing to send tokens to destination address\",\r\n });\r\n\r\n if (onSendToken) {\r\n await onSendToken(values);\r\n } else {\r\n const destinationPubkey = new PublicKey(values.destination);\r\n const selectedTokenInfo = availableTokens.find(\r\n (t) => t.id === values.token\r\n );\r\n\r\n if (!selectedTokenInfo || values.amount === undefined) {\r\n throw new Error(\"Invalid token or amount\");\r\n }\r\n\r\n const transaction = new Transaction();\r\n\r\n if (values.token === \"sol\") {\r\n transaction.add(\r\n SystemProgram.transfer({\r\n fromPubkey: publicKey,\r\n toPubkey: destinationPubkey,\r\n lamports: Math.floor(values.amount * LAMPORTS_PER_SOL),\r\n })\r\n );\r\n } else if (selectedTokenInfo.mintAddress) {\r\n const mintPubkey = new PublicKey(selectedTokenInfo.mintAddress);\r\n const senderATA = await getAssociatedTokenAddress(\r\n mintPubkey,\r\n publicKey\r\n );\r\n const receiverATA = await getAssociatedTokenAddress(\r\n mintPubkey,\r\n destinationPubkey\r\n );\r\n\r\n transaction.add(\r\n createTransferInstruction(\r\n senderATA,\r\n receiverATA,\r\n publicKey,\r\n Math.floor(\r\n values.amount * Math.pow(10, selectedTokenInfo.decimals)\r\n )\r\n )\r\n );\r\n }\r\n\r\n const { blockhash } = await connection.getLatestBlockhash();\r\n transaction.recentBlockhash = blockhash;\r\n transaction.feePayer = publicKey;\r\n\r\n const signature = await sendTransaction(transaction, connection);\r\n\r\n toast.message(\"Transaction sent\", {\r\n description: \"Waiting for confirmation...\",\r\n });\r\n\r\n try {\r\n let confirmed = false;\r\n let retries = 0;\r\n const maxRetries = 30;\r\n\r\n while (!confirmed && retries < maxRetries) {\r\n retries++;\r\n await new Promise((resolve) => setTimeout(resolve, 1000));\r\n const { value } = await connection.getSignatureStatus(signature);\r\n\r\n if (\r\n value?.confirmationStatus === \"confirmed\" ||\r\n value?.confirmationStatus === \"finalized\"\r\n ) {\r\n confirmed = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!confirmed) {\r\n throw new Error(\r\n \"Transaction confirmation timed out. Please check your wallet for status.\"\r\n );\r\n }\r\n } catch (confirmError) {\r\n console.error(\"Error confirming transaction:\", confirmError);\r\n toast.warning(\"Transaction sent but confirmation failed\", {\r\n description:\r\n \"Your transaction was submitted but we couldn't confirm it. Please check your wallet for status.\",\r\n });\r\n }\r\n }\r\n\r\n toast.success(\"Transaction complete\", {\r\n description: `Successfully sent ${values.amount} ${\r\n selectedToken?.symbol || values.token\r\n } to ${values.destination.slice(0, 6)}...${values.destination.slice(\r\n -4\r\n )}`,\r\n });\r\n\r\n if (publicKey) {\r\n setIsUpdatingBalance(true);\r\n\r\n setTimeout(async () => {\r\n try {\r\n const updatedTokens = await fetchTokenAccounts(publicKey);\r\n\r\n setAvailableTokens((prevTokens) => {\r\n return prevTokens.map((token) => {\r\n const updatedToken = updatedTokens.find(\r\n (t) => t.id === token.id\r\n );\r\n if (updatedToken) {\r\n return { ...token, balance: updatedToken.balance };\r\n }\r\n return token;\r\n });\r\n });\r\n\r\n if (selectedToken) {\r\n const updatedToken = updatedTokens.find(\r\n (t) => t.id === selectedToken.id\r\n );\r\n if (updatedToken) {\r\n setSelectedToken((prev) =>\r\n prev ? { ...prev, balance: updatedToken.balance } : null\r\n );\r\n }\r\n }\r\n\r\n toast.message(\"Balance updated\", {\r\n description: \"Your token balances have been refreshed\",\r\n });\r\n } catch (error) {\r\n console.error(\"Error updating balances:\", error);\r\n } finally {\r\n setIsUpdatingBalance(false);\r\n }\r\n }, 2000);\r\n }\r\n\r\n const currentTokenValue = form.getValues(\"token\");\r\n form.reset({\r\n destination: \"\",\r\n amount: undefined,\r\n token: currentTokenValue,\r\n });\r\n setAmountValue(\"\");\r\n } catch (error) {\r\n console.error(\"Transaction error:\", error);\r\n toast.error(\"Transaction failed\", {\r\n description:\r\n error instanceof Error ? error.message : \"Unknown error occurred\",\r\n });\r\n } finally {\r\n setTimeout(() => {\r\n setIsSubmitting(false);\r\n }, 1000);\r\n }\r\n }\r\n\r\n const handleTokenChange = (value: string) => {\r\n const token = availableTokens.find((t) => t.id === value);\r\n if (token) {\r\n setSelectedToken(token);\r\n form.setValue(\"token\", value);\r\n }\r\n };\r\n\r\n const renderTokenItem = (token: TokenInfo) => (\r\n \r\n
\r\n
\r\n {token.icon && (\r\n
\r\n {\r\n (e.target as HTMLImageElement).style.display = \"none\";\r\n }}\r\n />\r\n
\r\n )}\r\n {token.symbol}\r\n
\r\n {showTokenBalance && (\r\n \r\n {token.balance.toLocaleString(undefined, {\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: token.decimals > 6 ? 6 : token.decimals,\r\n })}\r\n \r\n )}\r\n
\r\n
\r\n );\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n Send Tokens\r\n \r\n \r\n \r\n
\r\n e.preventDefault()} className=\"space-y-6\">\r\n (\r\n \r\n Destination Address\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n\r\n
\r\n (\r\n \r\n Token\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {isLoadingTokens || isUpdatingBalance ? (\r\n
\r\n \r\n \r\n {isUpdatingBalance\r\n ? \"Updating balances...\"\r\n : \"Loading tokens...\"}\r\n \r\n
\r\n ) : availableTokens.length > 0 ? (\r\n \r\n {availableTokens.map(renderTokenItem)}\r\n \r\n ) : (\r\n
\r\n No tokens found\r\n
\r\n )}\r\n
\r\n \r\n \r\n
\r\n )}\r\n />\r\n\r\n (\r\n \r\n
\r\n Amount\r\n
\r\n \r\n {\r\n setAmountValue(e.target.value);\r\n field.onChange(\r\n e.target.value === \"\"\r\n ? undefined\r\n : Number.parseFloat(e.target.value)\r\n );\r\n }}\r\n disabled={!connected}\r\n />\r\n \r\n {selectedToken && showTokenBalance && (\r\n

\r\n Available:{\" \"}\r\n {selectedToken.balance.toLocaleString(undefined, {\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits:\r\n selectedToken.decimals > 6\r\n ? 6\r\n : selectedToken.decimals,\r\n })}{\" \"}\r\n {selectedToken.symbol}\r\n

\r\n )}\r\n \r\n
\r\n )}\r\n />\r\n
\r\n\r\n {connected ? (\r\n form.handleSubmit(handleSubmit)()}\r\n className=\"w-full\"\r\n disabled={isSubmitting || isLoading || isLoadingTokens}\r\n >\r\n {isSubmitting ? (\r\n <>\r\n \r\n Processing Transaction...\r\n \r\n ) : (\r\n <>\r\n Send Tokens\r\n \r\n \r\n )}\r\n \r\n ) : (\r\n \r\n Connect Wallet\r\n \r\n )}\r\n\r\n {connected && (\r\n
\r\n
\r\n Network\r\n \r\n {networkName}\r\n \r\n
\r\n
\r\n )}\r\n \r\n \r\n
\r\n
\r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/send-token-form.tsx" } diff --git a/public/r/sparkline.json b/public/r/sparkline.json index a7e746f..72bab34 100644 --- a/public/r/sparkline.json +++ b/public/r/sparkline.json @@ -12,13 +12,13 @@ "files": [ { "path": "components/ui/murphy/price-change.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { cn, formatUsd } from \"@/lib/utils\";\n\ntype PriceChangeProps = {\n data: {\n timestamp: number;\n price: number;\n }[];\n type?: \"%\" | \"$\";\n};\n\nconst PriceChange = ({ data, type = \"%\" }: PriceChangeProps) => {\n const [selectedType, setSelectedType] = React.useState(type);\n const startPrice = data[0]?.price || 0;\n const endPrice = data[data.length - 1]?.price || 0;\n const priceDifference = endPrice - startPrice;\n const percentageChange = (priceDifference / startPrice) * 100;\n const isPositive = priceDifference > 0;\n\n if (!data[0]?.price) return null;\n\n return (\n setSelectedType(selectedType === \"%\" ? \"$\" : \"%\")}\n >\n {isPositive && \"+\"}\n {selectedType === \"%\"\n ? `${percentageChange.toFixed(2)}%`\n : `${formatUsd(priceDifference)}`}\n \n );\n};\n\nexport { PriceChange };", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\nimport { cn, formatUsd } from \"@/lib/utils\";\r\n\r\ntype PriceChangeProps = {\r\n data: {\r\n timestamp: number;\r\n price: number;\r\n }[];\r\n type?: \"%\" | \"$\";\r\n};\r\n\r\nconst PriceChange = ({ data, type = \"%\" }: PriceChangeProps) => {\r\n const [selectedType, setSelectedType] = React.useState(type);\r\n const startPrice = data[0]?.price || 0;\r\n const endPrice = data[data.length - 1]?.price || 0;\r\n const priceDifference = endPrice - startPrice;\r\n const percentageChange = (priceDifference / startPrice) * 100;\r\n const isPositive = priceDifference > 0;\r\n\r\n if (!data[0]?.price) return null;\r\n\r\n return (\r\n setSelectedType(selectedType === \"%\" ? \"$\" : \"%\")}\r\n >\r\n {isPositive && \"+\"}\r\n {selectedType === \"%\"\r\n ? `${percentageChange.toFixed(2)}%`\r\n : `${formatUsd(priceDifference)}`}\r\n \r\n );\r\n};\r\n\r\nexport { PriceChange };", "type": "registry:file", "target": "components/ui/murphy/price-change.tsx" }, { "path": "components/ui/murphy/sparkline.tsx", - "content": "\"use client\";\nimport React from \"react\";\n\nimport { LineChart, CartesianGrid, XAxis, YAxis, Line } from \"recharts\";\n\nimport { ChartConfig, ChartContainer } from \"@/components/ui/chart\";\n\nimport { PriceChange } from \"@/components/ui/murphy/price-change\";\n\ntype SparklineProps = {\n data: {\n timestamp: number;\n price: number;\n }[];\n};\n\nconst chartConfig = {\n desktop: {\n label: \"Price\",\n color: \"hsl(var(--chart-1))\",\n },\n} satisfies ChartConfig;\n\nconst Sparkline = ({ data }: SparklineProps) => {\n if (!data.length) return null;\n\n const minPrice = Math.min(...data.map((d) => d.price));\n const maxPrice = Math.max(...data.map((d) => d.price));\n\n return (\n
\n \n \n \n \n \n \n \n = data[0].price\n ? \"#75ba80\"\n : \"#e07d6f\"\n }\n stopOpacity={0.8}\n />\n = data[0].price\n ? \"#75ba80\"\n : \"#e07d6f\"\n }\n stopOpacity={0.1}\n />\n \n \n = data[0].price\n ? \"#75ba80\"\n : \"#e07d6f\"\n }\n />\n \n \n
\n \n
\n
\n );\n};\n\nexport { Sparkline };\n", + "content": "\"use client\";\r\nimport React from \"react\";\r\n\r\nimport { LineChart, CartesianGrid, XAxis, YAxis, Line } from \"recharts\";\r\n\r\nimport { ChartConfig, ChartContainer } from \"@/components/ui/chart\";\r\n\r\nimport { PriceChange } from \"@/components/ui/murphy/price-change\";\r\n\r\ntype SparklineProps = {\r\n data: {\r\n timestamp: number;\r\n price: number;\r\n }[];\r\n};\r\n\r\nconst chartConfig = {\r\n desktop: {\r\n label: \"Price\",\r\n color: \"hsl(var(--chart-1))\",\r\n },\r\n} satisfies ChartConfig;\r\n\r\nconst Sparkline = ({ data }: SparklineProps) => {\r\n if (!data.length) return null;\r\n\r\n const minPrice = Math.min(...data.map((d) => d.price));\r\n const maxPrice = Math.max(...data.map((d) => d.price));\r\n\r\n return (\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n = data[0].price\r\n ? \"#75ba80\"\r\n : \"#e07d6f\"\r\n }\r\n stopOpacity={0.8}\r\n />\r\n = data[0].price\r\n ? \"#75ba80\"\r\n : \"#e07d6f\"\r\n }\r\n stopOpacity={0.1}\r\n />\r\n \r\n \r\n = data[0].price\r\n ? \"#75ba80\"\r\n : \"#e07d6f\"\r\n }\r\n />\r\n \r\n \r\n
\r\n \r\n
\r\n
\r\n );\r\n};\r\n\r\nexport { Sparkline };\r\n", "type": "registry:file", "target": "components/ui/murphy/sparkline.tsx" } diff --git a/public/r/stake-token-form.json b/public/r/stake-token-form.json index 1e89682..d73703c 100644 --- a/public/r/stake-token-form.json +++ b/public/r/stake-token-form.json @@ -22,13 +22,13 @@ "files": [ { "path": "components/ui/murphy/stake-token-form.tsx", - "content": "\"use client\";\n\nimport { useState, useEffect, useMemo, useContext } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { ArrowDown, Loader2, RefreshCw, Settings } from \"lucide-react\";\nimport {\n PublicKey,\n Transaction,\n LAMPORTS_PER_SOL,\n VersionedTransaction,\n clusterApiUrl\n} from \"@solana/web3.js\";\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\nimport { cn } from \"@/lib/utils\";\n\n// Type for stake form values\ntype StakeFormValues = {\n amountToStake: number | undefined;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate amount\n if (data.amountToStake === undefined || data.amountToStake === null || data.amountToStake === \"\") {\n errors.amountToStake = {\n type: \"required\",\n message: \"Amount is required\",\n };\n } else if (Number(data.amountToStake) <= 0) {\n errors.amountToStake = {\n type: \"min\",\n message: \"Amount must be greater than 0\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\nexport function StakeForm({className}: {className?: string}) {\n // State variables\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isLoadingBalance, setIsLoadingBalance] = useState(false);\n const [solBalance, setSolBalance] = useState(\"--\");\n const [amountToStake, setAmountToStake] = useState(\"\");\n const [transactionSignature, setTransactionSignature] = useState('');\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\n const [error, setError] = useState('');\n \n const { publicKey, connected, signTransaction } = useWallet();\n const { connection } = useConnection();\n const { endpoint } = useContext(ModalContext);\n \n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n amountToStake: undefined,\n },\n mode: \"onSubmit\", // Only validate on submit\n resolver: customResolver, // Use our custom resolver\n });\n\n // Add state to store timeout\n const [inputTimeout, setInputTimeout] = useState(null);\n\n // Clear timeout when component unmounts\n useEffect(() => {\n return () => {\n if (inputTimeout) {\n clearTimeout(inputTimeout);\n }\n };\n }, [inputTimeout]);\n\n // Fetch SOL balance when wallet connects\n useEffect(() => {\n if (connected && publicKey) {\n fetchBalance();\n } else {\n setSolBalance('--');\n }\n }, [connected, publicKey, connection]);\n\n // Fetch SOL balance\n const fetchBalance = async () => {\n if (!connected || !publicKey || !connection) return;\n \n setIsLoadingBalance(true);\n try {\n const balance = await connection.getBalance(publicKey);\n const solBalanceFormatted = (balance / LAMPORTS_PER_SOL).toFixed(6);\n setSolBalance(solBalanceFormatted);\n console.log(`fetchBalance: SOL balance = ${solBalanceFormatted}`);\n } catch (error) {\n console.error('Error fetching SOL balance:', error);\n setSolBalance('0');\n toast.error('Unable to fetch SOL balance', {\n description: 'Please check your wallet connection',\n });\n } finally {\n setIsLoadingBalance(false);\n }\n };\n\n // Handle use max amount\n const handleUseMax = (e?: React.MouseEvent) => {\n // Prevent form submit event if there is an event\n if (e) {\n e.preventDefault();\n e.stopPropagation();\n }\n \n if (solBalance !== '--' && parseFloat(solBalance) > 0) {\n // Keep 0.05 SOL for transaction fees\n const maxAmount = Math.max(parseFloat(solBalance) - 0.05, 0);\n setAmountToStake(maxAmount.toString());\n form.setValue(\"amountToStake\", maxAmount, {\n shouldValidate: false,\n shouldDirty: true,\n shouldTouch: true,\n });\n }\n };\n\n // Handle amount input change with debounce\n const handleAmountChange = (value: string) => {\n if (value === '' || /^\\d*\\.?\\d*$/.test(value)) {\n setAmountToStake(value);\n const parsedValue = value === \"\" ? undefined : parseFloat(value);\n form.setValue(\"amountToStake\", parsedValue, {\n shouldValidate: false // Prevent validation\n });\n }\n };\n\n // Handle form submission - Stake SOL with Solayer\n const onSubmit = async (values: StakeFormValues) => {\n if (!connected) {\n toast.error(\"Wallet not connected\");\n return;\n }\n\n if (!publicKey) {\n toast.error(\"Public key not found\");\n return;\n }\n\n if (!connection) {\n toast.error(\"Invalid connection\");\n return;\n }\n\n if (!endpoint) {\n toast.error(\"RPC endpoint not found\");\n return;\n }\n\n if (!values.amountToStake || values.amountToStake <= 0) {\n toast.error(\"Invalid amount\");\n return;\n }\n\n // Check SOL balance\n const inputAmount = values.amountToStake;\n if (solBalance !== '--' && parseFloat(solBalance) < inputAmount) {\n // Allow very small discrepancy for SOL (to account for transaction fees)\n if (inputAmount - parseFloat(solBalance) < 0.001) {\n console.log(`Detected small discrepancy in SOL balance, proceeding`);\n } else {\n toast.error(\"Insufficient SOL balance\");\n return;\n }\n }\n\n try {\n setIsSubmitting(true);\n setError('');\n setCurrentStage('confirming');\n \n // Log transaction information for debugging\n console.log(\"=== Transaction Information ===\");\n console.log(\"Endpoint:\", endpoint);\n console.log(\"Amount:\", values.amountToStake);\n console.log(\"Wallet connected:\", connected ? \"Yes\" : \"No\");\n console.log(\"PublicKey:\", publicKey.toString());\n console.log(\"========================\");\n \n // Use internal API route to avoid CORS error\n const response = await fetch(\n `/api/murphy/solayer/stake?amount=${parseFloat(amountToStake)}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n account: publicKey.toBase58(),\n }),\n },\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || \"Stake request failed\");\n }\n\n const data = await response.json();\n\n // Decode transaction from base64\n const txBuffer = Buffer.from(data.transaction, \"base64\");\n \n // Create VersionedTransaction from received data\n const tx = VersionedTransaction.deserialize(txBuffer);\n \n // Update to latest blockhash\n const { blockhash } = await connection.getLatestBlockhash();\n tx.message.recentBlockhash = blockhash;\n \n // Sign transaction with user's wallet\n if (!signTransaction) {\n throw new Error(\"Wallet does not support transaction signing\");\n }\n \n console.log(\"Signing transaction...\");\n \n try {\n const signedTx = await signTransaction(tx);\n \n console.log(\"Sending transaction...\");\n const signature = await connection.sendRawTransaction(signedTx.serialize());\n \n console.log(\"Transaction sent, signature:\", signature);\n \n // Wait for transaction confirmation\n const latestBlockhash = await connection.getLatestBlockhash();\n await connection.confirmTransaction({\n signature,\n blockhash: latestBlockhash.blockhash,\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\n });\n \n setTransactionSignature(signature);\n setCurrentStage('success');\n \n toast.success(\"Staking successful!\", {\n description: `Transaction: ${signature}`\n });\n \n // Reset form\n setAmountToStake(\"\");\n form.setValue(\"amountToStake\", undefined, {\n shouldValidate: false\n });\n \n // Refresh balance after successful stake\n fetchBalance();\n } catch (signError: any) {\n console.error('Error signing transaction:', signError);\n \n // Analyze user-canceled transaction error\n if (signError.message && signError.message.includes(\"canceled\")) {\n toast.error(\"Transaction canceled\", {\n description: \"You canceled the transaction\"\n });\n setError(\"You canceled the transaction\");\n } else {\n toast.error(\"Error signing transaction\", {\n description: signError.message || \"Unable to sign transaction\"\n });\n setError(`Error signing transaction: ${signError.message}`);\n }\n \n setCurrentStage('error');\n throw signError; // Re-throw to handle in finally\n }\n \n } catch (error: any) {\n console.error('Staking error:', error);\n \n // Signing error already handled above, no need to show toast again\n if (!error.message?.includes(\"canceled\")) {\n setError(`Staking failed: ${error.message}`);\n toast.error(\"Transaction failed\", {\n description: error.message || \"Unable to complete transaction\"\n });\n }\n \n setCurrentStage('error');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Render success view\n const renderSuccess = () => (\n
\n
\n \n \n \n
\n

Staking Successful!

\n

Your SOL has been successfully staked with Solayer.

\n {transactionSignature && (\n \n View transaction\n \n )}\n \n
\n );\n\n // Render error view\n const renderError = () => (\n
\n
\n \n \n \n
\n

Staking Failed

\n

{error || 'An error occurred while staking your SOL.'}

\n \n
\n );\n\n // Render confirmation view\n const renderConfirming = () => (\n
\n
\n \n
\n

Confirming Transaction

\n

Please wait while your staking transaction is being processed...

\n
\n );\n\n // Render input form\n const renderInputForm = () => (\n
\n {\n // Check if clicking MAX button then do not submit\n const target = e.target as HTMLElement;\n const maxButton = target.querySelector('.max-button');\n if (maxButton && (maxButton === document.activeElement || maxButton.contains(document.activeElement as Node))) {\n e.preventDefault();\n return;\n }\n \n e.preventDefault();\n form.handleSubmit(onSubmit)(e);\n }}\n className=\"space-y-4\"\n >\n (\n \n
\n Stake Amount\n
\n \n Balance: {isLoadingBalance ? '...' : solBalance}\n \n {connected && solBalance !== '--' && parseFloat(solBalance) > 0 && (\n
e.stopPropagation()}>\n {\n e.preventDefault();\n e.stopPropagation();\n handleUseMax();\n }}\n >\n MAX\n \n
\n )}\n
\n
\n
\n \n handleAmountChange(e.target.value)}\n disabled={!connected || isSubmitting}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n
\n
\n {\n console.log(\"Error loading SOL logo, using fallback\");\n e.currentTarget.src = \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWNpcmNsZSI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48L3N2Zz4=\"; \n }}\n />\n SOL\n
\n
\n
\n \n
\n )}\n />\n\n
\n
\n
\n Staking Platform\n Solayer\n
\n \n
\n Reward Token\n sSOL\n
\n \n
\n Estimated APY\n 9.26%\n
\n \n
\n Fee\n 0%\n
\n
\n \n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting ? (\n <>\n \n Staking...\n \n ) : (\n (solBalance !== '--' && parseFloat(solBalance) < parseFloat(amountToStake) && \n !(parseFloat(amountToStake) - parseFloat(solBalance) < 0.001))\n ? 'Insufficient SOL balance'\n : 'Stake SOL'\n )}\n \n )}\n
\n
\n \n \n );\n\n // Render based on current stage\n const renderStageContent = () => {\n switch (currentStage) {\n case 'success':\n return renderSuccess();\n case 'error':\n return renderError();\n case 'confirming':\n return renderConfirming();\n default:\n return renderInputForm();\n }\n };\n\n return (\n \n \n \n Stake SOL\n \n \n \n {renderStageContent()}\n \n \n );\n}\n\nexport default StakeForm;", + "content": "\"use client\";\r\n\r\nimport { useState, useEffect, useMemo, useContext } from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { ArrowDown, Loader2, RefreshCw, Settings } from \"lucide-react\";\r\nimport {\r\n PublicKey,\r\n Transaction,\r\n LAMPORTS_PER_SOL,\r\n VersionedTransaction,\r\n clusterApiUrl\r\n} from \"@solana/web3.js\";\r\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n// Type for stake form values\r\ntype StakeFormValues = {\r\n amountToStake: number | undefined;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate amount\r\n if (data.amountToStake === undefined || data.amountToStake === null || data.amountToStake === \"\") {\r\n errors.amountToStake = {\r\n type: \"required\",\r\n message: \"Amount is required\",\r\n };\r\n } else if (Number(data.amountToStake) <= 0) {\r\n errors.amountToStake = {\r\n type: \"min\",\r\n message: \"Amount must be greater than 0\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\nexport function StakeForm({className}: {className?: string}) {\r\n // State variables\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [isLoadingBalance, setIsLoadingBalance] = useState(false);\r\n const [solBalance, setSolBalance] = useState(\"--\");\r\n const [amountToStake, setAmountToStake] = useState(\"\");\r\n const [transactionSignature, setTransactionSignature] = useState('');\r\n const [currentStage, setCurrentStage] = useState('input'); // input, confirming, success, error\r\n const [error, setError] = useState('');\r\n \r\n const { publicKey, connected, signTransaction } = useWallet();\r\n const { connection } = useConnection();\r\n const { endpoint } = useContext(ModalContext);\r\n \r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n amountToStake: undefined,\r\n },\r\n mode: \"onSubmit\", // Only validate on submit\r\n resolver: customResolver, // Use our custom resolver\r\n });\r\n\r\n // Add state to store timeout\r\n const [inputTimeout, setInputTimeout] = useState(null);\r\n\r\n // Clear timeout when component unmounts\r\n useEffect(() => {\r\n return () => {\r\n if (inputTimeout) {\r\n clearTimeout(inputTimeout);\r\n }\r\n };\r\n }, [inputTimeout]);\r\n\r\n // Fetch SOL balance when wallet connects\r\n useEffect(() => {\r\n if (connected && publicKey) {\r\n fetchBalance();\r\n } else {\r\n setSolBalance('--');\r\n }\r\n }, [connected, publicKey, connection]);\r\n\r\n // Fetch SOL balance\r\n const fetchBalance = async () => {\r\n if (!connected || !publicKey || !connection) return;\r\n \r\n setIsLoadingBalance(true);\r\n try {\r\n const balance = await connection.getBalance(publicKey);\r\n const solBalanceFormatted = (balance / LAMPORTS_PER_SOL).toFixed(6);\r\n setSolBalance(solBalanceFormatted);\r\n console.log(`fetchBalance: SOL balance = ${solBalanceFormatted}`);\r\n } catch (error) {\r\n console.error('Error fetching SOL balance:', error);\r\n setSolBalance('0');\r\n toast.error('Unable to fetch SOL balance', {\r\n description: 'Please check your wallet connection',\r\n });\r\n } finally {\r\n setIsLoadingBalance(false);\r\n }\r\n };\r\n\r\n // Handle use max amount\r\n const handleUseMax = (e?: React.MouseEvent) => {\r\n // Prevent form submit event if there is an event\r\n if (e) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n \r\n if (solBalance !== '--' && parseFloat(solBalance) > 0) {\r\n // Keep 0.05 SOL for transaction fees\r\n const maxAmount = Math.max(parseFloat(solBalance) - 0.05, 0);\r\n setAmountToStake(maxAmount.toString());\r\n form.setValue(\"amountToStake\", maxAmount, {\r\n shouldValidate: false,\r\n shouldDirty: true,\r\n shouldTouch: true,\r\n });\r\n }\r\n };\r\n\r\n // Handle amount input change with debounce\r\n const handleAmountChange = (value: string) => {\r\n if (value === '' || /^\\d*\\.?\\d*$/.test(value)) {\r\n setAmountToStake(value);\r\n const parsedValue = value === \"\" ? undefined : parseFloat(value);\r\n form.setValue(\"amountToStake\", parsedValue, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n }\r\n };\r\n\r\n // Handle form submission - Stake SOL with Solayer\r\n const onSubmit = async (values: StakeFormValues) => {\r\n if (!connected) {\r\n toast.error(\"Wallet not connected\");\r\n return;\r\n }\r\n\r\n if (!publicKey) {\r\n toast.error(\"Public key not found\");\r\n return;\r\n }\r\n\r\n if (!connection) {\r\n toast.error(\"Invalid connection\");\r\n return;\r\n }\r\n\r\n if (!endpoint) {\r\n toast.error(\"RPC endpoint not found\");\r\n return;\r\n }\r\n\r\n if (!values.amountToStake || values.amountToStake <= 0) {\r\n toast.error(\"Invalid amount\");\r\n return;\r\n }\r\n\r\n // Check SOL balance\r\n const inputAmount = values.amountToStake;\r\n if (solBalance !== '--' && parseFloat(solBalance) < inputAmount) {\r\n // Allow very small discrepancy for SOL (to account for transaction fees)\r\n if (inputAmount - parseFloat(solBalance) < 0.001) {\r\n console.log(`Detected small discrepancy in SOL balance, proceeding`);\r\n } else {\r\n toast.error(\"Insufficient SOL balance\");\r\n return;\r\n }\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n setError('');\r\n setCurrentStage('confirming');\r\n \r\n // Log transaction information for debugging\r\n console.log(\"=== Transaction Information ===\");\r\n console.log(\"Endpoint:\", endpoint);\r\n console.log(\"Amount:\", values.amountToStake);\r\n console.log(\"Wallet connected:\", connected ? \"Yes\" : \"No\");\r\n console.log(\"PublicKey:\", publicKey.toString());\r\n console.log(\"========================\");\r\n \r\n // Use internal API route to avoid CORS error\r\n const response = await fetch(\r\n `/api/murphy/solayer/stake?amount=${parseFloat(amountToStake)}`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify({\r\n account: publicKey.toBase58(),\r\n }),\r\n },\r\n );\r\n\r\n if (!response.ok) {\r\n const errorData = await response.json();\r\n throw new Error(errorData.error || \"Stake request failed\");\r\n }\r\n\r\n const data = await response.json();\r\n\r\n // Decode transaction from base64\r\n const txBuffer = Buffer.from(data.transaction, \"base64\");\r\n \r\n // Create VersionedTransaction from received data\r\n const tx = VersionedTransaction.deserialize(txBuffer);\r\n \r\n // Update to latest blockhash\r\n const { blockhash } = await connection.getLatestBlockhash();\r\n tx.message.recentBlockhash = blockhash;\r\n \r\n // Sign transaction with user's wallet\r\n if (!signTransaction) {\r\n throw new Error(\"Wallet does not support transaction signing\");\r\n }\r\n \r\n console.log(\"Signing transaction...\");\r\n \r\n try {\r\n const signedTx = await signTransaction(tx);\r\n \r\n console.log(\"Sending transaction...\");\r\n const signature = await connection.sendRawTransaction(signedTx.serialize());\r\n \r\n console.log(\"Transaction sent, signature:\", signature);\r\n \r\n // Wait for transaction confirmation\r\n const latestBlockhash = await connection.getLatestBlockhash();\r\n await connection.confirmTransaction({\r\n signature,\r\n blockhash: latestBlockhash.blockhash,\r\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\r\n });\r\n \r\n setTransactionSignature(signature);\r\n setCurrentStage('success');\r\n \r\n toast.success(\"Staking successful!\", {\r\n description: `Transaction: ${signature}`\r\n });\r\n \r\n // Reset form\r\n setAmountToStake(\"\");\r\n form.setValue(\"amountToStake\", undefined, {\r\n shouldValidate: false\r\n });\r\n \r\n // Refresh balance after successful stake\r\n fetchBalance();\r\n } catch (signError: any) {\r\n console.error('Error signing transaction:', signError);\r\n \r\n // Analyze user-canceled transaction error\r\n if (signError.message && signError.message.includes(\"canceled\")) {\r\n toast.error(\"Transaction canceled\", {\r\n description: \"You canceled the transaction\"\r\n });\r\n setError(\"You canceled the transaction\");\r\n } else {\r\n toast.error(\"Error signing transaction\", {\r\n description: signError.message || \"Unable to sign transaction\"\r\n });\r\n setError(`Error signing transaction: ${signError.message}`);\r\n }\r\n \r\n setCurrentStage('error');\r\n throw signError; // Re-throw to handle in finally\r\n }\r\n \r\n } catch (error: any) {\r\n console.error('Staking error:', error);\r\n \r\n // Signing error already handled above, no need to show toast again\r\n if (!error.message?.includes(\"canceled\")) {\r\n setError(`Staking failed: ${error.message}`);\r\n toast.error(\"Transaction failed\", {\r\n description: error.message || \"Unable to complete transaction\"\r\n });\r\n }\r\n \r\n setCurrentStage('error');\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Render success view\r\n const renderSuccess = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Staking Successful!

\r\n

Your SOL has been successfully staked with Solayer.

\r\n {transactionSignature && (\r\n \r\n View transaction\r\n \r\n )}\r\n \r\n
\r\n );\r\n\r\n // Render error view\r\n const renderError = () => (\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n

Staking Failed

\r\n

{error || 'An error occurred while staking your SOL.'}

\r\n \r\n
\r\n );\r\n\r\n // Render confirmation view\r\n const renderConfirming = () => (\r\n
\r\n
\r\n \r\n
\r\n

Confirming Transaction

\r\n

Please wait while your staking transaction is being processed...

\r\n
\r\n );\r\n\r\n // Render input form\r\n const renderInputForm = () => (\r\n
\r\n {\r\n // Check if clicking MAX button then do not submit\r\n const target = e.target as HTMLElement;\r\n const maxButton = target.querySelector('.max-button');\r\n if (maxButton && (maxButton === document.activeElement || maxButton.contains(document.activeElement as Node))) {\r\n e.preventDefault();\r\n return;\r\n }\r\n \r\n e.preventDefault();\r\n form.handleSubmit(onSubmit)(e);\r\n }}\r\n className=\"space-y-4\"\r\n >\r\n (\r\n \r\n
\r\n Stake Amount\r\n
\r\n \r\n Balance: {isLoadingBalance ? '...' : solBalance}\r\n \r\n {connected && solBalance !== '--' && parseFloat(solBalance) > 0 && (\r\n
e.stopPropagation()}>\r\n {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n handleUseMax();\r\n }}\r\n >\r\n MAX\r\n \r\n
\r\n )}\r\n
\r\n
\r\n
\r\n \r\n handleAmountChange(e.target.value)}\r\n disabled={!connected || isSubmitting}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n
\r\n
\r\n {\r\n console.log(\"Error loading SOL logo, using fallback\");\r\n e.currentTarget.src = \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWNpcmNsZSI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48L3N2Zz4=\"; \r\n }}\r\n />\r\n SOL\r\n
\r\n
\r\n
\r\n \r\n
\r\n )}\r\n />\r\n\r\n
\r\n
\r\n
\r\n Staking Platform\r\n Solayer\r\n
\r\n \r\n
\r\n Reward Token\r\n sSOL\r\n
\r\n \r\n
\r\n Estimated APY\r\n 9.26%\r\n
\r\n \r\n
\r\n Fee\r\n 0%\r\n
\r\n
\r\n \r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting ? (\r\n <>\r\n \r\n Staking...\r\n \r\n ) : (\r\n (solBalance !== '--' && parseFloat(solBalance) < parseFloat(amountToStake) && \r\n !(parseFloat(amountToStake) - parseFloat(solBalance) < 0.001))\r\n ? 'Insufficient SOL balance'\r\n : 'Stake SOL'\r\n )}\r\n \r\n )}\r\n
\r\n
\r\n \r\n \r\n );\r\n\r\n // Render based on current stage\r\n const renderStageContent = () => {\r\n switch (currentStage) {\r\n case 'success':\r\n return renderSuccess();\r\n case 'error':\r\n return renderError();\r\n case 'confirming':\r\n return renderConfirming();\r\n default:\r\n return renderInputForm();\r\n }\r\n };\r\n\r\n return (\r\n \r\n \r\n \r\n Stake SOL\r\n \r\n \r\n \r\n {renderStageContent()}\r\n \r\n \r\n );\r\n}\r\n\r\nexport default StakeForm;", "type": "registry:component", "target": "components/ui/murphy/stake-token-form.tsx" }, { "path": "app/api/murphy/solayer/stake/route.ts", - "content": "// @ts-nocheck\nimport { NextRequest, NextResponse } from 'next/server';\n\n/**\n * Route handler for Solayer stake API\n * Acts as a proxy to avoid CORS errors\n */\nexport async function POST(request: NextRequest) {\n try {\n // Retrieve the amount parameter from the URL\n const searchParams = request.nextUrl.searchParams;\n const amount = searchParams.get('amount');\n\n if (!amount) {\n return NextResponse.json(\n { error: 'Amount is required' },\n { status: 400 }\n );\n }\n\n // Retrieve account information from the request body\n const body = await request.json();\n const { account } = body;\n\n if (!account) {\n return NextResponse.json(\n { error: 'Wallet address is required' },\n { status: 400 }\n );\n }\n\n // Call Solayer API\n const response = await fetch(\n `https://app.solayer.org/api/action/restake/ssol?amount=${amount}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n account,\n }),\n }\n );\n\n // Retrieve the result from Solayer API\n const data = await response.json();\n\n // If the request is unsuccessful, return an error\n if (!response.ok) {\n return NextResponse.json(\n { error: data.message || 'Stake request failed' },\n { status: response.status }\n );\n }\n\n // Return the successful result\n return NextResponse.json(data);\n } catch (error: any) {\n console.error('Error in Solayer stake API route:', error);\n return NextResponse.json(\n { error: error.message || 'An error occurred' },\n { status: 500 }\n );\n }\n}", + "content": "// @ts-nocheck\r\nimport { NextRequest, NextResponse } from 'next/server';\r\n\r\n/**\r\n * Route handler for Solayer stake API\r\n * Acts as a proxy to avoid CORS errors\r\n */\r\nexport async function POST(request: NextRequest) {\r\n try {\r\n // Retrieve the amount parameter from the URL\r\n const searchParams = request.nextUrl.searchParams;\r\n const amount = searchParams.get('amount');\r\n\r\n if (!amount) {\r\n return NextResponse.json(\r\n { error: 'Amount is required' },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n // Retrieve account information from the request body\r\n const body = await request.json();\r\n const { account } = body;\r\n\r\n if (!account) {\r\n return NextResponse.json(\r\n { error: 'Wallet address is required' },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n // Call Solayer API\r\n const response = await fetch(\r\n `https://app.solayer.org/api/action/restake/ssol?amount=${amount}`,\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n account,\r\n }),\r\n }\r\n );\r\n\r\n // Retrieve the result from Solayer API\r\n const data = await response.json();\r\n\r\n // If the request is unsuccessful, return an error\r\n if (!response.ok) {\r\n return NextResponse.json(\r\n { error: data.message || 'Stake request failed' },\r\n { status: response.status }\r\n );\r\n }\r\n\r\n // Return the successful result\r\n return NextResponse.json(data);\r\n } catch (error: any) {\r\n console.error('Error in Solayer stake API route:', error);\r\n return NextResponse.json(\r\n { error: error.message || 'An error occurred' },\r\n { status: 500 }\r\n );\r\n }\r\n}", "type": "registry:file", "target": "app/api/murphy/solayer/stake/route.ts" } diff --git a/public/r/step-flow-dialog.json b/public/r/step-flow-dialog.json new file mode 100644 index 0000000..fe82416 --- /dev/null +++ b/public/r/step-flow-dialog.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "step-flow-dialog", + "type": "registry:block", + "title": "Modal for guiding users through multi-step flows (e.g. Mint → Verify → Confirm).", + "dependencies": [], + "registryDependencies": [ + "dialog", + "button", + "txn-progress-steps" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx", + "content": "\"use client\"\r\n\r\nimport { useState } from \"react\"\r\nimport {\r\n Dialog,\r\n DialogContent,\r\n DialogDescription,\r\n DialogHeader,\r\n DialogTitle,\r\n} from \"@/components/ui/dialog\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { TxnProgressSteps } from \"./txn-progress-steps\"\r\nimport type { TxnStep } from \"@/types/transaction\"\r\n\r\ninterface StepFlowDialogProps {\r\n open: boolean\r\n onOpenChange: (open: boolean) => void\r\n title: string\r\n description?: string\r\n steps: TxnStep[]\r\n currentStep: number\r\n onNext?: () => Promise | void\r\n onPrevious?: () => void\r\n onCancel?: () => void\r\n nextButtonText?: string\r\n previousButtonText?: string\r\n cancelButtonText?: string\r\n isLoading?: boolean\r\n canGoNext?: boolean\r\n canGoPrevious?: boolean\r\n showCancel?: boolean\r\n}\r\n\r\nexport function StepFlowDialog({\r\n open,\r\n onOpenChange,\r\n title,\r\n description,\r\n steps,\r\n currentStep,\r\n onNext,\r\n onPrevious,\r\n onCancel,\r\n nextButtonText = \"Next\",\r\n previousButtonText = \"Previous\",\r\n cancelButtonText = \"Cancel\",\r\n isLoading = false,\r\n canGoNext = true,\r\n canGoPrevious = true,\r\n showCancel = true,\r\n}: StepFlowDialogProps) {\r\n const [isProcessing, setIsProcessing] = useState(false)\r\n\r\n const handleNext = async () => {\r\n if (!onNext || isProcessing) return\r\n setIsProcessing(true)\r\n try {\r\n await onNext()\r\n } catch (error) {\r\n console.error(\"Step failed:\", error)\r\n } finally {\r\n setIsProcessing(false)\r\n }\r\n }\r\n\r\n const isLastStep = currentStep === steps.length - 1\r\n const isFirstStep = currentStep === 0\r\n\r\n return (\r\n \r\n \r\n \r\n {title}\r\n {description && {description}}\r\n \r\n\r\n
\r\n \r\n\r\n {steps[currentStep] && (\r\n
\r\n

\r\n {steps[currentStep].title}\r\n

\r\n {steps[currentStep].description && (\r\n

\r\n {steps[currentStep].description}\r\n

\r\n )}\r\n
\r\n )}\r\n
\r\n\r\n
\r\n
\r\n {showCancel && (\r\n \r\n {cancelButtonText}\r\n \r\n )}\r\n {!isFirstStep && canGoPrevious && (\r\n \r\n {previousButtonText}\r\n \r\n )}\r\n
\r\n\r\n
\r\n {!isLastStep && (\r\n \r\n {isProcessing || isLoading ? \"Processing...\" : nextButtonText}\r\n \r\n )}\r\n {isLastStep && (\r\n onOpenChange(false)}\r\n disabled={isProcessing || isLoading}\r\n >\r\n Done\r\n \r\n )}\r\n
\r\n
\r\n
\r\n
\r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/success-dialog.json b/public/r/success-dialog.json new file mode 100644 index 0000000..5770fa9 --- /dev/null +++ b/public/r/success-dialog.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "success-dialog", + "type": "registry:block", + "title": "Modal shown when a transaction completes successfully.", + "dependencies": [], + "registryDependencies": [ + "dialog", + "button" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/success-dialog.tsx", + "content": "\"use client\";\r\n\r\nimport { CheckCircle, ExternalLink, Copy } from \"lucide-react\";\r\nimport {\r\n Dialog,\r\n DialogContent,\r\n DialogDescription,\r\n DialogFooter,\r\n DialogHeader,\r\n DialogTitle,\r\n} from \"@/components/ui/dialog\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { useState } from \"react\";\r\n\r\ninterface SuccessDialogProps {\r\n open: boolean;\r\n onOpenChange: (open: boolean) => void;\r\n title?: string;\r\n description?: string;\r\n signature?: string;\r\n amount?: string;\r\n token?: string;\r\n recipient?: string;\r\n onViewExplorer?: () => void;\r\n onClose?: () => void;\r\n}\r\n\r\nexport function SuccessDialog({\r\n open,\r\n onOpenChange,\r\n title = \"Transaction Successful! 🎉\",\r\n description = \"Your transaction has been confirmed on the blockchain\",\r\n signature,\r\n amount,\r\n token,\r\n recipient,\r\n onViewExplorer,\r\n onClose,\r\n}: SuccessDialogProps) {\r\n const [copied, setCopied] = useState(false);\r\n\r\n const copySignature = async () => {\r\n if (!signature) return;\r\n await navigator.clipboard.writeText(signature);\r\n setCopied(true);\r\n setTimeout(() => setCopied(false), 2000);\r\n };\r\n\r\n const handleClose = () => {\r\n onOpenChange(false);\r\n onClose?.();\r\n };\r\n\r\n return (\r\n \r\n \r\n \r\n
\r\n \r\n
\r\n \r\n {title}\r\n \r\n \r\n {description}\r\n \r\n
\r\n\r\n
\r\n {(amount || token) && (\r\n
\r\n
\r\n

\r\n {amount} {token}\r\n

\r\n {recipient && (\r\n

\r\n Sent to {recipient.slice(0, 8)}...{recipient.slice(-8)}\r\n

\r\n )}\r\n
\r\n
\r\n )}\r\n\r\n {signature && (\r\n
\r\n
\r\n
\r\n

\r\n Transaction Signature\r\n

\r\n

\r\n {signature.slice(0, 12)}...{signature.slice(-12)}\r\n

\r\n
\r\n
\r\n \r\n \r\n \r\n {onViewExplorer && (\r\n \r\n \r\n \r\n )}\r\n
\r\n
\r\n {copied && (\r\n \r\n Copied!\r\n \r\n )}\r\n
\r\n )}\r\n
\r\n\r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/success-dialog.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/swap-token-form.json b/public/r/swap-token-form.json index eb27124..78fbbcf 100644 --- a/public/r/swap-token-form.json +++ b/public/r/swap-token-form.json @@ -24,43 +24,43 @@ "files": [ { "path": "components/ui/murphy/swap-token-form.tsx", - "content": "\"use client\";\n\nimport { useState, useEffect, useMemo, useContext } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { ArrowDown, Loader2, RefreshCw, Settings } from \"lucide-react\";\nimport {\n PublicKey,\n Transaction,\n LAMPORTS_PER_SOL,\n} from \"@solana/web3.js\";\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n SelectGroup,\n} from \"@/components/ui/select\";\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { Slider } from \"@/components/ui/slider\";\nimport { useJupiterTrade } from \"@/hook/murphy/use-JupiterTrade\";\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\ndeclare global {\n interface Window {\n quoteTimeout: NodeJS.Timeout | null;\n }\n}\n\n// Token info type\nexport type TokenInfo = {\n id: string;\n symbol: string;\n name: string;\n balance: number;\n decimals: number;\n mintAddress?: string;\n icon?: string;\n};\n\n// Quote result interface - must match the result from Jupiter API\ninterface QuoteResult {\n outputAmount: string; // Amount of tokens received\n exchangeRate: number; // Exchange rate\n priceImpactPct: number; // Price impact (%)\n routeInfo: any; // Route information\n}\n\n// Type for swap form values\ntype SwapFormValues = {\n tokenIn: string;\n tokenOut: string;\n amountIn: number | undefined;\n amountOut: number | undefined;\n slippage: number;\n};\n\n// Create custom resolver for form\nconst customResolver = (data: any) => {\n const errors: any = {};\n\n // Validate token input\n if (!data.tokenIn) {\n errors.tokenIn = {\n type: \"required\",\n message: \"Please select an input token\",\n };\n }\n\n // Validate token output\n if (!data.tokenOut) {\n errors.tokenOut = {\n type: \"required\",\n message: \"Please select an output token\",\n };\n }\n\n // Validate amount\n if (data.amountIn === undefined || data.amountIn === null || data.amountIn === \"\") {\n errors.amountIn = {\n type: \"required\",\n message: \"Amount is required\",\n };\n } else if (Number(data.amountIn) <= 0) {\n errors.amountIn = {\n type: \"min\",\n message: \"Amount must be greater than 0\",\n };\n }\n\n return {\n values: Object.keys(errors).length === 0 ? data : {},\n errors,\n };\n};\n\n// Props interface\nexport interface SwapFormProps {\n onSwap?: (values: SwapFormValues) => Promise;\n tokens?: TokenInfo[];\n isLoading?: boolean;\n showTokenBalance?: boolean;\n className?: string;\n}\n\nexport function SwapForm({\n onSwap,\n tokens,\n isLoading = false,\n showTokenBalance = true,\n className,\n}: SwapFormProps) {\n // State variables\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [selectedTokenIn, setSelectedTokenIn] = useState(null);\n const [selectedTokenOut, setSelectedTokenOut] = useState(null);\n const [isLoadingTokens, setIsLoadingTokens] = useState(false);\n const [isUpdatingBalance, setIsUpdatingBalance] = useState(false);\n const [isLoadingQuote, setIsLoadingQuote] = useState(false);\n const [quoteResult, setQuoteResult] = useState(null);\n const [amountInValue, setAmountInValue] = useState(\"\");\n const [amountOutValue, setAmountOutValue] = useState(\"\");\n const [slippageValue, setSlippageValue] = useState(0.5); // 0.5% default\n const [slippageSettingsOpen, setSlippageSettingsOpen] = useState(false);\n \n const { publicKey, connected, sendTransaction, wallet } = useWallet();\n const { connection } = useConnection();\n const { executeTrade, getQuote } = useJupiterTrade();\n const { endpoint } = useContext(ModalContext);\n\n // Form setup with react-hook-form\n const form = useForm({\n defaultValues: {\n tokenIn: \"\",\n tokenOut: \"\",\n amountIn: undefined,\n amountOut: undefined,\n slippage: 0.5,\n },\n mode: \"onSubmit\", // Only validate on submit\n resolver: customResolver, // Use our custom resolver\n });\n\n // Available tokens state\n const [availableTokens, setAvailableTokens] = useState([]);\n\n // Add state to store timeout\n const [inputTimeout, setInputTimeout] = useState(null);\n\n // Clear timeout when component unmounts\n useEffect(() => {\n return () => {\n if (inputTimeout) {\n clearTimeout(inputTimeout);\n }\n };\n }, [inputTimeout]);\n\n // Determine network from connection endpoint\n const networkName = useMemo(() => {\n if (!connection) return \"Unknown\";\n\n const endpoint = connection.rpcEndpoint;\n\n if (endpoint.includes(\"devnet\")) return \"Devnet\";\n if (endpoint.includes(\"testnet\")) return \"Testnet\";\n if (endpoint.includes(\"mainnet\")) return \"Mainnet\";\n if (endpoint.includes(\"localhost\") || endpoint.includes(\"127.0.0.1\"))\n return \"Localnet\";\n\n // Custom endpoint - show partial URL\n const url = new URL(endpoint);\n return url.hostname;\n }, [connection]);\n\n // Fetch token accounts from wallet\n const fetchTokenAccounts = async (ownerPublicKey: PublicKey) => {\n try {\n setIsLoadingTokens(true);\n\n // Get SOL balance\n let solBalance = 0;\n try {\n if(!connection){\n throw new Error(\"No connection available\");\n }\n solBalance = (await connection.getBalance(ownerPublicKey)) / LAMPORTS_PER_SOL;\n\n let retryCount = 0;\n const maxRetries = 3;\n\n while (retryCount < maxRetries) {\n try {\n solBalance = (await\n connection.getBalance(ownerPublicKey)) / LAMPORTS_PER_SOL;\n break;\n } catch (error: any) {\n retryCount++;\n if (retryCount === maxRetries) {\n throw error;\n }\n\n await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for 1 second before retrying\n }\n }\n } catch (error: any) {\n console.error(\"Error fetching SOL balance:\", error);\n toast.error(\"Failed to fetch SOL balance\", {\n description: error?.message || \"Please check your wallet connection\",\n })\n }\n\n // Extended default tokens list\n const defaultTokens: TokenInfo[] = [\n {\n id: \"sol\",\n symbol: \"SOL\",\n name: \"Solana\",\n balance: solBalance,\n decimals: 9,\n mintAddress: \"So11111111111111111111111111111111111111112\",\n icon: \"/crypto-logos/solana-logo.svg\",\n },\n {\n id: \"usdc\",\n symbol: \"USDC\",\n name: \"USD Coin\",\n balance: 0,\n decimals: 6,\n mintAddress: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\",\n icon: \"/crypto-logos/usd-coin-usdc-logo.svg\",\n },\n {\n id: \"usdt\",\n symbol: \"USDT\",\n name: \"Tether USD\",\n balance: 0,\n decimals: 6,\n mintAddress: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\",\n icon: \"/crypto-logos/tether-usdt-logo.svg\",\n }\n ];\n\n // Fetch SPL tokens using the provider connection\n const splTokens: TokenInfo[] = [];\n\n try {\n const tokenAccounts = await connection.getParsedTokenAccountsByOwner(\n ownerPublicKey,\n {\n programId: new PublicKey(\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n ),\n }\n );\n\n for (const account of tokenAccounts.value) {\n const accountData = account.account.data.parsed.info;\n const mintAddress = accountData.mint;\n const tokenAmount = accountData.tokenAmount;\n\n if (tokenAmount.uiAmount > 0) {\n // Only include tokens with non-zero balance\n splTokens.push({\n id: mintAddress,\n symbol: mintAddress.substring(0, 4) + \"...\", // Use shortened mint as symbol if no metadata\n name: \"Token \" + mintAddress.substring(0, 6), // Use shortened mint as name if no metadata\n balance: tokenAmount.uiAmount,\n decimals: tokenAmount.decimals,\n mintAddress: mintAddress,\n });\n }\n }\n } catch (error) {\n console.error(\"Error fetching SPL token accounts:\", error);\n }\n\n // Return combined tokens\n return [...defaultTokens, ...splTokens];\n } catch (error) {\n console.error(\"Error fetching token accounts:\", error);\n // Return basic SOL token on error\n return [\n {\n id: \"sol\",\n symbol: \"SOL\",\n name: \"Solana\",\n balance: 0,\n decimals: 9,\n icon: \"/crypto-logos/solana-logo.svg\",\n },\n ];\n } finally {\n setIsLoadingTokens(false);\n }\n };\n\n // Load tokens effect\n useEffect(() => {\n // If tokens are provided as props, use those\n if (tokens) {\n setAvailableTokens(tokens);\n }\n // Otherwise, if wallet is connected, fetch tokens\n else if (connected && publicKey) {\n fetchTokenAccounts(publicKey)\n .then((fetchedTokens) => {\n setAvailableTokens(fetchedTokens);\n })\n .catch((error) => {\n console.error(\"Error setting tokens:\", error);\n // Set default SOL token on error\n setAvailableTokens([\n {\n id: \"sol\",\n symbol: \"SOL\",\n name: \"Solana\",\n balance: 0,\n decimals: 9,\n icon: \"/crypto-logos/solana-logo.svg\",\n },\n ]);\n });\n }\n }, [tokens, connected, publicKey]);\n\n // Handle use max amount\n const handleUseMax = (e?: React.MouseEvent) => {\n // Prevent form submit event if there is an event\n if (e) {\n e.preventDefault();\n e.stopPropagation();\n }\n \n if (selectedTokenIn && selectedTokenIn.balance > 0) {\n // If SOL is selected, keep 0.01 SOL for transaction fees\n let maxAmount: number;\n \n if (selectedTokenIn.id === \"sol\" || \n selectedTokenIn.mintAddress === \"So11111111111111111111111111111111111111112\") {\n // Keep 0.05 SOL for transaction fees, enough for most transactions\n maxAmount = Math.max(selectedTokenIn.balance - 0.05, 0);\n } else {\n maxAmount = selectedTokenIn.balance;\n }\n \n setAmountInValue(maxAmount.toString());\n form.setValue(\"amountIn\", maxAmount, {\n shouldValidate: false,\n shouldDirty: true,\n shouldTouch: true,\n });\n \n // If the output token is selected, wait a bit before getting the quote\n if (selectedTokenOut && maxAmount > 0) {\n setTimeout(() => {\n fetchSwapQuote(maxAmount, true);\n }, 0);\n }\n }\n };\n\n // Handle amount input change with debounce\n const handleAmountInChange = (value: string) => {\n setAmountInValue(value);\n const parsedValue = value === \"\" ? undefined : parseFloat(value);\n form.setValue(\"amountIn\", parsedValue, {\n shouldValidate: false // Prevent validation\n });\n \n if (!parsedValue || parsedValue <= 0) {\n setAmountOutValue(\"\");\n setQuoteResult(null);\n return;\n }\n\n // Cancel old timeout if any\n if (inputTimeout) {\n clearTimeout(inputTimeout);\n }\n \n // Automatically update the quote after the user stops typing for 500ms\n if (parsedValue && parsedValue > 0 && selectedTokenIn && selectedTokenOut) {\n const newTimeout = setTimeout(() => {\n fetchSwapQuote(parsedValue, false);\n }, 500);\n \n setInputTimeout(newTimeout);\n }\n };\n\n // Add blur event handler to ensure update when user loses focus\n const handleAmountInBlur = () => {\n if (amountInValue && parseFloat(amountInValue) > 0 && selectedTokenIn && selectedTokenOut) {\n fetchSwapQuote(parseFloat(amountInValue), false);\n }\n };\n\n // Handle token change\n const handleTokenChange = (isInput: boolean, tokenId: string) => {\n const token = availableTokens.find((t) => t.id === tokenId);\n \n if (!token) return;\n \n if (isInput) {\n if (selectedTokenOut && token.id === selectedTokenOut.id) {\n toast.error(\"Cannot select the same token\", {\n description: \"Please select different tokens for input and output\",\n });\n return;\n }\n \n setSelectedTokenIn(token);\n form.setValue(\"tokenIn\", token.id, {\n shouldValidate: false // Prevent validation\n });\n } else {\n if (selectedTokenIn && token.id === selectedTokenIn.id) {\n toast.error(\"Cannot select the same token\", {\n description: \"Please select different tokens for input and output\",\n });\n return;\n }\n \n setSelectedTokenOut(token);\n form.setValue(\"tokenOut\", token.id, {\n shouldValidate: false // Prevent validation\n });\n }\n \n // Clear amounts and re-quote if we have an input amount\n if (amountInValue && parseFloat(amountInValue) > 0) {\n fetchSwapQuote(parseFloat(amountInValue), false);\n }\n };\n\n // Handle slippage change\n const handleSlippageChange = (value: number) => {\n setSlippageValue(value);\n form.setValue(\"slippage\", value, {\n shouldValidate: false // Prevent validation\n });\n };\n\n // Switch tokens\n const handleSwitchTokens = () => {\n // Swap token selections\n const tempTokenIn = selectedTokenIn;\n const tempTokenOut = selectedTokenOut;\n \n setSelectedTokenIn(tempTokenOut);\n setSelectedTokenOut(tempTokenIn);\n \n if (tempTokenOut) {\n form.setValue(\"tokenIn\", tempTokenOut.id, {\n shouldValidate: false // Prevent validation\n });\n }\n \n if (tempTokenIn) {\n form.setValue(\"tokenOut\", tempTokenIn.id, {\n shouldValidate: false // Prevent validation\n });\n }\n \n // Clear amounts and re-quote if needed\n setAmountInValue(\"\");\n setAmountOutValue(\"\");\n form.setValue(\"amountIn\", undefined, {\n shouldValidate: false // Prevent validation\n });\n form.setValue(\"amountOut\", undefined, {\n shouldValidate: false // Prevent validation\n });\n setQuoteResult(null);\n };\n\n // Fetch swap quote\n const fetchSwapQuote = async (amount: number, isFromMaxButton: boolean = false) => {\n if (!connected || !publicKey) {\n toast.error(\"Wallet not connected\", { \n description: \"Please connect your wallet to get a quote\" \n });\n return;\n }\n \n if (!selectedTokenIn || !selectedTokenOut) {\n toast.error(\"Select tokens\", { \n description: \"Please select input and output tokens\" \n });\n return;\n }\n \n if (amount <= 0) {\n setAmountOutValue(\"\");\n setQuoteResult(null);\n return;\n }\n \n try {\n setIsLoadingQuote(true);\n \n // Check token address\n if (!selectedTokenIn.mintAddress || !selectedTokenOut.mintAddress) {\n throw new Error(\"Token mintAddress not found\");\n }\n\n // Create PublicKey from address\n const inputMint = new PublicKey(selectedTokenIn.mintAddress);\n const outputMint = new PublicKey(selectedTokenOut.mintAddress);\n const slippageBps = Math.floor(slippageValue * 100);\n \n // Call API to get quote\n const quoteResponse = await getQuote(\n outputMint,\n amount,\n inputMint,\n slippageBps\n );\n \n if (quoteResponse) {\n // Update state with result from API\n setQuoteResult(quoteResponse);\n setAmountOutValue(quoteResponse.outputAmount);\n form.setValue(\"amountOut\", Number(quoteResponse.outputAmount), {\n shouldValidate: false\n });\n } else {\n setQuoteResult(null);\n setAmountOutValue(\"\");\n form.setValue(\"amountOut\", undefined, {\n shouldValidate: false\n });\n }\n } catch (error: any) {\n setQuoteResult(null);\n setAmountOutValue(\"\");\n toast.error(\"Failed to get quote\", {\n description: error?.message || \"Unable to fetch quote from Jupiter\"\n });\n } finally {\n setIsLoadingQuote(false);\n }\n };\n\n // Handle form submission\n const onSubmit = async (values: SwapFormValues) => {\n if (!connected) {\n toast.error(\"Wallet not connected\");\n return;\n }\n\n if (!publicKey) {\n toast.error(\"Public key not found\");\n return;\n }\n\n if (!connection) {\n toast.error(\"Invalid connection\");\n return;\n }\n\n if (!endpoint) {\n toast.error(\"RPC endpoint not found\");\n return;\n }\n\n if (!selectedTokenIn || !selectedTokenOut) {\n toast.error(\"Select tokens\");\n return;\n }\n\n if (!values.amountIn || values.amountIn <= 0) {\n toast.error(\"Invalid amount\");\n return;\n }\n\n try {\n setIsSubmitting(true);\n \n // Check token address\n if (!selectedTokenIn.mintAddress || !selectedTokenOut.mintAddress) {\n throw new Error(\"Token mintAddress not found\");\n }\n \n // Create PublicKey from address\n const inputMint = new PublicKey(selectedTokenIn.mintAddress);\n const outputMint = new PublicKey(selectedTokenOut.mintAddress);\n const slippageBps = Math.floor(slippageValue * 100);\n \n // Log transaction information for debugging\n console.log(\"=== Transaction Information ===\");\n console.log(\"Endpoint:\", endpoint);\n console.log(\"Input token:\", selectedTokenIn.symbol, inputMint.toString());\n console.log(\"Output token:\", selectedTokenOut.symbol, outputMint.toString());\n console.log(\"Amount:\", values.amountIn);\n console.log(\"Slippage:\", slippageBps, \"bps\");\n console.log(\"Wallet connected:\", connected ? \"Yes\" : \"No\");\n console.log(\"PublicKey:\", publicKey.toString());\n console.log(\"========================\");\n \n // Check all parameters before executing the transaction\n if (!wallet) {\n throw new Error(\"Wallet not connected\");\n }\n \n try {\n // Execute the swap transaction with proper validation\n console.log(\"Calling executeTrade with parameters:\");\n console.log(\" - outputMint:\", outputMint.toString());\n console.log(\" - inputAmount:\", values.amountIn);\n console.log(\" - inputMint:\", inputMint.toString());\n console.log(\" - slippageBps:\", slippageBps);\n console.log(\" - wallet:\", typeof wallet, wallet ? \"connected\" : \"not connected\");\n \n // Check if wallet supports signTransaction method\n const walletAdapter = wallet as any;\n console.log(\" - wallet supports signTransaction:\", walletAdapter?.signTransaction ? \"yes\" : \"no\");\n console.log(\" - endpoint:\", endpoint);\n\n // Pass fewer parameters, compatible with new API\n const signature = await executeTrade(\n outputMint,\n values.amountIn,\n inputMint,\n slippageBps\n );\n \n toast.success(\"Swap successful!\", {\n description: `Transaction: ${signature}`\n });\n \n // Reset form and update balances\n setAmountInValue(\"\");\n setAmountOutValue(\"\");\n form.setValue(\"amountIn\", undefined, {\n shouldValidate: false\n });\n form.setValue(\"amountOut\", undefined, {\n shouldValidate: false\n });\n setQuoteResult(null);\n \n // Update balances after successful swap\n if (publicKey) {\n await updateBalances();\n }\n } catch (tradeError: any) {\n console.error(\"Trade execution error:\", tradeError);\n toast.error(\"Transaction failed\", {\n description: tradeError.message || \"Unable to execute transaction\"\n });\n }\n } catch (error: any) {\n console.error(\"Swap error:\", error);\n toast.error(\"Swap failed\", {\n description: error.message || \"Transaction failed\"\n });\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Separate function to update balances\n const updateSelectedTokenBalances = (updatedTokens: TokenInfo[]) => {\n // Update selected token balances if they exist in the updated tokens list\n if (selectedTokenIn) {\n const updatedTokenIn = updatedTokens.find(t => t.id === selectedTokenIn.id);\n if (updatedTokenIn) {\n setSelectedTokenIn(updatedTokenIn);\n }\n }\n \n if (selectedTokenOut) {\n const updatedTokenOut = updatedTokens.find(t => t.id === selectedTokenOut.id);\n if (updatedTokenOut) {\n setSelectedTokenOut(updatedTokenOut);\n }\n }\n };\n\n // Existing updateBalances function remains the same\n const updateBalances = async () => {\n setIsUpdatingBalance(true);\n try {\n const updatedTokens = await fetchTokenAccounts(publicKey!);\n setAvailableTokens(updatedTokens);\n updateSelectedTokenBalances(updatedTokens);\n toast.success(\"Balances updated\");\n } catch (error) {\n console.error(\"Error updating balances:\", error);\n } finally {\n setIsUpdatingBalance(false);\n }\n };\n\n // Render token item for the select dropdown\n const renderTokenItem = (token: TokenInfo) => (\n \n
\n
\n {token.icon && (\n
\n {\n (e.target as HTMLImageElement).style.display = \"none\";\n }}\n />\n
\n )}\n {token.symbol}\n
\n {showTokenBalance && (\n \n {token.balance.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: token.decimals > 6 ? 6 : token.decimals,\n })}\n \n )}\n
\n
\n );\n\n return (\n \n \n \n Swap Tokens\n \n \n \n \n \n
\n

Slippage Tolerance

\n
\n \n \n \n
\n
\n
\n Custom: {slippageValue.toFixed(1)}%\n
\n handleSlippageChange(value[0])}\n />\n {slippageValue > 3 && (\n

\n High slippage increases the risk of price impact\n

\n )}\n
\n
\n
\n
\n
\n
\n \n
\n {\n // Check if clicking MAX button then do not submit\n const target = e.target as HTMLElement;\n const maxButton = target.querySelector('.max-button');\n if (maxButton && (maxButton === document.activeElement || maxButton.contains(document.activeElement as Node))) {\n e.preventDefault();\n return;\n }\n \n e.preventDefault();\n form.handleSubmit(onSubmit)(e);\n }}\n className=\"space-y-4\"\n >\n {/* Token Input Field */}\n
\n (\n \n
\n You Pay\n {selectedTokenIn && showTokenBalance && (\n
\n \n Balance: {selectedTokenIn.balance.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: selectedTokenIn.decimals > 6 ? 6 : selectedTokenIn.decimals,\n })}\n \n
e.stopPropagation()}>\n {\n e.preventDefault();\n e.stopPropagation();\n handleUseMax();\n }}\n >\n MAX\n \n
\n
\n )}\n
\n
\n \n handleAmountInChange(e.target.value)}\n onBlur={handleAmountInBlur}\n disabled={!connected || !selectedTokenIn}\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n \n handleTokenChange(true, value)}\n value={field.value}\n disabled={!connected}\n >\n \n \n \n {selectedTokenIn && (\n
\n {selectedTokenIn.icon && (\n \n )}\n {selectedTokenIn.symbol}\n
\n )}\n \n
\n
\n \n {isLoadingTokens || isUpdatingBalance ? (\n
\n \n \n {isUpdatingBalance\n ? \"Updating balances...\"\n : \"Loading tokens...\"}\n \n
\n ) : availableTokens.length > 0 ? (\n \n {availableTokens.map(renderTokenItem)}\n \n ) : (\n
\n No tokens found\n
\n )}\n
\n \n
\n \n
\n )}\n />\n \n {/* Arrow button to switch tokens */}\n
\n \n \n \n
\n\n {/* Token Output Field */}\n (\n \n
\n You Receive\n {selectedTokenOut && showTokenBalance && (\n
\n Balance: {selectedTokenOut.balance.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: selectedTokenOut.decimals > 6 ? 6 : selectedTokenOut.decimals,\n })}\n
\n )}\n
\n
\n \n \n \n handleTokenChange(false, value)}\n value={field.value}\n disabled={!connected}\n >\n \n \n \n {selectedTokenOut && (\n
\n {selectedTokenOut.icon && (\n \n )}\n {selectedTokenOut.symbol}\n
\n )}\n \n
\n
\n \n {isLoadingTokens || isUpdatingBalance ? (\n
\n \n \n {isUpdatingBalance\n ? \"Updating balances...\"\n : \"Loading tokens...\"}\n \n
\n ) : availableTokens.length > 0 ? (\n \n {availableTokens.map(renderTokenItem)}\n \n ) : (\n
\n No tokens found\n
\n )}\n
\n \n
\n \n
\n )}\n />\n
\n {/* Add swap button section */}\n
\n {!connected ? (\n \n ) : (\n \n {isSubmitting || isLoading? (\n <>\n \n Swapping...\n \n ) : (\n \"Swap\"\n )}\n \n )}\n
\n\n\n {/*/ Add exchange rate info if quote exists */}\n {quoteResult && (\n
\n
\n 1 {selectedTokenIn?.symbol} ≈ {quoteResult.exchangeRate.toLocaleString(undefined, {\n minimumFractionDigits: 2,\n maximumFractionDigits: 6\n })} {selectedTokenOut?.symbol}\n
\n
\n \n Slippage: {slippageValue.toFixed(1)}%\n \n {quoteResult.priceImpactPct > 1 && (\n 3 ? 'text-red-500' : 'text-yellow-500'}`}>\n Price impact: {quoteResult.priceImpactPct.toFixed(2)}%\n \n )}\n
\n
\n )}\n
\n \n
\n
\n );\n}\n", + "content": "\"use client\";\r\n\r\nimport { useState, useEffect, useMemo, useContext } from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { toast } from \"sonner\";\r\nimport { ArrowDown, Loader2, RefreshCw, Settings } from \"lucide-react\";\r\nimport {\r\n PublicKey,\r\n Transaction,\r\n LAMPORTS_PER_SOL,\r\n} from \"@solana/web3.js\";\r\nimport { useWallet, useConnection } from \"@solana/wallet-adapter-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormItem,\r\n FormLabel,\r\n FormMessage,\r\n} from \"@/components/ui/form\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n SelectGroup,\r\n} from \"@/components/ui/select\";\r\nimport { ConnectWalletButton } from \"./connect-wallet-button\";\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/ui/popover\";\r\nimport { Slider } from \"@/components/ui/slider\";\r\nimport { useJupiterTrade } from \"@/hook/murphy/use-JupiterTrade\";\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\ndeclare global {\r\n interface Window {\r\n quoteTimeout: NodeJS.Timeout | null;\r\n }\r\n}\r\n\r\n// Token info type\r\nexport type TokenInfo = {\r\n id: string;\r\n symbol: string;\r\n name: string;\r\n balance: number;\r\n decimals: number;\r\n mintAddress?: string;\r\n icon?: string;\r\n};\r\n\r\n// Quote result interface - must match the result from Jupiter API\r\ninterface QuoteResult {\r\n outputAmount: string; // Amount of tokens received\r\n exchangeRate: number; // Exchange rate\r\n priceImpactPct: number; // Price impact (%)\r\n routeInfo: any; // Route information\r\n}\r\n\r\n// Type for swap form values\r\ntype SwapFormValues = {\r\n tokenIn: string;\r\n tokenOut: string;\r\n amountIn: number | undefined;\r\n amountOut: number | undefined;\r\n slippage: number;\r\n};\r\n\r\n// Create custom resolver for form\r\nconst customResolver = (data: any) => {\r\n const errors: any = {};\r\n\r\n // Validate token input\r\n if (!data.tokenIn) {\r\n errors.tokenIn = {\r\n type: \"required\",\r\n message: \"Please select an input token\",\r\n };\r\n }\r\n\r\n // Validate token output\r\n if (!data.tokenOut) {\r\n errors.tokenOut = {\r\n type: \"required\",\r\n message: \"Please select an output token\",\r\n };\r\n }\r\n\r\n // Validate amount\r\n if (data.amountIn === undefined || data.amountIn === null || data.amountIn === \"\") {\r\n errors.amountIn = {\r\n type: \"required\",\r\n message: \"Amount is required\",\r\n };\r\n } else if (Number(data.amountIn) <= 0) {\r\n errors.amountIn = {\r\n type: \"min\",\r\n message: \"Amount must be greater than 0\",\r\n };\r\n }\r\n\r\n return {\r\n values: Object.keys(errors).length === 0 ? data : {},\r\n errors,\r\n };\r\n};\r\n\r\n// Props interface\r\nexport interface SwapFormProps {\r\n onSwap?: (values: SwapFormValues) => Promise;\r\n tokens?: TokenInfo[];\r\n isLoading?: boolean;\r\n showTokenBalance?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function SwapForm({\r\n onSwap,\r\n tokens,\r\n isLoading = false,\r\n showTokenBalance = true,\r\n className,\r\n}: SwapFormProps) {\r\n // State variables\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [selectedTokenIn, setSelectedTokenIn] = useState(null);\r\n const [selectedTokenOut, setSelectedTokenOut] = useState(null);\r\n const [isLoadingTokens, setIsLoadingTokens] = useState(false);\r\n const [isUpdatingBalance, setIsUpdatingBalance] = useState(false);\r\n const [isLoadingQuote, setIsLoadingQuote] = useState(false);\r\n const [quoteResult, setQuoteResult] = useState(null);\r\n const [amountInValue, setAmountInValue] = useState(\"\");\r\n const [amountOutValue, setAmountOutValue] = useState(\"\");\r\n const [slippageValue, setSlippageValue] = useState(0.5); // 0.5% default\r\n const [slippageSettingsOpen, setSlippageSettingsOpen] = useState(false);\r\n \r\n const { publicKey, connected, sendTransaction, wallet } = useWallet();\r\n const { connection } = useConnection();\r\n const { executeTrade, getQuote } = useJupiterTrade();\r\n const { endpoint } = useContext(ModalContext);\r\n\r\n // Form setup with react-hook-form\r\n const form = useForm({\r\n defaultValues: {\r\n tokenIn: \"\",\r\n tokenOut: \"\",\r\n amountIn: undefined,\r\n amountOut: undefined,\r\n slippage: 0.5,\r\n },\r\n mode: \"onSubmit\", // Only validate on submit\r\n resolver: customResolver, // Use our custom resolver\r\n });\r\n\r\n // Available tokens state\r\n const [availableTokens, setAvailableTokens] = useState([]);\r\n\r\n // Add state to store timeout\r\n const [inputTimeout, setInputTimeout] = useState(null);\r\n\r\n // Clear timeout when component unmounts\r\n useEffect(() => {\r\n return () => {\r\n if (inputTimeout) {\r\n clearTimeout(inputTimeout);\r\n }\r\n };\r\n }, [inputTimeout]);\r\n\r\n // Determine network from connection endpoint\r\n const networkName = useMemo(() => {\r\n if (!connection) return \"Unknown\";\r\n\r\n const endpoint = connection.rpcEndpoint;\r\n\r\n if (endpoint.includes(\"devnet\")) return \"Devnet\";\r\n if (endpoint.includes(\"testnet\")) return \"Testnet\";\r\n if (endpoint.includes(\"mainnet\")) return \"Mainnet\";\r\n if (endpoint.includes(\"localhost\") || endpoint.includes(\"127.0.0.1\"))\r\n return \"Localnet\";\r\n\r\n // Custom endpoint - show partial URL\r\n const url = new URL(endpoint);\r\n return url.hostname;\r\n }, [connection]);\r\n\r\n // Fetch token accounts from wallet\r\n const fetchTokenAccounts = async (ownerPublicKey: PublicKey) => {\r\n try {\r\n setIsLoadingTokens(true);\r\n\r\n // Get SOL balance\r\n let solBalance = 0;\r\n try {\r\n if(!connection){\r\n throw new Error(\"No connection available\");\r\n }\r\n solBalance = (await connection.getBalance(ownerPublicKey)) / LAMPORTS_PER_SOL;\r\n\r\n let retryCount = 0;\r\n const maxRetries = 3;\r\n\r\n while (retryCount < maxRetries) {\r\n try {\r\n solBalance = (await\r\n connection.getBalance(ownerPublicKey)) / LAMPORTS_PER_SOL;\r\n break;\r\n } catch (error: any) {\r\n retryCount++;\r\n if (retryCount === maxRetries) {\r\n throw error;\r\n }\r\n\r\n await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for 1 second before retrying\r\n }\r\n }\r\n } catch (error: any) {\r\n console.error(\"Error fetching SOL balance:\", error);\r\n toast.error(\"Failed to fetch SOL balance\", {\r\n description: error?.message || \"Please check your wallet connection\",\r\n })\r\n }\r\n\r\n // Extended default tokens list\r\n const defaultTokens: TokenInfo[] = [\r\n {\r\n id: \"sol\",\r\n symbol: \"SOL\",\r\n name: \"Solana\",\r\n balance: solBalance,\r\n decimals: 9,\r\n mintAddress: \"So11111111111111111111111111111111111111112\",\r\n icon: \"/crypto-logos/solana-logo.svg\",\r\n },\r\n {\r\n id: \"usdc\",\r\n symbol: \"USDC\",\r\n name: \"USD Coin\",\r\n balance: 0,\r\n decimals: 6,\r\n mintAddress: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\",\r\n icon: \"/crypto-logos/usd-coin-usdc-logo.svg\",\r\n },\r\n {\r\n id: \"usdt\",\r\n symbol: \"USDT\",\r\n name: \"Tether USD\",\r\n balance: 0,\r\n decimals: 6,\r\n mintAddress: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\",\r\n icon: \"/crypto-logos/tether-usdt-logo.svg\",\r\n }\r\n ];\r\n\r\n // Fetch SPL tokens using the provider connection\r\n const splTokens: TokenInfo[] = [];\r\n\r\n try {\r\n const tokenAccounts = await connection.getParsedTokenAccountsByOwner(\r\n ownerPublicKey,\r\n {\r\n programId: new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n ),\r\n }\r\n );\r\n\r\n for (const account of tokenAccounts.value) {\r\n const accountData = account.account.data.parsed.info;\r\n const mintAddress = accountData.mint;\r\n const tokenAmount = accountData.tokenAmount;\r\n\r\n if (tokenAmount.uiAmount > 0) {\r\n // Only include tokens with non-zero balance\r\n splTokens.push({\r\n id: mintAddress,\r\n symbol: mintAddress.substring(0, 4) + \"...\", // Use shortened mint as symbol if no metadata\r\n name: \"Token \" + mintAddress.substring(0, 6), // Use shortened mint as name if no metadata\r\n balance: tokenAmount.uiAmount,\r\n decimals: tokenAmount.decimals,\r\n mintAddress: mintAddress,\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\"Error fetching SPL token accounts:\", error);\r\n }\r\n\r\n // Return combined tokens\r\n return [...defaultTokens, ...splTokens];\r\n } catch (error) {\r\n console.error(\"Error fetching token accounts:\", error);\r\n // Return basic SOL token on error\r\n return [\r\n {\r\n id: \"sol\",\r\n symbol: \"SOL\",\r\n name: \"Solana\",\r\n balance: 0,\r\n decimals: 9,\r\n icon: \"/crypto-logos/solana-logo.svg\",\r\n },\r\n ];\r\n } finally {\r\n setIsLoadingTokens(false);\r\n }\r\n };\r\n\r\n // Load tokens effect\r\n useEffect(() => {\r\n // If tokens are provided as props, use those\r\n if (tokens) {\r\n setAvailableTokens(tokens);\r\n }\r\n // Otherwise, if wallet is connected, fetch tokens\r\n else if (connected && publicKey) {\r\n fetchTokenAccounts(publicKey)\r\n .then((fetchedTokens) => {\r\n setAvailableTokens(fetchedTokens);\r\n })\r\n .catch((error) => {\r\n console.error(\"Error setting tokens:\", error);\r\n // Set default SOL token on error\r\n setAvailableTokens([\r\n {\r\n id: \"sol\",\r\n symbol: \"SOL\",\r\n name: \"Solana\",\r\n balance: 0,\r\n decimals: 9,\r\n icon: \"/crypto-logos/solana-logo.svg\",\r\n },\r\n ]);\r\n });\r\n }\r\n }, [tokens, connected, publicKey]);\r\n\r\n // Handle use max amount\r\n const handleUseMax = (e?: React.MouseEvent) => {\r\n // Prevent form submit event if there is an event\r\n if (e) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n \r\n if (selectedTokenIn && selectedTokenIn.balance > 0) {\r\n // If SOL is selected, keep 0.01 SOL for transaction fees\r\n let maxAmount: number;\r\n \r\n if (selectedTokenIn.id === \"sol\" || \r\n selectedTokenIn.mintAddress === \"So11111111111111111111111111111111111111112\") {\r\n // Keep 0.05 SOL for transaction fees, enough for most transactions\r\n maxAmount = Math.max(selectedTokenIn.balance - 0.05, 0);\r\n } else {\r\n maxAmount = selectedTokenIn.balance;\r\n }\r\n \r\n setAmountInValue(maxAmount.toString());\r\n form.setValue(\"amountIn\", maxAmount, {\r\n shouldValidate: false,\r\n shouldDirty: true,\r\n shouldTouch: true,\r\n });\r\n \r\n // If the output token is selected, wait a bit before getting the quote\r\n if (selectedTokenOut && maxAmount > 0) {\r\n setTimeout(() => {\r\n fetchSwapQuote(maxAmount, true);\r\n }, 0);\r\n }\r\n }\r\n };\r\n\r\n // Handle amount input change with debounce\r\n const handleAmountInChange = (value: string) => {\r\n setAmountInValue(value);\r\n const parsedValue = value === \"\" ? undefined : parseFloat(value);\r\n form.setValue(\"amountIn\", parsedValue, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n \r\n if (!parsedValue || parsedValue <= 0) {\r\n setAmountOutValue(\"\");\r\n setQuoteResult(null);\r\n return;\r\n }\r\n\r\n // Cancel old timeout if any\r\n if (inputTimeout) {\r\n clearTimeout(inputTimeout);\r\n }\r\n \r\n // Automatically update the quote after the user stops typing for 500ms\r\n if (parsedValue && parsedValue > 0 && selectedTokenIn && selectedTokenOut) {\r\n const newTimeout = setTimeout(() => {\r\n fetchSwapQuote(parsedValue, false);\r\n }, 500);\r\n \r\n setInputTimeout(newTimeout);\r\n }\r\n };\r\n\r\n // Add blur event handler to ensure update when user loses focus\r\n const handleAmountInBlur = () => {\r\n if (amountInValue && parseFloat(amountInValue) > 0 && selectedTokenIn && selectedTokenOut) {\r\n fetchSwapQuote(parseFloat(amountInValue), false);\r\n }\r\n };\r\n\r\n // Handle token change\r\n const handleTokenChange = (isInput: boolean, tokenId: string) => {\r\n const token = availableTokens.find((t) => t.id === tokenId);\r\n \r\n if (!token) return;\r\n \r\n if (isInput) {\r\n if (selectedTokenOut && token.id === selectedTokenOut.id) {\r\n toast.error(\"Cannot select the same token\", {\r\n description: \"Please select different tokens for input and output\",\r\n });\r\n return;\r\n }\r\n \r\n setSelectedTokenIn(token);\r\n form.setValue(\"tokenIn\", token.id, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n } else {\r\n if (selectedTokenIn && token.id === selectedTokenIn.id) {\r\n toast.error(\"Cannot select the same token\", {\r\n description: \"Please select different tokens for input and output\",\r\n });\r\n return;\r\n }\r\n \r\n setSelectedTokenOut(token);\r\n form.setValue(\"tokenOut\", token.id, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n }\r\n \r\n // Clear amounts and re-quote if we have an input amount\r\n if (amountInValue && parseFloat(amountInValue) > 0) {\r\n fetchSwapQuote(parseFloat(amountInValue), false);\r\n }\r\n };\r\n\r\n // Handle slippage change\r\n const handleSlippageChange = (value: number) => {\r\n setSlippageValue(value);\r\n form.setValue(\"slippage\", value, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n };\r\n\r\n // Switch tokens\r\n const handleSwitchTokens = () => {\r\n // Swap token selections\r\n const tempTokenIn = selectedTokenIn;\r\n const tempTokenOut = selectedTokenOut;\r\n \r\n setSelectedTokenIn(tempTokenOut);\r\n setSelectedTokenOut(tempTokenIn);\r\n \r\n if (tempTokenOut) {\r\n form.setValue(\"tokenIn\", tempTokenOut.id, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n }\r\n \r\n if (tempTokenIn) {\r\n form.setValue(\"tokenOut\", tempTokenIn.id, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n }\r\n \r\n // Clear amounts and re-quote if needed\r\n setAmountInValue(\"\");\r\n setAmountOutValue(\"\");\r\n form.setValue(\"amountIn\", undefined, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n form.setValue(\"amountOut\", undefined, {\r\n shouldValidate: false // Prevent validation\r\n });\r\n setQuoteResult(null);\r\n };\r\n\r\n // Fetch swap quote\r\n const fetchSwapQuote = async (amount: number, isFromMaxButton: boolean = false) => {\r\n if (!connected || !publicKey) {\r\n toast.error(\"Wallet not connected\", { \r\n description: \"Please connect your wallet to get a quote\" \r\n });\r\n return;\r\n }\r\n \r\n if (!selectedTokenIn || !selectedTokenOut) {\r\n toast.error(\"Select tokens\", { \r\n description: \"Please select input and output tokens\" \r\n });\r\n return;\r\n }\r\n \r\n if (amount <= 0) {\r\n setAmountOutValue(\"\");\r\n setQuoteResult(null);\r\n return;\r\n }\r\n \r\n try {\r\n setIsLoadingQuote(true);\r\n \r\n // Check token address\r\n if (!selectedTokenIn.mintAddress || !selectedTokenOut.mintAddress) {\r\n throw new Error(\"Token mintAddress not found\");\r\n }\r\n\r\n // Create PublicKey from address\r\n const inputMint = new PublicKey(selectedTokenIn.mintAddress);\r\n const outputMint = new PublicKey(selectedTokenOut.mintAddress);\r\n const slippageBps = Math.floor(slippageValue * 100);\r\n \r\n // Call API to get quote\r\n const quoteResponse = await getQuote(\r\n outputMint,\r\n amount,\r\n inputMint,\r\n slippageBps\r\n );\r\n \r\n if (quoteResponse) {\r\n // Update state with result from API\r\n setQuoteResult(quoteResponse);\r\n setAmountOutValue(quoteResponse.outputAmount);\r\n form.setValue(\"amountOut\", Number(quoteResponse.outputAmount), {\r\n shouldValidate: false\r\n });\r\n } else {\r\n setQuoteResult(null);\r\n setAmountOutValue(\"\");\r\n form.setValue(\"amountOut\", undefined, {\r\n shouldValidate: false\r\n });\r\n }\r\n } catch (error: any) {\r\n setQuoteResult(null);\r\n setAmountOutValue(\"\");\r\n toast.error(\"Failed to get quote\", {\r\n description: error?.message || \"Unable to fetch quote from Jupiter\"\r\n });\r\n } finally {\r\n setIsLoadingQuote(false);\r\n }\r\n };\r\n\r\n // Handle form submission\r\n const onSubmit = async (values: SwapFormValues) => {\r\n if (!connected) {\r\n toast.error(\"Wallet not connected\");\r\n return;\r\n }\r\n\r\n if (!publicKey) {\r\n toast.error(\"Public key not found\");\r\n return;\r\n }\r\n\r\n if (!connection) {\r\n toast.error(\"Invalid connection\");\r\n return;\r\n }\r\n\r\n if (!endpoint) {\r\n toast.error(\"RPC endpoint not found\");\r\n return;\r\n }\r\n\r\n if (!selectedTokenIn || !selectedTokenOut) {\r\n toast.error(\"Select tokens\");\r\n return;\r\n }\r\n\r\n if (!values.amountIn || values.amountIn <= 0) {\r\n toast.error(\"Invalid amount\");\r\n return;\r\n }\r\n\r\n try {\r\n setIsSubmitting(true);\r\n \r\n // Check token address\r\n if (!selectedTokenIn.mintAddress || !selectedTokenOut.mintAddress) {\r\n throw new Error(\"Token mintAddress not found\");\r\n }\r\n \r\n // Create PublicKey from address\r\n const inputMint = new PublicKey(selectedTokenIn.mintAddress);\r\n const outputMint = new PublicKey(selectedTokenOut.mintAddress);\r\n const slippageBps = Math.floor(slippageValue * 100);\r\n \r\n // Log transaction information for debugging\r\n console.log(\"=== Transaction Information ===\");\r\n console.log(\"Endpoint:\", endpoint);\r\n console.log(\"Input token:\", selectedTokenIn.symbol, inputMint.toString());\r\n console.log(\"Output token:\", selectedTokenOut.symbol, outputMint.toString());\r\n console.log(\"Amount:\", values.amountIn);\r\n console.log(\"Slippage:\", slippageBps, \"bps\");\r\n console.log(\"Wallet connected:\", connected ? \"Yes\" : \"No\");\r\n console.log(\"PublicKey:\", publicKey.toString());\r\n console.log(\"========================\");\r\n \r\n // Check all parameters before executing the transaction\r\n if (!wallet) {\r\n throw new Error(\"Wallet not connected\");\r\n }\r\n \r\n try {\r\n // Execute the swap transaction with proper validation\r\n console.log(\"Calling executeTrade with parameters:\");\r\n console.log(\" - outputMint:\", outputMint.toString());\r\n console.log(\" - inputAmount:\", values.amountIn);\r\n console.log(\" - inputMint:\", inputMint.toString());\r\n console.log(\" - slippageBps:\", slippageBps);\r\n console.log(\" - wallet:\", typeof wallet, wallet ? \"connected\" : \"not connected\");\r\n \r\n // Check if wallet supports signTransaction method\r\n const walletAdapter = wallet as any;\r\n console.log(\" - wallet supports signTransaction:\", walletAdapter?.signTransaction ? \"yes\" : \"no\");\r\n console.log(\" - endpoint:\", endpoint);\r\n\r\n // Pass fewer parameters, compatible with new API\r\n const signature = await executeTrade(\r\n outputMint,\r\n values.amountIn,\r\n inputMint,\r\n slippageBps\r\n );\r\n \r\n toast.success(\"Swap successful!\", {\r\n description: `Transaction: ${signature}`\r\n });\r\n \r\n // Reset form and update balances\r\n setAmountInValue(\"\");\r\n setAmountOutValue(\"\");\r\n form.setValue(\"amountIn\", undefined, {\r\n shouldValidate: false\r\n });\r\n form.setValue(\"amountOut\", undefined, {\r\n shouldValidate: false\r\n });\r\n setQuoteResult(null);\r\n \r\n // Update balances after successful swap\r\n if (publicKey) {\r\n await updateBalances();\r\n }\r\n } catch (tradeError: any) {\r\n console.error(\"Trade execution error:\", tradeError);\r\n toast.error(\"Transaction failed\", {\r\n description: tradeError.message || \"Unable to execute transaction\"\r\n });\r\n }\r\n } catch (error: any) {\r\n console.error(\"Swap error:\", error);\r\n toast.error(\"Swap failed\", {\r\n description: error.message || \"Transaction failed\"\r\n });\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Separate function to update balances\r\n const updateSelectedTokenBalances = (updatedTokens: TokenInfo[]) => {\r\n // Update selected token balances if they exist in the updated tokens list\r\n if (selectedTokenIn) {\r\n const updatedTokenIn = updatedTokens.find(t => t.id === selectedTokenIn.id);\r\n if (updatedTokenIn) {\r\n setSelectedTokenIn(updatedTokenIn);\r\n }\r\n }\r\n \r\n if (selectedTokenOut) {\r\n const updatedTokenOut = updatedTokens.find(t => t.id === selectedTokenOut.id);\r\n if (updatedTokenOut) {\r\n setSelectedTokenOut(updatedTokenOut);\r\n }\r\n }\r\n };\r\n\r\n // Existing updateBalances function remains the same\r\n const updateBalances = async () => {\r\n setIsUpdatingBalance(true);\r\n try {\r\n const updatedTokens = await fetchTokenAccounts(publicKey!);\r\n setAvailableTokens(updatedTokens);\r\n updateSelectedTokenBalances(updatedTokens);\r\n toast.success(\"Balances updated\");\r\n } catch (error) {\r\n console.error(\"Error updating balances:\", error);\r\n } finally {\r\n setIsUpdatingBalance(false);\r\n }\r\n };\r\n\r\n // Render token item for the select dropdown\r\n const renderTokenItem = (token: TokenInfo) => (\r\n \r\n
\r\n
\r\n {token.icon && (\r\n
\r\n {\r\n (e.target as HTMLImageElement).style.display = \"none\";\r\n }}\r\n />\r\n
\r\n )}\r\n {token.symbol}\r\n
\r\n {showTokenBalance && (\r\n \r\n {token.balance.toLocaleString(undefined, {\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: token.decimals > 6 ? 6 : token.decimals,\r\n })}\r\n \r\n )}\r\n
\r\n
\r\n );\r\n\r\n return (\r\n \r\n \r\n \r\n Swap Tokens\r\n \r\n \r\n \r\n \r\n \r\n
\r\n

Slippage Tolerance

\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n Custom: {slippageValue.toFixed(1)}%\r\n
\r\n handleSlippageChange(value[0])}\r\n />\r\n {slippageValue > 3 && (\r\n

\r\n High slippage increases the risk of price impact\r\n

\r\n )}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n {\r\n // Check if clicking MAX button then do not submit\r\n const target = e.target as HTMLElement;\r\n const maxButton = target.querySelector('.max-button');\r\n if (maxButton && (maxButton === document.activeElement || maxButton.contains(document.activeElement as Node))) {\r\n e.preventDefault();\r\n return;\r\n }\r\n \r\n e.preventDefault();\r\n form.handleSubmit(onSubmit)(e);\r\n }}\r\n className=\"space-y-4\"\r\n >\r\n {/* Token Input Field */}\r\n
\r\n (\r\n \r\n
\r\n You Pay\r\n {selectedTokenIn && showTokenBalance && (\r\n
\r\n \r\n Balance: {selectedTokenIn.balance.toLocaleString(undefined, {\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: selectedTokenIn.decimals > 6 ? 6 : selectedTokenIn.decimals,\r\n })}\r\n \r\n
e.stopPropagation()}>\r\n {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n handleUseMax();\r\n }}\r\n >\r\n MAX\r\n \r\n
\r\n
\r\n )}\r\n
\r\n
\r\n \r\n handleAmountInChange(e.target.value)}\r\n onBlur={handleAmountInBlur}\r\n disabled={!connected || !selectedTokenIn}\r\n className=\"bg-transparent border-none text-xl font-medium placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0\"\r\n />\r\n \r\n handleTokenChange(true, value)}\r\n value={field.value}\r\n disabled={!connected}\r\n >\r\n \r\n \r\n \r\n {selectedTokenIn && (\r\n
\r\n {selectedTokenIn.icon && (\r\n \r\n )}\r\n {selectedTokenIn.symbol}\r\n
\r\n )}\r\n \r\n
\r\n
\r\n \r\n {isLoadingTokens || isUpdatingBalance ? (\r\n
\r\n \r\n \r\n {isUpdatingBalance\r\n ? \"Updating balances...\"\r\n : \"Loading tokens...\"}\r\n \r\n
\r\n ) : availableTokens.length > 0 ? (\r\n \r\n {availableTokens.map(renderTokenItem)}\r\n \r\n ) : (\r\n
\r\n No tokens found\r\n
\r\n )}\r\n
\r\n \r\n
\r\n \r\n
\r\n )}\r\n />\r\n \r\n {/* Arrow button to switch tokens */}\r\n
\r\n \r\n \r\n \r\n
\r\n\r\n {/* Token Output Field */}\r\n (\r\n \r\n
\r\n You Receive\r\n {selectedTokenOut && showTokenBalance && (\r\n
\r\n Balance: {selectedTokenOut.balance.toLocaleString(undefined, {\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: selectedTokenOut.decimals > 6 ? 6 : selectedTokenOut.decimals,\r\n })}\r\n
\r\n )}\r\n
\r\n
\r\n \r\n \r\n \r\n handleTokenChange(false, value)}\r\n value={field.value}\r\n disabled={!connected}\r\n >\r\n \r\n \r\n \r\n {selectedTokenOut && (\r\n
\r\n {selectedTokenOut.icon && (\r\n \r\n )}\r\n {selectedTokenOut.symbol}\r\n
\r\n )}\r\n \r\n
\r\n
\r\n \r\n {isLoadingTokens || isUpdatingBalance ? (\r\n
\r\n \r\n \r\n {isUpdatingBalance\r\n ? \"Updating balances...\"\r\n : \"Loading tokens...\"}\r\n \r\n
\r\n ) : availableTokens.length > 0 ? (\r\n \r\n {availableTokens.map(renderTokenItem)}\r\n \r\n ) : (\r\n
\r\n No tokens found\r\n
\r\n )}\r\n
\r\n \r\n
\r\n \r\n
\r\n )}\r\n />\r\n
\r\n {/* Add swap button section */}\r\n
\r\n {!connected ? (\r\n \r\n ) : (\r\n \r\n {isSubmitting || isLoading? (\r\n <>\r\n \r\n Swapping...\r\n \r\n ) : (\r\n \"Swap\"\r\n )}\r\n \r\n )}\r\n
\r\n\r\n\r\n {/*/ Add exchange rate info if quote exists */}\r\n {quoteResult && (\r\n
\r\n
\r\n 1 {selectedTokenIn?.symbol} ≈ {quoteResult.exchangeRate.toLocaleString(undefined, {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: 6\r\n })} {selectedTokenOut?.symbol}\r\n
\r\n
\r\n \r\n Slippage: {slippageValue.toFixed(1)}%\r\n \r\n {quoteResult.priceImpactPct > 1 && (\r\n 3 ? 'text-red-500' : 'text-yellow-500'}`}>\r\n Price impact: {quoteResult.priceImpactPct.toFixed(2)}%\r\n \r\n )}\r\n
\r\n
\r\n )}\r\n
\r\n \r\n
\r\n
\r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/swap-token-form.tsx" }, { "path": "hook/murphy/use-JupiterTrade.ts", - "content": "import { VersionedTransaction, PublicKey, Connection } from \"@solana/web3.js\";\nimport {\n TOKENS,\n DEFAULT_OPTIONS,\n JUP_API,\n JUP_REFERRAL_ADDRESS,\n} from \"../../constants/swap/jupiter-constants\";\nimport { getMint, getAccount, getAssociatedTokenAddress, TokenAccountNotFoundError, TokenInvalidAccountOwnerError } from \"@solana/spl-token\";\nimport { useWallet, WalletContextState } from \"@solana/wallet-adapter-react\";\nimport { config } from \"../../config/swap\";\nimport { useContext } from \"react\";\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\n\n/**\n * Interface for quote result from Jupiter\n */\nexport interface QuoteResponse {\n inputMint: string;\n outputMint: string;\n amount: string;\n otherAmountThreshold: string;\n swapMode: string;\n slippageBps: number;\n platformFee?: {\n amount: string;\n feeBps: number;\n };\n priceImpactPct: number;\n routePlan: any[];\n contextSlot: number;\n timeTaken: number;\n outAmount: string;\n outAmountWithSlippage?: string;\n}\n\n/**\n * Get swap quote from Jupiter API\n * @param inputMint Mint address of input token\n * @param outputMint Mint address of output token\n * @param amount Amount of input token (scaled by decimals)\n * @param slippageBps Maximum slippage tolerance (basis points)\n * @returns Quote result\n */\nexport async function fetchQuote(\n outputMint: PublicKey,\n amount: number | string,\n inputMint: PublicKey,\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,\n useDynamicSlippage: boolean = false\n): Promise {\n try {\n // Convert amount to string to avoid issues with large numbers\n const amountStr = amount.toString();\n \n console.log(`fetchQuote: inputMint=${inputMint.toString()}, outputMint=${outputMint.toString()}, amount=${amountStr}`);\n \n // Validate parameters\n if (!inputMint || !outputMint || !amount || parseFloat(amountStr) <= 0) {\n throw new Error(\"Invalid quote parameters\");\n }\n \n // Check if input token is native SOL\n const isNativeSol = inputMint.equals(TOKENS.SOL);\n \n const apiUrl = `${JUP_API}/quote?` +\n `inputMint=${isNativeSol ? TOKENS.SOL.toString() : inputMint.toString()}` +\n `&outputMint=${outputMint.toString()}` +\n `&amount=${amountStr}` +\n `&slippageBps=${slippageBps}` +\n `&minimizeSlippage=false` +\n `&onlyDirectRoutes=false` +\n `&maxAccounts=64` +\n `&swapMode=ExactIn`;\n \n console.log(`Sending API request: ${apiUrl}`);\n \n const response = await fetch(apiUrl, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n },\n mode: 'cors',\n });\n \n // Check for HTTP errors\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Jupiter API error (${response.status}): ${errorText}`);\n \n if (response.status === 400) {\n throw new Error(`Unable to get quote: Invalid token amount or insufficient liquidity (${response.status})`);\n } else if (response.status === 429) {\n throw new Error(\"Too many requests, please try again later\");\n } else {\n throw new Error(`API error: ${response.status} - ${errorText || 'No error information'}`);\n }\n }\n \n const quoteResponse = await response.json();\n \n // Check if data is valid\n if (!quoteResponse) {\n console.error(\"Invalid quote data:\", quoteResponse);\n throw new Error(\"Invalid quote data\");\n }\n \n console.log(\"Received quote:\", quoteResponse);\n return quoteResponse;\n } catch (error: any) {\n console.error(\"Error fetching quote:\", error);\n throw new Error(`Unable to fetch quote: ${error.message || 'Unknown error'}`);\n }\n}\n\n/**\n * Scale token amount by decimals\n * @param amount Token amount (user input)\n * @param decimals Token decimals\n */\nexport function scaleAmount(amount: number, decimals: number): number {\n return amount * Math.pow(10, decimals);\n}\n\n/**\n * Format token amount from lamports to decimals\n * @param amount Token amount (in lamports)\n * @param decimals Token decimals\n */\nexport function formatAmount(amount: string | number, decimals: number): string {\n try {\n // Convert amount to string if it's a number\n const amountStr = typeof amount === 'number' ? amount.toString() : amount;\n \n // Convert to BigInt for precise handling of large numbers\n const amountBigInt = BigInt(amountStr);\n \n // Check if amount is zero\n if (amountBigInt === BigInt(0)) {\n return '0';\n }\n \n const divisor = BigInt(10 ** decimals);\n \n // Calculate whole part\n const wholePart = amountBigInt / divisor;\n \n // Calculate fractional part\n const fractionalPart = amountBigInt % divisor;\n \n // Format fractional part\n let fractionalStr = fractionalPart.toString().padStart(decimals, '0');\n \n // For SOL and very small amounts, ensure we show enough decimal places\n if (decimals === 9 && wholePart === BigInt(0) && fractionalPart > BigInt(0)) {\n // Format with fixed decimal places for visibility\n const formattedNumber = Number(amountBigInt) / Number(divisor);\n console.log(`Formatting small SOL amount: ${formattedNumber}`);\n \n // Ensure we display at least 4 significant digits\n // For 0.006, this would show 0.006 (not rounded)\n return formattedNumber.toFixed(Math.max(3, decimals.toString().length));\n }\n \n // Normal formatting for larger amounts\n // Remove trailing zeros but keep at least one decimal for small values\n const trimmedFractional = fractionalStr.replace(/0+$/, '');\n \n // If whole part is 0 and fractional part exists but would be trimmed to empty,\n // keep at least 4 decimal places to show small values\n if (wholePart === BigInt(0) && fractionalPart > BigInt(0) && trimmedFractional === '') {\n // Find first non-zero digit\n let significantDigits = 0;\n for (let i = 0; i < fractionalStr.length; i++) {\n if (fractionalStr[i] !== '0') {\n significantDigits = i;\n break;\n }\n }\n // Show at least the first non-zero digit and a few more\n const digitsToShow = Math.min(significantDigits + 3, fractionalStr.length);\n fractionalStr = fractionalStr.substring(0, digitsToShow);\n } else {\n fractionalStr = trimmedFractional;\n }\n \n // If no fractional part, return only whole part\n if (fractionalStr === '') {\n return wholePart.toString();\n }\n \n // Combine whole and fractional parts\n return `${wholePart.toString()}.${fractionalStr}`;\n } catch (error) {\n console.error(\"Error formatting token amount:\", error);\n return '0';\n }\n}\n\n// Hardcoded decimals for common tokens to avoid errors when querying blockchain\nconst TOKEN_DECIMALS: { [key: string]: number } = {\n // USDC\n 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 6,\n // USDT\n 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB': 6,\n // SOL (wrapped)\n 'So11111111111111111111111111111111111111112': 9,\n // BONK\n 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263': 5,\n // jitoSOL\n 'J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn': 9,\n // bSOL\n 'bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1': 9,\n // mSOL\n 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So': 9,\n // USDS\n 'USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA': 6,\n};\n\n/**\n * Function to get the decimals of a token by mint address\n */\nconst getTokenDecimals = (mintAddress: string): number => {\n // Use value from TOKEN_DECIMALS if available\n if (TOKEN_DECIMALS[mintAddress]) {\n return TOKEN_DECIMALS[mintAddress];\n }\n \n // Default value if not found\n console.warn(`Decimals for token ${mintAddress} not found, using default 6`);\n return 6;\n};\n\n/**\n * Solana blockchain token swap function, using Jupiter API\n */\nconst trade = async (\n outputMint: PublicKey,\n inputAmount: number,\n inputMint: PublicKey = TOKENS.USDC,\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,\n walletPublicKey: string, \n wallet: any,\n connectionEndpoint: string\n) => {\n try {\n // Check if all necessary parameters are provided\n if (!connectionEndpoint) {\n throw new Error(\"Connection endpoint is not defined\");\n }\n \n if (!walletPublicKey) {\n throw new Error(\"Wallet public key is not defined\");\n }\n \n if (!wallet) {\n throw new Error(\"Wallet is not defined\");\n }\n \n // Check if wallet has signTransaction function\n console.log(\"Checking wallet before trade:\", {\n walletType: typeof wallet,\n hasSignTransaction: typeof wallet.signTransaction === 'function'\n });\n \n if (typeof wallet.signTransaction !== 'function') {\n throw new Error(\"Wallet does not have signTransaction method\");\n }\n \n // Create connection to Solana blockchain\n const connection = new Connection(connectionEndpoint, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000\n });\n\n // Display transaction information\n console.log(`Executing swap with slippage ${slippageBps / 100}%`);\n console.log(\"Input token decimal:\", getTokenDecimals(inputMint.toString()));\n console.log(\"Output token decimal:\", getTokenDecimals(outputMint.toString()));\n \n // Adjust calculation of scaledAmount to only take the integer part\n const inputDecimals = getTokenDecimals(inputMint.toString());\n const scaledAmount = Math.floor(inputAmount * Math.pow(10, inputDecimals));\n console.log(\"Scaled amount:\", scaledAmount);\n\n // Get quote from Jupiter API\n const quoteResponse = await fetch(\n `${JUP_API}/quote?inputMint=${inputMint.toString()}&outputMint=${outputMint.toString()}&amount=${scaledAmount}&slippageBps=${slippageBps}`,\n {\n method: \"GET\",\n }\n );\n\n if (!quoteResponse.ok) {\n const errorText = await quoteResponse.text();\n console.error(`Jupiter API error (${quoteResponse.status}): ${errorText}`);\n \n if (quoteResponse.status === 400) {\n throw new Error(`Unable to get quote: Invalid token amount or insufficient liquidity (${quoteResponse.status}) - ${errorText}`);\n } else if (quoteResponse.status === 429) {\n throw new Error(\"Too many requests, please try again later\");\n } else {\n throw new Error(`API error: ${quoteResponse.status} - ${errorText || 'No error information'}`);\n }\n }\n\n const quote = await quoteResponse.json();\n console.log(\"Quote response:\", quote);\n \n // Set up referral fee if available\n const jupiterReferralAccount = process.env.NEXT_PUBLIC_JUPITER_REFERRAL_ACCOUNT;\n const referralAccount = jupiterReferralAccount ? new PublicKey(jupiterReferralAccount) : undefined;\n\n // Execute swap\n const swapResponse = await fetch(`${JUP_API}/swap`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n quoteResponse: quote,\n userPublicKey: walletPublicKey,\n feeAccount: referralAccount?.toString(),\n wrapAndUnwrapSol: true,\n }),\n });\n\n if (!swapResponse.ok) {\n throw new Error(`Error executing swap: ${swapResponse.status} ${swapResponse.statusText}`);\n }\n\n const swapResult = await swapResponse.json();\n console.log(\"Swap result:\", swapResult);\n\n // Decode transaction\n const swapTransaction = VersionedTransaction.deserialize(\n Buffer.from(swapResult.swapTransaction, \"base64\")\n );\n\n // Sign and send transaction\n try {\n console.log(\"Signing transaction with wallet:\", typeof wallet.signTransaction);\n const signedTransaction = await wallet.signTransaction(swapTransaction);\n console.log(\"Transaction successfully signed\");\n \n const txid = await connection.sendRawTransaction(\n signedTransaction.serialize()\n );\n console.log(\"Transaction sent. Txid:\", txid);\n \n console.log(\"Waiting for transaction confirmation...\");\n const confirmation = await connection.confirmTransaction(txid, \"confirmed\");\n console.log(\"Transaction confirmed:\", confirmation);\n \n return { success: true, txid };\n } catch (error: any) {\n console.error(\"Error signing or sending transaction:\", error);\n throw new Error(`Error signing or sending transaction: ${error.message}`);\n }\n } catch (error: any) {\n console.error(\"Error during trade execution:\", error);\n throw error;\n }\n};\n\n/**\n * Get token balance for a wallet address\n * @param walletAddress Wallet address to check balance for\n * @param tokenMint Token mint address to check\n * @param connection Solana connection\n * @returns Balance as a string with proper decimal formatting\n */\nexport async function getTokenBalance(\n walletAddress: PublicKey,\n tokenMint: PublicKey,\n connection: Connection\n): Promise {\n try {\n console.log(`Fetching balance for token: ${tokenMint.toString()} for wallet: ${walletAddress.toString()}`);\n \n // Check if token is SOL (native)\n if (tokenMint.equals(TOKENS.SOL)) {\n console.log(\"Getting native SOL balance\");\n // For native SOL, get the account info directly\n const balance = await connection.getBalance(walletAddress);\n console.log(`Raw SOL balance: ${balance}`);\n const formattedBalance = formatAmount(balance.toString(), 9); // SOL has 9 decimals\n console.log(`Formatted SOL balance: ${formattedBalance}`);\n return formattedBalance;\n }\n\n // For SPL tokens, get the associated token account\n const tokenAccount = await getAssociatedTokenAddress(\n tokenMint,\n walletAddress\n );\n console.log(`Token account address: ${tokenAccount.toString()}`);\n\n try {\n // Get token decimals first\n let decimals = 9; // Default\n \n // Use hardcoded decimals if available\n const mintString = tokenMint.toString();\n console.log(`Checking decimals for token: ${mintString}`);\n \n if (TOKEN_DECIMALS[mintString]) {\n decimals = TOKEN_DECIMALS[mintString];\n console.log(`Using hardcoded decimals: ${decimals}`);\n } else {\n // Otherwise query the mint\n try {\n console.log(\"Querying mint info for decimals\");\n const mintInfo = await getMint(connection, tokenMint);\n decimals = mintInfo.decimals;\n console.log(`Got decimals from mint: ${decimals}`);\n } catch (e) {\n console.error(\"Error getting mint info:\", e);\n console.log(\"Using default decimals (9)\");\n // Keep default decimals\n }\n }\n \n // Now get account info for the token account\n console.log(\"Fetching token account info\");\n const account = await getAccount(connection, tokenAccount);\n console.log(`Raw token amount: ${account.amount.toString()}`);\n \n // Format the balance with proper decimals\n const formattedBalance = formatAmount(account.amount.toString(), decimals);\n console.log(`Formatted token balance: ${formattedBalance} (using ${decimals} decimals)`);\n return formattedBalance;\n } catch (error) {\n // Check if error is due to account not found\n if (\n error instanceof TokenAccountNotFoundError ||\n error instanceof TokenInvalidAccountOwnerError\n ) {\n console.log(\"Token account not found or invalid owner, balance is 0\");\n // If account doesn't exist, balance is 0\n return \"0\";\n }\n console.error(\"Error getting token account:\", error);\n throw error;\n }\n } catch (error) {\n console.error(\"Error fetching token balance:\", error);\n return \"0\";\n }\n}\n\n// Hook to use in React components\nexport function useJupiterTrade() {\n const { endpoint } = useContext(ModalContext);\n const wallet = useWallet();\n const { publicKey } = wallet;\n\n /**\n * Get swap token quote\n */\n const getQuote = async (\n outputMint: PublicKey,\n inputAmount: number, // decimal number\n inputMint: PublicKey = TOKENS.USDC,\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS\n ) => {\n try {\n if (!inputAmount || inputAmount <= 0) throw new Error(\"Invalid token amount\");\n if (inputMint.equals(outputMint)) throw new Error(\"Input and output tokens must be different\");\n \n // Get decimals for input\n let inputDecimals = TOKEN_DECIMALS[inputMint.toString()] ?? 9;\n // Scale inputAmount to smallest unit and round down to avoid decimals\n const scaledAmount = Math.floor(inputAmount * Math.pow(10, inputDecimals));\n if (scaledAmount <= 0) throw new Error(\"Invalid token amount after conversion\");\n \n // Call Jupiter API\n const quote = await fetchQuote(outputMint, scaledAmount, inputMint, slippageBps, false);\n if (!quote) throw new Error(\"Unable to get quote\");\n \n // Get decimals for output\n let outputDecimals = TOKEN_DECIMALS[outputMint.toString()] ?? 9;\n // Format output (decimal number)\n const outAmount = quote.outAmount ? quote.outAmount : 0;\n const formattedOutAmount = formatAmount(outAmount, outputDecimals);\n \n // Calculate exchange rate\n const exchangeRate = inputAmount > 0 ? parseFloat(formattedOutAmount) / inputAmount : 0;\n const priceImpactPct = quote.priceImpactPct ? parseFloat(quote.priceImpactPct) : 0;\n \n return {\n outputAmount: formattedOutAmount,\n exchangeRate,\n priceImpactPct,\n routeInfo: quote.routePlan || null\n };\n } catch (error: any) {\n throw error;\n }\n };\n\n /**\n * Execute token swap transaction\n */\n const executeTrade = async (\n outputMint: PublicKey,\n inputAmount: number,\n inputMint: PublicKey = TOKENS.USDC,\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS\n ) => {\n try {\n // Check if wallet is connected and has endpoint\n if (!publicKey || !endpoint) {\n console.error(\"publicKey or endpoint does not exist:\", { publicKey, endpoint });\n throw new Error(\"Wallet not connected or endpoint not defined\");\n }\n\n // Check input parameters\n console.log(\"Checking input parameters for trade:\", {\n inputAmount,\n inputMintStr: inputMint.toString(),\n outputMintStr: outputMint.toString(),\n slippageBps,\n inputAmountType: typeof inputAmount\n });\n\n // Check if inputAmount is a positive number\n if (typeof inputAmount !== 'number' || isNaN(inputAmount) || inputAmount <= 0) {\n throw new Error(`Invalid token amount: ${inputAmount}`);\n }\n\n // Use wallet directly from useWallet hook\n console.log(\"Checking wallet details:\", {\n connected: wallet?.connected,\n publicKey: publicKey?.toString(),\n hasSignTransaction: !!wallet?.signTransaction,\n signTransactionType: typeof wallet?.signTransaction\n });\n\n // Check if wallet supports signTransaction method\n if (!wallet || typeof wallet.signTransaction !== 'function') {\n throw new Error(\"Wallet does not support signTransaction method\");\n }\n\n // Call trade function with full parameters\n console.log(\"Calling trade function with parameters:\", {\n outputMint: outputMint.toString(),\n inputAmount,\n inputMint: inputMint.toString(),\n slippageBps,\n publicKey: publicKey.toString()\n });\n\n return await trade(\n outputMint,\n inputAmount,\n inputMint,\n slippageBps,\n publicKey.toString(),\n wallet,\n endpoint\n );\n } catch (error: any) {\n console.error(\"Error in executeTrade:\", error);\n throw new Error(`Unable to execute trade: ${error.message}`);\n }\n };\n\n /**\n * Get balance for a token\n */\n const getBalance = async (\n tokenMint: PublicKey\n ): Promise => {\n if (!publicKey || !endpoint) {\n console.log(\"getBalance: Wallet not connected or endpoint not defined\");\n return \"0\";\n }\n \n console.log(`getBalance: Checking balance for token ${tokenMint.toString()}`);\n console.log(`getBalance: Using endpoint ${endpoint}`);\n console.log(`getBalance: Wallet address ${publicKey.toString()}`);\n \n // Create a promise with timeout to avoid hanging\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(\"getBalance: Connection timeout after 10 seconds\"));\n }, 10000); // 10 seconds timeout\n });\n \n try {\n // Race between API call and timeout\n return await Promise.race([\n (async () => {\n // Try using direct connection to Solana RPC\n try {\n console.log(\"getBalance: Creating direct connection to Solana RPC\");\n \n // Create connection with optimized options\n const connection = new Connection(endpoint, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 10000,\n disableRetryOnRateLimit: false,\n });\n \n console.log(\"getBalance: Created connection object\");\n \n // Skip connection check to avoid 403 error\n // Go straight to getting SOL balance\n \n // Special handling for SOL\n if (tokenMint.equals(TOKENS.SOL)) {\n console.log(\"getBalance: Getting SOL balance (special handling)\");\n try {\n console.log(`getBalance: Getting SOL balance for wallet ${publicKey.toString()}`);\n \n // Use try-catch for each API call\n const rawBalance = await connection.getBalance(publicKey);\n console.log(`getBalance: Raw SOL balance in lamports: ${rawBalance}`);\n \n // Convert lamports to SOL directly\n const solBalance = rawBalance / 1000000000;\n console.log(`getBalance: SOL balance in SOL units: ${solBalance}`);\n \n // SPECIAL: Display small SOL with enough decimal places\n if (solBalance > 0) {\n // Always display small SOL balance with fixed format, regardless of size\n const formatted = solBalance.toFixed(6);\n console.log(`getBalance: Formatted SOL balance for small amount: ${formatted}`);\n return formatted;\n }\n \n if (solBalance === 0) {\n return \"0\";\n }\n \n // Fallback: Use standard formatter\n const formattedBalance = formatAmount(rawBalance.toString(), 9);\n console.log(`getBalance: Formatted SOL balance: ${formattedBalance}`);\n return formattedBalance;\n } catch (error) {\n console.error(\"getBalance: Error getting SOL balance:\", error);\n return \"0\";\n }\n }\n \n // For SPL tokens, try getting token account\n try {\n // Try simpler method for SPL token instead of using getTokenBalance\n const tokenAccount = await getAssociatedTokenAddress(\n tokenMint,\n publicKey\n );\n console.log(`Token account address: ${tokenAccount.toString()}`);\n \n try {\n // Get decimals from hardcoded values instead of querying blockchain\n const mintString = tokenMint.toString();\n let decimals = 9; // Default\n \n if (TOKEN_DECIMALS[mintString]) {\n decimals = TOKEN_DECIMALS[mintString];\n console.log(`Using hardcoded decimals: ${decimals}`);\n }\n \n // Get token account info\n const account = await getAccount(connection, tokenAccount);\n console.log(`Raw token amount: ${account.amount.toString()}`);\n \n // Format balance with correct decimals\n return formatAmount(account.amount.toString(), decimals);\n } catch (error) {\n // Handle case where token account does not exist\n if (error instanceof TokenAccountNotFoundError) {\n console.log(\"Token account not found, balance is 0\");\n return \"0\";\n }\n console.error(\"Error getting token account:\", error);\n return \"0\";\n }\n } catch (tokenError) {\n console.error(\"getBalance: Error setting up token account check:\", tokenError);\n return \"0\";\n }\n } catch (connectionError) {\n console.error(\"getBalance: Could not establish connection:\", connectionError);\n return \"0\";\n }\n })(),\n timeoutPromise\n ]);\n } catch (error) {\n console.error(\"getBalance: Error getting balance:\", error);\n return \"0\";\n }\n };\n\n return { executeTrade, getQuote, getBalance };\n}", + "content": "import { VersionedTransaction, PublicKey, Connection } from \"@solana/web3.js\";\r\nimport {\r\n TOKENS,\r\n DEFAULT_OPTIONS,\r\n JUP_API,\r\n JUP_REFERRAL_ADDRESS,\r\n} from \"../../constants/swap/jupiter-constants\";\r\nimport { getMint, getAccount, getAssociatedTokenAddress, TokenAccountNotFoundError, TokenInvalidAccountOwnerError } from \"@solana/spl-token\";\r\nimport { useWallet, WalletContextState } from \"@solana/wallet-adapter-react\";\r\nimport { config } from \"../../config/swap\";\r\nimport { useContext } from \"react\";\r\nimport { ModalContext } from \"@/components/providers/wallet-provider\";\r\n\r\n/**\r\n * Interface for quote result from Jupiter\r\n */\r\nexport interface QuoteResponse {\r\n inputMint: string;\r\n outputMint: string;\r\n amount: string;\r\n otherAmountThreshold: string;\r\n swapMode: string;\r\n slippageBps: number;\r\n platformFee?: {\r\n amount: string;\r\n feeBps: number;\r\n };\r\n priceImpactPct: number;\r\n routePlan: any[];\r\n contextSlot: number;\r\n timeTaken: number;\r\n outAmount: string;\r\n outAmountWithSlippage?: string;\r\n}\r\n\r\n/**\r\n * Get swap quote from Jupiter API\r\n * @param inputMint Mint address of input token\r\n * @param outputMint Mint address of output token\r\n * @param amount Amount of input token (scaled by decimals)\r\n * @param slippageBps Maximum slippage tolerance (basis points)\r\n * @returns Quote result\r\n */\r\nexport async function fetchQuote(\r\n outputMint: PublicKey,\r\n amount: number | string,\r\n inputMint: PublicKey,\r\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,\r\n useDynamicSlippage: boolean = false\r\n): Promise {\r\n try {\r\n // Convert amount to string to avoid issues with large numbers\r\n const amountStr = amount.toString();\r\n \r\n console.log(`fetchQuote: inputMint=${inputMint.toString()}, outputMint=${outputMint.toString()}, amount=${amountStr}`);\r\n \r\n // Validate parameters\r\n if (!inputMint || !outputMint || !amount || parseFloat(amountStr) <= 0) {\r\n throw new Error(\"Invalid quote parameters\");\r\n }\r\n \r\n // Check if input token is native SOL\r\n const isNativeSol = inputMint.equals(TOKENS.SOL);\r\n \r\n const apiUrl = `${JUP_API}/quote?` +\r\n `inputMint=${isNativeSol ? TOKENS.SOL.toString() : inputMint.toString()}` +\r\n `&outputMint=${outputMint.toString()}` +\r\n `&amount=${amountStr}` +\r\n `&slippageBps=${slippageBps}` +\r\n `&minimizeSlippage=false` +\r\n `&onlyDirectRoutes=false` +\r\n `&maxAccounts=64` +\r\n `&swapMode=ExactIn`;\r\n \r\n console.log(`Sending API request: ${apiUrl}`);\r\n \r\n const response = await fetch(apiUrl, {\r\n method: 'GET',\r\n headers: {\r\n 'Accept': 'application/json',\r\n },\r\n mode: 'cors',\r\n });\r\n \r\n // Check for HTTP errors\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n console.error(`Jupiter API error (${response.status}): ${errorText}`);\r\n \r\n if (response.status === 400) {\r\n throw new Error(`Unable to get quote: Invalid token amount or insufficient liquidity (${response.status})`);\r\n } else if (response.status === 429) {\r\n throw new Error(\"Too many requests, please try again later\");\r\n } else {\r\n throw new Error(`API error: ${response.status} - ${errorText || 'No error information'}`);\r\n }\r\n }\r\n \r\n const quoteResponse = await response.json();\r\n \r\n // Check if data is valid\r\n if (!quoteResponse) {\r\n console.error(\"Invalid quote data:\", quoteResponse);\r\n throw new Error(\"Invalid quote data\");\r\n }\r\n \r\n console.log(\"Received quote:\", quoteResponse);\r\n return quoteResponse;\r\n } catch (error: any) {\r\n console.error(\"Error fetching quote:\", error);\r\n throw new Error(`Unable to fetch quote: ${error.message || 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Scale token amount by decimals\r\n * @param amount Token amount (user input)\r\n * @param decimals Token decimals\r\n */\r\nexport function scaleAmount(amount: number, decimals: number): number {\r\n return amount * Math.pow(10, decimals);\r\n}\r\n\r\n/**\r\n * Format token amount from lamports to decimals\r\n * @param amount Token amount (in lamports)\r\n * @param decimals Token decimals\r\n */\r\nexport function formatAmount(amount: string | number, decimals: number): string {\r\n try {\r\n // Convert amount to string if it's a number\r\n const amountStr = typeof amount === 'number' ? amount.toString() : amount;\r\n \r\n // Convert to BigInt for precise handling of large numbers\r\n const amountBigInt = BigInt(amountStr);\r\n \r\n // Check if amount is zero\r\n if (amountBigInt === BigInt(0)) {\r\n return '0';\r\n }\r\n \r\n const divisor = BigInt(10 ** decimals);\r\n \r\n // Calculate whole part\r\n const wholePart = amountBigInt / divisor;\r\n \r\n // Calculate fractional part\r\n const fractionalPart = amountBigInt % divisor;\r\n \r\n // Format fractional part\r\n let fractionalStr = fractionalPart.toString().padStart(decimals, '0');\r\n \r\n // For SOL and very small amounts, ensure we show enough decimal places\r\n if (decimals === 9 && wholePart === BigInt(0) && fractionalPart > BigInt(0)) {\r\n // Format with fixed decimal places for visibility\r\n const formattedNumber = Number(amountBigInt) / Number(divisor);\r\n console.log(`Formatting small SOL amount: ${formattedNumber}`);\r\n \r\n // Ensure we display at least 4 significant digits\r\n // For 0.006, this would show 0.006 (not rounded)\r\n return formattedNumber.toFixed(Math.max(3, decimals.toString().length));\r\n }\r\n \r\n // Normal formatting for larger amounts\r\n // Remove trailing zeros but keep at least one decimal for small values\r\n const trimmedFractional = fractionalStr.replace(/0+$/, '');\r\n \r\n // If whole part is 0 and fractional part exists but would be trimmed to empty,\r\n // keep at least 4 decimal places to show small values\r\n if (wholePart === BigInt(0) && fractionalPart > BigInt(0) && trimmedFractional === '') {\r\n // Find first non-zero digit\r\n let significantDigits = 0;\r\n for (let i = 0; i < fractionalStr.length; i++) {\r\n if (fractionalStr[i] !== '0') {\r\n significantDigits = i;\r\n break;\r\n }\r\n }\r\n // Show at least the first non-zero digit and a few more\r\n const digitsToShow = Math.min(significantDigits + 3, fractionalStr.length);\r\n fractionalStr = fractionalStr.substring(0, digitsToShow);\r\n } else {\r\n fractionalStr = trimmedFractional;\r\n }\r\n \r\n // If no fractional part, return only whole part\r\n if (fractionalStr === '') {\r\n return wholePart.toString();\r\n }\r\n \r\n // Combine whole and fractional parts\r\n return `${wholePart.toString()}.${fractionalStr}`;\r\n } catch (error) {\r\n console.error(\"Error formatting token amount:\", error);\r\n return '0';\r\n }\r\n}\r\n\r\n// Hardcoded decimals for common tokens to avoid errors when querying blockchain\r\nconst TOKEN_DECIMALS: { [key: string]: number } = {\r\n // USDC\r\n 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': 6,\r\n // USDT\r\n 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB': 6,\r\n // SOL (wrapped)\r\n 'So11111111111111111111111111111111111111112': 9,\r\n // BONK\r\n 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263': 5,\r\n // jitoSOL\r\n 'J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn': 9,\r\n // bSOL\r\n 'bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1': 9,\r\n // mSOL\r\n 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So': 9,\r\n // USDS\r\n 'USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA': 6,\r\n};\r\n\r\n/**\r\n * Function to get the decimals of a token by mint address\r\n */\r\nconst getTokenDecimals = (mintAddress: string): number => {\r\n // Use value from TOKEN_DECIMALS if available\r\n if (TOKEN_DECIMALS[mintAddress]) {\r\n return TOKEN_DECIMALS[mintAddress];\r\n }\r\n \r\n // Default value if not found\r\n console.warn(`Decimals for token ${mintAddress} not found, using default 6`);\r\n return 6;\r\n};\r\n\r\n/**\r\n * Solana blockchain token swap function, using Jupiter API\r\n */\r\nconst trade = async (\r\n outputMint: PublicKey,\r\n inputAmount: number,\r\n inputMint: PublicKey = TOKENS.USDC,\r\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,\r\n walletPublicKey: string, \r\n wallet: any,\r\n connectionEndpoint: string\r\n) => {\r\n try {\r\n // Check if all necessary parameters are provided\r\n if (!connectionEndpoint) {\r\n throw new Error(\"Connection endpoint is not defined\");\r\n }\r\n \r\n if (!walletPublicKey) {\r\n throw new Error(\"Wallet public key is not defined\");\r\n }\r\n \r\n if (!wallet) {\r\n throw new Error(\"Wallet is not defined\");\r\n }\r\n \r\n // Check if wallet has signTransaction function\r\n console.log(\"Checking wallet before trade:\", {\r\n walletType: typeof wallet,\r\n hasSignTransaction: typeof wallet.signTransaction === 'function'\r\n });\r\n \r\n if (typeof wallet.signTransaction !== 'function') {\r\n throw new Error(\"Wallet does not have signTransaction method\");\r\n }\r\n \r\n // Create connection to Solana blockchain\r\n const connection = new Connection(connectionEndpoint, {\r\n commitment: 'confirmed',\r\n confirmTransactionInitialTimeout: 60000\r\n });\r\n\r\n // Display transaction information\r\n console.log(`Executing swap with slippage ${slippageBps / 100}%`);\r\n console.log(\"Input token decimal:\", getTokenDecimals(inputMint.toString()));\r\n console.log(\"Output token decimal:\", getTokenDecimals(outputMint.toString()));\r\n \r\n // Adjust calculation of scaledAmount to only take the integer part\r\n const inputDecimals = getTokenDecimals(inputMint.toString());\r\n const scaledAmount = Math.floor(inputAmount * Math.pow(10, inputDecimals));\r\n console.log(\"Scaled amount:\", scaledAmount);\r\n\r\n // Get quote from Jupiter API\r\n const quoteResponse = await fetch(\r\n `${JUP_API}/quote?inputMint=${inputMint.toString()}&outputMint=${outputMint.toString()}&amount=${scaledAmount}&slippageBps=${slippageBps}`,\r\n {\r\n method: \"GET\",\r\n }\r\n );\r\n\r\n if (!quoteResponse.ok) {\r\n const errorText = await quoteResponse.text();\r\n console.error(`Jupiter API error (${quoteResponse.status}): ${errorText}`);\r\n \r\n if (quoteResponse.status === 400) {\r\n throw new Error(`Unable to get quote: Invalid token amount or insufficient liquidity (${quoteResponse.status}) - ${errorText}`);\r\n } else if (quoteResponse.status === 429) {\r\n throw new Error(\"Too many requests, please try again later\");\r\n } else {\r\n throw new Error(`API error: ${quoteResponse.status} - ${errorText || 'No error information'}`);\r\n }\r\n }\r\n\r\n const quote = await quoteResponse.json();\r\n console.log(\"Quote response:\", quote);\r\n \r\n // Set up referral fee if available\r\n const jupiterReferralAccount = process.env.NEXT_PUBLIC_JUPITER_REFERRAL_ACCOUNT;\r\n const referralAccount = jupiterReferralAccount ? new PublicKey(jupiterReferralAccount) : undefined;\r\n\r\n // Execute swap\r\n const swapResponse = await fetch(`${JUP_API}/swap`, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify({\r\n quoteResponse: quote,\r\n userPublicKey: walletPublicKey,\r\n feeAccount: referralAccount?.toString(),\r\n wrapAndUnwrapSol: true,\r\n }),\r\n });\r\n\r\n if (!swapResponse.ok) {\r\n throw new Error(`Error executing swap: ${swapResponse.status} ${swapResponse.statusText}`);\r\n }\r\n\r\n const swapResult = await swapResponse.json();\r\n console.log(\"Swap result:\", swapResult);\r\n\r\n // Decode transaction\r\n const swapTransaction = VersionedTransaction.deserialize(\r\n Buffer.from(swapResult.swapTransaction, \"base64\")\r\n );\r\n\r\n // Sign and send transaction\r\n try {\r\n console.log(\"Signing transaction with wallet:\", typeof wallet.signTransaction);\r\n const signedTransaction = await wallet.signTransaction(swapTransaction);\r\n console.log(\"Transaction successfully signed\");\r\n \r\n const txid = await connection.sendRawTransaction(\r\n signedTransaction.serialize()\r\n );\r\n console.log(\"Transaction sent. Txid:\", txid);\r\n \r\n console.log(\"Waiting for transaction confirmation...\");\r\n const confirmation = await connection.confirmTransaction(txid, \"confirmed\");\r\n console.log(\"Transaction confirmed:\", confirmation);\r\n \r\n return { success: true, txid };\r\n } catch (error: any) {\r\n console.error(\"Error signing or sending transaction:\", error);\r\n throw new Error(`Error signing or sending transaction: ${error.message}`);\r\n }\r\n } catch (error: any) {\r\n console.error(\"Error during trade execution:\", error);\r\n throw error;\r\n }\r\n};\r\n\r\n/**\r\n * Get token balance for a wallet address\r\n * @param walletAddress Wallet address to check balance for\r\n * @param tokenMint Token mint address to check\r\n * @param connection Solana connection\r\n * @returns Balance as a string with proper decimal formatting\r\n */\r\nexport async function getTokenBalance(\r\n walletAddress: PublicKey,\r\n tokenMint: PublicKey,\r\n connection: Connection\r\n): Promise {\r\n try {\r\n console.log(`Fetching balance for token: ${tokenMint.toString()} for wallet: ${walletAddress.toString()}`);\r\n \r\n // Check if token is SOL (native)\r\n if (tokenMint.equals(TOKENS.SOL)) {\r\n console.log(\"Getting native SOL balance\");\r\n // For native SOL, get the account info directly\r\n const balance = await connection.getBalance(walletAddress);\r\n console.log(`Raw SOL balance: ${balance}`);\r\n const formattedBalance = formatAmount(balance.toString(), 9); // SOL has 9 decimals\r\n console.log(`Formatted SOL balance: ${formattedBalance}`);\r\n return formattedBalance;\r\n }\r\n\r\n // For SPL tokens, get the associated token account\r\n const tokenAccount = await getAssociatedTokenAddress(\r\n tokenMint,\r\n walletAddress\r\n );\r\n console.log(`Token account address: ${tokenAccount.toString()}`);\r\n\r\n try {\r\n // Get token decimals first\r\n let decimals = 9; // Default\r\n \r\n // Use hardcoded decimals if available\r\n const mintString = tokenMint.toString();\r\n console.log(`Checking decimals for token: ${mintString}`);\r\n \r\n if (TOKEN_DECIMALS[mintString]) {\r\n decimals = TOKEN_DECIMALS[mintString];\r\n console.log(`Using hardcoded decimals: ${decimals}`);\r\n } else {\r\n // Otherwise query the mint\r\n try {\r\n console.log(\"Querying mint info for decimals\");\r\n const mintInfo = await getMint(connection, tokenMint);\r\n decimals = mintInfo.decimals;\r\n console.log(`Got decimals from mint: ${decimals}`);\r\n } catch (e) {\r\n console.error(\"Error getting mint info:\", e);\r\n console.log(\"Using default decimals (9)\");\r\n // Keep default decimals\r\n }\r\n }\r\n \r\n // Now get account info for the token account\r\n console.log(\"Fetching token account info\");\r\n const account = await getAccount(connection, tokenAccount);\r\n console.log(`Raw token amount: ${account.amount.toString()}`);\r\n \r\n // Format the balance with proper decimals\r\n const formattedBalance = formatAmount(account.amount.toString(), decimals);\r\n console.log(`Formatted token balance: ${formattedBalance} (using ${decimals} decimals)`);\r\n return formattedBalance;\r\n } catch (error) {\r\n // Check if error is due to account not found\r\n if (\r\n error instanceof TokenAccountNotFoundError ||\r\n error instanceof TokenInvalidAccountOwnerError\r\n ) {\r\n console.log(\"Token account not found or invalid owner, balance is 0\");\r\n // If account doesn't exist, balance is 0\r\n return \"0\";\r\n }\r\n console.error(\"Error getting token account:\", error);\r\n throw error;\r\n }\r\n } catch (error) {\r\n console.error(\"Error fetching token balance:\", error);\r\n return \"0\";\r\n }\r\n}\r\n\r\n// Hook to use in React components\r\nexport function useJupiterTrade() {\r\n const { endpoint } = useContext(ModalContext);\r\n const wallet = useWallet();\r\n const { publicKey } = wallet;\r\n\r\n /**\r\n * Get swap token quote\r\n */\r\n const getQuote = async (\r\n outputMint: PublicKey,\r\n inputAmount: number, // decimal number\r\n inputMint: PublicKey = TOKENS.USDC,\r\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS\r\n ) => {\r\n try {\r\n if (!inputAmount || inputAmount <= 0) throw new Error(\"Invalid token amount\");\r\n if (inputMint.equals(outputMint)) throw new Error(\"Input and output tokens must be different\");\r\n \r\n // Get decimals for input\r\n let inputDecimals = TOKEN_DECIMALS[inputMint.toString()] ?? 9;\r\n // Scale inputAmount to smallest unit and round down to avoid decimals\r\n const scaledAmount = Math.floor(inputAmount * Math.pow(10, inputDecimals));\r\n if (scaledAmount <= 0) throw new Error(\"Invalid token amount after conversion\");\r\n \r\n // Call Jupiter API\r\n const quote = await fetchQuote(outputMint, scaledAmount, inputMint, slippageBps, false);\r\n if (!quote) throw new Error(\"Unable to get quote\");\r\n \r\n // Get decimals for output\r\n let outputDecimals = TOKEN_DECIMALS[outputMint.toString()] ?? 9;\r\n // Format output (decimal number)\r\n const outAmount = quote.outAmount ? quote.outAmount : 0;\r\n const formattedOutAmount = formatAmount(outAmount, outputDecimals);\r\n \r\n // Calculate exchange rate\r\n const exchangeRate = inputAmount > 0 ? parseFloat(formattedOutAmount) / inputAmount : 0;\r\n const priceImpactPct = quote.priceImpactPct ? parseFloat(quote.priceImpactPct) : 0;\r\n \r\n return {\r\n outputAmount: formattedOutAmount,\r\n exchangeRate,\r\n priceImpactPct,\r\n routeInfo: quote.routePlan || null\r\n };\r\n } catch (error: any) {\r\n throw error;\r\n }\r\n };\r\n\r\n /**\r\n * Execute token swap transaction\r\n */\r\n const executeTrade = async (\r\n outputMint: PublicKey,\r\n inputAmount: number,\r\n inputMint: PublicKey = TOKENS.USDC,\r\n slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS\r\n ) => {\r\n try {\r\n // Check if wallet is connected and has endpoint\r\n if (!publicKey || !endpoint) {\r\n console.error(\"publicKey or endpoint does not exist:\", { publicKey, endpoint });\r\n throw new Error(\"Wallet not connected or endpoint not defined\");\r\n }\r\n\r\n // Check input parameters\r\n console.log(\"Checking input parameters for trade:\", {\r\n inputAmount,\r\n inputMintStr: inputMint.toString(),\r\n outputMintStr: outputMint.toString(),\r\n slippageBps,\r\n inputAmountType: typeof inputAmount\r\n });\r\n\r\n // Check if inputAmount is a positive number\r\n if (typeof inputAmount !== 'number' || isNaN(inputAmount) || inputAmount <= 0) {\r\n throw new Error(`Invalid token amount: ${inputAmount}`);\r\n }\r\n\r\n // Use wallet directly from useWallet hook\r\n console.log(\"Checking wallet details:\", {\r\n connected: wallet?.connected,\r\n publicKey: publicKey?.toString(),\r\n hasSignTransaction: !!wallet?.signTransaction,\r\n signTransactionType: typeof wallet?.signTransaction\r\n });\r\n\r\n // Check if wallet supports signTransaction method\r\n if (!wallet || typeof wallet.signTransaction !== 'function') {\r\n throw new Error(\"Wallet does not support signTransaction method\");\r\n }\r\n\r\n // Call trade function with full parameters\r\n console.log(\"Calling trade function with parameters:\", {\r\n outputMint: outputMint.toString(),\r\n inputAmount,\r\n inputMint: inputMint.toString(),\r\n slippageBps,\r\n publicKey: publicKey.toString()\r\n });\r\n\r\n return await trade(\r\n outputMint,\r\n inputAmount,\r\n inputMint,\r\n slippageBps,\r\n publicKey.toString(),\r\n wallet,\r\n endpoint\r\n );\r\n } catch (error: any) {\r\n console.error(\"Error in executeTrade:\", error);\r\n throw new Error(`Unable to execute trade: ${error.message}`);\r\n }\r\n };\r\n\r\n /**\r\n * Get balance for a token\r\n */\r\n const getBalance = async (\r\n tokenMint: PublicKey\r\n ): Promise => {\r\n if (!publicKey || !endpoint) {\r\n console.log(\"getBalance: Wallet not connected or endpoint not defined\");\r\n return \"0\";\r\n }\r\n \r\n console.log(`getBalance: Checking balance for token ${tokenMint.toString()}`);\r\n console.log(`getBalance: Using endpoint ${endpoint}`);\r\n console.log(`getBalance: Wallet address ${publicKey.toString()}`);\r\n \r\n // Create a promise with timeout to avoid hanging\r\n const timeoutPromise = new Promise((_, reject) => {\r\n setTimeout(() => {\r\n reject(new Error(\"getBalance: Connection timeout after 10 seconds\"));\r\n }, 10000); // 10 seconds timeout\r\n });\r\n \r\n try {\r\n // Race between API call and timeout\r\n return await Promise.race([\r\n (async () => {\r\n // Try using direct connection to Solana RPC\r\n try {\r\n console.log(\"getBalance: Creating direct connection to Solana RPC\");\r\n \r\n // Create connection with optimized options\r\n const connection = new Connection(endpoint, {\r\n commitment: 'confirmed',\r\n confirmTransactionInitialTimeout: 10000,\r\n disableRetryOnRateLimit: false,\r\n });\r\n \r\n console.log(\"getBalance: Created connection object\");\r\n \r\n // Skip connection check to avoid 403 error\r\n // Go straight to getting SOL balance\r\n \r\n // Special handling for SOL\r\n if (tokenMint.equals(TOKENS.SOL)) {\r\n console.log(\"getBalance: Getting SOL balance (special handling)\");\r\n try {\r\n console.log(`getBalance: Getting SOL balance for wallet ${publicKey.toString()}`);\r\n \r\n // Use try-catch for each API call\r\n const rawBalance = await connection.getBalance(publicKey);\r\n console.log(`getBalance: Raw SOL balance in lamports: ${rawBalance}`);\r\n \r\n // Convert lamports to SOL directly\r\n const solBalance = rawBalance / 1000000000;\r\n console.log(`getBalance: SOL balance in SOL units: ${solBalance}`);\r\n \r\n // SPECIAL: Display small SOL with enough decimal places\r\n if (solBalance > 0) {\r\n // Always display small SOL balance with fixed format, regardless of size\r\n const formatted = solBalance.toFixed(6);\r\n console.log(`getBalance: Formatted SOL balance for small amount: ${formatted}`);\r\n return formatted;\r\n }\r\n \r\n if (solBalance === 0) {\r\n return \"0\";\r\n }\r\n \r\n // Fallback: Use standard formatter\r\n const formattedBalance = formatAmount(rawBalance.toString(), 9);\r\n console.log(`getBalance: Formatted SOL balance: ${formattedBalance}`);\r\n return formattedBalance;\r\n } catch (error) {\r\n console.error(\"getBalance: Error getting SOL balance:\", error);\r\n return \"0\";\r\n }\r\n }\r\n \r\n // For SPL tokens, try getting token account\r\n try {\r\n // Try simpler method for SPL token instead of using getTokenBalance\r\n const tokenAccount = await getAssociatedTokenAddress(\r\n tokenMint,\r\n publicKey\r\n );\r\n console.log(`Token account address: ${tokenAccount.toString()}`);\r\n \r\n try {\r\n // Get decimals from hardcoded values instead of querying blockchain\r\n const mintString = tokenMint.toString();\r\n let decimals = 9; // Default\r\n \r\n if (TOKEN_DECIMALS[mintString]) {\r\n decimals = TOKEN_DECIMALS[mintString];\r\n console.log(`Using hardcoded decimals: ${decimals}`);\r\n }\r\n \r\n // Get token account info\r\n const account = await getAccount(connection, tokenAccount);\r\n console.log(`Raw token amount: ${account.amount.toString()}`);\r\n \r\n // Format balance with correct decimals\r\n return formatAmount(account.amount.toString(), decimals);\r\n } catch (error) {\r\n // Handle case where token account does not exist\r\n if (error instanceof TokenAccountNotFoundError) {\r\n console.log(\"Token account not found, balance is 0\");\r\n return \"0\";\r\n }\r\n console.error(\"Error getting token account:\", error);\r\n return \"0\";\r\n }\r\n } catch (tokenError) {\r\n console.error(\"getBalance: Error setting up token account check:\", tokenError);\r\n return \"0\";\r\n }\r\n } catch (connectionError) {\r\n console.error(\"getBalance: Could not establish connection:\", connectionError);\r\n return \"0\";\r\n }\r\n })(),\r\n timeoutPromise\r\n ]);\r\n } catch (error) {\r\n console.error(\"getBalance: Error getting balance:\", error);\r\n return \"0\";\r\n }\r\n };\r\n\r\n return { executeTrade, getQuote, getBalance };\r\n}", "type": "registry:hook", "target": "hook/murphy/use-JupiterTrade.ts" }, { "path": "config/swap/index.ts", - "content": "import { Config } from \"../../types/swap\";\n\nexport const config: Config = {\n JUPITER_REFERRAL_ACCOUNT: undefined,\n JUPITER_FEE_BPS: 0,\n};\n", + "content": "import { Config } from \"../../types/swap\";\r\n\r\nexport const config: Config = {\r\n JUPITER_REFERRAL_ACCOUNT: undefined,\r\n JUPITER_FEE_BPS: 0,\r\n};\r\n", "type": "registry:file", "target": "config/swap/index.ts" }, { "path": "constants/swap/jupiter-constants.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\n\nexport const JUP_API = \"https://quote-api.jup.ag/v6\";\nexport const JUP_REFERRAL_ADDRESS = \"JUPTRFXx5qe2wMFBtC7c7s6DvS3weDgAZu7Lr4ZKtoQ\";\n\nexport const DEFAULT_OPTIONS = {\n SLIPPAGE_BPS: 50, // 0.5%\n};\n\nexport const TOKENS = {\n SOL: new PublicKey(\"So11111111111111111111111111111111111111112\"),\n USDC: new PublicKey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\"),\n USDT: new PublicKey(\"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\")\n};", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\n\r\nexport const JUP_API = \"https://quote-api.jup.ag/v6\";\r\nexport const JUP_REFERRAL_ADDRESS = \"JUPTRFXx5qe2wMFBtC7c7s6DvS3weDgAZu7Lr4ZKtoQ\";\r\n\r\nexport const DEFAULT_OPTIONS = {\r\n SLIPPAGE_BPS: 50, // 0.5%\r\n};\r\n\r\nexport const TOKENS = {\r\n SOL: new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n USDC: new PublicKey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\"),\r\n USDT: new PublicKey(\"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\")\r\n};", "type": "registry:file", "target": "constants/swap/jupiter-constants.ts" }, { "path": "types/swap/index.ts", - "content": "import { PublicKey, Connection } from \"@solana/web3.js\";\n\nexport interface Config {\n JUPITER_REFERRAL_ACCOUNT?: string;\n JUPITER_FEE_BPS?: number;\n}\n \ndeclare const _default: {\n Config: Config;\n};\n\n\nexport default _default; ", + "content": "import { PublicKey, Connection } from \"@solana/web3.js\";\r\n\r\nexport interface Config {\r\n JUPITER_REFERRAL_ACCOUNT?: string;\r\n JUPITER_FEE_BPS?: number;\r\n}\r\n \r\ndeclare const _default: {\r\n Config: Config;\r\n};\r\n\r\n\r\nexport default _default; ", "type": "registry:file", "target": "types/swap/index.ts" }, { "path": "public/crypto-logos/solana-logo.svg", - "content": "\n\n\n\n\n\t\n\t\n\n\n\n\t\n\t\n\n\n\n\t\n\t\n\n\n\n", + "content": "\r\n\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n", "type": "registry:file", "target": "public/crypto-logos/solana-logo.svg" }, { "path": "public/crypto-logos/usd-coin-usdc-logo.svg", - "content": "\n \n \n \n\n", + "content": "\r\n \r\n \r\n \r\n\r\n", "type": "registry:file", "target": "public/crypto-logos/usd-coin-usdc-logo.svg" }, diff --git a/public/r/token-card.json b/public/r/token-card.json index 8f506e2..2ed1844 100644 --- a/public/r/token-card.json +++ b/public/r/token-card.json @@ -13,19 +13,19 @@ "files": [ { "path": "components/ui/murphy/token-card.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport Link from \"next/link\";\nimport { ExternalLinkIcon } from \"lucide-react\";\n\nimport { formatUsd, shortAddress, cn } from \"@/lib/utils\";\nimport { SolAsset } from \"@/types/assets\";\n\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@/components/ui/card\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\n\nimport { TokenIcon } from \"@/components/ui/murphy/token-icon\";\nimport { Sparkline } from \"@/components/ui/murphy/sparkline\";\nimport { PublicKey } from \"@solana/web3.js\";\n\ntype TokenCardProps = {\n asset: SolAsset | null;\n chartData?: { timestamp: number; price: number }[];\n size?: \"sm\" | \"md\";\n};\n\nconst TokenCard = ({ asset, chartData = [], size = \"md\" }: TokenCardProps) => {\n if (!asset) {\n return (\n \n \n \n Loading...\n \n
\n \n \n
\n
\n Loading...\n
\n \n \n \n
\n );\n }\nconst href= asset.mint instanceof PublicKey ?`https://solscan.io/token/${asset.mint.toBase58()}`:`https://solscan.io/token/${asset}`\n return (\n \n \n \n \n
\n {asset.symbol}\n \n \n {shortAddress(asset.mint)}\n \n
\n \n
\n \n {asset.price && (\n

\n {formatUsd(asset.price)}\n

\n )}\n \n
\n
\n );\n};\n\nexport { TokenCard };\n", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\nimport Link from \"next/link\";\r\nimport { ExternalLinkIcon } from \"lucide-react\";\r\n\r\nimport { formatUsd, shortAddress, cn } from \"@/lib/utils\";\r\nimport { SolAsset } from \"@/types/assets\";\r\n\r\nimport {\r\n Card,\r\n CardContent,\r\n CardDescription,\r\n CardHeader,\r\n CardTitle,\r\n} from \"@/components/ui/card\";\r\nimport { Skeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport { TokenIcon } from \"@/components/ui/murphy/token-icon\";\r\nimport { Sparkline } from \"@/components/ui/murphy/sparkline\";\r\nimport { PublicKey } from \"@solana/web3.js\";\r\n\r\ntype TokenCardProps = {\r\n asset: SolAsset | null;\r\n chartData?: { timestamp: number; price: number }[];\r\n size?: \"sm\" | \"md\";\r\n};\r\n\r\nconst TokenCard = ({ asset, chartData = [], size = \"md\" }: TokenCardProps) => {\r\n if (!asset) {\r\n return (\r\n \r\n \r\n \r\n Loading...\r\n \r\n
\r\n \r\n \r\n
\r\n
\r\n Loading...\r\n
\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\nconst href= asset.mint instanceof PublicKey ?`https://solscan.io/token/${asset.mint.toBase58()}`:`https://solscan.io/token/${asset}`\r\n return (\r\n \r\n \r\n \r\n \r\n
\r\n {asset.symbol}\r\n \r\n \r\n {shortAddress(asset.mint)}\r\n \r\n
\r\n \r\n
\r\n \r\n {asset.price && (\r\n

\r\n {formatUsd(asset.price)}\r\n

\r\n )}\r\n \r\n
\r\n
\r\n );\r\n};\r\n\r\nexport { TokenCard };\r\n", "type": "registry:component", "target": "components/ui/murphy/token-card.tsx" }, { "path": "types/assets/index.ts", - "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\n\nexport type SolAsset = {\n mint: PublicKey;\n name: string;\n symbol: string;\n image: string;\n decimals: number;\n price: number;\n userTokenAccount?: {\n address: PublicKey;\n amount: number;\n };\n};\n\nexport type FetchWalletArgs = {\n owner: PublicKey;\n limit?: number;\n};", + "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\r\n\r\nexport type SolAsset = {\r\n mint: PublicKey;\r\n name: string;\r\n symbol: string;\r\n image: string;\r\n decimals: number;\r\n price: number;\r\n userTokenAccount?: {\r\n address: PublicKey;\r\n amount: number;\r\n };\r\n};\r\n\r\nexport type FetchWalletArgs = {\r\n owner: PublicKey;\r\n limit?: number;\r\n};", "type": "registry:file", "target": "types/assets/index.ts" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" } diff --git a/public/r/token-combobox.json b/public/r/token-combobox.json index a579264..d01c779 100644 --- a/public/r/token-combobox.json +++ b/public/r/token-combobox.json @@ -16,37 +16,37 @@ "files": [ { "path": "components/ui/murphy/token-combobox.tsx", - "content": "\"use client\";\nimport React, { useEffect, useState } from \"react\";\nimport { ChevronsUpDownIcon } from \"lucide-react\";\nimport { Button } from \"../button\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@/components/ui/command\";\nimport { SolAsset } from \"@/types/assets\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { TokenIcon } from \"./token-icon\";\nimport { fetchWalletAssets } from \"@/lib/assets/birdeye/wallets\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\n\ntype TokenComboboxProps = {\n assets?: SolAsset[];\n trigger?: React.ReactNode;\n address?: PublicKey | null;\n showBalances?: boolean;\n onSelect?: (token: SolAsset) => void;\n onSearch?: ({\n query,\n owner,\n }: {\n query: string;\n owner?: PublicKey;\n }) => Promise;\n};\n\nexport function TokenCombobox({\n assets: initialAssets,\n trigger,\n address,\n showBalances = true,\n onSelect,\n onSearch,\n}: TokenComboboxProps) {\n const { publicKey } = useWallet();\n const [open, setOpen] = React.useState(false);\n const [assets, setAssets] = React.useState(initialAssets || []);\n const [value, setValue] = React.useState(\"\");\n const [searchValue, setSearchValue] = React.useState(\"\");\n const [isLoading, setLoading] = useState(false);\n const selectedAsset = React.useMemo(\n () => assets.find((asset) => asset.mint.toBase58().toLowerCase() === value),\n [assets, value],\n );\n\n const fetchData = async () => {\n if (!publicKey) return;\n try {\n setLoading(true);\n\n const fetchedAssets = await fetchWalletAssets({\n owner: publicKey,\n });\n setAssets(fetchedAssets);\n } finally {\n setLoading(false);\n }\n }\n // In case assets array not provided -> fetch from user wallet\n useEffect(() => {\n if (assets.length == 0) {\n fetchData()\n }\n }, []);\n return (\n \n \n {trigger || (\n \n {selectedAsset ? (\n <>\n \n {selectedAsset.symbol}\n \n ) : (\n \"Select token...\"\n )}\n \n \n )}\n \n \n \n \n \n {assets.length === 0 && (\n \n {searchValue ? \"No tokens found.\" : \"Loading...\"}\n \n )}\n \n {assets.map((asset) => (\n {\n setValue(currentValue === value ? \"\" : currentValue);\n setOpen(false);\n if (onSelect) onSelect(asset);\n }}\n className=\"flex items-center gap-2\"\n >\n \n {asset.symbol}\n \n ))}\n \n \n \n \n \n );\n}\n", + "content": "\"use client\";\r\nimport React, { useEffect, useState } from \"react\";\r\nimport { ChevronsUpDownIcon } from \"lucide-react\";\r\nimport { Button } from \"../button\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/ui/popover\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"@/components/ui/command\";\r\nimport { SolAsset } from \"@/types/assets\";\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { TokenIcon } from \"./token-icon\";\r\nimport { fetchWalletAssets } from \"@/lib/assets/birdeye/wallets\";\r\nimport { useWallet } from \"@solana/wallet-adapter-react\";\r\n\r\ntype TokenComboboxProps = {\r\n assets?: SolAsset[];\r\n trigger?: React.ReactNode;\r\n address?: PublicKey | null;\r\n showBalances?: boolean;\r\n onSelect?: (token: SolAsset) => void;\r\n onSearch?: ({\r\n query,\r\n owner,\r\n }: {\r\n query: string;\r\n owner?: PublicKey;\r\n }) => Promise;\r\n};\r\n\r\nexport function TokenCombobox({\r\n assets: initialAssets,\r\n trigger,\r\n address,\r\n showBalances = true,\r\n onSelect,\r\n onSearch,\r\n}: TokenComboboxProps) {\r\n const { publicKey } = useWallet();\r\n const [open, setOpen] = React.useState(false);\r\n const [assets, setAssets] = React.useState(initialAssets || []);\r\n const [value, setValue] = React.useState(\"\");\r\n const [searchValue, setSearchValue] = React.useState(\"\");\r\n const [isLoading, setLoading] = useState(false);\r\n const selectedAsset = React.useMemo(\r\n () => assets.find((asset) => asset.mint.toBase58().toLowerCase() === value),\r\n [assets, value],\r\n );\r\n\r\n const fetchData = async () => {\r\n if (!publicKey) return;\r\n try {\r\n setLoading(true);\r\n\r\n const fetchedAssets = await fetchWalletAssets({\r\n owner: publicKey,\r\n });\r\n setAssets(fetchedAssets);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }\r\n // In case assets array not provided -> fetch from user wallet\r\n useEffect(() => {\r\n if (assets.length == 0) {\r\n fetchData()\r\n }\r\n }, []);\r\n return (\r\n \r\n \r\n {trigger || (\r\n \r\n {selectedAsset ? (\r\n <>\r\n \r\n {selectedAsset.symbol}\r\n \r\n ) : (\r\n \"Select token...\"\r\n )}\r\n \r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n {assets.length === 0 && (\r\n \r\n {searchValue ? \"No tokens found.\" : \"Loading...\"}\r\n \r\n )}\r\n \r\n {assets.map((asset) => (\r\n {\r\n setValue(currentValue === value ? \"\" : currentValue);\r\n setOpen(false);\r\n if (onSelect) onSelect(asset);\r\n }}\r\n className=\"flex items-center gap-2\"\r\n >\r\n \r\n {asset.symbol}\r\n \r\n ))}\r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/token-combobox.tsx" }, { "path": "lib/assets/birdeye/wallets.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { SolAsset, FetchWalletArgs } from \"@/types/assets\";\n\n/* fetch all token addresses of a wallet using bird eye */\nconst fetchWalletAssets = async ({\n owner,\n limit = 20,\n}: FetchWalletArgs): Promise => {\n const headers = {\n \"x-api-key\": process.env.NEXT_PUBLIC_BIRDEYE_API_KEY!,\n accept: \"application/json\",\n \"x-chain\": \"solana\",\n };\n\n try {\n const response = await fetch(\n `https://public-api.birdeye.so/v1/wallet/token_list?wallet=${owner.toString()}`,\n { headers },\n );\n\n const { success, data } = await response.json();\n\n if (!success || !data?.items) {\n return [];\n }\n\n const items = data.items\n .filter((item: { symbol: string }) => item.symbol)\n .map(\n (item: {\n address: string;\n name: string;\n symbol: string;\n icon: string;\n logoURI: string;\n priceUsd: number;\n decimals: number;\n uiAmount: number;\n }) => ({\n mint: new PublicKey(item.address),\n name: item.name,\n symbol: item.symbol,\n image: item.icon || item.logoURI,\n price: item.priceUsd,\n decimals: item.decimals,\n userTokenAccount: {\n address: owner,\n amount: item.uiAmount,\n },\n }),\n );\n\n return items\n .sort((a: SolAsset, b: SolAsset) => {\n const aValue = (a.userTokenAccount?.amount || 0) * (a.price || 0);\n const bValue = (b.userTokenAccount?.amount || 0) * (b.price || 0);\n return bValue - aValue;\n })\n .slice(0, limit);\n } catch (error) {\n console.error(\"Error fetching wallet assets:\", error);\n return [];\n }\n};\n\nexport { fetchWalletAssets };\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { SolAsset, FetchWalletArgs } from \"@/types/assets\";\r\n\r\n/* fetch all token addresses of a wallet using bird eye */\r\nconst fetchWalletAssets = async ({\r\n owner,\r\n limit = 20,\r\n}: FetchWalletArgs): Promise => {\r\n const headers = {\r\n \"x-api-key\": process.env.NEXT_PUBLIC_BIRDEYE_API_KEY!,\r\n accept: \"application/json\",\r\n \"x-chain\": \"solana\",\r\n };\r\n\r\n try {\r\n const response = await fetch(\r\n `https://public-api.birdeye.so/v1/wallet/token_list?wallet=${owner.toString()}`,\r\n { headers },\r\n );\r\n\r\n const { success, data } = await response.json();\r\n\r\n if (!success || !data?.items) {\r\n return [];\r\n }\r\n\r\n const items = data.items\r\n .filter((item: { symbol: string }) => item.symbol)\r\n .map(\r\n (item: {\r\n address: string;\r\n name: string;\r\n symbol: string;\r\n icon: string;\r\n logoURI: string;\r\n priceUsd: number;\r\n decimals: number;\r\n uiAmount: number;\r\n }) => ({\r\n mint: new PublicKey(item.address),\r\n name: item.name,\r\n symbol: item.symbol,\r\n image: item.icon || item.logoURI,\r\n price: item.priceUsd,\r\n decimals: item.decimals,\r\n userTokenAccount: {\r\n address: owner,\r\n amount: item.uiAmount,\r\n },\r\n }),\r\n );\r\n\r\n return items\r\n .sort((a: SolAsset, b: SolAsset) => {\r\n const aValue = (a.userTokenAccount?.amount || 0) * (a.price || 0);\r\n const bValue = (b.userTokenAccount?.amount || 0) * (b.price || 0);\r\n return bValue - aValue;\r\n })\r\n .slice(0, limit);\r\n } catch (error) {\r\n console.error(\"Error fetching wallet assets:\", error);\r\n return [];\r\n }\r\n};\r\n\r\nexport { fetchWalletAssets };\r\n", "type": "registry:file", "target": "lib/assets/birdeye/wallets.ts" }, { "path": "types/assets/index.ts", - "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\n\nexport type SolAsset = {\n mint: PublicKey;\n name: string;\n symbol: string;\n image: string;\n decimals: number;\n price: number;\n userTokenAccount?: {\n address: PublicKey;\n amount: number;\n };\n};\n\nexport type FetchWalletArgs = {\n owner: PublicKey;\n limit?: number;\n};", + "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\r\n\r\nexport type SolAsset = {\r\n mint: PublicKey;\r\n name: string;\r\n symbol: string;\r\n image: string;\r\n decimals: number;\r\n price: number;\r\n userTokenAccount?: {\r\n address: PublicKey;\r\n amount: number;\r\n };\r\n};\r\n\r\nexport type FetchWalletArgs = {\r\n owner: PublicKey;\r\n limit?: number;\r\n};", "type": "registry:file", "target": "types/assets/index.ts" }, { "path": "types/swap/index.ts", - "content": "import { PublicKey, Connection } from \"@solana/web3.js\";\n\nexport interface Config {\n JUPITER_REFERRAL_ACCOUNT?: string;\n JUPITER_FEE_BPS?: number;\n}\n \ndeclare const _default: {\n Config: Config;\n};\n\n\nexport default _default; ", + "content": "import { PublicKey, Connection } from \"@solana/web3.js\";\r\n\r\nexport interface Config {\r\n JUPITER_REFERRAL_ACCOUNT?: string;\r\n JUPITER_FEE_BPS?: number;\r\n}\r\n \r\ndeclare const _default: {\r\n Config: Config;\r\n};\r\n\r\n\r\nexport default _default; ", "type": "registry:file", "target": "types/swap/index.ts" }, { "path": "public/crypto-logos/solana-logo.svg", - "content": "\n\n\n\n\n\t\n\t\n\n\n\n\t\n\t\n\n\n\n\t\n\t\n\n\n\n", + "content": "\r\n\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n", "type": "registry:file", "target": "public/crypto-logos/solana-logo.svg" }, { "path": "public/crypto-logos/usd-coin-usdc-logo.svg", - "content": "\n \n \n \n\n", + "content": "\r\n \r\n \r\n \r\n\r\n", "type": "registry:file", "target": "public/crypto-logos/usd-coin-usdc-logo.svg" }, diff --git a/public/r/token-icon.json b/public/r/token-icon.json index 7c21712..3cd7fd4 100644 --- a/public/r/token-icon.json +++ b/public/r/token-icon.json @@ -6,13 +6,13 @@ "files": [ { "path": "components/ui/murphy/token-icon.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { SolAsset } from \"@/types/assets\";\n\ntype IconProps = {\n asset: SolAsset | null;\n size?: number;\n};\n\nconst TokenIcon = ({ asset, size = 24 }: IconProps) => {\n return (\n \n \n \n );\n};\n\nexport { TokenIcon };", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\nimport { SolAsset } from \"@/types/assets\";\r\n\r\ntype IconProps = {\r\n asset: SolAsset | null;\r\n size?: number;\r\n};\r\n\r\nconst TokenIcon = ({ asset, size = 24 }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport { TokenIcon };", "type": "registry:file", "target": "components/ui/murphy/token-icon.tsx" }, { "path": "types/assets/index.ts", - "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\n\nexport type SolAsset = {\n mint: PublicKey;\n name: string;\n symbol: string;\n image: string;\n decimals: number;\n price: number;\n userTokenAccount?: {\n address: PublicKey;\n amount: number;\n };\n};\n\nexport type FetchWalletArgs = {\n owner: PublicKey;\n limit?: number;\n};", + "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\r\n\r\nexport type SolAsset = {\r\n mint: PublicKey;\r\n name: string;\r\n symbol: string;\r\n image: string;\r\n decimals: number;\r\n price: number;\r\n userTokenAccount?: {\r\n address: PublicKey;\r\n amount: number;\r\n };\r\n};\r\n\r\nexport type FetchWalletArgs = {\r\n owner: PublicKey;\r\n limit?: number;\r\n};", "type": "registry:file", "target": "types/assets/index.ts" } diff --git a/public/r/token-input.json b/public/r/token-input.json index d1a98fd..99bae24 100644 --- a/public/r/token-input.json +++ b/public/r/token-input.json @@ -14,25 +14,25 @@ "files": [ { "path": "components/ui/murphy/token-input.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { WalletIcon } from \"lucide-react\";\n\nimport { formatNumberGrouped, formatNumberShort } from \"@/lib/utils\";\nimport { SolAsset } from \"@/types/assets\";\n\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\n\nimport { TokenCombobox } from \"@/components/ui/murphy/token-combobox\";\n\ntype TokenInputProps = {\n assets: SolAsset[];\n disabled: boolean;\n showWalletBalance?: boolean;\n showQuickAmountButtons?: boolean;\n amount?: number;\n onTokenSelect?: (token: SolAsset) => void;\n onAmountChange?: (amount: number) => void;\n onSearch?: ({\n query,\n owner,\n }: {\n query: string;\n owner?: PublicKey;\n }) => Promise;\n};\n\nexport const TokenInput = React.forwardRef(\n (\n {\n assets,\n disabled = false,\n showWalletBalance = true,\n showQuickAmountButtons = true,\n amount: initAmount = 0,\n onTokenSelect,\n onAmountChange,\n onSearch,\n },\n amountInputRef: React.ForwardedRef,\n ) => {\n const [amount, setAmount] = React.useState(initAmount.toString());\n const [maxAmount, setMaxAmount] = React.useState(0);\n const [selectedToken, setSelectedToken] = React.useState();\n const handleInputChange = React.useCallback(\n (newAmount: string) => {\n let formattedAmount: string = \"\",\n amount: number = 0;\n const newAmountWithoutCommas = newAmount.replace(/,/g, \"\");\n let decimalPart = newAmountWithoutCommas.split(\".\")[1];\n\n if (\n (newAmount.endsWith(\",\") || newAmount.endsWith(\".\")) &&\n !newAmount.substring(0, newAmount.length - 1).includes(\".\")\n ) {\n amount = isNaN(Number.parseFloat(newAmountWithoutCommas))\n ? 0\n : Number.parseFloat(newAmountWithoutCommas);\n formattedAmount = formatNumberGrouped(amount).concat(\".\");\n } else if (selectedToken) {\n const mintDecimals = selectedToken?.decimals;\n const isDecimalPartInvalid = isNaN(Number.parseFloat(decimalPart));\n if (!isDecimalPartInvalid)\n decimalPart = decimalPart.substring(0, mintDecimals);\n decimalPart = isDecimalPartInvalid\n ? \"\"\n : \".\".concat(\n Number.parseFloat(\"1\".concat(decimalPart))\n .toString()\n .substring(1),\n );\n amount = isNaN(Number.parseFloat(newAmountWithoutCommas))\n ? 0\n : Number.parseFloat(newAmountWithoutCommas);\n formattedAmount = formatNumberGrouped(amount)\n .split(\".\")[0]\n .concat(decimalPart);\n }\n\n if (amount > maxAmount) {\n setAmount(formatNumberGrouped(maxAmount));\n if (onAmountChange) onAmountChange(maxAmount);\n } else {\n setAmount(formattedAmount);\n if (onAmountChange) onAmountChange(amount);\n }\n },\n [maxAmount, setAmount, selectedToken, onAmountChange],\n );\n React.useEffect(() => {\n setAmount(initAmount.toString());\n }, [initAmount]);\n return (\n
\n
\n {showWalletBalance && (\n {\n setAmount(formatNumberGrouped(maxAmount));\n }}\n >\n \n {formatNumberShort(maxAmount)}\n \n )}\n {showQuickAmountButtons && (\n <>\n {\n setAmount(formatNumberGrouped(maxAmount / 2));\n onAmountChange && onAmountChange(maxAmount / 2);\n }}\n >\n Half\n \n {\n setAmount(formatNumberGrouped(maxAmount));\n onAmountChange && onAmountChange(maxAmount);\n }}\n >\n Max\n \n \n )}\n
\n
\n {\n setSelectedToken(token);\n setMaxAmount(token?.userTokenAccount?.amount ?? 0);\n setAmount(\"\");\n if (\n amountInputRef &&\n \"current\" in amountInputRef &&\n amountInputRef.current instanceof HTMLInputElement\n ) {\n amountInputRef.current.focus();\n }\n if (onTokenSelect) onTokenSelect(token);\n }}\n onSearch={onSearch}\n />\n handleInputChange(e.target.value)}\n />\n
\n
\n );\n },\n);\n\nTokenInput.displayName = \"TokenInput\";\n", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { WalletIcon } from \"lucide-react\";\r\n\r\nimport { formatNumberGrouped, formatNumberShort } from \"@/lib/utils\";\r\nimport { SolAsset } from \"@/types/assets\";\r\n\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Button } from \"@/components/ui/button\";\r\n\r\nimport { TokenCombobox } from \"@/components/ui/murphy/token-combobox\";\r\n\r\ntype TokenInputProps = {\r\n assets: SolAsset[];\r\n disabled: boolean;\r\n showWalletBalance?: boolean;\r\n showQuickAmountButtons?: boolean;\r\n amount?: number;\r\n onTokenSelect?: (token: SolAsset) => void;\r\n onAmountChange?: (amount: number) => void;\r\n onSearch?: ({\r\n query,\r\n owner,\r\n }: {\r\n query: string;\r\n owner?: PublicKey;\r\n }) => Promise;\r\n};\r\n\r\nexport const TokenInput = React.forwardRef(\r\n (\r\n {\r\n assets,\r\n disabled = false,\r\n showWalletBalance = true,\r\n showQuickAmountButtons = true,\r\n amount: initAmount = 0,\r\n onTokenSelect,\r\n onAmountChange,\r\n onSearch,\r\n },\r\n amountInputRef: React.ForwardedRef,\r\n ) => {\r\n const [amount, setAmount] = React.useState(initAmount.toString());\r\n const [maxAmount, setMaxAmount] = React.useState(0);\r\n const [selectedToken, setSelectedToken] = React.useState();\r\n const handleInputChange = React.useCallback(\r\n (newAmount: string) => {\r\n let formattedAmount: string = \"\",\r\n amount: number = 0;\r\n const newAmountWithoutCommas = newAmount.replace(/,/g, \"\");\r\n let decimalPart = newAmountWithoutCommas.split(\".\")[1];\r\n\r\n if (\r\n (newAmount.endsWith(\",\") || newAmount.endsWith(\".\")) &&\r\n !newAmount.substring(0, newAmount.length - 1).includes(\".\")\r\n ) {\r\n amount = isNaN(Number.parseFloat(newAmountWithoutCommas))\r\n ? 0\r\n : Number.parseFloat(newAmountWithoutCommas);\r\n formattedAmount = formatNumberGrouped(amount).concat(\".\");\r\n } else if (selectedToken) {\r\n const mintDecimals = selectedToken?.decimals;\r\n const isDecimalPartInvalid = isNaN(Number.parseFloat(decimalPart));\r\n if (!isDecimalPartInvalid)\r\n decimalPart = decimalPart.substring(0, mintDecimals);\r\n decimalPart = isDecimalPartInvalid\r\n ? \"\"\r\n : \".\".concat(\r\n Number.parseFloat(\"1\".concat(decimalPart))\r\n .toString()\r\n .substring(1),\r\n );\r\n amount = isNaN(Number.parseFloat(newAmountWithoutCommas))\r\n ? 0\r\n : Number.parseFloat(newAmountWithoutCommas);\r\n formattedAmount = formatNumberGrouped(amount)\r\n .split(\".\")[0]\r\n .concat(decimalPart);\r\n }\r\n\r\n if (amount > maxAmount) {\r\n setAmount(formatNumberGrouped(maxAmount));\r\n if (onAmountChange) onAmountChange(maxAmount);\r\n } else {\r\n setAmount(formattedAmount);\r\n if (onAmountChange) onAmountChange(amount);\r\n }\r\n },\r\n [maxAmount, setAmount, selectedToken, onAmountChange],\r\n );\r\n React.useEffect(() => {\r\n setAmount(initAmount.toString());\r\n }, [initAmount]);\r\n return (\r\n
\r\n
\r\n {showWalletBalance && (\r\n {\r\n setAmount(formatNumberGrouped(maxAmount));\r\n }}\r\n >\r\n \r\n {formatNumberShort(maxAmount)}\r\n \r\n )}\r\n {showQuickAmountButtons && (\r\n <>\r\n {\r\n setAmount(formatNumberGrouped(maxAmount / 2));\r\n onAmountChange && onAmountChange(maxAmount / 2);\r\n }}\r\n >\r\n Half\r\n \r\n {\r\n setAmount(formatNumberGrouped(maxAmount));\r\n onAmountChange && onAmountChange(maxAmount);\r\n }}\r\n >\r\n Max\r\n \r\n \r\n )}\r\n
\r\n
\r\n {\r\n setSelectedToken(token);\r\n setMaxAmount(token?.userTokenAccount?.amount ?? 0);\r\n setAmount(\"\");\r\n if (\r\n amountInputRef &&\r\n \"current\" in amountInputRef &&\r\n amountInputRef.current instanceof HTMLInputElement\r\n ) {\r\n amountInputRef.current.focus();\r\n }\r\n if (onTokenSelect) onTokenSelect(token);\r\n }}\r\n onSearch={onSearch}\r\n />\r\n handleInputChange(e.target.value)}\r\n />\r\n
\r\n
\r\n );\r\n },\r\n);\r\n\r\nTokenInput.displayName = \"TokenInput\";\r\n", "type": "registry:component", "target": "components/ui/murphy/token-input.tsx" }, { "path": "components/ui/murphy/token-combobox.tsx", - "content": "\"use client\";\nimport React, { useEffect, useState } from \"react\";\nimport { ChevronsUpDownIcon } from \"lucide-react\";\nimport { Button } from \"../button\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@/components/ui/command\";\nimport { SolAsset } from \"@/types/assets\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { TokenIcon } from \"./token-icon\";\nimport { fetchWalletAssets } from \"@/lib/assets/birdeye/wallets\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\n\ntype TokenComboboxProps = {\n assets?: SolAsset[];\n trigger?: React.ReactNode;\n address?: PublicKey | null;\n showBalances?: boolean;\n onSelect?: (token: SolAsset) => void;\n onSearch?: ({\n query,\n owner,\n }: {\n query: string;\n owner?: PublicKey;\n }) => Promise;\n};\n\nexport function TokenCombobox({\n assets: initialAssets,\n trigger,\n address,\n showBalances = true,\n onSelect,\n onSearch,\n}: TokenComboboxProps) {\n const { publicKey } = useWallet();\n const [open, setOpen] = React.useState(false);\n const [assets, setAssets] = React.useState(initialAssets || []);\n const [value, setValue] = React.useState(\"\");\n const [searchValue, setSearchValue] = React.useState(\"\");\n const [isLoading, setLoading] = useState(false);\n const selectedAsset = React.useMemo(\n () => assets.find((asset) => asset.mint.toBase58().toLowerCase() === value),\n [assets, value],\n );\n\n const fetchData = async () => {\n if (!publicKey) return;\n try {\n setLoading(true);\n\n const fetchedAssets = await fetchWalletAssets({\n owner: publicKey,\n });\n setAssets(fetchedAssets);\n } finally {\n setLoading(false);\n }\n }\n // In case assets array not provided -> fetch from user wallet\n useEffect(() => {\n if (assets.length == 0) {\n fetchData()\n }\n }, []);\n return (\n \n \n {trigger || (\n \n {selectedAsset ? (\n <>\n \n {selectedAsset.symbol}\n \n ) : (\n \"Select token...\"\n )}\n \n \n )}\n \n \n \n \n \n {assets.length === 0 && (\n \n {searchValue ? \"No tokens found.\" : \"Loading...\"}\n \n )}\n \n {assets.map((asset) => (\n {\n setValue(currentValue === value ? \"\" : currentValue);\n setOpen(false);\n if (onSelect) onSelect(asset);\n }}\n className=\"flex items-center gap-2\"\n >\n \n {asset.symbol}\n \n ))}\n \n \n \n \n \n );\n}\n", + "content": "\"use client\";\r\nimport React, { useEffect, useState } from \"react\";\r\nimport { ChevronsUpDownIcon } from \"lucide-react\";\r\nimport { Button } from \"../button\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/ui/popover\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"@/components/ui/command\";\r\nimport { SolAsset } from \"@/types/assets\";\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { TokenIcon } from \"./token-icon\";\r\nimport { fetchWalletAssets } from \"@/lib/assets/birdeye/wallets\";\r\nimport { useWallet } from \"@solana/wallet-adapter-react\";\r\n\r\ntype TokenComboboxProps = {\r\n assets?: SolAsset[];\r\n trigger?: React.ReactNode;\r\n address?: PublicKey | null;\r\n showBalances?: boolean;\r\n onSelect?: (token: SolAsset) => void;\r\n onSearch?: ({\r\n query,\r\n owner,\r\n }: {\r\n query: string;\r\n owner?: PublicKey;\r\n }) => Promise;\r\n};\r\n\r\nexport function TokenCombobox({\r\n assets: initialAssets,\r\n trigger,\r\n address,\r\n showBalances = true,\r\n onSelect,\r\n onSearch,\r\n}: TokenComboboxProps) {\r\n const { publicKey } = useWallet();\r\n const [open, setOpen] = React.useState(false);\r\n const [assets, setAssets] = React.useState(initialAssets || []);\r\n const [value, setValue] = React.useState(\"\");\r\n const [searchValue, setSearchValue] = React.useState(\"\");\r\n const [isLoading, setLoading] = useState(false);\r\n const selectedAsset = React.useMemo(\r\n () => assets.find((asset) => asset.mint.toBase58().toLowerCase() === value),\r\n [assets, value],\r\n );\r\n\r\n const fetchData = async () => {\r\n if (!publicKey) return;\r\n try {\r\n setLoading(true);\r\n\r\n const fetchedAssets = await fetchWalletAssets({\r\n owner: publicKey,\r\n });\r\n setAssets(fetchedAssets);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }\r\n // In case assets array not provided -> fetch from user wallet\r\n useEffect(() => {\r\n if (assets.length == 0) {\r\n fetchData()\r\n }\r\n }, []);\r\n return (\r\n \r\n \r\n {trigger || (\r\n \r\n {selectedAsset ? (\r\n <>\r\n \r\n {selectedAsset.symbol}\r\n \r\n ) : (\r\n \"Select token...\"\r\n )}\r\n \r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n {assets.length === 0 && (\r\n \r\n {searchValue ? \"No tokens found.\" : \"Loading...\"}\r\n \r\n )}\r\n \r\n {assets.map((asset) => (\r\n {\r\n setValue(currentValue === value ? \"\" : currentValue);\r\n setOpen(false);\r\n if (onSelect) onSelect(asset);\r\n }}\r\n className=\"flex items-center gap-2\"\r\n >\r\n \r\n {asset.symbol}\r\n \r\n ))}\r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n", "type": "registry:component", "target": "components/ui/murphy/token-combobox.tsx" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" }, { "path": "types/swap/index.ts", - "content": "import { PublicKey, Connection } from \"@solana/web3.js\";\n\nexport interface Config {\n JUPITER_REFERRAL_ACCOUNT?: string;\n JUPITER_FEE_BPS?: number;\n}\n \ndeclare const _default: {\n Config: Config;\n};\n\n\nexport default _default; ", + "content": "import { PublicKey, Connection } from \"@solana/web3.js\";\r\n\r\nexport interface Config {\r\n JUPITER_REFERRAL_ACCOUNT?: string;\r\n JUPITER_FEE_BPS?: number;\r\n}\r\n \r\ndeclare const _default: {\r\n Config: Config;\r\n};\r\n\r\n\r\nexport default _default; ", "type": "registry:file", "target": "types/swap/index.ts" } diff --git a/public/r/token-list.json b/public/r/token-list.json index d87701f..4208ac3 100644 --- a/public/r/token-list.json +++ b/public/r/token-list.json @@ -25,37 +25,37 @@ "files": [ { "path": "components/ui/murphy/token-list.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport Link from \"next/link\";\nimport { ExternalLinkIcon } from \"lucide-react\";\n\nimport { shortAddress, formatUsd, formatNumberShort, cn } from \"@/lib/utils\";\nimport { SolAsset } from \"@/types/assets\";\n\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/components/ui/table\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\n\nimport { TokenIcon } from \"./token-icon\";\n\ntype TokenListProps = {\n assets: SolAsset[];\n showBalances?: boolean;\n onClick?: (token: SolAsset) => void;\n};\n\nconst TokenList = ({\n assets,\n showBalances = true,\n onClick,\n}: TokenListProps) => {\n return (\n \n \n \n Token\n Mint\n Price\n {showBalances && Balance}\n {showBalances && Value}\n \n \n \n {assets.length === 0 ? (\n <>\n {[...Array(3)].map((_, index) => (\n \n {[...Array(showBalances ? 5 : 3)].map((_, index) => (\n \n {index === 0 ? (\n
\n \n \n
\n ) : (\n \n )}\n
\n ))}\n
\n ))}\n \n ) : (\n assets.map((asset) => (\n onClick && onClick(asset)}\n >\n \n
\n \n {asset.symbol}\n
\n
\n \n e.stopPropagation()}\n >\n \n {shortAddress(asset.mint.toBase58())}\n \n \n \n \n {formatUsd(asset.price || 0)}\n {showBalances && (\n <>\n \n {asset.userTokenAccount?.amount &&\n formatNumberShort(asset.userTokenAccount.amount)}\n \n \n {asset.userTokenAccount?.amount &&\n formatUsd(\n asset.userTokenAccount.amount * (asset.price || 0),\n )}\n \n \n )}\n \n ))\n )}\n
\n
\n );\n};\n\nexport { TokenList };", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\nimport Link from \"next/link\";\r\nimport { ExternalLinkIcon } from \"lucide-react\";\r\n\r\nimport { shortAddress, formatUsd, formatNumberShort, cn } from \"@/lib/utils\";\r\nimport { SolAsset } from \"@/types/assets\";\r\n\r\nimport {\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableHead,\r\n TableHeader,\r\n TableRow,\r\n} from \"@/components/ui/table\";\r\nimport { Skeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport { TokenIcon } from \"./token-icon\";\r\n\r\ntype TokenListProps = {\r\n assets: SolAsset[];\r\n showBalances?: boolean;\r\n onClick?: (token: SolAsset) => void;\r\n};\r\n\r\nconst TokenList = ({\r\n assets,\r\n showBalances = true,\r\n onClick,\r\n}: TokenListProps) => {\r\n return (\r\n \r\n \r\n \r\n Token\r\n Mint\r\n Price\r\n {showBalances && Balance}\r\n {showBalances && Value}\r\n \r\n \r\n \r\n {assets.length === 0 ? (\r\n <>\r\n {[...Array(3)].map((_, index) => (\r\n \r\n {[...Array(showBalances ? 5 : 3)].map((_, index) => (\r\n \r\n {index === 0 ? (\r\n
\r\n \r\n \r\n
\r\n ) : (\r\n \r\n )}\r\n
\r\n ))}\r\n
\r\n ))}\r\n \r\n ) : (\r\n assets.map((asset) => (\r\n onClick && onClick(asset)}\r\n >\r\n \r\n
\r\n \r\n {asset.symbol}\r\n
\r\n
\r\n \r\n e.stopPropagation()}\r\n >\r\n \r\n {shortAddress(asset.mint.toBase58())}\r\n \r\n \r\n \r\n \r\n {formatUsd(asset.price || 0)}\r\n {showBalances && (\r\n <>\r\n \r\n {asset.userTokenAccount?.amount &&\r\n formatNumberShort(asset.userTokenAccount.amount)}\r\n \r\n \r\n {asset.userTokenAccount?.amount &&\r\n formatUsd(\r\n asset.userTokenAccount.amount * (asset.price || 0),\r\n )}\r\n \r\n \r\n )}\r\n \r\n ))\r\n )}\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport { TokenList };", "type": "registry:component", "target": "components/ui/murphy/token-list.tsx" }, { "path": "types/assets/index.ts", - "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\n\nexport type SolAsset = {\n mint: PublicKey;\n name: string;\n symbol: string;\n image: string;\n decimals: number;\n price: number;\n userTokenAccount?: {\n address: PublicKey;\n amount: number;\n };\n};\n\nexport type FetchWalletArgs = {\n owner: PublicKey;\n limit?: number;\n};", + "content": "import { PublicKey,Connection } from \"@solana/web3.js\";\r\n\r\nexport type SolAsset = {\r\n mint: PublicKey;\r\n name: string;\r\n symbol: string;\r\n image: string;\r\n decimals: number;\r\n price: number;\r\n userTokenAccount?: {\r\n address: PublicKey;\r\n amount: number;\r\n };\r\n};\r\n\r\nexport type FetchWalletArgs = {\r\n owner: PublicKey;\r\n limit?: number;\r\n};", "type": "registry:file", "target": "types/assets/index.ts" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" }, { "path": "components/ui/murphy/token-icon.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { SolAsset } from \"@/types/assets\";\n\ntype IconProps = {\n asset: SolAsset | null;\n size?: number;\n};\n\nconst TokenIcon = ({ asset, size = 24 }: IconProps) => {\n return (\n \n \n \n );\n};\n\nexport { TokenIcon };", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\nimport { SolAsset } from \"@/types/assets\";\r\n\r\ntype IconProps = {\r\n asset: SolAsset | null;\r\n size?: number;\r\n};\r\n\r\nconst TokenIcon = ({ asset, size = 24 }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport { TokenIcon };", "type": "registry:file", "target": "components/ui/murphy/token-icon.tsx" }, { "path": "public/crypto-logos/solana-logo.svg", - "content": "\n\n\n\n\n\t\n\t\n\n\n\n\t\n\t\n\n\n\n\t\n\t\n\n\n\n", + "content": "\r\n\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n\t\r\n\t\r\n\r\n\r\n\r\n", "type": "registry:file", "target": "public/crypto-logos/solana-logo.svg" }, { "path": "public/crypto-logos/usd-coin-usdc-logo.svg", - "content": "\n \n \n \n\n", + "content": "\r\n \r\n \r\n \r\n\r\n", "type": "registry:file", "target": "public/crypto-logos/usd-coin-usdc-logo.svg" }, diff --git a/public/r/txn-error-fallback.json b/public/r/txn-error-fallback.json new file mode 100644 index 0000000..aa0c5b9 --- /dev/null +++ b/public/r/txn-error-fallback.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "txn-error-fallback", + "type": "registry:block", + "title": "Fallback UI for failed transactions with retry and log support.", + "dependencies": [], + "registryDependencies": [ + "button" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx", + "content": "\"use client\"\r\n\r\nimport { AlertTriangle, RefreshCw, Copy, ExternalLink } from \"lucide-react\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from \"@/components/ui/card\"\r\nimport { Badge } from \"@/components/ui/badge\"\r\nimport { useState } from \"react\"\r\n\r\ninterface TxnErrorFallbackProps {\r\n error: string\r\n signature?: string\r\n onRetry?: () => void\r\n onClose?: () => void\r\n showLogs?: boolean\r\n logs?: string[]\r\n}\r\n\r\nexport function TxnErrorFallback({\r\n error,\r\n signature,\r\n onRetry,\r\n onClose,\r\n showLogs = false,\r\n logs = [],\r\n}: TxnErrorFallbackProps) {\r\n const [copied, setCopied] = useState(false)\r\n\r\n const copyError = async () => {\r\n await navigator.clipboard.writeText(error)\r\n setCopied(true)\r\n setTimeout(() => setCopied(false), 2000)\r\n }\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n
\r\n Transaction Failed\r\n Your transaction could not be completed\r\n
\r\n\r\n \r\n
\r\n
\r\n

{error}

\r\n \r\n \r\n \r\n
\r\n {copied && (\r\n \r\n Copied to clipboard\r\n \r\n )}\r\n
\r\n\r\n {signature && (\r\n
\r\n
\r\n

Transaction Signature

\r\n

\r\n {signature.slice(0, 8)}...{signature.slice(-8)}\r\n

\r\n
\r\n window.open(`https://explorer.solana.com/tx/${signature}`, \"_blank\")}\r\n >\r\n \r\n \r\n
\r\n )}\r\n\r\n {showLogs && logs.length > 0 && (\r\n
\r\n \r\n View Transaction Logs\r\n \r\n
\r\n {logs.map((log, index) => (\r\n

\r\n {log}\r\n

\r\n ))}\r\n
\r\n
\r\n )}\r\n
\r\n\r\n \r\n {onRetry && (\r\n \r\n )}\r\n \r\n \r\n
\r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/txn-explorer-link.json b/public/r/txn-explorer-link.json new file mode 100644 index 0000000..bc12053 --- /dev/null +++ b/public/r/txn-explorer-link.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "txn-explorer-link", + "type": "registry:block", + "title": "A link to open a transaction on Solana Explorer.", + "dependencies": [], + "registryDependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx", + "content": "\"use client\"\r\n\r\nimport type React from \"react\"\r\nimport { ExternalLink } from \"lucide-react\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\ninterface TxnExplorerLinkProps {\r\n signature: string\r\n cluster?: \"mainnet-beta\" | \"testnet\" | \"devnet\"\r\n children?: React.ReactNode\r\n className?: string\r\n variant?: \"default\" | \"destructive\" | \"outline\" | \"secondary\" | \"ghost\" | \"link\"\r\n size?: \"default\" | \"sm\" | \"lg\" | \"icon\"\r\n showIcon?: boolean\r\n}\r\n\r\nexport function TxnExplorerLink({\r\n signature,\r\n cluster = \"mainnet-beta\",\r\n children,\r\n className,\r\n variant = \"outline\",\r\n size = \"sm\",\r\n showIcon = true,\r\n}: TxnExplorerLinkProps) {\r\n const getExplorerUrl = () => {\r\n const baseUrl = \"https://explorer.solana.com/tx\"\r\n const clusterParam = cluster !== \"mainnet-beta\" ? `?cluster=${cluster}` : \"\"\r\n return `${baseUrl}/${signature}${clusterParam}`\r\n }\r\n\r\n const handleClick = () => {\r\n window.open(getExplorerUrl(), \"_blank\", \"noopener,noreferrer\")\r\n }\r\n\r\n return (\r\n \r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/txn-feedback-toast.json b/public/r/txn-feedback-toast.json new file mode 100644 index 0000000..9ef0644 --- /dev/null +++ b/public/r/txn-feedback-toast.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "txn-feedback-toast", + "type": "registry:block", + "title": "Toast component to display transaction status (loading, success, error).", + "dependencies": [ + "sonner" + ], + "registryDependencies": [ + "toast" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx", + "content": "\"use client\"\r\n\r\nimport { useEffect, useState } from \"react\"\r\nimport { CheckCircle, XCircle, Loader2, AlertCircle } from \"lucide-react\"\r\nimport { cn } from \"@/lib/utils\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport type { TxnFeedbackProps } from \"@/types/transaction\"\r\n\r\nexport function TxnFeedbackToast({ status, onRetry, onClose }: TxnFeedbackProps) {\r\n const [isVisible, setIsVisible] = useState(false)\r\n\r\n useEffect(() => {\r\n if (status.status !== \"idle\") {\r\n setIsVisible(true)\r\n }\r\n }, [status.status])\r\n\r\n useEffect(() => {\r\n if (status.status === \"success\") {\r\n const timer = setTimeout(() => {\r\n setIsVisible(false)\r\n onClose?.()\r\n }, 5000)\r\n return () => clearTimeout(timer)\r\n }\r\n }, [status.status, onClose])\r\n\r\n if (!isVisible || status.status === \"idle\") return null\r\n\r\n const getIcon = () => {\r\n switch (status.status) {\r\n case \"success\":\r\n return \r\n case \"error\":\r\n return \r\n case \"preparing\":\r\n case \"signing\":\r\n case \"sending\":\r\n case \"confirming\":\r\n return \r\n default:\r\n return \r\n }\r\n }\r\n\r\n const getMessage = () => {\r\n switch (status.status) {\r\n case \"preparing\":\r\n return \"Preparing transaction...\"\r\n case \"signing\":\r\n return \"Please sign the transaction\"\r\n case \"sending\":\r\n return \"Sending transaction...\"\r\n case \"confirming\":\r\n return \"Confirming transaction...\"\r\n case \"success\":\r\n return \"Transaction successful!\"\r\n case \"error\":\r\n return status.error || \"Transaction failed\"\r\n default:\r\n return \"Processing...\"\r\n }\r\n }\r\n\r\n const getBgColor = () => {\r\n switch (status.status) {\r\n case \"success\":\r\n return \"bg-green-50 border-green-200\"\r\n case \"error\":\r\n return \"bg-red-50 border-red-200\"\r\n default:\r\n return \"bg-blue-50 border-blue-200\"\r\n }\r\n }\r\n\r\n return (\r\n \r\n
\r\n
\r\n {getIcon()}\r\n
\r\n

{getMessage()}

\r\n {status.signature && (\r\n

\r\n Signature: {status.signature.slice(0, 8)}...{status.signature.slice(-8)}\r\n

\r\n )}\r\n
\r\n
\r\n {status.status === \"error\" && onRetry && (\r\n \r\n )}\r\n {\r\n setIsVisible(false)\r\n onClose?.()\r\n }}\r\n className=\"text-xs\"\r\n >\r\n ×\r\n \r\n
\r\n
\r\n
\r\n \r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/txn-list.json b/public/r/txn-list.json index e8fb82b..0736e3a 100644 --- a/public/r/txn-list.json +++ b/public/r/txn-list.json @@ -15,13 +15,13 @@ "files": [ { "path": "components/ui/murphy/txn-list.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport Link from \"next/link\";\n\nimport {\n VersionedTransactionResponse,\n LAMPORTS_PER_SOL,\n} from \"@solana/web3.js\";\n\nimport { useConnection } from \"@solana/wallet-adapter-react\";\nimport { formatDistanceToNow } from \"date-fns\";\nimport { AlertCircleIcon, ExternalLinkIcon } from \"lucide-react\";\n\nimport { shortAddress, cn } from \"@/lib/utils\";\n\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/components/ui/table\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\n\ntype TxnListProps = {\n transactions: VersionedTransactionResponse[];\n onClick?: (txn: VersionedTransactionResponse) => void;\n};\n\nconst TxnList = ({ transactions, onClick }: TxnListProps) => {\n const { connection } = useConnection();\n const [currentSlot, setCurrentSlot] = React.useState(null);\n const [averageBlockTime, setAverageBlockTime] = React.useState(0.4);\n React.useEffect(() => {\n console.log(\"transactions: \",transactions)\n},[transactions])\n React.useEffect(() => {\n const init = async () => {\n try {\n const [slot, recentPerformanceSamples] = await Promise.all([\n connection.getSlot(),\n connection.getRecentPerformanceSamples(30),\n ]);\n const totalSampleSeconds = recentPerformanceSamples.reduce(\n (acc, sample) => acc + sample.samplePeriodSecs,\n 0,\n );\n\n const totalSamples = recentPerformanceSamples.reduce(\n (acc, sample) => acc + sample.numSlots,\n 0,\n );\n const calculatedAverageBlockTime = totalSampleSeconds / totalSamples;\n setCurrentSlot(slot);\n setAverageBlockTime(calculatedAverageBlockTime);\n } catch (error) {\n console.error(\"Error fetching block time:\", error);\n }\n };\n if (!connection) return;\n init();\n }, [connection]);\n const estimateTimestamp = (blockTime: number | null | undefined) => {\n if (blockTime == null || blockTime == undefined || currentSlot === null) {\n return \"Unknown\";\n }\n const currentTime = Date.now() / 1000;\n const blockDifference = currentSlot - blockTime;\n const estimatedTimestamp = currentTime - blockDifference * averageBlockTime;\n return formatDistanceToNow(new Date(estimatedTimestamp * 1000), {\n addSuffix: true,\n });\n };\n return (\n \n \n \n Signature\n Block\n Time\n By\n Fee\n \n \n \n {transactions?.length === 0 ? (\n <>\n {[...Array(5)].map((_, index) => (\n \n {[...Array(5)].map((_, index) => (\n \n \n \n ))}\n \n ))}\n \n ) : (\n transactions?.length && transactions.map((txn) => (\n onClick && onClick(txn)}\n >\n \n e.stopPropagation()}\n >\n \n \n {shortAddress(txn.transaction.signatures[0])}\n \n {txn.meta?.err && (\n \n )}\n \n \n {txn.blockTime}\n {estimateTimestamp(txn.slot)}\n \n e.stopPropagation()}\n >\n \n \n {shortAddress(txn.transaction.message.staticAccountKeys[0])}\n \n \n \n {(txn.meta?.fee || 0) / LAMPORTS_PER_SOL}\n \n ))\n )}\n \n
\n );\n};\n\nexport default TxnList;", + "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\nimport Link from \"next/link\";\r\n\r\nimport {\r\n VersionedTransactionResponse,\r\n LAMPORTS_PER_SOL,\r\n} from \"@solana/web3.js\";\r\n\r\nimport { useConnection } from \"@solana/wallet-adapter-react\";\r\nimport { formatDistanceToNow } from \"date-fns\";\r\nimport { AlertCircleIcon, ExternalLinkIcon } from \"lucide-react\";\r\n\r\nimport { shortAddress, cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableHead,\r\n TableHeader,\r\n TableRow,\r\n} from \"@/components/ui/table\";\r\nimport { Skeleton } from \"@/components/ui/skeleton\";\r\n\r\ntype TxnListProps = {\r\n transactions: VersionedTransactionResponse[];\r\n onClick?: (txn: VersionedTransactionResponse) => void;\r\n};\r\n\r\nconst TxnList = ({ transactions, onClick }: TxnListProps) => {\r\n const { connection } = useConnection();\r\n const [currentSlot, setCurrentSlot] = React.useState(null);\r\n const [averageBlockTime, setAverageBlockTime] = React.useState(0.4);\r\n React.useEffect(() => {\r\n console.log(\"transactions: \",transactions)\r\n},[transactions])\r\n React.useEffect(() => {\r\n const init = async () => {\r\n try {\r\n const [slot, recentPerformanceSamples] = await Promise.all([\r\n connection.getSlot(),\r\n connection.getRecentPerformanceSamples(30),\r\n ]);\r\n const totalSampleSeconds = recentPerformanceSamples.reduce(\r\n (acc, sample) => acc + sample.samplePeriodSecs,\r\n 0,\r\n );\r\n\r\n const totalSamples = recentPerformanceSamples.reduce(\r\n (acc, sample) => acc + sample.numSlots,\r\n 0,\r\n );\r\n const calculatedAverageBlockTime = totalSampleSeconds / totalSamples;\r\n setCurrentSlot(slot);\r\n setAverageBlockTime(calculatedAverageBlockTime);\r\n } catch (error) {\r\n console.error(\"Error fetching block time:\", error);\r\n }\r\n };\r\n if (!connection) return;\r\n init();\r\n }, [connection]);\r\n const estimateTimestamp = (blockTime: number | null | undefined) => {\r\n if (blockTime == null || blockTime == undefined || currentSlot === null) {\r\n return \"Unknown\";\r\n }\r\n const currentTime = Date.now() / 1000;\r\n const blockDifference = currentSlot - blockTime;\r\n const estimatedTimestamp = currentTime - blockDifference * averageBlockTime;\r\n return formatDistanceToNow(new Date(estimatedTimestamp * 1000), {\r\n addSuffix: true,\r\n });\r\n };\r\n return (\r\n \r\n \r\n \r\n Signature\r\n Block\r\n Time\r\n By\r\n Fee\r\n \r\n \r\n \r\n {transactions?.length === 0 ? (\r\n <>\r\n {[...Array(5)].map((_, index) => (\r\n \r\n {[...Array(5)].map((_, index) => (\r\n \r\n \r\n \r\n ))}\r\n \r\n ))}\r\n \r\n ) : (\r\n transactions?.length && transactions.map((txn) => (\r\n onClick && onClick(txn)}\r\n >\r\n \r\n e.stopPropagation()}\r\n >\r\n \r\n \r\n {shortAddress(txn.transaction.signatures[0])}\r\n \r\n {txn.meta?.err && (\r\n \r\n )}\r\n \r\n \r\n {txn.blockTime}\r\n {estimateTimestamp(txn.slot)}\r\n \r\n e.stopPropagation()}\r\n >\r\n \r\n \r\n {shortAddress(txn.transaction.message.staticAccountKeys[0])}\r\n \r\n \r\n \r\n {(txn.meta?.fee || 0) / LAMPORTS_PER_SOL}\r\n \r\n ))\r\n )}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default TxnList;", "type": "registry:file", "target": "components/ui/murphy/txn-list.tsx" }, { "path": "lib/utils.ts", - "content": "import { PublicKey } from \"@solana/web3.js\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport millify from \"millify\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const shortAddress = (address: PublicKey | string) => {\n const key = typeof address === \"string\" ? address : address.toBase58();\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n};\n\nexport const formatUsd = (num: number): string => {\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\n};\n\nexport const formatNumber = (\n num: number,\n options: Intl.NumberFormatOptions = {},\n): string => {\n if (num === null || num === undefined) return \"0\";\n\n const absNum = Math.abs(num);\n let decimals = 2;\n\n if (absNum < 1) {\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\n }\n\n return new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: 2,\n maximumFractionDigits: decimals,\n ...options,\n }).format(num);\n};\n\nexport const formatNumberShort = (num: number): string => {\n if (num < 1000) return formatNumber(num);\n return millify(num, {\n precision: 2,\n });\n};\n\nexport const formatNumberGrouped = (\n value: number,\n expThreshold: number = 0.0001,\n expPrecision: number = 1,\n) => {\n if (value === 0) return \"0\";\n\n if (Math.abs(value) < expThreshold) {\n return value.toExponential(expPrecision);\n }\n\n if (Number.isInteger(value)) {\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\n }\n\n const valueParts = value.toString().split(\".\");\n const decimalPart = valueParts[1] ?? \"\";\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\n\n return new Intl.NumberFormat(\"en-US\", {\n useGrouping: true,\n minimumFractionDigits: minimumFractionDigits,\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\n }).format(value);\n};\n\nexport const validatePublicKey = (address: PublicKey | string) => {\n try {\n if (typeof address == \"string\") {\n new PublicKey(address);\n } else {\n address.toBase58();\n }\n return true;\n } catch (error) {\n return false;\n\n }\n};\n", + "content": "import { PublicKey } from \"@solana/web3.js\";\r\nimport { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport millify from \"millify\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport const shortAddress = (address: PublicKey | string) => {\r\n const key = typeof address === \"string\" ? address : address.toBase58();\r\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\r\n};\r\n\r\nexport const formatUsd = (num: number): string => {\r\n return formatNumber(num, { style: \"currency\", currency: \"USD\" });\r\n};\r\n\r\nexport const formatNumber = (\r\n num: number,\r\n options: Intl.NumberFormatOptions = {},\r\n): string => {\r\n if (num === null || num === undefined) return \"0\";\r\n\r\n const absNum = Math.abs(num);\r\n let decimals = 2;\r\n\r\n if (absNum < 1) {\r\n decimals = Math.max(2, Math.min(20, Math.ceil(-Math.log10(absNum)) + 2));\r\n }\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: decimals,\r\n ...options,\r\n }).format(num);\r\n};\r\n\r\nexport const formatNumberShort = (num: number): string => {\r\n if (num < 1000) return formatNumber(num);\r\n return millify(num, {\r\n precision: 2,\r\n });\r\n};\r\n\r\nexport const formatNumberGrouped = (\r\n value: number,\r\n expThreshold: number = 0.0001,\r\n expPrecision: number = 1,\r\n) => {\r\n if (value === 0) return \"0\";\r\n\r\n if (Math.abs(value) < expThreshold) {\r\n return value.toExponential(expPrecision);\r\n }\r\n\r\n if (Number.isInteger(value)) {\r\n return new Intl.NumberFormat(\"en-US\", { useGrouping: true }).format(value);\r\n }\r\n\r\n const valueParts = value.toString().split(\".\");\r\n const decimalPart = valueParts[1] ?? \"\";\r\n const leadingZeros = decimalPart.match(/^0*/)?.[0].length ?? 0;\r\n const minimumFractionDigits = leadingZeros > 0 ? leadingZeros + 1 : 2;\r\n\r\n return new Intl.NumberFormat(\"en-US\", {\r\n useGrouping: true,\r\n minimumFractionDigits: minimumFractionDigits,\r\n maximumFractionDigits: Math.max(2, minimumFractionDigits),\r\n }).format(value);\r\n};\r\n\r\nexport const validatePublicKey = (address: PublicKey | string) => {\r\n try {\r\n if (typeof address == \"string\") {\r\n new PublicKey(address);\r\n } else {\r\n address.toBase58();\r\n }\r\n return true;\r\n } catch (error) {\r\n return false;\r\n\r\n }\r\n};\r\n", "type": "registry:file", "target": "lib/utils.ts" } diff --git a/public/r/txn-pending-indicator.json b/public/r/txn-pending-indicator.json new file mode 100644 index 0000000..b686ac6 --- /dev/null +++ b/public/r/txn-pending-indicator.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "txn-pending-indicator", + "type": "registry:block", + "title": "Global indicator showing pending transactions in the UI.", + "dependencies": [], + "registryDependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx", + "content": "\"use client\"\r\n\r\nimport { useState, useEffect } from \"react\"\r\nimport { Loader2, X } from \"lucide-react\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { Badge } from \"@/components/ui/badge\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\ninterface PendingTransaction {\r\n id: string\r\n signature?: string\r\n description: string\r\n startTime: number\r\n}\r\n\r\ninterface TxnPendingIndicatorProps {\r\n transactions: PendingTransaction[]\r\n onCancel?: (id: string) => void\r\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\"\r\n className?: string\r\n}\r\n\r\nexport function TxnPendingIndicator({\r\n transactions,\r\n onCancel,\r\n position = \"bottom-right\",\r\n className,\r\n}: TxnPendingIndicatorProps) {\r\n const [isExpanded, setIsExpanded] = useState(false)\r\n\r\n useEffect(() => {\r\n if (transactions.length === 0) {\r\n setIsExpanded(false)\r\n }\r\n }, [transactions.length])\r\n\r\n if (transactions.length === 0) return null\r\n\r\n const positionClasses = {\r\n \"top-left\": \"top-4 left-4\",\r\n \"top-right\": \"top-4 right-4\",\r\n \"bottom-left\": \"bottom-4 left-4\",\r\n \"bottom-right\": \"bottom-4 right-4\",\r\n }\r\n\r\n const getElapsedTime = (startTime: number) => {\r\n const elapsed = Math.floor((Date.now() - startTime) / 1000)\r\n if (elapsed < 60) return `${elapsed}s`\r\n return `${Math.floor(elapsed / 60)}m ${elapsed % 60}s`\r\n }\r\n\r\n return (\r\n
\r\n {!isExpanded ? (\r\n \r\n ) : (\r\n
\r\n
\r\n

Pending Transactions

\r\n \r\n
\r\n\r\n
\r\n {transactions.map((tx) => (\r\n
\r\n
\r\n \r\n
\r\n

{tx.description}

\r\n

{getElapsedTime(tx.startTime)}

\r\n
\r\n
\r\n {onCancel && (\r\n onCancel(tx.id)}\r\n className=\"h-6 w-6 p-0 ml-2 flex-shrink-0\"\r\n >\r\n \r\n \r\n )}\r\n
\r\n ))}\r\n
\r\n
\r\n )}\r\n
\r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/txn-progress-steps.json b/public/r/txn-progress-steps.json new file mode 100644 index 0000000..5902704 --- /dev/null +++ b/public/r/txn-progress-steps.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "txn-progress-steps", + "type": "registry:block", + "title": "A visual step tracker for multi-step transaction workflows.", + "dependencies": [], + "registryDependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx", + "content": "\"use client\"\r\n\r\nimport { Check, Loader2, X } from \"lucide-react\"\r\nimport { cn } from \"@/lib/utils\"\r\nimport type { TxnStep } from \"@/types/transaction\"\r\n\r\ninterface TxnProgressStepsProps {\r\n steps: TxnStep[]\r\n orientation?: \"horizontal\" | \"vertical\"\r\n className?: string\r\n}\r\n\r\nexport function TxnProgressSteps({ steps, orientation = \"horizontal\", className }: TxnProgressStepsProps) {\r\n const isVertical = orientation === \"vertical\"\r\n\r\n return (\r\n
\r\n {steps.map((step, index) => (\r\n
\r\n \r\n {step.status === \"completed\" && }\r\n {step.status === \"active\" && }\r\n {step.status === \"error\" && }\r\n {step.status === \"pending\" && {index + 1}}\r\n
\r\n\r\n
\r\n \r\n {step.title}\r\n
\r\n {step.description &&
{step.description}
}\r\n
\r\n\r\n {!isVertical && index < steps.length - 1 &&
}\r\n
\r\n ))}\r\n \r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/txn-retry-button.json b/public/r/txn-retry-button.json new file mode 100644 index 0000000..83dc1aa --- /dev/null +++ b/public/r/txn-retry-button.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "txn-retry-button", + "type": "registry:block", + "title": "A button component with built-in retry handling for transactions.", + "dependencies": [], + "registryDependencies": [ + "button" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-retry-button.tsx", + "content": "\"use client\"\r\n\r\nimport type React from \"react\"\r\nimport { useState } from \"react\"\r\nimport { RefreshCw } from \"lucide-react\"\r\nimport { Button } from \"@/components/ui/button\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\ninterface TxnRetryButtonProps {\r\n onRetry: () => Promise | void\r\n disabled?: boolean\r\n maxRetries?: number\r\n retryDelay?: number\r\n children?: React.ReactNode\r\n className?: string\r\n variant?: \"default\" | \"destructive\" | \"outline\" | \"secondary\" | \"ghost\" | \"link\"\r\n size?: \"default\" | \"sm\" | \"lg\" | \"icon\"\r\n}\r\n\r\nexport function TxnRetryButton({\r\n onRetry,\r\n disabled = false,\r\n maxRetries = 3,\r\n retryDelay = 1000,\r\n children = \"Retry\",\r\n className,\r\n variant = \"default\",\r\n size = \"default\",\r\n}: TxnRetryButtonProps) {\r\n const [isRetrying, setIsRetrying] = useState(false)\r\n const [retryCount, setRetryCount] = useState(0)\r\n\r\n const handleRetry = async () => {\r\n if (retryCount >= maxRetries || isRetrying) return\r\n\r\n setIsRetrying(true)\r\n\r\n try {\r\n await new Promise((resolve) => setTimeout(resolve, retryDelay))\r\n await onRetry()\r\n setRetryCount(0)\r\n } catch (error) {\r\n setRetryCount((prev) => prev + 1)\r\n console.error(\"Retry failed:\", error)\r\n } finally {\r\n setIsRetrying(false)\r\n }\r\n }\r\n\r\n const isDisabled = disabled || isRetrying || retryCount >= maxRetries\r\n\r\n return (\r\n \r\n )\r\n}\r\n", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-retry-button.tsx" + } + ] +} \ No newline at end of file diff --git a/public/r/txn-settings.json b/public/r/txn-settings.json index 9ac6357..cf017b7 100644 --- a/public/r/txn-settings.json +++ b/public/r/txn-settings.json @@ -15,7 +15,7 @@ "files": [ { "path": "components/ui/murphy/txn-settings.tsx", - "content": "\"use client\";\nimport React from \"react\";\n\nimport { SettingsIcon } from \"lucide-react\";\nimport {\n Dialog,\n DialogContent,\n DialogTrigger,\n DialogHeader,\n DialogTitle,\n DialogFooter,\n DialogClose,\n} from \"@/components/ui/dialog\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { ToggleGroup, ToggleGroupItem } from \"@/components/ui/toggle-group\";\ntype TxnSettingsType = {\n priority: string;\n priorityFeeCap: \"dynamic\" | number;\n slippageMode: \"dynamic\" | \"fixed\";\n slippageValue: number;\n};\n\ntype TxnSettingsContextType = {\n settings: TxnSettingsType;\n updateSettings: (newSettings: Partial) => void;\n isOpen: boolean;\n setIsOpen: (isOpen: boolean) => void;\n};\n\nconst TxnSettingsContext = React.createContext<\n TxnSettingsContextType | undefined\n>(undefined);\n\nconst TxnSettingsProvider: React.FC<{\n children: React.ReactNode;\n}> = ({ children }) => {\n const [isOpen, setIsOpen] = React.useState(false);\n const [settings, setSettings] = React.useState({\n priority: \"normal\",\n priorityFeeCap: \"dynamic\",\n slippageMode: \"dynamic\",\n slippageValue: 1.0,\n });\n\n const updateSettings = (newSettings: Partial) => {\n setSettings((prevSettings) => ({ ...prevSettings, ...newSettings }));\n };\n\n return (\n \n {children}\n \n );\n};\n\nconst useTxnSettings = () => {\n const context = React.useContext(TxnSettingsContext);\n if (context === undefined) {\n throw new Error(\"useTxnSettings must be used within a TxnSettingsProvider\");\n }\n return context;\n};\n\ntype TxnSettingsProps = {\n trigger?: React.ReactNode;\n};\nconst TxnSettings = ({ trigger }: TxnSettingsProps) => {\n const { settings, updateSettings, isOpen, setIsOpen } = useTxnSettings();\n const [tempSettings, setTempSettings] =\n React.useState(settings);\n const [manualFee, setManualFee] = React.useState(\"\");\n const [manualSlippage, setManualSlippage] = React.useState(\"\");\n\n React.useEffect(() => {\n if (isOpen) {\n setTempSettings(settings);\n }\n }, [isOpen, settings]);\n \n const handleSave = () => {\n updateSettings(tempSettings);\n setIsOpen(false);\n };\n\n const handleCancel = () => {\n setTempSettings(settings);\n setIsOpen(false);\n };\n\n const handleSlippagePresetChange = (value: string) => {\n const slippageMap: Record = {\n low: 0.5,\n normal: 1.0,\n high: 1.5,\n };\n\n setTempSettings((prev) => ({\n ...prev,\n slippageValue: slippageMap[value] || prev.slippageValue,\n }));\n };\n return (\n \n \n {trigger || (\n \n )}\n \n \n \n Transaction Settings\n \n {\n e.preventDefault();\n handleSave();\n }}\n >\n
\n
\n

Priority fee

\n

\n Set the priority fee for your transactions.\n

\n
\n \n setTempSettings((prev) => ({ ...prev, priority: value }))\n }\n >\n Normal\n Medium\n Turbo\n \n
\n
\n
\n

Priority fee cap

\n

\n Set the priority fee cap for your transactions.\n

\n
\n {\n if (value === \"dynamic\") {\n setTempSettings((prev) => ({\n ...prev,\n priorityFeeCap: \"dynamic\",\n }));\n } else if (value === \"manual\") {\n setTempSettings((prev) => ({ ...prev, priorityFeeCap: 0 }));\n }\n }}\n >\n Manual\n Dynamic\n \n {tempSettings.priorityFeeCap !== \"dynamic\" && (\n {\n const value = e.target.value;\n setManualFee(value);\n const numValue = parseFloat(value);\n if (!isNaN(numValue)) {\n setTempSettings((prev) => ({\n ...prev,\n priorityFeeCap: numValue,\n }));\n }\n }}\n className=\"mt-2\"\n />\n )}\n
\n
\n
\n

Slippage mode

\n

\n Set a fixed slippage or let us calculate optimal slippage for\n you.\n

\n
\n {\n if (value) {\n setTempSettings((prev) => ({\n ...prev,\n slippageMode: value as \"dynamic\" | \"fixed\",\n }));\n }\n }}\n >\n Dynamic\n Fixed\n \n\n {tempSettings.slippageMode === \"fixed\" && (\n
\n {\n if (value && value !== \"custom\") {\n handleSlippagePresetChange(value);\n }\n }}\n >\n \n
\n Low\n 0.5 %\n
\n
\n \n
\n Normal\n 1 %\n
\n \n \n
\n High\n 1.5 %\n
\n
\n \n\n
\n

Or set manually

\n
\n {\n const value = e.target.value;\n setManualSlippage(value);\n const numValue = parseFloat(value);\n if (!isNaN(numValue)) {\n setTempSettings((prev) => ({\n ...prev,\n slippageValue: numValue,\n }));\n }\n }}\n className=\"pr-8\"\n />\n \n %\n \n
\n
\n
\n )}\n
\n \n \n \n \n \n \n \n
\n
\n );\n};\nexport { TxnSettingsProvider, TxnSettings, useTxnSettings };\nexport type { TxnSettingsType };\n", + "content": "\"use client\";\r\nimport React from \"react\";\r\n\r\nimport { SettingsIcon } from \"lucide-react\";\r\nimport {\r\n Dialog,\r\n DialogContent,\r\n DialogTrigger,\r\n DialogHeader,\r\n DialogTitle,\r\n DialogFooter,\r\n DialogClose,\r\n} from \"@/components/ui/dialog\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { ToggleGroup, ToggleGroupItem } from \"@/components/ui/toggle-group\";\r\ntype TxnSettingsType = {\r\n priority: string;\r\n priorityFeeCap: \"dynamic\" | number;\r\n slippageMode: \"dynamic\" | \"fixed\";\r\n slippageValue: number;\r\n};\r\n\r\ntype TxnSettingsContextType = {\r\n settings: TxnSettingsType;\r\n updateSettings: (newSettings: Partial) => void;\r\n isOpen: boolean;\r\n setIsOpen: (isOpen: boolean) => void;\r\n};\r\n\r\nconst TxnSettingsContext = React.createContext<\r\n TxnSettingsContextType | undefined\r\n>(undefined);\r\n\r\nconst TxnSettingsProvider: React.FC<{\r\n children: React.ReactNode;\r\n}> = ({ children }) => {\r\n const [isOpen, setIsOpen] = React.useState(false);\r\n const [settings, setSettings] = React.useState({\r\n priority: \"normal\",\r\n priorityFeeCap: \"dynamic\",\r\n slippageMode: \"dynamic\",\r\n slippageValue: 1.0,\r\n });\r\n\r\n const updateSettings = (newSettings: Partial) => {\r\n setSettings((prevSettings) => ({ ...prevSettings, ...newSettings }));\r\n };\r\n\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n};\r\n\r\nconst useTxnSettings = () => {\r\n const context = React.useContext(TxnSettingsContext);\r\n if (context === undefined) {\r\n throw new Error(\"useTxnSettings must be used within a TxnSettingsProvider\");\r\n }\r\n return context;\r\n};\r\n\r\ntype TxnSettingsProps = {\r\n trigger?: React.ReactNode;\r\n};\r\nconst TxnSettings = ({ trigger }: TxnSettingsProps) => {\r\n const { settings, updateSettings, isOpen, setIsOpen } = useTxnSettings();\r\n const [tempSettings, setTempSettings] =\r\n React.useState(settings);\r\n const [manualFee, setManualFee] = React.useState(\"\");\r\n const [manualSlippage, setManualSlippage] = React.useState(\"\");\r\n\r\n React.useEffect(() => {\r\n if (isOpen) {\r\n setTempSettings(settings);\r\n }\r\n }, [isOpen, settings]);\r\n \r\n const handleSave = () => {\r\n updateSettings(tempSettings);\r\n setIsOpen(false);\r\n };\r\n\r\n const handleCancel = () => {\r\n setTempSettings(settings);\r\n setIsOpen(false);\r\n };\r\n\r\n const handleSlippagePresetChange = (value: string) => {\r\n const slippageMap: Record = {\r\n low: 0.5,\r\n normal: 1.0,\r\n high: 1.5,\r\n };\r\n\r\n setTempSettings((prev) => ({\r\n ...prev,\r\n slippageValue: slippageMap[value] || prev.slippageValue,\r\n }));\r\n };\r\n return (\r\n \r\n \r\n {trigger || (\r\n \r\n )}\r\n \r\n \r\n \r\n Transaction Settings\r\n \r\n {\r\n e.preventDefault();\r\n handleSave();\r\n }}\r\n >\r\n
\r\n
\r\n

Priority fee

\r\n

\r\n Set the priority fee for your transactions.\r\n

\r\n
\r\n \r\n setTempSettings((prev) => ({ ...prev, priority: value }))\r\n }\r\n >\r\n Normal\r\n Medium\r\n Turbo\r\n \r\n
\r\n
\r\n
\r\n

Priority fee cap

\r\n

\r\n Set the priority fee cap for your transactions.\r\n

\r\n
\r\n {\r\n if (value === \"dynamic\") {\r\n setTempSettings((prev) => ({\r\n ...prev,\r\n priorityFeeCap: \"dynamic\",\r\n }));\r\n } else if (value === \"manual\") {\r\n setTempSettings((prev) => ({ ...prev, priorityFeeCap: 0 }));\r\n }\r\n }}\r\n >\r\n Manual\r\n Dynamic\r\n \r\n {tempSettings.priorityFeeCap !== \"dynamic\" && (\r\n {\r\n const value = e.target.value;\r\n setManualFee(value);\r\n const numValue = parseFloat(value);\r\n if (!isNaN(numValue)) {\r\n setTempSettings((prev) => ({\r\n ...prev,\r\n priorityFeeCap: numValue,\r\n }));\r\n }\r\n }}\r\n className=\"mt-2\"\r\n />\r\n )}\r\n
\r\n
\r\n
\r\n

Slippage mode

\r\n

\r\n Set a fixed slippage or let us calculate optimal slippage for\r\n you.\r\n

\r\n
\r\n {\r\n if (value) {\r\n setTempSettings((prev) => ({\r\n ...prev,\r\n slippageMode: value as \"dynamic\" | \"fixed\",\r\n }));\r\n }\r\n }}\r\n >\r\n Dynamic\r\n Fixed\r\n \r\n\r\n {tempSettings.slippageMode === \"fixed\" && (\r\n
\r\n {\r\n if (value && value !== \"custom\") {\r\n handleSlippagePresetChange(value);\r\n }\r\n }}\r\n >\r\n \r\n
\r\n Low\r\n 0.5 %\r\n
\r\n
\r\n \r\n
\r\n Normal\r\n 1 %\r\n
\r\n \r\n \r\n
\r\n High\r\n 1.5 %\r\n
\r\n
\r\n \r\n\r\n
\r\n

Or set manually

\r\n
\r\n {\r\n const value = e.target.value;\r\n setManualSlippage(value);\r\n const numValue = parseFloat(value);\r\n if (!isNaN(numValue)) {\r\n setTempSettings((prev) => ({\r\n ...prev,\r\n slippageValue: numValue,\r\n }));\r\n }\r\n }}\r\n className=\"pr-8\"\r\n />\r\n \r\n %\r\n \r\n
\r\n
\r\n
\r\n )}\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n};\r\nexport { TxnSettingsProvider, TxnSettings, useTxnSettings };\r\nexport type { TxnSettingsType };\r\n", "type": "registry:component", "target": "components/ui/murphy/txn-settings.tsx" } diff --git a/registry.json b/registry.json index 022f227..9a5290f 100644 --- a/registry.json +++ b/registry.json @@ -3,186 +3,6 @@ "name": "murphy", "homepage": "https://murphy.vercel.app/", "items": [ - { - "name": "CancelRecurringOrder", - "type": "registry:block", - "description": "Murphy component to cancel Jupiter Recurring DCA Orders on Solana mainnet", - "files": [ - { - "path": "components/ui/murphy/Jupiter-Recurring/CancelRecurringOrder.tsx", - "type": "registry:component", - "target": "components/ui/murphy/Jupiter-Recurring/CancelRecurringOrder.tsx" - } - ], - "dependencies": [ - "@solana/web3.js", - "@solana/wallet-adapter-react", - "sonner" - ], - "category": "Jupiter Recurring", - "keywords": [ - "jupiter", - "recurring", - "dca", - "cancel", - "order", - "solana", - "wallet" - ], - "author": "Murphy", - "license": "MIT" - }, - { - "name": "RecurringActiveOrders", - "type": "registry:block", - "description": "Murphy component to view active Jupiter Recurring DCA Orders on Solana mainnet", - "files": [ - { - "path": "components/ui/murphy/Jupiter-Recurring/RecurringActiveOrders.tsx", - "type": "registry:component", - "target": "components/ui/murphy/Jupiter-Recurring/RecurringActiveOrders.tsx" - } - ], - "dependencies": [ - "@solana/web3.js", - "@solana/wallet-adapter-react", - "sonner" - ], - "category": "Jupiter Recurring", - "keywords": [ - "jupiter", - "recurring", - "dca", - "active", - "orders", - "view", - "solana", - "wallet" - ], - "author": "Murphy", - "license": "MIT" - }, - { - "name": "RecurringHistoryList", - "type": "registry:block", - "description": "Murphy component to view Jupiter Recurring DCA Order history on Solana mainnet", - "files": [ - { - "path": "components/ui/murphy/Jupiter-Recurring/RecurringHistoryList.tsx", - "type": "registry:component", - "target": "components/ui/murphy/Jupiter-Recurring/RecurringHistoryList.tsx" - } - ], - "dependencies": [ - "@solana/web3.js", - "@solana/wallet-adapter-react", - "sonner" - ], - "category": "Jupiter Recurring", - "keywords": [ - "jupiter", - "recurring", - "dca", - "history", - "orders", - "view", - "solana", - "wallet" - ], - "author": "Murphy", - "license": "MIT" - }, - { - "name": "RecurringOrderCard", - "type": "registry:block", - "description": "Murphy component to display a single Jupiter Recurring DCA Order on Solana mainnet", - "files": [ - { - "path": "components/ui/murphy/Jupiter-Recurring/RecurringOrderCard.tsx", - "type": "registry:component", - "target": "components/ui/murphy/Jupiter-Recurring/RecurringOrderCard.tsx" - } - ], - "dependencies": [ - "@solana/web3.js", - "@solana/wallet-adapter-react", - "sonner" - ], - "category": "Jupiter Recurring", - "keywords": [ - "jupiter", - "recurring", - "dca", - "order", - "card", - "display", - "solana", - "wallet" - ], - "author": "Murphy", - "license": "MIT" - }, - { - "name": "RecurringOrderWidget", - "type": "registry:block", - "description": "Murphy component to manage and filter Jupiter Recurring DCA Orders on Solana mainnet", - "files": [ - { - "path": "components/ui/murphy/Jupiter-Recurring/RecurringOrderWidget.tsx", - "type": "registry:component", - "target": "components/ui/murphy/Jupiter-Recurring/RecurringOrderWidget.tsx" - } - ], - "dependencies": [ - "@solana/web3.js", - "@solana/wallet-adapter-react", - "sonner" - ], - "category": "Jupiter Recurring", - "keywords": [ - "jupiter", - "recurring", - "dca", - "widget", - "manage", - "filter", - "orders", - "solana", - "wallet" - ], - "author": "Murphy", - "license": "MIT" - }, - { - "name": "RecurringSetupForm", - "type": "registry:block", - "description": "Murphy component to create Jupiter Recurring DCA Orders on Solana mainnet", - "files": [ - { - "path": "components/ui/murphy/Jupiter-Recurring/RecurringSetupForm.tsx", - "type": "registry:component", - "target": "components/ui/murphy/Jupiter-Recurring/RecurringSetupForm.tsx" - } - ], - "dependencies": [ - "@solana/web3.js", - "@solana/wallet-adapter-react", - "sonner" - ], - "category": "Jupiter Recurring", - "keywords": [ - "jupiter", - "recurring", - "dca", - "setup", - "create", - "order", - "solana", - "wallet" - ], - "author": "Murphy", - "license": "MIT" - }, { "name": "avatar", "description": "A simple avatar icon", @@ -282,6 +102,35 @@ } ] }, + { + "name": "CancelRecurringOrder", + "type": "registry:block", + "description": "Murphy component to cancel Jupiter Recurring DCA Orders on Solana mainnet", + "files": [ + { + "path": "components/ui/murphy/Jupiter-Recurring/CancelRecurringOrder.tsx", + "type": "registry:component", + "target": "components/ui/murphy/Jupiter-Recurring/CancelRecurringOrder.tsx" + } + ], + "dependencies": [ + "@solana/web3.js", + "@solana/wallet-adapter-react", + "sonner" + ], + "category": "Jupiter Recurring", + "keywords": [ + "jupiter", + "recurring", + "dca", + "cancel", + "order", + "solana", + "wallet" + ], + "author": "Murphy", + "license": "MIT" + }, { "name": "claim-cToken", "type": "registry:block", @@ -528,10 +377,26 @@ ] }, { - "name": "mint-cToken", + "name": "inline-txn-status", "type": "registry:block", - "title": "Mint cToken", - "description": "A simple mint cToken form component.", + "title": "Inline icon or badge to show transaction status (loading, success, error).", + "registryDependencies": [], + "dependencies": [ + "lucide-react" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/inline-txn-status.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/inline-txn-status.tsx" + } + ] + }, + { + "name": "mint-cnft-form", + "type": "registry:block", + "title": "Mint CNFT Form", + "description": "A simple mint CNFT form component.", "registryDependencies": [ "input", "button", @@ -545,23 +410,21 @@ "dependencies": [ "@solana/web3.js", "@solana/spl-token", - "@solana/wallet-adapter-react", - "@lightprotocol/stateless.js", - "@lightprotocol/compressed-token" + "@solana/wallet-adapter-react" ], "files": [ { - "path": "components/ui/murphy/mint-cToken.tsx", + "path": "components/ui/murphy/mint-cnft-form.tsx", "type": "registry:component", - "target": "components/ui/murphy/mint-cToken.tsx" + "target": "components/ui/murphy/mint-cnft-form.tsx" } ] }, { - "name": "mint-cnft-form", + "name": "mint-cToken", "type": "registry:block", - "title": "Mint CNFT Form", - "description": "A simple mint CNFT form component.", + "title": "Mint cToken", + "description": "A simple mint cToken form component.", "registryDependencies": [ "input", "button", @@ -575,13 +438,15 @@ "dependencies": [ "@solana/web3.js", "@solana/spl-token", - "@solana/wallet-adapter-react" + "@solana/wallet-adapter-react", + "@lightprotocol/stateless.js", + "@lightprotocol/compressed-token" ], "files": [ { - "path": "components/ui/murphy/mint-cnft-form.tsx", + "path": "components/ui/murphy/mint-cToken.tsx", "type": "registry:component", - "target": "components/ui/murphy/mint-cnft-form.tsx" + "target": "components/ui/murphy/mint-cToken.tsx" } ] }, @@ -691,6 +556,157 @@ } ] }, + { + "name": "RecurringActiveOrders", + "type": "registry:block", + "description": "Murphy component to view active Jupiter Recurring DCA Orders on Solana mainnet", + "files": [ + { + "path": "components/ui/murphy/Jupiter-Recurring/RecurringActiveOrders.tsx", + "type": "registry:component", + "target": "components/ui/murphy/Jupiter-Recurring/RecurringActiveOrders.tsx" + } + ], + "dependencies": [ + "@solana/web3.js", + "@solana/wallet-adapter-react", + "sonner" + ], + "category": "Jupiter Recurring", + "keywords": [ + "jupiter", + "recurring", + "dca", + "active", + "orders", + "view", + "solana", + "wallet" + ], + "author": "Murphy", + "license": "MIT" + }, + { + "name": "RecurringHistoryList", + "type": "registry:block", + "description": "Murphy component to view Jupiter Recurring DCA Order history on Solana mainnet", + "files": [ + { + "path": "components/ui/murphy/Jupiter-Recurring/RecurringHistoryList.tsx", + "type": "registry:component", + "target": "components/ui/murphy/Jupiter-Recurring/RecurringHistoryList.tsx" + } + ], + "dependencies": [ + "@solana/web3.js", + "@solana/wallet-adapter-react", + "sonner" + ], + "category": "Jupiter Recurring", + "keywords": [ + "jupiter", + "recurring", + "dca", + "history", + "orders", + "view", + "solana", + "wallet" + ], + "author": "Murphy", + "license": "MIT" + }, + { + "name": "RecurringOrderCard", + "type": "registry:block", + "description": "Murphy component to display a single Jupiter Recurring DCA Order on Solana mainnet", + "files": [ + { + "path": "components/ui/murphy/Jupiter-Recurring/RecurringOrderCard.tsx", + "type": "registry:component", + "target": "components/ui/murphy/Jupiter-Recurring/RecurringOrderCard.tsx" + } + ], + "dependencies": [ + "@solana/web3.js", + "@solana/wallet-adapter-react", + "sonner" + ], + "category": "Jupiter Recurring", + "keywords": [ + "jupiter", + "recurring", + "dca", + "order", + "card", + "display", + "solana", + "wallet" + ], + "author": "Murphy", + "license": "MIT" + }, + { + "name": "RecurringOrderWidget", + "type": "registry:block", + "description": "Murphy component to manage and filter Jupiter Recurring DCA Orders on Solana mainnet", + "files": [ + { + "path": "components/ui/murphy/Jupiter-Recurring/RecurringOrderWidget.tsx", + "type": "registry:component", + "target": "components/ui/murphy/Jupiter-Recurring/RecurringOrderWidget.tsx" + } + ], + "dependencies": [ + "@solana/web3.js", + "@solana/wallet-adapter-react", + "sonner" + ], + "category": "Jupiter Recurring", + "keywords": [ + "jupiter", + "recurring", + "dca", + "widget", + "manage", + "filter", + "orders", + "solana", + "wallet" + ], + "author": "Murphy", + "license": "MIT" + }, + { + "name": "RecurringSetupForm", + "type": "registry:block", + "description": "Murphy component to create Jupiter Recurring DCA Orders on Solana mainnet", + "files": [ + { + "path": "components/ui/murphy/Jupiter-Recurring/RecurringSetupForm.tsx", + "type": "registry:component", + "target": "components/ui/murphy/Jupiter-Recurring/RecurringSetupForm.tsx" + } + ], + "dependencies": [ + "@solana/web3.js", + "@solana/wallet-adapter-react", + "sonner" + ], + "category": "Jupiter Recurring", + "keywords": [ + "jupiter", + "recurring", + "dca", + "setup", + "create", + "order", + "solana", + "wallet" + ], + "author": "Murphy", + "license": "MIT" + }, { "name": "send-token-form", "type": "registry:block", @@ -777,6 +793,41 @@ } ] }, + { + "name": "step-flow-dialog", + "type": "registry:block", + "title": "Modal for guiding users through multi-step flows (e.g. Mint → Verify → Confirm).", + "registryDependencies": [ + "dialog", + "button", + "txn-progress-steps" + ], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx" + } + ] + }, + { + "name": "success-dialog", + "type": "registry:block", + "title": "Modal shown when a transaction completes successfully.", + "registryDependencies": [ + "dialog", + "button" + ], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/success-dialog.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/success-dialog.tsx" + } + ] + }, { "name": "swap-token-form", "type": "registry:block", @@ -1036,6 +1087,54 @@ } ] }, + { + "name": "txn-error-fallback", + "type": "registry:block", + "title": "Fallback UI for failed transactions with retry and log support.", + "registryDependencies": [ + "button" + ], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx" + } + ] + }, + { + "name": "txn-explorer-link", + "type": "registry:block", + "title": "A link to open a transaction on Solana Explorer.", + "registryDependencies": [], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx" + } + ] + }, + { + "name": "txn-feedback-toast", + "type": "registry:block", + "title": "Toast component to display transaction status (loading, success, error).", + "registryDependencies": [ + "toast" + ], + "dependencies": [ + "sonner" + ], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx" + } + ] + }, { "name": "txn-list", "type": "registry:block", @@ -1062,6 +1161,50 @@ } ] }, + { + "name": "txn-pending-indicator", + "type": "registry:block", + "title": "Global indicator showing pending transactions in the UI.", + "registryDependencies": [], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx" + } + ] + }, + { + "name": "txn-progress-steps", + "type": "registry:block", + "title": "A visual step tracker for multi-step transaction workflows.", + "registryDependencies": [], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx" + } + ] + }, + { + "name": "txn-retry-button", + "type": "registry:block", + "title": "A button component with built-in retry handling for transactions.", + "registryDependencies": [ + "button" + ], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-retry-button.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-retry-button.tsx" + } + ] + }, { "name": "txn-settings", "type": "registry:block", diff --git a/registry/components/inline-txn-status.json b/registry/components/inline-txn-status.json new file mode 100644 index 0000000..71bbf30 --- /dev/null +++ b/registry/components/inline-txn-status.json @@ -0,0 +1,14 @@ +{ + "name": "inline-txn-status", + "type": "registry:block", + "title": "Inline icon or badge to show transaction status (loading, success, error).", + "registryDependencies": [], + "dependencies": ["lucide-react"], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/inline-txn-status.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/inline-txn-status.tsx" + } + ] +} diff --git a/registry/components/step-flow-dialog.json b/registry/components/step-flow-dialog.json new file mode 100644 index 0000000..641d9d7 --- /dev/null +++ b/registry/components/step-flow-dialog.json @@ -0,0 +1,14 @@ +{ + "name": "step-flow-dialog", + "type": "registry:block", + "title": "Modal for guiding users through multi-step flows (e.g. Mint → Verify → Confirm).", + "registryDependencies": ["dialog", "button", "txn-progress-steps"], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/step-flow-dialog.tsx" + } + ] +} diff --git a/registry/components/success-dialog.json b/registry/components/success-dialog.json new file mode 100644 index 0000000..1537249 --- /dev/null +++ b/registry/components/success-dialog.json @@ -0,0 +1,14 @@ +{ + "name": "success-dialog", + "type": "registry:block", + "title": "Modal shown when a transaction completes successfully.", + "registryDependencies": ["dialog", "button"], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/success-dialog.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/success-dialog.tsx" + } + ] +} diff --git a/registry/components/txn-error-fallback.json b/registry/components/txn-error-fallback.json new file mode 100644 index 0000000..e481352 --- /dev/null +++ b/registry/components/txn-error-fallback.json @@ -0,0 +1,14 @@ +{ + "name": "txn-error-fallback", + "type": "registry:block", + "title": "Fallback UI for failed transactions with retry and log support.", + "registryDependencies": ["button"], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-error-fallback.tsx" + } + ] +} diff --git a/registry/components/txn-explorer-link.json b/registry/components/txn-explorer-link.json new file mode 100644 index 0000000..b253226 --- /dev/null +++ b/registry/components/txn-explorer-link.json @@ -0,0 +1,14 @@ +{ + "name": "txn-explorer-link", + "type": "registry:block", + "title": "A link to open a transaction on Solana Explorer.", + "registryDependencies": [], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx" + } + ] +} diff --git a/registry/components/txn-feedback-toast.json b/registry/components/txn-feedback-toast.json new file mode 100644 index 0000000..f769f5d --- /dev/null +++ b/registry/components/txn-feedback-toast.json @@ -0,0 +1,14 @@ +{ + "name": "txn-feedback-toast", + "type": "registry:block", + "title": "Toast component to display transaction status (loading, success, error).", + "registryDependencies": ["toast"], + "dependencies": ["sonner"], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx" + } + ] +} diff --git a/registry/components/txn-pending-indicator.json b/registry/components/txn-pending-indicator.json new file mode 100644 index 0000000..b2b7f48 --- /dev/null +++ b/registry/components/txn-pending-indicator.json @@ -0,0 +1,14 @@ +{ + "name": "txn-pending-indicator", + "type": "registry:block", + "title": "Global indicator showing pending transactions in the UI.", + "registryDependencies": [], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-pending-indicator.tsx" + } + ] +} diff --git a/registry/components/txn-progress-steps.json b/registry/components/txn-progress-steps.json new file mode 100644 index 0000000..fdec8cb --- /dev/null +++ b/registry/components/txn-progress-steps.json @@ -0,0 +1,14 @@ +{ + "name": "txn-progress-steps", + "type": "registry:block", + "title": "A visual step tracker for multi-step transaction workflows.", + "registryDependencies": [], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-progress-steps.tsx" + } + ] +} diff --git a/registry/components/txn-retry-button.json b/registry/components/txn-retry-button.json new file mode 100644 index 0000000..61e4e42 --- /dev/null +++ b/registry/components/txn-retry-button.json @@ -0,0 +1,14 @@ +{ + "name": "txn-retry-button", + "type": "registry:block", + "title": "A button component with built-in retry handling for transactions.", + "registryDependencies": ["button"], + "dependencies": [], + "files": [ + { + "path": "components/ui/murphy/Txn-Feedback/txn-retry-button.tsx", + "type": "registry:file", + "target": "components/ui/murphy/Txn-Feedback/txn-retry-button.tsx" + } + ] +} diff --git a/types/transaction/index.ts b/types/transaction/index.ts new file mode 100644 index 0000000..8f70ce2 --- /dev/null +++ b/types/transaction/index.ts @@ -0,0 +1,20 @@ +export interface TransactionStatus { + status: "idle" | "preparing" | "signing" | "sending" | "confirming" | "success" | "error" + signature?: string + error?: string + step?: number + totalSteps?: number +} + +export interface TxnStep { + id: string + title: string + description?: string + status: "pending" | "active" | "completed" | "error" +} + +export interface TxnFeedbackProps { + status: TransactionStatus + onRetry?: () => void + onClose?: () => void +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..d1b4cb9 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,11358 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adraffy/ens-normalize@^1.10.1", "@adraffy/ens-normalize@^1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" + integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== + +"@ai-sdk/openai@^1.3.21": + version "1.3.23" + resolved "https://registry.yarnpkg.com/@ai-sdk/openai/-/openai-1.3.23.tgz#77e91a74029532bae7b6f5a5dfcc90d9bc33c9f1" + integrity sha512-86U7rFp8yacUAOE/Jz8WbGcwMCqWvjK33wk5DXkfnAOEn3mx2r7tNSJdjukQFZbAK97VMXGPPHxF+aEARDXRXQ== + dependencies: + "@ai-sdk/provider" "1.1.3" + "@ai-sdk/provider-utils" "2.2.8" + +"@ai-sdk/provider-utils@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz#ad11b92d5a1763ab34ba7b5fc42494bfe08b76d1" + integrity sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA== + dependencies: + "@ai-sdk/provider" "1.1.3" + nanoid "^3.3.8" + secure-json-parse "^2.7.0" + +"@ai-sdk/provider@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-1.1.3.tgz#ebdda8077b8d2b3f290dcba32c45ad19b2704681" + integrity sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg== + dependencies: + json-schema "^0.4.0" + +"@ai-sdk/react@1.2.12", "@ai-sdk/react@^1.2.10": + version "1.2.12" + resolved "https://registry.yarnpkg.com/@ai-sdk/react/-/react-1.2.12.tgz#f4250b6df566b170af98a71d5708b52108dd0ce1" + integrity sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g== + dependencies: + "@ai-sdk/provider-utils" "2.2.8" + "@ai-sdk/ui-utils" "1.2.11" + swr "^2.2.5" + throttleit "2.1.0" + +"@ai-sdk/ui-utils@1.2.11": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz#4f815589d08d8fef7292ade54ee5db5d09652603" + integrity sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w== + dependencies: + "@ai-sdk/provider" "1.1.3" + "@ai-sdk/provider-utils" "2.2.8" + zod-to-json-schema "^3.24.1" + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@antfu/ni@^23.2.0": + version "23.3.1" + resolved "https://registry.yarnpkg.com/@antfu/ni/-/ni-23.3.1.tgz#a9dc6e41735cb0fbdc5b1b938ed4388ab47c32d1" + integrity sha512-C90iyzm/jLV7Lomv2UzwWUzRv9WZr1oRsFRKsX5HjQL4EXrbi9H/RtBkjCP+NF+ABZXUKpAa4F1dkoTaea4zHg== + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" + integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== + +"@babel/core@^7.22.1": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" + integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.27.3" + "@babel/helpers" "^7.27.6" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.0" + "@babel/types" "^7.28.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" + integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== + dependencies: + "@babel/parser" "^7.28.0" + "@babel/types" "^7.28.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.27.1", "@babel/helper-annotate-as-pure@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" + integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg== + dependencies: + "@babel/types" "^7.27.3" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281" + integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.27.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-member-expression-to-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" + integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02" + integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.3" + +"@babel/helper-optimise-call-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" + integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-replace-supers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" + integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" + integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.27.6": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c" + integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.27.6" + +"@babel/parser@^7.22.6", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-typescript@^7.22.5": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz#796cbd249ab56c18168b49e3e1d341b72af04a6b" + integrity sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.27.1" + +"@babel/runtime@^7.24.0", "@babel/runtime@^7.25.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6" + integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== + +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" + integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.0" + debug "^4.3.1" + +"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.27.6", "@babel/types@^7.28.0": + version "7.28.1" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.1.tgz#2aaf3c10b31ba03a77ac84f52b3912a0edef4cf9" + integrity sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@bundled-es-modules/cookie@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz#b41376af6a06b3e32a15241d927b840a9b4de507" + integrity sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw== + dependencies: + cookie "^0.7.2" + +"@bundled-es-modules/statuses@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz#761d10f44e51a94902c4da48675b71a76cc98872" + integrity sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg== + dependencies: + statuses "^2.0.1" + +"@bundled-es-modules/tough-cookie@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz#fa9cd3cedfeecd6783e8b0d378b4a99e52bde5d3" + integrity sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw== + dependencies: + "@types/tough-cookie" "^4.0.5" + tough-cookie "^4.1.4" + +"@coral-xyz/anchor-errors@^0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz#d635cbac2533973ae6bfb5d3ba1de89ce5aece2d" + integrity sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ== + +"@coral-xyz/anchor@^0.31.0", "@coral-xyz/anchor@^0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.31.1.tgz#0fdeebf45a3cb2e47e8ebbb815ca98542152962c" + integrity sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA== + dependencies: + "@coral-xyz/anchor-errors" "^0.31.1" + "@coral-xyz/borsh" "^0.31.1" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.69.0" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + eventemitter3 "^4.0.7" + pako "^2.0.3" + superstruct "^0.15.4" + toml "^3.0.0" + +"@coral-xyz/borsh@^0.26.0": + version "0.26.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.26.0.tgz#d054f64536d824634969e74138f9f7c52bbbc0d5" + integrity sha512-uCZ0xus0CszQPHYfWAqKS5swS1UxvePu83oOF+TWpUkedsNlg6p2p4azxZNSSqwXb9uXMFgxhuMBX9r3Xoi0vQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@coral-xyz/borsh@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.29.0.tgz#79f7045df2ef66da8006d47f5399c7190363e71f" + integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@coral-xyz/borsh@^0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.31.1.tgz#5328e1e0921b75d7f4a62dd3f61885a938bc7241" + integrity sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@emnapi/core@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" + integrity sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q== + dependencies: + "@emnapi/wasi-threads" "1.0.4" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3", "@emnapi/runtime@^1.4.4": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9" + integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.0.4", "@emnapi/wasi-threads@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz#703fc094d969e273b1b71c292523b2f792862bf4" + integrity sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g== + dependencies: + tslib "^2.4.0" + +"@emurgo/cardano-serialization-lib-browser@^13.2.0": + version "13.2.1" + resolved "https://registry.yarnpkg.com/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-13.2.1.tgz#b5ef35f2d60773e493b7647aa8cd766d31897c28" + integrity sha512-7RfX1gI16Vj2DgCp/ZoXqyLAakWo6+X95ku/rYGbVzuS/1etrlSiJmdbmdm+eYmszMlGQjrtOJQeVLXoj4L/Ag== + +"@emurgo/cardano-serialization-lib-nodejs@13.2.0": + version "13.2.0" + resolved "https://registry.yarnpkg.com/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-13.2.0.tgz#7427c30c94c7e9676327c9362f4f4d2e387efd2d" + integrity sha512-Bz1zLGEqBQ0BVkqt1OgMxdBOE3BdUWUd7Ly9Ecr/aUwkA8AV1w1XzBMe4xblmJHnB1XXNlPH4SraXCvO+q0Mig== + +"@esbuild/aix-ppc64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz#a1414903bb38027382f85f03dda6065056757727" + integrity sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA== + +"@esbuild/android-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz#c859994089e9767224269884061f89dae6fb51c6" + integrity sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w== + +"@esbuild/android-arm@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.8.tgz#96a8f2ca91c6cd29ea90b1af79d83761c8ba0059" + integrity sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw== + +"@esbuild/android-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.8.tgz#a3a626c4fec4a024a9fa8c7679c39996e92916f0" + integrity sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA== + +"@esbuild/darwin-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz#a5e1252ca2983d566af1c0ea39aded65736fc66d" + integrity sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw== + +"@esbuild/darwin-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz#5271b0df2bb12ce8df886704bfdd1c7cc01385d2" + integrity sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg== + +"@esbuild/freebsd-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz#d0a0e7fdf19733b8bb1566b81df1aa0bb7e46ada" + integrity sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA== + +"@esbuild/freebsd-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz#2de8b2e0899d08f1cb1ef3128e159616e7e85343" + integrity sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw== + +"@esbuild/linux-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz#a4209efadc0c2975716458484a4e90c237c48ae9" + integrity sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w== + +"@esbuild/linux-arm@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz#ccd9e291c24cd8d9142d819d463e2e7200d25b19" + integrity sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg== + +"@esbuild/linux-ia32@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz#006ad1536d0c2b28fb3a1cf0b53bcb85aaf92c4d" + integrity sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg== + +"@esbuild/linux-loong64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz#127b3fbfb2c2e08b1397e985932f718f09a8f5c4" + integrity sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ== + +"@esbuild/linux-mips64el@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz#837d1449517791e3fa7d82675a2d06d9f56cb340" + integrity sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw== + +"@esbuild/linux-ppc64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz#aa2e3bd93ab8df084212f1895ca4b03c42d9e0fe" + integrity sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ== + +"@esbuild/linux-riscv64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz#a340620e31093fef72767dd28ab04214b3442083" + integrity sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg== + +"@esbuild/linux-s390x@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz#ddfed266c8c13f5efb3105a0cd47f6dcd0e79e71" + integrity sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg== + +"@esbuild/linux-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz#9a4f78c75c051e8c060183ebb39a269ba936a2ac" + integrity sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ== + +"@esbuild/netbsd-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz#902c80e1d678047926387230bc037e63e00697d0" + integrity sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw== + +"@esbuild/netbsd-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz#2d9eb4692add2681ff05a14ce99de54fbed7079c" + integrity sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg== + +"@esbuild/openbsd-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz#89c3b998c6de739db38ab7fb71a8a76b3fa84a45" + integrity sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ== + +"@esbuild/openbsd-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz#2f01615cf472b0e48c077045cfd96b5c149365cc" + integrity sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ== + +"@esbuild/openharmony-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz#a201f720cd2c3ebf9a6033fcc3feb069a54b509a" + integrity sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg== + +"@esbuild/sunos-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz#07046c977985a3334667f19e6ab3a01a80862afb" + integrity sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w== + +"@esbuild/win32-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz#4a5470caf0d16127c05d4833d4934213c69392d1" + integrity sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ== + +"@esbuild/win32-ia32@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz#3de3e8470b7b328d99dbc3e9ec1eace207e5bbc4" + integrity sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg== + +"@esbuild/win32-x64@0.25.8": + version "0.25.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c" + integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw== + +"@ethereumjs/common@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-10.0.0.tgz#7beb1d2135c9eeaf03fd7dd9fed94fea18182a2c" + integrity sha512-qb0M1DGdXzMAf3O6Zg5Wr5UDjoxBmplLPbQyC6DQ0LfgVDBRdqn0Pk+/hHm4q0McE22Of0MxbV4hhiDTkSgKag== + dependencies: + "@ethereumjs/util" "^10.0.0" + eventemitter3 "^5.0.1" + +"@ethereumjs/rlp@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-10.0.0.tgz#8305d99422b4cde522f5feeb77593687287633c1" + integrity sha512-h2SK6RxFBfN5ZGykbw8LTNNLckSXZeuUZ6xqnmtF22CzZbHflFMcIOyfVGdvyCVQqIoSbGMHtvyxMCWnOyB9RA== + +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/rlp@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-5.0.2.tgz#c89bd82f2f3bec248ab2d517ae25f5bbc4aac842" + integrity sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA== + +"@ethereumjs/tx@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-10.0.0.tgz#100ee3cf4cb7342cabeb4f0ec41f4ccadf50df26" + integrity sha512-DApm04kp2nbvaOuHy2Rkcz1ZeJkTVgW6oCuNnQf9bRtGc+LsvLrdULE3LoGtBItEoNEcgXLJqrV0foooWFX6jw== + dependencies: + "@ethereumjs/common" "^10.0.0" + "@ethereumjs/rlp" "^10.0.0" + "@ethereumjs/util" "^10.0.0" + ethereum-cryptography "^3.2.0" + +"@ethereumjs/util@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-10.0.0.tgz#1afcb06d769cb979a628a65604ba7e7fb61167ac" + integrity sha512-lO23alM4uQsv8dp6/yEm4Xw4328+wIRjSeuBO1mRTToUWRcByEMTk87yzBpXgpixpgHrl+9LTn9KB2vvKKtOQQ== + dependencies: + "@ethereumjs/rlp" "^10.0.0" + ethereum-cryptography "^3.2.0" + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethereumjs/util@^9.0.3": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-9.1.0.tgz#75e3898a3116d21c135fa9e29886565609129bce" + integrity sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog== + dependencies: + "@ethereumjs/rlp" "^5.0.2" + ethereum-cryptography "^2.2.1" + +"@fivebinaries/coin-selection@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@fivebinaries/coin-selection/-/coin-selection-3.0.0.tgz#00f19f21a8c6d183c8922efef6c102d0ce2b1af3" + integrity sha512-h25Pn1ZA7oqQBQDodGAgIsQt66T2wDge9onBKNqE66WNWL0KJiKJbpij8YOLo5AAlEIg5IS7EB1QjBgDOIg6DQ== + dependencies: + "@emurgo/cardano-serialization-lib-browser" "^13.2.0" + "@emurgo/cardano-serialization-lib-nodejs" "13.2.0" + +"@floating-ui/core@^1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.2.tgz#3d1c35263950b314b6d5a72c8bfb9e3c1551aefd" + integrity sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw== + dependencies: + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/dom@^1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.2.tgz#3540b051cf5ce0d4f4db5fb2507a76e8ea5b4a45" + integrity sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA== + dependencies: + "@floating-ui/core" "^1.7.2" + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/react-dom@^2.0.0": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.4.tgz#a0689be8978352fff2be2dfdd718cf668c488ec3" + integrity sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw== + dependencies: + "@floating-ui/dom" "^1.7.2" + +"@floating-ui/utils@^0.2.10": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" + integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== + +"@formatjs/intl-localematcher@^0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz#25dc30675320bf65a9d7f73876fc1e4064c0e299" + integrity sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg== + dependencies: + tslib "^2.8.0" + +"@fractalwagmi/popup-connection@^1.0.18": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@fractalwagmi/popup-connection/-/popup-connection-1.1.1.tgz#2dfff4f3bb89d17947adae597f355faf46c194a9" + integrity sha512-hYL+45iYwNbwjvP2DxP3YzVsrAGtj/RV9LOgMpJyCxsfNoyyOoi2+YrnywKkiANingiG2kJ1nKsizbu1Bd4zZw== + +"@fractalwagmi/solana-wallet-adapter@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@fractalwagmi/solana-wallet-adapter/-/solana-wallet-adapter-0.1.1.tgz#13d97bca657007a62b2118ea60f5d9e73f654a37" + integrity sha512-oTZLEuD+zLKXyhZC5tDRMPKPj8iaxKLxXiCjqRfOo4xmSbS2izGRWLJbKMYYsJysn/OI3UJ3P6CWP8WUWi0dZg== + dependencies: + "@fractalwagmi/popup-connection" "^1.0.18" + "@solana/wallet-adapter-base" "^0.9.17" + bs58 "^5.0.0" + +"@hookform/resolvers@^5.0.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-5.1.1.tgz#91074ba4fb749cc74e6465e75d38256146b0c4ab" + integrity sha512-J/NVING3LMAEvexJkyTLjruSm7aOFx7QX21pzkiJfMoNG0wl5aFEjLTl7ay7IQb9EWY6AkrBy7tHL2Alijpdcg== + dependencies: + "@standard-schema/utils" "^0.3.0" + +"@img/sharp-darwin-arm64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz#4850c8ace3c1dc13607fa07d43377b1f9aa774da" + integrity sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.0" + +"@img/sharp-darwin-x64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz#edf93fb01479604f14ad6a64a716e2ef2bb23100" + integrity sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.0" + +"@img/sharp-libvips-darwin-arm64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz#e20e9041031acde1de19da121dc5162c7d2cf251" + integrity sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ== + +"@img/sharp-libvips-darwin-x64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz#918ca81c5446f31114834cb908425a7532393185" + integrity sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg== + +"@img/sharp-libvips-linux-arm64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz#1a5beafc857b43f378c3030427aa981ee3edbc54" + integrity sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA== + +"@img/sharp-libvips-linux-arm@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz#bff51182d5238ca35c5fe9e9f594a18ad6a5480d" + integrity sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw== + +"@img/sharp-libvips-linux-ppc64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz#10c53ccf6f2d47d71fb3fa282697072c8fe9e40e" + integrity sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ== + +"@img/sharp-libvips-linux-s390x@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz#392fd7557ddc5c901f1bed7ab3c567c08833ef3b" + integrity sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw== + +"@img/sharp-libvips-linux-x64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz#9315cf90a2fdcdc0e29ea7663cbd8b0f15254400" + integrity sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz#705e03e67d477f6f842f37eb7f66285b1150dc06" + integrity sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q== + +"@img/sharp-libvips-linuxmusl-x64@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz#ec905071cc538df64848d5900e0d386d77c55f13" + integrity sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q== + +"@img/sharp-linux-arm64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz#476f8f13ce192555391ae9d4bc658637a6acf3e5" + integrity sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.0" + +"@img/sharp-linux-arm@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz#9898cd68ea3e3806b94fe25736d5d7ecb5eac121" + integrity sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.0" + +"@img/sharp-linux-ppc64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz#6a7cd4c608011333a0ddde6d96e03ac042dd9079" + integrity sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.0" + +"@img/sharp-linux-s390x@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz#48e27ab969efe97d270e39297654c0e0c9b42919" + integrity sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.0" + +"@img/sharp-linux-x64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz#5aa77ad4aa447ddf6d642e2a2c5599eb1292dfaa" + integrity sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.0" + +"@img/sharp-linuxmusl-arm64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz#62053a9d77c7d4632c677619325b741254689dd7" + integrity sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.0" + +"@img/sharp-linuxmusl-x64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz#5107c7709c7e0a44fe5abef59829f1de86fa0a3a" + integrity sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.0" + +"@img/sharp-wasm32@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz#c1dcabb834ec2f71308a810b399bb6e6e3b79619" + integrity sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg== + dependencies: + "@emnapi/runtime" "^1.4.4" + +"@img/sharp-win32-arm64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz#3e8654e368bb349d45799a0d7aeb29db2298628e" + integrity sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ== + +"@img/sharp-win32-ia32@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz#9d4c105e8d5074a351a81a0b6d056e0af913bf76" + integrity sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw== + +"@img/sharp-win32-x64@0.34.3": + version "0.34.3" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz#d20c89bd41b1dd3d76d8575714aaaa3c43204b6a" + integrity sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g== + +"@inquirer/confirm@^5.0.0": + version "5.1.14" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.14.tgz#e6321edf51a3a5f54dc548b80ef6ba89891351ad" + integrity sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q== + dependencies: + "@inquirer/core" "^10.1.15" + "@inquirer/type" "^3.0.8" + +"@inquirer/core@^10.1.15": + version "10.1.15" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.15.tgz#8feb69fd536786181a2b6bfb84d8674faa9d2e59" + integrity sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA== + dependencies: + "@inquirer/figures" "^1.0.13" + "@inquirer/type" "^3.0.8" + ansi-escapes "^4.3.2" + cli-width "^4.1.0" + mute-stream "^2.0.0" + signal-exit "^4.1.0" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/figures@^1.0.13": + version "1.0.13" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.13.tgz#ad0afd62baab1c23175115a9b62f511b6a751e45" + integrity sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw== + +"@inquirer/type@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.8.tgz#efc293ba0ed91e90e6267f1aacc1c70d20b8b4e8" + integrity sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw== + +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" + integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" + integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" + integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@keystonehq/alias-sampling@^0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@keystonehq/alias-sampling/-/alias-sampling-0.1.2.tgz#63af931ffe6500aef4c0d87775a5b279189abf8d" + integrity sha512-5ukLB3bcgltgaFfQfYKYwHDUbwHicekYo53fSEa7xhVkAEqsA74kxdIwoBIURmGUtXe3EVIRm4SYlgcrt2Ri0w== + +"@keystonehq/bc-ur-registry-sol@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry-sol/-/bc-ur-registry-sol-0.9.5.tgz#f7c9395c38e4734cd49c45318d9342894a05a51b" + integrity sha512-HZeeph9297ZHjAziE9wL/u2W1dmV0p1H9Bu9g1bLJazP4F6W2fjCK9BAoCiKEsMBqadk6KI6r6VD67fmDzWyug== + dependencies: + "@keystonehq/bc-ur-registry" "^0.7.0" + bs58check "^2.1.2" + uuid "^8.3.2" + +"@keystonehq/bc-ur-registry@0.5.4": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.5.4.tgz#5802486a29f5d772520d15579d40fba02860e27f" + integrity sha512-z7bZe10I5k0zz9znmDTXh+o3Rzb5XsRVpwAzexubOaLxVdZ0F7aMbe2LoEsw766Hpox/7zARi7UGmLz5C8BAzA== + dependencies: + "@ngraveio/bc-ur" "^1.1.5" + bs58check "^2.1.2" + tslib "^2.3.0" + +"@keystonehq/bc-ur-registry@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.7.0.tgz#d0322d6a5cd2796dd0e40662c47b5a95ec917d9a" + integrity sha512-E6NUd6Y+YYM+IcYGOEXfO9+MU1s63Qjm8brtHftvNhxbdXhGtTYIsa4FQmqZ6q34q91bMkMqUQFsQYPmIxcxfg== + dependencies: + "@ngraveio/bc-ur" "^1.1.5" + bs58check "^2.1.2" + tslib "^2.3.0" + +"@keystonehq/sdk@^0.19.2": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@keystonehq/sdk/-/sdk-0.19.2.tgz#2c7e35b93fc8c853b1161f32c1f0f68d272b43f3" + integrity sha512-ilA7xAhPKvpHWlxjzv3hjMehD6IKYda4C1TeG2/DhFgX9VSffzv77Eebf8kVwzPLdYV4LjX1KQ2ZDFoN1MsSFQ== + dependencies: + "@ngraveio/bc-ur" "^1.0.0" + qrcode.react "^1.0.1" + react-modal "^3.12.1" + react-qr-reader "^2.2.1" + rxjs "^6.6.3" + +"@keystonehq/sol-keyring@^0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@keystonehq/sol-keyring/-/sol-keyring-0.20.0.tgz#0fe224a0ef751fb6b2c93907e5ad7bd05cea7f06" + integrity sha512-UBeMlecybTDQaFMI951LBEVRyZarqKHOcwWqqvphV+x7WquYz0SZ/wf/PhizV0MWoGTQwt2m5aqROzksi6svqw== + dependencies: + "@keystonehq/bc-ur-registry" "0.5.4" + "@keystonehq/bc-ur-registry-sol" "^0.9.2" + "@keystonehq/sdk" "^0.19.2" + "@solana/web3.js" "^1.36.0" + bs58 "^5.0.0" + uuid "^8.3.2" + +"@lazorkit/wallet@^1.4.9": + version "1.4.9" + resolved "https://registry.yarnpkg.com/@lazorkit/wallet/-/wallet-1.4.9.tgz#4ad679bb5751bd64723bf956d5e361ee2f4e520f" + integrity sha512-mOcSo3ovUtf0z7A0iOV32mxESLFkTcDEtUCCzUb13D3RAmub3tRVwN+U10xF562u8+igv/oUsDxNYlcKfVrsBQ== + dependencies: + "@coral-xyz/anchor" "^0.31.1" + "@solana/web3.js" "^1.98.2" + bs58 "^6.0.0" + eventemitter3 "^5.0.1" + js-sha256 "^0.11.0" + zustand "^5.0.5" + +"@ledgerhq/devices@8.4.7", "@ledgerhq/devices@^8.4.5": + version "8.4.7" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.4.7.tgz#ba81aa84bbceeaad13e797723716e4edf82ebac3" + integrity sha512-CljHIaPmtv93H2If1Zs1xW0pgg+M37bAoJkm6+V6Yw5S0MgFWFpLnTTNgCvHXyD8pG0+uq8TuOXUiG1oAV5AyA== + dependencies: + "@ledgerhq/errors" "^6.22.0" + "@ledgerhq/logs" "^6.13.0" + rxjs "^7.8.1" + semver "^7.3.5" + +"@ledgerhq/errors@^6.22.0": + version "6.22.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.22.0.tgz#cb72f31890f142565160b8bd446907f7bf0d5634" + integrity sha512-rXtpIOfHL62jWB7o77PNFD4EDYdcqyMeVgt7TZcmTkWT78cK+YYSUTMrNuGLhnZZZTMLWH023Wgt65OfKIdGBQ== + +"@ledgerhq/hw-transport-webhid@^6.30.1": + version "6.30.3" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webhid/-/hw-transport-webhid-6.30.3.tgz#69ef22284915ba0cfc4f134f840976b7f9f03bb2" + integrity sha512-DV2QL4gZ3XvB5i271np5DHROu3Ry6Pjvhd65mu6JLpasAQr0VeW0L8KZ+JK9VryARC1soU1ZEPkL2uVw8MRmvg== + dependencies: + "@ledgerhq/devices" "8.4.7" + "@ledgerhq/errors" "^6.22.0" + "@ledgerhq/hw-transport" "^6.31.7" + "@ledgerhq/logs" "^6.13.0" + +"@ledgerhq/hw-transport@^6.31.5", "@ledgerhq/hw-transport@^6.31.7": + version "6.31.7" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.7.tgz#b3808c1c9cd837798b05b297690ebb868154a426" + integrity sha512-R+QMlqoLJDPeCiqwWv85PbZ3m0hel5PwQzWwSIbyEwialqjXnG7LFQgytkgXlgMcayT0chvvLeYjuY5ZfMPY7w== + dependencies: + "@ledgerhq/devices" "8.4.7" + "@ledgerhq/errors" "^6.22.0" + "@ledgerhq/logs" "^6.13.0" + events "^3.3.0" + +"@ledgerhq/logs@^6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-6.13.0.tgz#0b083af64b6b85db0630c7b940a0ed74ff6262b6" + integrity sha512-4+qRW2Pc8V+btL0QEmdB2X+uyx0kOWMWE1/LWsq5sZy3Q5tpi4eItJS6mB0XL3wGW59RQ+8bchNQQ1OW/va8Og== + +"@lightprotocol/compressed-token@^0.21.0": + version "0.21.0" + resolved "https://registry.yarnpkg.com/@lightprotocol/compressed-token/-/compressed-token-0.21.0.tgz#a9fadf8dba3c24ccbba52f01cd7549a1abc53da6" + integrity sha512-TmQwpzyA9LZRiOEgURrdqPmjseNTpH9l3T953QRzkufXhSZ6zrg5AXLiogCbKmyj392/2BMhfpIJrUtoPqLxuA== + dependencies: + "@coral-xyz/borsh" "^0.29.0" + bn.js "^5.2.1" + buffer "6.0.3" + +"@lightprotocol/stateless.js@^0.21.0": + version "0.21.0" + resolved "https://registry.yarnpkg.com/@lightprotocol/stateless.js/-/stateless.js-0.21.0.tgz#c96017f6368bbd65ee9ab769aabe1ef2ab02ab3a" + integrity sha512-IWX586WFdvex4YKmrtuqtV0SpohRw7OhVwuxBw0IMkJoNQiFWLU9cOFp/Yeayw/ltlL9P15fHT0nVvOkZ8++Wg== + dependencies: + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "1.5.0" + bn.js "^5.2.1" + bs58 "^6.0.0" + buffer "6.0.3" + buffer-layout "^1.2.2" + camelcase "^8.0.0" + camelcase-keys "^9.1.3" + superstruct "2.0.2" + +"@lit-labs/ssr-dom-shim@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz#55eb80ab5ef6e188f7e541c1e2bea1ef582413b8" + integrity sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw== + +"@lit/reactive-element@^2.0.0", "@lit/reactive-element@^2.1.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.1.1.tgz#0662ac4a43d4898974aef9a6c5cd47b9e331919a" + integrity sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg== + dependencies: + "@lit-labs/ssr-dom-shim" "^1.4.0" + +"@mdx-js/loader@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-3.1.0.tgz#715fdab11d0c9567e45049c16a7d9c83cec88214" + integrity sha512-xU/lwKdOyfXtQGqn3VnJjlDrmKXEvMi1mgYxVmukEUtVycIz1nh7oQ40bKTd4cA7rLStqu0740pnhGYxGoqsCg== + dependencies: + "@mdx-js/mdx" "^3.0.0" + source-map "^0.7.0" + +"@mdx-js/mdx@^3.0.0", "@mdx-js/mdx@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-3.1.0.tgz#10235cab8ad7d356c262e8c21c68df5850a97dc3" + integrity sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw== + dependencies: + "@types/estree" "^1.0.0" + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdx" "^2.0.0" + collapse-white-space "^2.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + estree-util-scope "^1.0.0" + estree-walker "^3.0.0" + hast-util-to-jsx-runtime "^2.0.0" + markdown-extensions "^2.0.0" + recma-build-jsx "^1.0.0" + recma-jsx "^1.0.0" + recma-stringify "^1.0.0" + rehype-recma "^1.0.0" + remark-mdx "^3.0.0" + remark-parse "^11.0.0" + remark-rehype "^11.0.0" + source-map "^0.7.0" + unified "^11.0.0" + unist-util-position-from-estree "^2.0.0" + unist-util-stringify-position "^4.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + +"@mdx-js/react@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.1.0.tgz#c4522e335b3897b9a845db1dbdd2f966ae8fb0ed" + integrity sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ== + dependencies: + "@types/mdx" "^2.0.0" + +"@metaplex-foundation/digital-asset-standard-api@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/digital-asset-standard-api/-/digital-asset-standard-api-1.0.6.tgz#c8951bbd43a8883681823abf52abe4954877da64" + integrity sha512-lgequ4N69A7QQjyVt0ViqdeXrnviihXZR+Y9rzAD79JtM3NdbKJ3/BTASgYdCm8oAsVBeLw1Wbf5NjCYdfgS8w== + +"@metaplex-foundation/mpl-bubblegum@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-bubblegum/-/mpl-bubblegum-4.4.0.tgz#7203cdd6182e01987b66dcb07e2e34dff1974716" + integrity sha512-FiRlInn3ZAcdrJHKEWmVOrcQDI4CaME1w9DcxrlbYxbbpsSnO6of6g5zZ8SsimebGjDR+oxSkYO6LkcCPagvHQ== + dependencies: + "@metaplex-foundation/digital-asset-standard-api" "^1.0.5" + "@metaplex-foundation/mpl-token-metadata" "3.2.1" + "@metaplex-foundation/mpl-toolbox" "^0.10.0" + "@noble/hashes" "^1.3.1" + merkletreejs "^0.3.11" + +"@metaplex-foundation/mpl-core-candy-machine@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-core-candy-machine/-/mpl-core-candy-machine-0.3.0.tgz#6634ec97b217299c22bed0309559130b527543fc" + integrity sha512-J2eo6aggZ0BrKyJ6qusEfANM7eSsGzneyLTp/KxfcxUTI0etzdAbivj+cBzTLYVzTC/lHNyvSDA3J96lYwFaSA== + dependencies: + "@metaplex-foundation/mpl-token-metadata" "3.0.0-alpha.27" + "@metaplex-foundation/mpl-toolbox" "^0.9.0" + "@noble/hashes" "^1.2.0" + merkletreejs "^0.3.9" + +"@metaplex-foundation/mpl-core@^1.4.1": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-core/-/mpl-core-1.6.0.tgz#31b9415215642ded78290b5ae261ecbfb65dbd85" + integrity sha512-iy56yXzd/KwKbXpQPymLOZVBn03035RXAGKOPRUUP/xPMR9SY52eC7aBUS9SSQDT2f/wWhShej6pvMuEo6LFvA== + dependencies: + "@msgpack/msgpack" "^3.0.0-beta2" + +"@metaplex-foundation/mpl-token-metadata@3.0.0-alpha.27": + version "3.0.0-alpha.27" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-token-metadata/-/mpl-token-metadata-3.0.0-alpha.27.tgz#7fa5e8432dcb1744be1cb3bd82fb462061ab589d" + integrity sha512-MSERz5HB2XZ/K+FOMh0tPeqcZZEpGVzdy7e+Cy3MHg7x52JtbGBDtWIoxBJn1OBZayCBfX9gytEoqrXe2YRGqQ== + dependencies: + "@metaplex-foundation/mpl-toolbox" "^0.9.0" + +"@metaplex-foundation/mpl-token-metadata@3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-token-metadata/-/mpl-token-metadata-3.2.1.tgz#d424e378a1ee441a6431d2641d66873118d6dc67" + integrity sha512-26W1NhQwDWmLOg/pBRYut7x/vEs/5kFS2sWVEY5/X0f2jJOLhnd4NaZQcq+5u+XZsXvm1jq2AtrRGPNK43oqWQ== + dependencies: + "@metaplex-foundation/mpl-toolbox" "^0.9.4" + +"@metaplex-foundation/mpl-token-metadata@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-token-metadata/-/mpl-token-metadata-3.4.0.tgz#03a2ab3b90ac30973407565e07cc570c8897385d" + integrity sha512-AxBAYCK73JWxY3g9//z/C9krkR0t1orXZDknUPS4+GjwGH2vgPfsk04yfZ31Htka2AdS9YE/3wH7sMUBHKn9Rg== + dependencies: + "@metaplex-foundation/mpl-toolbox" "^0.10.0" + +"@metaplex-foundation/mpl-toolbox@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-toolbox/-/mpl-toolbox-0.10.0.tgz#c7d2f27259e69ab86cc4b7dd55b7bfef11bbed13" + integrity sha512-84KD1L5cFyw5xnntHwL4uPwfcrkKSiwuDeypiVr92qCUFuF3ZENa2zlFVPu+pQcjTlod2LmEX3MhBmNjRMpdKg== + +"@metaplex-foundation/mpl-toolbox@^0.9.0", "@metaplex-foundation/mpl-toolbox@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/mpl-toolbox/-/mpl-toolbox-0.9.4.tgz#2211b2f726b1e5745c03908d26fd8ee580838b6f" + integrity sha512-fd6JxfoLbj/MM8FG2x91KYVy1U6AjBQw4qjt7+Da3trzQaWnSaYHDcYRG/53xqfvZ9qofY1T2t53GXPlD87lnQ== + +"@metaplex-foundation/umi-bundle-defaults@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-bundle-defaults/-/umi-bundle-defaults-1.2.0.tgz#5f895cd3c9bbcd374a22733a2248654d4589d481" + integrity sha512-xbBxnvsADoC/L40HOvWWnrfE1q+7FCSwZ+LsYi3dWn8A93FhcI2gpxZ+Uqy+LzHDmGmuipdECbTRFdSBLMulBA== + dependencies: + "@metaplex-foundation/umi-downloader-http" "^1.2.0" + "@metaplex-foundation/umi-eddsa-web3js" "^1.0.1" + "@metaplex-foundation/umi-http-fetch" "^1.2.0" + "@metaplex-foundation/umi-program-repository" "^1.2.0" + "@metaplex-foundation/umi-rpc-chunk-get-accounts" "^1.2.0" + "@metaplex-foundation/umi-rpc-web3js" "^1.2.0" + "@metaplex-foundation/umi-serializer-data-view" "^1.2.0" + "@metaplex-foundation/umi-transaction-factory-web3js" "^1.2.0" + +"@metaplex-foundation/umi-downloader-http@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-downloader-http/-/umi-downloader-http-1.2.0.tgz#067c57e71ac4d7d14736776374e60164c58a7438" + integrity sha512-voEu9BFePmPGkucZCIVDOGkkvBMuzkeHjkvmSP3E2i0YT5299HryR8sr7i9G4uNwKF/FIVdTw1qQnW61cpS2qQ== + +"@metaplex-foundation/umi-eddsa-web3js@^1.0.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-eddsa-web3js/-/umi-eddsa-web3js-1.1.1.tgz#a60ed2461c7f7c2a96d048cf7183a3b1faa308a1" + integrity sha512-rL22HATY7W02DqJLdBKZ8jedhMtd7iKReIFNPXLGnVeUpDwxXaqWPySZxZ+2TjY6f+Idoq2g2TpPCUGND/iOeA== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "1.1.1" + "@noble/curves" "^1.0.0" + yaml "^2.7.0" + +"@metaplex-foundation/umi-http-fetch@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-http-fetch/-/umi-http-fetch-1.2.0.tgz#109b7a1f5dc6deff61baa932a5de26a695117508" + integrity sha512-rbM97PPCAmjbR90wnSCTxJFkCUIKR++gS5lIm+ZNZ96XrjvOrFURZpSYloyDGvXRNgF44eTYWDYIDLy5zmI2JQ== + dependencies: + node-fetch "^2.6.7" + +"@metaplex-foundation/umi-options@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-options/-/umi-options-1.2.0.tgz#934fae509b15de9a02d8c06315a7fc24defe35bd" + integrity sha512-dNEfhDg9PUoosU46SnmB8PzdhgAF7qJ0RUkn5keLKU2s0Xy2DKZVtdaELTfMZZckhaDvOzRTKdphTRrEwIjbyw== + +"@metaplex-foundation/umi-program-repository@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-program-repository/-/umi-program-repository-1.2.0.tgz#c770fbe20dc491118bab94436a5fb5766c17b600" + integrity sha512-mbsE0BPmqv3cMfk/jn+EKoUDJHbUieFcp8o2eRSkVBJhjXqkfLJgJ8s3koBn8vv5mcmavEBDqPYNqJQs93je0g== + +"@metaplex-foundation/umi-public-keys@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-public-keys/-/umi-public-keys-1.2.0.tgz#ce970035b0975ca6728cc85dd084163b328898e8" + integrity sha512-UZISKLcrsAQ3M17JCkNIXtacoKHpSNEgXHGcxyJp7zfJkdLDq5Qlvd7KeyZoYC7A7XuA3lAlVY14qhhIwC5p5w== + dependencies: + "@metaplex-foundation/umi-serializers-encodings" "^1.2.0" + +"@metaplex-foundation/umi-rpc-chunk-get-accounts@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-rpc-chunk-get-accounts/-/umi-rpc-chunk-get-accounts-1.2.0.tgz#46ce2b03ee6f7c106d178104c5a3579bbd58ed83" + integrity sha512-j5eSFmilDxIjw/uudZh6cvwIpwwp1vjW0XBFB7SLCDzsAHn4SaEq2j+Xwn3cvjKLBB0haJqHlMG9x35gXqBkqg== + +"@metaplex-foundation/umi-rpc-web3js@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-rpc-web3js/-/umi-rpc-web3js-1.2.0.tgz#5f664628756d0f7ca4a92aa14640e23433eb33e4" + integrity sha512-nMWJA/v8gnhA3D2iBHSHWyS02YAL9zIhE8gxWufk56GY1fTo/jBp8HQrxI4PZH0E8A1fGnBZSU0SkL4lRm7Ljw== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "^1.2.0" + +"@metaplex-foundation/umi-serializer-data-view@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-serializer-data-view/-/umi-serializer-data-view-1.2.0.tgz#1f0794537f651a8ea8c1f3a24d447ef63a79da4b" + integrity sha512-3w9WQzfrq851cIyvzcbEslJEL4oah3r/9Y/A2zyUwCsri5/3s/G0CcHgHPaS6/cvpyYybqBJjyJKMcGiVxzs8Q== + +"@metaplex-foundation/umi-serializers-core@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-serializers-core/-/umi-serializers-core-1.2.0.tgz#6efd22ac44f8f531f8decfcb3ed3a4c843a62004" + integrity sha512-9scqhjkjW8tJ+/q1veh73jQjo9vvgTN5iN4OfOYFMtFVTT8/y2AVxGmniV/DbQC5wIgx7WTZkAnJmqOMs2904Q== + +"@metaplex-foundation/umi-serializers-encodings@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-serializers-encodings/-/umi-serializers-encodings-1.2.0.tgz#59283ccd7c364e8ed701d61484e7361a9c22bd4f" + integrity sha512-Yo3TPI9ei8Z5eTJ1UeT12+pYaQ1zMSn57/M/3r4WAOTFtTCOuKsDRKg8eBQCpBuffH8yGUbRs0poy1n25IzeNg== + dependencies: + "@metaplex-foundation/umi-serializers-core" "^1.2.0" + +"@metaplex-foundation/umi-serializers-numbers@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-serializers-numbers/-/umi-serializers-numbers-1.2.0.tgz#9d9b3af100b3026311731947954d9f53d814bc62" + integrity sha512-ZBVb498GHYlfB+1JzOcczJ1LrCYWr0IiiXjeEAf+64mSSp3IFwK7D3rjL6RZ05bjxBzuWDJVRzI+mFVFC9UgtQ== + dependencies: + "@metaplex-foundation/umi-serializers-core" "^1.2.0" + +"@metaplex-foundation/umi-serializers@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-serializers/-/umi-serializers-1.2.0.tgz#1038d609cc2a5037c210e4d96760b317eff9e931" + integrity sha512-7ivgqVP6ZouN13EBN5aMirjoX2x0Ja7IuzrBeIa8YYrxGcy7YQp+fUj4YCPtMClzsETgJ5jL8EZnZPpZX4dxaQ== + dependencies: + "@metaplex-foundation/umi-options" "^1.2.0" + "@metaplex-foundation/umi-public-keys" "^1.2.0" + "@metaplex-foundation/umi-serializers-core" "^1.2.0" + "@metaplex-foundation/umi-serializers-encodings" "^1.2.0" + "@metaplex-foundation/umi-serializers-numbers" "^1.2.0" + +"@metaplex-foundation/umi-signer-wallet-adapters@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-signer-wallet-adapters/-/umi-signer-wallet-adapters-1.2.0.tgz#aa1baea38e3e75a2cc0e4d711df3ff43bac18ea8" + integrity sha512-HwC73FQr6NBRkLiW3ksjDaGpWPSxmiiyXuVksG/WMBxB+jVfeh+CqgOlxqvnOjN96M+Y3apKnPNUQvbSNbgkog== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "^1.2.0" + +"@metaplex-foundation/umi-transaction-factory-web3js@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-transaction-factory-web3js/-/umi-transaction-factory-web3js-1.2.0.tgz#c595ed6520162e00ffe45c150e4fc59b0bd32c03" + integrity sha512-CDpx6KSYOEonWsHJEVUfZTzu3g0ElclUNgeAXhLyKzimS1fd7FvAkbFom6egQz6ZPuqGv/5ZTHQv37UxoGy+Zg== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "^1.2.0" + +"@metaplex-foundation/umi-web3js-adapters@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-web3js-adapters/-/umi-web3js-adapters-1.1.1.tgz#5afc9568ea3c4811ff5b1cbff16462c5eb33200d" + integrity sha512-UXP2aY3ce59nSxsVJ4sFLtGCHpesqLTxTag2yI6grCXe0dEz+1kONMn0XFRLcYgiSKOcptJSoJWbILlHnUsWDg== + dependencies: + buffer "^6.0.3" + +"@metaplex-foundation/umi-web3js-adapters@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi-web3js-adapters/-/umi-web3js-adapters-1.2.0.tgz#6114aed3831d32644e0a14c5c9506707e0446d5e" + integrity sha512-kKfsva8aoHTZXHbet6U/dV/va+hSFoVpqLiKFoUg3HV2Cp5IgdLXo2PH4/iN6AlE+S+a0S3+jt/7gat2rsskuw== + dependencies: + buffer "^6.0.3" + +"@metaplex-foundation/umi@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/umi/-/umi-1.2.0.tgz#905ce9efb4c5baa3ab451cd2ca8545ebdc76b791" + integrity sha512-SIcDO8O9gRYL2C5ntsedVfpRBICK7ZoMB5ap8P5N2TEJ/QC205UxDzhdQsImdWQG1DQ7XJsDXWiiFzccpFZcSg== + dependencies: + "@metaplex-foundation/umi-options" "^1.2.0" + "@metaplex-foundation/umi-public-keys" "^1.2.0" + "@metaplex-foundation/umi-serializers" "^1.2.0" + +"@meteora-ag/dynamic-bonding-curve-sdk@^1.1.1-rc.6": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@meteora-ag/dynamic-bonding-curve-sdk/-/dynamic-bonding-curve-sdk-1.3.1.tgz#a68bb7cebbe811cac760036ff763e0bfbaefc29d" + integrity sha512-qVr4P891xLKgI9pMSv7YqMD6Vg/BuCQd5sDyvuQSokM0zhC+a9WnL9+haxLpnw4IAVXp7fgCB5Nkgvz+ZAKrjw== + dependencies: + "@coral-xyz/anchor" "^0.31.0" + "@solana/spl-token" "^0.4.13" + "@solana/web3.js" "^1.98.0" + bn.js "^5.2.1" + decimal.js "^10.5.0" + +"@mobily/ts-belt@^3.13.1": + version "3.13.1" + resolved "https://registry.yarnpkg.com/@mobily/ts-belt/-/ts-belt-3.13.1.tgz#8f8ce2a2eca41d88c2ca70c84d0f47d0f7f5cd5f" + integrity sha512-K5KqIhPI/EoCTbA6CGbrenM9s41OouyK8A03fGJJcla/zKucsgLbz8HNbeseoLarRPgyWJsUyCYqFhI7t3Ra9Q== + +"@modelcontextprotocol/sdk@^1.10.2": + version "1.16.0" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.16.0.tgz#39a28a4f775778ec90369ddb5ccfb58a5b9b838f" + integrity sha512-8ofX7gkZcLj9H9rSd50mCgm3SSF8C7XoclxJuLoV0Cz3rEQ1tv9MZRYYvJtm9n1BiEQQMzSmE/w2AEkNacLYfg== + dependencies: + ajv "^6.12.6" + content-type "^1.0.5" + cors "^2.8.5" + cross-spawn "^7.0.5" + eventsource "^3.0.2" + eventsource-parser "^3.0.0" + express "^5.0.1" + express-rate-limit "^7.5.0" + pkce-challenge "^5.0.0" + raw-body "^3.0.0" + zod "^3.23.8" + zod-to-json-schema "^3.24.1" + +"@mongodb-js/saslprep@^1.1.9": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.3.0.tgz#75bb770b4b0908047b6c6ac2ec841047660e1c82" + integrity sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ== + dependencies: + sparse-bitfield "^3.0.3" + +"@msgpack/msgpack@^3.0.0-beta2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-3.1.2.tgz#fdd25cc2202297519798bbaf4689152ad9609e19" + integrity sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ== + +"@mswjs/interceptors@^0.39.1": + version "0.39.3" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.39.3.tgz#d27886db295c9a7dbc41aa229a644bc7bbb04723" + integrity sha512-9bw/wBL7pblsnOCIqvn1788S9o4h+cC5HWXg0Xhh0dOzsZ53IyfmBM+FYqpDDPbm0xjCqEqvCITloF3Dm4TXRQ== + dependencies: + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/logger" "^0.3.0" + "@open-draft/until" "^2.0.0" + is-node-process "^1.2.0" + outvariant "^1.4.3" + strict-event-emitter "^0.5.1" + +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + +"@next/env@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.3.0.tgz#ea3a2a02e8023097efa23ec573540f522815e9d4" + integrity sha512-6mDmHX24nWlHOlbwUiAOmMyY7KELimmi+ed8qWcJYjqXeC+G6JzPZ3QosOAfjNwgMIzwhXBiRiCgdh8axTTdTA== + +"@next/mdx@^15.3.2": + version "15.4.2" + resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-15.4.2.tgz#4a4c69e6f2e65332c92c640862bacca3d56393da" + integrity sha512-uh/QbquRl8dtzRDQBtf28ho4fJ37tO2phdN79olomG61ftyjKSazebEz1ri9Fi0mtwSrZTpjKGom7xiYJmwI9Q== + dependencies: + source-map "^0.7.0" + +"@next/swc-darwin-arm64@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.0.tgz#804660ea060920ed9835d079a0af64552771ccf4" + integrity sha512-PDQcByT0ZfF2q7QR9d+PNj3wlNN4K6Q8JoHMwFyk252gWo4gKt7BF8Y2+KBgDjTFBETXZ/TkBEUY7NIIY7A/Kw== + +"@next/swc-darwin-x64@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.0.tgz#0e352c9aee544b18d3e4c138487ecc6aa71469b4" + integrity sha512-m+eO21yg80En8HJ5c49AOQpFDq+nP51nu88ZOMCorvw3g//8g1JSUsEiPSiFpJo1KCTQ+jm9H0hwXK49H/RmXg== + +"@next/swc-linux-arm64-gnu@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.0.tgz#2dbdc7e7234bb56031ede78ad48275f66a09cdce" + integrity sha512-H0Kk04ZNzb6Aq/G6e0un4B3HekPnyy6D+eUBYPJv9Abx8KDYgNMWzKt4Qhj57HXV3sTTjsfc1Trc1SxuhQB+Tg== + +"@next/swc-linux-arm64-musl@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.0.tgz#410143ca5650e366da5483bd5078ba9dfdd96185" + integrity sha512-k8GVkdMrh/+J9uIv/GpnHakzgDQhrprJ/FbGQvwWmstaeFG06nnAoZCJV+wO/bb603iKV1BXt4gHG+s2buJqZA== + +"@next/swc-linux-x64-gnu@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.0.tgz#1db7dc39e528a2de8ba11156585dfc74b4d6e2aa" + integrity sha512-ZMQ9yzDEts/vkpFLRAqfYO1wSpIJGlQNK9gZ09PgyjBJUmg8F/bb8fw2EXKgEaHbCc4gmqMpDfh+T07qUphp9A== + +"@next/swc-linux-x64-musl@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.0.tgz#3f7f0fb55a16d7b87801451555cb929117b8ff88" + integrity sha512-RFwq5VKYTw9TMr4T3e5HRP6T4RiAzfDJ6XsxH8j/ZeYq2aLsBqCkFzwMI0FmnSsLaUbOb46Uov0VvN3UciHX5A== + +"@next/swc-win32-arm64-msvc@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.0.tgz#1eb4ba20beae55d41e02e1780bc45ceabd45550f" + integrity sha512-a7kUbqa/k09xPjfCl0RSVAvEjAkYBYxUzSVAzk2ptXiNEL+4bDBo9wNC43G/osLA/EOGzG4CuNRFnQyIHfkRgQ== + +"@next/swc-win32-x64-msvc@15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.0.tgz#68740dee9831fcd738ab2056438bd3de75712f65" + integrity sha512-vHUQS4YVGJPmpjn7r5lEZuMhK5UQBNBRSB+iGDvJjaNk649pTIcRluDWNb9siunyLLiu/LDPHfvxBtNamyuLTw== + +"@next/third-parties@^15.3.1": + version "15.4.2" + resolved "https://registry.yarnpkg.com/@next/third-parties/-/third-parties-15.4.2.tgz#f430f3788a21de60ccc77f9a55a0b58037460bc5" + integrity sha512-ncm6RqzJnEo+cjILGo4Ql1/qmf0vaB8LpEkDCu5/XpOoNyynkYFC3GGuOTVJGsRQc7FxRQifbh3F+wHUK/5Dtg== + dependencies: + third-party-capital "1.0.20" + +"@ngraveio/bc-ur@^1.0.0", "@ngraveio/bc-ur@^1.1.5": + version "1.1.13" + resolved "https://registry.yarnpkg.com/@ngraveio/bc-ur/-/bc-ur-1.1.13.tgz#27719fd3e745ccdbe97a7950905edcd1fed4844b" + integrity sha512-j73akJMV4+vLR2yQ4AphPIT5HZmxVjn/LxpL7YHoINnXoH6ccc90Zzck6/n6a3bCXOVZwBxq+YHwbAKRV+P8Zg== + dependencies: + "@keystonehq/alias-sampling" "^0.1.1" + assert "^2.0.0" + bignumber.js "^9.0.1" + cbor-sync "^1.0.4" + crc "^3.8.0" + jsbi "^3.1.5" + sha.js "^2.4.11" + +"@noble/ciphers@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.2.1.tgz#3812b72c057a28b44ff0ad4aff5ca846e5b9cdc9" + integrity sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA== + +"@noble/ciphers@1.3.0", "@noble/ciphers@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.3.0.tgz#f64b8ff886c240e644e5573c097f86e5b43676dc" + integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== + +"@noble/curves@1.4.2", "@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/curves@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.0.tgz#fe035a23959e6aeadf695851b51a87465b5ba8f7" + integrity sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ== + dependencies: + "@noble/hashes" "1.7.0" + +"@noble/curves@1.8.1": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.1.tgz#19bc3970e205c99e4bdb1c64a4785706bce497ff" + integrity sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ== + dependencies: + "@noble/hashes" "1.7.1" + +"@noble/curves@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.0.tgz#13e0ca8be4a0ce66c113693a94514e5599f40cfc" + integrity sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/curves@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.2.tgz#73388356ce733922396214a933ff7c95afcef911" + integrity sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/curves@^1.0.0", "@noble/curves@^1.4.2", "@noble/curves@^1.6.0", "@noble/curves@^1.8.0", "@noble/curves@^1.9.1", "@noble/curves@~1.9.0": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.4.tgz#a748c6837ee7854a558cc3b951aedd87a5e7d6a5" + integrity sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/curves@~1.8.1": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" + integrity sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== + dependencies: + "@noble/hashes" "1.7.2" + +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@noble/hashes@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + +"@noble/hashes@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.0.tgz#5d9e33af2c7d04fee35de1519b80c958b2e35e39" + integrity sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w== + +"@noble/hashes@1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.1.tgz#5738f6d765710921e7a751e00c20ae091ed8db0f" + integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ== + +"@noble/hashes@1.7.2", "@noble/hashes@~1.7.1": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" + integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== + +"@noble/hashes@1.8.0", "@noble/hashes@^1.0.0", "@noble/hashes@^1.2.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@^1.5.0", "@noble/hashes@^1.6.1", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@open-draft/deferred-promise@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" + integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA== + +"@open-draft/logger@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954" + integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ== + dependencies: + is-node-process "^1.2.0" + outvariant "^1.4.0" + +"@open-draft/until@^2.0.0", "@open-draft/until@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" + integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== + +"@opentelemetry/api@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== + +"@orama/orama@^3.1.9": + version "3.1.11" + resolved "https://registry.yarnpkg.com/@orama/orama/-/orama-3.1.11.tgz#c9d5b11e70b3bce552b07a88f535932a8c4a8f3b" + integrity sha512-Szki0cgFiXE5F9RLx2lUyEtJllnuCSQ4B8RLDwIjXkVit6qZjoDAxH+xhJs29MjKLDz0tbPLdKFa6QrQ/qoGGA== + +"@particle-network/analytics@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@particle-network/analytics/-/analytics-1.0.2.tgz#cbcff42618e1c3045ed52183278b1a7963ff40a7" + integrity sha512-E4EpTRYcfNOkxj+bgNdQydBrvdLGo4HfVStZCuOr3967dYek30r6L7Nkaa9zJXRE2eGT4lPvcAXDV2WxDZl/Xg== + dependencies: + hash.js "^1.1.7" + uuidv4 "^6.2.13" + +"@particle-network/auth@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@particle-network/auth/-/auth-1.3.1.tgz#f9ee51749e3b10e700e0d8c51a8c0769ab0b9851" + integrity sha512-hu6ie5RjjN4X+6y/vfjyCsSX3pQuS8k8ZoMb61QWwhWsnZXKzpBUVeAEk55aGfxxXY+KfBkSmZosyaZHGoHnfw== + dependencies: + "@particle-network/analytics" "^1.0.1" + "@particle-network/chains" "*" + "@particle-network/crypto" "^1.0.1" + buffer "^6.0.3" + draggabilly "^3.0.0" + +"@particle-network/chains@*": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.8.3.tgz#76d90cb36bf4e1fa72418dfaac6a46abcc1dea9a" + integrity sha512-WgzY2Hp3tpQYBKXF0pOFdCyJ4yekTTOCzBvBt2tvt7Wbzti2bLyRlfGZAoP57TvIMiy1S1oUfasVfM0Dqd6k5w== + +"@particle-network/crypto@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@particle-network/crypto/-/crypto-1.0.1.tgz#26afef622a3eb906dca5c810fef8001ffee29029" + integrity sha512-GgvHmHcFiNkCLZdcJOgctSbgvs251yp+EAdUydOE3gSoIxN6KEr/Snu9DebENhd/nFb7FDk5ap0Hg49P7pj1fg== + dependencies: + crypto-js "^4.1.1" + uuidv4 "^6.2.13" + +"@particle-network/solana-wallet@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@particle-network/solana-wallet/-/solana-wallet-1.3.2.tgz#9966209ccda60abb0114bf0447a524c781536b76" + integrity sha512-KviKVP87OtWq813y8IumM3rIQMNkTjHBaQmCUbTWGebz3csFOv54JIoy1r+3J3NnA+mBxBdZeRedZ5g+07v75w== + dependencies: + "@particle-network/auth" "^1.3.1" + +"@project-serum/anchor@^0.26.0": + version "0.26.0" + resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.26.0.tgz#99e15a3923a5d10514f8185b2d3909e5699d60d5" + integrity sha512-Nq+COIjE1135T7qfnOHEn7E0q39bQTgXLFk837/rgFe6Hkew9WML7eHsS+lSYD2p3OJaTiUOHTAq1lHy36oIqQ== + dependencies: + "@coral-xyz/borsh" "^0.26.0" + "@solana/web3.js" "^1.68.0" + base64-js "^1.5.1" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + js-sha256 "^0.9.0" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + +"@project-serum/sol-wallet-adapter@^0.2.6": + version "0.2.6" + resolved "https://registry.yarnpkg.com/@project-serum/sol-wallet-adapter/-/sol-wallet-adapter-0.2.6.tgz#b4cd25a566294354427c97c26d716112b91a0107" + integrity sha512-cpIb13aWPW8y4KzkZAPDgw+Kb+DXjCC6rZoH74MGm3I/6e/zKyGnfAuW5olb2zxonFqsYgnv7ev8MQnvSgJ3/g== + dependencies: + bs58 "^4.0.1" + eventemitter3 "^4.0.7" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@radix-ui/number@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.1.tgz#7b2c9225fbf1b126539551f5985769d0048d9090" + integrity sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g== + +"@radix-ui/primitive@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.2.tgz#83f415c4425f21e3d27914c12b3272a32e3dae65" + integrity sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA== + +"@radix-ui/react-accordion@^1.2.11": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.2.11.tgz#7837dd4d44aeed56aabad2b098727b8b4f89ae4c" + integrity sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collapsible" "1.1.11" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-arrow@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz#e14a2657c81d961598c5e72b73dd6098acc04f09" + integrity sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + +"@radix-ui/react-avatar@^1.1.7": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz#c58a8800ef3d3ee783b3168fee7c76f6534bfd93" + integrity sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog== + dependencies: + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-is-hydrated" "0.1.0" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-collapsible@1.1.11", "@radix-ui/react-collapsible@^1.1.11", "@radix-ui/react-collapsible@^1.1.7": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.11.tgz#a2d132d5baa6f14551f15b1fff29f925cae46b83" + integrity sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-collection@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.7.tgz#d05c25ca9ac4695cc19ba91f42f686e3ea2d9aec" + integrity sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + +"@radix-ui/react-compose-refs@1.1.2", "@radix-ui/react-compose-refs@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" + integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== + +"@radix-ui/react-context@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.2.tgz#61628ef269a433382c364f6f1e3788a6dc213a36" + integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA== + +"@radix-ui/react-dialog@^1.1.10", "@radix-ui/react-dialog@^1.1.14", "@radix-ui/react-dialog@^1.1.6": + version "1.1.14" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz#4c69c80c258bc6561398cfce055202ea11075107" + integrity sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-direction@1.1.1", "@radix-ui/react-direction@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.1.tgz#39e5a5769e676c753204b792fbe6cf508e550a14" + integrity sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw== + +"@radix-ui/react-dismissable-layer@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz#429b9bada3672c6895a5d6a642aca6ecaf4f18c3" + integrity sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-escape-keydown" "1.1.1" + +"@radix-ui/react-dropdown-menu@^2.1.10": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz#f507320de8e11bc1e671a6ec0c27a7a89e725131" + integrity sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-menu" "2.1.15" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-focus-guards@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz#4ec9a7e50925f7fb661394460045b46212a33bed" + integrity sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA== + +"@radix-ui/react-focus-scope@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz#dfe76fc103537d80bf42723a183773fd07bfb58d" + integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + +"@radix-ui/react-id@1.1.1", "@radix-ui/react-id@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.1.tgz#1404002e79a03fe062b7e3864aa01e24bd1471f7" + integrity sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-label@^2.1.4": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-2.1.7.tgz#ad959ff9c6e4968d533329eb95696e1ba8ad72ab" + integrity sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + +"@radix-ui/react-menu@2.1.15": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.15.tgz#a1a8f06cab3c309f9998cdbd2b3ad279e42ed483" + integrity sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-popper" "1.2.7" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-roving-focus" "1.1.10" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-navigation-menu@^1.2.13", "@radix-ui/react-navigation-menu@^1.2.6": + version "1.2.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.13.tgz#8d49ce275bf4f49a8642be520074b5a7438a5fb0" + integrity sha512-WG8wWfDiJlSF5hELjwfjSGOXcBR/ZMhBFCGYe8vERpC39CQYZeq1PQ2kaYHdye3V95d06H89KGMsVCIE4LWo3g== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-controllable-state" "1.2.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-use-previous" "1.1.1" + "@radix-ui/react-visually-hidden" "1.2.3" + +"@radix-ui/react-popover@^1.1.14", "@radix-ui/react-popover@^1.1.7": + version "1.1.14" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.14.tgz#5496d1986f0287cdfc77e73f70a887e4cb77ad08" + integrity sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-popper" "1.2.7" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-popper@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.7.tgz#531cf2eebb3d3270d58f7d8136e4517646429978" + integrity sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-use-rect" "1.1.1" + "@radix-ui/react-use-size" "1.1.1" + "@radix-ui/rect" "1.1.1" + +"@radix-ui/react-portal@1.1.9": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz#14c3649fe48ec474ac51ed9f2b9f5da4d91c4472" + integrity sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-presence@1.1.4", "@radix-ui/react-presence@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.4.tgz#253ac0ad4946c5b4a9c66878335f5cf07c967ced" + integrity sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-primitive@2.1.3", "@radix-ui/react-primitive@^2.0.2": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz#db9b8bcff49e01be510ad79893fb0e4cda50f1bc" + integrity sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ== + dependencies: + "@radix-ui/react-slot" "1.2.3" + +"@radix-ui/react-progress@^1.1.4": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-progress/-/react-progress-1.1.7.tgz#a2b76398b3f24b6bd5e37f112b1e30fbedd4f38e" + integrity sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg== + dependencies: + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + +"@radix-ui/react-roving-focus@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz#46030496d2a490c4979d29a7e1252465e51e4b0b" + integrity sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-scroll-area@^1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.9.tgz#90c49bd3231d7f0796d5d12dabc065afa829cf07" + integrity sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A== + dependencies: + "@radix-ui/number" "1.1.1" + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-select@^2.2.2": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.2.5.tgz#9e2fa5b8f4cc99b86ef5bba3cb9b73828afb51f0" + integrity sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA== + dependencies: + "@radix-ui/number" "1.1.1" + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-popper" "1.2.7" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-controllable-state" "1.2.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-use-previous" "1.1.1" + "@radix-ui/react-visually-hidden" "1.2.3" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-slider@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-1.3.5.tgz#f9c074dc0dd2850aa42609e72de74642a4851b79" + integrity sha512-rkfe2pU2NBAYfGaxa3Mqosi7VZEWX5CxKaanRv0vZd4Zhl9fvQrg0VM93dv3xGLGfrHuoTRF3JXH8nb9g+B3fw== + dependencies: + "@radix-ui/number" "1.1.1" + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-use-previous" "1.1.1" + "@radix-ui/react-use-size" "1.1.1" + +"@radix-ui/react-slot@1.2.3", "@radix-ui/react-slot@^1.2.0", "@radix-ui/react-slot@^1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz#502d6e354fc847d4169c3bc5f189de777f68cfe1" + integrity sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + +"@radix-ui/react-switch@^1.2.4": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-1.2.5.tgz#56c15a4cd219e00b0745ec6b2ea1c0feeb0b21d0" + integrity sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + "@radix-ui/react-use-previous" "1.1.1" + "@radix-ui/react-use-size" "1.1.1" + +"@radix-ui/react-tabs@^1.1.12", "@radix-ui/react-tabs@^1.1.7": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz#99b3522c73db9263f429a6d0f5a9acb88df3b129" + integrity sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-roving-focus" "1.1.10" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-toggle-group@^1.1.7": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.10.tgz#4406b3be3869cad497ca7ee4993c3598731f774e" + integrity sha512-kiU694Km3WFLTC75DdqgM/3Jauf3rD9wxeS9XtyWFKsBUeZA337lC+6uUazT7I1DhanZ5gyD5Stf8uf2dbQxOQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-roving-focus" "1.1.10" + "@radix-ui/react-toggle" "1.1.9" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-toggle@1.1.9", "@radix-ui/react-toggle@^1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.1.9.tgz#9cb99a29bc7cd15186ba3ba797808a013a726fba" + integrity sha512-ZoFkBBz9zv9GWer7wIjvdRxmh2wyc2oKWw6C6CseWd6/yq1DK/l5lJ+wnsmFwJZbBYqr02mrf8A2q/CVCuM3ZA== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-use-callback-ref@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz#62a4dba8b3255fdc5cc7787faeac1c6e4cc58d40" + integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg== + +"@radix-ui/react-use-controllable-state@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz#905793405de57d61a439f4afebbb17d0645f3190" + integrity sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg== + dependencies: + "@radix-ui/react-use-effect-event" "0.0.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-effect-event@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz#090cf30d00a4c7632a15548512e9152217593907" + integrity sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-escape-keydown@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz#b3fed9bbea366a118f40427ac40500aa1423cc29" + integrity sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g== + dependencies: + "@radix-ui/react-use-callback-ref" "1.1.1" + +"@radix-ui/react-use-is-hydrated@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz#544da73369517036c77659d7cdd019dc0f5ff9a0" + integrity sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA== + dependencies: + use-sync-external-store "^1.5.0" + +"@radix-ui/react-use-layout-effect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz#0c4230a9eed49d4589c967e2d9c0d9d60a23971e" + integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ== + +"@radix-ui/react-use-previous@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz#1a1ad5568973d24051ed0af687766f6c7cb9b5b5" + integrity sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ== + +"@radix-ui/react-use-rect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz#01443ca8ed071d33023c1113e5173b5ed8769152" + integrity sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w== + dependencies: + "@radix-ui/rect" "1.1.1" + +"@radix-ui/react-use-size@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz#6de276ffbc389a537ffe4316f5b0f24129405b37" + integrity sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-visually-hidden@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz#a8c38c8607735dc9f05c32f87ab0f9c2b109efbf" + integrity sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + +"@radix-ui/rect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.1.tgz#78244efe12930c56fd255d7923865857c41ac8cb" + integrity sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw== + +"@react-native-async-storage/async-storage@^1.17.7": + version "1.24.0" + resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz#888efbc62a26f7d9464b32f4d3027b7f2771999b" + integrity sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g== + dependencies: + merge-options "^3.0.4" + +"@reown/appkit-common@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-common/-/appkit-common-1.7.2.tgz#31f809095b4f1b97fb4951acd92d75e80b612e1e" + integrity sha512-DZkl3P5+Iw3TmsitWmWxYbuSCox8iuzngNp/XhbNDJd7t4Cj4akaIUxSEeCajNDiGHlu4HZnfyM1swWsOJ0cOw== + dependencies: + big.js "6.2.2" + dayjs "1.11.13" + viem ">=2.23.11" + +"@reown/appkit-controllers@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-controllers/-/appkit-controllers-1.7.2.tgz#d3e5a22716d4273147d7309f4e0d4fbc8dddc64b" + integrity sha512-KCN/VOg+bgwaX5kcxcdN8Xq8YXnchMeZOvmbCltPEFDzaLRUWmqk9tNu1OVml0434iGMNo6hcVimIiwz6oaL3Q== + dependencies: + "@reown/appkit-common" "1.7.2" + "@reown/appkit-wallet" "1.7.2" + "@walletconnect/universal-provider" "2.19.1" + valtio "1.13.2" + viem ">=2.23.11" + +"@reown/appkit-polyfills@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-polyfills/-/appkit-polyfills-1.7.2.tgz#8be1bc5b6cb1b87785c844524aecba443724104b" + integrity sha512-TxCVSh9dV2tf1u+OzjzLjAwj7WHhBFufHlJ36tDp5vjXeUUne8KvYUS85Zsyg4Y9Yeh+hdSIOdL2oDCqlRxCmw== + dependencies: + buffer "6.0.3" + +"@reown/appkit-scaffold-ui@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.7.2.tgz#485758b89f141a2a5ec458583f71c4215141b627" + integrity sha512-2Aifk5d23e40ijUipsN3qAMIB1Aphm2ZgsRQ+UvKRb838xR1oRs+MOsfDWgXhnccXWKbjPqyapZ25eDFyPYPNw== + dependencies: + "@reown/appkit-common" "1.7.2" + "@reown/appkit-controllers" "1.7.2" + "@reown/appkit-ui" "1.7.2" + "@reown/appkit-utils" "1.7.2" + "@reown/appkit-wallet" "1.7.2" + lit "3.1.0" + +"@reown/appkit-ui@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-ui/-/appkit-ui-1.7.2.tgz#80e3bfaa6735298184d11f66860a996caa82a948" + integrity sha512-fZv8K7Df6A/TlTIWD/9ike1HwK56WfzYpHN1/yqnR/BnyOb3CKroNQxmRTmjeLlnwKWkltlOf3yx+Y6ucKMk6Q== + dependencies: + "@reown/appkit-common" "1.7.2" + "@reown/appkit-controllers" "1.7.2" + "@reown/appkit-wallet" "1.7.2" + lit "3.1.0" + qrcode "1.5.3" + +"@reown/appkit-utils@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-utils/-/appkit-utils-1.7.2.tgz#d3255d2ee876ce05d0c13cd082627beb72620e3d" + integrity sha512-Z3gQnMPQopBdf1XEuptbf+/xVl9Hy0+yoK3K9pBb2hDdYNqJgJ4dXComhlRT8LjXFCQe1ZW0pVZTXmGQvOZ/OQ== + dependencies: + "@reown/appkit-common" "1.7.2" + "@reown/appkit-controllers" "1.7.2" + "@reown/appkit-polyfills" "1.7.2" + "@reown/appkit-wallet" "1.7.2" + "@walletconnect/logger" "2.1.2" + "@walletconnect/universal-provider" "2.19.1" + valtio "1.13.2" + viem ">=2.23.11" + +"@reown/appkit-wallet@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit-wallet/-/appkit-wallet-1.7.2.tgz#02fce896c78ed83ea575256306396a42c58ec646" + integrity sha512-WQ0ykk5TwsjOcUL62ajT1bhZYdFZl0HjwwAH9LYvtKYdyZcF0Ps4+y2H4HHYOc03Q+LKOHEfrFztMBLXPTxwZA== + dependencies: + "@reown/appkit-common" "1.7.2" + "@reown/appkit-polyfills" "1.7.2" + "@walletconnect/logger" "2.1.2" + zod "3.22.4" + +"@reown/appkit@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@reown/appkit/-/appkit-1.7.2.tgz#71b253fc4bee5579bc720cbcb63c8f037a9ba4c8" + integrity sha512-oo/evAyVxwc33i8ZNQ0+A/VE6vyTyzL3NBJmAe3I4vobgQeiobxMM0boKyLRMMbJggPn8DtoAAyG4GfpKaUPzQ== + dependencies: + "@reown/appkit-common" "1.7.2" + "@reown/appkit-controllers" "1.7.2" + "@reown/appkit-polyfills" "1.7.2" + "@reown/appkit-scaffold-ui" "1.7.2" + "@reown/appkit-ui" "1.7.2" + "@reown/appkit-utils" "1.7.2" + "@reown/appkit-wallet" "1.7.2" + "@walletconnect/types" "2.19.1" + "@walletconnect/universal-provider" "2.19.1" + bs58 "6.0.0" + valtio "1.13.2" + viem ">=2.23.11" + +"@scure/base@^1.1.3", "@scure/base@~1.2.2", "@scure/base@~1.2.4", "@scure/base@~1.2.5": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== + +"@scure/base@~1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== + +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== + dependencies: + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip32@1.6.2": + version "1.6.2" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.6.2.tgz#093caa94961619927659ed0e711a6e4bf35bffd0" + integrity sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw== + dependencies: + "@noble/curves" "~1.8.1" + "@noble/hashes" "~1.7.1" + "@scure/base" "~1.2.2" + +"@scure/bip32@1.7.0", "@scure/bip32@^1.3.1", "@scure/bip32@^1.5.0", "@scure/bip32@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" + integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== + dependencies: + "@noble/curves" "~1.9.0" + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip39@1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.5.4.tgz#07fd920423aa671be4540d59bdd344cc1461db51" + integrity sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA== + dependencies: + "@noble/hashes" "~1.7.1" + "@scure/base" "~1.2.4" + +"@scure/bip39@1.6.0", "@scure/bip39@^1.2.1", "@scure/bip39@^1.4.0", "@scure/bip39@^1.5.1", "@scure/bip39@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" + integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== + dependencies: + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + +"@shikijs/core@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-3.8.1.tgz#4ae50865a40292119d58254c46be40dd59d54888" + integrity sha512-uTSXzUBQ/IgFcUa6gmGShCHr4tMdR3pxUiiWKDm8pd42UKJdYhkAYsAmHX5mTwybQ5VyGDgTjW4qKSsRvGSang== + dependencies: + "@shikijs/types" "3.8.1" + "@shikijs/vscode-textmate" "^10.0.2" + "@types/hast" "^3.0.4" + hast-util-to-html "^9.0.5" + +"@shikijs/engine-javascript@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/engine-javascript/-/engine-javascript-3.8.1.tgz#ea1b8bff59c505fbbb725232ff2a48cf419bb88e" + integrity sha512-rZRp3BM1llrHkuBPAdYAzjlF7OqlM0rm/7EWASeCcY7cRYZIrOnGIHE9qsLz5TCjGefxBFnwgIECzBs2vmOyKA== + dependencies: + "@shikijs/types" "3.8.1" + "@shikijs/vscode-textmate" "^10.0.2" + oniguruma-to-es "^4.3.3" + +"@shikijs/engine-oniguruma@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/engine-oniguruma/-/engine-oniguruma-3.8.1.tgz#318a4405c3b524065a163b5adbb10cc5705a3050" + integrity sha512-KGQJZHlNY7c656qPFEQpIoqOuC4LrxjyNndRdzk5WKB/Ie87+NJCF1xo9KkOUxwxylk7rT6nhlZyTGTC4fCe1g== + dependencies: + "@shikijs/types" "3.8.1" + "@shikijs/vscode-textmate" "^10.0.2" + +"@shikijs/langs@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/langs/-/langs-3.8.1.tgz#ebf04cc68e0a4dfbbdaa122042af0c5ad41f1361" + integrity sha512-TjOFg2Wp1w07oKnXjs0AUMb4kJvujML+fJ1C5cmEj45lhjbUXtziT1x2bPQb9Db6kmPhkG5NI2tgYW1/DzhUuQ== + dependencies: + "@shikijs/types" "3.8.1" + +"@shikijs/rehype@^3.3.0", "@shikijs/rehype@^3.7.0": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/rehype/-/rehype-3.8.1.tgz#46162c346897587aabeb4585bdcc082ffe920eb1" + integrity sha512-ERs9IUaORBY8vu3OQfmB1L0nwGey0qhJi3NVSLwl22H+FPIg3dDyi2bHULY7pcyKC2qo5b1yiu5Vf3jp3ZkPvA== + dependencies: + "@shikijs/types" "3.8.1" + "@types/hast" "^3.0.4" + hast-util-to-string "^3.0.1" + shiki "3.8.1" + unified "^11.0.5" + unist-util-visit "^5.0.0" + +"@shikijs/themes@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/themes/-/themes-3.8.1.tgz#41220312a1eab3959f146856a48bca25a4b61231" + integrity sha512-Vu3t3BBLifc0GB0UPg2Pox1naTemrrvyZv2lkiSw3QayVV60me1ujFQwPZGgUTmwXl1yhCPW8Lieesm0CYruLQ== + dependencies: + "@shikijs/types" "3.8.1" + +"@shikijs/transformers@^3.7.0": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/transformers/-/transformers-3.8.1.tgz#794ce2912eaa057ddf3b3b9bff1c833e51143136" + integrity sha512-nmTyFfBrhJk6HJi118jes0wuWdfKXeVUq1Nq+hm8h6wbk1KUfvtg+LY/uDfxZD2VDItHO3QoINIs3NtoKBmgxw== + dependencies: + "@shikijs/core" "3.8.1" + "@shikijs/types" "3.8.1" + +"@shikijs/types@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@shikijs/types/-/types-3.8.1.tgz#6d1d4260ab07597cad7a6fea4933a7b860229c3c" + integrity sha512-5C39Q8/8r1I26suLh+5TPk1DTrbY/kn3IdWA5HdizR0FhlhD05zx5nKCqhzSfDHH3p4S0ZefxWd77DLV+8FhGg== + dependencies: + "@shikijs/vscode-textmate" "^10.0.2" + "@types/hast" "^3.0.4" + +"@shikijs/vscode-textmate@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz#a90ab31d0cc1dfb54c66a69e515bf624fa7b2224" + integrity sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg== + +"@sinclair/typebox@^0.33.7": + version "0.33.22" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.33.22.tgz#3339d85172509095a8384cb4b44834a7c9309d86" + integrity sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ== + +"@socket.io/component-emitter@~3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" + integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== + +"@solana-mobile/mobile-wallet-adapter-protocol-web3js@^2.2.0": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol-web3js/-/mobile-wallet-adapter-protocol-web3js-2.2.2.tgz#3172924d9bcbc983cc1a565a5909e6a2ab612c0c" + integrity sha512-XmLJrEdkAJ3CBV+bkYDKSBqF6QfjGTIeX+tFGPcwcc9rQ68sE1MPhpUKV9ehRwDLrZXcin2UDMOpWB/S6FJWBQ== + dependencies: + "@solana-mobile/mobile-wallet-adapter-protocol" "^2.2.0" + bs58 "^5.0.0" + js-base64 "^3.7.5" + +"@solana-mobile/mobile-wallet-adapter-protocol@^2.2.0": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol/-/mobile-wallet-adapter-protocol-2.2.2.tgz#805ba204e4f910f5f76bc63c28ecd0fdae82c972" + integrity sha512-ZJVwPVXmIfoqEhPRbpj/atnyIkcxOrJcLOqIQSaRfgmGGhCAcXmC8dTxlrtjVisxkZviXEshmBVxvOD/kqLQOw== + dependencies: + "@solana/wallet-standard" "^1.1.2" + "@solana/wallet-standard-util" "^1.1.1" + "@wallet-standard/core" "^1.0.3" + js-base64 "^3.7.5" + +"@solana-mobile/wallet-adapter-mobile@^2.2.0": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@solana-mobile/wallet-adapter-mobile/-/wallet-adapter-mobile-2.2.2.tgz#8c2d6342c25e957aa46ae9a8a255a511370cdaeb" + integrity sha512-4whHagJRduFDWUjLi1kQc4k7LKPjnDn+mLigAd/cv9iPjk0NYNtQOqdGMT+5ENRm3q1XX3DO5jBVd++ckDPJvw== + dependencies: + "@solana-mobile/mobile-wallet-adapter-protocol-web3js" "^2.2.0" + "@solana-mobile/wallet-standard-mobile" "^0.2.0" + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/wallet-standard-features" "^1.2.0" + js-base64 "^3.7.5" + optionalDependencies: + "@react-native-async-storage/async-storage" "^1.17.7" + +"@solana-mobile/wallet-standard-mobile@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@solana-mobile/wallet-standard-mobile/-/wallet-standard-mobile-0.2.0.tgz#805c732204c36736048d3631b6c3b1a48253e47c" + integrity sha512-vAv95mID0682O8wLMzsbnMzfwL8EBtJVUOQiywjnwuTxMlYhSdjp0jJw05Otm/j9N1lbkZ9tbgANGHHL8wRmjw== + dependencies: + "@solana-mobile/mobile-wallet-adapter-protocol-web3js" "^2.2.0" + "@solana/wallet-standard-chains" "^1.1.0" + "@solana/wallet-standard-features" "^1.2.0" + "@wallet-standard/base" "^1.0.1" + "@wallet-standard/features" "^1.0.3" + bs58 "^5.0.0" + js-base64 "^3.7.5" + qrcode "^1.5.4" + +"@solana-program/compute-budget@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz#0930aca4de1170ed607d64d89375074930aa8b93" + integrity sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ== + +"@solana-program/stake@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@solana-program/stake/-/stake-0.2.1.tgz#cc3367e5aa0258fa6599658b0ed48b02f86487a2" + integrity sha512-ssNPsJv9XHaA+L7ihzmWGYcm/+XYURQ8UA3wQMKf6ccEHyHOUgoglkkDU/BoA0+wul6HxZUN0tHFymC0qFw6sg== + +"@solana-program/system@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@solana-program/system/-/system-0.7.0.tgz#3e21c9fb31d3795eb65ba5cb663947c19b305bad" + integrity sha512-FKTBsKHpvHHNc1ATRm7SlC5nF/VdJtOSjldhcyfMN9R7xo712Mo2jHIzvBgn8zQO5Kg0DcWuKB7268Kv1ocicw== + +"@solana-program/token-2022@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@solana-program/token-2022/-/token-2022-0.4.2.tgz#f90a638de82acb7933a114e884a24ac4be8ef635" + integrity sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw== + +"@solana-program/token@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@solana-program/token/-/token-0.5.1.tgz#10e327df23f05a7f892fd33a9b6418f17dd62296" + integrity sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag== + +"@solana/accounts@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/accounts/-/accounts-2.3.0.tgz#957360edd572c1294772ee0eae3abd598189b16e" + integrity sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/rpc-spec" "2.3.0" + "@solana/rpc-types" "2.3.0" + +"@solana/addresses@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/addresses/-/addresses-2.3.0.tgz#d89cba142819f01905a4bf30a1b990a1b55e490d" + integrity sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA== + dependencies: + "@solana/assertions" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/nominal-types" "2.3.0" + +"@solana/assertions@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/assertions/-/assertions-2.3.0.tgz#f96f655088dea6fe9f79604da7615c745c64173b" + integrity sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ== + dependencies: + "@solana/errors" "2.3.0" + +"@solana/buffer-layout-utils@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" + integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/web3.js" "^1.32.0" + bigint-buffer "^1.1.5" + bignumber.js "^9.0.1" + +"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/codecs-core@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz#1a2d76b9c7b9e7b7aeb3bd78be81c2ba21e3ce22" + integrity sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ== + dependencies: + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-core@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.3.0.tgz#6bf2bb565cb1ae880f8018635c92f751465d8695" + integrity sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw== + dependencies: + "@solana/errors" "2.3.0" + +"@solana/codecs-data-structures@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz#d47b2363d99fb3d643f5677c97d64a812982b888" + integrity sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-data-structures@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz#ae4ea2b3177d79a95fdcde20c04fde93b9fd190d" + integrity sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/codecs-numbers@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz#f34978ddf7ea4016af3aaed5f7577c1d9869a614" + integrity sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-numbers@2.3.0", "@solana/codecs-numbers@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz#ac7e7f38aaf7fcd22ce2061fbdcd625e73828dc6" + integrity sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/codecs-strings@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz#e1d9167075b8c5b0b60849f8add69c0f24307018" + integrity sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-strings@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz#1b3a855dcd260283a732060aa6220f78b41251ae" + integrity sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/codecs@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-rc.1.tgz#146dc5db58bd3c28e04b4c805e6096c2d2a0a875" + integrity sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/options" "2.0.0-rc.1" + +"@solana/codecs@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.3.0.tgz#75ea5811e2792d7344409b83ffbfd1d096292e36" + integrity sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/codecs-data-structures" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/options" "2.3.0" + +"@solana/errors@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-rc.1.tgz#3882120886eab98a37a595b85f81558861b29d62" + integrity sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + +"@solana/errors@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.3.0.tgz#4ac9380343dbeffb9dffbcb77c28d0e457c5fa31" + integrity sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ== + dependencies: + chalk "^5.4.1" + commander "^14.0.0" + +"@solana/fast-stable-stringify@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz#723b94e373952bad4549bdd2318f79f46313d85a" + integrity sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw== + +"@solana/functional@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/functional/-/functional-2.3.0.tgz#ac33815655e954bb78151446a571bc6c9fd9be28" + integrity sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q== + +"@solana/instructions@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/instructions/-/instructions-2.3.0.tgz#ff25cbe545000a33fb3604d83f4e2b683de94ad3" + integrity sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/keys@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/keys/-/keys-2.3.0.tgz#9d0b0ec09c2789a051b4df1945ed52631261186e" + integrity sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ== + dependencies: + "@solana/assertions" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/nominal-types" "2.3.0" + +"@solana/kit@^2.1.1": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/kit/-/kit-2.3.0.tgz#92deb7c4883293617209aecac9a43d5e41ccf092" + integrity sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ== + dependencies: + "@solana/accounts" "2.3.0" + "@solana/addresses" "2.3.0" + "@solana/codecs" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/instructions" "2.3.0" + "@solana/keys" "2.3.0" + "@solana/programs" "2.3.0" + "@solana/rpc" "2.3.0" + "@solana/rpc-parsed-types" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + "@solana/rpc-subscriptions" "2.3.0" + "@solana/rpc-types" "2.3.0" + "@solana/signers" "2.3.0" + "@solana/sysvars" "2.3.0" + "@solana/transaction-confirmation" "2.3.0" + "@solana/transaction-messages" "2.3.0" + "@solana/transactions" "2.3.0" + +"@solana/nominal-types@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/nominal-types/-/nominal-types-2.3.0.tgz#b67637241b4a45c756464e049c7a830880b6e944" + integrity sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA== + +"@solana/options@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-rc.1.tgz#06924ba316dc85791fc46726a51403144a85fc4d" + integrity sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/options@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.3.0.tgz#f8a967b9ebae703b2c8adb8f4294df303ab866e8" + integrity sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/codecs-data-structures" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/programs@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/programs/-/programs-2.3.0.tgz#344193a0a4443217c177e2ec21bac7bc52afe4da" + integrity sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/promises@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/promises/-/promises-2.3.0.tgz#ae3fc000f4aef65561d9e4f9724d4635ed042750" + integrity sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ== + +"@solana/rpc-api@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-api/-/rpc-api-2.3.0.tgz#c6e5f7353910bd7c7d2f8a6d4dab44d080bd313a" + integrity sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/keys" "2.3.0" + "@solana/rpc-parsed-types" "2.3.0" + "@solana/rpc-spec" "2.3.0" + "@solana/rpc-transformers" "2.3.0" + "@solana/rpc-types" "2.3.0" + "@solana/transaction-messages" "2.3.0" + "@solana/transactions" "2.3.0" + +"@solana/rpc-parsed-types@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz#132b03f6b4c1b4688336ad48e76c2eea0d8c91d7" + integrity sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg== + +"@solana/rpc-spec-types@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz#010ea9de2f720e84bec2b93ca77ad3664b77235f" + integrity sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ== + +"@solana/rpc-spec@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz#2b679eb750c0f9270da6d451ea1bdc2c7783eb42" + integrity sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw== + dependencies: + "@solana/errors" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + +"@solana/rpc-subscriptions-api@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz#e779b8ad10e89b2f4a4ccb0fcd1a722d8bdd7729" + integrity sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/keys" "2.3.0" + "@solana/rpc-subscriptions-spec" "2.3.0" + "@solana/rpc-transformers" "2.3.0" + "@solana/rpc-types" "2.3.0" + "@solana/transaction-messages" "2.3.0" + "@solana/transactions" "2.3.0" + +"@solana/rpc-subscriptions-channel-websocket@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz#11352ed281eccfa89a782a1b27444613ebeacca4" + integrity sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw== + dependencies: + "@solana/errors" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/rpc-subscriptions-spec" "2.3.0" + "@solana/subscribable" "2.3.0" + +"@solana/rpc-subscriptions-spec@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz#a718a4ea97f57ed62291526b70740a42d576fada" + integrity sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg== + dependencies: + "@solana/errors" "2.3.0" + "@solana/promises" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + "@solana/subscribable" "2.3.0" + +"@solana/rpc-subscriptions@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz#12639c17603e1a30113825350ddbfc3b50b6a031" + integrity sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg== + dependencies: + "@solana/errors" "2.3.0" + "@solana/fast-stable-stringify" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/promises" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + "@solana/rpc-subscriptions-api" "2.3.0" + "@solana/rpc-subscriptions-channel-websocket" "2.3.0" + "@solana/rpc-subscriptions-spec" "2.3.0" + "@solana/rpc-transformers" "2.3.0" + "@solana/rpc-types" "2.3.0" + "@solana/subscribable" "2.3.0" + +"@solana/rpc-transformers@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz#e008d2782047d574dbc74985c6cce26d7c3555f3" + integrity sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA== + dependencies: + "@solana/errors" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/nominal-types" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + "@solana/rpc-types" "2.3.0" + +"@solana/rpc-transport-http@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz#581601b9579b2a7fed9e0cb6fbcb95b4186e5b49" + integrity sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg== + dependencies: + "@solana/errors" "2.3.0" + "@solana/rpc-spec" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + undici-types "^7.11.0" + +"@solana/rpc-types@2.3.0", "@solana/rpc-types@^2.1.1": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc-types/-/rpc-types-2.3.0.tgz#38adf5cb1c79c08086bd672edf7a56d19581d19f" + integrity sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/nominal-types" "2.3.0" + +"@solana/rpc@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/rpc/-/rpc-2.3.0.tgz#a65919520d14c122625fb887a2d72c95bf8691cf" + integrity sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ== + dependencies: + "@solana/errors" "2.3.0" + "@solana/fast-stable-stringify" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/rpc-api" "2.3.0" + "@solana/rpc-spec" "2.3.0" + "@solana/rpc-spec-types" "2.3.0" + "@solana/rpc-transformers" "2.3.0" + "@solana/rpc-transport-http" "2.3.0" + "@solana/rpc-types" "2.3.0" + +"@solana/signers@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/signers/-/signers-2.3.0.tgz#94569a7fb025a3f473661078fbca15b34ceacf94" + integrity sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/instructions" "2.3.0" + "@solana/keys" "2.3.0" + "@solana/nominal-types" "2.3.0" + "@solana/transaction-messages" "2.3.0" + "@solana/transactions" "2.3.0" + +"@solana/spl-token-group@^0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.7.tgz#83c00f0cd0bda33115468cd28b89d94f8ec1fee4" + integrity sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + +"@solana/spl-token-metadata@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.6.tgz#d240947aed6e7318d637238022a7b0981b32ae80" + integrity sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + +"@solana/spl-token@^0.4.13": + version "0.4.13" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.13.tgz#8f65c3c2b315e1a00a91b8d0f60922c6eb71de62" + integrity sha512-cite/pYWQZZVvLbg5lsodSovbetK/eA24gaR0eeUeMuBAMNrT8XFCwaygKy0N2WSg3gSyjjNpIeAGBAKZaY/1w== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.7" + "@solana/spl-token-metadata" "^0.1.6" + buffer "^6.0.3" + +"@solana/subscribable@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/subscribable/-/subscribable-2.3.0.tgz#4e48f1a4eeb1ccf22065b46fb8e3ed80d1a27f80" + integrity sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og== + dependencies: + "@solana/errors" "2.3.0" + +"@solana/sysvars@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/sysvars/-/sysvars-2.3.0.tgz#eeea82f89716682014e801de5870344ddd02becd" + integrity sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA== + dependencies: + "@solana/accounts" "2.3.0" + "@solana/codecs" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/rpc-types" "2.3.0" + +"@solana/transaction-confirmation@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz#f66e70334d797b5010b4ae27dc59de2f90b8ebe6" + integrity sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/keys" "2.3.0" + "@solana/promises" "2.3.0" + "@solana/rpc" "2.3.0" + "@solana/rpc-subscriptions" "2.3.0" + "@solana/rpc-types" "2.3.0" + "@solana/transaction-messages" "2.3.0" + "@solana/transactions" "2.3.0" + +"@solana/transaction-messages@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz#e2a9c2f5565c7cc720aa09816aa3c17fb79c2abc" + integrity sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-data-structures" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/instructions" "2.3.0" + "@solana/nominal-types" "2.3.0" + "@solana/rpc-types" "2.3.0" + +"@solana/transactions@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/transactions/-/transactions-2.3.0.tgz#fc99f6ce6cc5706f2b8116bbf8a2f396c3ec3177" + integrity sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug== + dependencies: + "@solana/addresses" "2.3.0" + "@solana/codecs-core" "2.3.0" + "@solana/codecs-data-structures" "2.3.0" + "@solana/codecs-numbers" "2.3.0" + "@solana/codecs-strings" "2.3.0" + "@solana/errors" "2.3.0" + "@solana/functional" "2.3.0" + "@solana/instructions" "2.3.0" + "@solana/keys" "2.3.0" + "@solana/nominal-types" "2.3.0" + "@solana/rpc-types" "2.3.0" + "@solana/transaction-messages" "2.3.0" + +"@solana/wallet-adapter-alpha@^0.1.14": + version "0.1.14" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-alpha/-/wallet-adapter-alpha-0.1.14.tgz#52dcfdb048d77b1c0f04a133920fb762ee22f1b2" + integrity sha512-ZSEvQmTdkiXPeHWIHbvdU4yDC5PfyTqG/1ZKIf2Uo6c+HslMkYer7mf9HUqJJ80dU68XqBbzBlIv34LCDVWijw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-avana@^0.1.17": + version "0.1.17" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-avana/-/wallet-adapter-avana-0.1.17.tgz#e4ffaf5f6db440940decec81ed55201149375f68" + integrity sha512-I3h+dPWVTEylOWoY2qxyI7mhcn3QNL+tkYLrZLi3+PBaoz79CVIVFi3Yb4NTKYDP+hz7/Skm/ZsomSY5SJua5A== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-base-ui@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base-ui/-/wallet-adapter-base-ui-0.1.6.tgz#29036bede9e993a921727279b9262057e640fbbe" + integrity sha512-OuxLBOXA2z3dnmuGP0agEb7xhsT3+Nttd+gAkSLgJRX2vgNEAy3Fvw8IKPXv1EE2vRdw/U6Rq0Yjpp3McqVZhw== + dependencies: + "@solana/wallet-adapter-react" "^0.15.39" + +"@solana/wallet-adapter-base@^0.9.17", "@solana/wallet-adapter-base@^0.9.23", "@solana/wallet-adapter-base@^0.9.25", "@solana/wallet-adapter-base@^0.9.27": + version "0.9.27" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.27.tgz#f76463db172ac1d7d1f5aa064800363777731dfd" + integrity sha512-kXjeNfNFVs/NE9GPmysBRKQ/nf+foSaq3kfVSeMcO/iVgigyRmB551OjU3WyAolLG/1jeEfKLqF9fKwMCRkUqg== + dependencies: + "@solana/wallet-standard-features" "^1.3.0" + "@wallet-standard/base" "^1.1.0" + "@wallet-standard/features" "^1.1.0" + eventemitter3 "^5.0.1" + +"@solana/wallet-adapter-bitkeep@^0.3.24": + version "0.3.24" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-bitkeep/-/wallet-adapter-bitkeep-0.3.24.tgz#83a502def815d00b0d84b640413020db339b8107" + integrity sha512-LQvS9pr/Qm95w8XFAvxqgYKVndgifwlQYV1+Exc0XMnbxpw40blMTMKxSfiiPq78e3Zi2XWRApQyqtFUafOK5g== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-bitpie@^0.5.22": + version "0.5.22" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-bitpie/-/wallet-adapter-bitpie-0.5.22.tgz#7b0d94531aa59405d323c1f6818c2fec126525df" + integrity sha512-S1dSg041f8CKqzy7HQy/BPhY56ZZiZeanmdx4S6fMDpf717sgkCa7jBjLFtx8ugZzO/VpYQJtRXtKEtHpx0X0A== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-clover@^0.4.23": + version "0.4.23" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-clover/-/wallet-adapter-clover-0.4.23.tgz#5483a8e6197439013334eea7d10bea17cafd806d" + integrity sha512-0PIAP0g1CmSLyphwXLHjePpKiB1dg+veWIbkziIdLHwSsLq6aBr2FimC/ljrbtqrduL1bH7sphNZOGE0IF0JtQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-coin98@^0.5.24": + version "0.5.24" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-coin98/-/wallet-adapter-coin98-0.5.24.tgz#77e5e9d9c9cd9734eadd836cbe25010fc2e71ca1" + integrity sha512-lEHk2L00PitymreyACv5ShGyyeG/NLhryohcke4r/8yDL3m2XTOeyzkhd1/6mDWavMhno1WNivHxByNHDSQhEw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + bs58 "^6.0.0" + buffer "^6.0.3" + +"@solana/wallet-adapter-coinbase@^0.1.23": + version "0.1.23" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-coinbase/-/wallet-adapter-coinbase-0.1.23.tgz#8a395c519dd1d036ae7e4f90cc8a4d381f06e9cf" + integrity sha512-vCJi/clbq1VVgydPFnHGAc2jdEhDAClYmhEAR4RJp9UHBg+MEQUl1WW8PVIREY5uOzJHma0qEiyummIfyt0b4A== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-coinhub@^0.3.22": + version "0.3.22" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-coinhub/-/wallet-adapter-coinhub-0.3.22.tgz#a37ce5a336f5db7044389a9a656fbde8eed0b4a0" + integrity sha512-an/0FyUIY5xWfPYcOxjaVV11IbCCeErURbw+nHyWV89kw/CuiaYwaWXxATGdj8XJjg/UPsPbiLAGyKkdOMjjfw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-fractal@^0.1.12": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-fractal/-/wallet-adapter-fractal-0.1.12.tgz#8ba6d6b52dab8f6f519f23e1533cb2a46d876c02" + integrity sha512-gu9deyHxwrRfBt6VqaCVIN7FmViZn47NwORuja4wc95OX2ZxsjGE6hEs1bJsfy7uf/CsUjwDe1V309r7PlKz8g== + dependencies: + "@fractalwagmi/solana-wallet-adapter" "^0.1.1" + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-huobi@^0.1.19": + version "0.1.19" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-huobi/-/wallet-adapter-huobi-0.1.19.tgz#3747c2c2571b8450ebd57396db6190c12e4d57bd" + integrity sha512-wLv2E/VEYhgVot7qyRop2adalHyw0Y+Rb1BG9RkFUa3paZUZEsIozBK3dBScTwSCJpmLCjzTVWZEvtHOfVLLSw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-hyperpay@^0.1.18": + version "0.1.18" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-hyperpay/-/wallet-adapter-hyperpay-0.1.18.tgz#6ce845514d662de6ccf4c8308dcfeb1bf977dfa1" + integrity sha512-On95zV7Dq5UTqYAtLFvttwDgPVz0a2iWl1XZ467YYXbvXPWSxkQmvPD0jHPUvHepGw60Hf5p0qkylyYANIAgoQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-keystone@^0.1.19": + version "0.1.19" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-keystone/-/wallet-adapter-keystone-0.1.19.tgz#da58c8e1fa0a4f932c2ea3df662ba35299d3b417" + integrity sha512-u7YmrQCrdZHI2hwJpX3rAiYuUdK0UIFX6m8+LSDOlA2bijlPJuTeH416aqqjueJTpvuZHowOPmV/no46PBqG0Q== + dependencies: + "@keystonehq/sol-keyring" "^0.20.0" + "@solana/wallet-adapter-base" "^0.9.27" + buffer "^6.0.3" + +"@solana/wallet-adapter-krystal@^0.1.16": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-krystal/-/wallet-adapter-krystal-0.1.16.tgz#b054c325da8107b26efeccfcc148be99370a1f6a" + integrity sha512-crAVzzPzMo63zIH0GTHDqYjIrjGFhrAjCntOV2hMjebMGSAmaUPTJKRi+vgju2Ons2Ktva7tRwiVaJxD8370DA== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-ledger@^0.9.29": + version "0.9.29" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-ledger/-/wallet-adapter-ledger-0.9.29.tgz#4b7a8ea14562ac87961cc4efce6f8449640449b6" + integrity sha512-1feOHQGdMOPtXtXBCuUuHlsoco2iqDNcUTbHW+Bj+3ItXGJctwMicSSWgfATEAFNUanvOB+kKZ4N3B1MQrP/9w== + dependencies: + "@ledgerhq/devices" "^8.4.5" + "@ledgerhq/hw-transport" "^6.31.5" + "@ledgerhq/hw-transport-webhid" "^6.30.1" + "@solana/wallet-adapter-base" "^0.9.27" + buffer "^6.0.3" + +"@solana/wallet-adapter-mathwallet@^0.9.22": + version "0.9.22" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-mathwallet/-/wallet-adapter-mathwallet-0.9.22.tgz#6c6e5678f9115f1dd24823a834ef9ef327acc873" + integrity sha512-5ePUe4lyTbwHlXQJwNrXRXDfyouAeIbfBTkJxcAWVivlVQcxcnE7BOwsCjImVaGNh4MumMLblxd2ywoSVDNf/g== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-neko@^0.2.16": + version "0.2.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-neko/-/wallet-adapter-neko-0.2.16.tgz#ee863c3a9654db80ac9503a21c1b941b041ef4d4" + integrity sha512-0l/s+NJUGkyVm24nHF0aPsTMo9lsdw21PO+obDszJziZZmiKrI1l1WmhCDwYwAllY0nQjaxQ0tJBYy066pmnVg== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-nightly@^0.1.20": + version "0.1.20" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-nightly/-/wallet-adapter-nightly-0.1.20.tgz#ce85da36dd7734c69799c40e23db641440d6f41e" + integrity sha512-37kRXzZ+54JhT21Cp3lC0O+hg9ZBC4epqkwNbev8piNnZUghKdsvsG5RjbsngVY6572jPlFGiuniDmb0vUSs3A== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-nufi@^0.1.21": + version "0.1.21" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-nufi/-/wallet-adapter-nufi-0.1.21.tgz#2337f2e21f0561ade6625071baa318978327ae2e" + integrity sha512-up9V4BfWl/oR0rIDQio1JD2oic+isHPk5DI4sUUxBPmWF/BYlpDVxwEfL7Xjg+jBfeiYGn0sVjTvaHY4/qUZAw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-onto@^0.1.11": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-onto/-/wallet-adapter-onto-0.1.11.tgz#b40cf941635d34ce881a91eca4ab1a10a379d00c" + integrity sha512-fyTJ5xFaYD8/Izu8q+oGD9iXZvg7ljLxi/JkVwN/HznVdac95ee1fvthkF3PPRmWGZeA7O/kYAxdQMXxlwy+xw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-particle@^0.1.16": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-particle/-/wallet-adapter-particle-0.1.16.tgz#a025abbb1de7e53642720327cb70fddefa6d991f" + integrity sha512-uB2FFN2SqV0cJQTvQ+pyVL6OXwGMhbz5KuWU14pcZWqfrOxs+L4grksLwMCGw+yBw/+jydLGMTUWntuEm6r7ag== + dependencies: + "@particle-network/solana-wallet" "^1.3.2" + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-phantom@^0.9.28": + version "0.9.28" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-phantom/-/wallet-adapter-phantom-0.9.28.tgz#306252eaafbfc6a1e9efe976e43f933eb87c8b80" + integrity sha512-g/hcuWwWjzo5l8I4vor9htniVhLxd/GhoVK52WSd0hy8IZ8/FBnV3u8ABVTheLqO13d0IVy+xTxoVBbDaMjLog== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-react-ui@^0.9.37": + version "0.9.39" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-react-ui/-/wallet-adapter-react-ui-0.9.39.tgz#36e2afb265a6dd73b6bbc5fc77c15c9558e808cf" + integrity sha512-B6GdOobwVuIgEX1qjcbTQEeo+0UGs3WPuBeUlR0dDCzQh9J3IAWRRyL/47FYSHYRp26LAu4ImWy4+M2TFD5OJg== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + "@solana/wallet-adapter-base-ui" "^0.1.6" + "@solana/wallet-adapter-react" "^0.15.39" + +"@solana/wallet-adapter-react@^0.15.37", "@solana/wallet-adapter-react@^0.15.39": + version "0.15.39" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-react/-/wallet-adapter-react-0.15.39.tgz#6e7a3df7b09afa4beea6b12384451cfb2aeb5976" + integrity sha512-WXtlo88ith5m22qB+qiGw301/Zb9r5pYr4QdXWmlXnRNqwST5MGmJWhG+/RVrzc+OG7kSb3z1gkVNv+2X/Y0Gg== + dependencies: + "@solana-mobile/wallet-adapter-mobile" "^2.2.0" + "@solana/wallet-adapter-base" "^0.9.27" + "@solana/wallet-standard-wallet-adapter-react" "^1.1.4" + +"@solana/wallet-adapter-safepal@^0.5.22": + version "0.5.22" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-safepal/-/wallet-adapter-safepal-0.5.22.tgz#52fff825dcb28740758d1f41a783ade5ad5d89e3" + integrity sha512-K1LlQIPoKgg3rdDIVUtMV218+uUM1kCtmuVKq2N+e+ZC8zK05cW3w7++nakDtU97AOmg+y4nsSFRCFsWBWmhTw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-saifu@^0.1.19": + version "0.1.19" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-saifu/-/wallet-adapter-saifu-0.1.19.tgz#3b2eb3aaaa1499ddf988c22997c7254a71cdc21d" + integrity sha512-RWguxtKSXTZUNlc7XTUuMi78QBjy5rWcg7Fis3R8rfMtCBZIUZ/0nPb/wZbRfTk3OqpvnwRQl89TC9d2P7/SvA== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-salmon@^0.1.18": + version "0.1.18" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-salmon/-/wallet-adapter-salmon-0.1.18.tgz#54cdd649af14f4402875783a74f2b9ed6f5a18db" + integrity sha512-YN2/j5MsaurrlVIijlYA7SfyJU6IClxfmbUjQKEuygq0eP6S7mIAB/LK7qK2Ut3ll5vyTq/5q9Gejy6zQEaTMg== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + salmon-adapter-sdk "^1.1.1" + +"@solana/wallet-adapter-sky@^0.1.19": + version "0.1.19" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-sky/-/wallet-adapter-sky-0.1.19.tgz#3b964f2d398cac4af0753e713f5051a9f8fd10d1" + integrity sha512-jJBAg5TQLyPUSFtjne3AGxUgGV8cxMicJCdDFG6HalNK6N9jAB9eWfPxwsGRKv2RijXVtzo3/ejzcKrGp3oAuQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-solflare@^0.6.32": + version "0.6.32" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-solflare/-/wallet-adapter-solflare-0.6.32.tgz#6fd92deddb85c21a2be3bafca69f94d2c6becbe1" + integrity sha512-FIqNyooif3yjPnw2gPNBZnsG6X9JYSrwCf1Oa0NN4/VxQcPjzGqvc+Tq1+js/nBOHju5roToeMFTbwNTdEOuZw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + "@solana/wallet-standard-chains" "^1.1.1" + "@solflare-wallet/metamask-sdk" "^1.0.3" + "@solflare-wallet/sdk" "^1.4.2" + "@wallet-standard/wallet" "^1.1.0" + +"@solana/wallet-adapter-solong@^0.9.22": + version "0.9.22" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-solong/-/wallet-adapter-solong-0.9.22.tgz#73cdea21a4ec0555f1f2663a3149b1fc3f7a9d19" + integrity sha512-lGTwQmHQrSTQp3OkYUbfzeFCDGi60ScOpgfC0IOZNSfWl7jwG5tnRXAJ4A1RG9Val9XcVe5b2biur2hyEMJlSQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-spot@^0.1.19": + version "0.1.19" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-spot/-/wallet-adapter-spot-0.1.19.tgz#8d262414280aaebc1bc12b777110f205d4c41ada" + integrity sha512-p7UgT+4+2r82YIJ+NsniNrXKSaYNgrM43FHkjdVVmEw69ZGvSSXJ3x108bCE9pshy6ldl+sb7VhJGg+uQ/OF9g== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-tokenary@^0.1.16": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-tokenary/-/wallet-adapter-tokenary-0.1.16.tgz#6c22de518929f9eac56e145b46ecbffb798bb429" + integrity sha512-7FrDcRrXogCn13Ni2vwA1K/74RMLq+n37+j5fW0KtU2AEA6QVPqPgl/o0rRRgwdaG1q6EM3BXfgscYkmMTlxQQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-tokenpocket@^0.4.23": + version "0.4.23" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-tokenpocket/-/wallet-adapter-tokenpocket-0.4.23.tgz#fd88ddc656bf18b8180b50751da7932d9cdb5ded" + integrity sha512-5/sgNj+WK0I+0+pMB8CmTPhRbImXJ8ZcqfO8+i2uHbmKwU+zddPFDT4Fin/Gm9AX/n//M+5bxhhN4FpnA9oM8w== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-torus@^0.11.32": + version "0.11.32" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-torus/-/wallet-adapter-torus-0.11.32.tgz#77ba2817d6bc60e8d9f0b99c2d592ebf723ed159" + integrity sha512-LHvCNIL3tvD3q3EVJ1VrcvqIz7JbLBJcvpi5+PwG6DQzrRLHJ7oxOHFwc1SUX41WwifQHKI+lXWlTrVpIOgDOA== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + "@toruslabs/solana-embed" "^2.1.0" + assert "^2.1.0" + crypto-browserify "^3.12.1" + process "^0.11.10" + stream-browserify "^3.0.0" + +"@solana/wallet-adapter-trezor@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-trezor/-/wallet-adapter-trezor-0.1.6.tgz#d1124348097bb2f9eeaf71ccdcbfbb05a492fdcd" + integrity sha512-jItXhzaNq/UxSSPKVxgrUamx4mr2voMDjcEBHVUqOQhcujmzoPpBSahWKgpsDIegeX6zDCmuTAULnTpLs6YuzA== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + "@trezor/connect-web" "^9.5.5" + buffer "^6.0.3" + +"@solana/wallet-adapter-trust@^0.1.17": + version "0.1.17" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-trust/-/wallet-adapter-trust-0.1.17.tgz#cb223c8bee9f5f8ee40a21fe1d5c0f9d3325a240" + integrity sha512-raVtYoemFxrmsq8xtxhp3mD1Hke7CJuPqZsYr20zODjM1H2N+ty6zQa7z9ApJtosYNHAGek5S1/+n4/gnrC4nQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-adapter-unsafe-burner@^0.1.10", "@solana/wallet-adapter-unsafe-burner@^0.1.11": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-unsafe-burner/-/wallet-adapter-unsafe-burner-0.1.11.tgz#729971badb8121f7fc7a14af9e9fd6a0917db785" + integrity sha512-VyRQ2xRbVcpRSPTv+qyxOYFtWHxrVlLiH2nIuqIRCZcmGkFmxr+egwMjCCIURS6KCX7Ye3AbHK8IWJX6p9yuFQ== + dependencies: + "@noble/curves" "^1.9.1" + "@solana/wallet-adapter-base" "^0.9.27" + "@solana/wallet-standard-features" "^1.3.0" + "@solana/wallet-standard-util" "^1.1.2" + +"@solana/wallet-adapter-walletconnect@^0.1.21": + version "0.1.21" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-walletconnect/-/wallet-adapter-walletconnect-0.1.21.tgz#947662ab4eef475d22e7d0f59de6e7006bb7c38a" + integrity sha512-OE2ZZ60RbeobRsCa2gTD7IgXqofSa5B+jBLUu0DO8TVeRWro40JKYJuUedthALjO5oLelWSpcds+i7PRL+RQcQ== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + "@walletconnect/solana-adapter" "^0.0.8" + +"@solana/wallet-adapter-wallets@^0.19.35": + version "0.19.37" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-wallets/-/wallet-adapter-wallets-0.19.37.tgz#27b816f9dc716aedffa133f49b9eb19df42bb2ec" + integrity sha512-LUHK2Zh6gELt0+kt+viIMxqc/bree65xZgTPXXBzjhbJNKJaV4D4wanYG2LM9O35/avehZ5BTLMHltbkibE+GA== + dependencies: + "@solana/wallet-adapter-alpha" "^0.1.14" + "@solana/wallet-adapter-avana" "^0.1.17" + "@solana/wallet-adapter-bitkeep" "^0.3.24" + "@solana/wallet-adapter-bitpie" "^0.5.22" + "@solana/wallet-adapter-clover" "^0.4.23" + "@solana/wallet-adapter-coin98" "^0.5.24" + "@solana/wallet-adapter-coinbase" "^0.1.23" + "@solana/wallet-adapter-coinhub" "^0.3.22" + "@solana/wallet-adapter-fractal" "^0.1.12" + "@solana/wallet-adapter-huobi" "^0.1.19" + "@solana/wallet-adapter-hyperpay" "^0.1.18" + "@solana/wallet-adapter-keystone" "^0.1.19" + "@solana/wallet-adapter-krystal" "^0.1.16" + "@solana/wallet-adapter-ledger" "^0.9.29" + "@solana/wallet-adapter-mathwallet" "^0.9.22" + "@solana/wallet-adapter-neko" "^0.2.16" + "@solana/wallet-adapter-nightly" "^0.1.20" + "@solana/wallet-adapter-nufi" "^0.1.21" + "@solana/wallet-adapter-onto" "^0.1.11" + "@solana/wallet-adapter-particle" "^0.1.16" + "@solana/wallet-adapter-phantom" "^0.9.28" + "@solana/wallet-adapter-safepal" "^0.5.22" + "@solana/wallet-adapter-saifu" "^0.1.19" + "@solana/wallet-adapter-salmon" "^0.1.18" + "@solana/wallet-adapter-sky" "^0.1.19" + "@solana/wallet-adapter-solflare" "^0.6.32" + "@solana/wallet-adapter-solong" "^0.9.22" + "@solana/wallet-adapter-spot" "^0.1.19" + "@solana/wallet-adapter-tokenary" "^0.1.16" + "@solana/wallet-adapter-tokenpocket" "^0.4.23" + "@solana/wallet-adapter-torus" "^0.11.32" + "@solana/wallet-adapter-trezor" "^0.1.6" + "@solana/wallet-adapter-trust" "^0.1.17" + "@solana/wallet-adapter-unsafe-burner" "^0.1.11" + "@solana/wallet-adapter-walletconnect" "^0.1.21" + "@solana/wallet-adapter-xdefi" "^0.1.11" + +"@solana/wallet-adapter-xdefi@^0.1.11": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-xdefi/-/wallet-adapter-xdefi-0.1.11.tgz#a994511f81223e38e877e3783dc2b0bcd4772dfd" + integrity sha512-WzhzhNtA4ECX9ZMyAyZV8TciuwvbW8VoJWwF+hdts5xHfnitRJDR/17Br6CQH0CFKkqymVHCMWOBIWEjmp+3Rw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.27" + +"@solana/wallet-standard-chains@^1.1.0", "@solana/wallet-standard-chains@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-chains/-/wallet-standard-chains-1.1.1.tgz#bbab9f3836006e9e4722afc408ca323df9623657" + integrity sha512-Us3TgL4eMVoVWhuC4UrePlYnpWN+lwteCBlhZDUhFZBJ5UMGh94mYPXno3Ho7+iHPYRtuCi/ePvPcYBqCGuBOw== + dependencies: + "@wallet-standard/base" "^1.1.0" + +"@solana/wallet-standard-core@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-core/-/wallet-standard-core-1.1.2.tgz#86512ae188450d70ff5d1ee0f58b5c29b83226c6" + integrity sha512-FaSmnVsIHkHhYlH8XX0Y4TYS+ebM+scW7ZeDkdXo3GiKge61Z34MfBPinZSUMV08hCtzxxqH2ydeU9+q/KDrLA== + dependencies: + "@solana/wallet-standard-chains" "^1.1.1" + "@solana/wallet-standard-features" "^1.3.0" + "@solana/wallet-standard-util" "^1.1.2" + +"@solana/wallet-standard-features@^1.1.0", "@solana/wallet-standard-features@^1.2.0", "@solana/wallet-standard-features@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-features/-/wallet-standard-features-1.3.0.tgz#c489eca9d0c78f97084b4af6ca8ad8c1ca197de5" + integrity sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg== + dependencies: + "@wallet-standard/base" "^1.1.0" + "@wallet-standard/features" "^1.1.0" + +"@solana/wallet-standard-util@^1.1.1", "@solana/wallet-standard-util@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-util/-/wallet-standard-util-1.1.2.tgz#1e281178c04b52923ea530799c589ed64e5526bc" + integrity sha512-rUXFNP4OY81Ddq7qOjQV4Kmkozx4wjYAxljvyrqPx8Ycz0FYChG/hQVWqvgpK3sPsEaO/7ABG1NOACsyAKWNOA== + dependencies: + "@noble/curves" "^1.8.0" + "@solana/wallet-standard-chains" "^1.1.1" + "@solana/wallet-standard-features" "^1.3.0" + +"@solana/wallet-standard-wallet-adapter-base@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter-base/-/wallet-standard-wallet-adapter-base-1.1.4.tgz#fc05b153674e29839eee49b30d05106bd42dd789" + integrity sha512-Q2Rie9YaidyFA4UxcUIxUsvynW+/gE2noj/Wmk+IOwDwlVrJUAXCvFaCNsPDSyKoiYEKxkSnlG13OA1v08G4iw== + dependencies: + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/wallet-standard-chains" "^1.1.1" + "@solana/wallet-standard-features" "^1.3.0" + "@solana/wallet-standard-util" "^1.1.2" + "@wallet-standard/app" "^1.1.0" + "@wallet-standard/base" "^1.1.0" + "@wallet-standard/features" "^1.1.0" + "@wallet-standard/wallet" "^1.1.0" + +"@solana/wallet-standard-wallet-adapter-react@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter-react/-/wallet-standard-wallet-adapter-react-1.1.4.tgz#5f48a68bea19fe570e1741d0e26f98c6d8ad0628" + integrity sha512-xa4KVmPgB7bTiWo4U7lg0N6dVUtt2I2WhEnKlIv0jdihNvtyhOjCKMjucWet6KAVhir6I/mSWrJk1U9SvVvhCg== + dependencies: + "@solana/wallet-standard-wallet-adapter-base" "^1.1.4" + "@wallet-standard/app" "^1.1.0" + "@wallet-standard/base" "^1.1.0" + +"@solana/wallet-standard-wallet-adapter@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter/-/wallet-standard-wallet-adapter-1.1.4.tgz#fd4f9d1b61e85daa6d940618854528945cacdfa7" + integrity sha512-YSBrxwov4irg2hx9gcmM4VTew3ofNnkqsXQ42JwcS6ykF1P1ecVY8JCbrv75Nwe6UodnqeoZRbN7n/p3awtjNQ== + dependencies: + "@solana/wallet-standard-wallet-adapter-base" "^1.1.4" + "@solana/wallet-standard-wallet-adapter-react" "^1.1.4" + +"@solana/wallet-standard@^1.1.2": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard/-/wallet-standard-1.1.4.tgz#afe6d8a6d6ea04acd9bb4a92bef6bb93e08c81f3" + integrity sha512-NF+MI5tOxyvfTU4A+O5idh/gJFmjm52bMwsPpFGRSL79GECSN0XLmpVOO/jqTKJgac2uIeYDpQw/eMaQuWuUXw== + dependencies: + "@solana/wallet-standard-core" "^1.1.2" + "@solana/wallet-standard-wallet-adapter" "^1.1.4" + +"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.69.0", "@solana/web3.js@^1.91.4", "@solana/web3.js@^1.98.0", "@solana/web3.js@^1.98.2": + version "1.98.2" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.98.2.tgz#45167a5cfb64436944bf4dc1e8be8482bd6d4c14" + integrity sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A== + dependencies: + "@babel/runtime" "^7.25.0" + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" + "@solana/buffer-layout" "^4.0.1" + "@solana/codecs-numbers" "^2.1.0" + agentkeepalive "^4.5.0" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.1" + node-fetch "^2.7.0" + rpc-websockets "^9.0.2" + superstruct "^2.0.2" + +"@solflare-wallet/metamask-sdk@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@solflare-wallet/metamask-sdk/-/metamask-sdk-1.0.3.tgz#3baaa22de2c86515e6ba6025285cd1f5d74b04e5" + integrity sha512-os5Px5PTMYKGS5tzOoyjDxtOtj0jZKnbI1Uwt8+Jsw1HHIA+Ib2UACCGNhQ/un2f8sIbTfLD1WuucNMOy8KZpQ== + dependencies: + "@solana/wallet-standard-features" "^1.1.0" + "@wallet-standard/base" "^1.0.1" + bs58 "^5.0.0" + eventemitter3 "^5.0.1" + uuid "^9.0.0" + +"@solflare-wallet/sdk@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@solflare-wallet/sdk/-/sdk-1.4.2.tgz#630b9a26f7bca255ee4a7088f287ae8c8335e345" + integrity sha512-jrseNWipwl9xXZgrzwZF3hhL0eIVxuEtoZOSLmuPuef7FgHjstuTtNJAeT4icA7pzdDV4hZvu54pI2r2f7SmrQ== + dependencies: + bs58 "^5.0.0" + eventemitter3 "^5.0.1" + uuid "^9.0.0" + +"@standard-schema/spec@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" + integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== + +"@standard-schema/utils@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@standard-schema/utils/-/utils-0.3.0.tgz#3d5e608f16c2390c10528e98e59aef6bf73cae7b" + integrity sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g== + +"@stellar/js-xdr@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@stellar/js-xdr/-/js-xdr-3.1.2.tgz#db7611135cf21e989602fd72f513c3bed621bc74" + integrity sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ== + +"@stellar/stellar-base@^13.1.0": + version "13.1.0" + resolved "https://registry.yarnpkg.com/@stellar/stellar-base/-/stellar-base-13.1.0.tgz#06d9075cc72da05bc5dd6f1971e6682a0525cec9" + integrity sha512-90EArG+eCCEzDGj3OJNoCtwpWDwxjv+rs/RNPhvg4bulpjN/CSRj+Ys/SalRcfM4/WRC5/qAfjzmJBAuquWhkA== + dependencies: + "@stellar/js-xdr" "^3.1.2" + base32.js "^0.1.0" + bignumber.js "^9.1.2" + buffer "^6.0.3" + sha.js "^2.3.6" + tweetnacl "^1.0.3" + optionalDependencies: + sodium-native "^4.3.3" + +"@stellar/stellar-sdk@^13.3.0": + version "13.3.0" + resolved "https://registry.yarnpkg.com/@stellar/stellar-sdk/-/stellar-sdk-13.3.0.tgz#72bf3eea4797de053aaebb889bf4de342d0b6b54" + integrity sha512-8+GHcZLp+mdin8gSjcgfb/Lb6sSMYRX6Nf/0LcSJxvjLQR0XHpjGzOiRbYb2jSXo51EnA6kAV5j+4Pzh5OUKUg== + dependencies: + "@stellar/stellar-base" "^13.1.0" + axios "^1.8.4" + bignumber.js "^9.3.0" + eventsource "^2.0.2" + feaxios "^0.0.23" + randombytes "^2.1.0" + toml "^3.0.0" + urijs "^1.19.1" + +"@swc/counter@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/helpers@0.5.15": + version "0.5.15" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7" + integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g== + dependencies: + tslib "^2.8.0" + +"@swc/helpers@^0.5.11": + version "0.5.17" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.17.tgz#5a7be95ac0f0bf186e7e6e890e7a6f6cda6ce971" + integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== + dependencies: + tslib "^2.8.0" + +"@tailwindcss/node@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.11.tgz#d626af65fc9872e5e9d8884791d7e3856e945359" + integrity sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q== + dependencies: + "@ampproject/remapping" "^2.3.0" + enhanced-resolve "^5.18.1" + jiti "^2.4.2" + lightningcss "1.30.1" + magic-string "^0.30.17" + source-map-js "^1.2.1" + tailwindcss "4.1.11" + +"@tailwindcss/oxide-android-arm64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz#1f387d8302f011b61c226deb0c3a1d2bd79c6915" + integrity sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg== + +"@tailwindcss/oxide-darwin-arm64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz#acd35ffb7e4eae83d0a3fe2f8ea36cfcc9b21f7e" + integrity sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ== + +"@tailwindcss/oxide-darwin-x64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz#a0022312993a3893d6ff0312d6e3c83c4636fef4" + integrity sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw== + +"@tailwindcss/oxide-freebsd-x64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz#dd8e55eb0b88fe7995b8148c0e0ae5fa27092d22" + integrity sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz#02ee99090988847d3f13d277679012cbffcdde37" + integrity sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz#4837559c102bebe65089879f6a0278ed473b4813" + integrity sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz#bec465112a13a1383558ff36afdf28b8a8cb9021" + integrity sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz#f9e47e6aa67ff77f32f7412bc9698d4278e101bf" + integrity sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg== + +"@tailwindcss/oxide-linux-x64-musl@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz#7d6e8adcfb9bc84d8e2e2e8781d661edb9e41ba8" + integrity sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q== + +"@tailwindcss/oxide-wasm32-wasi@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz#a1762f4939c6ebaa824696fda2fd7db1b85fbed2" + integrity sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@emnapi/wasi-threads" "^1.0.2" + "@napi-rs/wasm-runtime" "^0.2.11" + "@tybys/wasm-util" "^0.9.0" + tslib "^2.8.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz#70ba392dca0fa3707ebe27d2bd6ac3e69d35e3b7" + integrity sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz#cdcb9eea9225a346c0695f67f621990b0534763f" + integrity sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg== + +"@tailwindcss/oxide@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.11.tgz#569b668c99c337b7b8204bc5b6a833429755a05b" + integrity sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg== + dependencies: + detect-libc "^2.0.4" + tar "^7.4.3" + optionalDependencies: + "@tailwindcss/oxide-android-arm64" "4.1.11" + "@tailwindcss/oxide-darwin-arm64" "4.1.11" + "@tailwindcss/oxide-darwin-x64" "4.1.11" + "@tailwindcss/oxide-freebsd-x64" "4.1.11" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.11" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.11" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.11" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.11" + "@tailwindcss/oxide-linux-x64-musl" "4.1.11" + "@tailwindcss/oxide-wasm32-wasi" "4.1.11" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.11" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.11" + +"@tailwindcss/postcss@^4.1.3": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/postcss/-/postcss-4.1.11.tgz#4d844f7ff295c731ceab54934531bece7380ce0c" + integrity sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + "@tailwindcss/node" "4.1.11" + "@tailwindcss/oxide" "4.1.11" + postcss "^8.4.41" + tailwindcss "4.1.11" + +"@toruslabs/base-controllers@^5.5.5": + version "5.11.0" + resolved "https://registry.yarnpkg.com/@toruslabs/base-controllers/-/base-controllers-5.11.0.tgz#39cb9ec3d3a9861997a5c4e0699dce5348b04f0a" + integrity sha512-5AsGOlpf3DRIsd6PzEemBoRq+o2OhgSFXj5LZD6gXcBlfe0OpF+ydJb7Q8rIt5wwpQLNJCs8psBUbqIv7ukD2w== + dependencies: + "@ethereumjs/util" "^9.0.3" + "@toruslabs/broadcast-channel" "^10.0.2" + "@toruslabs/http-helpers" "^6.1.1" + "@toruslabs/openlogin-jrpc" "^8.3.0" + "@toruslabs/openlogin-utils" "^8.2.1" + async-mutex "^0.5.0" + bignumber.js "^9.1.2" + bowser "^2.11.0" + jwt-decode "^4.0.0" + loglevel "^1.9.1" + +"@toruslabs/broadcast-channel@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@toruslabs/broadcast-channel/-/broadcast-channel-10.0.2.tgz#90da5a9ea9e61374355f3d915e983cb177a45844" + integrity sha512-aZbKNgV/OhiTKSdxBTGO86xRdeR7Ct1vkB8yeyXRX32moARhZ69uJQL49jKh4cWKV3VeijrL9XvKdn5bzgHQZg== + dependencies: + "@babel/runtime" "^7.24.0" + "@toruslabs/eccrypto" "^4.0.0" + "@toruslabs/metadata-helpers" "^5.1.0" + loglevel "^1.9.1" + oblivious-set "1.4.0" + socket.io-client "^4.7.5" + unload "^2.4.1" + +"@toruslabs/constants@^13.2.0": + version "13.4.0" + resolved "https://registry.yarnpkg.com/@toruslabs/constants/-/constants-13.4.0.tgz#4e986a4d6b87bf0e8a389dddabbb21ed6a1a1320" + integrity sha512-CjmnMQ5Oj0bqSBGkhv7Xm3LciGJDHwe4AJ1LF6mijlP+QcCnUM5I6kVp60j7zZ/r0DT7nIEiuHHHczGpCZor0A== + +"@toruslabs/eccrypto@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@toruslabs/eccrypto/-/eccrypto-4.0.0.tgz#0b27ed2d1e9483e77f42a7619a2c3c19cb802f44" + integrity sha512-Z3EINkbsgJx1t6jCDVIJjLSUEGUtNIeDjhMWmeDGOWcP/+v/yQ1hEvd1wfxEz4q5WqIHhevacmPiVxiJ4DljGQ== + dependencies: + elliptic "^6.5.4" + +"@toruslabs/http-helpers@^6.1.0", "@toruslabs/http-helpers@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@toruslabs/http-helpers/-/http-helpers-6.1.1.tgz#0869fe78a31c8a6b5d9447f353e1b59700ee00ec" + integrity sha512-bJYOaltRzklzObhRdutT1wau17vXyrCCBKJOeN46F1t99MUXi5udQNeErFOcr9qBsvrq2q67eVBkU5XOeBMX5A== + dependencies: + lodash.merge "^4.6.2" + loglevel "^1.9.1" + +"@toruslabs/metadata-helpers@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@toruslabs/metadata-helpers/-/metadata-helpers-5.1.0.tgz#a7a73c96b8afc3aaf9fa6b277218d4828c2f97a5" + integrity sha512-7fdqKuWUaJT/ng+PlqrA4XKkn8Dij4JJozfv/4gHTi0f/6JFncpzIces09jTV70hCf0JIsTCvIDlzKOdJ+aeZg== + dependencies: + "@toruslabs/eccrypto" "^4.0.0" + "@toruslabs/http-helpers" "^6.1.0" + elliptic "^6.5.5" + ethereum-cryptography "^2.1.3" + json-stable-stringify "^1.1.1" + +"@toruslabs/openlogin-jrpc@^8.1.1", "@toruslabs/openlogin-jrpc@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@toruslabs/openlogin-jrpc/-/openlogin-jrpc-8.3.0.tgz#9c6c373b0b9052ae5317b7977af5ec16bdfa9897" + integrity sha512-1OdSkUXGXJobkkMIJHuf+XzwmUB4ROy6uQfPEJ3NXvNj84+N4hNpvC4JPg7VoWBHdfCba9cv6QnQsVArlwai4A== + dependencies: + end-of-stream "^1.4.4" + events "^3.3.0" + fast-safe-stringify "^2.1.1" + once "^1.4.0" + pump "^3.0.0" + readable-stream "^4.5.2" + +"@toruslabs/openlogin-utils@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@toruslabs/openlogin-utils/-/openlogin-utils-8.2.1.tgz#88e6f3d0e17b1f15dafd1c9d9daa3bbb8054912b" + integrity sha512-NSOtj61NZe7w9qbd92cYwMlE/1UwPGtDH02NfUjoEEc3p1yD5U2cLZjdSwsnAgjGNgRqVomXpND4hii12lI/ew== + dependencies: + "@toruslabs/constants" "^13.2.0" + base64url "^3.0.1" + color "^4.2.3" + +"@toruslabs/solana-embed@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@toruslabs/solana-embed/-/solana-embed-2.1.0.tgz#049f8cb4f2f5d5531d3acd4078a45ddcf1070779" + integrity sha512-rgZniKy+yuqJp8/Z/RcqzhTL4iCH+4nP55XD5T2nEIajAClsmonsGp24AUqYwEqu+7x2hjumZEh+12rUv+Ippw== + dependencies: + "@solana/web3.js" "^1.91.4" + "@toruslabs/base-controllers" "^5.5.5" + "@toruslabs/http-helpers" "^6.1.1" + "@toruslabs/openlogin-jrpc" "^8.1.1" + eth-rpc-errors "^4.0.3" + fast-deep-equal "^3.1.3" + lodash-es "^4.17.21" + loglevel "^1.9.1" + pump "^3.0.0" + +"@trezor/analytics@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@trezor/analytics/-/analytics-1.4.2.tgz#4eb7a8ed8687ebbc2993659eb1b31e89e3bdeda5" + integrity sha512-FgjJekuDvx1TjiDemvpnPiRck7Kp/v1ZeppsBYpQR3yGKyKzbG1pVpcl0RyI2237raXxbORaz7XV8tcyjq4BXg== + dependencies: + "@trezor/env-utils" "1.4.2" + "@trezor/utils" "9.4.2" + +"@trezor/blockchain-link-types@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@trezor/blockchain-link-types/-/blockchain-link-types-1.4.2.tgz#ccdcdbee6eb5789ee60978930fd181212f867798" + integrity sha512-KThBmGOFLJAFnmou9ThQhnjEVxfYPfEwMOaVTVNgJ+NAkt5rEMx0SKBBelCGZ63XtOLWdVPglFo83wtm+I9Vpg== + dependencies: + "@trezor/utxo-lib" "2.4.2" + +"@trezor/blockchain-link-utils@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@trezor/blockchain-link-utils/-/blockchain-link-utils-1.4.2.tgz#56884209e8111cee91d4bd20f4e728fcaec38eb4" + integrity sha512-PBEBrdtHn0dn/c9roW6vjdHI/CucMywJm5gthETZAZmzBOtg6ZDpLTn+qL8+jZGIbwcAkItrQ3iHrHhR6xTP5g== + dependencies: + "@mobily/ts-belt" "^3.13.1" + "@stellar/stellar-sdk" "^13.3.0" + "@trezor/env-utils" "1.4.2" + "@trezor/utils" "9.4.2" + xrpl "^4.3.0" + +"@trezor/blockchain-link@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@trezor/blockchain-link/-/blockchain-link-2.5.2.tgz#dc4cfc13638674c96d91a553eb92a8c82c1456b1" + integrity sha512-/egUnIt/fR57QY33ejnkPMhZwRvVRS/pUCoqdVIGitN1Q7QZsdopoR4hw37hdK/Ux/q1ZLH6LZz7U2UFahjppw== + dependencies: + "@solana-program/stake" "^0.2.1" + "@solana-program/token" "^0.5.1" + "@solana-program/token-2022" "^0.4.2" + "@solana/kit" "^2.1.1" + "@solana/rpc-types" "^2.1.1" + "@stellar/stellar-sdk" "^13.3.0" + "@trezor/blockchain-link-types" "1.4.2" + "@trezor/blockchain-link-utils" "1.4.2" + "@trezor/env-utils" "1.4.2" + "@trezor/utils" "9.4.2" + "@trezor/utxo-lib" "2.4.2" + "@trezor/websocket-client" "1.2.2" + "@types/web" "^0.0.197" + events "^3.3.0" + socks-proxy-agent "8.0.5" + xrpl "^4.3.0" + +"@trezor/connect-analytics@1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@trezor/connect-analytics/-/connect-analytics-1.3.5.tgz#d965ac376268de1cd80a881df3f6ec4c8d04952d" + integrity sha512-Aoi+EITpZZycnELQJEp9XV0mHFfaCQ6JE0Ka5mWuHtOny3nJdFLBrih4ipcEXJdJbww6pBxRJB09sJ19cTyacA== + dependencies: + "@trezor/analytics" "1.4.2" + +"@trezor/connect-common@0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@trezor/connect-common/-/connect-common-0.4.2.tgz#472e8e46c09c0e0879c25739809d0e55c1437d3d" + integrity sha512-ND5TTjrTPnJdfl8Wlhl9YtFWnY2u6FHM1dsPkNYCmyUKIMoflJ5cLn95Xabl6l1btHERYn3wTUvgEYQG7r8OVQ== + dependencies: + "@trezor/env-utils" "1.4.2" + "@trezor/utils" "9.4.2" + +"@trezor/connect-web@^9.5.5": + version "9.6.2" + resolved "https://registry.yarnpkg.com/@trezor/connect-web/-/connect-web-9.6.2.tgz#bcbb423447e4f4cd0bcbabdf385d80f2eb7fb06c" + integrity sha512-QGuCjX8Bx9aCq1Pg52KifbbzYn00FQu9mCTDSgCVGH/HAzbxhcRkDKc86kFwW8z9NdJxw+XeVJq5Ky/js3iEDA== + dependencies: + "@trezor/connect" "9.6.2" + "@trezor/connect-common" "0.4.2" + "@trezor/utils" "9.4.2" + "@trezor/websocket-client" "1.2.2" + +"@trezor/connect@9.6.2": + version "9.6.2" + resolved "https://registry.yarnpkg.com/@trezor/connect/-/connect-9.6.2.tgz#4d48a0bc8f571a8e4c8cdd11fd2d75652c697c8b" + integrity sha512-XsSERBK+KnF6FPsATuhB9AEM0frekVLwAwFo35MRV9I4P+mdv6tnUiZUq8O8aoPbfJwDjtNJSYv+PMsKuRH6rg== + dependencies: + "@ethereumjs/common" "^10.0.0" + "@ethereumjs/tx" "^10.0.0" + "@fivebinaries/coin-selection" "3.0.0" + "@mobily/ts-belt" "^3.13.1" + "@noble/hashes" "^1.6.1" + "@scure/bip39" "^1.5.1" + "@solana-program/compute-budget" "^0.8.0" + "@solana-program/system" "^0.7.0" + "@solana-program/token" "^0.5.1" + "@solana-program/token-2022" "^0.4.2" + "@solana/kit" "^2.1.1" + "@trezor/blockchain-link" "2.5.2" + "@trezor/blockchain-link-types" "1.4.2" + "@trezor/blockchain-link-utils" "1.4.2" + "@trezor/connect-analytics" "1.3.5" + "@trezor/connect-common" "0.4.2" + "@trezor/crypto-utils" "1.1.4" + "@trezor/device-utils" "1.1.2" + "@trezor/env-utils" "^1.4.2" + "@trezor/protobuf" "1.4.2" + "@trezor/protocol" "1.2.8" + "@trezor/schema-utils" "1.3.4" + "@trezor/transport" "1.5.2" + "@trezor/type-utils" "1.1.8" + "@trezor/utils" "9.4.2" + "@trezor/utxo-lib" "2.4.2" + blakejs "^1.2.1" + bs58 "^6.0.0" + bs58check "^4.0.0" + cross-fetch "^4.0.0" + jws "^4.0.0" + +"@trezor/crypto-utils@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@trezor/crypto-utils/-/crypto-utils-1.1.4.tgz#86ebde3ff745d3672f4ed475f00ee68d2ff05e43" + integrity sha512-Y6VziniqMPoMi70IyowEuXKqRvBYQzgPAekJaUZTHhR+grtYNRKRH2HJCvuZ8MGmSKUFSYfa7y8AvwALA8mQmA== + +"@trezor/device-utils@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@trezor/device-utils/-/device-utils-1.1.2.tgz#541c2bf623b7acda7e445b876336a0579da0c504" + integrity sha512-R3AJvAo+a3wYVmcGZO2VNl9PZOmDEzCZIlmCJn0BlSRWWd8G9u1qyo/fL9zOwij/YhCaJyokmSHmIEmbY9qpgw== + +"@trezor/env-utils@1.4.2", "@trezor/env-utils@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@trezor/env-utils/-/env-utils-1.4.2.tgz#b1608e98a975f2a071c9005a30b606f5a5a8cd00" + integrity sha512-lQvrqcNK5I4dy2MuiLyMuEm0KzY59RIu2GLtc9GsvqyxSPZkADqVzGeLJjXj/vI2ajL8leSpMvmN4zPw3EK8AA== + dependencies: + ua-parser-js "^2.0.4" + +"@trezor/protobuf@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@trezor/protobuf/-/protobuf-1.4.2.tgz#92a1732262f991fea911eec1b21010c6806b430a" + integrity sha512-AeIYKCgKcE9cWflggGL8T9gD+IZLSGrwkzqCk3wpIiODd5dUCgEgA4OPBufR6OMu3RWu/Tgu2xviHunijG3LXQ== + dependencies: + "@trezor/schema-utils" "1.3.4" + long "5.2.5" + protobufjs "7.4.0" + +"@trezor/protocol@1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@trezor/protocol/-/protocol-1.2.8.tgz#3980018b4c5c3d2b126fb17cd11d26b575b9f1ce" + integrity sha512-8EH+EU4Z1j9X4Ljczjbl9G7vVgcUz41qXcdE+6FOG3BFvMDK4KUVvaOtWqD+1dFpeo5yvWSTEKdhgXMPFprWYQ== + +"@trezor/schema-utils@1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@trezor/schema-utils/-/schema-utils-1.3.4.tgz#6ebd17aadf9534c1054e852d44e3c351bb919a79" + integrity sha512-guP5TKjQEWe6c5HGx+7rhM0SAdEL5gylpkvk9XmJXjZDnl1Ew81nmLHUs2ghf8Od3pKBe4qjBIMBHUQNaOqWUg== + dependencies: + "@sinclair/typebox" "^0.33.7" + ts-mixer "^6.0.3" + +"@trezor/transport@1.5.2": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@trezor/transport/-/transport-1.5.2.tgz#d5373c4364546933944a76dc817c65b8660dc123" + integrity sha512-rYP87zdVll2bNBtsD3VxJq0yjaNvIClcgszZjQwVTQxpKGFPkx8bLSpAGI05R9qfxusZJCfYarjX3qki9nHYPw== + dependencies: + "@trezor/protobuf" "1.4.2" + "@trezor/protocol" "1.2.8" + "@trezor/type-utils" "1.1.8" + "@trezor/utils" "9.4.2" + cross-fetch "^4.0.0" + usb "^2.15.0" + +"@trezor/type-utils@1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@trezor/type-utils/-/type-utils-1.1.8.tgz#3cddcdfb483342459e22fa6d89a2e918da1ac718" + integrity sha512-VtvkPXpwtMtTX9caZWYlMMTmhjUeDq4/1LGn0pSdjd4OuL/vQyuPWXCT/0RtlnRraW6R2dZF7rX2UON2kQIMTQ== + +"@trezor/utils@9.4.2": + version "9.4.2" + resolved "https://registry.yarnpkg.com/@trezor/utils/-/utils-9.4.2.tgz#8d62bea5f032b3b368a06ed97a4e942c5496a0cc" + integrity sha512-Fm3m2gmfXsgv4chqn5HX8e8dElEr2ibBJSJ7HE3bsHh/1OSQcDdzsSioAK04Fo9ws/v7n6lt+QBZ6fGmwyIkZQ== + dependencies: + bignumber.js "^9.3.0" + +"@trezor/utxo-lib@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@trezor/utxo-lib/-/utxo-lib-2.4.2.tgz#1d2cc81863c2c89bc207ff3eb013aa1cbfde9719" + integrity sha512-dTXfBg/cEKnmHM5CLG5+0qrp6fqOfwxqe8YPACdKeM7g1XJKCGDAuFpDUVeT3lrcUsTh6bEMHM06z4H3gZp5MQ== + dependencies: + "@trezor/utils" "9.4.2" + bchaddrjs "^0.5.2" + bech32 "^2.0.0" + bip66 "^2.0.0" + bitcoin-ops "^1.4.1" + blake-hash "^2.0.0" + blakejs "^1.2.1" + bn.js "^5.2.2" + bs58 "^6.0.0" + bs58check "^4.0.0" + create-hmac "^1.1.7" + int64-buffer "^1.1.0" + pushdata-bitcoin "^1.0.1" + tiny-secp256k1 "^1.1.7" + typeforce "^1.18.0" + varuint-bitcoin "2.0.0" + wif "^5.0.0" + +"@trezor/websocket-client@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@trezor/websocket-client/-/websocket-client-1.2.2.tgz#f7fe1da844df847d83e3de66906b22fe092aed10" + integrity sha512-vu9L1V/5yh8LHQCmsGC9scCnihELsVuR5Tri1IvW3CdgTUFFcfjsEgXsFqFME3HlxuUmx6qokw0Gx/o0/hzaSQ== + dependencies: + "@trezor/utils" "9.4.2" + ws "^8.18.0" + +"@ts-morph/common@~0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.19.0.tgz#927fcd81d1bbc09c89c4a310a84577fb55f3694e" + integrity sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ== + dependencies: + fast-glob "^3.2.12" + minimatch "^7.4.3" + mkdirp "^2.1.6" + path-browserify "^1.0.1" + +"@tsparticles/basic@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/basic/-/basic-3.8.1.tgz#ba8c372c8ea462f737a7cab296ca2892e955112b" + integrity sha512-my114zRmekT/+I2cGuEnHxlX5G/jO0iVtNnsxxlsgspXUTSY+fDixmrNF4UgFkuaIwd9Bv/yH+7S/4HE4qte7A== + dependencies: + "@tsparticles/engine" "3.8.1" + "@tsparticles/move-base" "3.8.1" + "@tsparticles/plugin-hex-color" "3.8.1" + "@tsparticles/plugin-hsl-color" "3.8.1" + "@tsparticles/plugin-rgb-color" "3.8.1" + "@tsparticles/shape-circle" "3.8.1" + "@tsparticles/updater-color" "3.8.1" + "@tsparticles/updater-opacity" "3.8.1" + "@tsparticles/updater-out-modes" "3.8.1" + "@tsparticles/updater-size" "3.8.1" + +"@tsparticles/engine@3.8.1", "@tsparticles/engine@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/engine/-/engine-3.8.1.tgz#1dc538cdb043757c8b8a90bd03b1069c1801cc1e" + integrity sha512-S8h10nuZfElY7oih//NUHnT5qf4v3/dnsU8CMs7dz5lBEGr3amrYrXk0V+YKPTIQwfdmJHUaSBoAqFiv4aEGIA== + +"@tsparticles/interaction-external-attract@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-attract/-/interaction-external-attract-3.8.1.tgz#7808282bf005f99c7150e8b86aa9870a8e1e49de" + integrity sha512-GWzyj5MOzjb5pNWuqAueNZS2ilPcZ0isiqwcb0BjjpwfiGfL72UyIbNUDMLncsW+4jcwB4WyMsv/qOGDmAwVfQ== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-bounce@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-bounce/-/interaction-external-bounce-3.8.1.tgz#41d14c7e6ac3b7afad2258510b530b6df95077a2" + integrity sha512-tgVzsE3orneSeSUc1XhRD6Iqs8Rkm11iRdkncKSpNx4SI2eJWFPhwit2wIiHQ+IuvgCmM2DXRtLgEVeaux71zg== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-bubble@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-bubble/-/interaction-external-bubble-3.8.1.tgz#1a3236d647f4cfdbbdd063466dd952eb38bc425f" + integrity sha512-edRVFybiVFd5vEjfEkHgrBTXfPTKc05EqCmRuOEd5gOll1ui0nPtknzj9JiLrPacQAJ7OgZKlHWYQb1u5Yy5Tw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-connect@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-connect/-/interaction-external-connect-3.8.1.tgz#ca4a3e0603cb2b29b4a564afde064957e948fb1a" + integrity sha512-DQ0nNB0VDSxFxeaJQvm91NDUU/UPoiHE+uUzyw5qSoWJEGTUOj/QkW0GuBinCo99i8MH/wLDqMS9nb+7ZejpUw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-grab@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-grab/-/interaction-external-grab-3.8.1.tgz#3f17e3a88573a0f8b054c0da02148918f045b258" + integrity sha512-nPaHrazEr14CGokGGkFHYXZJTN3Inshe04uQNj+Rj4Lz9dAIqq8EFuSejp0g9lk2cTHWfVf4SK4r8+aJz9Ow4Q== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-pause@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-pause/-/interaction-external-pause-3.8.1.tgz#04227deaaf2b0787246b83e0e574ab5fbb0f28b3" + integrity sha512-W+6bjNDddtzlikwnfmk2G/GJsz4ZnoqvK0c63earvnPNUAJmkzrvmLS52JoaIOSyclOIeD4LmubT6IsQDv5ohA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-push@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-push/-/interaction-external-push-3.8.1.tgz#ad675dc34b3aaca4038dbe68d5fbafbce2e93648" + integrity sha512-LgaXaBM5QXRCeYt3DzphEhE/OirEGnV4iJrXKGJ/FrYMH7kOao85rPmCtYQNYzIy6K0XstmATmTvFRziZ/M4VQ== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-remove@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-remove/-/interaction-external-remove-3.8.1.tgz#527efd06f93123c384699ea080053d66fa337ebd" + integrity sha512-mwo1DRJPIqzrWfs2G+kfQ5/HyM5j/soIj11zur3BkIlm9vdYIxUpA+hvO734oekSjJxY7YFmYUaqc4vC5TFE5w== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-repulse@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-repulse/-/interaction-external-repulse-3.8.1.tgz#894ce2d8451906516d50ebea5c07387add154075" + integrity sha512-r0E828zrKIRHA27daItHtI9QEp1tO8d8dmF8Ld8+orn7q0+BKG+uGvNTYJFZ+hqR+lp5AkLOiThf7L2wLS9M1A== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-external-slow@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-external-slow/-/interaction-external-slow-3.8.1.tgz#1424364ac0fc523ed8eeecc39b192fb3114a11d7" + integrity sha512-U4P6c9V6/fSDsWchD4oAYAIPHA/203LzQ7+792cMxa7YThza0VS7YyJUQ1PACjGMmfeKbE34/eoGPqESKakeLw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-particles-attract@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-particles-attract/-/interaction-particles-attract-3.8.1.tgz#a3e225a7f81619188c22f2c039b6f2334e6c1e37" + integrity sha512-lo5JAVdeh1tQq/7SDsIllNdyIJgF3hSquWLARUIwGolezD91bEmHp/rlhTscX5NrqiM3y7z3inJPhR0nP5kGeg== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-particles-collisions@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-particles-collisions/-/interaction-particles-collisions-3.8.1.tgz#18e57f33ef5de5ebc9fd762d25a2366d8fe8afd7" + integrity sha512-teqn1CZVoJkT/ubhkb4R/H1rnx7DoIeerHXS5uME+vrLIqzkn8QlWdEdTJ7PhdB+Ct2iYAeXCrJWwIqnKaAL3w== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/interaction-particles-links@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/interaction-particles-links/-/interaction-particles-links-3.8.1.tgz#1f0b2aee657cc96d46c29f38fba02b602fb55d97" + integrity sha512-D+X7wEWyhfV7J0uDWf5vWDhxjfaNovNZW0BWscR9qSy8pl3hjRpv0sJ/QaQFscmK5SzVz28tUFDRLbH1aV5v/Q== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/move-base@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/move-base/-/move-base-3.8.1.tgz#4a9681076eca09d5fd45ce4d786f44e5de1cb291" + integrity sha512-DNFRL1QT8ZQYLg3fIk74EbHJq5HGOq9CM2bCci9dDcdymvN4L7aWVFQavRiWDbi3y1EUW3+jeHSMbD3qHAfOeA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/move-parallax@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/move-parallax/-/move-parallax-3.8.1.tgz#ea80cd3853f5f26ecd26b49458b192325b1635f0" + integrity sha512-umrIttaJGUgfxpnolbMU2BekoN4gw0RgcfVsWR7jzHErA7eTzdJ2mikbQFD+3/1DfTDgJOjWx+dy8a3G/bSsZg== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/plugin-easing-quad@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/plugin-easing-quad/-/plugin-easing-quad-3.8.1.tgz#8578aae07295b9624648d755762b4b50f50ac48d" + integrity sha512-+BiPNHgsNbbh0AhWKjrmJaAu5c37naqjbME8ZYl0BClI0AC5AzBUaezYRxECaLrdtHJvKrZXFMr6Q0sxjDc6QQ== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/plugin-hex-color@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/plugin-hex-color/-/plugin-hex-color-3.8.1.tgz#622c093845aafe61d9325a6b77498f4943277321" + integrity sha512-AmgB7XIYBCvg5HcqYb19YpcjEx2k4DpU2e24n0rradDDeqKKcz7EWI/08FlAnDb5HUs1em63vaAanl1vdm3+OA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/plugin-hsl-color@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/plugin-hsl-color/-/plugin-hsl-color-3.8.1.tgz#61a5b053ee7df32a11a87bf77949591467f88625" + integrity sha512-Ja6oEX6yu0064e4a+Fv1TBJiG5y0hqWwoOKSqf/Ra/zo01ageOEvDVX70FOVSrP+iEPGPznKVNcZs1tEOOvO0g== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/plugin-rgb-color@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/plugin-rgb-color/-/plugin-rgb-color-3.8.1.tgz#f1cd79de595fed6f17112b14145057853f59237a" + integrity sha512-xNLqnaFUYjU+7dCHQXjZdM4UojUAVorPVmXlYmkh1xmujLljEaFTwCg1UJVlNq+fXENIFkeaf3/XT0U/q0ZBTA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/react@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@tsparticles/react/-/react-3.0.0.tgz#d0a794ba53164eb39ce88a3961be723a636b37c0" + integrity sha512-hjGEtTT1cwv6BcjL+GcVgH++KYs52bIuQGW3PWv7z3tMa8g0bd6RI/vWSLj7p//NZ3uTjEIeilYIUPBh7Jfq/Q== + +"@tsparticles/shape-circle@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-circle/-/shape-circle-3.8.1.tgz#01e58bd4a2d6fd2ca06ca0ea12f9021e9f276878" + integrity sha512-dM/f+qcpd8/KfviuVuKiTS8KLDE/T7xxHK7EI2S49yPW6yrJJBXdL7T4N9/n/6PF+Wslcl+kf/eTDjEAI3WjNQ== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/shape-emoji@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-emoji/-/shape-emoji-3.8.1.tgz#8b3334a3186617e295de617cb730de435e3762f2" + integrity sha512-xiXNZ/afdecengUXhOqgUwR+vysgaseVpzEjoGoliOMWq4WHWv+S6ujNfes2oz3x736mTlvKdXcEWRncSXaKWw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/shape-image@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-image/-/shape-image-3.8.1.tgz#960f0ebc94b8755b7b8ea1545ab194c0d8ce3bcd" + integrity sha512-7Yi25uLXvcY5A6TzyVBjYPsTmeTrE+0a2YO8kdp3O7V9NRGCSfXKnPRFp+lNOTiQRRvOG+SSzx2G18dfc/jwQg== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/shape-line@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-line/-/shape-line-3.8.1.tgz#c00fb18ceb1f3b86492f934b15fb0b61b92c2bb2" + integrity sha512-aXVKkpGLgi1hbU/JO+opzy3OTt6PfxWrhGZyI0ms3vdcRX9uYlq4GoNUoKPVfntjWzhecF+FNNZ9gqUG/+WZLQ== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/shape-polygon@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-polygon/-/shape-polygon-3.8.1.tgz#b3b28b523bd0af6766c9ca4d3eaedce9facadd47" + integrity sha512-1pAx85NJbgmsOngl+ZAYH8vxwPJmoddjWCbWTD0wlp/x+2NRjn1iaGBKObPKLgwVzsAXb9qNHMsUX/x0C54svw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/shape-square@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-square/-/shape-square-3.8.1.tgz#0356e931dbb3edb5768a92c6be12b898962da5fb" + integrity sha512-4cjDt6542dkc15zxG1VYT7ScgPXM3+5VGtwMfh5CYNBx+GZZ3R+XUo1Q66JadcqKcNdHXfMWbXCMxs0GaiTtSw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/shape-star@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/shape-star/-/shape-star-3.8.1.tgz#2191f4d4b252e712469eb0f85a5a307517f2601e" + integrity sha512-wBxnawqan/ocguNxY6cOEXF+YVnLIUmGBlnVGYx/7U9E2UHuHEKkoumob4fUflKISjvj5eQLpm/E1eUfYMd6RA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/slim@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/slim/-/slim-3.8.1.tgz#198cc80bbfd787a3e55da1f35f29d6aaf6de4b24" + integrity sha512-b6JV8MrxMz0XYn0eBCI/Mq8VCRyeaWfUyQaQyxLiRd96xpBXCeULooJF+Eaz9it1sUI898a5QfvY8djNXs4OJw== + dependencies: + "@tsparticles/basic" "3.8.1" + "@tsparticles/engine" "3.8.1" + "@tsparticles/interaction-external-attract" "3.8.1" + "@tsparticles/interaction-external-bounce" "3.8.1" + "@tsparticles/interaction-external-bubble" "3.8.1" + "@tsparticles/interaction-external-connect" "3.8.1" + "@tsparticles/interaction-external-grab" "3.8.1" + "@tsparticles/interaction-external-pause" "3.8.1" + "@tsparticles/interaction-external-push" "3.8.1" + "@tsparticles/interaction-external-remove" "3.8.1" + "@tsparticles/interaction-external-repulse" "3.8.1" + "@tsparticles/interaction-external-slow" "3.8.1" + "@tsparticles/interaction-particles-attract" "3.8.1" + "@tsparticles/interaction-particles-collisions" "3.8.1" + "@tsparticles/interaction-particles-links" "3.8.1" + "@tsparticles/move-parallax" "3.8.1" + "@tsparticles/plugin-easing-quad" "3.8.1" + "@tsparticles/shape-emoji" "3.8.1" + "@tsparticles/shape-image" "3.8.1" + "@tsparticles/shape-line" "3.8.1" + "@tsparticles/shape-polygon" "3.8.1" + "@tsparticles/shape-square" "3.8.1" + "@tsparticles/shape-star" "3.8.1" + "@tsparticles/updater-life" "3.8.1" + "@tsparticles/updater-rotate" "3.8.1" + "@tsparticles/updater-stroke-color" "3.8.1" + +"@tsparticles/updater-color@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-color/-/updater-color-3.8.1.tgz#f35954159a8671be6a4102644ede673370f164e1" + integrity sha512-HKrZzrF8YJ+TD+FdIwaWOPV565bkBhe+Ewj7CwKblG7H/SG+C6n1xIYobXkGP5pYkkQ+Cm1UV/Aq0Ih7sa+rJg== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/updater-life@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-life/-/updater-life-3.8.1.tgz#54f95dc1d16740a6ff2e275585657a7468d7d9fb" + integrity sha512-5rCFFKD7js1lKgTpKOLo2OfmisWp4qqMVUVR4bNPeR0Ne/dcwDbKDzWyYS2AMsvWv/gcTTtWiarRfAiVQ5HtNg== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/updater-opacity@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-opacity/-/updater-opacity-3.8.1.tgz#ffebbf9260aede3194682bc2f377185cbf902cfd" + integrity sha512-41dJ0T7df7AUFFkV9yU0buUfUwh+hLYcViXxkDy+6CJiiNCNZ4H404w1DTpBQLL4fbxUcDk9BXZLV7gkE2OfAw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/updater-out-modes@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-out-modes/-/updater-out-modes-3.8.1.tgz#8de70e28510cd50a1d77d7a7910b20d3a1c61eeb" + integrity sha512-BY8WqQwoDFpgPybwTzBU2GnxtRkjWnGStqBnR53x5+f1j7geTSY6WjcOvl1W+IkjtwtjiifriwBl41EbqMrjdQ== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/updater-rotate@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-rotate/-/updater-rotate-3.8.1.tgz#12accee0128ab1bf9bb022589643ea90ed01ffc7" + integrity sha512-gpI07H1+diuuUdhJsQ1RlfHSD3fzBJrjyuwGuoXgHmvKzak6EWKpYfUMOraH4Dm41m/4kJZelle4nST+NpIuoA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/updater-size@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-size/-/updater-size-3.8.1.tgz#b1b7f5197fa69b1346bed9a2da68771f35d0a88c" + integrity sha512-SC2ZxewtpwKadCalotK6x2YanxRO3hTMW1Rxzx9V2rcjAIgh/Nw49Vuithy2TDq8RtTc9rHDAPic2vMQ/lYQwA== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tsparticles/updater-stroke-color@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@tsparticles/updater-stroke-color/-/updater-stroke-color-3.8.1.tgz#ab6bdf5035a714d49dad6efbd94a571edfa67fef" + integrity sha512-rofHCf5oRHP2H+BTJ4D3r4mTqZtre3c8bsdJHATle26+gLpzbt6I1a83wAY8xnsQa1BNnRAfEsnb7GpdZ1vYaw== + dependencies: + "@tsparticles/engine" "3.8.1" + +"@tybys/wasm-util@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" + integrity sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ== + dependencies: + tslib "^2.4.0" + +"@tybys/wasm-util@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" + integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== + dependencies: + tslib "^2.4.0" + +"@types/bn.js@^5.1.6": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.2.0.tgz#4349b9710e98f9ab3cdc50f1c5e4dcbd8ef29c80" + integrity sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q== + dependencies: + "@types/node" "*" + +"@types/connect@^3.4.33": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/cookie@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5" + integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA== + +"@types/d3-array@^3.0.3": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5" + integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg== + +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-ease@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-interpolate@^3.0.1": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.1.tgz#f632b380c3aca1dba8e34aa049bcd6a4af23df8a" + integrity sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg== + +"@types/d3-scale@^4.0.2": + version "4.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.9.tgz#57a2f707242e6fe1de81ad7bfcccaaf606179afb" + integrity sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw== + dependencies: + "@types/d3-time" "*" + +"@types/d3-shape@^3.1.0": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555" + integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time@*", "@types/d3-time@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f" + integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g== + +"@types/d3-timer@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + +"@types/debug@^4.0.0": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== + dependencies: + "@types/ms" "*" + +"@types/diff-match-patch@^1.0.36": + version "1.0.36" + resolved "https://registry.yarnpkg.com/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz#dcef10a69d357fe9d43ac4ff2eca6b85dbf466af" + integrity sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg== + +"@types/estree-jsx@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" + integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== + dependencies: + "@types/estree" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/hast@^3.0.0", "@types/hast@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + dependencies: + "@types/unist" "*" + +"@types/katex@^0.16.0": + version "0.16.7" + resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.16.7.tgz#03ab680ab4fa4fbc6cb46ecf987ecad5d8019868" + integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ== + +"@types/mdast@^4.0.0": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" + integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== + dependencies: + "@types/unist" "*" + +"@types/mdx@^2.0.0", "@types/mdx@^2.0.13": + version "2.0.13" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.13.tgz#68f6877043d377092890ff5b298152b0a21671bd" + integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== + +"@types/ms@*": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" + integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== + +"@types/node-fetch@^2.6.12": + version "2.6.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" + integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + +"@types/node@*", "@types/node@>=13.7.0": + version "24.0.15" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.0.15.tgz#f34fbc973e7d64217106e0c59ed8761e6b51381e" + integrity sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA== + dependencies: + undici-types "~7.8.0" + +"@types/node@22.14.0": + version "22.14.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.0.tgz#d3bfa3936fef0dbacd79ea3eb17d521c628bb47e" + integrity sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA== + dependencies: + undici-types "~6.21.0" + +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/react-dom@^19.1.2": + version "19.1.6" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.6.tgz#4af629da0e9f9c0f506fc4d1caa610399c595d64" + integrity sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw== + +"@types/react@^19.1.0": + version "19.1.8" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.8.tgz#ff8395f2afb764597265ced15f8dddb0720ae1c3" + integrity sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g== + dependencies: + csstype "^3.0.2" + +"@types/statuses@^2.0.4": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/statuses/-/statuses-2.0.6.tgz#66748315cc9a96d63403baa8671b2c124f8633aa" + integrity sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA== + +"@types/tough-cookie@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + +"@types/trusted-types@^2.0.2": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + +"@types/unist@*", "@types/unist@^3.0.0": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" + integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== + +"@types/unist@^2.0.0": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + +"@types/uuid@8.3.4", "@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + +"@types/w3c-web-usb@^1.0.6": + version "1.0.10" + resolved "https://registry.yarnpkg.com/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz#cf89cccd2d93b6245e784c19afe0a9f5038d4528" + integrity sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ== + +"@types/web@^0.0.197": + version "0.0.197" + resolved "https://registry.yarnpkg.com/@types/web/-/web-0.0.197.tgz#624cf02b57e79ec9d90b61b24b95fe1732713e45" + integrity sha512-V4sOroWDADFx9dLodWpKm298NOJ1VJ6zoDVgaP+WBb/utWxqQ6gnMzd9lvVDAr/F3ibiKaxH9i45eS0gQPSTaQ== + +"@types/webidl-conversions@*": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859" + integrity sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA== + +"@types/whatwg-url@^11.0.2": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-11.0.5.tgz#aaa2546e60f0c99209ca13360c32c78caf2c409f" + integrity sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ== + dependencies: + "@types/webidl-conversions" "*" + +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@types/ws@^8.2.2": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== + dependencies: + "@types/node" "*" + +"@ungap/structured-clone@^1.0.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +"@wallet-standard/app@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@wallet-standard/app/-/app-1.1.0.tgz#2ca32e4675536224ebe55a00ad533b7923d7380a" + integrity sha512-3CijvrO9utx598kjr45hTbbeeykQrQfKmSnxeWOgU25TOEpvcipD/bYDQWIqUv1Oc6KK4YStokSMu/FBNecGUQ== + dependencies: + "@wallet-standard/base" "^1.1.0" + +"@wallet-standard/base@^1.0.1", "@wallet-standard/base@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@wallet-standard/base/-/base-1.1.0.tgz#214093c0597a1e724ee6dbacd84191dfec62bb33" + integrity sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ== + +"@wallet-standard/core@^1.0.3": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@wallet-standard/core/-/core-1.1.1.tgz#432e10420dc8892a63224d4863f8304fa01b4ea1" + integrity sha512-5Xmjc6+Oe0hcPfVc5n8F77NVLwx1JVAoCVgQpLyv/43/bhtIif+Gx3WUrDlaSDoM8i2kA2xd6YoFbHCxs+e0zA== + dependencies: + "@wallet-standard/app" "^1.1.0" + "@wallet-standard/base" "^1.1.0" + "@wallet-standard/errors" "^0.1.1" + "@wallet-standard/features" "^1.1.0" + "@wallet-standard/wallet" "^1.1.0" + +"@wallet-standard/errors@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@wallet-standard/errors/-/errors-0.1.1.tgz#e745c5925276c0ac6d02f0d489888c171f5e4680" + integrity sha512-V8Ju1Wvol8i/VDyQOHhjhxmMVwmKiwyxUZBnHhtiPZJTWY0U/Shb2iEWyGngYEbAkp2sGTmEeNX1tVyGR7PqNw== + dependencies: + chalk "^5.4.1" + commander "^13.1.0" + +"@wallet-standard/features@^1.0.3", "@wallet-standard/features@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@wallet-standard/features/-/features-1.1.0.tgz#f256d7b18940c8d134f66164330db358a8f5200e" + integrity sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg== + dependencies: + "@wallet-standard/base" "^1.1.0" + +"@wallet-standard/wallet@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@wallet-standard/wallet/-/wallet-1.1.0.tgz#a1e46a3f1b2d06a0206058562169b1f0e9652d0f" + integrity sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg== + dependencies: + "@wallet-standard/base" "^1.1.0" + +"@walletconnect/core@2.19.0": + version "2.19.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.19.0.tgz#acd84b605b05469aa9962079af2590e583815d49" + integrity sha512-AEoyICLHQEnjijZr9XsL4xtFhC5Cmu0RsEGxAxmwxbfGvAcYcSCNp1fYq0Q6nHc8jyoPOALpwySTle300Y1vxw== + dependencies: + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/jsonrpc-ws-connection" "1.0.16" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.1.0" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.19.0" + "@walletconnect/utils" "2.19.0" + "@walletconnect/window-getters" "1.0.1" + events "3.3.0" + lodash.isequal "4.5.0" + uint8arrays "3.1.0" + +"@walletconnect/core@2.19.1": + version "2.19.1" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.19.1.tgz#71738940341b438326b65b3f49226decbe070bae" + integrity sha512-rMvpZS0tQXR/ivzOxN1GkHvw3jRRMlI/jRX5g7ZteLgg2L0ZcANsFvAU5IxILxIKcIkTCloF9TcfloKVbK3qmw== + dependencies: + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/jsonrpc-ws-connection" "1.0.16" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.1.0" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.19.1" + "@walletconnect/utils" "2.19.1" + "@walletconnect/window-getters" "1.0.1" + es-toolkit "1.33.0" + events "3.3.0" + uint8arrays "3.1.0" + +"@walletconnect/environment@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/environment/-/environment-1.0.1.tgz#1d7f82f0009ab821a2ba5ad5e5a7b8ae3b214cd7" + integrity sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg== + dependencies: + tslib "1.14.1" + +"@walletconnect/events@1.0.1", "@walletconnect/events@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/events/-/events-1.0.1.tgz#2b5f9c7202019e229d7ccae1369a9e86bda7816c" + integrity sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ== + dependencies: + keyvaluestorage-interface "^1.0.0" + tslib "1.14.1" + +"@walletconnect/heartbeat@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz#e8dc5179db7769950c6f9cf59b23516d9b95227d" + integrity sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw== + dependencies: + "@walletconnect/events" "^1.0.1" + "@walletconnect/time" "^1.0.2" + events "^3.3.0" + +"@walletconnect/jsonrpc-http-connection@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz#2f4c3948f074960a3edd07909560f3be13e2c7ae" + integrity sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.6" + "@walletconnect/safe-json" "^1.0.1" + cross-fetch "^3.1.4" + events "^3.3.0" + +"@walletconnect/jsonrpc-provider@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz#696f3e3b6d728b361f2e8b853cfc6afbdf2e4e3e" + integrity sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.8" + "@walletconnect/safe-json" "^1.0.2" + events "^3.3.0" + +"@walletconnect/jsonrpc-types@1.0.4", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz#ce1a667d79eadf2a2d9d002c152ceb68739c230c" + integrity sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ== + dependencies: + events "^3.3.0" + keyvaluestorage-interface "^1.0.0" + +"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz#82d0cc6a5d6ff0ecc277cb35f71402c91ad48d72" + integrity sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw== + dependencies: + "@walletconnect/environment" "^1.0.1" + "@walletconnect/jsonrpc-types" "^1.0.3" + tslib "1.14.1" + +"@walletconnect/jsonrpc-ws-connection@1.0.16": + version "1.0.16" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz#666bb13fbf32a2d4f7912d5b4d0bdef26a1d057b" + integrity sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.6" + "@walletconnect/safe-json" "^1.0.2" + events "^3.3.0" + ws "^7.5.1" + +"@walletconnect/keyvaluestorage@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" + integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== + dependencies: + "@walletconnect/safe-json" "^1.0.1" + idb-keyval "^6.2.1" + unstorage "^1.9.0" + +"@walletconnect/logger@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.1.2.tgz#813c9af61b96323a99f16c10089bfeb525e2a272" + integrity sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw== + dependencies: + "@walletconnect/safe-json" "^1.0.2" + pino "7.11.0" + +"@walletconnect/relay-api@1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.11.tgz#80ab7ef2e83c6c173be1a59756f95e515fb63224" + integrity sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q== + dependencies: + "@walletconnect/jsonrpc-types" "^1.0.2" + +"@walletconnect/relay-auth@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz#c3c5f54abd44a5138ea7d4fe77970597ba66c077" + integrity sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ== + dependencies: + "@noble/curves" "1.8.0" + "@noble/hashes" "1.7.0" + "@walletconnect/safe-json" "^1.0.1" + "@walletconnect/time" "^1.0.2" + uint8arrays "^3.0.0" + +"@walletconnect/safe-json@1.0.2", "@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.2.tgz#7237e5ca48046e4476154e503c6d3c914126fa77" + integrity sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA== + dependencies: + tslib "1.14.1" + +"@walletconnect/sign-client@2.19.0": + version "2.19.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.19.0.tgz#775d21928a402ab5506f7c0b6065932cd6c8724d" + integrity sha512-+GkuJzPK9SPq+RZgdKHNOvgRagxh/hhYWFHOeSiGh3DyAQofWuFTq4UrN/MPjKOYswSSBKfIa+iqKYsi4t8zLQ== + dependencies: + "@walletconnect/core" "2.19.0" + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/logger" "2.1.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.19.0" + "@walletconnect/utils" "2.19.0" + events "3.3.0" + +"@walletconnect/sign-client@2.19.1": + version "2.19.1" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.19.1.tgz#6cfbb4ee0eaf3a8774a8c70ff65ba23177e8f388" + integrity sha512-OgBHRPo423S02ceN3lAzcZ3MYb1XuLyTTkKqLmKp/icYZCyRzm3/ynqJDKndiBLJ5LTic0y07LiZilnliYqlvw== + dependencies: + "@walletconnect/core" "2.19.1" + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/logger" "2.1.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.19.1" + "@walletconnect/utils" "2.19.1" + events "3.3.0" + +"@walletconnect/solana-adapter@^0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@walletconnect/solana-adapter/-/solana-adapter-0.0.8.tgz#c727fee835ef45a868479e15662d2ccdb41a405c" + integrity sha512-Qb7MT8SdkeBldfUCmF+rYW6vL98mxPuT1yAwww5X2vpx7xEPZvFCoAKnyT5fXu0v56rMxhW3MGejnHyyYdDY7Q== + dependencies: + "@reown/appkit" "1.7.2" + "@walletconnect/universal-provider" "2.19.0" + "@walletconnect/utils" "2.19.0" + bs58 "6.0.0" + +"@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" + integrity sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g== + dependencies: + tslib "1.14.1" + +"@walletconnect/types@2.19.0": + version "2.19.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.19.0.tgz#cbb8053c20064377a85440ede06d5057c34c5786" + integrity sha512-Ttse3p3DCdFQ/TRQrsPMQJzFr7cb/2AF5ltLPzXRNMmapmGydc6WO8QU7g/tGEB3RT9nHcLY2aqlwsND9sXMxA== + dependencies: + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + events "3.3.0" + +"@walletconnect/types@2.19.1": + version "2.19.1" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.19.1.tgz#ec78c5a05238e220871cca3e360193584af2d968" + integrity sha512-XWWGLioddH7MjxhyGhylL7VVariVON2XatJq/hy0kSGJ1hdp31z194nHN5ly9M495J9Hw8lcYjGXpsgeKvgxzw== + dependencies: + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + events "3.3.0" + +"@walletconnect/universal-provider@2.19.0": + version "2.19.0" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.19.0.tgz#2648a604def3a81cc91893ffd1bba01c6fa637d5" + integrity sha512-e9JvadT5F8QwdLmd7qBrmACq04MT7LQEe1m3X2Fzvs3DWo8dzY8QbacnJy4XSv5PCdxMWnua+2EavBk8nrI9QA== + dependencies: + "@walletconnect/events" "1.0.1" + "@walletconnect/jsonrpc-http-connection" "1.0.8" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + "@walletconnect/sign-client" "2.19.0" + "@walletconnect/types" "2.19.0" + "@walletconnect/utils" "2.19.0" + events "3.3.0" + lodash "4.17.21" + +"@walletconnect/universal-provider@2.19.1": + version "2.19.1" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.19.1.tgz#9908431b766fffcb0f617f3fdb7e85f27f05f9de" + integrity sha512-4rdLvJ2TGDIieNWW3sZw2MXlX65iHpTuKb5vyvUHQtjIVNLj+7X/09iUAI/poswhtspBK0ytwbH+AIT/nbGpjg== + dependencies: + "@walletconnect/events" "1.0.1" + "@walletconnect/jsonrpc-http-connection" "1.0.8" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + "@walletconnect/sign-client" "2.19.1" + "@walletconnect/types" "2.19.1" + "@walletconnect/utils" "2.19.1" + es-toolkit "1.33.0" + events "3.3.0" + +"@walletconnect/utils@2.19.0": + version "2.19.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.19.0.tgz#5fffb1f83928ece8c534d1596134e5c097010804" + integrity sha512-LZ0D8kevknKfrfA0Sq3Hf3PpmM8oWyNfsyWwFR51t//2LBgtN2Amz5xyoDDJcjLibIbKAxpuo/i0JYAQxz+aPA== + dependencies: + "@noble/ciphers" "1.2.1" + "@noble/curves" "1.8.1" + "@noble/hashes" "1.7.1" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.1.0" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.19.0" + "@walletconnect/window-getters" "1.0.1" + "@walletconnect/window-metadata" "1.0.1" + detect-browser "5.3.0" + elliptic "6.6.1" + query-string "7.1.3" + uint8arrays "3.1.0" + viem "2.23.2" + +"@walletconnect/utils@2.19.1": + version "2.19.1" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.19.1.tgz#16cbc173cd3b28cbf86ca5c6e362057810da07f9" + integrity sha512-aOwcg+Hpph8niJSXLqkU25pmLR49B8ECXp5gFQDW5IeVgXHoOoK7w8a79GBhIBheMLlIt1322sTKQ7Rq5KzzFg== + dependencies: + "@noble/ciphers" "1.2.1" + "@noble/curves" "1.8.1" + "@noble/hashes" "1.7.1" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.1.0" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.19.1" + "@walletconnect/window-getters" "1.0.1" + "@walletconnect/window-metadata" "1.0.1" + bs58 "6.0.0" + detect-browser "5.3.0" + elliptic "6.6.1" + query-string "7.1.3" + uint8arrays "3.1.0" + viem "2.23.2" + +"@walletconnect/window-getters@1.0.1", "@walletconnect/window-getters@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.1.tgz#f36d1c72558a7f6b87ecc4451fc8bd44f63cbbdc" + integrity sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q== + dependencies: + tslib "1.14.1" + +"@walletconnect/window-metadata@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz#2124f75447b7e989e4e4e1581d55d25bc75f7be5" + integrity sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA== + dependencies: + "@walletconnect/window-getters" "^1.0.1" + tslib "1.14.1" + +"@xrplf/isomorphic@^1.0.0", "@xrplf/isomorphic@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@xrplf/isomorphic/-/isomorphic-1.0.1.tgz#d7676e0ec0e55a39f37ddc1f3cc30eeab52e0739" + integrity sha512-0bIpgx8PDjYdrLFeC3csF305QQ1L7sxaWnL5y71mCvhenZzJgku9QsA+9QCXBC1eNYtxWO/xR91zrXJy2T/ixg== + dependencies: + "@noble/hashes" "^1.0.0" + eventemitter3 "5.0.1" + ws "^8.13.0" + +"@xrplf/secret-numbers@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@xrplf/secret-numbers/-/secret-numbers-1.0.0.tgz#cc19ff84236cc2737b38f2e42a29924f2b8ffc0e" + integrity sha512-qsCLGyqe1zaq9j7PZJopK+iGTGRbk6akkg6iZXJJgxKwck0C5x5Gnwlb1HKYGOwPKyrXWpV6a2YmcpNpUFctGg== + dependencies: + "@xrplf/isomorphic" "^1.0.0" + ripple-keypairs "^2.0.0" + +"@zxing/browser@0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@zxing/browser/-/browser-0.0.7.tgz#5fa7680a867b660f48d3288fdf63e0174ad531c7" + integrity sha512-AepzMgDnD6EjxewqmXpHJsi4S3Gw9ilZJLIbTf6fWuWySEcHBodnGu3p7FWlgq1Sd5QyfPhTum5z3CBkkhMVng== + optionalDependencies: + "@zxing/text-encoding" "^0.9.0" + +"@zxing/library@^0.18.3": + version "0.18.6" + resolved "https://registry.yarnpkg.com/@zxing/library/-/library-0.18.6.tgz#717af8c6c1fd982865e21051afdd7b470ae6674c" + integrity sha512-bulZ9JHoLFd9W36pi+7e7DnEYNJhljYjZ1UTsKPOoLMU3qtC+REHITeCRNx40zTRJZx18W5TBRXt5pq2Uopjsw== + dependencies: + ts-custom-error "^3.0.0" + optionalDependencies: + "@zxing/text-encoding" "~0.9.0" + +"@zxing/text-encoding@^0.9.0", "@zxing/text-encoding@~0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" + integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== + +abitype@1.0.8, abitype@^1.0.6, abitype@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba" + integrity sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +accepts@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" + integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== + dependencies: + mime-types "^3.0.0" + negotiator "^1.0.0" + +acorn-jsx@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.0.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +agent-base@^7.0.2, agent-base@^7.1.2: + version "7.1.4" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" + integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== + +agentkeepalive@^4.5.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== + dependencies: + humanize-ms "^1.2.1" + +ai@^4.3.12: + version "4.3.19" + resolved "https://registry.yarnpkg.com/ai/-/ai-4.3.19.tgz#e94f5b37f3885bc9c9637f892e13bddd0a1857e5" + integrity sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q== + dependencies: + "@ai-sdk/provider" "1.1.3" + "@ai-sdk/provider-utils" "2.2.8" + "@ai-sdk/react" "1.2.12" + "@ai-sdk/ui-utils" "1.2.11" + "@opentelemetry/api" "1.9.0" + jsondiffpatch "0.6.0" + +ajv@^6.12.6: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-hidden@^1.2.4: + version "1.2.6" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a" + integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA== + dependencies: + tslib "^2.0.0" + +asn1.js@^4.10.1: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +assert@^2.0.0, assert@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + +ast-types@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.16.1.tgz#7a9da1617c9081bc121faafe91711b4c8bb81da2" + integrity sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg== + dependencies: + tslib "^2.0.1" + +astring@^1.8.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.9.0.tgz#cc73e6062a7eb03e7d19c22d8b0b3451fd9bfeef" + integrity sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg== + +async-mutex@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.5.0.tgz#353c69a0b9e75250971a64ac203b0ebfddd75482" + integrity sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA== + dependencies: + tslib "^2.4.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axios@^1.8.4: + version "1.10.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.10.0.tgz#af320aee8632eaf2a400b6a1979fa75856f38d54" + integrity sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +bare-addon-resolve@^1.3.0: + version "1.9.4" + resolved "https://registry.yarnpkg.com/bare-addon-resolve/-/bare-addon-resolve-1.9.4.tgz#50ad7b26de493f978f09bbbbe987219c4ecbfd28" + integrity sha512-unn6Vy/Yke6F99vg/7tcrvM2KUvIhTNniaSqDbam4AWkd4NhvDVSrQiRYVlNzUV2P7SPobkCK7JFVxrJk9btCg== + dependencies: + bare-module-resolve "^1.10.0" + bare-semver "^1.0.0" + +bare-module-resolve@^1.10.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/bare-module-resolve/-/bare-module-resolve-1.11.1.tgz#4ea4d1dd82947a00b4f4bbbfce2379eedd9c9e09" + integrity sha512-DCxeT9i8sTs3vUMA3w321OX/oXtNEu5EjObQOnTmCdNp5RXHBAvAaBDHvAi9ta0q/948QPz+co6SsGi6aQMYRg== + dependencies: + bare-semver "^1.0.0" + +bare-os@^3.0.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-3.6.1.tgz#9921f6f59edbe81afa9f56910658422c0f4858d4" + integrity sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g== + +bare-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.0.0.tgz#b59d18130ba52a6af9276db3e96a2e3d3ea52178" + integrity sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw== + dependencies: + bare-os "^3.0.1" + +bare-semver@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bare-semver/-/bare-semver-1.0.1.tgz#4737d660785f07cb723cefa6b022089e59120a61" + integrity sha512-UtggzHLiTrmFOC/ogQ+Hy7VfoKoIwrP1UFcYtTxoCUdLtsIErT8+SWtOC2DH/snT9h+xDrcBEPcwKei1mzemgg== + +bare-url@^2.1.0: + version "2.1.6" + resolved "https://registry.yarnpkg.com/bare-url/-/bare-url-2.1.6.tgz#86937c11c29b094c821459d3041b7fa67322266e" + integrity sha512-FgjDeR+/yDH34By4I0qB5NxAoWv7dOTYcOXwn73kr+c93HyC2lU6tnjifqUe33LKMJcDyCYPQjEAqgOQiXkE2Q== + dependencies: + bare-path "^3.0.0" + +base-x@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.11.tgz#40d80e2a1aeacba29792ccc6c5354806421287ff" + integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== + dependencies: + safe-buffer "^5.0.1" + +base-x@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.1.tgz#817fb7b57143c501f649805cb247617ad016a885" + integrity sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw== + +base-x@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.1.tgz#16bf35254be1df8aca15e36b7c1dda74b2aa6b03" + integrity sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg== + +base32.js@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base32.js/-/base32.js-0.1.0.tgz#b582dec693c2f11e893cf064ee6ac5b6131a2202" + integrity sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ== + +base64-js@^1.3.1, base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base64url@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + +bchaddrjs@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/bchaddrjs/-/bchaddrjs-0.5.2.tgz#1f52b5077329774e7c82d4882964628106bb11a0" + integrity sha512-OO7gIn3m7ea4FVx4cT8gdlWQR2+++EquhdpWQJH9BQjK63tJJ6ngB3QMZDO6DiBoXiIGUsTPHjlrHVxPGcGxLQ== + dependencies: + bs58check "2.1.2" + buffer "^6.0.3" + cashaddrjs "0.4.4" + stream-browserify "^3.0.0" + +bech32@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355" + integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== + +big-integer@1.6.36: + version "1.6.36" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.36.tgz#78631076265d4ae3555c04f85e7d9d2f3a071a36" + integrity sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg== + +big.js@6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-6.2.2.tgz#be3bb9ac834558b53b099deef2a1d06ac6368e1a" + integrity sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ== + +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.1.2, bignumber.js@^9.3.0: + version "9.3.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.1.tgz#759c5aaddf2ffdc4f154f7b493e1c8770f88c4d7" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bip66@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bip66/-/bip66-2.0.0.tgz#96b5cca18ad10a009f7c8ea4eb24079e37ec9c79" + integrity sha512-kBG+hSpgvZBrkIm9dt5T1Hd/7xGCPEX2npoxAWZfsK1FvjgaxySEh2WizjyIstWXriKo9K9uJ4u0OnsyLDUPXQ== + +bitcoin-ops@^1.3.0, bitcoin-ops@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz#e45de620398e22fd4ca6023de43974ff42240278" + integrity sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow== + +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + +blake-hash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/blake-hash/-/blake-hash-2.0.0.tgz#af184dce641951126d05b7d1c3de3224f538d66e" + integrity sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w== + dependencies: + node-addon-api "^3.0.0" + node-gyp-build "^4.2.2" + readable-stream "^3.6.0" + +blakejs@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== + +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1, bn.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== + +body-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa" + integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg== + dependencies: + bytes "^3.1.2" + content-type "^1.0.5" + debug "^4.4.0" + http-errors "^2.0.0" + iconv-lite "^0.6.3" + on-finished "^2.4.1" + qs "^6.14.0" + raw-body "^3.0.0" + type-is "^2.0.0" + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserify-aes@^1.0.4, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.1.tgz#06e530907fe2949dc21fc3c2e2302e10b1437238" + integrity sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ== + dependencies: + bn.js "^5.2.1" + randombytes "^2.1.0" + safe-buffer "^5.2.1" + +browserify-sign@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208" + integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw== + dependencies: + bn.js "^5.2.1" + browserify-rsa "^4.1.0" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.5" + hash-base "~3.0" + inherits "^2.0.4" + parse-asn1 "^5.1.7" + readable-stream "^2.3.8" + safe-buffer "^5.2.1" + +browserslist@^4.24.0: + version "4.25.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" + integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== + dependencies: + caniuse-lite "^1.0.30001726" + electron-to-chromium "^1.5.173" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + +bs58@6.0.0, bs58@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-6.0.0.tgz#a2cda0130558535dd281a2f8697df79caaf425d8" + integrity sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw== + dependencies: + base-x "^5.0.0" + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== + dependencies: + base-x "^4.0.0" + +bs58check@2.1.2, bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +bs58check@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-4.0.0.tgz#46cda52a5713b7542dcb78ec2efdf78f5bf1d23c" + integrity sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g== + dependencies: + "@noble/hashes" "^1.2.0" + bs58 "^6.0.0" + +bson@^6.10.4: + version "6.10.4" + resolved "https://registry.yarnpkg.com/bson/-/bson-6.10.4.tgz#d530733bb5bb16fb25c162e01a3344fab332fd2b" + integrity sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng== + +buffer-equal-constant-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer-layout@^1.2.0, buffer-layout@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" + integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== + +buffer-reverse@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" + integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +buffer@^5.1.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +bufferutil@^4.0.1: + version "4.0.9" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.9.tgz#6e81739ad48a95cad45a279588e13e95e24a800a" + integrity sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw== + dependencies: + node-gyp-build "^4.3.0" + +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +bytes@3.1.2, bytes@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-keys@^9.1.3: + version "9.1.3" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-9.1.3.tgz#6367b2f9ec5724af541f58f0dcfee9b200022e5c" + integrity sha512-Rircqi9ch8AnZscQcsA1C47NFdaO3wukpmIRzYcDOrmvgt78hM/sj5pZhZNec2NM12uk5vTwRHZ4anGcrC4ZTg== + dependencies: + camelcase "^8.0.0" + map-obj "5.0.0" + quick-lru "^6.1.1" + type-fest "^4.3.2" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +camelcase@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-8.0.0.tgz#c0d36d418753fb6ad9c5e0437579745c1c14a534" + integrity sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA== + +caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001726: + version "1.0.30001727" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz#22e9706422ad37aa50556af8c10e40e2d93a8b85" + integrity sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q== + +cashaddrjs@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cashaddrjs/-/cashaddrjs-0.4.4.tgz#169f1ae620d325db77700273d972282adeeee331" + integrity sha512-xZkuWdNOh0uq/mxJIng6vYWfTowZLd9F4GMAlp2DwFHlcCqCm91NtuAc47RuV4L7r4PYcY5p6Cr2OKNb4hnkWA== + dependencies: + big-integer "1.6.36" + +cbor-sync@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cbor-sync/-/cbor-sync-1.0.4.tgz#5a11a1ab75c2a14d1af1b237fd84aa8c1593662f" + integrity sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA== + +ccount@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" + integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== + +chalk@^5.0.0, chalk@^5.3.0, chalk@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + +character-entities-html4@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" + integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== + +character-entities-legacy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" + integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== + +character-entities@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" + integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== + +character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + +chokidar@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7" + integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + +class-variance-authority@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz#4008a798a0e4553a781a57ac5177c9fb5d043787" + integrity sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg== + dependencies: + clsx "^2.1.1" + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-spinners@^2.6.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== + +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + +clsx@^2.0.0, clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +cmdk@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-1.1.1.tgz#b8524272699ccaa37aaf07f36850b376bf3d58e5" + integrity sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg== + dependencies: + "@radix-ui/react-compose-refs" "^1.1.1" + "@radix-ui/react-dialog" "^1.1.6" + "@radix-ui/react-id" "^1.1.0" + "@radix-ui/react-primitive" "^2.0.2" + +code-block-writer@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" + integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== + +collapse-white-space@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-2.1.0.tgz#640257174f9f42c740b40f3b55ee752924feefca" + integrity sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + +colorette@^2.0.7: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + +commander@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + +commander@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.0.tgz#f244fc74a92343514e56229f16ef5c5e22ced5e9" + integrity sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA== + +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +compute-scroll-into-view@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz#02c3386ec531fb6a9881967388e53e8564f3e9aa" + integrity sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw== + +content-disposition@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2" + integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg== + dependencies: + safe-buffer "5.2.1" + +content-type@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-es@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.2.2.tgz#18ceef9eb513cac1cb6c14bcbf8bdb2679b34821" + integrity sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg== + +cookie-signature@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" + integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== + +cookie@^0.7.1, cookie@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +"core@link:@shikijs/rehype/core": + version "0.0.0" + uid "" + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cosmiconfig@^8.1.3: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + +crc@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" + integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== + dependencies: + buffer "^5.1.0" + +create-ecdh@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hash@~1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + integrity sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-fetch@^3.1.4, cross-fetch@^3.1.5: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.2.0.tgz#34e9192f53bc757d6614304d9e5e6fb4edb782e3" + integrity sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q== + dependencies: + node-fetch "^2.7.0" + +cross-fetch@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.1.0.tgz#8f69355007ee182e47fa692ecbaa37a52e43c3d2" + integrity sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw== + dependencies: + node-fetch "^2.7.0" + +cross-spawn@^7.0.3, cross-spawn@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crossws@^0.3.4: + version "0.3.5" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.3.5.tgz#daad331d44148ea6500098bc858869f3a5ab81a6" + integrity sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA== + dependencies: + uncrypto "^0.1.3" + +crypto-browserify@^3.12.1: + version "3.12.1" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.1.tgz#bb8921bec9acc81633379aa8f52d69b0b69e0dac" + integrity sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ== + dependencies: + browserify-cipher "^1.0.1" + browserify-sign "^4.2.3" + create-ecdh "^4.0.4" + create-hash "^1.2.0" + create-hmac "^1.1.7" + diffie-hellman "^5.0.3" + hash-base "~3.0.4" + inherits "^2.0.4" + pbkdf2 "^3.1.2" + public-encrypt "^4.0.3" + randombytes "^2.1.0" + randomfill "^1.0.4" + +crypto-hash@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247" + integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== + +crypto-js@^4.1.1, crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: + version "3.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== + dependencies: + internmap "1 - 2" + +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +d3-ease@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-format@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== + +d3-scale@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + +d3-shape@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== + dependencies: + d3-path "^3.1.0" + +"d3-time-format@2 - 4": + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +d3-timer@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + +date-fns@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14" + integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== + +dateformat@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" + integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== + +dayjs@1.11.13: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@4, debug@4.x, debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +debug@~4.3.1, debug@~4.3.2: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decimal.js-light@^2.4.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" + integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== + +decimal.js@^10.5.0: + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + +decode-named-character-reference@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz#25c32ae6dd5e21889549d40f676030e9514cc0ed" + integrity sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q== + dependencies: + character-entities "^2.0.0" + +decode-uri-component@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +defu@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0, depd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +dequal@^2.0.0, dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +derive-valtio@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/derive-valtio/-/derive-valtio-0.1.0.tgz#4b9fb393dfefccfef15fcbbddd745dd22d5d63d7" + integrity sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A== + +des.js@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destr@^2.0.3, destr@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb" + integrity sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA== + +detect-browser@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" + integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== + +detect-europe-js@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/detect-europe-js/-/detect-europe-js-0.1.2.tgz#aa76642e05dae786efc2e01a23d4792cd24c7b88" + integrity sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow== + +detect-libc@^2.0.3, detect-libc@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" + integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== + +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + +devlop@^1.0.0, devlop@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" + integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== + dependencies: + dequal "^2.0.0" + +diff-match-patch@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + +diff@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +diffie-hellman@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dijkstrajs@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23" + integrity sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA== + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dotenv@^16.5.0: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +draggabilly@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/draggabilly/-/draggabilly-3.0.0.tgz#48defe10a67f346a0338caaa40c0765c4d3912d6" + integrity sha512-aEs+B6prbMZQMxc9lgTpCBfyCUhRur/VFucHhIOvlvvdARTj7TcDmX/cdOUtqbjJJUh7+agyJXR5Z6IFe1MxwQ== + dependencies: + get-size "^3.0.0" + unidragger "^3.0.0" + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +duplexify@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" + integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.2" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.5.173: + version "1.5.187" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.187.tgz#8c58854e065962351dc87e95614dd78d50425966" + integrity sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA== + +elliptic@6.6.1, elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + +encodeurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + +engine.io-client@~6.6.1: + version "6.6.3" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.6.3.tgz#815393fa24f30b8e6afa8f77ccca2f28146be6de" + integrity sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.17.1" + xmlhttprequest-ssl "~2.1.1" + +engine.io-parser@~5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== + +enhanced-resolve@^5.18.1: + version "5.18.2" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz#7903c5b32ffd4b2143eeb4b92472bd68effd5464" + integrity sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694" + integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-toolkit@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.33.0.tgz#bcc9d92ef2e1ed4618c00dd30dfda9faddf4a0b7" + integrity sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg== + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +esast-util-from-estree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz#8d1cfb51ad534d2f159dc250e604f3478a79f1ad" + integrity sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ== + dependencies: + "@types/estree-jsx" "^1.0.0" + devlop "^1.0.0" + estree-util-visit "^2.0.0" + unist-util-position-from-estree "^2.0.0" + +esast-util-from-js@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz#5147bec34cc9da44accf52f87f239a40ac3e8225" + integrity sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw== + dependencies: + "@types/estree-jsx" "^1.0.0" + acorn "^8.0.0" + esast-util-from-estree "^2.0.0" + vfile-message "^4.0.0" + +esbuild@^0.25.5, esbuild@~0.25.0: + version "0.25.8" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.8.tgz#482d42198b427c9c2f3a81b63d7663aecb1dda07" + integrity sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.8" + "@esbuild/android-arm" "0.25.8" + "@esbuild/android-arm64" "0.25.8" + "@esbuild/android-x64" "0.25.8" + "@esbuild/darwin-arm64" "0.25.8" + "@esbuild/darwin-x64" "0.25.8" + "@esbuild/freebsd-arm64" "0.25.8" + "@esbuild/freebsd-x64" "0.25.8" + "@esbuild/linux-arm" "0.25.8" + "@esbuild/linux-arm64" "0.25.8" + "@esbuild/linux-ia32" "0.25.8" + "@esbuild/linux-loong64" "0.25.8" + "@esbuild/linux-mips64el" "0.25.8" + "@esbuild/linux-ppc64" "0.25.8" + "@esbuild/linux-riscv64" "0.25.8" + "@esbuild/linux-s390x" "0.25.8" + "@esbuild/linux-x64" "0.25.8" + "@esbuild/netbsd-arm64" "0.25.8" + "@esbuild/netbsd-x64" "0.25.8" + "@esbuild/openbsd-arm64" "0.25.8" + "@esbuild/openbsd-x64" "0.25.8" + "@esbuild/openharmony-arm64" "0.25.8" + "@esbuild/sunos-x64" "0.25.8" + "@esbuild/win32-arm64" "0.25.8" + "@esbuild/win32-ia32" "0.25.8" + "@esbuild/win32-x64" "0.25.8" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +esprima@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estree-util-attach-comments@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz#344bde6a64c8a31d15231e5ee9e297566a691c2d" + integrity sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw== + dependencies: + "@types/estree" "^1.0.0" + +estree-util-build-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz#b6d0bced1dcc4f06f25cf0ceda2b2dcaf98168f1" + integrity sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ== + dependencies: + "@types/estree-jsx" "^1.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + estree-walker "^3.0.0" + +estree-util-is-identifier-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" + integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== + +estree-util-scope@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/estree-util-scope/-/estree-util-scope-1.0.0.tgz#9cbdfc77f5cb51e3d9ed4ad9c4adbff22d43e585" + integrity sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ== + dependencies: + "@types/estree" "^1.0.0" + devlop "^1.0.0" + +estree-util-to-js@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz#10a6fb924814e6abb62becf0d2bc4dea51d04f17" + integrity sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg== + dependencies: + "@types/estree-jsx" "^1.0.0" + astring "^1.8.0" + source-map "^0.7.0" + +estree-util-value-to-estree@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/estree-util-value-to-estree/-/estree-util-value-to-estree-3.4.0.tgz#827122e40c3a756d3c4cf5d5d296fa06026a1a4f" + integrity sha512-Zlp+gxis+gCfK12d3Srl2PdX2ybsEA8ZYy6vQGVQTNNYLEGRQQ56XB64bjemN8kxIKXP1nC9ip4Z+ILy9LGzvQ== + dependencies: + "@types/estree" "^1.0.0" + +estree-util-visit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-2.0.0.tgz#13a9a9f40ff50ed0c022f831ddf4b58d05446feb" + integrity sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/unist" "^3.0.0" + +estree-walker@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +etag@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eth-rpc-errors@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" + integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg== + dependencies: + fast-safe-stringify "^2.0.6" + +ethereum-bloom-filters@^1.0.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz#8294f074c1a6cbd32c39d2cc77ce86ff14797dab" + integrity sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA== + dependencies: + "@noble/hashes" "^1.4.0" + +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2, ethereum-cryptography@^2.1.3, ethereum-cryptography@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" + integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== + dependencies: + "@noble/curves" "1.4.2" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" + +ethereum-cryptography@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz#42a04b57834bf536e552b50a70b9ee5057c71dc6" + integrity sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg== + dependencies: + "@noble/ciphers" "1.3.0" + "@noble/curves" "1.9.0" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ev-emitter@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ev-emitter/-/ev-emitter-2.1.2.tgz#91737a2deae9fa95453e7e86cfae976f8c3ced38" + integrity sha512-jQ5Ql18hdCQ4qS+RCrbLfz1n+Pags27q5TwMKvZyhp5hh2UULUYZUy1keqj6k6SYsdqIYjnmz7xyyEY0V67B8Q== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@5.0.1, eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +eventemitter3@^4.0.1, eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@3.3.0, events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource-parser@^3.0.0, eventsource-parser@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.3.tgz#e9af1d40b77e6268cdcbc767321e8b9f066adea8" + integrity sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA== + +eventsource@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" + integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== + +eventsource@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-3.0.7.tgz#1157622e2f5377bb6aef2114372728ba0c156989" + integrity sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA== + dependencies: + eventsource-parser "^3.0.1" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" + integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw== + +express-rate-limit@^7.5.0: + version "7.5.1" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.1.tgz#8c3a42f69209a3a1c969890070ece9e20a879dec" + integrity sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw== + +express@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9" + integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== + dependencies: + accepts "^2.0.0" + body-parser "^2.2.0" + content-disposition "^1.0.0" + content-type "^1.0.5" + cookie "^0.7.1" + cookie-signature "^1.2.1" + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + finalhandler "^2.1.0" + fresh "^2.0.0" + http-errors "^2.0.0" + merge-descriptors "^2.0.0" + mime-types "^3.0.0" + on-finished "^2.4.1" + once "^1.4.0" + parseurl "^1.3.3" + proxy-addr "^2.0.7" + qs "^6.14.0" + range-parser "^1.2.1" + router "^2.2.0" + send "^1.1.0" + serve-static "^2.2.0" + statuses "^2.0.1" + type-is "^2.0.1" + vary "^1.1.2" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + +fast-copy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.2.tgz#59c68f59ccbcac82050ba992e0d5c389097c9d35" + integrity sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-equals@^5.0.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.2.2.tgz#885d7bfb079fac0ce0e8450374bce29e9b742484" + integrity sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw== + +fast-glob@^3.2.12, fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-redact@^3.0.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" + integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== + +fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fdir@^6.4.4: + version "6.4.6" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281" + integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== + +feaxios@^0.0.23: + version "0.0.23" + resolved "https://registry.yarnpkg.com/feaxios/-/feaxios-0.0.23.tgz#76f37a2666232377ce75354e46dd85cbceeb1758" + integrity sha512-eghR0A21fvbkcQBgZuMfQhrXxJzC0GNUGC9fXhBge33D+mFDTwl0aJ35zoQQn575BhyjQitRc5N4f+L4cP708g== + dependencies: + is-retry-allowed "^3.0.0" + +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== + +finalhandler@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f" + integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q== + dependencies: + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + on-finished "^2.4.1" + parseurl "^1.3.3" + statuses "^2.0.1" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +form-data@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +framer-motion@^12.23.6, framer-motion@^12.9.2: + version "12.23.6" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-12.23.6.tgz#29a78d0b05081fda3fdfd2f3eb4f570d7989d2e8" + integrity sha512-dsJ389QImVE3lQvM8Mnk99/j8tiZDM/7706PCqvkQ8sSCnpmWxsgX+g0lj7r5OBVL0U36pIecCTBoIWcM2RuKw== + dependencies: + motion-dom "^12.23.6" + motion-utils "^12.23.6" + tslib "^2.4.0" + +fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" + integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== + +fs-extra@^11.1.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" + integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +fumadocs-core@15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/fumadocs-core/-/fumadocs-core-15.6.1.tgz#4224f5a61523d6ea9e193634481cb4dd0f40f897" + integrity sha512-5DXVptT+LN145xUHzUy07IAtaBYBoWOVMAKbUQQhcGNxhXPvbVAT9bIHnfjklU+yyosc8Rhn/gxSrKdlrn9HtQ== + dependencies: + "@formatjs/intl-localematcher" "^0.6.1" + "@orama/orama" "^3.1.9" + "@shikijs/rehype" "^3.7.0" + "@shikijs/transformers" "^3.7.0" + github-slugger "^2.0.0" + hast-util-to-estree "^3.1.3" + hast-util-to-jsx-runtime "^2.3.6" + image-size "^2.0.2" + negotiator "^1.0.0" + npm-to-yarn "^3.0.1" + react-remove-scroll "^2.7.1" + remark "^15.0.0" + remark-gfm "^4.0.1" + remark-rehype "^11.1.2" + scroll-into-view-if-needed "^3.1.0" + shiki "^3.7.0" + unist-util-visit "^5.0.0" + +fumadocs-mdx@11.6.10: + version "11.6.10" + resolved "https://registry.yarnpkg.com/fumadocs-mdx/-/fumadocs-mdx-11.6.10.tgz#21a46380217f6878f06d56edf08c9ae5b9931973" + integrity sha512-W13mGPKDviKHq1FdxJqbBmA8vQ0niEISUUREJU8u3q1g5lQgnZ9whZjTnvijnqiGNbBsjb8CmjU20OlmwG6nhA== + dependencies: + "@mdx-js/mdx" "^3.1.0" + "@standard-schema/spec" "^1.0.0" + chokidar "^4.0.3" + esbuild "^0.25.5" + estree-util-value-to-estree "^3.4.0" + js-yaml "^4.1.0" + lru-cache "^11.1.0" + picocolors "^1.1.1" + tinyexec "^1.0.1" + tinyglobby "^0.2.14" + unist-util-visit "^5.0.0" + zod "^3.25.67" + +fumadocs-ui@15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/fumadocs-ui/-/fumadocs-ui-15.6.1.tgz#b146ffd9dffe6a1e810c681f343a4a05d9d66934" + integrity sha512-3O0uTMeU1ohVQE7HTV7+8I/1IIlgJPIBFOHjoQkRaXTf41LJ7EKfNHue80BOuhG4vyeL/Sx184v2hjljuKrX3Q== + dependencies: + "@radix-ui/react-accordion" "^1.2.11" + "@radix-ui/react-collapsible" "^1.1.11" + "@radix-ui/react-dialog" "^1.1.14" + "@radix-ui/react-direction" "^1.1.1" + "@radix-ui/react-navigation-menu" "^1.2.13" + "@radix-ui/react-popover" "^1.1.14" + "@radix-ui/react-presence" "^1.1.4" + "@radix-ui/react-scroll-area" "^1.2.9" + "@radix-ui/react-slot" "^1.2.3" + "@radix-ui/react-tabs" "^1.1.12" + class-variance-authority "^0.7.1" + fumadocs-core "15.6.1" + lodash.merge "^4.6.2" + next-themes "^0.4.6" + postcss-selector-parser "^7.1.0" + react-medium-image-zoom "^5.2.14" + scroll-into-view-if-needed "^3.1.0" + tailwind-merge "^3.3.1" + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + +get-own-enumerable-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz#59bbda0f7e7469c8c74086e08f79f1381b203899" + integrity sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA== + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-size@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-size/-/get-size-3.0.0.tgz#00e39a8042a3de237b2fcf288eaf55d3f472417c" + integrity sha512-Y8aiXLq4leR7807UY0yuKEwif5s3kbVp1nTv+i4jBeoUzByTLKkLWu/HorS6/pB+7gsB0o7OTogC8AoOOeT0Hw== + +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-tsconfig@^4.7.5: + version "4.10.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.1.tgz#d34c1c01f47d65a606c37aa7a177bc3e56ab4b2e" + integrity sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ== + dependencies: + resolve-pkg-maps "^1.0.0" + +github-slugger@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" + integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +"google@link:@next/third-parties/google": + version "0.0.0" + uid "" + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphql@^16.8.1: + version "16.11.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.11.0.tgz#96d17f66370678027fdf59b2d4c20b4efaa8a633" + integrity sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw== + +h3@^1.15.3: + version "1.15.3" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.15.3.tgz#e242ec6a7692a45caed3e4a73710cede4fb8d863" + integrity sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ== + dependencies: + cookie-es "^1.2.2" + crossws "^0.3.4" + defu "^6.1.4" + destr "^2.0.5" + iron-webcrypto "^1.2.1" + node-mock-http "^1.0.0" + radix3 "^1.1.2" + ufo "^1.6.1" + uncrypto "^0.1.3" + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + integrity sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw== + dependencies: + inherits "^2.0.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash-base@~3.0, hash-base@~3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.5.tgz#52480e285395cf7fba17dc4c9e47acdc7f248a8a" + integrity sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + +hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hast-util-from-dom@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz#c3c92fbd8d4e1c1625edeb3a773952b9e4ad64a8" + integrity sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q== + dependencies: + "@types/hast" "^3.0.0" + hastscript "^9.0.0" + web-namespaces "^2.0.0" + +hast-util-from-html-isomorphic@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz#b31baee386a899a2472326a3c5692f29f86d1d3c" + integrity sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw== + dependencies: + "@types/hast" "^3.0.0" + hast-util-from-dom "^5.0.0" + hast-util-from-html "^2.0.0" + unist-util-remove-position "^5.0.0" + +hast-util-from-html@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz#485c74785358beb80c4ba6346299311ac4c49c82" + integrity sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.1.0" + hast-util-from-parse5 "^8.0.0" + parse5 "^7.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + +hast-util-from-parse5@^8.0.0: + version "8.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz#830a35022fff28c3fea3697a98c2f4cc6b835a2e" + integrity sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + hastscript "^9.0.0" + property-information "^7.0.0" + vfile "^6.0.0" + vfile-location "^5.0.0" + web-namespaces "^2.0.0" + +hast-util-is-element@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz#6e31a6532c217e5b533848c7e52c9d9369ca0932" + integrity sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g== + dependencies: + "@types/hast" "^3.0.0" + +hast-util-parse-selector@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" + integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A== + dependencies: + "@types/hast" "^3.0.0" + +hast-util-to-estree@^3.0.0, hast-util-to-estree@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz#e654c1c9374645135695cc0ab9f70b8fcaf733d7" + integrity sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w== + dependencies: + "@types/estree" "^1.0.0" + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + devlop "^1.0.0" + estree-util-attach-comments "^3.0.0" + estree-util-is-identifier-name "^3.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + style-to-js "^1.0.0" + unist-util-position "^5.0.0" + zwitch "^2.0.0" + +hast-util-to-html@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz#ccc673a55bb8e85775b08ac28380f72d47167005" + integrity sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + ccount "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-whitespace "^3.0.0" + html-void-elements "^3.0.0" + mdast-util-to-hast "^13.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + stringify-entities "^4.0.0" + zwitch "^2.0.4" + +hast-util-to-jsx-runtime@^2.0.0, hast-util-to-jsx-runtime@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz#ff31897aae59f62232e21594eac7ef6b63333e98" + integrity sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg== + dependencies: + "@types/estree" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + comma-separated-tokens "^2.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + style-to-js "^1.0.0" + unist-util-position "^5.0.0" + vfile-message "^4.0.0" + +hast-util-to-string@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz#a4f15e682849326dd211c97129c94b0c3e76527c" + integrity sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A== + dependencies: + "@types/hast" "^3.0.0" + +hast-util-to-text@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz#57b676931e71bf9cb852453678495b3080bfae3e" + integrity sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + hast-util-is-element "^3.0.0" + unist-util-find-after "^5.0.0" + +hast-util-whitespace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621" + integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== + dependencies: + "@types/hast" "^3.0.0" + +hast@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hast/-/hast-1.0.0.tgz#50615e6b2b0583e5608bc76c47029722f1e00607" + integrity sha512-vFUqlRV5C+xqP76Wwq2SrM0kipnmpxJm7OfvVXpB35Fp+Fn4MV+ozr+JZr5qFvyR1q/U+Foim2x+3P+x9S1PLA== + +hastscript@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-9.0.1.tgz#dbc84bef6051d40084342c229c451cd9dc567dff" + integrity sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w== + dependencies: + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + hast-util-parse-selector "^4.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + +headers-polyfill@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07" + integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ== + +help-me@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" + integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +html-void-elements@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7" + integrity sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg== + +http-errors@2.0.0, http-errors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +https-proxy-agent@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-6.2.1.tgz#0965ab47371b3e531cf6794d1eb148710a992ba7" + integrity sha512-ONsE3+yfZF2caH5+bJlcddtWqNI3Gvs5A38+ngvljxaBiRXRswym2c7yf8UAeFpRFKjFNHIFEHqR/OLAWJzyiA== + dependencies: + agent-base "^7.0.2" + debug "4" + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +iconv-lite@0.6.3, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +idb-keyval@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.2.tgz#b0171b5f73944854a3291a5cdba8e12768c4854a" + integrity sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg== + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +image-size@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-2.0.2.tgz#84a7b43704db5736f364bf0d1b029821299b4bdc" + integrity sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w== + +import-fresh@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inline-style-parser@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.4.tgz#f4af5fe72e612839fcd453d989a586566d695f22" + integrity sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q== + +int64-buffer@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-1.1.0.tgz#7ebe9822196a93bbedf93ec6b73b569561b5ae3a" + integrity sha512-94smTCQOvigN4d/2R/YDjz8YVG0Sufvv2aAh8P5m42gwhCsDAJqnbNOrxJsrADuAFAA69Q/ptGzxvNcNuIJcvw== + +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +iron-webcrypto@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz#aa60ff2aa10550630f4c0b11fd2442becdb35a6f" + integrity sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg== + +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + +is-arguments@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b" + integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-function@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== + dependencies: + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + +is-nan@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-node-process@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" + integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-3.0.0.tgz#b0889f1f9f8cb87e87df53a8d1230a2250f8b9be" + integrity sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + +is-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-regexp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-3.1.0.tgz#0235eab9cda5b83f96ac4a263d8c32c9d5ad7422" + integrity sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA== + +is-retry-allowed@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-3.0.0.tgz#ea79389fd350d156823c491bee9c69f485b1445c" + integrity sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A== + +is-standalone-pwa@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz#7a1b0459471a95378aa0764d5dc0a9cec95f2871" + integrity sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-typed-array@^1.1.14, is-typed-array@^1.1.3: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-unicode-supported@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" + integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + +isows@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" + integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw== + +isows@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + +"javascript@link:shiki/engine/javascript": + version "0.0.0" + uid "" + +jayson@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.2.0.tgz#b71762393fa40bc9637eaf734ca6f40d3b8c0c93" + integrity sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + stream-json "^1.9.1" + uuid "^8.3.2" + ws "^7.5.10" + +jiti@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +js-base64@^3.7.5: + version "3.7.7" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79" + integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw== + +js-sha256@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.11.1.tgz#712262e8fc9569d6f7f6eea72c0d8e5ccc7c976c" + integrity sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg== + +js-sha256@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsbi@^3.1.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" + integrity sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== + +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stable-stringify@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz#8903cfac42ea1a0f97f35d63a4ce0518f0cc6a70" + integrity sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsondiffpatch@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz#daa6a25bedf0830974c81545568d5f671c82551f" + integrity sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ== + dependencies: + "@types/diff-match-patch" "^1.0.36" + chalk "^5.3.0" + diff-match-patch "^1.0.5" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + +jsqr@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.4.0.tgz#8efb8d0a7cc6863cb6d95116b9069123ce9eb2d1" + integrity sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A== + +jwa@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.1.tgz#bf8176d1ad0cd72e0f3f58338595a13e110bc804" + integrity sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg== + dependencies: + buffer-equal-constant-time "^1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" + integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg== + dependencies: + jwa "^2.0.0" + safe-buffer "^5.0.1" + +jwt-decode@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-4.0.0.tgz#2270352425fd413785b2faf11f6e755c5151bd4b" + integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA== + +kareem@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.6.3.tgz#23168ec8ffb6c1abfd31b7169a6fb1dd285992ac" + integrity sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q== + +katex@^0.16.0: + version "0.16.22" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.22.tgz#d2b3d66464b1e6d69e6463b28a86ced5a02c5ccd" + integrity sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg== + dependencies: + commander "^8.3.0" + +keyvaluestorage-interface@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz#13ebdf71f5284ad54be94bd1ad9ed79adad515ff" + integrity sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +kleur@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + +lightningcss-darwin-arm64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" + integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== + +lightningcss-darwin-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" + integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== + +lightningcss-freebsd-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" + integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== + +lightningcss-linux-arm-gnueabihf@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" + integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== + +lightningcss-linux-arm64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" + integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== + +lightningcss-linux-arm64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" + integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== + +lightningcss-linux-x64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" + integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== + +lightningcss-linux-x64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" + integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== + +lightningcss-win32-arm64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" + integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== + +lightningcss-win32-x64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" + integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== + +lightningcss@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" + integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== + dependencies: + detect-libc "^2.0.3" + optionalDependencies: + lightningcss-darwin-arm64 "1.30.1" + lightningcss-darwin-x64 "1.30.1" + lightningcss-freebsd-x64 "1.30.1" + lightningcss-linux-arm-gnueabihf "1.30.1" + lightningcss-linux-arm64-gnu "1.30.1" + lightningcss-linux-arm64-musl "1.30.1" + lightningcss-linux-x64-gnu "1.30.1" + lightningcss-linux-x64-musl "1.30.1" + lightningcss-win32-arm64-msvc "1.30.1" + lightningcss-win32-x64-msvc "1.30.1" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lit-element@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.2.1.tgz#0a3782f36eaa545862fe07f84abcb14b2903a042" + integrity sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw== + dependencies: + "@lit-labs/ssr-dom-shim" "^1.4.0" + "@lit/reactive-element" "^2.1.0" + lit-html "^3.3.0" + +lit-html@^3.1.0, lit-html@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.3.1.tgz#f0a7e4b9ea0a1d034eb28a4bf2d1b0a0096253e3" + integrity sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA== + dependencies: + "@types/trusted-types" "^2.0.2" + +lit@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lit/-/lit-3.1.0.tgz#76429b85dc1f5169fed499a0f7e89e2e619010c9" + integrity sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w== + dependencies: + "@lit/reactive-element" "^2.0.0" + lit-element "^4.0.0" + lit-html "^3.1.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash.isequal@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@4.17.21, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-5.1.0.tgz#a20e3b9a5f53fac6aeb8e2bb22c07cf2c8f16d93" + integrity sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA== + dependencies: + chalk "^5.0.0" + is-unicode-supported "^1.1.0" + +loglevel@^1.9.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" + integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== + +long@5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.5.tgz#716dcb0807c406345b3fc0f34d8042b41edb9d16" + integrity sha512-e0r9YBBgNCq1D1o5Dp8FMH0N5hsFtXDBiVa0qoJPHpakvZkmDKPRoGffZJII/XsHvj9An9blm+cRJ01yQqU+Dw== + +long@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + +longest-streak@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" + integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== + +loose-envify@^1.0.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.1.0.tgz#afafb060607108132dbc1cf8ae661afb69486117" + integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lucide-react@^0.488.0: + version "0.488.0" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.488.0.tgz#1cd1fb9f653db018c48c465bb76eb20be40a69bd" + integrity sha512-ronlL0MyKut4CEzBY/ai2ZpKPxyWO4jUqdAkm2GNK5Zn3Rj+swDz+3lvyAUXN0PNqPKIX6XM9Xadwz/skLs/pQ== + +magic-string@^0.30.17: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +map-obj@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-5.0.0.tgz#126c98596b63927d7360f287cccc67177aa1938b" + integrity sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA== + +markdown-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-2.0.0.tgz#34bebc83e9938cae16e0e017e4a9814a8330d3c4" + integrity sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q== + +markdown-table@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.4.tgz#fe44d6d410ff9d6f2ea1797a3f60aa4d2b631c2a" + integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdast-util-find-and-replace@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz#70a3174c894e14df722abf43bc250cbae44b11df" + integrity sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg== + dependencies: + "@types/mdast" "^4.0.0" + escape-string-regexp "^5.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + +mdast-util-from-markdown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz#4850390ca7cf17413a9b9a0fbefcd1bc0eb4160a" + integrity sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + mdast-util-to-string "^4.0.0" + micromark "^4.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-decode-string "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-stringify-position "^4.0.0" + +mdast-util-gfm-autolink-literal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5" + integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== + dependencies: + "@types/mdast" "^4.0.0" + ccount "^2.0.0" + devlop "^1.0.0" + mdast-util-find-and-replace "^3.0.0" + micromark-util-character "^2.0.0" + +mdast-util-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz#7778e9d9ca3df7238cc2bd3fa2b1bf6a65b19403" + integrity sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + +mdast-util-gfm-strikethrough@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz#d44ef9e8ed283ac8c1165ab0d0dfd058c2764c16" + integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-gfm-table@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz#7a435fb6223a72b0862b33afbd712b6dae878d38" + integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + markdown-table "^3.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-gfm-task-list-item@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz#e68095d2f8a4303ef24094ab642e1047b991a936" + integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-gfm@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz#2cdf63b92c2a331406b0fb0db4c077c1b0331751" + integrity sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ== + dependencies: + mdast-util-from-markdown "^2.0.0" + mdast-util-gfm-autolink-literal "^2.0.0" + mdast-util-gfm-footnote "^2.0.0" + mdast-util-gfm-strikethrough "^2.0.0" + mdast-util-gfm-table "^2.0.0" + mdast-util-gfm-task-list-item "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-math@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-math/-/mdast-util-math-3.0.0.tgz#8d79dd3baf8ab8ac781f62b8853768190b9a00b0" + integrity sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + longest-streak "^3.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.1.0" + unist-util-remove-position "^5.0.0" + +mdast-util-mdx-expression@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz#43f0abac9adc756e2086f63822a38c8d3c3a5096" + integrity sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-jsx@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz#fd04c67a2a7499efb905a8a5c578dddc9fdada0d" + integrity sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + ccount "^2.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" + +mdast-util-mdx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz#792f9cf0361b46bee1fdf1ef36beac424a099c41" + integrity sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w== + dependencies: + mdast-util-from-markdown "^2.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdxjs-esm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" + integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-phrasing@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz#7cc0a8dec30eaf04b7b1a9661a92adb3382aa6e3" + integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== + dependencies: + "@types/mdast" "^4.0.0" + unist-util-is "^6.0.0" + +mdast-util-to-hast@^13.0.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz#5ca58e5b921cc0a3ded1bc02eed79a4fe4fe41f4" + integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@ungap/structured-clone" "^1.0.0" + devlop "^1.0.0" + micromark-util-sanitize-uri "^2.0.0" + trim-lines "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + +mdast-util-to-markdown@^2.0.0, mdast-util-to-markdown@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz#f910ffe60897f04bb4b7e7ee434486f76288361b" + integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" + +mdast-util-to-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" + integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== + dependencies: + "@types/mdast" "^4.0.0" + +media-typer@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" + integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +merge-descriptors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808" + integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== + +merge-options@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7" + integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ== + dependencies: + is-plain-obj "^2.1.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +merkletreejs@^0.3.11, merkletreejs@^0.3.9: + version "0.3.11" + resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.3.11.tgz#e0de05c3ca1fd368de05a12cb8efb954ef6fc04f" + integrity sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ== + dependencies: + bignumber.js "^9.0.1" + buffer-reverse "^1.0.1" + crypto-js "^4.2.0" + treeify "^1.1.0" + web3-utils "^1.3.4" + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + +micromark-core-commonmark@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz#c691630e485021a68cf28dbc2b2ca27ebf678cd4" + integrity sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg== + dependencies: + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-factory-destination "^2.0.0" + micromark-factory-label "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-factory-title "^2.0.0" + micromark-factory-whitespace "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-html-tag-name "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-autolink-literal@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935" + integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750" + integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== + dependencies: + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-strikethrough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923" + integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-table@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz#fac70bcbf51fe65f5f44033118d39be8a9b5940b" + integrity sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg== + dependencies: + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-tagfilter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz#f26d8a7807b5985fba13cf61465b58ca5ff7dc57" + integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg== + dependencies: + micromark-util-types "^2.0.0" + +micromark-extension-gfm-task-list-item@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c" + integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== + dependencies: + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz#3e13376ab95dd7a5cfd0e29560dfe999657b3c5b" + integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w== + dependencies: + micromark-extension-gfm-autolink-literal "^2.0.0" + micromark-extension-gfm-footnote "^2.0.0" + micromark-extension-gfm-strikethrough "^2.0.0" + micromark-extension-gfm-table "^2.0.0" + micromark-extension-gfm-tagfilter "^2.0.0" + micromark-extension-gfm-task-list-item "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-math@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz#c42ee3b1dd5a9a03584e83dd8f08e3de510212c1" + integrity sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg== + dependencies: + "@types/katex" "^0.16.0" + devlop "^1.0.0" + katex "^0.16.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-mdx-expression@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz#43d058d999532fb3041195a3c3c05c46fa84543b" + integrity sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q== + dependencies: + "@types/estree" "^1.0.0" + devlop "^1.0.0" + micromark-factory-mdx-expression "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-mdx-jsx@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz#ffc98bdb649798902fa9fc5689f67f9c1c902044" + integrity sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ== + dependencies: + "@types/estree" "^1.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + micromark-factory-mdx-expression "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + vfile-message "^4.0.0" + +micromark-extension-mdx-md@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz#1d252881ea35d74698423ab44917e1f5b197b92d" + integrity sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ== + dependencies: + micromark-util-types "^2.0.0" + +micromark-extension-mdxjs-esm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz#de21b2b045fd2059bd00d36746081de38390d54a" + integrity sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A== + dependencies: + "@types/estree" "^1.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-position-from-estree "^2.0.0" + vfile-message "^4.0.0" + +micromark-extension-mdxjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz#b5a2e0ed449288f3f6f6c544358159557549de18" + integrity sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ== + dependencies: + acorn "^8.0.0" + acorn-jsx "^5.0.0" + micromark-extension-mdx-expression "^3.0.0" + micromark-extension-mdx-jsx "^3.0.0" + micromark-extension-mdx-md "^2.0.0" + micromark-extension-mdxjs-esm "^3.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-destination@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz#8fef8e0f7081f0474fbdd92deb50c990a0264639" + integrity sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-label@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz#5267efa97f1e5254efc7f20b459a38cb21058ba1" + integrity sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg== + dependencies: + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-mdx-expression@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz#bb09988610589c07d1c1e4425285895041b3dfa9" + integrity sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ== + dependencies: + "@types/estree" "^1.0.0" + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-position-from-estree "^2.0.0" + vfile-message "^4.0.0" + +micromark-factory-space@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz#36d0212e962b2b3121f8525fc7a3c7c029f334fc" + integrity sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-title@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz#237e4aa5d58a95863f01032d9ee9b090f1de6e94" + integrity sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-whitespace@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz#06b26b2983c4d27bfcc657b33e25134d4868b0b1" + integrity sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-character@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz#2f987831a40d4c510ac261e89852c4e9703ccda6" + integrity sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-chunked@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz#47fbcd93471a3fccab86cff03847fc3552db1051" + integrity sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-classify-character@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz#d399faf9c45ca14c8b4be98b1ea481bced87b629" + integrity sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-combine-extensions@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz#2a0f490ab08bff5cc2fd5eec6dd0ca04f89b30a9" + integrity sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg== + dependencies: + micromark-util-chunked "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-decode-numeric-character-reference@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz#fcf15b660979388e6f118cdb6bf7d79d73d26fe5" + integrity sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-decode-string@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz#6cb99582e5d271e84efca8e61a807994d7161eb2" + integrity sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-symbol "^2.0.0" + +micromark-util-encode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz#0d51d1c095551cfaac368326963cf55f15f540b8" + integrity sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw== + +micromark-util-events-to-acorn@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz#e7a8a6b55a47e5a06c720d5a1c4abae8c37c98f3" + integrity sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg== + dependencies: + "@types/estree" "^1.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + estree-util-visit "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + vfile-message "^4.0.0" + +micromark-util-html-tag-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz#e40403096481986b41c106627f98f72d4d10b825" + integrity sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA== + +micromark-util-normalize-identifier@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz#c30d77b2e832acf6526f8bf1aa47bc9c9438c16d" + integrity sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-resolve-all@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz#e1a2d62cdd237230a2ae11839027b19381e31e8b" + integrity sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg== + dependencies: + micromark-util-types "^2.0.0" + +micromark-util-sanitize-uri@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz#ab89789b818a58752b73d6b55238621b7faa8fd7" + integrity sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-symbol "^2.0.0" + +micromark-util-subtokenize@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz#d8ade5ba0f3197a1cf6a2999fbbfe6357a1a19ee" + integrity sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-symbol@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz#e5da494e8eb2b071a0d08fb34f6cefec6c0a19b8" + integrity sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q== + +micromark-util-types@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.2.tgz#f00225f5f5a0ebc3254f96c36b6605c4b393908e" + integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA== + +micromark@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.2.tgz#91395a3e1884a198e62116e33c9c568e39936fdb" + integrity sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +millify@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/millify/-/millify-6.1.0.tgz#6919d09377c28923624f9e4f41493d9706b8aadf" + integrity sha512-H/E3J6t+DQs/F2YgfDhxUVZz/dF8JXPPKTLHL/yHCcLZLtCXJDUaqvhJXQwqOVBvbyNn4T0WjLpIHd7PAw7fBA== + dependencies: + yargs "^17.0.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime-types@^3.0.0, mime-types@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" + integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA== + dependencies: + mime-db "^1.54.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +minidenticons@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/minidenticons/-/minidenticons-4.2.1.tgz#c2c3b98779e7c3aaded308bc3f123074946acb6b" + integrity sha512-oWfFivA0lOx/V/bO/YIJbthB26lV8JXYvhnv9zM2hNd3fzsHTXQ6c6bWZPcvhD3nnOB+lQk/D9lF43BXixrN8g== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^7.4.3: + version "7.4.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb" + integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^7.0.4, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" + integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== + dependencies: + minipass "^7.1.2" + +mkdirp@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== + +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +mongodb-connection-string-url@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz#e223089dfa0a5fa9bf505f8aedcbc67b077b33e7" + integrity sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA== + dependencies: + "@types/whatwg-url" "^11.0.2" + whatwg-url "^14.1.0 || ^13.0.0" + +mongodb@~6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.17.0.tgz#b52da4e3cdf62299e55c51584cb5657283157594" + integrity sha512-neerUzg/8U26cgruLysKEjJvoNSXhyID3RvzvdcpsIi2COYM3FS3o9nlH7fxFtefTb942dX3W9i37oPfCVj4wA== + dependencies: + "@mongodb-js/saslprep" "^1.1.9" + bson "^6.10.4" + mongodb-connection-string-url "^3.0.0" + +mongoose@^8.14.1: + version "8.16.4" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-8.16.4.tgz#89ed4b3baab1972cc951cfc82a4f754f280a9433" + integrity sha512-jslgdQ8pY2vcNSKPv3Dbi5ogo/NT8zcvf6kPDyD8Sdsjsa1at3AFAF0F5PT+jySPGSPbvlNaQ49nT9h+Kx2UDA== + dependencies: + bson "^6.10.4" + kareem "2.6.3" + mongodb "~6.17.0" + mpath "0.9.0" + mquery "5.0.0" + ms "2.1.3" + sift "17.1.3" + +motion-dom@^12.23.6: + version "12.23.6" + resolved "https://registry.yarnpkg.com/motion-dom/-/motion-dom-12.23.6.tgz#03856178d92a3b460797b57fa3b20e06847f8dab" + integrity sha512-G2w6Nw7ZOVSzcQmsdLc0doMe64O/Sbuc2bVAbgMz6oP/6/pRStKRiVRV4bQfHp5AHYAKEGhEdVHTM+R3FDgi5w== + dependencies: + motion-utils "^12.23.6" + +motion-utils@^12.23.6: + version "12.23.6" + resolved "https://registry.yarnpkg.com/motion-utils/-/motion-utils-12.23.6.tgz#fafef80b4ea85122dd0d6c599a0c63d72881f312" + integrity sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ== + +motion@^12.7.3: + version "12.23.6" + resolved "https://registry.yarnpkg.com/motion/-/motion-12.23.6.tgz#9f1b2b3848507fef4e433210e0824a2a2e138dfa" + integrity sha512-6U55IW5i6Vut2ryKEhrZKg55490k9d6qdGXZoNSf98oQgDj5D7bqTnVJotQ6UW3AS6QfbW6KSLa7/e1gy+a07g== + dependencies: + framer-motion "^12.23.6" + tslib "^2.4.0" + +mpath@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" + integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== + +mquery@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-5.0.0.tgz#a95be5dfc610b23862df34a47d3e5d60e110695d" + integrity sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg== + dependencies: + debug "4.x" + +ms@2.1.3, ms@^2.0.0, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +msw@^2.7.1: + version "2.10.4" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.10.4.tgz#a39dad96468aecfd752e5b7df4bbc86f1d73dec4" + integrity sha512-6R1or/qyele7q3RyPwNuvc0IxO8L8/Aim6Sz5ncXEgcWUNxSKE+udriTOWHtpMwmfkLYlacA2y7TIx4cL5lgHA== + dependencies: + "@bundled-es-modules/cookie" "^2.0.1" + "@bundled-es-modules/statuses" "^1.0.1" + "@bundled-es-modules/tough-cookie" "^0.1.6" + "@inquirer/confirm" "^5.0.0" + "@mswjs/interceptors" "^0.39.1" + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/until" "^2.1.0" + "@types/cookie" "^0.6.0" + "@types/statuses" "^2.0.4" + graphql "^16.8.1" + headers-polyfill "^4.0.2" + is-node-process "^1.2.0" + outvariant "^1.4.3" + path-to-regexp "^6.3.0" + picocolors "^1.1.1" + strict-event-emitter "^0.5.1" + type-fest "^4.26.1" + yargs "^17.7.2" + +multiformats@^9.4.2: + version "9.9.0" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" + integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== + +mute-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" + integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== + +nan@^2.13.2: + version "2.23.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.23.0.tgz#24aa4ddffcc37613a2d2935b97683c1ec96093c6" + integrity sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ== + +nanoid@^3.3.11, nanoid@^3.3.6, nanoid@^3.3.8: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== + +next-themes@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.4.6.tgz#8d7e92d03b8fea6582892a50a928c9b23502e8b6" + integrity sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA== + +next@15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/next/-/next-15.3.0.tgz#f8aa64ab584664db75648bd87d5d68c02eb2d56f" + integrity sha512-k0MgP6BsK8cZ73wRjMazl2y2UcXj49ZXLDEgx6BikWuby/CN+nh81qFFI16edgd7xYpe/jj2OZEIwCoqnzz0bQ== + dependencies: + "@next/env" "15.3.0" + "@swc/counter" "0.1.3" + "@swc/helpers" "0.5.15" + busboy "1.6.0" + caniuse-lite "^1.0.30001579" + postcss "8.4.31" + styled-jsx "5.1.6" + optionalDependencies: + "@next/swc-darwin-arm64" "15.3.0" + "@next/swc-darwin-x64" "15.3.0" + "@next/swc-linux-arm64-gnu" "15.3.0" + "@next/swc-linux-arm64-musl" "15.3.0" + "@next/swc-linux-x64-gnu" "15.3.0" + "@next/swc-linux-x64-musl" "15.3.0" + "@next/swc-win32-arm64-msvc" "15.3.0" + "@next/swc-win32-x64-msvc" "15.3.0" + sharp "^0.34.1" + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-addon-api@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-addon-api@^8.0.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.5.0.tgz#c91b2d7682fa457d2e1c388150f0dff9aafb8f3f" + integrity sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A== + +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch-native@^1.6.4, node-fetch-native@^1.6.6: + version "1.6.6" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.6.tgz#ae1d0e537af35c2c0b0de81cbff37eedd410aa37" + integrity sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ== + +node-fetch@^2.6.7, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" + integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + +node-gyp-build@^4.2.2, node-gyp-build@^4.3.0, node-gyp-build@^4.5.0: + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + +node-mock-http@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.1.tgz#29b4e0b08d786acadda450e8c159d3e652b3cbfd" + integrity sha512-0gJJgENizp4ghds/Ywu2FCmcRsgBTmRQzYPZm61wy+Em2sBarSka0OhQS5huLBg6od1zkNpnWMCZloQDFVvOMQ== + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== + dependencies: + path-key "^4.0.0" + +npm-to-yarn@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-to-yarn/-/npm-to-yarn-3.0.1.tgz#d1ed47551321ad5cd51342729fe21c8146644529" + integrity sha512-tt6PvKu4WyzPwWUzy/hvPFqn+uwXO0K1ZHka8az3NnrhWJDmSqI8ncWq0fkL0k/lmmi5tAC11FXwXuh0rFbt1A== + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +object-assign@^4, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +oblivious-set@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.4.0.tgz#1ee7c90f0605bb2a182fbcc8fffbe324d9994b43" + integrity sha512-szyd0ou0T8nsAqHtprRcP3WidfsN1TnAR5yWXf2mFCEr5ek3LEOkT6EZ/92Xfs74HIdyhG5WkGxIssMU0jBaeg== + +ofetch@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.4.1.tgz#b6bf6b0d75ba616cef6519dd8b6385a8bae480ec" + integrity sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw== + dependencies: + destr "^2.0.3" + node-fetch-native "^1.6.4" + ufo "^1.5.4" + +on-exit-leak-free@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" + integrity sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg== + +on-exit-leak-free@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" + integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== + +on-finished@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +oniguruma-parser@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz#82ba2208d7a2b69ee344b7efe0ae930c627dcc4a" + integrity sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w== + +oniguruma-to-es@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/oniguruma-to-es/-/oniguruma-to-es-4.3.3.tgz#50db2c1e28ec365e102c1863dfd3d1d1ad18613e" + integrity sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg== + dependencies: + oniguruma-parser "^0.12.1" + regex "^6.0.1" + regex-recursion "^6.0.2" + +ora@^6.1.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-6.3.1.tgz#a4e9e5c2cf5ee73c259e8b410273e706a2ad3ed6" + integrity sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ== + dependencies: + chalk "^5.0.0" + cli-cursor "^4.0.0" + cli-spinners "^2.6.1" + is-interactive "^2.0.0" + is-unicode-supported "^1.1.0" + log-symbols "^5.1.0" + stdin-discarder "^0.1.0" + strip-ansi "^7.0.1" + wcwidth "^1.0.1" + +outvariant@^1.4.0, outvariant@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873" + integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA== + +ox@0.6.7: + version "0.6.7" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.6.7.tgz#afd53f2ecef68b8526660e9d29dee6e6b599a832" + integrity sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA== + dependencies: + "@adraffy/ens-normalize" "^1.10.1" + "@noble/curves" "^1.6.0" + "@noble/hashes" "^1.5.0" + "@scure/bip32" "^1.5.0" + "@scure/bip39" "^1.4.0" + abitype "^1.0.6" + eventemitter3 "5.0.1" + +ox@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.8.1.tgz#c1328e4c890583b9c19d338126aef4b796d53543" + integrity sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "^1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.0.8" + eventemitter3 "5.0.1" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.7.tgz#73cdaaa822125f9647165625eb45f8a051d2df06" + integrity sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg== + dependencies: + asn1.js "^4.10.1" + browserify-aes "^1.2.0" + evp_bytestokey "^1.0.3" + hash-base "~3.0" + pbkdf2 "^3.1.2" + safe-buffer "^5.2.1" + +parse-entities@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.2.tgz#61d46f5ed28e4ee62e9ddc43d6b010188443f159" + integrity sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw== + dependencies: + "@types/unist" "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@^7.0.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" + integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw== + dependencies: + entities "^6.0.0" + +parseurl@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-to-regexp@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" + integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ== + +path-to-regexp@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4" + integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.3.tgz#8be674d591d65658113424592a95d1517318dd4b" + integrity sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA== + dependencies: + create-hash "~1.1.3" + create-hmac "^1.1.7" + ripemd160 "=2.0.1" + safe-buffer "^5.2.1" + sha.js "^2.4.11" + to-buffer "^1.2.0" + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +pino-abstract-transport@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz#de241578406ac7b8a33ce0d77ae6e8a0b3b68a60" + integrity sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw== + dependencies: + split2 "^4.0.0" + +pino-abstract-transport@v0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz#4b54348d8f73713bfd14e3dc44228739aa13d9c0" + integrity sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ== + dependencies: + duplexify "^4.1.2" + split2 "^4.0.0" + +pino-pretty@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-13.0.0.tgz#21d57fe940e34f2e279905d7dba2d7e2c4f9bf17" + integrity sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA== + dependencies: + colorette "^2.0.7" + dateformat "^4.6.3" + fast-copy "^3.0.2" + fast-safe-stringify "^2.1.1" + help-me "^5.0.0" + joycon "^3.1.1" + minimist "^1.2.6" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^2.0.0" + pump "^3.0.0" + secure-json-parse "^2.4.0" + sonic-boom "^4.0.1" + strip-json-comments "^3.1.1" + +pino-std-serializers@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1791ccd2539c091ae49ce9993205e2cd5dbba1e2" + integrity sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q== + +pino@7.11.0: + version "7.11.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-7.11.0.tgz#0f0ea5c4683dc91388081d44bff10c83125066f6" + integrity sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg== + dependencies: + atomic-sleep "^1.0.0" + fast-redact "^3.0.0" + on-exit-leak-free "^0.2.0" + pino-abstract-transport v0.5.0 + pino-std-serializers "^4.0.0" + process-warning "^1.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.1.0" + safe-stable-stringify "^2.1.0" + sonic-boom "^2.2.1" + thread-stream "^0.15.1" + +pkce-challenge@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97" + integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ== + +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +postcss-selector-parser@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz#4d6af97eba65d73bc4d84bcb343e865d7dd16262" + integrity sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.24, postcss@^8.4.41, postcss@^8.5.3: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-warning@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" + integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +property-information@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.1.0.tgz#b622e8646e02b580205415586b40804d3e8bfd5d" + integrity sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ== + +protobufjs@7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-compare@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.6.0.tgz#5e8c8b5c3af7e7f17e839bf6cf1435bcc4d315b0" + integrity sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +psl@^1.1.33: + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + +public-encrypt@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pushdata-bitcoin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz#15931d3cd967ade52206f523aa7331aef7d43af7" + integrity sha512-hw7rcYTJRAl4olM8Owe8x0fBuJJ+WGbMhQuLWOXEMN3PxPCKQHRkhfL+XG0+iXUmSHjkMmb3Ba55Mt21cZc9kQ== + dependencies: + bitcoin-ops "^1.3.0" + +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ== + +qrcode.react@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-1.0.1.tgz#2834bb50e5e275ffe5af6906eff15391fe9e38a5" + integrity sha512-8d3Tackk8IRLXTo67Y+c1rpaiXjoz/Dd2HpcMdW//62/x8J1Nbho14Kh8x974t9prsLHN6XqVgcnRiBGFptQmg== + dependencies: + loose-envify "^1.4.0" + prop-types "^15.6.0" + qr.js "0.0.0" + +qrcode@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170" + integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg== + dependencies: + dijkstrajs "^1.0.1" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" + +qrcode@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.4.tgz#5cb81d86eb57c675febb08cf007fff963405da88" + integrity sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg== + dependencies: + dijkstrajs "^1.0.1" + pngjs "^5.0.0" + yargs "^15.3.1" + +qs@^6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + +query-string@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" + integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg== + dependencies: + decode-uri-component "^0.2.2" + filter-obj "^1.1.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + +quick-lru@^6.1.1: + version "6.1.2" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-6.1.2.tgz#e9a90524108629be35287d0b864e7ad6ceb3659e" + integrity sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ== + +radix3@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" + integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f" + integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.6.3" + unpipe "1.0.0" + +react-dom@^19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" + integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== + dependencies: + scheduler "^0.26.0" + +react-fast-marquee@^1.6.5: + version "1.6.5" + resolved "https://registry.yarnpkg.com/react-fast-marquee/-/react-fast-marquee-1.6.5.tgz#98929ae93eef087a607a71e9d45ab76bba97dc16" + integrity sha512-swDnPqrT2XISAih0o74zQVE2wQJFMvkx+9VZXYYNSLb/CUcAzU9pNj637Ar2+hyRw6b4tP6xh4GQZip2ZCpQpg== + +react-hook-form@^7.55.0: + version "7.60.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.60.0.tgz#cc4bfa2952d602fc8f1dcf2d4929fcb6d9cdc782" + integrity sha512-SBrYOvMbDB7cV8ZfNpaiLcgjH/a1c7aK0lK+aNigpf4xWLO8q+o4tcvVurv3c4EOyzn/3dCsYt4GKD42VvJ/+A== + +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-medium-image-zoom@^5.2.14: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-medium-image-zoom/-/react-medium-image-zoom-5.3.0.tgz#e3b78bc8b4f11d893f661556be637a514be60b15" + integrity sha512-RCIzVlsKqy3BYgGgYbolUfuvx0aSKC7YhX/IJGEp+WJxsqdIVYJHkBdj++FAj6VD7RiWj6VVmdCfa/9vJE9hZg== + +react-modal@^3.12.1: + version "3.16.3" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.3.tgz#c412d41915782e3c261253435d01468e2439b11b" + integrity sha512-yCYRJB5YkeQDQlTt17WGAgFJ7jr2QYcWa1SHqZ3PluDmnKJ/7+tVU+E6uKyZ0nODaeEj+xCpK4LcSnKXLMC0Nw== + dependencies: + exenv "^1.2.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + +react-qr-code@^2.0.15: + version "2.0.18" + resolved "https://registry.yarnpkg.com/react-qr-code/-/react-qr-code-2.0.18.tgz#237de8fbab537885d6b2b10f4fd5318b371e3b17" + integrity sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg== + dependencies: + prop-types "^15.8.1" + qr.js "0.0.0" + +react-qr-reader@3.0.0-beta-1: + version "3.0.0-beta-1" + resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-3.0.0-beta-1.tgz#e04a20876409313439959d8e0ea6df3ba6e36d68" + integrity sha512-5HeFH9x/BlziRYQYGK2AeWS9WiKYZtGGMs9DXy3bcySTX3C9UJL9EwcPnWw8vlf7JP4FcrAlr1SnZ5nsWLQGyw== + dependencies: + "@zxing/browser" "0.0.7" + "@zxing/library" "^0.18.3" + rollup "^2.67.2" + +react-qr-reader@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-2.2.1.tgz#dc89046d1c1a1da837a683dd970de5926817d55b" + integrity sha512-EL5JEj53u2yAOgtpAKAVBzD/SiKWn0Bl7AZy6ZrSf1lub7xHwtaXe6XSx36Wbhl1VMGmvmrwYMRwO1aSCT2fwA== + dependencies: + jsqr "^1.2.0" + prop-types "^15.7.2" + webrtc-adapter "^7.2.1" + +react-remove-scroll-bar@^2.3.7: + version "2.3.8" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223" + integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q== + dependencies: + react-style-singleton "^2.2.2" + tslib "^2.0.0" + +react-remove-scroll@^2.6.3, react-remove-scroll@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz#d2101d414f6d81d7d3bf033f3c1cb4785789f753" + integrity sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA== + dependencies: + react-remove-scroll-bar "^2.3.7" + react-style-singleton "^2.2.3" + tslib "^2.1.0" + use-callback-ref "^1.3.3" + use-sidecar "^1.1.3" + +react-smooth@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.4.tgz#a5875f8bb61963ca61b819cedc569dc2453894b4" + integrity sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q== + dependencies: + fast-equals "^5.0.1" + prop-types "^15.8.1" + react-transition-group "^4.4.5" + +react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388" + integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ== + dependencies: + get-nonce "^1.0.0" + tslib "^2.0.0" + +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" + integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== + +readable-stream@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^4.5.2: + version "4.7.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.7.0.tgz#cedbd8a1146c13dfff8dab14068028d58c15ac91" + integrity sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +real-require@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" + integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== + +recast@^0.23.2: + version "0.23.11" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.11.tgz#8885570bb28cf773ba1dc600da7f502f7883f73f" + integrity sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA== + dependencies: + ast-types "^0.16.1" + esprima "~4.0.0" + source-map "~0.6.1" + tiny-invariant "^1.3.3" + tslib "^2.0.1" + +recharts-scale@^0.4.4: + version "0.4.5" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.5.tgz#0969271f14e732e642fcc5bd4ab270d6e87dd1d9" + integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w== + dependencies: + decimal.js-light "^2.4.1" + +recharts@^2.15.3: + version "2.15.4" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.15.4.tgz#0ed3e66c0843bcf2d9f9a172caf97b1d05127a5f" + integrity sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw== + dependencies: + clsx "^2.0.0" + eventemitter3 "^4.0.1" + lodash "^4.17.21" + react-is "^18.3.1" + react-smooth "^4.0.4" + recharts-scale "^0.4.4" + tiny-invariant "^1.3.1" + victory-vendor "^36.6.8" + +recma-build-jsx@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz#c02f29e047e103d2fab2054954e1761b8ea253c4" + integrity sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew== + dependencies: + "@types/estree" "^1.0.0" + estree-util-build-jsx "^3.0.0" + vfile "^6.0.0" + +recma-jsx@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/recma-jsx/-/recma-jsx-1.0.0.tgz#f7bef02e571a49d6ba3efdfda8e2efab48dbe3aa" + integrity sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q== + dependencies: + acorn-jsx "^5.0.0" + estree-util-to-js "^2.0.0" + recma-parse "^1.0.0" + recma-stringify "^1.0.0" + unified "^11.0.0" + +recma-parse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/recma-parse/-/recma-parse-1.0.0.tgz#c351e161bb0ab47d86b92a98a9d891f9b6814b52" + integrity sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ== + dependencies: + "@types/estree" "^1.0.0" + esast-util-from-js "^2.0.0" + unified "^11.0.0" + vfile "^6.0.0" + +recma-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/recma-stringify/-/recma-stringify-1.0.0.tgz#54632030631e0c7546136ff9ef8fde8e7b44f130" + integrity sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g== + dependencies: + "@types/estree" "^1.0.0" + estree-util-to-js "^2.0.0" + unified "^11.0.0" + vfile "^6.0.0" + +regex-recursion@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/regex-recursion/-/regex-recursion-6.0.2.tgz#a0b1977a74c87f073377b938dbedfab2ea582b33" + integrity sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg== + dependencies: + regex-utilities "^2.3.0" + +regex-utilities@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/regex-utilities/-/regex-utilities-2.3.0.tgz#87163512a15dce2908cf079c8960d5158ff43280" + integrity sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng== + +regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/regex/-/regex-6.0.1.tgz#282fa4435d0c700b09c0eb0982b602e05ab6a34f" + integrity sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA== + dependencies: + regex-utilities "^2.3.0" + +rehype-katex@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/rehype-katex/-/rehype-katex-7.0.1.tgz#832e6d7af2744a228981d1b0fe89483a9e7c93a1" + integrity sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA== + dependencies: + "@types/hast" "^3.0.0" + "@types/katex" "^0.16.0" + hast-util-from-html-isomorphic "^2.0.0" + hast-util-to-text "^4.0.0" + katex "^0.16.0" + unist-util-visit-parents "^6.0.0" + vfile "^6.0.0" + +rehype-recma@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rehype-recma/-/rehype-recma-1.0.0.tgz#d68ef6344d05916bd96e25400c6261775411aa76" + integrity sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw== + dependencies: + "@types/estree" "^1.0.0" + "@types/hast" "^3.0.0" + hast-util-to-estree "^3.0.0" + +remark-gfm@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.1.tgz#33227b2a74397670d357bf05c098eaf8513f0d6b" + integrity sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-gfm "^3.0.0" + micromark-extension-gfm "^3.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" + +remark-math@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/remark-math/-/remark-math-6.0.0.tgz#0acdf74675f1c195fea6efffa78582f7ed7fc0d7" + integrity sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-math "^3.0.0" + micromark-extension-math "^3.0.0" + unified "^11.0.0" + +remark-mdx@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-3.1.0.tgz#f979be729ecb35318fa48e2135c1169607a78343" + integrity sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA== + dependencies: + mdast-util-mdx "^3.0.0" + micromark-extension-mdxjs "^3.0.0" + +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" + +remark-rehype@^11.0.0, remark-rehype@^11.1.2: + version "11.1.2" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.2.tgz#2addaadda80ca9bd9aa0da763e74d16327683b37" + integrity sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-hast "^13.0.0" + unified "^11.0.0" + vfile "^6.0.0" + +remark-stringify@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3" + integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-to-markdown "^2.0.0" + unified "^11.0.0" + +remark@^15.0.0, remark@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/remark/-/remark-15.0.1.tgz#ac7e7563260513b66426bc47f850e7aa5862c37c" + integrity sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A== + dependencies: + "@types/mdast" "^4.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" + +require-addon@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/require-addon/-/require-addon-1.1.0.tgz#0a1ef0ba98b186a3aa304a1abda5208902e63e17" + integrity sha512-KbXAD5q2+v1GJnkzd8zzbOxchTkStSyJZ9QwoCq3QwEXAaIlG3wDYRZGzVD357jmwaGY7hr5VaoEAL0BkF0Kvg== + dependencies: + bare-addon-resolve "^1.3.0" + bare-url "^2.1.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +ripemd160@=2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + integrity sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w== + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +ripple-address-codec@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ripple-address-codec/-/ripple-address-codec-5.0.0.tgz#97059f7bba6f9ed7a52843de8aa427723fb529f6" + integrity sha512-de7osLRH/pt5HX2xw2TRJtbdLLWHu0RXirpQaEeCnWKY5DYHykh3ETSkofvm0aX0LJiV7kwkegJxQkmbO94gWw== + dependencies: + "@scure/base" "^1.1.3" + "@xrplf/isomorphic" "^1.0.0" + +ripple-binary-codec@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/ripple-binary-codec/-/ripple-binary-codec-2.4.1.tgz#14990af5ab48775cbe109526c6066692768a25de" + integrity sha512-ABwQnWE1WBOvya9WIJ/KiogdsulOw5X8IrIZ3wW0Ec1hiWUNitNuI9LhN9XwHhNFuuvZyRAr+SzgFTBTCTfxFg== + dependencies: + "@xrplf/isomorphic" "^1.0.1" + bignumber.js "^9.0.0" + ripple-address-codec "^5.0.0" + +ripple-keypairs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ripple-keypairs/-/ripple-keypairs-2.0.0.tgz#4a1a8142e9a58c07e61b3cc6cfe7317db718d289" + integrity sha512-b5rfL2EZiffmklqZk1W+dvSy97v3V/C7936WxCCgDynaGPp7GE6R2XO7EU9O2LlM/z95rj870IylYnOQs+1Rag== + dependencies: + "@noble/curves" "^1.0.0" + "@xrplf/isomorphic" "^1.0.0" + ripple-address-codec "^5.0.0" + +rollup@^2.67.2: + version "2.79.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.2.tgz#f150e4a5db4b121a21a747d762f701e5e9f49090" + integrity sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ== + optionalDependencies: + fsevents "~2.3.2" + +router@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" + integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== + dependencies: + debug "^4.4.0" + depd "^2.0.0" + is-promise "^4.0.0" + parseurl "^1.3.3" + path-to-regexp "^8.0.0" + +rpc-websockets@^9.0.2: + version "9.1.1" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.1.1.tgz#5764336f3623ee1c5cc8653b7335183e3c0c78bd" + integrity sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA== + dependencies: + "@swc/helpers" "^0.5.11" + "@types/uuid" "^8.3.4" + "@types/ws" "^8.2.2" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + +rtcpeerconnection-shim@^1.2.15: + version "1.2.15" + resolved "https://registry.yarnpkg.com/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz#e7cc189a81b435324c4949aa3dfb51888684b243" + integrity sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw== + dependencies: + sdp "^2.6.0" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^6.6.3: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +rxjs@^7.8.1: + version "7.8.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +safe-stable-stringify@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +salmon-adapter-sdk@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/salmon-adapter-sdk/-/salmon-adapter-sdk-1.1.1.tgz#d5fdd2d27b1a6c58e38c188c977eeeeface8b20c" + integrity sha512-28ysSzmDjx2AbotxSggqdclh9MCwlPJUldKkCph48oS5Xtwu0QOg8T9ZRHS2Mben4Y8sTq6VvxXznKssCYFBJA== + dependencies: + "@project-serum/sol-wallet-adapter" "^0.2.6" + eventemitter3 "^4.0.7" + +scheduler@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" + integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== + +scroll-into-view-if-needed@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz#fa9524518c799b45a2ef6bbffb92bcad0296d01f" + integrity sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ== + dependencies: + compute-scroll-into-view "^3.0.2" + +sdp@^2.12.0, sdp@^2.6.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/sdp/-/sdp-2.12.0.tgz#338a106af7560c86e4523f858349680350d53b22" + integrity sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw== + +secure-json-parse@^2.4.0, secure-json-parse@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" + integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5, semver@^7.7.2: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +send@^1.1.0, send@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212" + integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw== + dependencies: + debug "^4.3.5" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + fresh "^2.0.0" + http-errors "^2.0.0" + mime-types "^3.0.1" + ms "^2.1.3" + on-finished "^2.4.1" + range-parser "^1.2.1" + statuses "^2.0.1" + +serve-static@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9" + integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ== + dependencies: + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.3.6, sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: + version "2.4.12" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.12.tgz#eb8b568bf383dfd1867a32c3f2b74eb52bdbf23f" + integrity sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + to-buffer "^1.2.0" + +shadcn-ui@^0.9.5: + version "0.9.5" + resolved "https://registry.yarnpkg.com/shadcn-ui/-/shadcn-ui-0.9.5.tgz#b7f35b78f2c7fe0b71651fe542ed62f01795b4a6" + integrity sha512-dsBQWpdLLYCdSdmvOmu53nJhhWnQD1OiblhuhkI4rPYxPKTyfbmZ2NTJHWMu1fXN9PTfN6IVK5vvh+BrjHJx2g== + dependencies: + chalk "^5.4.1" + +shadcn@^2.4.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/shadcn/-/shadcn-2.9.2.tgz#12c3676452c5dbbb5690422c23d46088e99841a1" + integrity sha512-Ssat5Qlosk3XQckSmHEUZ1WDiXXxZbeXEl2HI4QKlBwmboMHYFaVhOMl3ObRVN578C/d369AsKQcgLWF8F5hCA== + dependencies: + "@antfu/ni" "^23.2.0" + "@babel/core" "^7.22.1" + "@babel/parser" "^7.22.6" + "@babel/plugin-transform-typescript" "^7.22.5" + "@modelcontextprotocol/sdk" "^1.10.2" + commander "^10.0.0" + cosmiconfig "^8.1.3" + deepmerge "^4.3.1" + diff "^5.1.0" + execa "^7.0.0" + fast-glob "^3.3.2" + fs-extra "^11.1.0" + https-proxy-agent "^6.2.0" + kleur "^4.1.5" + msw "^2.7.1" + node-fetch "^3.3.0" + ora "^6.1.2" + postcss "^8.4.24" + prompts "^2.4.2" + recast "^0.23.2" + stringify-object "^5.0.0" + ts-morph "^18.0.0" + tsconfig-paths "^4.2.0" + zod "^3.20.2" + zod-to-json-schema "^3.24.5" + +sharp@^0.34.1: + version "0.34.3" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.3.tgz#10a03bcd15fb72f16355461af0b9245ccb8a5da3" + integrity sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg== + dependencies: + color "^4.2.3" + detect-libc "^2.0.4" + semver "^7.7.2" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.3" + "@img/sharp-darwin-x64" "0.34.3" + "@img/sharp-libvips-darwin-arm64" "1.2.0" + "@img/sharp-libvips-darwin-x64" "1.2.0" + "@img/sharp-libvips-linux-arm" "1.2.0" + "@img/sharp-libvips-linux-arm64" "1.2.0" + "@img/sharp-libvips-linux-ppc64" "1.2.0" + "@img/sharp-libvips-linux-s390x" "1.2.0" + "@img/sharp-libvips-linux-x64" "1.2.0" + "@img/sharp-libvips-linuxmusl-arm64" "1.2.0" + "@img/sharp-libvips-linuxmusl-x64" "1.2.0" + "@img/sharp-linux-arm" "0.34.3" + "@img/sharp-linux-arm64" "0.34.3" + "@img/sharp-linux-ppc64" "0.34.3" + "@img/sharp-linux-s390x" "0.34.3" + "@img/sharp-linux-x64" "0.34.3" + "@img/sharp-linuxmusl-arm64" "0.34.3" + "@img/sharp-linuxmusl-x64" "0.34.3" + "@img/sharp-wasm32" "0.34.3" + "@img/sharp-win32-arm64" "0.34.3" + "@img/sharp-win32-ia32" "0.34.3" + "@img/sharp-win32-x64" "0.34.3" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shiki@3.8.1, shiki@^3.3.0, shiki@^3.7.0: + version "3.8.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-3.8.1.tgz#f8b7d126ad51e388835ff0c419be052f79f2dc91" + integrity sha512-+MYIyjwGPCaegbpBeFN9+oOifI8CKiKG3awI/6h3JeT85c//H2wDW/xCJEGuQ5jPqtbboKNqNy+JyX9PYpGwNg== + dependencies: + "@shikijs/core" "3.8.1" + "@shikijs/engine-javascript" "3.8.1" + "@shikijs/engine-oniguruma" "3.8.1" + "@shikijs/langs" "3.8.1" + "@shikijs/themes" "3.8.1" + "@shikijs/types" "3.8.1" + "@shikijs/vscode-textmate" "^10.0.2" + "@types/hast" "^3.0.4" + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +sift@17.1.3: + version "17.1.3" + resolved "https://registry.yarnpkg.com/sift/-/sift-17.1.3.tgz#9d2000d4d41586880b0079b5183d839c7a142bf7" + integrity sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ== + +signal-exit@^3.0.2, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +socket.io-client@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.8.1.tgz#1941eca135a5490b94281d0323fe2a35f6f291cb" + integrity sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.6.1" + socket.io-parser "~4.2.4" + +socket.io-parser@~4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" + integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socks-proxy-agent@8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" + integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== + dependencies: + agent-base "^7.1.2" + debug "^4.3.4" + socks "^2.8.3" + +socks@^2.8.3: + version "2.8.6" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.6.tgz#e335486a2552f34f932f0c27d8dbb93f2be867aa" + integrity sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + +sodium-native@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-4.3.3.tgz#fae4866b52366f5e6cc1b7ae8c8a71673d50c7df" + integrity sha512-OnxSlN3uyY8D0EsLHpmm2HOFmKddQVvEMmsakCrXUzSd8kjjbzL413t4ZNF3n0UxSwNgwTyUvkmZHTfuCeiYSw== + dependencies: + require-addon "^1.1.0" + +sonic-boom@^2.2.1: + version "2.8.0" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" + integrity sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg== + dependencies: + atomic-sleep "^1.0.0" + +sonic-boom@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.0.tgz#e59a525f831210fa4ef1896428338641ac1c124d" + integrity sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww== + dependencies: + atomic-sleep "^1.0.0" + +sonner@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/sonner/-/sonner-2.0.6.tgz#623b73faec55229d63ec35226d42021f2119bfa7" + integrity sha512-yHFhk8T/DK3YxjFQXIrcHT1rGEeTLliVzWbO0xN8GberVun2RiBnxAjXAYpZrqwEVHBG9asI/Li8TAAhN9m59Q== + +source-map-js@^1.0.2, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@^0.7.0: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +statuses@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" + integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== + +stdin-discarder@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz#22b3e400393a8e28ebf53f9958f3880622efde21" + integrity sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ== + dependencies: + bl "^5.0.0" + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-chain@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09" + integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== + +stream-json@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.9.1.tgz#e3fec03e984a503718946c170db7d74556c2a187" + integrity sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw== + dependencies: + stream-chain "^2.2.5" + +stream-shift@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +strict-event-emitter@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" + integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-entities@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.4.tgz#b3b79ef5f277cc4ac73caeb0236c5ba939b3a4f3" + integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== + dependencies: + character-entities-html4 "^2.0.0" + character-entities-legacy "^3.0.0" + +stringify-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-5.0.0.tgz#d5b05649fedaf8860640471641f70906fea7f351" + integrity sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg== + dependencies: + get-own-enumerable-keys "^1.0.0" + is-obj "^3.0.0" + is-regexp "^3.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-to-js@^1.0.0: + version "1.1.17" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.17.tgz#488b1558a8c1fd05352943f088cc3ce376813d83" + integrity sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA== + dependencies: + style-to-object "1.0.9" + +style-to-object@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.9.tgz#35c65b713f4a6dba22d3d0c61435f965423653f0" + integrity sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw== + dependencies: + inline-style-parser "0.2.4" + +styled-jsx@5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499" + integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== + dependencies: + client-only "0.0.1" + +superstruct@2.0.2, superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== + +superstruct@^0.15.4: + version "0.15.5" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab" + integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== + +swr@^2.2.5: + version "2.3.4" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.3.4.tgz#60bcb5b97cae157a6ef69eff0ed2beb9010eba69" + integrity sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg== + dependencies: + dequal "^2.0.3" + use-sync-external-store "^1.4.0" + +tailwind-merge@^3.2.0, tailwind-merge@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-3.3.1.tgz#a7e7db7c714f6020319e626ecfb7e7dac8393a4b" + integrity sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g== + +tailwindcss@4.1.11, tailwindcss@^4.1.3: + version "4.1.11" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.11.tgz#799af3e98c19c5baaefafc6e0c16304a0e684854" + integrity sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA== + +tapable@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" + integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== + +tar@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + +third-party-capital@1.0.20: + version "1.0.20" + resolved "https://registry.yarnpkg.com/third-party-capital/-/third-party-capital-1.0.20.tgz#e218a929a35bf4d2245da9addb8ab978d2f41685" + integrity sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA== + +thread-stream@^0.15.1: + version "0.15.2" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4" + integrity sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA== + dependencies: + real-require "^0.1.0" + +throttleit@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-2.1.0.tgz#a7e4aa0bf4845a5bd10daa39ea0c783f631a07b4" + integrity sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw== + +tiny-invariant@^1.3.1, tiny-invariant@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + +tiny-secp256k1@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/tiny-secp256k1/-/tiny-secp256k1-1.1.7.tgz#0c1b6b9d2d93404f9093dc7e287b0aa834480573" + integrity sha512-eb+F6NabSnjbLwNoC+2o5ItbmP1kg7HliWue71JgLegQt6A5mTN8YbvTLCazdlg6e5SV6A+r8OGvZYskdlmhqQ== + dependencies: + bindings "^1.3.0" + bn.js "^4.11.8" + create-hmac "^1.1.7" + elliptic "^6.4.0" + nan "^2.13.2" + +tinyexec@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" + integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw== + +tinyglobby@^0.2.14: + version "0.2.14" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" + +to-buffer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.1.tgz#2ce650cdb262e9112a18e65dc29dcb513c8155e0" + integrity sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ== + dependencies: + isarray "^2.0.5" + safe-buffer "^5.2.1" + typed-array-buffer "^1.0.3" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +toml@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== + +tough-cookie@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.1.1.tgz#96ae867cddb8fdb64a49cc3059a8d428bcf238ca" + integrity sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw== + dependencies: + punycode "^2.3.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +treeify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" + integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== + +trim-lines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" + integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== + +trough@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" + integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== + +ts-custom-error@^3.0.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/ts-custom-error/-/ts-custom-error-3.3.1.tgz#8bd3c8fc6b8dc8e1cb329267c45200f1e17a65d1" + integrity sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A== + +ts-mixer@^6.0.3: + version "6.0.4" + resolved "https://registry.yarnpkg.com/ts-mixer/-/ts-mixer-6.0.4.tgz#1da39ceabc09d947a82140d9f09db0f84919ca28" + integrity sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA== + +ts-morph@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-18.0.0.tgz#b9e7a898ea115064585a8a775d86da6edc9c5b4e" + integrity sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA== + dependencies: + "@ts-morph/common" "~0.19.0" + code-block-writer "^12.0.0" + +tsconfig-paths@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@1.14.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tsx@^4.20.3: + version "4.20.3" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.20.3.tgz#f913e4911d59ad177c1bcee19d1035ef8dd6e2fb" + integrity sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ== + dependencies: + esbuild "~0.25.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + +tw-animate-css@^1.2.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/tw-animate-css/-/tw-animate-css-1.3.5.tgz#1bc393f6ac8b51f467235787561ac4334d523af2" + integrity sha512-t3u+0YNoloIhj1mMXs779P6MO9q3p3mvGn4k1n3nJPqJw/glZcuijG2qTSN4z4mgNRfW5ZC3aXJFLwDtiipZXA== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^4.26.1, type-fest@^4.3.2: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + +type-is@^2.0.0, type-is@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" + integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== + dependencies: + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typeforce@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.18.0.tgz#d7416a2c5845e085034d70fcc5b6cc4a90edbfdc" + integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== + +typescript@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +ua-is-frozen@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz#bfbc5f06336e379590e36beca444188c7dc3a7f3" + integrity sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw== + +ua-parser-js@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-2.0.4.tgz#ea6698b055af2a61661d8793f069452cf456c0df" + integrity sha512-XiBOnM/UpUq21ZZ91q2AVDOnGROE6UQd37WrO9WBgw4u2eGvUCNOheMmZ3EfEUj7DLHr8tre+Um/436Of/Vwzg== + dependencies: + "@types/node-fetch" "^2.6.12" + detect-europe-js "^0.1.2" + is-standalone-pwa "^0.1.1" + node-fetch "^2.7.0" + ua-is-frozen "^0.1.2" + +ufo@^1.5.4, ufo@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +uint8array-tools@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/uint8array-tools/-/uint8array-tools-0.0.8.tgz#712bab001f8347bd782f45bc47c76ffff32d1e0b" + integrity sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g== + +uint8arrays@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.0.tgz#8186b8eafce68f28bd29bd29d683a311778901e2" + integrity sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog== + dependencies: + multiformats "^9.4.2" + +uint8arrays@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" + integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg== + dependencies: + multiformats "^9.4.2" + +uncrypto@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" + integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== + +undici-types@^7.11.0: + version "7.12.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.12.0.tgz#15c5c7475c2a3ba30659529f5cdb4674b622fafb" + integrity sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +undici-types@~7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.8.0.tgz#de00b85b710c54122e44fbfd911f8d70174cd294" + integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw== + +unidragger@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/unidragger/-/unidragger-3.0.1.tgz#72b2e63f2571ca6e95a884b139dfec764e08c7f3" + integrity sha512-RngbGSwBFmqGBWjkaH+yB677uzR95blSQyxq6hYbrQCejH3Mx1nm8DVOuh3M9k2fQyTstWUG5qlgCnNqV/9jVw== + dependencies: + ev-emitter "^2.0.0" + +unified@^11.0.0, unified@^11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" + integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== + dependencies: + "@types/unist" "^3.0.0" + bail "^2.0.0" + devlop "^1.0.0" + extend "^3.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^6.0.0" + +unist-util-find-after@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz#3fccc1b086b56f34c8b798e1ff90b5c54468e896" + integrity sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + +unist-util-is@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" + integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-position-from-estree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz#d94da4df596529d1faa3de506202f0c9a23f2200" + integrity sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" + integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-remove-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" + integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== + dependencies: + "@types/unist" "^3.0.0" + unist-util-visit "^5.0.0" + +unist-util-stringify-position@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" + integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-visit-parents@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" + integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + +unist-util-visit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" + integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +unload@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.4.1.tgz#b0c5b7fb44e17fcbf50dcb8fb53929c59dd226a5" + integrity sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw== + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +unstorage@^1.9.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.16.1.tgz#b2c25d05610a64de7be61e54f61ec79c5f9ba43c" + integrity sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ== + dependencies: + anymatch "^3.1.3" + chokidar "^4.0.3" + destr "^2.0.5" + h3 "^1.15.3" + lru-cache "^10.4.3" + node-fetch-native "^1.6.6" + ofetch "^1.4.1" + ufo "^1.6.1" + +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urijs@^1.19.1: + version "1.19.11" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" + integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +usb@^2.15.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/usb/-/usb-2.16.0.tgz#6c7a043d2b6305859974a92c30c2fa0d1285bbd3" + integrity sha512-jD88fvzDViMDH5KmmNJgzMBDj/95bDTt6+kBNaNxP4G98xUTnDMiLUY2CYmToba6JAFhM9VkcaQuxCNRLGR7zg== + dependencies: + "@types/w3c-web-usb" "^1.0.6" + node-addon-api "^8.0.0" + node-gyp-build "^4.5.0" + +use-callback-ref@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" + integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== + dependencies: + tslib "^2.0.0" + +use-sidecar@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" + integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + +use-sync-external-store@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + +use-sync-external-store@^1.4.0, use-sync-external-store@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0" + integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A== + +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +uuid@8.3.2, uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +uuidv4@^6.2.13: + version "6.2.13" + resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.13.tgz#8f95ec5ef22d1f92c8e5d4c70b735d1c89572cb7" + integrity sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ== + dependencies: + "@types/uuid" "8.3.4" + uuid "8.3.2" + +valtio@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.13.2.tgz#e31d452d5da3550935417670aafd34d832dc7241" + integrity sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A== + dependencies: + derive-valtio "0.1.0" + proxy-compare "2.6.0" + use-sync-external-store "1.2.0" + +varuint-bitcoin@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz#59a53845a87ad18c42f184a3d325074465341523" + integrity sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog== + dependencies: + uint8array-tools "^0.0.8" + +vary@^1, vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +vfile-location@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.3.tgz#cb9eacd20f2b6426d19451e0eafa3d0a846225c3" + integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg== + dependencies: + "@types/unist" "^3.0.0" + vfile "^6.0.0" + +vfile-message@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" + integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-stringify-position "^4.0.0" + +vfile@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.3.tgz#3652ab1c496531852bf55a6bac57af981ebc38ab" + integrity sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== + dependencies: + "@types/unist" "^3.0.0" + vfile-message "^4.0.0" + +victory-vendor@^36.6.8: + version "36.9.2" + resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801" + integrity sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ== + dependencies: + "@types/d3-array" "^3.0.3" + "@types/d3-ease" "^3.0.0" + "@types/d3-interpolate" "^3.0.1" + "@types/d3-scale" "^4.0.2" + "@types/d3-shape" "^3.1.0" + "@types/d3-time" "^3.0.0" + "@types/d3-timer" "^3.0.0" + d3-array "^3.1.6" + d3-ease "^3.0.1" + d3-interpolate "^3.0.1" + d3-scale "^4.0.2" + d3-shape "^3.1.0" + d3-time "^3.0.0" + d3-timer "^3.0.1" + +viem@2.23.2: + version "2.23.2" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.23.2.tgz#db395c8cf5f4fb5572914b962fb8ce5db09f681c" + integrity sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA== + dependencies: + "@noble/curves" "1.8.1" + "@noble/hashes" "1.7.1" + "@scure/bip32" "1.6.2" + "@scure/bip39" "1.5.4" + abitype "1.0.8" + isows "1.0.6" + ox "0.6.7" + ws "8.18.0" + +viem@>=2.23.11: + version "2.33.0" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.33.0.tgz#d4ed73a69e26507c523ae70d19548572bfedc0f8" + integrity sha512-SxBM3CmeU+LWLlBclV9MPdbuFV8mQEl0NeRc9iyYU4a7Xb5sr5oku3s/bRGTPpEP+1hCAHYpM09/ui3/dQ6EsA== + dependencies: + "@noble/curves" "1.9.2" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + abitype "1.0.8" + isows "1.0.7" + ox "0.8.1" + ws "8.18.2" + +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +web-namespaces@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" + integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== + +web-streams-polyfill@^3.0.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + +web3-utils@^1.3.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" + integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== + dependencies: + "@ethereumjs/util" "^8.1.0" + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereum-cryptography "^2.1.2" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + +"web@link:shiki/bundle/web": + version "0.0.0" + uid "" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +webrtc-adapter@^7.2.1: + version "7.7.1" + resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz#b2c227a6144983b35057df67bd984a7d4bfd17f1" + integrity sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A== + dependencies: + rtcpeerconnection-shim "^1.2.15" + sdp "^2.12.0" + +"whatwg-url@^14.1.0 || ^13.0.0": + version "14.2.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.2.0.tgz#4ee02d5d725155dae004f6ae95c73e7ef5d95663" + integrity sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw== + dependencies: + tr46 "^5.1.0" + webidl-conversions "^7.0.0" + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which-typed-array@^1.1.16, which-typed-array@^1.1.2: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wif@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/wif/-/wif-5.0.0.tgz#445e44b8f62e155144d1c970c01ca2ba3979cc3f" + integrity sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA== + dependencies: + bs58check "^4.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + +ws@8.18.2: + version "8.18.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" + integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== + +ws@^7.5.1, ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + +ws@^8.13.0, ws@^8.18.0, ws@^8.5.0: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + +ws@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +xmlhttprequest-ssl@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23" + integrity sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ== + +xrpl@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/xrpl/-/xrpl-4.3.0.tgz#769fb81b2ec169ff98391a55720b65bccb7b86c9" + integrity sha512-MW/VyWyTGNmfmt5EaPexKb7ojcnobdzaqtm5UC9NErtlq7IgayqAZpMI26ptOzQolGndK7vOk8U0iOBpMSykJQ== + dependencies: + "@scure/bip32" "^1.3.1" + "@scure/bip39" "^1.2.1" + "@xrplf/isomorphic" "^1.0.1" + "@xrplf/secret-numbers" "^1.0.0" + bignumber.js "^9.0.0" + eventemitter3 "^5.0.1" + ripple-address-codec "^5.0.0" + ripple-binary-codec "^2.4.0" + ripple-keypairs "^2.0.0" + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + +yaml@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.0.tgz#15f8c9866211bdc2d3781a0890e44d4fa1a5fff6" + integrity sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^17.0.1, yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== + +zod-to-json-schema@^3.24.1, zod-to-json-schema@^3.24.5: + version "3.24.6" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz#5920f020c4d2647edfbb954fa036082b92c9e12d" + integrity sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg== + +zod@3.22.4: + version "3.22.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" + integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== + +zod@^3.20.2, zod@^3.23.8, zod@^3.24.3, zod@^3.25.67: + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== + +zustand@^5.0.5: + version "5.0.6" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.6.tgz#a2da43d8dc3d31e314279e5baec06297bea70a5c" + integrity sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A== + +zwitch@^2.0.0, zwitch@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== From c759c87e7051c5e78d887274450183400c3c1155 Mon Sep 17 00:00:00 2001 From: Van Minh Date: Mon, 28 Jul 2025 01:30:18 +0700 Subject: [PATCH 2/3] feat(docs): Add guideline for txn-explorer-link --- components/txn-error-fallback-preview.tsx | 8 - components/txn-explorer-link-preview.tsx | 109 +++++++ .../murphy/Txn-Feedback/txn-explorer-link.tsx | 56 ++-- .../Txn-Feedback/txn-error-fallback.mdx | 16 +- .../Txn-Feedback/txn-explorer-link.mdx | 287 ++++++++++++++++++ 5 files changed, 432 insertions(+), 44 deletions(-) create mode 100644 components/txn-explorer-link-preview.tsx create mode 100644 content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx diff --git a/components/txn-error-fallback-preview.tsx b/components/txn-error-fallback-preview.tsx index 8df4f51..4d74bec 100644 --- a/components/txn-error-fallback-preview.tsx +++ b/components/txn-error-fallback-preview.tsx @@ -90,14 +90,6 @@ export default function TxnErrorFallbackPreview() { > Error with Logs - - {showError && ( diff --git a/components/txn-explorer-link-preview.tsx b/components/txn-explorer-link-preview.tsx new file mode 100644 index 0000000..afcd63d --- /dev/null +++ b/components/txn-explorer-link-preview.tsx @@ -0,0 +1,109 @@ +"use client"; + +import Link from "next/link"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { ArrowLeft } from "lucide-react"; +import { TxnExplorerLink } from "@/components/ui/murphy"; + +export default function TxnExplorerLinkPreview() { + const sampleSignatures = { + mainnet: + "5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM7n", + testnet: + "2B5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM", + devnet: + "3C6VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM", + }; + + return ( +
+
+

Transaction Explorer Link

+

+ Direct links to Solana Explorer for transaction details +

+
+ +
+ {/* Different Clusters */} + + + Different Clusters + + Links to different Solana network clusters + + + + {(["mainnet", "testnet", "devnet"] as const).map((cluster) => ( +
+

{cluster}

+ +
+ ))} +
+
+ + {/* Different Variants */} + + + Different Variants + + Various button styles and sizes + + + + {(["default", "outline", "ghost", "link"] as const).map( + (variant) => ( +
+

{variant} Variant

+ +
+ ) + )} +
+
+
+ + {/* Different Sizes */} + + + Different Sizes + + Various button sizes for different use cases + + + +
+ {(["sm", "default", "lg", "icon"] as const).map((size) => ( +
+

{size}

+ + {size === "icon" ? "🔗" : undefined} + +
+ ))} +
+
+
+
+ ); +} diff --git a/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx b/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx index e011d30..cce722c 100644 --- a/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx +++ b/components/ui/murphy/Txn-Feedback/txn-explorer-link.tsx @@ -1,18 +1,24 @@ -"use client" +"use client"; -import type React from "react" -import { ExternalLink } from "lucide-react" -import { Button } from "@/components/ui/button" -import { cn } from "@/lib/utils" +import type React from "react"; +import { ExternalLink } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; interface TxnExplorerLinkProps { - signature: string - cluster?: "mainnet-beta" | "testnet" | "devnet" - children?: React.ReactNode - className?: string - variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" - size?: "default" | "sm" | "lg" | "icon" - showIcon?: boolean + signature: string; + cluster?: "mainnet-beta" | "testnet" | "devnet"; + children?: React.ReactNode; + className?: string; + variant?: + | "default" + | "destructive" + | "outline" + | "secondary" + | "ghost" + | "link"; + size?: "default" | "sm" | "lg" | "icon"; + showIcon?: boolean; } export function TxnExplorerLink({ @@ -25,23 +31,31 @@ export function TxnExplorerLink({ showIcon = true, }: TxnExplorerLinkProps) { const getExplorerUrl = () => { - const baseUrl = "https://explorer.solana.com/tx" - const clusterParam = cluster !== "mainnet-beta" ? `?cluster=${cluster}` : "" - return `${baseUrl}/${signature}${clusterParam}` - } + const baseUrl = "https://explorer.solana.com/tx"; + const clusterParam = + cluster !== "mainnet-beta" ? `?cluster=${cluster}` : ""; + return `${baseUrl}/${signature}${clusterParam}`; + }; const handleClick = () => { - window.open(getExplorerUrl(), "_blank", "noopener,noreferrer") - } + window.open(getExplorerUrl(), "_blank", "noopener,noreferrer"); + }; return ( - - ) + ); } diff --git a/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx b/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx index 5a25d8a..103093a 100644 --- a/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx +++ b/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx @@ -1,7 +1,7 @@ --- title: Transaction Error Fallback description: Comprehensive error handling UI with retry and debugging features -icon: AlertTriangle +icon: Ban --- import TxnErrorFallbackPreiew from "@/components/txn-error-fallback-preview"; @@ -18,14 +18,6 @@ import TxnErrorFallbackPreiew from "@/components/txn-error-fallback-preview"; ## Installation - - Install dependencies - - - - - -{" "} Install Transaction Error Fallback @@ -34,12 +26,6 @@ import TxnErrorFallbackPreiew from "@/components/txn-error-fallback-preview"; /> - - Add the component to your project - - After installation, you can find the component in `components/ui/murphy/txn-error-fallback.tsx` - - ## Basic Usage diff --git a/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx b/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx new file mode 100644 index 0000000..2840a2c --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx @@ -0,0 +1,287 @@ +--- +title: Transaction Explorer Link +description: Direct links to Solana Explorer for transaction details +icon: ExternalLink +--- + +import TxnExplorerLinkPreiew from "@/components/txn-explorer-link-preview"; + + +
+ +
+
+ +## Installation + + + + + Install Transaction Explorer Link + + + + + +## Basic Usage + +```tsx +"use client"; + +import { TxnExplorerLink } from "@/components/ui/murphy/tx-explorer-link"; + +export default function MyPage() { + const transactionSignature = + "5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM7n"; + + return ( +
+

Transaction Details

+ +
+

Transaction completed successfully!

+ + + View on Solana Explorer + +
+
+ ); +} +``` + +## Props + + + +## Examples + +### Different Clusters + +```tsx +// Mainnet transaction + + + View on Mainnet + + +// Devnet transaction + + + View on Devnet + + +// Testnet transaction + + + View on Testnet + +``` + +### Different Button Variants + +```tsx +// Default variant + + + Default Style + + +// Outline variant (default) + + + Outline Style + + +// Ghost variant + + + Ghost Style + + +// Link variant + + + Link Style + +``` + +### Different Sizes + +```tsx +// Small size + + + Small Link + + +// Default size + + + Default Link + + +// Large size + + + Large Link + + +// Icon only + + + 🔗 + +``` + +### Custom Content + +```tsx +// Custom text + +View Transaction Details + +// Without icon + + + Check on Explorer + + +// With truncated signature + + + {signature.slice(0, 8)}...{signature.slice(-8)} + + +// Custom styling + + + Custom Styled Link + + +``` + +## Explorer Features + +When users click the explorer link, they can see: + +### Transaction Details + +- Transaction signature and status +- Block confirmation details +- Fee information and compute units used +- Timestamp and slot number + +### Account Changes + +- Balance changes for all involved accounts +- Token transfers and amounts +- Account modifications and updates +- Program interactions and calls + +### Program Logs + +- Instruction execution logs +- Error messages and debugging info +- Program outputs and return values +- Custom program log messages + +### Additional Information + +- Transaction size and priority fee +- Recent blockhash used +- Signer accounts and permissions +- Cross-program invocations + +## Customization + +### Custom URL Generation + +```tsx +const getCustomExplorerUrl = (signature: string, cluster: string) => { + // Use different explorer based on preference + const explorers = { + solana: `https://explorer.solana.com/tx/${signature}${ + cluster !== "mainnet-beta" ? `?cluster=${cluster}` : "" + }`, + solscan: `https://solscan.io/tx/${signature}${ + cluster !== "mainnet-beta" ? `?cluster=${cluster}` : "" + }`, + xray: `https://xray.helius.xyz/tx/${signature}${ + cluster !== "mainnet-beta" ? `?network=${cluster}` : "" + }`, + }; + + return explorers.solana; // or based on user preference +}; +``` + +### Custom Styling + +```tsx + + 🔍 Explore Transaction + +``` From d4ab99ff19900fffd0def64b2348aa9ac1439cef Mon Sep 17 00:00:00 2001 From: Van Minh Date: Mon, 28 Jul 2025 17:44:52 +0700 Subject: [PATCH 3/3] feat(docs): Add guideline for txn-feedback-toast, txn-pending-indicator, txn-progress-steps, txn-retry-button --- components/step-flow-dialog-preview.tsx | 173 +++++++++---- components/success-dialog-preview.tsx | 2 - components/txn-error-fallback-preview.tsx | 3 - components/txn-explorer-link-preview.tsx | 7 - components/txn-feedback-toast-preview.tsx | 112 +++++++++ components/txn-pending-indication-preview.tsx | 180 +++++++++++++ components/txn-progress-steps-preview.tsx | 193 ++++++++++++++ components/txn-retry-button-preview.tsx | 83 ++++++ .../Txn-Feedback/txn-feedback-toast.tsx | 236 +++++++++++------- .../Txn-Feedback/txn-error-fallback.mdx | 2 +- .../Txn-Feedback/txn-explorer-link.mdx | 2 +- .../Txn-Feedback/txn-feedback-toast.mdx | 145 +++++++++++ .../Txn-Feedback/txn-pending-indicator.mdx | 199 +++++++++++++++ .../Txn-Feedback/txn-progress-steps.mdx | 159 ++++++++++++ .../Txn-Feedback/txn-retry-button.mdx | 190 ++++++++++++++ 15 files changed, 1536 insertions(+), 150 deletions(-) create mode 100644 components/txn-feedback-toast-preview.tsx create mode 100644 components/txn-pending-indication-preview.tsx create mode 100644 components/txn-progress-steps-preview.tsx create mode 100644 components/txn-retry-button-preview.tsx create mode 100644 content/docs/onchainkit/Txn-Feedback/txn-feedback-toast.mdx create mode 100644 content/docs/onchainkit/Txn-Feedback/txn-pending-indicator.mdx create mode 100644 content/docs/onchainkit/Txn-Feedback/txn-progress-steps.mdx create mode 100644 content/docs/onchainkit/Txn-Feedback/txn-retry-button.mdx diff --git a/components/step-flow-dialog-preview.tsx b/components/step-flow-dialog-preview.tsx index faafdca..8ff28d5 100644 --- a/components/step-flow-dialog-preview.tsx +++ b/components/step-flow-dialog-preview.tsx @@ -1,104 +1,173 @@ -"use client" +"use client"; -import { useState } from "react" -import { Button } from "@/components/ui/button" -import { TxnStep } from "@/types/transaction" -import { StepFlowDialog } from "./ui/murphy" +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { TxnStep } from "@/types/transaction"; +import { StepFlowDialog } from "./ui/murphy"; export default function StepFlowDialogPreview() { - const [showDialog, setShowDialog] = useState(false) - const [currentStep, setCurrentStep] = useState(0) - const [dialogType, setDialogType] = useState<"nft-mint" | "token-swap" | "staking">("nft-mint") + const [showDialog, setShowDialog] = useState(false); + const [currentStep, setCurrentStep] = useState(0); + const [dialogType, setDialogType] = useState< + "nft-mint" | "token-swap" | "staking" + >("nft-mint"); const workflows = { "nft-mint": { title: "Mint NFT Process", description: "Complete the following steps to mint your NFT", steps: [ - { id: "1", title: "Upload Metadata", description: "Upload image and metadata to IPFS", status: "pending" as const }, - { id: "2", title: "Create Mint Account", description: "Create NFT mint account on Solana", status: "pending" as const }, - { id: "3", title: "Mint Token", description: "Mint NFT to your wallet", status: "pending" as const }, - { id: "4", title: "Verify Ownership", description: "Verify NFT in your wallet", status: "pending" as const }, + { + id: "1", + title: "Upload Metadata", + description: "Upload image and metadata to IPFS", + status: "pending" as const, + }, + { + id: "2", + title: "Create Mint Account", + description: "Create NFT mint account on Solana", + status: "pending" as const, + }, + { + id: "3", + title: "Mint Token", + description: "Mint NFT to your wallet", + status: "pending" as const, + }, + { + id: "4", + title: "Verify Ownership", + description: "Verify NFT in your wallet", + status: "pending" as const, + }, ], }, "token-swap": { title: "Token Swap Process", description: "Swap your tokens through the following steps", steps: [ - { id: "1", title: "Get Quote", description: "Calculate swap rates and fees", status: "pending" as const }, - { id: "2", title: "Approve Spending", description: "Approve token spending limit", status: "pending" as const }, - { id: "3", title: "Execute Swap", description: "Perform the token exchange", status: "pending" as const }, + { + id: "1", + title: "Get Quote", + description: "Calculate swap rates and fees", + status: "pending" as const, + }, + { + id: "2", + title: "Approve Spending", + description: "Approve token spending limit", + status: "pending" as const, + }, + { + id: "3", + title: "Execute Swap", + description: "Perform the token exchange", + status: "pending" as const, + }, ], }, staking: { title: "Staking Process", description: "Stake your tokens to earn rewards", steps: [ - { id: "1", title: "Select Validator", description: "Choose a validator to stake with", status: "pending" as const }, - { id: "2", title: "Create Stake Account", description: "Create a new stake account", status: "pending" as const }, - { id: "3", title: "Delegate Stake", description: "Delegate tokens to validator", status: "pending" as const }, - { id: "4", title: "Activate Stake", description: "Wait for stake activation", status: "pending" as const }, + { + id: "1", + title: "Select Validator", + description: "Choose a validator to stake with", + status: "pending" as const, + }, + { + id: "2", + title: "Create Stake Account", + description: "Create a new stake account", + status: "pending" as const, + }, + { + id: "3", + title: "Delegate Stake", + description: "Delegate tokens to validator", + status: "pending" as const, + }, + { + id: "4", + title: "Activate Stake", + description: "Wait for stake activation", + status: "pending" as const, + }, ], }, - } + }; const updateStepStatus = (stepIndex: number, status: TxnStep["status"]) => { - const currentWorkflow = workflows[dialogType] + const currentWorkflow = workflows[dialogType]; return currentWorkflow.steps.map((step, index) => { - if (index < stepIndex) return { ...step, status: "completed" as const } - if (index === stepIndex) return { ...step, status } - return { ...step, status: "pending" as const } - }) - } + if (index < stepIndex) return { ...step, status: "completed" as const }; + if (index === stepIndex) return { ...step, status }; + return { ...step, status: "pending" as const }; + }); + }; - const [currentSteps, setCurrentSteps] = useState(workflows["nft-mint"].steps) + const [currentSteps, setCurrentSteps] = useState( + workflows["nft-mint"].steps + ); const openDialog = (type: keyof typeof workflows) => { - setDialogType(type) - setCurrentStep(0) - setCurrentSteps(workflows[type].steps) - setShowDialog(true) - } + setDialogType(type); + setCurrentStep(0); + setCurrentSteps(workflows[type].steps); + setShowDialog(true); + }; const handleNext = async () => { - await new Promise((resolve) => setTimeout(resolve, 1500)) + await new Promise((resolve) => setTimeout(resolve, 1500)); - const nextStep = currentStep + 1 - setCurrentSteps(updateStepStatus(currentStep, "completed")) + const nextStep = currentStep + 1; + setCurrentSteps(updateStepStatus(currentStep, "completed")); if (nextStep < workflows[dialogType].steps.length) { - setCurrentStep(nextStep) - setCurrentSteps(updateStepStatus(nextStep, "active")) + setCurrentStep(nextStep); + setCurrentSteps(updateStepStatus(nextStep, "active")); } - } + }; const handlePrevious = () => { - const prevStep = Math.max(currentStep - 1, 0) - setCurrentStep(prevStep) - setCurrentSteps(updateStepStatus(prevStep, "active")) - } + const prevStep = Math.max(currentStep - 1, 0); + setCurrentStep(prevStep); + setCurrentSteps(updateStepStatus(prevStep, "active")); + }; const handleCancel = () => { - setShowDialog(false) - setCurrentStep(0) - setCurrentSteps(workflows[dialogType].steps) - } + setShowDialog(false); + setCurrentStep(0); + setCurrentSteps(workflows[dialogType].steps); + }; return (
-

Multi-Step Workflow Preview

-

Choose a workflow to simulate

+

+ Choose a workflow to simulate +

- - -
@@ -117,5 +186,5 @@ export default function StepFlowDialogPreview() { canGoNext={currentStep < workflows[dialogType].steps.length - 1} />
- ) + ); } diff --git a/components/success-dialog-preview.tsx b/components/success-dialog-preview.tsx index 67aa2d1..102d5d6 100644 --- a/components/success-dialog-preview.tsx +++ b/components/success-dialog-preview.tsx @@ -51,8 +51,6 @@ export default function SuccessDialogPreview() { return (
-

Success Dialog Examples

- + ))} +
+ +
+ + +
+ + + + + + + {/* Toast */} + setTxStatus({ status: "idle" })} + /> + + ); +} diff --git a/components/txn-pending-indication-preview.tsx b/components/txn-pending-indication-preview.tsx new file mode 100644 index 0000000..c5c995b --- /dev/null +++ b/components/txn-pending-indication-preview.tsx @@ -0,0 +1,180 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Plus, X } from "lucide-react"; +import { TxnPendingIndicator } from "./ui/murphy"; + +interface PendingTransaction { + id: string; + signature?: string; + description: string; + startTime: number; +} + +export default function TxnPendingIndicatorPreview() { + const [pendingTransactions, setPendingTransactions] = useState< + PendingTransaction[] + >([]); + const [position, setPosition] = useState< + "top-left" | "top-right" | "bottom-left" | "bottom-right" + >("bottom-right"); + + const addTransaction = (description: string) => { + const newTransaction: PendingTransaction = { + id: Date.now().toString(), + description, + startTime: Date.now(), + }; + setPendingTransactions((prev) => [...prev, newTransaction]); + + setTimeout(() => { + setPendingTransactions((prev) => + prev.filter((txn) => txn.id !== newTransaction.id) + ); + }, 15000); + }; + + const removeTransaction = (id: string) => { + setPendingTransactions((prev) => prev.filter((txn) => txn.id !== id)); + }; + + const clearAllTransactions = () => { + setPendingTransactions([]); + }; + + const addBatchTransactions = () => { + const batchTransactions = [ + "Transfer to Alice", + "Transfer to Bob", + "Transfer to Charlie", + ].map((desc, index) => ({ + id: `batch_${Date.now()}_${index}`, + description: desc, + startTime: Date.now(), + })); + + setPendingTransactions((prev) => [...prev, ...batchTransactions]); + + setTimeout(() => { + batchTransactions.forEach((txn) => { + setPendingTransactions((prev) => prev.filter((t) => t.id !== txn.id)); + }); + }, 20000); + }; + + return ( +
+
+ + + + Example Usage + + + Add transactions to see the pending indicator appear. It will show + in the {position} corner. + + + +
+ + + +
+ +
+ + +
+ +
+ + Current pending: + + {pendingTransactions.length} +
+
+
+ + + + + Position Options + + + Change the position of the pending indicator on screen + + + +
+ {( + [ + "top-left", + "top-right", + "bottom-left", + "bottom-right", + ] as const + ).map((pos) => ( + + ))} +
+
+
+
+ + +
+ ); +} diff --git a/components/txn-progress-steps-preview.tsx b/components/txn-progress-steps-preview.tsx new file mode 100644 index 0000000..e65257c --- /dev/null +++ b/components/txn-progress-steps-preview.tsx @@ -0,0 +1,193 @@ +"use client"; + +import { useRef, useState } from "react"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { TxnStep } from "@/types/transaction"; +import { TxnProgressSteps } from "./ui/murphy"; + +export default function TxnProgressStepsPreview() { + const initialSteps: TxnStep[] = [ + { + id: "1", + title: "Connect Wallet", + description: "Connect your Solana wallet", + status: "completed", + }, + { + id: "2", + title: "Prepare Transaction", + description: "Preparing transaction data", + status: "completed", + }, + { + id: "3", + title: "Sign Transaction", + description: "Sign with your wallet", + status: "active", + }, + { + id: "4", + title: "Submit to Network", + description: "Broadcasting to Solana", + status: "pending", + }, + { + id: "5", + title: "Confirmation", + description: "Waiting for confirmation", + status: "pending", + }, + ]; + + const [currentSteps, setCurrentSteps] = useState(initialSteps); + const intervalRef = useRef(null); + + const updateSteps = ( + stepIndex: number, + status: TxnStep["status"] + ): TxnStep[] => { + return initialSteps.map((step, index) => { + if (index < stepIndex) return { ...step, status: "completed" }; + if (index === stepIndex) return { ...step, status }; + return { ...step, status: "pending" }; + }); + }; + + const simulateProgress = () => { + if (intervalRef.current) return; // prevent multiple intervals + + let step = 0; + intervalRef.current = setInterval(() => { + if (step < initialSteps.length) { + setCurrentSteps(updateSteps(step, "active")); + step++; + } else { + setCurrentSteps(updateSteps(initialSteps.length - 1, "completed")); + clearStimulate(); + } + }, 1500); + }; + + const simulateError = () => { + const activeIndex = currentSteps.findIndex( + (step) => step.status === "active" + ); + if (activeIndex === -1) return; + + // Stop progression + clearStimulate(); + + // Set error step + setCurrentSteps((prev) => + prev.map((step, index) => + index === activeIndex ? { ...step, status: "error" } : step + ) + ); + }; + + const clearStimulate = () => { + if (intervalRef.current) { + clearInterval(intervalRef.current); + intervalRef.current = null; + } + }; + + const reset = () => { + clearStimulate(); + setCurrentSteps(initialSteps); + }; + + return ( +
+ {/* Horizontal */} + + + Horizontal Layout + + Perfect for desktop interfaces and wide layouts + + + + +
+ + + +
+
+
+ + {/* Vertical */} + + + Vertical Layout + + Ideal for mobile interfaces and detailed descriptions + + + + + + + + {/* Step States */} + + + Step States + + Different visual states for transaction steps + + + +
+

Success Flow

+ +
+
+

Error Flow

+ +
+
+
+
+ ); +} diff --git a/components/txn-retry-button-preview.tsx b/components/txn-retry-button-preview.tsx new file mode 100644 index 0000000..c48f2fb --- /dev/null +++ b/components/txn-retry-button-preview.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { useState } from "react"; +import { TxnFeedbackToast, TxnRetryButton } from "./ui/murphy"; +import type { TransactionStatus } from "@/types/transaction"; + +export default function TxnRetryButtonPreview() { + const [toastStatus, setToastStatus] = useState({ + status: "idle", + }); + + const simulateTransaction = async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const success = Math.random() < 0.6; + + if (success) { + setToastStatus({ + status: "success", + }); + } else { + setToastStatus({ + status: "error", + }); + throw new Error("Simulated transaction failure"); + } + }; + + const closeToast = () => { + setToastStatus({ status: "idle" }); + }; + + return ( +
+
+
+

+ Standard Retry (3 attempts) +

+ + Retry Transaction + +
+ +
+

+ Quick Retry (5 attempts, 500ms delay) +

+ + Quick Retry + +
+ +
+

+ Single Retry (1 attempt) +

+ + Single Retry + +
+
+ + +
+ ); +} diff --git a/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx b/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx index 5c8fe00..b469f06 100644 --- a/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx +++ b/components/ui/murphy/Txn-Feedback/txn-feedback-toast.tsx @@ -1,117 +1,185 @@ -"use client" +"use client"; -import { useEffect, useState } from "react" -import { CheckCircle, XCircle, Loader2, AlertCircle } from "lucide-react" -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import type { TxnFeedbackProps } from "@/types/transaction" +import { useEffect, useState } from "react"; +import { + X, + CheckCircle, + AlertCircle, + Loader2, + Send, + Clock, + FileSignature, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import type { TransactionStatus } from "@/types/transaction"; -export function TxnFeedbackToast({ status, onRetry, onClose }: TxnFeedbackProps) { - const [isVisible, setIsVisible] = useState(false) +interface TxnFeedbackToastProps { + status: TransactionStatus; + onRetry?: () => void; + onClose: () => void; +} - useEffect(() => { - if (status.status !== "idle") { - setIsVisible(true) - } - }, [status.status]) +export function TxnFeedbackToast({ + status, + onRetry, + onClose, +}: TxnFeedbackToastProps) { + const [isVisible, setIsVisible] = useState(false); useEffect(() => { - if (status.status === "success") { - const timer = setTimeout(() => { - setIsVisible(false) - onClose?.() - }, 5000) - return () => clearTimeout(timer) + if (status.status !== "idle") { + setIsVisible(true); + } else { + setIsVisible(false); } - }, [status.status, onClose]) + }, [status.status]); - if (!isVisible || status.status === "idle") return null - - const getIcon = () => { - switch (status.status) { - case "success": - return - case "error": - return - case "preparing": - case "signing": - case "sending": - case "confirming": - return - default: - return - } + if (!isVisible || status.status === "idle") { + return null; } - const getMessage = () => { + const getStatusConfig = () => { switch (status.status) { case "preparing": - return "Preparing transaction..." + return { + icon: , + title: "Preparing Transaction", + description: "Setting up your transaction...", + bgColor: "bg-blue-50 dark:bg-blue-950", + borderColor: "border-blue-200 dark:border-blue-800", + textColor: "text-blue-900 dark:text-blue-100", + }; case "signing": - return "Please sign the transaction" + return { + icon: , + title: "Signing Transaction", + description: "Please sign the transaction in your wallet...", + bgColor: "bg-yellow-50 dark:bg-yellow-950", + borderColor: "border-yellow-200 dark:border-yellow-800", + textColor: "text-yellow-900 dark:text-yellow-100", + }; case "sending": - return "Sending transaction..." + return { + icon: , + title: "Sending Transaction", + description: "Broadcasting to the network...", + bgColor: "bg-purple-50 dark:bg-purple-950", + borderColor: "border-purple-200 dark:border-purple-800", + textColor: "text-purple-900 dark:text-purple-100", + }; case "confirming": - return "Confirming transaction..." + return { + icon: , + title: "Confirming Transaction", + description: "Waiting for network confirmation...", + bgColor: "bg-orange-50 dark:bg-orange-950", + borderColor: "border-orange-200 dark:border-orange-800", + textColor: "text-orange-900 dark:text-orange-100", + }; case "success": - return "Transaction successful!" + return { + icon: ( + + ), + title: "Transaction Successful", + description: status.signature + ? `Signature: ${status.signature.slice( + 0, + 8 + )}...${status.signature.slice(-8)}` + : "Your transaction has been completed successfully.", + bgColor: "bg-green-50 dark:bg-green-950", + borderColor: "border-green-200 dark:border-green-800", + textColor: "text-green-900 dark:text-green-100", + }; case "error": - return status.error || "Transaction failed" + return { + icon: , + title: "Transaction Failed", + description: + status.error || + "An error occurred while processing your transaction.", + bgColor: "bg-red-50 dark:bg-red-950", + borderColor: "border-red-200 dark:border-red-800", + textColor: "text-red-900 dark:text-red-100", + }; default: - return "Processing..." + return null; } - } + }; - const getBgColor = () => { - switch (status.status) { - case "success": - return "bg-green-50 border-green-200" - case "error": - return "bg-red-50 border-red-200" - default: - return "bg-blue-50 border-blue-200" - } - } + const config = getStatusConfig(); + if (!config) return null; return ( -
-
-
- {getIcon()} -
-

{getMessage()}

- {status.signature && ( -

- Signature: {status.signature.slice(0, 8)}...{status.signature.slice(-8)} -

- )} +
+
+
+ {/* Icon container with proper alignment */} +
+ {config.icon}
-
+ + {/* Content container */} +
+
+ {config.title} +
+
+ {config.description} +
+ + {/* Action buttons */} {status.status === "error" && onRetry && ( - +
+ +
+ )} + + {status.status === "success" && status.signature && ( +
+ +
)} +
+ + {/* Close button with proper alignment */} +
- ) + ); } diff --git a/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx b/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx index 103093a..8e95e39 100644 --- a/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx +++ b/content/docs/onchainkit/Txn-Feedback/txn-error-fallback.mdx @@ -35,7 +35,7 @@ import TxnErrorFallbackPreiew from "@/components/txn-error-fallback-preview"; import { useState } from "react"; import { Button } from "@/components/ui/button"; -import { TxnnErrorFallback } from "@/components/ui/murphy/txn-error-fallback"; +import { TxnnErrorFallback } from "@/components/ui/murphy/Txn-Feedback/txn-error-fallback"; export default function MyPage() { const [showError, setShowError] = useState(false); diff --git a/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx b/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx index 2840a2c..cbca8ab 100644 --- a/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx +++ b/content/docs/onchainkit/Txn-Feedback/txn-explorer-link.mdx @@ -33,7 +33,7 @@ import TxnExplorerLinkPreiew from "@/components/txn-explorer-link-preview"; ```tsx "use client"; -import { TxnExplorerLink } from "@/components/ui/murphy/tx-explorer-link"; +import { TxnExplorerLink } from "@/components/ui/murphy/Txn-Feedback/txn-explorer-link"; export default function MyPage() { const transactionSignature = diff --git a/content/docs/onchainkit/Txn-Feedback/txn-feedback-toast.mdx b/content/docs/onchainkit/Txn-Feedback/txn-feedback-toast.mdx new file mode 100644 index 0000000..cdcd48c --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/txn-feedback-toast.mdx @@ -0,0 +1,145 @@ +--- +title: Transaction Feedback Toast +description: Real-time toast notifications for transaction status updates +icon: Bell +--- + +import TxnFeedbackToastPreview from "@/components/txn-feedback-toast-preview"; + + +
+ +

+ Click buttons above to see toast notifications in the top-right corner +

+
+
+ +## Installation + + + + + Install Transaction Feedback Toast + + + + + +## Basic Usage + +```tsx +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { TxnFeedbackToast } from "@/components/ui/murphy/Txn-Feedback/txn-feedback-toast"; +import type { TransactionStatus } from "@/types/transaction"; + +export default function MyPage() { + const [txnStatus, setTxnStatus] = useState({ + status: "idle", + }); + + const simulateTransaction = async () => { + const statuses: TransactionStatus["status"][] = [ + "preparing", + "signing", + "sending", + "confirming", + ]; + + for (const status of statuses) { + setTxnStatus({ status }); + await new Promise((resolve) => setTimeout(resolve, 2000)); + } + + // Simulate success or error + if (Math.random() > 0.3) { + setTxnStatus({ + status: "success", + signature: + "5VfYmGC9L8ty3D4HutfxndoKXGBwXJWKKvxgF7qQzqK8xMjU9v7Rw2sP3nT6hL4jK9mN8bC1dF2eG3hI5jK6lM7n", + }); + } else { + setTxnStatus({ + status: "error", + error: "Transaction failed: Insufficient funds for transaction fees", + }); + } + }; + + return ( +
+

Transaction Demo

+ + + + simulateTransaction()} + onClose={() => setTxnStatus({ status: "idle" })} + /> +
+ ); +} +``` + +## Props + + void", + default: "undefined", + }, + onClose: { + description: "Callback function when toast is closed", + type: "() => void", + default: "undefined", + }, + }} +/> + +### TransactionStatus Interface + + diff --git a/content/docs/onchainkit/Txn-Feedback/txn-pending-indicator.mdx b/content/docs/onchainkit/Txn-Feedback/txn-pending-indicator.mdx new file mode 100644 index 0000000..fd8d37a --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/txn-pending-indicator.mdx @@ -0,0 +1,199 @@ +--- +title: Pending Transactions Indicator +description: Global indicator showing pending transactions with elapsed time +icon: Clock +--- + +import TxnPendingIndicatorPreview from "@/components/txn-pending-indication-preview"; + + + + + +## Installation + + + + + Install Pending Transactions Indicator + + + + + +## Basic Usage + +```tsx +"use client"; + +import { useState } from "react"; +import { TxnPendingIndicator } from "@/components/ui/murphy/Txn-Feedback/txn-pending-indicator"; +import { Button } from "@/components/ui/button"; + +interface PendingTransaction { + id: string; + description: string; + startTime: number; +} + +export default function MyPage() { + const [pendingTxns, setPendingTxns] = useState([]); + + const addTxn = () => { + const id = Date.now().toString(); + const newTxn: PendingTransaction = { + id, + description: "Simulated Transaction", + startTime: Date.now(), + }; + + setPendingTxns((prev) => [...prev, newTxn]); + }; + + const cancelTxn = (id: string) => { + setPendingTxns((prev) => prev.filter((t) => t.id !== id)); + }; + + return ( +
+ + + +
+ ); +} +``` + +## Props + + void", + default: "undefined", + }, + position: { + description: "Position of the indicator on screen", + type: "'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'", + default: "'bottom-right'", + }, + className: { + description: "Additional CSS classes", + type: "string", + default: "undefined", + }, + }} +/> + +### PendingTransaction Interface + + + +## Indicator Features + +### Collapsible Interface + +- Collapsed: Shows count badge with pending transactions +- Expanded: Shows detailed list of all pending transactions +- Click to toggle between states + +### Elapsed Time Tracking + +- Real-time elapsed time display +- Format: seconds (30s), minutes (2m 30s) +- Updates automatically every second + +### Individual Transaction Management + +- Cancel individual transactions +- Transaction descriptions +- Unique transaction IDs + +### Positioning Options + +- **top-left**: Upper left corner +- **top-right**: Upper right corner +- **bottom-left**: Lower left corner +- **bottom-right**: Lower right corner (default) + +### Auto-hide Behavior + +- Automatically hides when no pending transactions +- Smooth fade in/out animations +- Responsive design for mobile devices + +## Customization + +### Custom Positioning + +```tsx + +``` + +### Custom Styling + +```tsx + +``` + +### Custom Transaction Display + +```tsx +// Extend the component for custom transaction rendering +const CustomPendingIndicator = ({ transactions, onCancel }) => { + return ( + ({ + ...txn, + description: `🔄 ${txn.description} (${txn.type})`, + }))} + onCancel={onCancel} + /> + ); +}; +``` diff --git a/content/docs/onchainkit/Txn-Feedback/txn-progress-steps.mdx b/content/docs/onchainkit/Txn-Feedback/txn-progress-steps.mdx new file mode 100644 index 0000000..96276a2 --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/txn-progress-steps.mdx @@ -0,0 +1,159 @@ +--- +title: Transaction Progress Steps +description: Visual progress indicator for multi-step transaction workflows +icon: Activity +--- + +import TxnProgressStepsPreview from "@/components/txn-progress-steps-preview"; + + +
+
+ +
+
+
+ +## Installation + + + + + Install Transaction Progress Steps + + + + + +## Basic Usage + +```tsx +"use client"; + +import { TxProgressSteps } from "@/components/ui/murphy/Txn-Feedback/txn-progress-steps"; +import type { TxStep } from "@/types/transaction"; + +export default function MyPage() { + const steps: TxStep[] = [ + { + id: "1", + title: "Connect Wallet", + description: "Connect your Solana wallet", + status: "completed", + }, + { + id: "2", + title: "Prepare Transaction", + description: "Preparing transaction data", + status: "completed", + }, + { + id: "3", + title: "Sign Transaction", + description: "Sign with your wallet", + status: "active", + }, + { + id: "4", + title: "Submit to Network", + description: "Broadcasting to Solana", + status: "pending", + }, + { + id: "5", + title: "Confirmation", + description: "Waiting for confirmation", + status: "pending", + }, + ]; + + return ( +
+

Transaction Progress

+ +
+ ); +} +``` + +## Props + + + +### TxStep Interface + + + +## Customization + +### Custom Styling + +```tsx + +``` + +### Responsive Design + +```tsx + + + +``` diff --git a/content/docs/onchainkit/Txn-Feedback/txn-retry-button.mdx b/content/docs/onchainkit/Txn-Feedback/txn-retry-button.mdx new file mode 100644 index 0000000..18c4511 --- /dev/null +++ b/content/docs/onchainkit/Txn-Feedback/txn-retry-button.mdx @@ -0,0 +1,190 @@ +--- +title: Transaction Retry Button +description: Smart retry functionality with configurable limits and delays +icon: RefreshCw +--- + +import TxnRetryButtonPreview from "@/components/txn-retry-button-preview"; + + +
+ +
+
+ +## Installation + + + + + Install Transaction Retry Button + + + + + +## Basic Usage + +```tsx +"use client"; + +import { TxnRetryButton } from "@/components/ui/murphy/Txn-Feedback/txn-retry-button"; + +export default function MyPage() { + const executeTransaction = async () => { + // Simulate network delay + await new Promise((resolve) => setTimeout(resolve, 1500)); + + // 60% chance of failure to demonstrate retry logic + if (Math.random() < 0.6) { + throw new Error("Transaction failed: Network timeout"); + } + + console.log("Transaction successful!"); + }; + + return ( +
+

Retry Button Demo

+ + + Execute Transaction + +
+ ); +} +``` + +## Props + + Promise | void", + default: "required", + }, + disabled: { + description: "Whether the button is disabled", + type: "boolean", + default: "false", + }, + maxRetries: { + description: "Maximum number of retry attempts", + type: "number", + default: "3", + }, + retryDelay: { + description: "Delay between retries in milliseconds", + type: "number", + default: "1000", + }, + children: { + description: "Button content/label", + type: "React.ReactNode", + default: "'Retry'", + }, + className: { + description: "Additional CSS classes", + type: "string", + default: "undefined", + }, + variant: { + description: "Button variant style", + type: "'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'", + default: "'default'", + }, + size: { + description: "Button size", + type: "'default' | 'sm' | 'lg' | 'icon'", + default: "'default'", + }, + }} +/> + +## Retry Strategies + +### Network Errors + +For network-related failures, use longer delays and more retries: + +```tsx + + Network Transaction + +``` + +### Program Errors + +For smart contract errors, use fewer retries: + +```tsx + + Program Transaction + +``` + +### Timeout Errors + +For timeout errors, use moderate retries with increasing delays: + +```tsx + + Timeout-Prone Transaction + +``` + +## Button States + +### Loading State + +Shows spinning icon and "Retrying..." text during retry attempts. + +### Disabled State + +Button becomes disabled after reaching maximum retry attempts. + +### Retry Counter + +Displays current retry attempt count: "(2/3)" + +### Success Reset + +Retry counter resets to 0 after successful execution. + +## Customization + +### Custom Labels + +```tsx + + {(isRetrying) => (isRetrying ? "Processing..." : "Try Again")} + +``` + +### Custom Styling + +```tsx + + Custom Styled Retry + +```