useMintBurn Hook
The useMintBurn hook is the write-side transaction orchestrator for the Colored Key NFT. It wraps wagmi write/receipt hooks, network validation, WalletConnect deeplinking, and notification dispatch into a single cohesive API, so UI components can focus on what to show rather than how to talk to the blockchain.
-
Source:
dapp/app/hooks/useMintBurn.ts -
Primary consumers: components like
ButtonSection -
Companion docs:
At a high level, useMintBurn:
- Validates network before any write.
- Sends mint and burn transactions.
- Tracks confirmation status via
useWaitForTransactionReceipt. - Deduplicates success handling per transaction hash.
- Dispatches success and error notifications.
- Integrates with WalletConnect to open the wallet on mobile.
Hook API
export interface UseMintBurnOptions {
onMintSuccess?: () => Promise<void> | void
onBurnSuccess?: () => Promise<void> | void
onMintError?: (error: Error) => void
onBurnError?: (error: Error) => void
autoRefresh?: boolean
notificationDelay?: number
}
export interface UseMintBurnReturn {
// Actions
mint: () => void
burn: (tokenId: string | number | null) => void
// Aggregate state
isProcessing: boolean
// Fine-grained state
isMinting: boolean
isBurning: boolean
isMintConfirming: boolean
isBurnConfirming: boolean
// Transaction hashes
mintHash: `0x${string}` | undefined
burnHash: `0x${string}` | undefined
// Success flags
isMintSuccess: boolean
isBurnSuccess: boolean
// Error objects
mintError: Error | null
burnError: Error | null
// Reset helpers
resetMint: () => void
resetBurn: () => void
resetAll: () => void
}
export function useMintBurn(options?: UseMintBurnOptions): UseMintBurnReturnNote
autoRefreshexists in the options interface as a future extension point. In the current implementation, refresh behavior is driven by caller-provided callbacks (onMintSuccess,onBurnSuccess), not automatic polling inside the hook.
Options (UseMintBurnOptions)
Configuration knobs for the hook:
| Option | Type | Purpose |
|---|---|---|
onMintSuccess | () => void | Promise<void> | Called after a successful mint transaction, once the hook has seen a confirmed receipt and waited for a brief propagation delay. |
onBurnSuccess | () => void | Promise<void> | Same as |
onMintError | (error: Error) => void | Optional callback invoked after mint errors are formatted and surfaced via notifications. |
onBurnError | (error: Error) => void | Optional callback invoked after burn errors are formatted and surfaced via notifications. |
notificationDelay | number | Delay (ms) before firing success notification events like |
autoRefresh | boolean | undefined | Reserved for future use. At present, the hook expects callers to refresh external
state (e.g. via |
In practice, most UI components only pass onMintSuccess, onBurnSuccess, and occasionally notificationDelay.
Return Shape (UseMintBurnReturn)
Actions
-
mint()- Wraps a write to the Colored Key NFT contract using
createMintAction()anduseWriteContract. - Guarded by
useNetworkCheck().executeWithNetworkCheckto prevent wrong-chain transactions. - If
displayUriis present in the WalletConnect store, callsopenWallet()to bring up the mobile wallet after sending the write.
- Wraps a write to the Colored Key NFT contract using
-
burn(tokenId)-
Validates
tokenIdbefore attempting a burn.- If
tokenIdisnull,undefined, or an empty string, the hook sends a user-friendly error notification ("No token ID available for burning") and does not attempt a write.
- If
-
Otherwise, wraps a burn write using
createBurnAction(tokenId)anduseWriteContractunderexecuteWithNetworkCheck. -
Triggers WalletConnect deeplink in the same way as
mint()whendisplayUriis present.
-
Transaction State Flags
-
isMinting/isBurning- Mirror the
isPendingflags from the underlyinguseWriteContractcalls.
- Mirror the
-
isMintConfirming/isBurnConfirming- Come from
useWaitForTransactionReceipt({ hash }), and indicate that a transaction has been sent and is waiting for confirmation.
- Come from
-
isProcessing-
Aggregate flag computed as:
isMinting || isBurning || isMintConfirming || isBurnConfirming
-
Recommended flag for showing global “Processing…” states in the UI.
-
Hashes and Success Flags
-
mintHash/burnHash- Populated as soon as the corresponding
writeContractcalls succeed locally. - Used by UIs (for example
ProcessingModal) to render explorer links for pending transactions.
- Populated as soon as the corresponding
-
isMintSuccess/isBurnSuccess- Become
truewhenuseWaitForTransactionReceiptreports success for the associated hash.
- Become
Errors and Reset Helpers
-
mintError/burnError- Exposed raw error objects. Internally, the hook passes them to
formatMintError/formatBurnError, which handle user-facing messaging and notification dispatch.
- Exposed raw error objects. Internally, the hook passes them to
-
resetMint()/resetBurn()- Clear wagmi’s internal state for the respective write hooks via stable refs (
resetMintRef,resetBurnRef).
- Clear wagmi’s internal state for the respective write hooks via stable refs (
-
resetAll()- Calls both resets and clears internal hash-tracking refs (
lastMintHashRef,lastBurnHashRef). - Useful when a UI wants to “hard reset” the transaction state, e.g. when closing a modal.
- Calls both resets and clears internal hash-tracking refs (
Core Responsibilities & Internal Design
Internally, useMintBurn coordinates several concerns: contract writes, confirmation tracking, network checks, WalletConnect, notifications, and success deduplication.
1. Contract Writes & Receipts
The hook maintains two write flows and two receipt trackers:
-
Mint write + receipt:
useWriteContract()for mint actions.useWaitForTransactionReceipt({ hash: mintHash })for confirmations.
-
Burn write + receipt:
useWriteContract()for burn actions.useWaitForTransactionReceipt({ hash: burnHash })for confirmations.
isProcessing is derived from the union of these four flags and is the recommended signal for disabling UI buttons and showing processing labels.
2. Network Validation
Writes are guarded by the shared network check hook:
useNetworkCheck()returnsexecuteWithNetworkCheck(fn).- Both
mint()andburn()pass their write closures into this helper. - On the wrong network, the helper prevents the write and surfaces a notification;
useMintBurndoes not attempt to write until the network is corrected.
See docs/content/dapp/smart-contract-data/contract-config.mdx for how chains and addresses are configured.
3. WalletConnect Deeplinking
To support mobile flows, the hook integrates with the WalletConnect store:
-
Reads:
displayUri– WalletConnect URI when active.openWallet()– function to deep link into the wallet app.
-
Behavior:
- After a write is initiated, if
displayUriis truthy, the hook callsopenWallet()so users can approve the transaction in their wallet.
- After a write is initiated, if
If displayUri is null, the hook gracefully skips deeplinking, which supports non-WalletConnect flows.
4. Notifications & Error Formatting
Success and error messaging is centralized via a small client-side facade plus helpers:
-
Success notifications
sendNotificationEvent('NFT_MINTED', { source: 'user' })sendNotificationEvent('NFT_BURNED', { source: 'user' })
-
Error formatting and notifications
formatMintError(error)andformatBurnError(error)map low-level wagmi/viem errors into user-friendly messages.- These helpers also send notifications through
sendErrorNotification(...).
This design means UI components (like ButtonSection) do not emit their own success/error toasts for mint/burn; they rely on the shared notifications layer instead, avoiding duplicates.
5. Success Lifecycles & Deduplication
To avoid double handling on rerenders, the hook tracks the last-seen hash for each flow:
lastMintHashRef: Ref<string | null>lastBurnHashRef: Ref<string | null>
When a transaction succeeds, the hook checks whether the hash has already been processed:
Step 1: Transaction hash appears
A write sets mintHash or burnHash when it is accepted by the client.
Step 2: Receipt confirms
useWaitForTransactionReceipt flips isMintSuccess or isBurnSuccess to true.
Step 3: Dedup check
The hook verifies that the hash is non-null and different from the last processed hash in lastMintHashRef or lastBurnHashRef.
Step 4: Notifications & callback
It logs the transaction (console.log(‘Mint transaction:’, mintHash) or ‘Burn transaction:’), schedules a success notification after notificationDelay, and schedules the appropriate success callback.
Step 5: Reset
After the callback, the hook resets wagmi state for that flow, leaving the hash ref populated so the same hash isn’t processed again on rerender.
This dedup behavior is explicitly tested in useMintBurn.test.tsx to ensure that a confirmed transaction only triggers a single success event + callback per hash.
6. Reset Helpers & Stable Refs
The hook stores several values in refs to avoid identity issues:
resetMintRef,resetBurnRefwrap wagmi’sresetfunctions.onMintSuccessRef,onBurnSuccessRefwrap the callbacks passed in options.
This allows the hook to use these callbacks safely inside effects and timers without invalidating dependencies or re-registering timers on every render.
Usage Patterns
Basic Integration
A minimal component that uses useMintBurn directly:
import { useState } from 'react'
import { useMintBurn } from '@/app/hooks/useMintBurn'
function SimpleMintButton() {
const [isLoading, setLoading] = useState(false)
const { mint, isProcessing } = useMintBurn({
onMintSuccess: () => {
setLoading(false)
// e.g., trigger a visual celebration here
},
})
const handleClick = () => {
setLoading(true)
mint()
}
const label = isProcessing ? 'Processing…' : 'Mint NFT'
return (
<button onClick={handleClick} disabled={isProcessing} aria-busy={isProcessing}>
{label}
</button>
)
}Working with the Smart Contract Data Layer
In the actual app, useMintBurn is almost always paired with the smart-contract data system:
useNFTDatahandles reads and state sync into the NFT store.useMintBurnhandles writes and transaction lifecycles.
A common pattern is:
MintPageWrappercallsuseNFTData()and passesforceRefreshdown asonRefresh.ButtonSectioncallsuseMintBurn({ onMintSuccess, onBurnSuccess }).onMintSuccess/onBurnSuccesscallonRefresh()and clear loading flags in the NFT store.
function MintPageWrapper() {
const { forceRefresh } = useNFTData()
return (
<>
{/* ...status + visualization components... */}
<ButtonSection onRefresh={forceRefresh} />
</>
)
}
// Inside ButtonSection
const handleMintSuccess = async () => {
setBlockProcessingText(true)
await onRefresh?.()
setLoading(false)
}
const handleBurnSuccess = async () => {
setBlockProcessingText(true)
await onRefresh?.()
setLoading(false)
}
const { mint, burn, isProcessing, mintHash, burnHash, resetAll } = useMintBurn({
onMintSuccess: handleMintSuccess,
onBurnSuccess: handleBurnSuccess,
})This separation keeps useMintBurn narrowly focused on transactions while the data layer remains responsible for reading and caching on-chain state.
ButtonSection Integration
ButtonSection is the canonical consumer of useMintBurn. It layers UX concerns on top of the hook:
- State-based UI (
not-connected,no-nft,has-nft,used-gate). - Hydration safety and account switching UX.
- Accessibility roles and
aria-*attributes. - Integration with
ProcessingModal. - Responsive layout and animated transitions.
useMintBurn provides the transaction brain; ButtonSection wires it into the interface:
-
Uses
isProcessingplus store flags to compute abusystate, which drives button labels ("Mint NFT"vs"Processing…"),disabledstate, andaria-busyattributes. -
Chooses the correct hash to pass into
ProcessingModal:- In the latest implementation, ButtonSection passes
mintHashorburnHashbased on which action is active. Earlier docs show amintHash || burnHashpattern; see the ButtonSection docs for current JSX.
- In the latest implementation, ButtonSection passes
-
Invokes
resetAll()and refresh callbacks from the modal’s cancel button to reset transaction state and avoid stuck UIs.
ButtonSection owns what the user sees (buttons, labels, transitions, modal), while useMintBurn owns what the blockchain does (writes, confirmations, notifications, deeplinking). This separation makes it safe to reuse the hook in alternate UIs without duplicating transaction logic.
Testing
useMintBurn has a dedicated unit test suite that validates its behavior in isolation from the UI:
Key behaviors covered in useMintBurn.test.tsx:
-
Mint flow
-
mint()executes underexecuteWithNetworkCheck. -
Writes the expected mint action (
{ kind: 'MINT_ACTION' }). -
Calls
openWallet()whendisplayUriis present (WalletConnect path). -
On confirmed success, the hook:
- Logs the transaction (
"Mint transaction:", hash). - Dispatches
sendNotificationEvent('NFT_MINTED', { source: 'user' }). - Invokes the
onMintSuccesscallback once. - Calls the mint
resetfunction.
- Logs the transaction (
-
Success handling is deduplicated per hash; rerenders with the same hash do not re-fire logs or notifications.
-
-
Burn flow
-
burn(null)(or an empty token ID) sends an error notification ("No token ID available for burning") and does not callexecuteWithNetworkCheckorwriteContract. -
For a valid token ID, on confirmed success, the hook:
- Logs the burn transaction.
- Dispatches
sendNotificationEvent('NFT_BURNED', { source: 'user' }). - Invokes
onBurnSuccessonce. - Calls the burn
resetfunction.
-
-
Error handling
-
When
mintErrororburnErrorare injected into the mocked wagmi hooks, the test asserts that:formatMintError/formatBurnErrorare called.sendErrorNotificationis called with the formatted message (e.g."Mint failed: boom mint").onMintError/onBurnErrorcallbacks are invoked.- The corresponding
resetfunctions are called exactly once.
-
-
WalletConnect behavior
- With
displayUri = null, the hook calls neitheropenWallet()for mint nor burn, confirming non-WalletConnect flows are respected.
- With
These tests are built with @testing-library/react’s renderHook, plus explicit mocks for:
useWriteContractanduseWaitForTransactionReceiptfromwagmi.useNetworkCheckfor guarded writes.useWalletConnectStoreforopenWalletanddisplayUri.- The notifications facade and client helpers in
@lib/client/mint.client.
Together, they verify that useMintBurn implements the contract promised by this documentation.
Related Documentation
Adaptive action interface that consumes useMintBurn for mint, burn, and token gate navigation.
Read-side data orchestration for NFT ownership, colors, and token usage, paired with useMintBurn for a full read/write pipeline.
Zustand store for NFT UI state, including loading flags and account switching used by both useNFTData and ButtonSection.
High-level overview of the smart contract data system that useMintBurn plugs into.
Centralized notification facade used by useMintBurn for success and error messaging.
Architecture for mobile wallet deeplinking that useMintBurn taps into via the wallet connect store.
Summary
useMintBurn is the transaction brain for the Colored Key mint/burn flow:
- It encapsulates network validation, wagmi writes, transaction receipts, notifications, and WalletConnect deeplinking.
- It exposes a small, stable API (
mint,burn,isProcessing, hashes, reset helpers) that can be consumed by any UI. - It pairs with
useNFTDataand the NFT store to form a complete read/write pipeline for on-chain NFT state.
By centralizing transaction logic in this hook, RitoSwap keeps components like ButtonSection focused on UX, while ensuring consistent, well-tested behavior across all transaction entry points.