Files
bridge/docs/out/integrations.html
T
Abhishek KrishnaandGitHub 56a583189a docs: refresh Nextra site + complete docs/*.md fold (closes #391) (#404)
* docs: fold loose docs/*.md into Nextra content/docs/ tree (issue #391)

The four MPC-migration .md files plus BRIDGE-STATUS / LOCAL-SETUP /
DEPLOYMENT / CI-CD-DOCKER-IMAGES were already deleted in 2b9f899 (v1.1.12).
The remaining loose docs at docs/ root (INTEGRATIONS, LUX-ID-INTEGRATION,
operator-runbook, operator-deploy-phase-1-4) were still current but lived
outside the Nextra page tree, so the site only ever served Home + Architecture.

Move them into docs/content/docs/*.mdx so the Nextra build can surface them:

  docs/INTEGRATIONS.md              -> docs/content/docs/integrations.mdx
  docs/LUX-ID-INTEGRATION.md        -> docs/content/docs/lux-id-integration.mdx
  docs/operator-runbook.md          -> docs/content/docs/operator-runbook.mdx
  docs/operator-deploy-phase-1-4.md -> docs/content/docs/operator-deploy.mdx

docs/LLM.md stays at docs/ root because it's the symlink target for
AGENTS.md (and any future CLAUDE.md / GEMINI.md), per the .gitignore.

Content of the moved files is unchanged in this commit.

* docs: wire content/docs/* into Nextra pages, refresh _meta + index (issue #391)

Add Nextra page wrappers for each moved doc so the site sidebar surfaces the
full set:

  docs/pages/integrations.mdx        -> imports content/docs/integrations.mdx
  docs/pages/lux-id-integration.mdx  -> imports content/docs/lux-id-integration.mdx
  docs/pages/operator-runbook.mdx    -> imports content/docs/operator-runbook.mdx
  docs/pages/operator-deploy.mdx     -> imports content/docs/operator-deploy.mdx

Refresh docs/pages/_meta.json to list the new pages in display order:
  Home -> Architecture -> Integrations -> Operator Runbook -> Deploy Guide
  -> Lux ID -> (External) LLM Knowledge Base, GitHub.

Refresh docs/pages/index.mdx:
  - replace the legacy "make up && make start-mpc-nodes" quickstart (predates
    the unified Go binary) with the docker run pattern for ghcr.io/luxfi/bridge.
  - point SDK consumers at pkg/bridge README + mountBridge.
  - call out the post-quantum-safe protocol options (pulsar, corona, magnetar)
    alongside the classical cggmp21/doerner/frost/bls set.
  - link docs/LLM.md as the canonical AI/onboarding source of truth.

Build verified: pnpm install && pnpm build prerenders 8 static pages
(index, docs, integrations, lux-id-integration, operator-runbook,
operator-deploy, plus _app and 404).

* docs: update README/LLM.md/REQUIREMENTS pointers for the new layout (issue #391)

The loose docs/*.md set at docs/ root was folded into docs/content/docs/*.mdx
in the previous two commits. Update the three places that still point at the
old paths or describe the old layout:

  - README.md: drop the direct link to docs/LUX-ID-INTEGRATION.md; point
    readers at the Nextra site (`pnpm --filter @luxfi/bridge-docs build`)
    and call out the new content/docs/ + pages/ split.
  - docs/LLM.md: refresh "Key Documentation Files" to list every
    content/docs/*.mdx page and explain why docs/LLM.md stays at root.
  - REQUIREMENTS.md: update the §4 tree comment and the §7 row 1.5 status
    note so they reflect the v1.1.13 fold.

No file content moves in this commit — pointers only.

* docs: regenerate docs/out static site for the 8-page Nextra build (issue #391)

`docs/out/` is the static export served at the GitHub Pages mirror. Rebuild
it with `pnpm --filter @luxfi/bridge-docs build` so the artifact contains
all six content pages (index, docs, integrations, lux-id-integration,
operator-runbook, operator-deploy) plus _app and 404.

No source code or docs content changes in this commit — build artefacts only.
2026-06-22 22:13:50 -07:00

117 lines
47 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html><head><meta charSet="utf-8"/><title>Integrations – Nextra</title><meta name="robots" content="index,follow"/><meta property="og:title" content="Integrations – Nextra"/><meta name="theme-color" content="#111" media="(prefers-color-scheme: dark)"/><style>
:root {
--nextra-primary-hue: 200deg;
--nextra-primary-saturation: 100%;
--nextra-navbar-height: 4rem;
--nextra-menu-height: 3.75rem;
--nextra-banner-height: 2.5rem;
}
.dark {
--nextra-primary-hue: 200deg;
--nextra-primary-saturation: 100%;
}
</style><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta property="og:title" content="Lux Bridge Documentation"/><meta property="og:description" content="Comprehensive documentation for the Lux Bridge - a decentralized cross-chain bridge using MPC"/><meta name="next-head-count" content="9"/><link rel="preload" href="/_next/static/css/f996cf9b737d77f6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f996cf9b737d77f6.css" data-n-g=""/><link rel="preload" href="/_next/static/css/1b75bb7537b53e78.css" as="style"/><link rel="stylesheet" href="/_next/static/css/1b75bb7537b53e78.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-6ef43a8d4a395f49.js" defer=""></script><script src="/_next/static/chunks/framework-0cbe3b56a5f66701.js" defer=""></script><script src="/_next/static/chunks/main-35d29b002b9b8976.js" defer=""></script><script src="/_next/static/chunks/pages/_app-048d9d4ed025df82.js" defer=""></script><script src="/_next/static/chunks/455-d1a02f1720f55d00.js" defer=""></script><script src="/_next/static/chunks/pages/integrations-f872cba62b0fc5f9.js" defer=""></script><script src="/_next/static/hnS4DkNCR004by-hexIXU/_buildManifest.js" defer=""></script><script src="/_next/static/hnS4DkNCR004by-hexIXU/_ssgManifest.js" defer=""></script></head><body><div id="__next"><script>!function(){try{var d=document.documentElement,c=d.classList;c.remove('light','dark');var e=localStorage.getItem('theme');if('system'===e||(!e&&true)){var t='(prefers-color-scheme: dark)',m=window.matchMedia(t);if(m.media!==t||m.matches){d.style.colorScheme = 'dark';c.add('dark')}else{d.style.colorScheme = 'light';c.add('light')}}else if(e){c.add(e|| '')}if(e==='light'||e==='dark')d.style.colorScheme=e}catch(e){}}()</script><div dir="ltr"><script>document.documentElement.setAttribute('dir','ltr')</script><script>try{if(localStorage.getItem("bridge-v1")==='0'){document.body.classList.add('nextra-banner-hidden')}}catch(e){}</script><div class="nextra-banner-container nx-sticky nx-top-0 nx-z-20 nx-flex nx-items-center md:nx-relative nx-h-[var(--nextra-banner-height)] [body.nextra-banner-hidden_&amp;]:nx-hidden nx-text-slate-50 dark:nx-text-white nx-bg-neutral-900 dark:nx-bg-[linear-gradient(1deg,#383838,#212121)] nx-px-2 ltr:nx-pl-10 rtl:nx-pr-10 print:nx-hidden"><div class="nx-w-full nx-truncate nx-px-4 nx-text-center nx-font-medium nx-text-sm"><a href="https://lux.network" target="_blank">🚀 Lux Bridge v1.0 is now live! Learn more →</a></div><button type="button" aria-label="Dismiss banner" class="nx-w-8 nx-h-8 nx-opacity-80 hover:nx-opacity-100"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="currentColor" class="nx-mx-auto nx-h-4 nx-w-4"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div><div class="nextra-nav-container nx-sticky nx-top-0 nx-z-20 nx-w-full nx-bg-transparent print:nx-hidden"><div class="nextra-nav-container-blur nx-pointer-events-none nx-absolute nx-z-[-1] nx-h-full nx-w-full nx-bg-white dark:nx-bg-dark nx-shadow-[0_2px_4px_rgba(0,0,0,.02),0_1px_0_rgba(0,0,0,.06)] dark:nx-shadow-[0_-1px_0_rgba(255,255,255,.1)_inset] contrast-more:nx-shadow-[0_0_0_1px_#000] contrast-more:dark:nx-shadow-[0_0_0_1px_#fff]"></div><nav class="nx-mx-auto nx-flex nx-h-[var(--nextra-navbar-height)] nx-max-w-[90rem] nx-items-center nx-justify-end nx-gap-2 nx-pl-[max(env(safe-area-inset-left),1.5rem)] nx-pr-[max(env(safe-area-inset-right),1.5rem)]"><a class="nx-flex nx-items-center hover:nx-opacity-75 ltr:nx-mr-auto rtl:nx-ml-auto" href="/"><span>Lux Bridge</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-text-gray-600 hover:nx-text-gray-800 dark:nx-text-gray-400 dark:hover:nx-text-gray-200" aria-current="false" href="/"><span class="nx-absolute nx-inset-x-0 nx-text-center">Home</span><span class="nx-invisible nx-font-medium">Home</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-text-gray-600 hover:nx-text-gray-800 dark:nx-text-gray-400 dark:hover:nx-text-gray-200" aria-current="false" href="/docs"><span class="nx-absolute nx-inset-x-0 nx-text-center">Architecture</span><span class="nx-invisible nx-font-medium">Architecture</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-font-medium nx-subpixel-antialiased" aria-current="true" href="/integrations"><span class="nx-absolute nx-inset-x-0 nx-text-center">Integrations</span><span class="nx-invisible nx-font-medium">Integrations</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-text-gray-600 hover:nx-text-gray-800 dark:nx-text-gray-400 dark:hover:nx-text-gray-200" aria-current="false" href="/operator-runbook"><span class="nx-absolute nx-inset-x-0 nx-text-center">Operator Runbook</span><span class="nx-invisible nx-font-medium">Operator Runbook</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-text-gray-600 hover:nx-text-gray-800 dark:nx-text-gray-400 dark:hover:nx-text-gray-200" aria-current="false" href="/operator-deploy"><span class="nx-absolute nx-inset-x-0 nx-text-center">Deploy Guide</span><span class="nx-invisible nx-font-medium">Deploy Guide</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-text-gray-600 hover:nx-text-gray-800 dark:nx-text-gray-400 dark:hover:nx-text-gray-200" aria-current="false" href="/lux-id-integration"><span class="nx-absolute nx-inset-x-0 nx-text-center">Lux ID</span><span class="nx-invisible nx-font-medium">Lux ID</span></a><div class="nextra-search nx-relative md:nx-w-64 nx-hidden md:nx-inline-block mx-min-w-[200px]"><div class="nx-relative nx-flex nx-items-center nx-text-gray-900 contrast-more:nx-text-gray-800 dark:nx-text-gray-300 contrast-more:dark:nx-text-gray-300"><input spellcheck="false" class="nx-block nx-w-full nx-appearance-none nx-rounded-lg nx-px-3 nx-py-2 nx-transition-colors nx-text-base nx-leading-tight md:nx-text-sm nx-bg-black/[.05] dark:nx-bg-gray-50/10 focus:nx-bg-white dark:focus:nx-bg-dark placeholder:nx-text-gray-500 dark:placeholder:nx-text-gray-400 contrast-more:nx-border contrast-more:nx-border-current" type="search" placeholder="Search documentation…" value=""/></div></div><a href="https://github.com/luxfi/bridge" target="_blank" rel="noreferrer" class="nx-p-2 nx-text-current"><svg width="24" height="24" fill="currentColor" viewBox="3 3 18 18"><title>GitHub</title><path d="M12 3C7.0275 3 3 7.12937 3 12.2276C3 16.3109 5.57625 19.7597 9.15374 20.9824C9.60374 21.0631 9.77249 20.7863 9.77249 20.5441C9.77249 20.3249 9.76125 19.5982 9.76125 18.8254C7.5 19.2522 6.915 18.2602 6.735 17.7412C6.63375 17.4759 6.19499 16.6569 5.8125 16.4378C5.4975 16.2647 5.0475 15.838 5.80124 15.8264C6.51 15.8149 7.01625 16.4954 7.18499 16.7723C7.99499 18.1679 9.28875 17.7758 9.80625 17.5335C9.885 16.9337 10.1212 16.53 10.38 16.2993C8.3775 16.0687 6.285 15.2728 6.285 11.7432C6.285 10.7397 6.63375 9.9092 7.20749 9.26326C7.1175 9.03257 6.8025 8.08674 7.2975 6.81794C7.2975 6.81794 8.05125 6.57571 9.77249 7.76377C10.4925 7.55615 11.2575 7.45234 12.0225 7.45234C12.7875 7.45234 13.5525 7.55615 14.2725 7.76377C15.9937 6.56418 16.7475 6.81794 16.7475 6.81794C17.2424 8.08674 16.9275 9.03257 16.8375 9.26326C17.4113 9.9092 17.76 10.7281 17.76 11.7432C17.76 15.2843 15.6563 16.0687 13.6537 16.2993C13.98 16.5877 14.2613 17.1414 14.2613 18.0065C14.2613 19.2407 14.25 20.2326 14.25 20.5441C14.25 20.7863 14.4188 21.0746 14.8688 20.9824C16.6554 20.364 18.2079 19.1866 19.3078 17.6162C20.4077 16.0457 20.9995 14.1611 21 12.2276C21 7.12937 16.9725 3 12 3Z"></path></svg><span class="nx-sr-only">GitHub</span><span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a><a href="https://discord.gg/luxnetwork" target="_blank" rel="noreferrer" class="nx-p-2 nx-text-current"><svg width="24" height="24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 5 30.67 23.25"><title>Discord</title><path d="M26.0015 6.9529C24.0021 6.03845 21.8787 5.37198 19.6623 5C19.3833 5.48048 19.0733 6.13144 18.8563 6.64292C16.4989 6.30193 14.1585 6.30193 11.8336 6.64292C11.6166 6.13144 11.2911 5.48048 11.0276 5C8.79575 5.37198 6.67235 6.03845 4.6869 6.9529C0.672601 12.8736 -0.41235 18.6548 0.130124 24.3585C2.79599 26.2959 5.36889 27.4739 7.89682 28.2489C8.51679 27.4119 9.07477 26.5129 9.55525 25.5675C8.64079 25.2265 7.77283 24.808 6.93587 24.312C7.15286 24.1571 7.36986 23.9866 7.57135 23.8161C12.6241 26.1255 18.0969 26.1255 23.0876 23.8161C23.3046 23.9866 23.5061 24.1571 23.7231 24.312C22.8861 24.808 22.0182 25.2265 21.1037 25.5675C21.5842 26.5129 22.1422 27.4119 22.7621 28.2489C25.2885 27.4739 27.8769 26.2959 30.5288 24.3585C31.1952 17.7559 29.4733 12.0212 26.0015 6.9529ZM10.2527 20.8402C8.73376 20.8402 7.49382 19.4608 7.49382 17.7714C7.49382 16.082 8.70276 14.7025 10.2527 14.7025C11.7871 14.7025 13.0425 16.082 13.0115 17.7714C13.0115 19.4608 11.7871 20.8402 10.2527 20.8402ZM20.4373 20.8402C18.9183 20.8402 17.6768 19.4608 17.6768 17.7714C17.6768 16.082 18.8873 14.7025 20.4373 14.7025C21.9717 14.7025 23.2271 16.082 23.1961 17.7714C23.1961 19.4608 21.9872 20.8402 20.4373 20.8402Z"></path></svg><span class="nx-sr-only">Discord</span><span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a><button type="button" aria-label="Menu" class="nextra-hamburger -nx-mr-2 nx-rounded nx-p-2 active:nx-bg-gray-400/20 md:nx-hidden"><svg fill="none" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor" class=""><g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16"></path></g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16"></path><g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 18h16"></path></g></svg></button></nav></div><div class="nx-mx-auto nx-flex nx-max-w-[90rem]"><div class="max-xl:nx-hidden nx-h-0 nx-w-64 nx-shrink-0"></div><div class="motion-reduce:nx-transition-none [transition:background-color_1.5s_ease] nx-bg-transparent"></div><aside class="nextra-sidebar-container nx-flex nx-flex-col md:nx-top-16 md:nx-shrink-0 motion-reduce:nx-transform-none nx-transform-gpu nx-transition-all nx-ease-in-out print:nx-hidden md:nx-w-64 md:nx-hidden max-md:[transform:translate3d(0,-100%,0)]"><div class="nx-px-4 nx-pt-4 md:nx-hidden"><div class="nextra-search nx-relative md:nx-w-64"><div class="nx-relative nx-flex nx-items-center nx-text-gray-900 contrast-more:nx-text-gray-800 dark:nx-text-gray-300 contrast-more:dark:nx-text-gray-300"><input spellcheck="false" class="nx-block nx-w-full nx-appearance-none nx-rounded-lg nx-px-3 nx-py-2 nx-transition-colors nx-text-base nx-leading-tight md:nx-text-sm nx-bg-black/[.05] dark:nx-bg-gray-50/10 focus:nx-bg-white dark:focus:nx-bg-dark placeholder:nx-text-gray-500 dark:placeholder:nx-text-gray-400 contrast-more:nx-border contrast-more:nx-border-current" type="search" placeholder="Search documentation…" value=""/></div></div></div><div class="nx-overflow-y-auto nx-overflow-x-hidden nx-p-4 nx-grow md:nx-h-[calc(100vh-var(--nextra-navbar-height)-var(--nextra-menu-height))] nextra-scrollbar"></div><div class="nx-sticky nx-bottom-0 nx-bg-white dark:nx-bg-dark nx-mx-4 nx-py-4 nx-shadow-[0_-12px_16px_#fff] nx-flex nx-items-center nx-gap-2 dark:nx-border-neutral-800 dark:nx-shadow-[0_-12px_16px_#111] contrast-more:nx-border-neutral-400 contrast-more:nx-shadow-none contrast-more:dark:nx-shadow-none nx-border-t" data-toggle-animation="off"><div class="nx-grow nx-flex nx-flex-col"><button title="Change theme" class="nx-h-7 nx-rounded-md nx-px-2 nx-text-left nx-text-xs nx-font-medium nx-text-gray-600 nx-transition-colors dark:nx-text-gray-400 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50" id="headlessui-listbox-button-:Rlsr6:" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state=""><div class="nx-flex nx-items-center nx-gap-2 nx-capitalize"><svg fill="none" viewBox="3 3 18 18" width="12" height="12" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="currentColor" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg><span class="">Light</span></div></button></div><button title="Hide sidebar" class="max-md:nx-hidden nx-h-7 nx-rounded-md nx-transition-colors nx-text-gray-600 dark:nx-text-gray-400 nx-px-2 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50"><svg height="12" width="12" viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M4.177 7.823l2.396-2.396A.25.25 0 017 5.604v4.792a.25.25 0 01-.427.177L4.177 8.177a.25.25 0 010-.354z" class=""></path><path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm1.75-.25a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25H9.5v-13H1.75zm12.5 13H11v-13h3.25a.25.25 0 01.25.25v12.5a.25.25 0 01-.25.25z"></path></svg></button></div></aside><nav class="nextra-toc nx-order-last nx-hidden nx-w-64 nx-shrink-0 xl:nx-block print:nx-hidden" aria-label="table of contents"></nav><div id="reach-skip-nav"></div><article class="nx-w-full nx-break-words nextra-content nx-flex nx-min-h-[calc(100vh-var(--nextra-navbar-height))] nx-min-w-0 nx-justify-center nx-pb-8 nx-pr-[calc(env(safe-area-inset-right)-1.5rem)]"><main class="nx-w-full nx-min-w-0 nx-max-w-6xl nx-px-6 nx-pt-4 md:nx-px-12"><h1 class="nx-mt-2 nx-text-4xl nx-font-bold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100">Integrations — Go-side operator guide</h1>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">This document describes the Go-side daemon architecture of the Lux
bridge for <strong>operators</strong> running validator / watcher / signer nodes.
It is not an SDK reference. The only npm package consumers ever import
is <strong><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">@luxfi/bridge</code></strong> — see that package&#x27;s README for client usage.</p>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The Go side is what an operator deploys to physically observe source
chains, run the threshold-signature protocol, and submit relays to the
destination chain. The two binaries built by goreleaser are:</p>
<table class="nx-block nx-overflow-x-scroll nextra-scrollbar nx-mt-6 nx-p-0 first:nx-mt-0"><thead><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600" align="left">Binary</th><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600" align="left">Path</th><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600" align="left">Role</th></tr></thead><tbody><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">bridge</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">cmd/bridge</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">API + frontend host; coordinates the watcher fleet and serves the relay queue.</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher/</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">Per-chain indexer + threshold cosigner. One instance per source chain, federated across operators.</td></tr></tbody></table>
<hr class="nx-my-8 nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400"/>
<h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">1. Cross-chain MPC bridge model<a href="#1-cross-chain-mpc-bridge-model" id="1-cross-chain-mpc-bridge-model" class="subheading-anchor" aria-label="Permalink for this section"></a></h2>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The bridge connects <strong>15+ heterogeneous chain families</strong> —
EVM L1s, EVM L2 rollups, non-EVM L1s, Cosmos zones, UTXO chains, and
a small number of niche substrates — into a uniform deposit / relay /
mint pipeline.</p>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Each source chain is observed by a per-chain plugin that emits a
single canonical event type:</p>
<div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="go" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="go" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">type</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">DepositEvent</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-keyword)">struct</span><span style="color:var(--shiki-color-text)"> {</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> SrcChainID </span><span style="color:var(--shiki-token-keyword)">uint64</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> Nonce </span><span style="color:var(--shiki-token-keyword)">uint64</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> Recipient [</span><span style="color:var(--shiki-token-constant)">20</span><span style="color:var(--shiki-color-text)">]</span><span style="color:var(--shiki-token-keyword)">byte</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">// destination address on the relay chain</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> Amount </span><span style="color:var(--shiki-token-keyword)">*</span><span style="color:var(--shiki-color-text)">big.Int</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> TxID </span><span style="color:var(--shiki-token-keyword)">string</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">// source-chain tx identifier</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> BlockHeight </span><span style="color:var(--shiki-token-keyword)">uint64</span></span>
<span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover&gt;&amp;]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Operators never write chain-specific glue at the relay or signer
layer. A new chain only has to satisfy <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">ChainPlugin</code> (see
<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher/plugins/plugin.go</code>):</p>
<div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="go" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="go" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">type</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">ChainPlugin</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-keyword)">interface</span><span style="color:var(--shiki-color-text)"> {</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">Name</span><span style="color:var(--shiki-color-text)">() </span><span style="color:var(--shiki-token-keyword)">string</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">ChainID</span><span style="color:var(--shiki-color-text)">() </span><span style="color:var(--shiki-token-keyword)">uint64</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">PollDeposits</span><span style="color:var(--shiki-color-text)">(ctx context.Context, fromSlot </span><span style="color:var(--shiki-token-keyword)">uint64</span><span style="color:var(--shiki-color-text)">) ([]DepositEvent, </span><span style="color:var(--shiki-token-keyword)">uint64</span><span style="color:var(--shiki-color-text)">, </span><span style="color:var(--shiki-token-keyword)">error</span><span style="color:var(--shiki-color-text)">)</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">QueryBacking</span><span style="color:var(--shiki-color-text)">(ctx context.Context) (</span><span style="color:var(--shiki-token-keyword)">*</span><span style="color:var(--shiki-color-text)">big.Int, </span><span style="color:var(--shiki-token-keyword)">error</span><span style="color:var(--shiki-color-text)">)</span></span>
<span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover&gt;&amp;]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Everything downstream — proof-hash construction, signer participation,
relay submission, backing attestation — is chain-agnostic.</p>
<hr class="nx-my-8 nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400"/>
<h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">2. Threshold-signature scheme<a href="#2-threshold-signature-scheme" id="2-threshold-signature-scheme" class="subheading-anchor" aria-label="Permalink for this section"></a></h2>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The signer in <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher/signer.go</code> is built on
<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">github.com/luxfi/crypto/threshold</code> and supports three production
schemes selected per destination context:</p>
<table class="nx-block nx-overflow-x-scroll nextra-scrollbar nx-mt-6 nx-p-0 first:nx-mt-0"><thead><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600" align="left">Scheme</th><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600" align="left">Curve</th><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600" align="left">Use</th></tr></thead><tbody><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><strong>CGGMP21</strong> (<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">SchemeCMP</code>)</td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">secp256k1</td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">Threshold ECDSA for EVM-compatible destinations — the default relay path.</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><strong>FROST</strong> (<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">SchemeFROST</code>)</td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">secp256k1 / ed25519</td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">Threshold Schnorr for Taproot and ed25519-native destinations.</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left"><strong>BLS</strong> (<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">SchemeBLS</code>)</td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">BLS12-381</td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600" align="left">Threshold BLS for aggregated internal attestations.</td></tr></tbody></table>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">CGGMP21 is the canonical choice because it is <strong>non-interactive at
signing time</strong> after a one-time interactive keygen, and it produces
signatures that are bit-for-bit identical to any standard secp256k1
ECDSA signature — destination contracts verify with <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">ecrecover</code> and
do not need to know that a threshold scheme produced the signature.</p>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Key shares are generated once via the keygen ceremony in
<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">pkg/threshold/</code> (TS-side ceremony coordinator) and distributed to
operator HSMs out of band. The Go-side daemon never sees a full
private key — only its share — and <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">t-of-n</code> participation is required
for every relay signature.</p>
<hr class="nx-my-8 nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400"/>
<h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">3. The <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">WebhookHandler</code> pattern<a href="#3-the-webhookhandler-pattern" id="3-the-webhookhandler-pattern" class="subheading-anchor" aria-label="Permalink for this section"></a></h2>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">A small but load-bearing convention in the Lux ecosystem: any
provider / plugin that can receive <strong>asynchronous callbacks</strong> from an
external system (chain RPC push, custodian webhook, oracle feed)
implements the optional <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">WebhookHandler</code> capability rather than
embedding the callback path inside its primary interface.</p>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The canonical shape (mirrored from <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">forex/pkg/provider/provider.go</code>):</p>
<div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="go" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="go" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">type</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">WebhookHandler</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-keyword)">interface</span><span style="color:var(--shiki-color-text)"> {</span></span>
<span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">ParseWebhook</span><span style="color:var(--shiki-color-text)">(eventType </span><span style="color:var(--shiki-token-keyword)">string</span><span style="color:var(--shiki-color-text)">, body []</span><span style="color:var(--shiki-token-keyword)">byte</span><span style="color:var(--shiki-color-text)">, headers http.Header) (</span><span style="color:var(--shiki-token-keyword)">*</span><span style="color:var(--shiki-color-text)">NormalizedEvent, </span><span style="color:var(--shiki-token-keyword)">error</span><span style="color:var(--shiki-color-text)">)</span></span>
<span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover&gt;&amp;]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Rules:</p>
<ul class="nx-mt-6 nx-list-disc first:nx-mt-0 ltr:nx-ml-6 rtl:nx-mr-6">
<li class="nx-my-2">It is <strong>optional</strong> — providers/plugins that poll only do not
implement it. Consumers do an interface assertion and skip.</li>
<li class="nx-my-2">The handler returns a <strong>normalised event</strong> in the same shape the
poll path emits. The downstream pipeline cannot tell whether an
event arrived by polling or by webhook.</li>
<li class="nx-my-2">All authentication / signature verification of the inbound webhook
happens <strong>inside</strong> <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">ParseWebhook</code>, using <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">headers</code>. The caller does
not pre-validate.</li>
</ul>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Adopt this pattern for any new chain plugin that gains a push API.
Do not invent a parallel callback interface.</p>
<hr class="nx-my-8 nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400"/>
<h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">4. Adding a new chain<a href="#4-adding-a-new-chain" id="4-adding-a-new-chain" class="subheading-anchor" aria-label="Permalink for this section"></a></h2>
<ol class="nx-mt-6 nx-list-decimal first:nx-mt-0 ltr:nx-ml-6 rtl:nx-mr-6">
<li class="nx-my-2">Drop a new file in <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher/plugins/&lt;chain&gt;.go</code> implementing
<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">ChainPlugin</code>. Use one of the existing plugins as the closest
structural reference for your chain family (EVM, Cosmos, UTXO,
account-model non-EVM, rollup).</li>
<li class="nx-my-2">Add the chain ID to <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">cmd/bridge/networks.example.yaml</code>.</li>
<li class="nx-my-2">Register the plugin in <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher/main.go</code> so it is wired into
the watcher fleet at boot.</li>
<li class="nx-my-2">If the chain provides a push API, additionally implement
<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">WebhookHandler</code> (§3) and register the route in <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">cmd/bridge/api.go</code>.</li>
<li class="nx-my-2">Write a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">&lt;chain&gt;_test.go</code> that exercises <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">PollDeposits</code> against a
recorded fixture — every existing plugin ships one; the test
matrix in CI requires it.</li>
</ol>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">No changes are required to the signer, relay, or destination
contract. The plugin contract is the only seam.</p>
<hr class="nx-my-8 nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400"/>
<h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">5. Public SDK boundary<a href="#5-public-sdk-boundary" id="5-public-sdk-boundary" class="subheading-anchor" aria-label="Permalink for this section"></a></h2>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">@luxfi/bridge</code> (the npm package in <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">pkg/bridge/</code>) is the <strong>only</strong>
surface a downstream application is ever expected to import. The Go
binaries here are operational infrastructure: an integrating
application does not run <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">bridge</code> or <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">opnet-watcher</code> in-process — it
talks to a federated relay network of operators who do.</p>
<p class="nx-mt-6 nx-leading-7 first:nx-mt-0">If an integration question is about <em>what an app developer calls</em>, the
answer is in <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">pkg/bridge/README.md</code>. If it is about <em>what an operator
runs</em>, the answer is in this document.</p><div class="nx-mt-16"></div></main></article></div><footer class="nx-bg-gray-100 nx-pb-[env(safe-area-inset-bottom)] dark:nx-bg-neutral-900 print:nx-bg-transparent"><div class="nx-mx-auto nx-flex nx-max-w-[90rem] nx-gap-2 nx-py-2 nx-px-4 nx-flex"><button title="Change theme" class="nx-h-7 nx-rounded-md nx-px-2 nx-text-left nx-text-xs nx-font-medium nx-text-gray-600 nx-transition-colors dark:nx-text-gray-400 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50" id="headlessui-listbox-button-:Rkt6:" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state=""><div class="nx-flex nx-items-center nx-gap-2 nx-capitalize"><svg fill="none" viewBox="3 3 18 18" width="12" height="12" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="currentColor" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg><span class="">Light</span></div></button></div><hr class="dark:nx-border-neutral-800"/><div class="nx-mx-auto nx-flex nx-max-w-[90rem] nx-justify-center nx-py-12 nx-text-gray-600 dark:nx-text-gray-400 md:nx-justify-start nx-pl-[max(env(safe-area-inset-left),1.5rem)] nx-pr-[max(env(safe-area-inset-right),1.5rem)]">Lux Bridge Documentation</div></footer></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/integrations","query":{},"buildId":"hnS4DkNCR004by-hexIXU","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>