Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/how-arbitrum-works/01-inside-arbitrum-nitro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ user_story: "As a developer, I need to understand how transactions flow through
content_type: concept
---

import DrawioReactFlow from '@site/src/components/DrawioReactFlow';

## Transaction processing journey on Arbitrum

As a developer initiating a <a data-quicklook-from="transaction">transaction</a> on <a data-quicklook-from="arbitrum">Arbitrum</a>, gaining a clear understanding of the end-to-end flow—from initial submission through to finality—is helpful, but it isn't required.

This overview methodically traces the transaction lifecycle, emphasizing how Arbitrum’s architecture ensures precise, efficient, and secure handling at every stage. This article covers the complete <a data-quicklook-from="arbitrum-nitro">Arbitrum Nitro</a> stack, beginning with the <a data-quicklook-from="sequencer">Sequencer</a>, which is responsible for transaction ordering, advancing to the <a data-quicklook-from="state-transition-function">State Transition Function</a> (STF) for execution, and culminating in validation mechanisms that uphold integrity.

<ImageZoom src="/img/haw-transaction-lifecycle.png" className="img-600px" alt="Transaction lifecycle">
Transaction lifecycle
</ImageZoom>
<DrawioReactFlow manifest="/diagrams/haw-transaction-lifecycle.manifest.xml" height="640px" />

Along the way, you'll learn about Arbitrum's ability to deliver security on par with Ethereum, while achieving fee reductions by a factor of ten and transaction speeds accelerated by a factor of 100 using optimized mechanisms.

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,17 @@
"dotenv": "^17.4.2",
"ethers": "6.17.0",
"got": "15.1.0",
"marked": "^18.0.10",
"mermaid": "^11.16.1",
"marked": "^18.0.6",
"mermaid": "^11.16.0",
"motion": "^12.23.24",
"posthog-docusaurus": "^2.0.5",
"posthog-js": "^1.418.1",
"prism-react-renderer": "^2.4.1",
"prismjs": "^1.30.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-syntax-highlighter": "^16.1.1",
"reactflow": "^11.11.4",
"rehype-katex": "7",
"remark-math": "6",
"sass": "^1.102.0",
Expand Down
161 changes: 161 additions & 0 deletions src/components/DrawioReactFlow/ClickableNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React from 'react';
import { NodeProps, Handle, Position } from 'reactflow';
import { NodeData } from './types';
import { DiagramHoverModal } from './DiagramHoverModal';

export function ClickableNode({ data }: NodeProps<NodeData>) {
const { label, shape, link, centerable, colorToken, onNavigate, hoverContentComponent } = data;
const isClickable = !!link || !!centerable;

const handleClick = () => {
if (link && onNavigate) {
onNavigate(link);
}
};

const handleKeyDown = (e: React.KeyboardEvent) => {
if (isClickable && (e.key === 'Enter' || e.key === ' ')) {
e.preventDefault();
if (link && onNavigate) {
onNavigate(link);
}
}
};

// Resolve text alignment — explicit NodeData hints win, then the legacy `topAligned`
// shortcut from drawio, then default (centered)
const alignItems: React.CSSProperties['alignItems'] =
data.verticalAlign === 'top' || data.topAligned
? 'flex-start'
: data.verticalAlign === 'bottom'
? 'flex-end'
: 'center';
const justifyContent: React.CSSProperties['justifyContent'] =
data.textAlign === 'left' ? 'flex-start' : data.textAlign === 'right' ? 'flex-end' : 'center';
const paddingTop = alignItems === 'flex-start' ? '4px' : undefined;
const paddingBottom = alignItems === 'flex-end' ? '4px' : undefined;
const paddingLeft = justifyContent === 'flex-start' ? '6px' : undefined;
const paddingRight = justifyContent === 'flex-end' ? '6px' : undefined;

const baseStyle: React.CSSProperties = {
cursor: isClickable ? 'pointer' : 'default',
alignItems,
justifyContent,
...(paddingTop ? { paddingTop } : {}),
...(paddingBottom ? { paddingBottom } : {}),
...(paddingLeft ? { paddingLeft } : {}),
...(paddingRight ? { paddingRight } : {}),
};

// Apply shape-specific transforms
let shapeStyle: React.CSSProperties = {};
if (shape === 'diamond') {
shapeStyle = {
transform: 'rotate(45deg)',
};
}

const contentStyle: React.CSSProperties =
shape === 'diamond' ? { transform: 'rotate(-45deg)' } : {};

const labelContent = hoverContentComponent ? (
<DiagramHoverModal ContentComponent={hoverContentComponent}>{label}</DiagramHoverModal>
) : (
label
);

return (
<div
className={`custom-node ${isClickable ? 'node-clickable' : 'node-static'} shape-${shape}${
colorToken ? ` color-${colorToken}` : ''
}`}
style={{ ...baseStyle, ...shapeStyle }}
onClick={handleClick}
onKeyDown={handleKeyDown}
role={isClickable ? 'button' : undefined}
tabIndex={isClickable ? 0 : -1}
aria-label={isClickable ? `Navigate to ${link || label}` : label}
>
{/* Connection handles — 4 sides, 3 positions per side (20/50/80%), plus legacy
midpoint-only ids (e.g. "top-source") for the draw.io converter that doesn't
emit along-side offsets. */}
{/* Top — legacy midpoint */}
<Handle id="top-target" type="target" position={Position.Top} />
<Handle id="top-source" type="source" position={Position.Top} />
{/* Top — 20/50/80 */}
<Handle id="top-20-target" type="target" position={Position.Top} style={{ left: '20%' }} />
<Handle id="top-20-source" type="source" position={Position.Top} style={{ left: '20%' }} />
<Handle id="top-50-target" type="target" position={Position.Top} style={{ left: '50%' }} />
<Handle id="top-50-source" type="source" position={Position.Top} style={{ left: '50%' }} />
<Handle id="top-80-target" type="target" position={Position.Top} style={{ left: '80%' }} />
<Handle id="top-80-source" type="source" position={Position.Top} style={{ left: '80%' }} />

{/* Right — legacy midpoint */}
<Handle id="right-target" type="target" position={Position.Right} />
<Handle id="right-source" type="source" position={Position.Right} />
{/* Right — 20/50/80 */}
<Handle id="right-20-target" type="target" position={Position.Right} style={{ top: '20%' }} />
<Handle id="right-20-source" type="source" position={Position.Right} style={{ top: '20%' }} />
<Handle id="right-50-target" type="target" position={Position.Right} style={{ top: '50%' }} />
<Handle id="right-50-source" type="source" position={Position.Right} style={{ top: '50%' }} />
<Handle id="right-80-target" type="target" position={Position.Right} style={{ top: '80%' }} />
<Handle id="right-80-source" type="source" position={Position.Right} style={{ top: '80%' }} />

{/* Bottom — legacy midpoint */}
<Handle id="bottom-target" type="target" position={Position.Bottom} />
<Handle id="bottom-source" type="source" position={Position.Bottom} />
{/* Bottom — 20/50/80 */}
<Handle
id="bottom-20-target"
type="target"
position={Position.Bottom}
style={{ left: '20%' }}
/>
<Handle
id="bottom-20-source"
type="source"
position={Position.Bottom}
style={{ left: '20%' }}
/>
<Handle
id="bottom-50-target"
type="target"
position={Position.Bottom}
style={{ left: '50%' }}
/>
<Handle
id="bottom-50-source"
type="source"
position={Position.Bottom}
style={{ left: '50%' }}
/>
<Handle
id="bottom-80-target"
type="target"
position={Position.Bottom}
style={{ left: '80%' }}
/>
<Handle
id="bottom-80-source"
type="source"
position={Position.Bottom}
style={{ left: '80%' }}
/>

{/* Left — legacy midpoint */}
<Handle id="left-target" type="target" position={Position.Left} />
<Handle id="left-source" type="source" position={Position.Left} />
{/* Left — 20/50/80 */}
<Handle id="left-20-target" type="target" position={Position.Left} style={{ top: '20%' }} />
<Handle id="left-20-source" type="source" position={Position.Left} style={{ top: '20%' }} />
<Handle id="left-50-target" type="target" position={Position.Left} style={{ top: '50%' }} />
<Handle id="left-50-source" type="source" position={Position.Left} style={{ top: '50%' }} />
<Handle id="left-80-target" type="target" position={Position.Left} style={{ top: '80%' }} />
<Handle id="left-80-source" type="source" position={Position.Left} style={{ top: '80%' }} />

<div className="node-content" style={contentStyle}>
{labelContent}
</div>
</div>
);
}
115 changes: 115 additions & 0 deletions src/components/DrawioReactFlow/DiagramHoverModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useState } from 'react';
import {
useFloating,
useHover,
useFocus,
useDismiss,
useRole,
useInteractions,
FloatingPortal,
offset,
flip,
shift,
autoUpdate,
useMergeRefs,
} from '@floating-ui/react';
import { MDXProvider } from '@mdx-js/react';
type MdxChildrenProps = { children?: React.ReactNode };
type MdxAnchorProps = MdxChildrenProps & { href?: string };

const mdxComponents = {
h1: ({ children }: MdxChildrenProps) => (
<h1 className="diagram-hover-modal__title">{children}</h1>
),
h2: ({ children }: MdxChildrenProps) => (
<h2 className="diagram-hover-modal__subtitle">{children}</h2>
),
h3: ({ children }: MdxChildrenProps) => (
<h3 className="diagram-hover-modal__heading3">{children}</h3>
),
h4: ({ children }: MdxChildrenProps) => (
<h4 className="diagram-hover-modal__heading4">{children}</h4>
),
p: ({ children }: MdxChildrenProps) => (
<p className="diagram-hover-modal__paragraph">{children}</p>
),
ul: ({ children }: MdxChildrenProps) => <ul className="diagram-hover-modal__list">{children}</ul>,
ol: ({ children }: MdxChildrenProps) => <ol className="diagram-hover-modal__list">{children}</ol>,
li: ({ children }: MdxChildrenProps) => (
<li className="diagram-hover-modal__list-item">{children}</li>
),
strong: ({ children }: MdxChildrenProps) => (
<strong className="diagram-hover-modal__strong">{children}</strong>
),
code: ({ children }: MdxChildrenProps) => (
<code className="diagram-hover-modal__inline-code">{children}</code>
),
a: ({ children, href }: MdxAnchorProps) => (
<a href={href} className="diagram-hover-modal__link" target="_blank" rel="noopener noreferrer">
{children}
</a>
),
};

interface DiagramHoverModalProps {
ContentComponent: React.ComponentType;
children: React.ReactNode;
}

export function DiagramHoverModal({ ContentComponent, children }: DiagramHoverModalProps) {
const [isOpen, setIsOpen] = useState(false);

const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
middleware: [offset(10), flip({ fallbackAxisSideDirection: 'start' }), shift({ padding: 5 })],
whileElementsMounted: autoUpdate,
});

const hover = useHover(context, {
move: false,
delay: { open: 150, close: 150 },
});
const focus = useFocus(context);
const dismiss = useDismiss(context);
const role = useRole(context, { role: 'dialog' });

const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, dismiss, role]);

const ref = useMergeRefs([refs.setReference]);

return (
<>
<span ref={ref} className="diagram-hover-modal__trigger" {...getReferenceProps()}>
{children}
</span>

{isOpen && (
<FloatingPortal>
<div
ref={refs.setFloating}
style={floatingStyles}
className="diagram-hover-modal__content"
{...getFloatingProps()}
>
<div className="diagram-hover-modal__header">
<button
className="diagram-hover-modal__close"
onClick={() => setIsOpen(false)}
aria-label="Close modal"
>
x
</button>
</div>
<div className="diagram-hover-modal__body">
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any -- Docusaurus bundles conflicting @types/react versions */}
<MDXProvider components={mdxComponents as any}>
<ContentComponent />
</MDXProvider>
</div>
</div>
</FloatingPortal>
)}
</>
);
}
Loading
Loading