web3-transaction-manager-react
v1.0.0
Published
React library for managing multi-step Web3 transactions (on-chain, HTTP, message signing) with themeable UI
Readme
web3-transaction-manager-react
React library for managing multi-step Web3 transaction flows: on-chain transactions, HTTP requests, and message signing (personal and EIP-712), with a themeable modal UI.
Installation
npm install web3-transaction-manager-reactPeer dependencies
- react ^18.0.0
- react-dom ^18.0.0
- ethers ^5.7.2 or ^6.0.0
Both ethers v5 and v6 are supported. Pass any SignerLike (ethers v5 or v6 Signer) to setSigner, TransactionModal, or useTransactionManager. Receipt and chain ID values are normalized internally (e.g. v6 bigint to number where needed).
Quick start
Define a transaction flow, hold status in state, and pass onTxExecute to run each step (e.g. via Web3Service).
import { useState, useCallback, useMemo } from "react";
import {
TransactionModal,
Web3Service,
type Transaction,
type TransactionState,
} from "web3-transaction-manager-react";
const transactions: Transaction[] = [
{
id: "approve",
type: "approval",
params: { to: "0x...", data: "0x..." },
metadata: { title: "Approve USDC", buttonLabel: "Approve" },
},
{
id: "borrow",
type: "contract",
params: { to: "0x...", data: "0x..." },
metadata: { title: "Borrow", buttonLabel: "Borrow" },
},
];
function App() {
const [isOpen, setIsOpen] = useState(false);
const [statuses, setStatuses] = useState<Record<string, TransactionState>>({});
const signer = useWalletSigner(); // your hook
const address = useWalletAddress();
const web3 = useMemo(() => {
const w = new Web3Service();
if (signer) w.setSigner(signer);
return w;
}, [signer]);
const handleTxExecute = useCallback(
async ({ transactionId }: { transactionId: string }) => {
const tx = transactions.find((t) => t.id === transactionId);
if (!tx || !signer) return;
setStatuses((s) => ({ ...s, [transactionId]: { status: "processing" } }));
try {
if (tx.type === "fetch") {
const result = await web3.executeFetchRequest(tx);
setStatuses((s) => ({ ...s, [transactionId]: { status: "success", fetchResult: result } }));
} else {
const res = await web3.sendTransaction(tx);
const state = await web3.waitForTransaction(res.hash);
setStatuses((s) => ({ ...s, [transactionId]: state }));
}
} catch (err) {
setStatuses((s) => ({
...s,
[transactionId]: { status: "failed", error: String(err) },
}));
}
},
[web3, signer]
);
return (
<>
<button onClick={() => setIsOpen(true)}>Start flow</button>
<TransactionModal
isOpen={isOpen}
transactions={transactions}
transactionStatuses={statuses}
signer={signer}
address={address}
blockExplorerUrl="https://etherscan.io/tx/"
onClose={() => setIsOpen(false)}
onTxExecute={handleTxExecute}
/>
</>
);
}Supported transaction types
- approval / contract / standard – on-chain (via
Web3Service.sendTransactionandwaitForTransaction) - fetch – HTTP request (via
Web3Service.executeFetchRequest) - signature – personal sign or EIP-712 typed data (via
Web3Service.signMessage/signTypedData)
Exports
- Components:
TransactionModal,ProgressTracker,TransactionCard,SummarySection - Services:
Web3Service,TransactionManager - Hooks:
useTransactionManager,useTransactionState,useTransactionStateOptional - Context:
TransactionProvider - Theme:
defaultTheme,resolveTheme - Types:
Transaction,TransactionState,SignerLike,TransactionManagerConfig,ThemeConfig, and related types
Framework and tooling
- React 18+ (compatible with React 19).
- Next.js App Router: Use
'use client'in any component that rendersTransactionModalor usesuseTransactionManager/ a signer. Do not import wallet or signer in server components. - SSR: Components and services that use
windowor a signer should only run on the client; gate withtypeof window !== 'undefined'or dynamic import if needed.
Theming
Use theme="light" or theme="dark" and optionally customTheme to override colors and typography. All styles are scoped under .web3-tx-modal and applied via CSS variables.
Demo
A minimal demo app lives in examples/demo. It runs a two-step fetch flow (JSONPlaceholder) with no wallet required. From the repo root:
npm run demoThis builds the library, installs the demo’s dependencies, and starts the Vite dev server (default port 5174).
Publishing
Before publishing, the package runs prepublishOnly (typecheck, test, build). See docs/publishing.md for version bump and npm publish steps. Only the dist directory is included in the published package.
License
MIT
