Intro

Overview

W3 Registrar is a specialized software system designed for blockchain identity registrars who need to verify and validate user identities across multiple platforms. It provides an automated solution for managing identity verification requests, handling cross-platform validation, and issuing blockchain-based identity judgements.

Purpose

The primary purpose of W3 Registrar is to streamline the identity verification process for blockchain networks, particularly focusing on:

  • Automated verification of user identities across multiple platforms (Discord, Twitter, Matrix, etc.)
  • Management of verification challenges and responses
  • Integration with blockchain networks for identity judgement issuance
  • Real-time status tracking of verification processes
  • Secure storage and handling of verification data

Who Should Use This?

This software is specifically designed for:

Primary Users: Identity Registrars

  • Blockchain network registrars who need to verify user identities
  • Organizations providing identity verification services
  • Entities responsible for issuing identity judgements on blockchain networks

Core Features

1. Multi-Platform Verification

  • Supports verification across multiple platforms:
    • Discord
    • Twitter
    • Matrix
    • Email
    • Display names
    • Legal identities(out of scope)
    • Web presence(tbd)
    • GitHub accounts(tbd)
    • PGP keys(tbd)

2. Automated Challenge-Response System

  • Generates unique verification challenges
  • Handles automated response validation
  • Manages verification status tracking

3. Blockchain Integration

  • Direct integration with substrate-based blockchain networks
  • Automated judgement issuance
  • Support for multiple verification states (Pending, Done)

4. Real-Time Communication

  • WebSocket-based real-time status updates
  • Matrix bot integration for automated verification
  • Redis-based state management

5. Security Features

  • Secure token generation and validation
  • Encrypted storage of verification data
  • State persistence and recovery mechanisms

Technical Architecture

The system consists of several key components:

  1. WebSocket Server: Handles real-time communication with clients
  2. Matrix Bot: Manages automated verification through Matrix
  3. Node Listener: Monitors blockchain events and handles registration requests
  4. Redis Backend: Manages state and verification data
  5. Blockchain Interface: Handles interaction with the substrate network

Benefits

For Registrars:

  • Reduced manual verification workload
  • Automated cross-platform validation
  • Streamlined verification workflow
  • Real-time status monitoring
  • Secure and compliant verification process

For the Network:

  • Improved identity verification reliability
  • Faster verification processing
  • Reduced verification errors
  • Enhanced security and trust

Setting Up Bridges via Matrix

This guide explains how to set up messaging bridges to connect different adapters through Matrix.

Quick Setup with Beeper (Easies)t

The easiest way to set up bridges is using Beeper's client, which includes built-in bridge functionality and is hosted by Beeper. Even bridge is not self-hosted, all messages are e2ee, so messaging data on the server side is encrypted.

Initial Setup

  1. Create an account at beeper.com
  2. After registration, you'll receive a secret key - make sure to save this securely
  3. Log in to app.element.io using your Beeper account
  4. Set up a password for your account (required for bridging):
    • Use Element web client to set/reset your account password
    • Store this password securely - you'll need it for bridge connections

Bridge Configuration

Discord Bridge

  1. Connect your Discord account through Beeper
  2. Important Discord-specific steps:
    • Ensure you're in the same channels as people who need to message you
    • Configure your Discord privacy settings to allow direct messages

Twitter Bridge

  1. Connect your Discord account through Beeper
  2. Important Discord-specific steps:
    • Ensure you're in the same channels as people who need to message you
    • Configure your Discord privacy settings to allow direct messages

Advanced Self-Hosting Options

For registrars interested in self-hosting, these options are available:

Both options require:

  • Setting up and maintaining your own Matrix Synapse server

  • More technical expertise in Matrix server administration

W3Registrar backend setup

Prerequisites

  • Redis server (not needed for Docker setup)
  • config.toml (copy from config.example.toml)
  • Matrix account credentials

1. Docker Setup

  1. Create configuration:
cp config.example.toml config.toml
# Edit config.toml with your settings
# Important: use "redis" as host in [redis] section
  1. Run services:
docker compose up -d

2. Binary Installation

  1. Create service user:
sudo useradd -r -s /bin/false w3r
sudo mkdir -p /etc/w3registrar
sudo chown -R w3r:w3r /etc/w3registrar
  1. Install binary:
# Download from releases page
# https://github.com/rotkonetworks/w3registrar/releases/
sudo cp w3registrar-* /usr/local/bin/w3registrar
sudo chown w3r:w3r /usr/local/bin/w3registrar
sudo chmod 755 /usr/local/bin/w3registrar
  1. Configure:
sudo cp config.toml /etc/w3registrar/
sudo chown w3r:w3r /etc/w3registrar/config.toml
sudo chmod 600 /etc/w3registrar/config.toml
  1. Create systemd service:
sudo tee /etc/systemd/system/w3registrar.service << EOF
[Unit]
Description=Identity Registrar Service
After=network.target redis.service

[Service]
Type=simple
User=w3r
Group=w3r
ExecStart=/usr/local/bin/w3registrar
Restart=on-failure
Environment=RUST_LOG=info

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now w3registrar

3. Building from Source

# Install dependencies
sudo apt install -y build-essential pkg-config libssl-dev git

# Build
git clone https://github.com/rotkonetworks/w3registrar.git
cd w3registrar
cargo build --release

# Follow binary installation steps 1-4 above

Configuration Example

[registrar]

[registrar.polkadot]
endpoint = "wss://people-polkadot.dotters.network" # people system chain
registrar_index = 11 # your registrar index
keystore_path = "./keyfile_polkadot" # IdentityJudgement proxy private key
accountid = "1Ard..."  # registrar public key

[websocket]
host = "127.0.0.1"
port = 8080

[redis]
host = "redis"  # Use "redis" for Docker, "127.0.0.1" otherwise
port = 6379

[matrix]
homeserver = "https://matrix.beeper.com"
username = "regbot"
password = "your-password"
security_key = "EsTg A8Uh 9yFK 3uN1 16s6 WVDA gHLU kEid j9F1 iHt6 5V3u XSPs"
admins = ["@admin:matrix.org"]

Common Issues

  • Redis Connection: Check if Redis is running and host configuration
  • Matrix Login: Verify credentials and security key
  • Permissions: Ensure proper file ownership and permissions under w3r user

Redis

We use Redis as a cache to maintain application statelessness in our Kubernetes setup. This allows us to scale horizontally while keeping track of ongoing verification challenges. If Redis data is lost, users simply need to restart their verification challenges.

Architecture Overview

The application uses Redis to temporarily store verification states and challenge tokens. This eliminates the need for local state management in application instances, making them stateless and easily scalable.

Data Structure

We use hash maps (HSET/HGETALL) with composite keys to store verification states and challenge data.

Key Structure

  • Main verification state: {network}:{account_address}
  • Media-specific state: {network}:{account_address}:{media_type}

Main Verification State

HGETALL "polkadot:5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"

Fields:

  • status: Overall verification status (Done/Pending)
  • created_at: Timestamp when verification process started
  • updated_at: Timestamp of last status change
  • media_types: Comma-separated list of media accounts being verified

Example:

{
    "status": "Pending",
    "created_at": "2024-01-11T22:25:36",
    "updated_at": "2024-01-11T22:26:36",
    "media_types": "discord,twitter,matrix"
}

Media-Specific State

HGETALL "polkadot:5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY:discord"

Fields:

  • name: Username on the platform
  • status: Verification status for this specific media
  • token: Verification token

Example:

{
    "name": "patchwinner",
    "status": "Pending",
    "token": "Q8KGYC7P"
}

Examples

Storing New Verification State

# Create main verification state
redis_client.hmset(f"{network}:{address}", {
    "status": "Pending",
    "created_at": datetime.utcnow().isoformat(),
    "updated_at": datetime.utcnow().isoformat(),
    "media_types": ",".join(media_types)
})

# Create media-specific state
redis_client.hmset(f"{network}:{address}:discord", {
    "name": username,
    "status": "Pending",
    "token": generate_token()
})

Retrieving Verification State

# Get main verification state
state = redis_client.hgetall(f"{network}:{address}")

# Get media-specific state
discord_state = redis_client.hgetall(f"{network}:{address}:discord")

Frontend

Frontend application for managing identity operations on polkadot-sdk chains. The application enables users to submit setIdentity and requestJudgement operations using polkadot-api.

Features

  • Identity registration on polkadot-sdk chains
  • Integration with W3 Registrar backend
  • Real-time verification status updates
  • Support for multiple social account verifications

Development Setup

Prerequisites

Install required versions to ensure compatibility:

# Install Bun 1.1.35
curl -fsSL https://bun.sh/install | bash -s "bun-v1.1.35"

# Install NVM and Node 22
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
nvm install 22

Installation

  1. Clone the repository:
git clone https://github.com/rotkoneworks/w3registrar-www
cd w3registrar-www
  1. Install dependencies:
bun install
  1. Set up environment:
cp .env.example .env
# Edit .env with your endpoints
  1. Update scale metadata:
bunx polkadot-api@1.8.0 update
# or
bun metadata

Development Server

Start the development server:

bun dev

Visit http://localhost:3333 in your browser. The server will automatically reload on file changes.

Building

Create production build:

bun build

Chain Documentation

  • Access documentation at [docs link]
  • Generate fresh documentation:
    bunx papi-generate-docs --config .papi/polkadot-api.json --output docs/
    

Environment Configuration

Copy .env.example to .env and configure the following variables:

# WalletConnect Project ID
VITE_APP_WALLET_CONNECT_PROJECT_ID=rotko-w3-registrar

# Chain WebSocket Endpoints
VITE_APP_DEFAULT_WS_URL=wss://dev.rotko.net/people-rococo
VITE_APP_DEFAULT_WS_URL_RELAY=wss://dev.rotko.net/rococo

# Registrar Indices for Different Networks
VITE_APP_REGISTRAR_INDEX__PEOPLE_POLKADOT=19
VITE_APP_REGISTRAR_INDEX__PEOPLE_KUSAMA=17
VITE_APP_REGISTRAR_INDEX__PEOPLE_WESTEND=18
VITE_APP_REGISTRAR_INDEX__PEOPLE_PASEO=16
VITE_APP_REGISTRAR_INDEX__PEOPLE_ROCOCO=0

# API Configuration
VITE_APP_CHALLENGES_API_URL=wss://dev.rotko.net/api

# Chain Configuration
VITE_APP_AVAILABLE_CHAINS=polkadot_people,ksmcc3_people,paseo_people,rococo_people
VITE_APP_DEFAULT_CHAIN=rococo_people  # Optional

Available Scripts

  • bun dev: Start development server
  • bun build: Create production build
  • bun metadata: Update scale metadata
  • bun docs: Generate chain documentation

Integration with Backend

The frontend expects a W3 Registrar backend instance running. Configure the WebSocket endpoint in your .env file:

VITE_BACKEND_URL="wss://your-backend:8080"

Registrar testnet

To install pop-cli for the testnet or use our deployed testnet, follow these steps:

1. Clone and Run the Pop-CLI

git clone https://github.com/rotkonetworks/pop-cli
cd pop-cli
cargo run up parachain --file ~/rotko/pop-cli/tests/networks/rococo+people.toml --verbose

2. Set WebSocket Endpoint

Use either the provided endpoint or your local testnet for people-rococo:

wss://dev.rotko.net/people-rococo

3. Generate Call Data

In the Polkadot UI, navigate to Extrinsics and create a transaction to add a registrar. Copy the calldata from the generated transaction. image

Example transaction for call data extraction: Extrinsics decode tool

4. Relaychain Sudo Rights Requirement

Executing the above call from a local parachain account will fail due to lack of rights. You need sudo access at the relaychain level.

5. Create a Sudo Call on the Relaychain

Go to the relaychain’s Sudo page and submit a sudo call with the following XCM transaction:

#![allow(unused)]
fn main() {
xcmPallet::send(
    dest: XcmVersionedLocation::V4(StagingXcmV4Location {
        parents: 0,
        interior: StagingXcmV4Junctions::X1([Lookup71::Parachain(Compact(1004))])
    }),
    message: XcmVersionedXcm::V4(StagingXcmV4Xcm {
        0: StagingXcmV4Instruction::UnpaidExecution {
            weightLimit: XcmV3WeightLimit::Unlimited,
            checkOrigin: None
        },
        1: StagingXcmV4Instruction::Transact {
            originKind: XcmV3OriginKind::Superuser,
            requireWeightAtMost: SpWeightsWeightV2Weight {
                refTime: Compact(5000000000),
                proofSize: Compact(50000)
            },
            call: XcmDoubleEncoded::new(Bytes::from_hex("0x3200001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c"))
        }
    })
);
}

Submit this sudo call as Alice (the first validator in the network): image

6. Verify Registrar Creation

Watch the Explorer for events confirming the registrar was created on the parachain (people-rococo).

Secure Registrar Setup Guide

Core Architecture

The registrar setup consists of three key components:

  1. Pure Proxy (Main Registrar) - controlled by multisig, stays cold
  2. Multisig - for governance and critical operations only
  3. Identity Judgement Proxy - hot wallet for registrar operations

When to Use Multisig

Multisig is required ONLY for these critical operations:

  1. Requesting registrar rights via governance for the pure proxy
  2. Setting supported bitflags (declaring which identity fields you verify)
  3. Setting up new Identity Judgement proxy

All other operations should use the Identity Judgement proxy.

Operational Flow

Initial Setup

  1. Create pure proxy (will be your registrar address)
  2. Set up multisig (minimum 3/5 recommended)
  3. Request registrar rights via governance
  4. Set supported identity verification bitflags
  5. Create Identity Judgement proxy for server operations

Daily Operations

  • Identity Judgement proxy runs on server
  • Provides actual judgements
  • Main registrar (pure proxy) stays cold
  • No multisig needed for routine judgements

Security Model

Proxy Setup Diagram

The diagram shows the complete security setup:

  • Pure proxy at the top serves as the registrar
  • Controlled by a 3/5 multisig
  • Identity Judgement proxy connected to server hot wallet
  • Members 1-5 participating in multisig operations
  • Ownership of registrar can be assigned to new wallet/multisig

Transaction Review

CRITICAL: Always verify transactions on Polkadot.js Apps:

1. Visit: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpeople-paseo.dotters.network#/extrinsics
2. Go to 'Decode' section
3. Paste raw transaction (e.g., 0x2a0400000000000000)
4. Verify ALL parameters
5. When sharing multisig calldata, send extrinsics link for easier verification

Multisig Changes

IMPORTANT: Multisig membership cannot be changed once created. To handle member changes:

  1. Create entirely new multisig with desired members
  2. Use old multisig to give control rights to new multisig over pure proxy
  3. Use new multisig to remove old multisig's rights

This is why we use pure proxy as registrar - it allows changing the controlling multisig while maintaining the same registrar identity.

Common Operations

Setting Up Judgement Proxy

  1. Create new proxy for Identity Judgement
  2. Use multisig to authorize it
  3. Verify setup via transaction decode

Providing Judgements

  1. Use Identity Judgement proxy
  2. No multisig required
  3. Server can operate autonomously

Changing Supported Fields

  1. Requires multisig
  2. Update bitflags via pure proxy
  3. Verify via transaction decode

Identity Verification System

1. Overview

The identity verification system consists of registrars who verify specific fields of user identities. The system uses bitflags to specify verification fields and proxies for secure operation.

2. Identity Fields and Bitflags

Field Positions

Each identity field corresponds to a specific bit position in a binary number:

Position | Field         | Binary Value      | Decimal Value
---------|--------------|-------------------|---------------
9        | Discord      | 0b1000000000      | 512
8        | GitHub       | 0b0100000000      | 256
7        | Twitter      | 0b0010000000      | 128
6        | Image        | 0b0001000000      | 64
5        | PgpFingerprint| 0b0000100000     | 32
4        | Email        | 0b0000010000      | 16
3        | Matrix       | 0b0000001000      | 8
2        | Web          | 0b0000000100      | 4
1        | Legal        | 0b0000000010      | 2
0        | Display      | 0b0000000001      | 1

Common Combinations

Standard Verification (665):
Discord + Twitter + Email + Matrix + Display
1010011001 = 512 + 128 + 16 + 8 + 1 = 665

3. Setting Up a Registrar

Setting Fields

#![allow(unused)]
fn main() {
identity.setFields(registrarIndex, fields)
}

Example:

identity.setFields(0, 665)  // Sets registrar 0 to verify Display, Matrix, Email, Twitter, Discord

Field Validation

  • Chain automatically blocks judgment requests that don't match registrar's fields
  • All specified fields must be present in identity information
  • Extra fields are ignored for verification purposes

4. Proxy System

Setting Up Proxy

#![allow(unused)]
fn main() {
proxy.addProxy(delegate, proxyType, delay)
}

Parameters:

  • delegate: Hot wallet address for making judgments
  • proxyType: IdentityJudgement
  • delay: 0 (no delay for judgments)

Proxy Types Available

#![allow(unused)]
fn main() {
pub enum ProxyType {
    Any,               // Full permissions
    NonTransfer,       // Non-financial calls
    CancelProxy,       // Cancel proxy announcements
    Identity,          // All identity calls
    IdentityJudgement, // Only judgment calls
    Collator          // Collator selection calls
}
}

5. Judgment Process

Available Judgments

#![allow(unused)]
fn main() {
pub enum Judgement {
    Unknown,            // 0
    FeePaid(u128),     // 1 - Judgement Requested from registrar(index)
    Reasonable,        // 2 - Standard positive judgment
    KnownGood,         // 3
    OutOfDate,         // 4
    LowQuality,        // 5
    Erroneous         // 6 - Used for failed verifications
}
}

Making Judgments via Proxy

#![allow(unused)]
fn main() {
proxy.proxy(
    registrarAccount,
    Some(IdentityJudgement),
    identity.provideJudgement(regIndex, target, judgement, identityHash)
)
}

6. Security Considerations

Chain-Level Security

  • Automatic field validation
  • Proxy system limits exposure of registrar account
  • Identity hash changes trigger new verification requirements

Best Practices

  1. Use cold storage for main registrar account
  2. Set up proxy for daily operations
  3. Regularly verify proxy permissions
  4. Monitor identity hash changes

7. Implementation Example

Standard Setup Process

  1. Get registered as a registrar
  2. Set verification fields:
    identity.setFields(registrarIndex, 665)
    
  3. Set up proxy:
    proxy.addProxy(hotWalletAddress, IdentityJudgement, 0)
    
  4. Use hot wallet for judgments:
    proxy.proxy(registrarAccount, Some(IdentityJudgement), 
               identity.provideJudgement(...))
    

Field Verification

The system automatically ensures:

  • All required fields are present
  • Fields match registrar's bitflag specification
  • Identity hash consistency
  • Proper proxy permissions

8. Important Notes

  • Identity hashes change when verified fields are modified
  • Only specified fields are considered for verification
  • Proxy permissions cannot be exceeded
  • Chain enforces all validation rules
  • Registrar must handle both successful (Reasonable) and failed (Erroneous) cases

FAQ

Q: Why are we facing M_UNKNOWN error 500 from the Matrix Synapse server?

Error Details

2025-01-11T03:47:38.385306Z ERROR w3registrar::matrix: 178: can't sync duo to Http(
    Api(
        Server(
            ClientApi(
                Error {
                    status_code: 500,
                    body: Standard {
                        kind: Unknown,
                        message: "synapse sync failed with status 400 Bad Request: internal error generating sync response",
                    },
                },
            ),
        ),
    ),
)

Answer

This error can occur if your account has exceeded the usual limit of 20 active Device IDs. When this happens, the server may fail to handle /sync requests due to the overhead of managing too many devices.

How to Check for Too Many Devices

Use the following curl command to list all Device IDs associated with your account:

curl -v "https://matrix.beeper.com/_matrix/client/v3/devices" \
-H "Authorization: Bearer <your_access_token>"

Example response:

{
  "devices": [
    {"device_id": "AEQJNOWHXG", "display_name": "Beeper Desktop (Linux)", "last_seen_ip": "", "last_seen_ts": 1730201177000},
    {"device_id": "BGKCFSZTRN", "display_name": "Beeper Desktop (Linux)", "last_seen_ip": "", "last_seen_ts": 1733668251000},
    {"device_id": "BVKAPCXANW", "display_name": "w3r", "last_seen_ip": "", "last_seen_ts": 1736377586000},
    ...
  ]
}

Solution: Remove Unnecessary Devices

Identify and remove devices that are no longer in use. Focus on devices with:

  • A last_seen_ts of 0 or very old timestamps.
  • Duplicate or generic display names.

Example Cleanup

To remove specific devices, use the /delete_devices endpoint:

curl -X POST "https://matrix.beeper.com/_matrix/client/v3/delete_devices" \
-H "Authorization: Bearer <your_access_token>" \
-H "Content-Type: application/json" \
-d '{
  "devices": ["FJHQEVOVOD", "KSQHECIAAA", "KZIRBZPAHB"]
}'

If required, include authentication:

curl -X POST "https://matrix.beeper.com/_matrix/client/v3/delete_devices" \
-H "Authorization: Bearer <your_access_token>" \
-H "Content-Type: application/json" \
-d '{
  "devices": ["FJHQEVOVOD", "KSQHECIAAA", "KZIRBZPAHB"],
  "auth": {
    "type": "m.login.password",
    "user": "@w3r:beeper.com",
    "password": "your_password"
  }
}'

Verify Cleanup

After removing devices, verify the remaining devices:

curl -v "https://matrix.beeper.com/_matrix/client/v3/devices" \
-H "Authorization: Bearer <your_access_token>"

Prevent Future Issues

  1. Reuse Existing Tokens: Avoid logging into the same account unnecessarily.
  2. Logout Unused Sessions: Regularly clean up old sessions.
  3. Monitor Active Devices: Periodically review the list of active devices to ensure it stays manageable.

By keeping the number of active Device IDs below the limit, you can avoid these errors and ensure smoother synchronization with the Matrix server.

Support

Thank you for using W3 Registrar! If you need assistance, feel free to contact us or explore our resources below.

Contact Information

  • Matrix Chat
    Join our support channel on Matrix for real-time assistance:
    #w3reg:matrix.org

Resources

We’re here to support you and make your experience with W3 Registrar seamless!