From a365b7876430b4587cd4fa28f8a88a2808877059 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 31 May 2026 02:19:12 +0300 Subject: [PATCH 1/2] ci: add deterministic docs checks (typos, Vale, SEO, links) Free, no-AI GitHub Actions replacing the deterministic Mintlify Automate workflows: - spelling.yml + _typos.toml: spell-check on PRs (blocking; high precision) - prose-style.yml + .vale.ini + .github/styles/Sei: style-guide and grammar linting derived from AGENTS.md and STYLE_GUIDE.md (advisory, changed lines only, so the existing heading backlog doesn't create noise) - seo-audit.yml + scripts/audit-seo.mjs: title/description + page-structure audit over docs.json pages (blocks only on missing metadata) - external-links.yml + lychee.toml: scheduled external link-rot check that opens an issue; complements the existing mint broken-links workflow Co-Authored-By: Claude Opus 4.8 --- .github/styles/Sei/ClickHere.yml | 11 + .github/styles/Sei/Headings.yml | 41 ++++ .github/styles/Sei/Qualifiers.yml | 18 ++ .github/styles/Sei/Terminology.yml | 18 ++ .../styles/config/vocabularies/Sei/accept.txt | 39 +++ .github/workflows/external-links.yml | 47 ++++ .github/workflows/prose-style.yml | 37 +++ .github/workflows/seo-audit.yml | 28 +++ .github/workflows/spelling.yml | 24 ++ .vale.ini | 31 +++ _typos.toml | 39 +++ lychee.toml | 45 ++++ scripts/audit-seo.mjs | 227 ++++++++++++++++++ 13 files changed, 605 insertions(+) create mode 100644 .github/styles/Sei/ClickHere.yml create mode 100644 .github/styles/Sei/Headings.yml create mode 100644 .github/styles/Sei/Qualifiers.yml create mode 100644 .github/styles/Sei/Terminology.yml create mode 100644 .github/styles/config/vocabularies/Sei/accept.txt create mode 100644 .github/workflows/external-links.yml create mode 100644 .github/workflows/prose-style.yml create mode 100644 .github/workflows/seo-audit.yml create mode 100644 .github/workflows/spelling.yml create mode 100644 .vale.ini create mode 100644 _typos.toml create mode 100644 lychee.toml create mode 100644 scripts/audit-seo.mjs diff --git a/.github/styles/Sei/ClickHere.yml b/.github/styles/Sei/ClickHere.yml new file mode 100644 index 0000000..9d9de5a --- /dev/null +++ b/.github/styles/Sei/ClickHere.yml @@ -0,0 +1,11 @@ +extends: existence +message: "Avoid '%s' as link text — use descriptive link text (STYLE_GUIDE.md)." +link: https://github.com/sei-protocol/sei-docs/blob/main/STYLE_GUIDE.md +level: warning +ignorecase: true +# STYLE_GUIDE.md: links should be descriptive — "click here" / "[here]" tell +# the reader nothing about where they're going. +tokens: + - 'click here' + - '\[here\]\(' + - '\[this link\]\(' diff --git a/.github/styles/Sei/Headings.yml b/.github/styles/Sei/Headings.yml new file mode 100644 index 0000000..fbba533 --- /dev/null +++ b/.github/styles/Sei/Headings.yml @@ -0,0 +1,41 @@ +extends: capitalization +message: "Use sentence case for headings: '%s'." +link: https://github.com/sei-protocol/sei-docs/blob/main/AGENTS.md +level: warning +scope: heading +# AGENTS.md: "Sentence case for headings." Only the first word and proper nouns +# are capitalized. Proper nouns below are exempt so they may appear mid-heading. +match: $sentence +exceptions: + - Sei + - Sei Giga + - Sei EVM + - Sei Network + - SeiDB + - EVM + - CosmWasm + - Cosmos + - Ethereum + - Solidity + - Hardhat + - Foundry + - MetaMask + - Compass + - Rabby + - Ledger + - Twin Turbo Consensus + - Autobahn + - Pectra + - RPC + - API + - CLI + - SDK + - NFT + - IBC + - VRF + - JSON + - RocksDB + - StateSync + - IPv4 + - IPv6 + - I diff --git a/.github/styles/Sei/Qualifiers.yml b/.github/styles/Sei/Qualifiers.yml new file mode 100644 index 0000000..364aa92 --- /dev/null +++ b/.github/styles/Sei/Qualifiers.yml @@ -0,0 +1,18 @@ +extends: existence +message: "'%s' is often unnecessary qualifying language — consider removing it." +link: https://github.com/sei-protocol/sei-docs/blob/main/STYLE_GUIDE.md +level: suggestion +ignorecase: true +# STYLE_GUIDE.md: "Avoid qualifying language, which is quite often completely +# unnecessary." Suggestion-level — informational, never blocks a PR. +tokens: + - very + - really + - quite + - simply + - completely + - totally + - basically + - essentially + - obviously + - of course diff --git a/.github/styles/Sei/Terminology.yml b/.github/styles/Sei/Terminology.yml new file mode 100644 index 0000000..3651d3d --- /dev/null +++ b/.github/styles/Sei/Terminology.yml @@ -0,0 +1,18 @@ +extends: substitution +message: "Use '%s' instead of '%s' (Sei terminology)." +link: https://github.com/sei-protocol/sei-docs/blob/main/AGENTS.md +level: warning +ignorecase: false +action: + name: replace +# observed (wrong) form : preferred form. Patterns are written so the correct +# spelling never matches itself. +swap: + 'the Sei blockchain': Sei + 'Sei [Cc]hain': Sei + 'gas fees?': gas + '\bCW\b': CosmWasm + '[Cc]osmwasm': CosmWasm + '[Mm]etamask': MetaMask + 'Sei-?[Jj][Ss]': sei-js + 'seijs': sei-js diff --git a/.github/styles/config/vocabularies/Sei/accept.txt b/.github/styles/config/vocabularies/Sei/accept.txt new file mode 100644 index 0000000..f25778e --- /dev/null +++ b/.github/styles/config/vocabularies/Sei/accept.txt @@ -0,0 +1,39 @@ +Sei +seid +sei-js +SeiDB +Sei Giga +CosmWasm +Cosmos +Tendermint +CometBFT +Autobahn +Pectra +Mintlify +MetaMask +Compass +Rabby +Hardhat +Foundry +Solidity +wagmi +viem +ethers +RainbowKit +Ankr +DRPC +Nirvana +Takara +Citrex +Symphony +DragonSwap +Cambrian +precompile +precompiles +mempool +calldata +multicall +statesync +gigagas +dApp +dApps diff --git a/.github/workflows/external-links.yml b/.github/workflows/external-links.yml new file mode 100644 index 0000000..39a579e --- /dev/null +++ b/.github/workflows/external-links.yml @@ -0,0 +1,47 @@ +name: External link check + +# Scheduled check for external link rot (dead third-party URLs) with lychee — +# the free, no-AI complement to the existing link-check workflow (which runs +# `mint broken-links` for internal links). Config lives in lychee.toml. On +# failure it opens/updates a tracking issue instead of blocking any PR. +# +# Triggers: +# - workflow_dispatch (manual) +# - schedule (weekly, Mondays 09:00 UTC) + +on: + workflow_dispatch: + schedule: + - cron: '0 9 * * 1' + +permissions: + contents: read + issues: write + +defaults: + run: + shell: bash + +jobs: + lychee: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + + - name: Check external links + id: lychee + uses: lycheeverse/lychee-action@v2 + with: + args: "--config lychee.toml --no-progress '**/*.md' '**/*.mdx'" + fail: false + format: markdown + output: ./lychee-report.md + + - name: Open or update tracking issue on broken links + if: steps.lychee.outputs.exit_code != 0 + uses: peter-evans/create-issue-from-file@v5 + with: + title: 🔗 Broken external links detected + content-filepath: ./lychee-report.md + labels: broken-links, automated diff --git a/.github/workflows/prose-style.yml b/.github/workflows/prose-style.yml new file mode 100644 index 0000000..2a1ff9a --- /dev/null +++ b/.github/workflows/prose-style.yml @@ -0,0 +1,37 @@ +name: Prose style + +# Advisory prose/style linting on PRs — the free, no-AI replacement for +# Mintlify's "Apply style guide" workflow and the grammar half of "Fix grammar +# & typos". Rules live in .github/styles/Sei (derived from AGENTS.md and +# STYLE_GUIDE.md). Annotations are posted on *changed lines only* and never +# fail the build, so the existing heading backlog doesn't create noise. + +on: + pull_request: + +permissions: + contents: read + checks: write + pull-requests: read + +defaults: + run: + shell: bash + +jobs: + vale: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Vale + uses: errata-ai/vale-action@v2 + with: + version: 3.14.2 + reporter: github-pr-check + filter_mode: added + fail_on_error: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/seo-audit.yml b/.github/workflows/seo-audit.yml new file mode 100644 index 0000000..3f6e2ae --- /dev/null +++ b/.github/workflows/seo-audit.yml @@ -0,0 +1,28 @@ +name: SEO audit + +# Deterministic SEO + page-structure audit on every PR — the free, no-AI +# replacement for Mintlify's "Audit SEO metadata" workflow. Walks docs.json so +# it only checks published pages. Fails only on missing title/description +# (regressions); length/heading issues are warnings. See scripts/audit-seo.mjs. + +on: + pull_request: + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + - name: Audit SEO metadata and structure + run: node scripts/audit-seo.mjs diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml new file mode 100644 index 0000000..306d676 --- /dev/null +++ b/.github/workflows/spelling.yml @@ -0,0 +1,24 @@ +name: Spelling + +# Deterministic spell-check on every PR — the free, no-AI replacement for the +# spelling half of Mintlify's "Fix grammar & typos" workflow. Config + the +# allowlist of protocol terms live in _typos.toml. + +on: + pull_request: + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + typos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check spelling + uses: crate-ci/typos@master + with: + config: _typos.toml diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000..9711ca9 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,31 @@ +# Vale configuration — https://vale.sh +# Free, deterministic prose/style linting in CI: the no-AI replacement for +# Mintlify's "Apply style guide" workflow and the grammar half of "Fix grammar +# & typos". Rules in .github/styles/Sei are derived from AGENTS.md and +# STYLE_GUIDE.md. Spelling is handled by `typos` (see _typos.toml), so Vale's +# own spell-checker is disabled here to avoid double-reporting. + +StylesPath = .github/styles +MinAlertLevel = suggestion + +Vocab = Sei + +# Lint MDX as Markdown. +[formats] +mdx = md + +[*.{md,mdx}] +# Only the Sei style. typos owns spelling, and Vale's built-in Repetition rule +# false-positives on fenced code nested inside MDX/JSX components (e.g. a `bash` +# block inside ), so we don't enable the bundled `Vale` style. +BasedOnStyles = Sei + +# Skip MDX/JSX so Vale lints prose, not markup: +# - {expression} braces (e.g. cols={2}, {/* comments */}) +# - import / export statements at the top of MDX files +TokenIgnores = (\{[^}]*\}) +BlockIgnores = (?m)^(?:import|export) .*$ + +# Deprecated section (SIP-3) — don't lint it. +[cosmos-sdk/**] +BasedOnStyles = '' diff --git a/_typos.toml b/_typos.toml new file mode 100644 index 0000000..b3e55ad --- /dev/null +++ b/_typos.toml @@ -0,0 +1,39 @@ +# typos configuration — https://github.com/crate-ci/typos +# Free, deterministic spell-checking in CI: the no-AI replacement for the +# spelling half of Mintlify's "Fix grammar & typos" workflow. +# +# typos only flags *known* misspellings (not every unknown word), so the +# false-positive surface is small — the [default.extend-words] list below +# allowlists the few protocol terms it would otherwise "correct". + +[files] +extend-exclude = [ + "llms.txt", + "llms-full.txt", + "*.lock", + "package-lock.json", + "pnpm-lock.yaml", + "yarn.lock", + "assets/**", + "logo/**", + "favicons/**", + "*.svg", + "*.min.js", + "cosmos-sdk/**", + "google*.html", # Google Search Console site-verification tokens +] + +[default] +# Don't treat hex addresses / hashes as words to be spell-checked. +extend-ignore-re = ['0x[0-9a-fA-F]{6,}'] + +[default.extend-identifiers] +# "UPnP" is a real protocol name; typos splits it and flags the "Pn". +# It appears in the auto-generated config block in node/node-operators.mdx. +UPnP = "UPnP" + +[default.extend-words] +# Allowlist (word = same word). Populated from a real `typos` run over the repo. +# "maxiumum" is an upstream typo in CometBFT's config.toml comments, inlined by +# scripts/sync-default-configs.mjs — fixing it here would be reverted on re-sync. +maxiumum = "maxiumum" diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 0000000..0d86963 --- /dev/null +++ b/lychee.toml @@ -0,0 +1,45 @@ +# lychee configuration — https://lychee.cli.rs +# Checks *external* URLs for rot (404s, dead domains) on a schedule. This +# complements `mint broken-links` (which validates internal/relative links) and +# replaces the external half of Mintlify's "Fix broken links" workflow. + +# Only check web URLs — relative/internal links are mint's job. +scheme = ["https", "http"] + +# Resolve root-relative links (e.g. /evm/foo) against the live site so lychee +# doesn't warn that it can't build a URL for them... +base_url = "https://docs.sei.io" + +# Network behavior. +# Deprecated section (SIP-3) — don't check its links. +exclude_path = ["cosmos-sdk"] + +max_concurrency = 16 +max_retries = 3 +retry_wait_time = 2 +timeout = 20 +# A real browser UA avoids naive bot-blocks. +user_agent = "Mozilla/5.0 (compatible; lychee link checker; +https://github.com/sei-protocol/sei-docs)" + +# Treat rate-limiting / bot-challenge responses as OK rather than broken. +accept = ["200..=206", "301", "302", "304", "403", "429"] + +# Don't flag these — local/example hosts and domains that hard-block automated +# requests (so a failure here is a false positive, not real rot). +exclude = [ + # ...then skip the docs site itself — `mint broken-links` owns internal links. + # blog.sei.io, dashboard.sei.io, www.sei.io and all third-party URLs are still checked. + "^https?://docs\\.sei\\.io", + "^https?://localhost", + "^https?://127\\.0\\.0\\.1", + "^https?://0\\.0\\.0\\.0", + "^https?://.*\\.local", + "^https?://example\\.(com|org|net)", + "^https?://(www\\.)?(twitter|x)\\.com", + "^https?://(www\\.)?linkedin\\.com", + "^https?://(www\\.)?reddit\\.com", + "^https?://(t\\.me|discord\\.gg|discord\\.com)", +] + +# Don't check mailto: links (this is the default; set explicitly for clarity). +include_mail = false diff --git a/scripts/audit-seo.mjs b/scripts/audit-seo.mjs new file mode 100644 index 0000000..06aa8a3 --- /dev/null +++ b/scripts/audit-seo.mjs @@ -0,0 +1,227 @@ +#!/usr/bin/env node +/** + * Audits SEO metadata and basic page structure for every page referenced in + * `docs.json`. This is the free, no-AI replacement for Mintlify's "Audit SEO + * metadata" workflow — auditing is fully deterministic (only *writing* good + * metadata needs a human or an LLM). + * + * It walks the same navigation tree as `generate-llms.mjs`, so it only checks + * the pages you actually publish — not README.md, this script, or the + * deprecated cosmos-sdk section. + * + * Checks (per page): + * ERROR — file referenced in nav is missing + * ERROR — no frontmatter `title` + * ERROR — no frontmatter `description` + * WARN — title longer than MAX_TITLE chars (truncated in search results) + * WARN — description outside [DESC_MIN, DESC_MAX] chars + * WARN — body starts headings with a `# H1` (Mintlify renders the title + * from frontmatter; the body should start at `##` — see STYLE_GUIDE) + * WARN — heading levels skip (e.g. `##` followed by `####`) + * + * Exit code: 1 if any ERROR, else 0. Warnings never fail the build. + * + * Run: + * node scripts/audit-seo.mjs + * + * Env (optional): + * SEO_STRICT=1 treat warnings as errors too (fail on any finding) + */ + +import { readFile } from 'node:fs/promises'; +import { existsSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const REPO_ROOT = resolve(dirname(__filename), '..'); +const DOCS_JSON_PATH = join(REPO_ROOT, 'docs.json'); + +// SEO display thresholds (chars). Titles/descriptions outside these get +// truncated in Google results; not fatal, but worth flagging. +const MAX_TITLE = 60; +const DESC_MIN = 50; +const DESC_MAX = 160; + +// Page-path prefixes excluded from the audit (kept in sync with the llms.txt +// generator). cosmos-sdk is deprecated per SIP-3 and not SEO-maintained. +const EXCLUDED_PREFIXES = ['cosmos-sdk']; + +const STRICT = process.env.SEO_STRICT === '1'; +const IN_CI = process.env.GITHUB_ACTIONS === 'true'; + +/** Recursively pull every page path out of the docs.json navigation tree. */ +function collectPages(navigation) { + const pages = []; + function walk(node) { + if (!node) return; + if (Array.isArray(node)) { + for (const item of node) walk(item); + return; + } + if (typeof node === 'string') { + pages.push(node); + return; + } + if (typeof node !== 'object') return; + if (Array.isArray(node.pages)) walk(node.pages); + if (Array.isArray(node.groups)) walk(node.groups); + if (Array.isArray(node.tabs)) walk(node.tabs); + } + walk(navigation); + return Array.from(new Set(pages)); +} + +/** Split a page's frontmatter block from its body. Returns null frontmatter if absent. */ +function splitFrontmatter(raw) { + // Frontmatter must be the very first thing in the file: a `---` line, + // some YAML, then a closing `---` line. + if (!raw.startsWith('---')) return { frontmatter: null, body: raw, bodyStartLine: 1 }; + const lines = raw.split('\n'); + if (lines[0].trim() !== '---') return { frontmatter: null, body: raw, bodyStartLine: 1 }; + for (let i = 1; i < lines.length; i++) { + if (lines[i].trim() === '---') { + return { + frontmatter: lines.slice(1, i).join('\n'), + body: lines.slice(i + 1).join('\n'), + bodyStartLine: i + 2 + }; + } + } + return { frontmatter: null, body: raw, bodyStartLine: 1 }; +} + +/** Minimal YAML scalar reader: pulls `key: value` (handles quotes). Good enough for title/description. */ +function readScalar(frontmatter, key) { + if (!frontmatter) return null; + const re = new RegExp(`^${key}:\\s*(.*)$`, 'm'); + const m = frontmatter.match(re); + if (!m) return null; + let v = m[1].trim(); + // Strip a single layer of matching quotes. + if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) { + v = v.slice(1, -1); + } + return v.trim() || null; +} + +/** + * Scan a page body for heading problems, skipping fenced code blocks. + * Returns { h1: , skips: [{line, from, to}] }. + */ +function analyzeHeadings(body, bodyStartLine) { + const lines = body.split('\n'); + let inFence = false; + let fenceMarker = ''; + let h1Line = null; + const skips = []; + // Treat the Mintlify-rendered title as the implicit level-1 heading, so the + // first body heading is expected to be level 2. + let prevLevel = 1; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const fence = line.match(/^\s*(```+|~~~+)/); + if (fence) { + if (!inFence) { + inFence = true; + fenceMarker = fence[1][0]; + } else if (fence[1][0] === fenceMarker) { + inFence = false; + } + continue; + } + if (inFence) continue; + + const h = line.match(/^(#{1,6})\s+\S/); + if (!h) continue; + const level = h[1].length; + const lineNo = bodyStartLine + i; + if (level === 1 && h1Line === null) h1Line = lineNo; + if (level > prevLevel + 1) skips.push({ line: lineNo, from: prevLevel, to: level }); + prevLevel = level; + } + return { h1: h1Line, skips }; +} + +function relForCi(absPath) { + return absPath.startsWith(`${REPO_ROOT}/`) ? absPath.slice(REPO_ROOT.length + 1) : absPath; +} + +async function main() { + const docsJson = JSON.parse(await readFile(DOCS_JSON_PATH, 'utf8')); + const pagePaths = collectPages(docsJson.navigation) + // Skip external links and in-page anchors that can appear in nav. + .filter((p) => !/^https?:\/\//.test(p) && !p.startsWith('#')) + .filter((p) => !EXCLUDED_PREFIXES.some((prefix) => p === prefix || p.startsWith(`${prefix}/`))); + + const errors = []; + const warnings = []; + const add = (bucket, file, line, msg) => bucket.push({ file, line, msg }); + + for (const page of pagePaths) { + const mdx = join(REPO_ROOT, `${page}.mdx`); + const md = join(REPO_ROOT, `${page}.md`); + const filePath = existsSync(mdx) ? mdx : existsSync(md) ? md : null; + if (!filePath) { + add(errors, `${page}.mdx`, 1, `Page referenced in docs.json is missing on disk`); + continue; + } + const rel = relForCi(filePath); + const raw = await readFile(filePath, 'utf8'); + const { frontmatter, body, bodyStartLine } = splitFrontmatter(raw); + + const title = readScalar(frontmatter, 'title'); + const description = readScalar(frontmatter, 'description'); + + if (!title) add(errors, rel, 1, `Missing frontmatter "title"`); + else if (title.length > MAX_TITLE) + add(warnings, rel, 1, `Title is ${title.length} chars (>${MAX_TITLE}); will be truncated in search results`); + + if (!description) add(errors, rel, 1, `Missing frontmatter "description"`); + else if (description.length < DESC_MIN || description.length > DESC_MAX) + add( + warnings, + rel, + 1, + `Description is ${description.length} chars (ideal ${DESC_MIN}-${DESC_MAX})` + ); + + const { h1, skips } = analyzeHeadings(body, bodyStartLine); + if (h1 !== null) + add(warnings, rel, h1, `Body uses an H1 ("# ..."); start sections at "##" (Mintlify renders the title)`); + for (const s of skips) + add(warnings, rel, s.line, `Heading skips from H${s.from} to H${s.to} (don't skip levels)`); + } + + // Emit findings. + const emit = ({ file, line, msg }, level) => { + if (IN_CI) console.log(`::${level} file=${file},line=${line}::${msg}`); + else console.log(` ${level === 'error' ? 'ERROR' : 'warn '} ${file}:${line} ${msg}`); + }; + if (!IN_CI) console.log(`\nSEO + structure audit — ${pagePaths.length} pages\n`); + for (const e of errors) emit(e, 'error'); + for (const w of warnings) emit(w, 'warning'); + + const summary = `\n${errors.length} error(s), ${warnings.length} warning(s) across ${pagePaths.length} pages.`; + console.log(summary); + + if (IN_CI && process.env.GITHUB_STEP_SUMMARY) { + const md = [ + `### SEO + structure audit`, + ``, + `- **${errors.length}** errors, **${warnings.length}** warnings across **${pagePaths.length}** pages.`, + `` + ].join('\n'); + const { appendFile } = await import('node:fs/promises'); + await appendFile(process.env.GITHUB_STEP_SUMMARY, md); + } + + const failed = errors.length > 0 || (STRICT && warnings.length > 0); + process.exit(failed ? 1 : 0); +} + +main().catch((err) => { + console.error('❌', err); + process.exit(1); +}); From fc0ec5d67a526b1a177164fad855e7da8d954552 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 31 May 2026 02:19:19 +0300 Subject: [PATCH 2/2] docs: fix three spelling typos Surfaced by the new typos check: - node/statesync.mdx: sycing -> syncing - evm/reference.mdx: hexdecimal -> hexadecimal - evm/evm-verify-contracts.mdx: Prerequsite -> Prerequisite Co-Authored-By: Claude Opus 4.8 --- evm/evm-verify-contracts.mdx | 2 +- evm/reference.mdx | 2 +- node/statesync.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm/evm-verify-contracts.mdx b/evm/evm-verify-contracts.mdx index b7f8275..4b3a0c1 100644 --- a/evm/evm-verify-contracts.mdx +++ b/evm/evm-verify-contracts.mdx @@ -183,7 +183,7 @@ Verification status will be displayed in the plugin interface, and your verified You can batch‑verify a contract that is already verified on another chain using the community tool [Etherscan Verification by 0xngmi](https://etherscan-verification.0xngmi.com/). This copies the verified source from a "source chain" and submits it to [Seiscan](https://seiscan.io), as long as the bytecode and compiler settings match. -Prerequsite: The contract is already verified on at least one supported chain (same compiler version, optimization runs, constructor args, and library addresses as on Sei). +Prerequisite: The contract is already verified on at least one supported chain (same compiler version, optimization runs, constructor args, and library addresses as on Sei). Steps: diff --git a/evm/reference.mdx b/evm/reference.mdx index c3c4ecd..4385253 100644 --- a/evm/reference.mdx +++ b/evm/reference.mdx @@ -253,7 +253,7 @@ Object Schema: ```json { address: // The requested address. - hexValues: // An array of the hexdecimal form of the values at the given keys. + hexValues: // An array of the hexadecimal form of the values at the given keys. storageProof: // An array of storage proofs. } ``` diff --git a/node/statesync.mdx b/node/statesync.mdx index 23e3eba..78da00b 100644 --- a/node/statesync.mdx +++ b/node/statesync.mdx @@ -126,7 +126,7 @@ sudo systemctl start seid **A:** Try another statesync url in that case and inform us in the [Sei Tech Chat](https://t.me/+KZdhZ1eE-G01NmZk). -**Q:** The statesync finishes, but immediately get `AppHash` errors upon regular block sycing: +**Q:** The statesync finishes, but immediately get `AppHash` errors upon regular block syncing: **A:** Make sure that you use the latest version of the chain node when you state-sync.