Shreds
Realtime transaction confirmations in 3ms
Shreds
Shreds are RISE's breakthrough innovation for realtime blockchain transactions. Rather than processing transactions in large batches (blocks), RISE processes them individually and immediately, providing confirmations in as little as 3 milliseconds.
Overview
Traditional blockchains batch transactions into blocks, forcing users to wait seconds or minutes for confirmation. Shreds solve this by propagating incremental state updates across the network in realtime. Each shred is a lightweight, cryptographically signed packet containing state changes from one or more transactions, enabling instant confirmations while maintaining full EVM compatibility and security guarantees.
Interactive Demo
Try incrementing the counter below. Each transaction confirms in milliseconds and events arrive in realtime via WebSocket.
sendTransactionSync() directly - it's easier but makes multiple RPC calls. Viem will soon integrate this optimization natively. See the commented code at the bottom for the simpler approach."use client";import { createPublicClient, createWalletClient, http, webSocket, encodeFunctionData, parseGwei } from "viem";import { privateKeyToAccount } from "viem/accounts";import { riseTestnet } from "viem/chains";import { shredActions } from "shreds/viem";import { NonceManager } from "@/lib/NonceManager";import { useEffect, useState, useMemo, useRef } from "react";const COUNTER_ADDRESS = "0x48249F3688F37f5122231A5b67bc49E063CF0784";const COUNTER_ABI = [ { type: "function", name: "count", outputs: [{ type: "uint256" }], stateMutability: "view" }, { type: "function", name: "increment", outputs: [], stateMutability: "nonpayable" }, { type: "event", name: "CounterIncremented", inputs: [ { name: "newCount", type: "uint256" }, { name: "incrementer", type: "address" } ]}] as const;export function ShredsDemo() { const [count, setCount] = useState<number>(0); const [confirmTime, setConfirmTime] = useState<number | null>(null); const [isIncrementing, setIsIncrementing] = useState(false); const [events, setEvents] = useState<Array<{ count: number; time: string }>>([]); // Setup wallet with Anvil test account #1 // ⚠️ WARNING: NEVER use NEXT_PUBLIC_ for real private keys! // This is only acceptable for publicly known test keys like Anvil's defaults. const account = useMemo( () => privateKeyToAccount(process.env.NEXT_PUBLIC_DEMO_PRIVATE_KEY), [] ); const client = useMemo( () => createWalletClient({ account, chain: riseTestnet, transport: http("https://testnet.riselabs.xyz") }).extend(shredActions), [account] ); const publicClient = useMemo( () => createPublicClient({ chain: riseTestnet, transport: http("https://testnet.riselabs.xyz") }), [] ); // Initialize nonce manager for local nonce tracking const nonceManagerRef = useRef<NonceManager | null>(null); useEffect(() => { if (!nonceManagerRef.current) { nonceManagerRef.current = new NonceManager(publicClient, account.address); nonceManagerRef.current.initialize(); } }, [publicClient, account.address]); // Pre-encode function data to exclude encoding time from performance measurement const incrementData = useMemo( () => encodeFunctionData({ abi: COUNTER_ABI, functionName: "increment" }), [] ); // Read initial count useEffect(() => { const fetchCount = async () => { const value = await publicClient.readContract({ address: COUNTER_ADDRESS, abi: COUNTER_ABI, functionName: "count" }); setCount(Number(value)); }; fetchCount(); }, [publicClient]); // Watch for events in realtime via WebSocket useEffect(() => { const wsClient = createPublicClient({ chain: riseTestnet, transport: webSocket("wss://testnet.riselabs.xyz/ws") }); const unwatch = wsClient.watchContractEvent({ address: COUNTER_ADDRESS, abi: COUNTER_ABI, eventName: "CounterIncremented", onLogs: (logs) => { const log = logs[logs.length - 1]; const newCount = Number(log.args.newCount); setCount(newCount); setEvents(prev => [ { count: newCount, time: new Date().toLocaleTimeString() }, ...prev.slice(0, 4) ]); } }); return () => unwatch(); }, []); const handleIncrement = async () => { if (!nonceManagerRef.current) return; setIsIncrementing(true); const startTime = performance.now(); try { // Get nonce from local manager (no RPC call) const nonce = await nonceManagerRef.current.getNonce(); // Hardcoded gas values (no estimation RPC call) const gas = 300000n; const gasPrice = parseGwei('0.001'); const chainId = riseTestnet.id; // Build and sign transaction locally const transaction = { to: COUNTER_ADDRESS, data: incrementData, gas, gasPrice, nonce, chainId, type: 'legacy' as const }; const signature = await account.signTransaction(transaction); // Send using sync method (only RPC call) await client.sendRawTransactionSync({ serializedTransaction: signature }); const elapsed = performance.now() - startTime; setConfirmTime(elapsed); await nonceManagerRef.current.onTransactionComplete(true); } catch (error) { console.error(error); if (nonceManagerRef.current) { await nonceManagerRef.current.onTransactionComplete(false); } } finally { setIsIncrementing(false); } }; // SIMPLER ALTERNATIVE: Use sendTransactionSync directly // This is easier but makes multiple RPC calls (chainId, nonce, gas estimation). // Viem will soon integrate this pattern natively. /* const handleIncrement = async () => { setIsIncrementing(true); const startTime = performance.now(); try { await client.sendTransactionSync({ to: COUNTER_ADDRESS, data: incrementData }); setConfirmTime(performance.now() - startTime); } catch (error) { console.error(error); } finally { setIsIncrementing(false); } }; */ return ( <div className="space-y-4"> <div className="text-6xl font-bold text-center py-8"> {count} </div> {confirmTime && ( <div className="text-center text-sm text-green-500"> ✓ Total Round Trip Time: {confirmTime.toFixed(2)}ms </div> )} <Button onClick={handleIncrement} disabled={isIncrementing}> {isIncrementing ? "Incrementing..." : "Increment Counter"} </Button> {events.length > 0 && ( <div className="text-xs space-y-1"> <p className="font-semibold">Recent Events (WebSocket):</p> {events.map((e, i) => ( <div key={i}>Count: {e.count} at {e.time}</div> ))} </div> )} </div> );}Why Shreds?
- 3ms confirmation times: Transactions confirm faster than a blink of an eye
- Full EVM compatibility: Works with existing Ethereum tools and libraries
- Real-time updates: Subscribe to state changes as they happen
- Maintained security: Cryptographically signed, deterministic state transitions