diff --git a/README.md b/README.md index d61a7489..9f2c1e97 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,198 @@ # Dither Service -The **Dither Service** utilizes **event-sourcing data** to deterministically rebuild application state. This is achieved by processing events streamed directly from cosmos-based chains, specifically **AtomOne**. +Dither is a memo-based social protocol that runs on the AtomOne blockchain. This repository contains the full reference implementation: the blockchain reader that interprets `dither.*` memos, the REST API that reconstructs application state, and the Vue SPA that renders the social feed. The goal of this document is to give new stewards enough context to run, extend, and eventually transfer custody of the platform safely. -## πŸš€ Getting Started (Usage) +## Table of Contents -To quickly spin up the entire Dither Service and its components, install [Tilt](https://tilt.dev) and run: +- [Dither Service](#dither-service) + - [Table of Contents](#table-of-contents) + - [System Architecture](#system-architecture) + - [Transaction Lifecycle](#transaction-lifecycle) + - [Package Topology](#package-topology) + - [Running the Stack Locally](#running-the-stack-locally) + - [Prerequisites](#prerequisites) + - [Quick Start with Tilt](#quick-start-with-tilt) + - [Manual Workflow](#manual-workflow) + - [Required Environment Variables](#required-environment-variables) + - [Operational Responsibilities](#operational-responsibilities) + - [Production Deployment Checklist](#production-deployment-checklist) + - [Developer Workflow](#developer-workflow) + - [Installing \& Bootstrapping](#installing--bootstrapping) + - [Testing](#testing) + - [Linting \& Formatting](#linting--formatting) + - [Hot Reload](#hot-reload) + - [Support \& Escalation](#support--escalation) + - [Reference Material](#reference-material) -```sh +## System Architecture + +``` + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Wallet Client β”‚ β”‚ reader-main β”‚ β”‚ api-main β”‚ + β”‚ (Keplr/Leap/etc) │──────▢│ (ChronoState app) │──────▢│ (Elysia + Postgres) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ PostgreSQL (db) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ frontend-main β”‚ + β”‚ (Vue 3 + Vite) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +- **Wallet Client**: Users broadcast `MsgSend` transactions on AtomOne with a `dither.*` memo. PHOTON fees/tips are sent to a community-controlled address. +- **`reader-main`**: A ChronoState application that tails AtomOne blocks, extracts memos, enriches them, and forwards normalized actions to the REST API using a shared `AUTH` secret. +- **`api-main`**: An ElysiaJS service backed by Postgres and Drizzle ORM. It verifies authorization, persists posts/replies/follows, and exposes REST endpoints consumed by the frontend. +- **PostgreSQL**: Stores the canonical application state (feed, replies, notifications, moderator actions). +- **`frontend-main`**: A Vue 3 SPA that renders the social feed and manages wallet interactions via Cosmos SDK libraries. + +## Transaction Lifecycle + +1. **Compose & Sign**: A wallet (Keplr, Leap, Cosmostation) sends `MsgSend` with `memo = dither.Post("hello world")`, denomination `uphoton`, recipient `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep`. +2. **On-Chain Commit**: AtomOne includes the transaction in a block. The memo and PHOTON transfer are public and immutable. +3. **Reader Ingestion**: `reader-main` streams the block, detects the `dither.*` memo, normalizes the payload, and calls `api-main` with the parsed data plus the original transaction metadata. +4. **API Persistence**: `api-main` validates the request (AUTH header, memo length), writes to Postgres via prepared statements, triggers side effects like notifications, and confirms back to the reader. +5. **Frontend Consumption**: `frontend-main` fetches paginated feeds and notifications from `api-main` using Vue Query. When a user loads the app, they see the new post pulled from Postgres. +6. **Optional Integrations**: Discord webhooks, CLI tools, or future data pipelines can subscribe to the same REST endpoints or replicate the reader logic. + +> [!IMPORTANT] +> All PHOTON fees/tips are directed to `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep` for the interim. Stewardship requires rotating this address to a multi-party key and eventually migrating to DAO-controlled governance. + +## Package Topology + +| Package | Purpose | +|-------------------------------------|-------------------------------------------------------------------------| +| `packages/api-main` | REST API (ElysiaJS + Drizzle + Postgres) | +| `packages/reader-main` | ChronoState reader that parses `dither.*` memos | +| `packages/frontend-main` | Vue 3 SPA for browsing and posting | +| `packages/lib-api-types` | Shared TypeScript types between reader and API | +| `packages/tool-network-spammer` | Utility script for stress testing the network | +| `packages/cli` | CLI tool that fetches recent `dither.*` messages | +| `docs/` | Protocol docs, FAQs, and runbook drafts | +| `Tiltfile` | Local orchestration with Tilt | +| `docker-compose.yml` | Development docker services (Postgres, reader, API) | + +## Running the Stack Locally + +### Prerequisites +- Node.js 20+ +- pnpm 8+ +- Docker Desktop or compatible engine +- Optional: [Tilt](https://tilt.dev/) for orchestrating services + +### Quick Start with Tilt +```bash +# Install dependencies +pnpm install + +# Provide required secrets in .env or shell (see next section) +export AUTH="local-shared-secret" +export JWT="$(openssl rand -hex 64)" +export PG_URI="postgresql://default:password@localhost:5432/postgres" + +# Launch the full stack tilt up +# Dashboard: http://localhost:10350/ +``` + +### Manual Workflow +```bash +# Install dependencies +pnpm install + +# Start Postgres, reader, and API +docker compose up -d --build + +# Seed database schema (first run) +pnpm --dir packages/api-main db:push + +# Start frontend +cd packages/frontend-main +pnpm dev # served at http://localhost:5173 ``` -You can vist Tilt dashboard at [http://localhost:10350/](http://localhost:10350/) +> [!NOTE] +> The API auto-generates a JWT secret if `process.env.JWT` is missing. This behavior is slated for removal; always set a stable value in development and production to avoid session churn. + +## Required Environment Variables + +| Variable | Component | Description | +|-------------|------------------|---------------------------------------------------------------------------------------------| +| `AUTH` | reader + API | Shared secret that authorizes reader requests. Must be identical across reader/API. | +| `JWT` | API | Secret used to sign authentication cookies. Must be long, random, and managed per env. | +| `PG_URI` | API | PostgreSQL connection string. Example: `postgresql://user:pass@host:5432/dbname`. | +| `JWT_STRICTNESS` | API | Controls cookie attributes (`lax`, `strict`, `none`). Defaults to `lax` if unset. | +| `DISCORD_WEBHOOK_URL` | API | Optional webhook for post notifications. Empty string disables Discord integration. | +| `API_URLS` | reader | Comma-separated list of API base URLs. | +| `RECEIVER` | reader | AtomOne address that receives PHOTON tips (currently the community fund address). | +| `MEMO_PREFIX` | reader | Memo prefix to parse (defaults to `dither.`). | + +> [!IMPORTANT] +> Explicitly set these variables in production. Relying on the defaults (`'default'`, random JWT) will break authentication or leave the reader in a retry loop. + +## Operational Responsibilities -## Project Structure Explanation +- **Fund Key Custody**: All PHOTON tips are sent to `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep`. Rotate this to a stewardship-controlled key immediately, then plan a multi-sig/DAO migration for the first official release. +- **Deployment Targets**: Historically deployed via Fly.io (`fly.mainnet.toml`, `fly.testnet.toml`) and Netlify (frontend). Tilt simplifies local orchestration but still requires explicit secrets. +- **Secrets Management**: Avoid committing `.env` files. Coordinate rotation across reader/API; mismatched `AUTH` causes silent reader failure. +- **Monitoring & Alerts**: There is no automated observability. Add basic health checks (`/v1/health`) and post-deploy smoke tests before shipping changes to mainnet. +- **Discord Webhooks**: Currently synchronous; expect higher latency if Discord is slow. Consider moving to an async queue. +- **Rate Limiting**: Implemented in Postgres with per-second cleanup. Monitor table growth and plan migration to Redis or Cloudflare KV for production scale. -### [api-main](./packages/api-main/README.md) +## Production Deployment Checklist -A REST Endpoint Provider for post feeds, and looking up individual posts. +1. Confirm `AUTH` and `JWT` secrets are provisioned in the target environment and match reader/API. +2. Ensure Postgres migrations (`pnpm --dir packages/api-main db:push`) are applied before rolling services. +3. Rotate the fund receiver address if ownership is transitioning; document the custodian. +4. Deploy `reader-main` and `api-main` sequentially to avoid memo backlogs. +5. Run smoke tests: `GET /v1/health`, `GET /v1/feed?limit=5`, create a test post on staging. +6. Verify Discord webhook (if configured) is delivering responses; disable if unavailable. +7. Announce deploy window to validators/community if service interruptions are expected. +8. After deploy, monitor logs for reader authorization failures and rate limiter churn. + +## Developer Workflow + +### Installing & Bootstrapping +```bash +pnpm install +pnpm -r build # optional: build all packages +``` + +### Testing +```bash +pnpm --dir packages/api-main test +pnpm --dir packages/reader-main test +# Frontend currently has no automated tests; linting covers Vue components. +``` + +### Linting & Formatting +```bash +pnpm lint # runs ESLint across packages +pnpm format # if configured +``` -### [reader-main](./packages/reader-main/README.md) +### Hot Reload +- `pnpm dev`: Run in `packages/frontend-main` to enable Vite hot reload. +- Docker Compose: Mounts source directories for reader/API so code changes reflect automatically. -A blockchain reader that parses memos, and re-routes them through an event system. +## Support & Escalation -### [cli](./packages/cli) +- **Issue Tracker**: Use GitHub issues for bugs, enhancements, and audit follow-ups. Reference `DITHER_ISSUE_MANAGEMENT_PLAN.md` for triage workflow. +- **Operational Incidents**: If reader β†’ API communication fails (AUTH mismatch, network issues), expect the reader to retry indefinitely. Investigate secrets first. +- **Community Channels**: Announce significant outages or fund key changes in the AtomOne Discord/Telegram servers. +- **Security Contact**: Report vulnerabilities privately to the stewardship team before disclosure. -A small reader that pulls all `dither.` messages from the chain in the last 100 blocks. +## Reference Material -### [frontend-main](./packages/frontend-main/README.md) +- [`packages/frontend-main/ARCHITECTURE.md`](./packages/frontend-main/ARCHITECTURE.md): Detailed frontend component guide. +- [`packages/frontend-main/STYLEGUIDE.md`](./packages/frontend-main/STYLEGUIDE.md): UI conventions and design tokens. +- [`packages/api-main/README.md`](./packages/api-main/README.md): Additional API usage notes. +- [`packages/reader-main/README.md`](./packages/reader-main/README.md): Reader configuration hints. +- [`docs/guides/protocol.md`](./docs/guides/protocol.md): Memo protocol reference and CLI tips. +- [`docs/guides/FAQ.md`](./docs/guides/FAQ.md): Frequently asked questions for users. -An frontend Single Page Application for Dither as a whole. +For outstanding issues and remediation tracking, consult `DITHER_ISSUE_MANAGEMENT_PLAN.md` and the GitHub issue tracker. Handle secrets and custody before ramping up adoption. The current goal is stability first, growth second. diff --git a/docs/guides/FAQ.md b/docs/guides/FAQ.md index 383b5bf0..4b2ea880 100644 --- a/docs/guides/FAQ.md +++ b/docs/guides/FAQ.md @@ -1,32 +1,94 @@ -!!! Hey Listen! -We will never ask you for your private keys, or mnemonic phrase. -Never share this information with anyone else. -!!! +# Frequently Asked Questions -# FAQ +> [!IMPORTANT] +> Dither will never ask for your mnemonic or private key. Beware of impostor sites or bots that request seed phrases. Always verify URLs and bot usernames before interacting. -Information for people who have questions about Dither and how it works. +## About Dither -## How does dither work? +**What is Dither?** +Dither is a memo-based social protocol built on the AtomOne blockchain. Every post, reply, and reaction is a real transaction recorded on-chain. The open-source reader/API/frontend stack in this repository provides the canonical implementation. -Dither pushes messages to the AtomOne blockchain using a specific format. +**Why run social posts on-chain?** +On-chain posts are censorship-resistant, timestamped, and permanently verifiable. Governance communities (validators, DAO delegates) can publish positions that cannot be altered or removed by a centralized platform. -For posting, the memo must be `dither.Post("My message goes here")` +## Posting & Fees -As long as the message is sent to the address `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep` it will be indexed. +**How do I post?** +Use the web app ([dither.chat](https://dither.chat)) or broadcast a `MsgSend` transaction with a `dither.Post("message")` memo via CLI. See [`usage.md`](./usage.md) for step-by-step instructions. -## Can I upload images? +**Why does posting cost PHOTON?** +Each post/reaction burns a fraction of a PHOTON to cover indexing operations and validator costs. Typical fees are under 0.01 PHOTON (fractions of a cent). -No, instead you can link to other third-party providers who will be image hosts. This prevents nefarious content from being uploaded to the chain. It's important to understand that Dither is a text-only service. +**Can I post for free?** +Not currently. Fee grants may be introduced later, but the protocol expects a small PHOTON payment to prevent spam and fund operations. -## How do I post without Keplr? +## Content & Features -If you are using a cli application like `atomoned` you can do a simple bank transfer to `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep` with `dither.Post("My message goes here")` to post a message. +**Is there a character limit?** +Yes. Memos are capped at 512 bytes. Longer messages must be split or linked externally. -## Why does dither cost PHOTON? +**Can I upload images or files?** +No. Dither stores plain text only. Link to content hosted on third-party services if needed. -Dither's indexing fee is exceptionally small and a mere fraction of a cent. This fee is to cover the operational cost of keeping our service alive. This tiny fee allows us to index your message, reply, or like. The rest is paid to the network validators who process and permanently store the data on the blockchain. +**Can posts be deleted?** +Posts remain on-chain permanently. `dither.Remove` marks them as removed in the off-chain index so the frontend can hide them, but the original transaction remains accessible. -## Can messages be deleted? +**Does Dither use algorithms or ranking?** +No. The current frontend renders chronological feeds. Communities can build alternative frontends if they want curated or algorithmic views. -No, they cannot be deleted. However, Dither does reserve the right to hide a message. However, you as a user will always have access to these messages as they are **always available on-chain, if you go looking for them**. \ No newline at end of file +## Wallet & Security + +**Which wallets are supported?** +Keplr, Leap, and Cosmostation for AtomOne. Desktop browsers require the extension; mobile users should open Dither inside the wallet’s in-app browser. + +**What permissions does Dither need?** +You sign a session message (no funds move) and then approve transactions when posting. Dither never gains spending authority beyond the specific transactions you sign. + +**What if my session keeps expiring?** +Sessions last ~3 days. API restarts currently rotate JWT secrets, forcing re-authentication. This behavior is being addressed; for now, re-sign when prompted. + +## Protocol Details + +**Where are the posts stored?** +On AtomOne. The receiver address is currently `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep`. Reader services fetch from the blockchain and persist normalized state in Postgres for fast querying. + +**How are replies and reactions encoded?** +Replies: `dither.Reply(parentHash, "message")` +Likes: `dither.Like(targetHash)` +Dislikes: `dither.Dislike(targetHash)` +Flags: `dither.Flag(targetHash)` +Follow: `dither.Follow(address)` +See [`protocol.md`](./protocol.md) for the full catalogue. + +**What happens if someone sends a malformed memo?** +The reader skips transactions that fail validation (wrong prefix, wrong address, memo too long, etc.). The memo remains on-chain, but it won't appear in the indexed feed. + +## Moderation & Governance + +**Can moderators remove content?** +Moderators can hide content in the off-chain index, preventing it from appearing in the frontend. They cannot delete on-chain data. Moderator actions are logged via API endpoints, not public memos. + +**Who controls the PHOTON fund address?** +Historically, a single maintainer. Stewardship is rotating the key to a multi-party custodial model and planning a DAO governance structure. Check the main README and release notes for updates. + +**How do I report abuse?** +File an issue on GitHub or contact the stewardship team via community channels (Discord, Telegram). Include links to the relevant transaction hashes. + +## Troubleshooting + +**My post isn't showing up. Why?** +Check the transaction on any AtomOne explorer to confirm it succeeded. If it did, but the post is missing, the reader or API may be experiencing issues. Check status channels or GitHub issues. + +**I'm seeing β€œinsufficient funds” errors.** +Ensure you have enough PHOTON for the burn and ATONE for network fees. Wallets typically require both balances to complete a transaction. + +**I can’t connect my wallet.** +Make sure the wallet has the AtomOne network configured. In Keplr, open Settings β†’ Manage Chain Visibility β†’ enable AtomOne. + +## Further Reading + +- [`usage.md`](./usage.md): End-user guide to connecting wallets and posting. +- [`protocol.md`](./protocol.md): Detailed memo formats and validation rules. +- [`README.md`](../../README.md): Architecture and operational overview. + +If your question isn’t covered, open an issue or contact the stewardship team directly. Dither is evolving quickly, so feedback and contributions are welcome. \ No newline at end of file diff --git a/docs/guides/protocol.md b/docs/guides/protocol.md index 3932f3e5..5e45e788 100644 --- a/docs/guides/protocol.md +++ b/docs/guides/protocol.md @@ -45,4 +45,10 @@ dither.Dislike("0xjkl012...") // Flag: Expects a single argument (the PostHash to flag). dither.Flag("0xmnp345...") -``` \ No newline at end of file +``` + +- **On-Chain Commit**: AtomOne includes the transaction in a block. The memo and PHOTON transfer are public and immutable. +- **Frontend Consumption**: `frontend-main` fetches paginated feeds and notifications from `api-main` using Vue Query. When a user loads the app, they see the new post pulled from Postgres. +- **Optional Integrations**: Discord webhooks, CLI tools, or future data pipelines can subscribe to the same REST endpoints or replicate the reader logic. + +> Document updates should accompany any protocol change. If new memo signatures are introduced, update this guide, the reader parser (`packages/reader-main/src/messages`), and shared type definitions (`packages/lib-api-types`). diff --git a/docs/guides/usage.md b/docs/guides/usage.md index bf0d558b..5ceeb211 100644 --- a/docs/guides/usage.md +++ b/docs/guides/usage.md @@ -1,57 +1,96 @@ -!!! Hey Listen! -We will never ask you for your private keys, or mnemonic phrase. -Never share this information with anyone else. -!!! +# Usage Guide -# Usage +Dither lets you publish posts, replies, and reactions directly on the AtomOne blockchain. Every action is a live transaction, so you need a compatible wallet, PHOTON for fees, and a basic understanding of how the protocol works. This guide walks through setup, posting, troubleshooting, and best practices. -Dither is a blockchain first application, meaning you will need an extension such as [Keplr](https://www.keplr.app) to post to the website directly. However, there are alternative ways to post to the protocol in an offline way. +## Safety Notice -## What _YOU_ need +> [!IMPORTANT] +> Never share your mnemonic, private keys, or wallet passwords. Dither maintainers will never ask for them. Verify URLs and bot usernames before interactingβ€”phishing attempts often imitate legitimate tooling. -1. AtomOne Address / Cosmos Account -2. PHOTON tokens on AtomOne +## Requirements -## Install Keplr +1. **Wallet**: Keplr, Leap, or Cosmostation with AtomOne support. +2. **AtomOne address**: Provided by your wallet once the chain is enabled. +3. **PHOTON balance**: Required for posting fees. Acquire by + - Swapping on Osmosis ([app.osmosis.zone](https://app.osmosis.zone/assets/PHOTON)), or + - Minting from ATONE ([How to mint PHOTON](https://cogwheel.zone/blog/how-to-mint-photon)). +4. **Browser**: Chrome, Firefox, Edge (extensions) or a mobile wallet with in-app browser. -Below are the official links to the Keplr extension for Cosmos based chains. +## Connect Your Wallet -- [Chrome Store](https://chrome.google.com/webstore/detail/keplr/dmkamcknogkgcdfhhbddcghachkejeap?hl=en) -- [Firefox](https://addons.mozilla.org/en-US/firefox/addon/keplr/) -- [Edge](https://microsoftedge.microsoft.com/addons/detail/keplr/ocodgmmffbkkeecmadcijjhkmeohinei) - -## Connect to Dither - -Dither uses your account address associated with the AtomOne chain to post. - -**This means you will also need PHOTON to post to the chain.** - -You can [obtain PHOTON on Osmosis](https://app.osmosis.zone/assets/PHOTON). - -Alternatively, you can [Mint Photon if you have ATONE](https://cogwheel.zone/blog/how-to-mint-photon). - -To connect your wallet click on `Connect Wallet` or the `Wallet Icon`. +1. Go to [https://dither.chat](https://dither.chat). +2. Click `Connect Wallet` in the header. +3. Choose Keplr, Leap, or Cosmostation. +4. Approve the connection request in your wallet. ![](./images/connect-wallet.png) -## Select a Wallet +## Authorize Your Session -Select a wallet such as Keplr, Leap, or Cosmostation - -![](./images/select-wallet.png) - -## Sign a Message - -You will be prompted to sign a message. - -This message is used as an identifier to pull notifications from our database. +After connecting, the site asks you to sign a one-time session message: +- Confirms you control the wallet; no funds move. +- Allows the backend to issue a short-lived JWT cookie for notifications. +- Required whenever you clear cookies or switch browsers. ![](./images/sign-message.png) -## Post! +> [!NOTE] +> Sessions currently last about three days. API restarts also invalidate sessions until you re-sign. -Once you are signed in you will be able to post! +## Create a Post -![](./images/new-post.png) +1. Click `New Post`. +2. Enter up to 512 bytes of text (plain text only; link to external media if needed). +3. Press `Post`. +4. Review the transaction in your wallet, confirm the PHOTON burn, and approve. +5. Wait a few seconds for AtomOne to include the transaction. Once the reader picks it up, the post appears in the feed. -![](./images/new-post-dialog.png) \ No newline at end of file +![](./images/new-post.png) +![](./images/new-post-dialog.png) + +## Replies, Reactions, Follows + +- **Reply**: `Reply` button β†’ write response β†’ approve TX (`dither.Reply(...)`). +- **Like / Dislike / Flag**: Click the corresponding icon; PHOTON amount shown under the button is burned when you sign (`dither.Like(...)`, etc.). +- **Follow / Unfollow**: Buttons on a profile issue `dither.Follow(address)` or `dither.Unfollow(address)`. + +## CLI Posting (Advanced) + +```bash +atomoned tx bank send \ + \ + atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep \ + 1000uphoton \ + --chain-id atomone-1 \ + --fees 2500uatone \ + --memo 'dither.Post("Hello from CLI")' \ + --from +``` + +Key points: +- Receiver **must** be `atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep`. +- Memo must match a supported action signature (see [`protocol.md`](./protocol.md)). +- Fees are paid in ATONE (uatone); PHOTON amount is the burned tip. + +## Troubleshooting + +| Issue | Suggested Fix | +|-------|---------------| +| Wallet not detected | Unlock the extension; on mobile, open dither.chat inside the wallet’s in-app browser. | +| β€œInsufficient funds” | Ensure you have both PHOTON (for burn) and ATONE (for fees). | +| Post missing from feed | Verify the transaction on any AtomOne explorer. If it succeeded on-chain but is missing in the feed, the reader or API may be experiencing issuesβ€”check community status channels. | +| Session expires frequently | Re-sign the session message. This currently happens after deployments; a permanent fix is planned. | +| Stuck signing transaction | Re-enable the AtomOne chain in your wallet settings (e.g., Keplr β†’ Settings β†’ Manage Chain Visibility). | + +## Best Practices + +- Keep a buffer of PHOTON (e.g., 5–10 PHOTON) for reactions and replies. +- Bookmark the official fund address to avoid phishing. +- Rate limiting: the API allows roughly 10 write requests per minute per IP. Scripts should respect backoff on `429` responses. +- For moderation issues or concerns about abuse, contact the stewardship team via GitHub or community channels. + +## Next Steps + +- Read [`protocol.md`](./protocol.md) for memo schemas if you plan to automate postings. +- Consult [`FAQ.md`](./FAQ.md) for answers about moderation, content permanence, and wallet support. +- Review the repository [`README`](../../README.md) for architecture and operational context. \ No newline at end of file