npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

0g-wagmi

v1.0.3

Published

Wagmi hooks for 0G Compute Network

Downloads

32

Readme

0G Wagmi SDK

A monorepo containing wagmi hooks for interacting with the 0G Compute Network.

Packages

  • 0g-wagmi - Core SDK with React hooks for 0G Network integration
  • examples - Example React application demonstrating the 0g-wagmi SDK usage
  • contracts - Smart contracts for Intelligent NFTs (iNFTs) with deployment scripts

0g-wagmi SDK Usage

Installation

npm install 0g-wagmi wagmi viem @tanstack/react-query ethers @0glabs/0g-serving-broker

Quick Reference

| Category | Hook | Description | |----------|------|-------------| | AI Inference | use0gChat | Interact with AI models (streaming & non-streaming) | | | use0gServices | List available AI services | | | use0gServiceMetadata | Get service metadata for a provider | | | use0gBroker | Get underlying broker instance | | Broker Balance | use0gBalance | Query broker balance | | | use0gAddFunds | Add funds to broker | | | use0gWithdrawFunds | Withdraw funds from broker | | | use0gInferenceBalance | Query inference balance for provider | | | use0gInferenceAddFunds | Add funds to specific provider | | Storage | use0gStorageUpload | Upload files to 0G Storage | | | use0gStorageDownload | Download files from 0G Storage | | | use0gStorageFile | Create 0G file objects & compute merkle root | | Key-Value | use0gKeyValue | Store and retrieve key-value pairs | | iNFT | use0gInftMint | Mint intelligent NFTs with AI metadata | | | use0gInftList | List user's iNFTs | | | use0gInftMetadata | Fetch and decrypt iNFT metadata | | Utilities | useEthersSigner | Convert wagmi client to ethers signer |

Available Hooks

AI Inference Hooks

use0gChat (Non-streaming)

Interact with AI models on the 0G network:

import ReactMarkdown from "react-markdown";
import remarkMath from "remark-math";
import remarkGfm from "remark-gfm";
import rehypeKatex from "rehype-katex";
import rehypeRaw from "rehype-raw";
import "katex/dist/katex.min.css";
import { use0gChat } from '0g-wagmi'

function ChatComponent({ providerAddress }: { providerAddress: string }) {
  const { chat, isLoading, error } = use0gChat(providerAddress)
  const [question, setQuestion] = useState('')
  const [response, setResponse] = useState('')

  const handleSubmit = async () => {
    try {
      const answer = await chat(question)
      setResponse(answer)
    } catch (err) {
      console.error('Chat error:', err)
    }
  }

  return (
    <div>
      <input 
        value={question}
        onChange={(e) => setQuestion(e.target.value)}
        placeholder="Ask a question..."
      />
      <button onClick={handleSubmit} disabled={isLoading}>
        {isLoading ? 'Processing...' : 'Send'}
      </button>

      <div>Response:</div>
      <div>
        <ReactMarkdown
          remarkPlugins={[remarkMath, remarkGfm]}
          rehypePlugins={[rehypeKatex, rehypeRaw]}
        >
          {response}
        </ReactMarkdown>
      </div>

      {error && <div>Error: {error}</div>}
    </div>
  )
}

In non-streaming mode, the user only receives the final response once the AI has completed all of its processing. The answer is delivered in full at the end, without showing the AI’s intermediate reasoning or thought process.

use0gChat (Streaming)

Interact with AI models on the 0G network with a streaming response by passing a callback function (response, reason) => { ... } in addition to the chat messages:

import ReactMarkdown from "react-markdown";
import remarkMath from "remark-math";
import remarkGfm from "remark-gfm";
import rehypeKatex from "rehype-katex";
import rehypeRaw from "rehype-raw";
import "katex/dist/katex.min.css";
import { use0gChat } from '0g-wagmi'

function ChatComponent({ providerAddress }: { providerAddress: string }) {
  const { chat, isLoading, error } = use0gChat(providerAddress)
  const [question, setQuestion] = useState('')
  const [response, setResponse] = useState('')
  const [reason, setReason] = useState('')

  const handleSubmit = async () => {
    try {
      const answer = await chat(question, (answer: string, reason: string) => {
        setResponse(answer)
        setReason(reason)
      })
    } catch (err) {
      console.error('Chat error:', err)
    }
  }

  return (
    <div>
      <input 
        value={question}
        onChange={(e) => setQuestion(e.target.value)}
        placeholder="Ask a question..."
      />
      <button onClick={handleSubmit} disabled={isLoading}>
        {isLoading ? 'Processing...' : 'Send'}
      </button>

      <div>Thinking Reason:</div>
      <div>
        <ReactMarkdown
          remarkPlugins={[remarkMath, remarkGfm]}
          rehypePlugins={[rehypeKatex, rehypeRaw]}
        >
          {reason}
        </ReactMarkdown>
      </div>

      <div>Response:</div>
      <div>
        <ReactMarkdown
          remarkPlugins={[remarkMath, remarkGfm]}
          rehypePlugins={[rehypeKatex, rehypeRaw]}
        >
          {response}
        </ReactMarkdown>
      </div>

      {error && <div>Error: {error}</div>}
    </div>
  )
}

In streaming mode, the AI begins sending partial responses as soon as processing starts. Instead of waiting for the full computation to finish, the user can see both the answer and thinking reason unfold in real time.

Passing a series of chat messages

The chat function also supports multi-turn conversations. Simply pass in your conversation as an array of ChatMessage objects (ChatMessage[]):

import ReactMarkdown from "react-markdown";
import remarkMath from "remark-math";
import remarkGfm from "remark-gfm";
import rehypeKatex from "rehype-katex";
import rehypeRaw from "rehype-raw";
import "katex/dist/katex.min.css";
import { use0gChat, ChatMessage } from '0g-wagmi'

function ChatWithHistory({ providerAddress }: { providerAddress: string }) {
  const { chat, isLoading, error } = use0gChat(providerAddress)
  const [messages, setMessages] = useState<ChatMessage[]>([
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "Hello, who won the World Cup in 2018?" },
    { role: "assistant", content: "France won the 2018 FIFA World Cup." }
  ])
  const [question, setQuestion] = useState("")
  const [response, setResponse] = useState("")
  const [reason, setReason] = useState("")

  const handleSubmit = async () => {
    try {
      // Add the new user message to the conversation
      const updatedMessages = [...messages, { role: "user", content: question }]
      setMessages(updatedMessages)

      // Pass the full history to the chat function
      await chat(updatedMessages, (answer: string, reason: string) => {
        setResponse(answer)
        setReason(reason)
      })
    } catch (err) {
      console.error("Chat error:", err)
    }
  }

  return (
    <div>
      <input 
        value={question}
        onChange={(e) => setQuestion(e.target.value)}
        placeholder="Ask a question..."
      />
      <button onClick={handleSubmit} disabled={isLoading}>
        {isLoading ? "Processing..." : "Send"}
      </button>

      <div>Thinking Reason:</div>
      <div>
        <ReactMarkdown
          remarkPlugins={[remarkMath, remarkGfm]}
          rehypePlugins={[rehypeKatex, rehypeRaw]}
        >
          {reason}
        </ReactMarkdown>
      </div>

      <div>Response:</div>
      <div>
        <ReactMarkdown
          remarkPlugins={[remarkMath, remarkGfm]}
          rehypePlugins={[rehypeKatex, rehypeRaw]}
        >
          {response}
        </ReactMarkdown>
      </div>

      {error && <div>Error: {error}</div>}
    </div>
  )
}

use0gBalance

Query balance from the 0G broker:

import { use0gBalance } from '0g-wagmi'

function BalanceComponent() {
  const { balance, isLoading, refetch } = use0gBalance({
    enabled: true,
    refetchInterval: 30000, // Refetch every 30 seconds
  })

  if (isLoading) return <div>Loading...</div>
  
  return (
    <div>
      <p>Total: {balance ? (Number(balance.totalBalance) / 1e18).toFixed(6) : '0'} OG</p>
      <p>Available: {balance ? (Number(balance.availableBalance) / 1e18).toFixed(6) : '0'} OG</p>
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  )
}

use0gAddFunds

Add funds to the 0G broker:

import { use0gAddFunds } from '0g-wagmi'

function AddFundsComponent() {
  const { addFunds, isLoading } = use0gAddFunds({
    onSuccess: (txHash) => {
      console.log('Transaction successful:', txHash)
    },
    onError: (error) => {
      console.error('Transaction failed:', error)
    },
  })

  return (
    <button 
      onClick={() => addFunds('0.1')}
      disabled={isLoading}
    >
      {isLoading ? 'Adding...' : 'Add 0.1 OG'}
    </button>
  )
}

use0gWithdrawFunds

Withdraw funds from the 0G broker:

import { use0gWithdrawFunds } from '0g-wagmi'

function WithdrawComponent() {
  const { withdrawFunds, isLoading } = use0gWithdrawFunds({
    onSuccess: (txHash) => {
      console.log('Withdrawal successful:', txHash)
    },
    onError: (error) => {
      console.error('Withdrawal failed:', error)
    },
  })

  return (
    <button 
      onClick={() => withdrawFunds('0.05')}
      disabled={isLoading}
    >
      {isLoading ? 'Withdrawing...' : 'Withdraw 0.05 OG'}
    </button>
  )
}

use0gServices

List available AI services on the 0G network:

import { use0gServices } from '0g-wagmi'

function ServicesComponent() {
  const { services, isLoading, error } = use0gServices()

  if (isLoading) return <div>Loading services...</div>
  if (error) return <div>Error loading services</div>
  
  return (
    <div>
      {services?.map((service, index) => (
        <div key={index}>
          <h3>{service.model}</h3>
          <p>Provider: {service.provider}</p>
          <p>Input Price: {service.inputPrice.toString()} per 1M tokens</p>
          <p>Output Price: {service.outputPrice.toString()} per 1M tokens</p>
        </div>
      ))}
    </div>
  )
}

use0gInferenceBalance

Query inference-specific balance for a provider:

import { use0gInferenceBalance } from '0g-wagmi'

function InferenceBalanceComponent({ providerAddress }: { providerAddress: string }) {
  const { balance, isLoading, error, refetch } = use0gInferenceBalance(providerAddress)

  if (isLoading) return <div>Loading balance...</div>
  if (error) return <div>Error loading balance</div>
  
  return (
    <div>
      <p>Allocated Credit: {balance ? (Number(balance) / 1e18).toFixed(6) : '0'} OG</p>
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  )
}

use0gInferenceAddFunds

Add funds to a specific inference provider:

import { use0gInferenceAddFunds } from '0g-wagmi'

function AddInferenceFundsComponent({ providerAddress }: { providerAddress: string }) {
  const { addFunds, isLoading } = use0gInferenceAddFunds()

  const handleAddFunds = async () => {
    try {
      await addFunds(providerAddress, '0.1')
      console.log('Funds added successfully')
    } catch (err) {
      console.error('Failed to add funds:', err)
    }
  }

  return (
    <button onClick={handleAddFunds} disabled={isLoading}>
      {isLoading ? 'Adding...' : 'Add 0.1 OG to Provider'}
    </button>
  )
}

use0gBroker

Get the underlying 0G broker instance:

import { use0gBroker } from '0g-wagmi'

function BrokerComponent() {
  const { broker, isLoading, error } = use0gBroker()

  if (isLoading) return <div>Initializing broker...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!broker) return <div>Connect wallet to continue</div>

  // Use broker directly for advanced operations
  return <div>Broker initialized</div>
}

use0gServiceMetadata

Get detailed metadata for a specific service provider:

import { use0gServiceMetadata } from '0g-wagmi'

function ServiceMetadataComponent({ providerAddress }: { providerAddress: string }) {
  const { metadata, modelName, endpoint, isLoading, error } = use0gServiceMetadata(providerAddress)

  if (isLoading) return <div>Loading service metadata...</div>
  if (error) return <div>Error loading metadata</div>

  return (
    <div>
      <h3>Service Details</h3>
      <p>Model: {modelName}</p>
      <p>Endpoint: {endpoint}</p>
    </div>
  )
}

Storage Hooks

use0gStorageUpload

Upload files to 0G Storage:

import { use0gStorageUpload } from '0g-wagmi'

function UploadComponent() {
  const [file, setFile] = useState<File | null>(null)
  const { upload, isLoading, data, error, isSuccess } = use0gStorageUpload({
    onSuccess: (result) => {
      console.log('File uploaded successfully!')
      console.log('Root Hash:', result.rootHash)
      console.log('Transaction:', result.txHash)
    },
    onError: (err) => {
      console.error('Upload failed:', err)
    },
  })

  const handleUpload = async () => {
    if (!file) return
    try {
      await upload(file)
    } catch (err) {
      console.error('Upload error:', err)
    }
  }

  return (
    <div>
      <input
        type="file"
        onChange={(e) => setFile(e.target.files?.[0] || null)}
      />
      <button onClick={handleUpload} disabled={!file || isLoading}>
        {isLoading ? 'Uploading...' : 'Upload to 0G Storage'}
      </button>

      {isSuccess && data && (
        <div>
          <p>Root Hash: {data.rootHash}</p>
          <p>Transaction: {data.txHash}</p>
        </div>
      )}

      {error && <div>Error: {error.message}</div>}
    </div>
  )
}

use0gStorageDownload

Download files from 0G Storage:

import { use0gStorageDownload } from '0g-wagmi'

function DownloadComponent() {
  const [rootHash, setRootHash] = useState('')
  const { download, downloadAndSave, isLoading, data, error } = use0gStorageDownload({
    onSuccess: (result) => {
      console.log('File downloaded:', result.fileName)
      console.log('Size:', result.fileData.byteLength, 'bytes')
    },
  })

  const handleDownload = async () => {
    if (!rootHash) return
    try {
      // Option 1: Download and get the data
      const result = await download(rootHash, 'my-file.txt')

      // Option 2: Download and automatically save to user's computer
      // await downloadAndSave(rootHash, 'my-file.txt')
    } catch (err) {
      console.error('Download error:', err)
    }
  }

  return (
    <div>
      <input
        type="text"
        placeholder="Enter root hash"
        value={rootHash}
        onChange={(e) => setRootHash(e.target.value)}
      />
      <button onClick={handleDownload} disabled={!rootHash || isLoading}>
        {isLoading ? 'Downloading...' : 'Download from 0G Storage'}
      </button>

      {data && (
        <div>
          <p>File: {data.fileName}</p>
          <p>Size: {(data.fileData.byteLength / 1024).toFixed(2)} KB</p>
        </div>
      )}

      {error && <div>Error: {error.message}</div>}
    </div>
  )
}

use0gStorageFile

Create 0G file objects and compute merkle root hash from browser files:

import { use0gStorageFile } from '0g-wagmi'

function FileInfoComponent() {
  const [file, setFile] = useState<File | null>(null)
  const { file: zgFile, rootHash, error, isLoading } = use0gStorageFile(file)

  return (
    <div>
      <input
        type="file"
        onChange={(e) => setFile(e.target.files?.[0] || null)}
      />

      {isLoading && <div>Computing merkle root...</div>}

      {rootHash && (
        <div>
          <p>File ready for upload</p>
          <p>Root Hash: {rootHash}</p>
        </div>
      )}

      {error && <div>Error: {error.message}</div>}
    </div>
  )
}

Key-Value Storage

use0gKeyValue

Store and retrieve key-value pairs on 0G Network:

import { use0gKeyValue } from '0g-wagmi'

function KeyValueComponent() {
  const streamId = 'your-stream-id'
  const {
    setValue,
    getValue,
    cachedValues,
    isSettingValue,
    setSuccess
  } = use0gKeyValue({
    streamId,
    onSetSuccess: (result) => {
      console.log('Value set successfully!')
      console.log('Transaction:', result.txHash)
    },
  })

  // Set a value
  const handleSet = async () => {
    try {
      await setValue('myKey', 'myValue')
    } catch (err) {
      console.error('Set error:', err)
    }
  }

  // Get a value
  const MyValueDisplay = () => {
    const { data: value, isLoading } = getValue('myKey')

    if (isLoading) return <div>Loading...</div>
    return <div>Value: {value || 'Not set'}</div>
  }

  return (
    <div>
      <button onClick={handleSet} disabled={isSettingValue}>
        {isSettingValue ? 'Setting...' : 'Set Value'}
      </button>

      <MyValueDisplay />

      {/* Access cached values */}
      <div>Cached: {cachedValues['myKey'] || 'Not in cache'}</div>
    </div>
  )
}

Intelligent NFT (iNFT) Hooks

use0gInftMint

Mint intelligent NFTs with encrypted metadata stored on 0G Storage:

import { use0gInftMint, InftMetadata } from '0g-wagmi'

function MintInftComponent() {
  const { mint, isLoading, data, error, isSuccess } = use0gInftMint({
    onSuccess: (result) => {
      console.log('iNFT minted!')
      console.log('Token ID:', result.tokenId)
      console.log('Metadata Hash:', result.metadataHash)
    },
  })

  const handleMint = async () => {
    const metadata: InftMetadata = {
      name: 'My AI Agent',
      description: 'An intelligent agent with unique capabilities',
      aiModel: 'GPT-4',
      image: 'https://example.com/image.png',
      modelWeights: 'ipfs://weights-hash',
      configuration: {
        temperature: 0.7,
        maxTokens: 2048,
      },
      attributes: [
        { trait_type: 'Type', value: 'Conversational' },
        { trait_type: 'Intelligence', value: 95 },
      ],
    }

    try {
      await mint(metadata)
    } catch (err) {
      console.error('Mint error:', err)
    }
  }

  return (
    <div>
      <button onClick={handleMint} disabled={isLoading}>
        {isLoading ? 'Minting...' : 'Mint iNFT'}
      </button>

      {isSuccess && data && (
        <div>
          <p>Token ID: {data.tokenId}</p>
          <p>Metadata Hash: {data.metadataHash}</p>
          <p>Transaction: {data.txHash}</p>
        </div>
      )}

      {error && <div>Error: {error.message}</div>}
    </div>
  )
}

use0gInftList

List all iNFTs owned by the connected wallet:

import { use0gInftList } from '0g-wagmi'

function MyInftsComponent() {
  const { infts, isLoading, refetch } = use0gInftList({
    enabled: true,
  })

  if (isLoading) return <div>Loading iNFTs...</div>

  return (
    <div>
      <h2>My iNFTs ({infts.length})</h2>
      <button onClick={() => refetch()}>Refresh</button>

      {infts.map((inft) => (
        <div key={inft.tokenId}>
          <p>Token ID: {inft.tokenId}</p>
          <p>Metadata Hash: {inft.metadataHash}</p>
          <p>Owner: {inft.owner}</p>
          <p>Minted: {new Date(inft.mintedAt).toLocaleDateString()}</p>
        </div>
      ))}
    </div>
  )
}

use0gInftMetadata

Fetch and decrypt iNFT metadata from 0G Storage:

import { use0gInftMetadata } from '0g-wagmi'

function InftMetadataComponent({ metadataHash }: { metadataHash: string }) {
  const { data: metadata, isLoading, error } = use0gInftMetadata({
    metadataHash,
    enabled: !!metadataHash,
  })

  if (isLoading) return <div>Loading metadata...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!metadata) return null

  return (
    <div>
      <h3>{metadata.name}</h3>
      <p>{metadata.description}</p>

      {metadata.aiModel && <p>AI Model: {metadata.aiModel}</p>}

      {metadata.image && (
        <img src={metadata.image} alt={metadata.name} />
      )}

      {metadata.attributes && (
        <div>
          <h4>Attributes:</h4>
          {metadata.attributes.map((attr, i) => (
            <span key={i}>
              {attr.trait_type}: {attr.value}
            </span>
          ))}
        </div>
      )}
    </div>
  )
}

Utility Hooks

useEthersSigner

Convert wagmi wallet client to ethers.js signer (useful for advanced integrations):

import { useEthersSigner } from '0g-wagmi'
import { ethers } from 'ethers'

function CustomContractComponent() {
  const signer = useEthersSigner()

  const interactWithContract = async () => {
    if (!signer) return

    // Use signer with ethers.js contracts
    const contract = new ethers.Contract(contractAddress, abi, signer)
    const tx = await contract.someFunction()
    await tx.wait()
  }

  return (
    <button onClick={interactWithContract} disabled={!signer}>
      Interact with Contract
    </button>
  )
}

Polyfills

The @0glabs/0g-serving-broker package depends on several Node.js server-side modules that are not available in the browser. To prevent build errors, make sure to exclude these modules from the Vite build process by creating app/empty.js and updating your configuration as shown below. You also need to include a Buffer polyfill.

app/empty.js

const unsupported = (name) => (..._args) => {
  throw new Error(`child_process.${name} is not supported in this environment`);
};

// Functions
export const spawn = unsupported("spawn");
export const exec = unsupported("exec");
export const execFile = unsupported("execFile");
export const fork = unsupported("fork");
export const execSync = unsupported("execSync");
export const spawnSync = unsupported("spawnSync");
export const execFileSync = unsupported("execFileSync");

// Classes / symbols that libraries sometimes reference
export class ChildProcess {}
export const forkOpts = {}; // placeholder sometimes used in examples

// Default export with the same members (helps with `import cp from 'child_process'`)
export default {
  spawn,
  exec,
  execFile,
  fork,
  execSync,
  spawnSync,
  execFileSync,
  ChildProcess,
  forkOpts,
};

vite.config.ts

export default defineConfig({
  ...,
  resolve: {
    alias: {
      child_process: "/src/empty.js",
      "fs/promises": "/src/empty.js",
      fs: "/src/empty.js",
      path: "/src/empty.js",
    },
  },
  define: {
    global: "globalThis",
  },
  optimizeDeps: {
    include: ["buffer"],
  },
});

package.json

Install buffer package

iNFT Smart Contracts

This repository includes complete smart contract infrastructure for Intelligent NFTs (iNFTs). See the dedicated documentation:

iNFT Features

  • 🤖 AI-Powered NFTs - Store AI models, weights, and configurations
  • 🔐 Encrypted Metadata - Secure storage on 0G Network
  • 🎨 ERC-721 Compatible - Works with existing NFT infrastructure
  • 📦 Full Type Safety - TypeScript support throughout
  • 🚀 Production Ready - Audited OpenZeppelin contracts

To deploy the iNFT contract:

cd packages/contracts
pnpm install
cp .env.example .env
# Edit .env with your private key
pnpm deploy

See INFT_QUICKSTART.md for detailed instructions.

Development

  1. Install dependencies:

    pnpm install
  2. Build the SDK and examples:

    pnpm build
  3. Set up environment variables for the example app:

    cp packages/examples/.env.example packages/examples/.env

    Edit packages/examples/.env and add your Reown (WalletConnect) project ID:

    REOWN_PROJECT_ID=your_project_id_here

    Optionally, add your deployed iNFT contract address:

    VITE_INFT_CONTRACT_ADDRESS=0x_your_contract_address

    Get your project ID from Reown Cloud

  4. Run the example app:

    pnpm dev

    The app will be available at http://localhost:5173 (or next available port)

Examples

The examples package demonstrates all available hooks:

  • AI Inference - Chat with AI models on 0G Network
  • Storage - Upload and download files to/from 0G Storage
  • Key-Value - Store and retrieve key-value pairs
  • iNFT - Mint and manage intelligent NFTs
  • Broker Management - Add/withdraw funds, check balances

Navigate through the tabs in the demo app to explore each feature.

Additional Resources

License

MIT