Zero-dependency transaction verifier for Squads Protocol v4 multisigs on Solana.
Reads multisig state directly from on-chain accounts, decodes proposal transactions (vault, config, batch), and lets connected wallet members approve or reject — all from a single static page with no backend. Account discriminators and struct layouts are verified against @sqds/multisig v2.1.4.
- Deserializes all Squads v4 account types (Multisig, Proposal, VaultTransaction, ConfigTransaction, Batch, VaultBatchTransaction)
- Decodes SPL Token, Token-2022, System Program, Compute Budget, and Associated Token instructions into human-readable summaries
- Resolves Address Lookup Tables for complete account display
- Collapsible instruction cards with accounts table, flags (writable/signer), and raw hex
- Approval progress bar with collapsible member grid showing vote status per member
- Wallet connect/disconnect via Wallet Standard (Phantom, Solflare, Backpack, etc.)
- Approve/reject flow with transaction signing, confirmation tracking, and stale-state re-fetch
- Inline address bar with live base58 validation and multisig switching
- Explorer links to Solscan, Solana Explorer, or Helius XRAY
- Dark/light mode via
prefers-color-scheme - Build hash verification for reproducible deploys
- Content Security Policy headers — no inline scripts, no external resources
Browser ──fetch──> Solana RPC (your provider)
│
├── Deserialize multisig account (members, threshold, transaction index)
├── Batch-fetch proposal PDAs (getMultipleAccounts)
├── Fetch transaction PDAs (vault/config/batch)
│ └── Resolve Address Lookup Tables for v0 messages
├── Decode instructions (SPL Token, System, Compute Budget)
└── Sign + send approve/reject via Wallet Standard
All account parsing uses a hand-written Borsh reader with no external dependencies. PDA derivation uses the Web Crypto API (SHA-256) with a pure-JS Ed25519 curve check.
multisig-verifier/
├── index.html # Shell — CSP headers, no inline scripts
├── style.css # Full design system (dark/light, tokens, components)
├── webpack.config.js # Production build config (content hashing, minification)
├── src/
│ ├── main.js # Boot, state wiring, event handlers
│ ├── state.js # Frozen immutable state + localStorage persistence
│ ├── rpc.js # JSON-RPC fetch wrapper, ALT resolution, batch fetching
│ ├── squads.js # Borsh reader, discriminators, PDA derivation, deserialization
│ ├── crypto.js # SHA-256 (Web Crypto), Ed25519 curve check, findProgramAddress
│ ├── decode.js # Instruction decoder registry (SPL Token, System, etc.)
│ ├── transaction.js # Transaction builder for approve/reject instructions
│ ├── actions.js # Vote flow (dynamic import, re-fetch, sign, confirm)
│ ├── wallet.js # Wallet Standard discovery + adapter (zero deps)
│ ├── ui-layout.js # All views: setup, main layout, modals, proposal detail
│ └── ui-helpers.js # Hyperscript el(), address elements, formatting, sanitization
├── public/ # Static assets (SVG logos)
├── scripts/
│ ├── build.sh # Production build + hash generation
│ ├── generate-hash.sh # SHA-256 of dist/ contents
│ └── verify.sh # Verify a build against an expected hash
└── test/
├── verify.mjs # Discriminator + deserialization tests
└── cross-validate-pda.mjs # PDA derivation cross-check against @sqds/multisig
npm install
npm run dev # starts on http://localhost:8080npm run build:hash # webpack production build + SHA-256 hash of dist/The build hash is printed to stdout. Distribute it alongside the dist/ folder so users can verify the build:
bash scripts/verify.sh <expected-hash> distThe dist/ directory is a fully static site. Deploy to any static host:
# Cloudflare Pages
npx wrangler pages deploy dist
# Vercel
npx vercel dist
# Netlify
npx netlify deploy --dir=dist --prod
# Or just serve locally
npx serve distAll configuration happens in the browser UI. On first visit:
| Field | Description |
|---|---|
| Multisig Address | Base58-encoded Squads v4 multisig account address. Also accepts vault addresses (auto-resolved). |
| RPC URL | HTTPS endpoint for a Solana RPC provider (Helius, Triton, QuickNode). |
| Explorer | Block explorer for account/transaction links (Solscan, Solana Explorer, Helius XRAY). |
Settings persist in localStorage and sync across tabs.
- No innerHTML — all DOM construction uses
createElement+textContentvia theel()hyperscript helper - Bidi sanitization — on-chain strings are stripped of Unicode bidirectional override characters before display
- Content Security Policy —
default-src 'none'; scripts and styles from'self'only; connects restricted tohttps:andlocalhost - Script injection detection — a
MutationObserverhalts the page if any unexpected<script>element is added at runtime - Frame-busting — CSP
frame-ancestors 'none'prevents embedding in iframes - No secrets — RPC URLs and wallet keys are never sent to any backend; all operations are client-to-RPC
- Program ID:
SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf - Network: Solana Mainnet
- SDK Reference:
@sqds/multisigv2.1.4
The official @sqds/multisig SDK depends on @solana/web3.js v1.x (~400 KB) and its transitive dependency tree. This verifier re-implements Borsh deserialization and PDA derivation from scratch (~300 lines in squads.js + crypto.js) to stay at zero runtime dependencies. All discriminators and struct layouts are cross-validated against the SDK in the test suite.
npm install
npm run dev # webpack-dev-server with hot reload
npm run build # production build
npm run build:hash # production build + integrity hashnode test/verify.mjs # discriminator + deserialization
node test/cross-validate-pda.mjs # PDA derivation vs @sqds/multisigDual-licensed under Apache 2.0 and MIT.