or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account.mdadvanced.mdbatch.mdblockchain.mdcontracts.mdens.mdgas-fees.mdindex.mdsigning.mdtransactions.mdwatch.md

watch.mddocs/

0

# Real-time Data Watching

1

2

Event listeners and watchers for real-time blockchain data updates and contract events. This module provides comprehensive real-time data subscription functionality for monitoring blockchain state changes and contract events.

3

4

## Capabilities

5

6

### useWatchBlockNumber

7

8

Hook to watch for new block numbers in real-time with automatic updates.

9

10

```typescript { .api }

11

/**

12

* Hook to watch for new blocks

13

* @param parameters - Block number watching parameters

14

* @returns Real-time block number updates

15

*/

16

function useWatchBlockNumber<config = Config>(

17

parameters?: UseWatchBlockNumberParameters<config>

18

): UseWatchBlockNumberReturnType;

19

20

interface UseWatchBlockNumberParameters<config = Config> {

21

/** Chain to watch */

22

chainId?: config['chains'][number]['id'];

23

config?: Config | config;

24

/** Whether to watch block numbers */

25

enabled?: boolean;

26

/** Callback when block number changes */

27

onBlockNumber?: (blockNumber: bigint, prevBlockNumber?: bigint) => void;

28

/** Callback on error */

29

onError?: (error: Error) => void;

30

/** Polling interval in milliseconds (default: 4000) */

31

pollingInterval?: number;

32

/** Whether to sync connected chain */

33

syncConnectedChain?: boolean;

34

}

35

36

type UseWatchBlockNumberReturnType = void;

37

```

38

39

**Usage Example:**

40

41

```typescript

42

import { useWatchBlockNumber, useBlockNumber } from "wagmi";

43

import { useState } from "react";

44

45

function BlockNumberWatcher() {

46

const [latestBlock, setLatestBlock] = useState<bigint>();

47

const { data: currentBlock } = useBlockNumber();

48

49

useWatchBlockNumber({

50

onBlockNumber(blockNumber, prevBlockNumber) {

51

console.log('New block:', blockNumber.toString());

52

setLatestBlock(blockNumber);

53

},

54

onError(error) {

55

console.error('Block watch error:', error);

56

},

57

});

58

59

return (

60

<div>

61

<h3>Block Number Watcher</h3>

62

<p>Current Block: {currentBlock?.toString()}</p>

63

<p>Latest Watched Block: {latestBlock?.toString()}</p>

64

</div>

65

);

66

}

67

```

68

69

### useWatchBlocks

70

71

Hook to watch for new blocks with full block data in real-time.

72

73

```typescript { .api }

74

/**

75

* Hook to watch for new blocks

76

* @param parameters - Block watching parameters

77

* @returns Real-time block data updates

78

*/

79

function useWatchBlocks<config = Config>(

80

parameters?: UseWatchBlocksParameters<config>

81

): UseWatchBlocksReturnType;

82

83

interface UseWatchBlocksParameters<config = Config> {

84

/** Chain to watch */

85

chainId?: config['chains'][number]['id'];

86

config?: Config | config;

87

/** Block tag to watch */

88

blockTag?: 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized';

89

/** Whether to watch blocks */

90

enabled?: boolean;

91

/** Whether to emit missed blocks on reconnect */

92

emitMissed?: boolean;

93

/** Whether to emit on begin */

94

emitOnBegin?: boolean;

95

/** Include full transaction data */

96

includeTransactions?: boolean;

97

/** Callback when new block arrives */

98

onBlock?: (block: Block, prevBlock?: Block) => void;

99

/** Callback on error */

100

onError?: (error: Error) => void;

101

/** Polling interval in milliseconds */

102

pollingInterval?: number;

103

/** Whether to sync connected chain */

104

syncConnectedChain?: boolean;

105

}

106

107

type UseWatchBlocksReturnType = void;

108

109

interface Block {

110

/** Block hash */

111

hash: Hash;

112

/** Block number */

113

number: bigint;

114

/** Parent block hash */

115

parentHash: Hash;

116

/** Timestamp */

117

timestamp: bigint;

118

/** Gas limit */

119

gasLimit: bigint;

120

/** Gas used */

121

gasUsed: bigint;

122

/** Miner/validator address */

123

miner: Address;

124

/** Transaction hashes or full transactions */

125

transactions: Hash[] | Transaction[];

126

/** Additional block properties */

127

difficulty?: bigint;

128

totalDifficulty?: bigint;

129

size?: bigint;

130

nonce?: Hex;

131

baseFeePerGas?: bigint;

132

}

133

```

134

135

### useWatchContractEvent

136

137

Hook to watch for specific contract events in real-time.

138

139

```typescript { .api }

140

/**

141

* Hook to watch contract events

142

* @param parameters - Event watching parameters

143

* @returns Event watcher that triggers on new events

144

*/

145

function useWatchContractEvent<config = Config>(

146

parameters: UseWatchContractEventParameters<config>

147

): UseWatchContractEventReturnType;

148

149

interface UseWatchContractEventParameters<config = Config> {

150

/** Contract ABI */

151

abi: Abi;

152

/** Contract address */

153

address?: Address | Address[];

154

/** Event name to watch */

155

eventName?: string;

156

/** Event parameter filters */

157

args?: Record<string, unknown> | readonly unknown[];

158

/** Batch event handling */

159

batch?: boolean;

160

/** Chain to watch */

161

chainId?: config['chains'][number]['id'];

162

config?: Config | config;

163

/** Whether to watch events */

164

enabled?: boolean;

165

/** From block */

166

fromBlock?: bigint;

167

/** Event handler callback */

168

onLogs: (logs: Log[]) => void;

169

/** Error handler callback */

170

onError?: (error: Error) => void;

171

/** Polling interval in milliseconds */

172

pollingInterval?: number;

173

/** Whether to fetch past events on mount */

174

strict?: boolean;

175

/** Whether to sync connected chain */

176

syncConnectedChain?: boolean;

177

}

178

179

type UseWatchContractEventReturnType = void;

180

181

interface Log {

182

/** Event address */

183

address: Address;

184

/** Topics (indexed parameters) */

185

topics: readonly Hash[];

186

/** Event data */

187

data: Hex;

188

/** Block hash */

189

blockHash?: Hash;

190

/** Block number */

191

blockNumber?: bigint;

192

/** Transaction hash */

193

transactionHash?: Hash;

194

/** Transaction index */

195

transactionIndex?: number;

196

/** Log index */

197

logIndex?: number;

198

/** Whether log was removed */

199

removed?: boolean;

200

}

201

```

202

203

**Usage Example:**

204

205

```typescript

206

import { useWatchContractEvent } from "wagmi";

207

import { erc20Abi } from "viem";

208

import { useState } from "react";

209

210

function TokenTransferWatcher() {

211

const [transfers, setTransfers] = useState<Log[]>([]);

212

213

useWatchContractEvent({

214

abi: erc20Abi,

215

address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

216

eventName: 'Transfer',

217

args: {

218

// Watch transfers from specific address

219

from: '0x742d35Cc6634C0532925a3b8D',

220

},

221

onLogs(logs) {

222

console.log('New transfer events:', logs);

223

setTransfers(prev => [...prev, ...logs]);

224

},

225

onError(error) {

226

console.error('Event watch error:', error);

227

},

228

});

229

230

return (

231

<div>

232

<h3>Token Transfer Monitor</h3>

233

<p>Watching {transfers.length} transfers</p>

234

{transfers.slice(-5).map((transfer, i) => (

235

<div key={i}>

236

<p>Block: {transfer.blockNumber?.toString()}</p>

237

<p>Hash: {transfer.transactionHash}</p>

238

</div>

239

))}

240

</div>

241

);

242

}

243

```

244

245

### useWatchPendingTransactions

246

247

Hook to watch for pending transactions in the mempool.

248

249

```typescript { .api }

250

/**

251

* Hook to watch pending transactions

252

* @param parameters - Pending transaction watching parameters

253

* @returns Real-time pending transaction updates

254

*/

255

function useWatchPendingTransactions<config = Config>(

256

parameters?: UseWatchPendingTransactionsParameters<config>

257

): UseWatchPendingTransactionsReturnType;

258

259

interface UseWatchPendingTransactionsParameters<config = Config> {

260

/** Chain to watch */

261

chainId?: config['chains'][number]['id'];

262

config?: Config | config;

263

/** Whether to watch pending transactions */

264

enabled?: boolean;

265

/** Callback when new pending transaction */

266

onTransactions?: (hashes: Hash[]) => void;

267

/** Error handler callback */

268

onError?: (error: Error) => void;

269

/** Polling interval in milliseconds */

270

pollingInterval?: number;

271

/** Whether to sync connected chain */

272

syncConnectedChain?: boolean;

273

}

274

275

type UseWatchPendingTransactionsReturnType = void;

276

```

277

278

### useWatchAsset

279

280

Hook to request adding an asset (token) to the user's wallet.

281

282

```typescript { .api }

283

/**

284

* Hook to request adding asset to wallet

285

* @param parameters - Watch asset configuration with mutation callbacks

286

* @returns Watch asset mutation

287

*/

288

function useWatchAsset<config = Config, context = unknown>(

289

parameters?: UseWatchAssetParameters<config, context>

290

): UseWatchAssetReturnType<config, context>;

291

292

interface UseWatchAssetParameters<config = Config, context = unknown> {

293

config?: Config | config;

294

mutation?: {

295

onMutate?: (variables: WatchAssetVariables) => Promise<context> | context;

296

onError?: (error: WatchAssetErrorType, variables: WatchAssetVariables, context?: context) => Promise<void> | void;

297

onSuccess?: (data: WatchAssetData, variables: WatchAssetVariables, context?: context) => Promise<void> | void;

298

onSettled?: (data?: WatchAssetData, error?: WatchAssetErrorType, variables?: WatchAssetVariables, context?: context) => Promise<void> | void;

299

};

300

}

301

302

interface UseWatchAssetReturnType<config = Config, context = unknown> {

303

/** Request to add asset to wallet */

304

watchAsset: (variables: WatchAssetVariables, options?: WatchAssetMutateOptions) => void;

305

/** Async version of watchAsset */

306

watchAssetAsync: (variables: WatchAssetVariables, options?: WatchAssetMutateAsyncOptions) => Promise<WatchAssetData>;

307

/** Watch asset data */

308

data?: WatchAssetData;

309

/** Watch asset error */

310

error: WatchAssetErrorType | null;

311

/** Watch asset status flags */

312

isError: boolean;

313

isIdle: boolean;

314

isPending: boolean;

315

isSuccess: boolean;

316

/** Reset watch asset state */

317

reset: () => void;

318

/** Current status */

319

status: 'error' | 'idle' | 'pending' | 'success';

320

/** Additional variables */

321

variables?: WatchAssetVariables;

322

}

323

324

interface WatchAssetVariables {

325

/** Asset type (currently only 'ERC20' supported) */

326

type: 'ERC20';

327

/** Token options */

328

options: {

329

/** Token contract address */

330

address: Address;

331

/** Token symbol */

332

symbol?: string;

333

/** Token decimals */

334

decimals?: number;

335

/** Token image URL */

336

image?: string;

337

};

338

}

339

340

type WatchAssetData = boolean; // Whether user accepted the request

341

```

342

343

**Usage Example:**

344

345

```typescript

346

import { useWatchAsset } from "wagmi";

347

348

function AddTokenButton() {

349

const { watchAsset, isPending } = useWatchAsset();

350

351

const handleAddToken = () => {

352

watchAsset({

353

type: 'ERC20',

354

options: {

355

address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

356

symbol: 'DAI',

357

decimals: 18,

358

image: 'https://wallet-asset-matic.s3.amazonaws.com/img/tokens/dai.svg',

359

},

360

});

361

};

362

363

return (

364

<button onClick={handleAddToken} disabled={isPending}>

365

{isPending ? 'Adding...' : 'Add DAI to Wallet'}

366

</button>

367

);

368

}

369

```

370

371

## Advanced Watching Patterns

372

373

### Multi-Contract Event Aggregator

374

375

```typescript

376

import { useWatchContractEvent } from "wagmi";

377

import { erc20Abi } from "viem";

378

import { useState } from "react";

379

380

interface TokenEvent {

381

token: Address;

382

event: string;

383

data: Log;

384

timestamp: number;

385

}

386

387

function MultiTokenWatcher() {

388

const [events, setEvents] = useState<TokenEvent[]>([]);

389

390

const tokens = [

391

'0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

392

'0xA0b86a33E6417C90CC5F6d2c4a29f9D7e5D8ecf0', // USDC

393

'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT

394

];

395

396

// Watch Transfer events for all tokens

397

tokens.forEach(token => {

398

useWatchContractEvent({

399

abi: erc20Abi,

400

address: token,

401

eventName: 'Transfer',

402

onLogs(logs) {

403

const tokenEvents: TokenEvent[] = logs.map(log => ({

404

token: token,

405

event: 'Transfer',

406

data: log,

407

timestamp: Date.now(),

408

}));

409

setEvents(prev => [...prev.slice(-50), ...tokenEvents]);

410

},

411

});

412

});

413

414

return (

415

<div>

416

<h3>Multi-Token Event Monitor</h3>

417

<p>Total events: {events.length}</p>

418

{events.slice(-10).map((event, i) => (

419

<div key={i} style={{ border: '1px solid #ccc', margin: '4px', padding: '8px' }}>

420

<p>Token: {event.token}</p>

421

<p>Event: {event.event}</p>

422

<p>Block: {event.data.blockNumber?.toString()}</p>

423

<p>Time: {new Date(event.timestamp).toLocaleTimeString()}</p>

424

</div>

425

))}

426

</div>

427

);

428

}

429

```

430

431

### Real-time Portfolio Tracker

432

433

```typescript

434

import {

435

useWatchContractEvent,

436

useAccount,

437

useBalance

438

} from "wagmi";

439

import { erc20Abi } from "viem";

440

import { useState, useEffect } from "react";

441

442

function PortfolioTracker() {

443

const { address } = useAccount();

444

const [lastUpdate, setLastUpdate] = useState<Date>();

445

const [transactionCount, setTransactionCount] = useState(0);

446

447

const { data: ethBalance, refetch: refetchEth } = useBalance({

448

address: address!,

449

query: { enabled: !!address }

450

});

451

452

const { data: daiBalance, refetch: refetchDai } = useBalance({

453

address: address!,

454

token: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

455

query: { enabled: !!address }

456

});

457

458

// Watch for transactions affecting this address

459

useWatchContractEvent({

460

abi: erc20Abi,

461

address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

462

eventName: 'Transfer',

463

args: {

464

from: address,

465

},

466

enabled: !!address,

467

onLogs(logs) {

468

console.log('Outgoing DAI transfers:', logs);

469

setTransactionCount(prev => prev + logs.length);

470

setLastUpdate(new Date());

471

refetchDai();

472

},

473

});

474

475

useWatchContractEvent({

476

abi: erc20Abi,

477

address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

478

eventName: 'Transfer',

479

args: {

480

to: address,

481

},

482

enabled: !!address,

483

onLogs(logs) {

484

console.log('Incoming DAI transfers:', logs);

485

setTransactionCount(prev => prev + logs.length);

486

setLastUpdate(new Date());

487

refetchDai();

488

},

489

});

490

491

// Watch for new blocks to refresh ETH balance

492

useWatchBlockNumber({

493

enabled: !!address,

494

onBlockNumber() {

495

refetchEth();

496

},

497

});

498

499

if (!address) return <p>Please connect wallet</p>;

500

501

return (

502

<div>

503

<h3>Real-time Portfolio</h3>

504

<p>ETH Balance: {ethBalance?.formatted} {ethBalance?.symbol}</p>

505

<p>DAI Balance: {daiBalance?.formatted} {daiBalance?.symbol}</p>

506

<p>DAI Transactions Detected: {transactionCount}</p>

507

{lastUpdate && <p>Last Update: {lastUpdate.toLocaleTimeString()}</p>}

508

</div>

509

);

510

}

511

```

512

513

### Event Log Analyzer

514

515

```typescript

516

import { useWatchContractEvent } from "wagmi";

517

import { useState } from "react";

518

import { decodeEventLog } from "viem";

519

520

function EventAnalyzer() {

521

const [eventStats, setEventStats] = useState<Record<string, number>>({});

522

523

useWatchContractEvent({

524

abi: erc20Abi,

525

address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI

526

onLogs(logs) {

527

logs.forEach(log => {

528

try {

529

const decoded = decodeEventLog({

530

abi: erc20Abi,

531

data: log.data,

532

topics: log.topics,

533

});

534

535

setEventStats(prev => ({

536

...prev,

537

[decoded.eventName]: (prev[decoded.eventName] || 0) + 1,

538

}));

539

} catch (error) {

540

console.error('Failed to decode event:', error);

541

}

542

});

543

},

544

});

545

546

return (

547

<div>

548

<h3>Event Statistics</h3>

549

{Object.entries(eventStats).map(([event, count]) => (

550

<p key={event}>{event}: {count}</p>

551

))}

552

</div>

553

);

554

}

555

```

556

557

## Common Types

558

559

```typescript { .api }

560

type Hash = `0x${string}`;

561

type Hex = `0x${string}`;

562

type Address = `0x${string}`;

563

564

interface Transaction {

565

hash: Hash;

566

blockHash?: Hash;

567

blockNumber?: bigint;

568

transactionIndex?: number;

569

from: Address;

570

to?: Address;

571

value: bigint;

572

gas: bigint;

573

gasPrice?: bigint;

574

maxFeePerGas?: bigint;

575

maxPriorityFeePerGas?: bigint;

576

input: Hex;

577

nonce: number;

578

type?: 'legacy' | 'eip2930' | 'eip1559';

579

}

580

581

interface Abi {

582

readonly [key: number]: AbiItem;

583

}

584

585

interface AbiItem {

586

type: 'function' | 'event' | 'error' | 'constructor' | 'fallback' | 'receive';

587

name?: string;

588

inputs?: AbiParameter[];

589

outputs?: AbiParameter[];

590

stateMutability?: 'pure' | 'view' | 'nonpayable' | 'payable';

591

anonymous?: boolean;

592

}

593

594

interface AbiParameter {

595

name: string;

596

type: string;

597

components?: AbiParameter[];

598

indexed?: boolean;

599

}

600

601

interface WatchAssetMutateOptions {

602

onError?: (error: Error, variables: WatchAssetVariables, context?: unknown) => void;

603

onSuccess?: (data: boolean, variables: WatchAssetVariables, context?: unknown) => void;

604

onSettled?: (data?: boolean, error?: Error, variables?: WatchAssetVariables, context?: unknown) => void;

605

}

606

607

type WatchAssetErrorType = Error;

608

```