Files

🏛️ KYC Council Backend

Backend simulation of pallet-collective voting for KYC approvals.

📋 Overview

Purpose: Decentralized KYC approval system without runtime changes

Architecture:

  • Backend tracks council votes (in-memory)
  • 60% threshold (e.g., 7/11 votes)
  • Auto-executes approve_kyc when threshold reached
  • Uses SUDO account to sign blockchain transactions

🔗 Chain Flow

User applies → Blockchain (PENDING) → Council votes → Backend auto-approves → Welati NFT minted

Why SUDO account?

  • identityKyc.approveKyc() requires EnsureRoot origin
  • Backend signs transactions on behalf of council
  • Alternative: Change runtime to accept council origin (not needed for MVP)

🚀 Installation

1. Install Dependencies

cd /home/mamostehp/pwap/backend
npm install

2. Configure Environment

cp .env.example .env
nano .env

Required variables:

WS_ENDPOINT=wss://ws.pezkuwichain.io
SUDO_SEED=your_sudo_seed_phrase_here
PORT=3001

⚠️ Security Warning: Keep SUDO_SEED secret! Use a dedicated account for KYC approvals only.

3. Start Server

Development (with hot reload):

npm run dev

Production:

npm start

📡 API Endpoints

Council Management

Add Council Member

POST /api/council/add-member
{
  "address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
  "signature": "0x..." // TODO: Implement signature verification
}

Remove Council Member

POST /api/council/remove-member
{
  "address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}

Get Council Members

GET /api/council/members

Response:

{
  "members": ["5DFw...Dwd3", "5Grw...utQY"],
  "totalMembers": 2,
  "threshold": 0.6,
  "votesRequired": 2
}

Sync with Noter Tiki Holders

POST /api/council/sync-notaries

Auto-fetches first 10 Noter tiki holders from blockchain and updates council.


KYC Voting

Propose KYC Approval

POST /api/kyc/propose
{
  "userAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
  "proposerAddress": "5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3",
  "signature": "0x..."
}

Logic:

  • Proposer auto-votes AYE
  • If threshold already met (e.g., 1/1 member), auto-executes immediately

Vote on Proposal

POST /api/kyc/vote
{
  "userAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
  "voterAddress": "5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3",
  "approve": true,
  "signature": "0x..."
}

Approve: true = AYE, false = NAY

Auto-execute: If votes reach threshold, backend signs and submits approve_kyc transaction.

Get Pending Proposals

GET /api/kyc/pending

Response:

{
  "pending": [
    {
      "userAddress": "5Grw...utQY",
      "proposer": "5DFw...Dwd3",
      "ayes": ["5DFw...Dwd3", "5HpG...vSKr"],
      "nays": [],
      "timestamp": 1700000000000,
      "votesCount": 2,
      "threshold": 7,
      "status": "VOTING"
    }
  ]
}

🔐 Council Membership Rules

Initial Setup

  • 1 member: Founder delegate (hardcoded: 5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3)
  • Threshold: 1/1 = 100% (single vote approves)

Growth Path

  1. Add Noter holders: Use /api/council/sync-notaries to fetch first 10 Noter tiki holders
  2. Council size: 11 members (1 founder + 10 notaries)
  3. Threshold: 7/11 = 63.6% (60% threshold met)

Automatic Updates

  • When Noter loses tiki → Remove from council
  • When new Noter available → Add to council (first 10 priority)
  • If no Notaries available → Serok (president) can appoint manually

🧪 Testing

Test 1: Single Member (Founder Only)

# 1. Start backend
npm run dev

# 2. Get council members
curl http://localhost:3001/api/council/members

# Expected: 1 member (founder delegate)

# 3. User applies KYC (via frontend)
# 4. Propose approval
curl -X POST http://localhost:3001/api/kyc/propose \
  -H "Content-Type: application/json" \
  -d '{
    "userAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
    "proposerAddress": "5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3"
  }'

# Expected: Auto-execute (1/1 threshold reached)

Test 2: 3 Members

# 1. Add 2 notaries
curl -X POST http://localhost:3001/api/council/add-member \
  -d '{"address": "5HpG...vSKr"}'

curl -X POST http://localhost:3001/api/council/add-member \
  -d '{"address": "5FLe...dXRp"}'

# 2. Council: 3 members, threshold = 2 votes (60% of 3 = 1.8 → ceil = 2)

# 3. Propose
curl -X POST http://localhost:3001/api/kyc/propose \
  -d '{
    "userAddress": "5Grw...utQY",
    "proposerAddress": "5DFw...Dwd3"
  }'

# Status: 1/2 (proposer voted AYE)

# 4. Vote from member 2
curl -X POST http://localhost:3001/api/kyc/vote \
  -d '{
    "userAddress": "5Grw...utQY",
    "voterAddress": "5HpG...vSKr",
    "approve": true
  }'

# Expected: Auto-execute (2/2 threshold reached) ✅

📊 Monitoring

Health Check

GET /health

Response:

{
  "status": "ok",
  "blockchain": "connected",
  "sudoAccount": "5DFw...Dwd3",
  "councilMembers": 11,
  "pendingVotes": 3
}

Console Logs

🔗 Connecting to PezkuwiChain...
✅ Sudo account loaded: 5DFw...Dwd3
✅ Connected to blockchain
📊 Chain: PezkuwiChain
🏛️  Runtime version: 106

🚀 KYC Council Backend running on port 3001
📊 Council members: 1
🎯 Threshold: 60%

📝 KYC proposal created for 5Grw...utQY by 5DFw...Dwd3
📊 Votes: 1/1 (1 members, 60% threshold)
🎉 Threshold reached for 5Grw...utQY! Executing approve_kyc...
📡 Transaction status: Ready
📡 Transaction status: InBlock
✅ KYC APPROVED for 5Grw...utQY
🏛️  User will receive Welati NFT automatically

🔄 Integration with Frontend

Option A: Direct Backend API Calls

Frontend calls backend endpoints directly (simpler for MVP).

// Propose KYC approval
const response = await fetch('http://localhost:3001/api/kyc/propose', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    userAddress: application.address,
    proposerAddress: selectedAccount.address,
    signature: await signMessage(...)
  })
});

Option B: Blockchain Events + Backend Sync

Backend listens to blockchain events and auto-tracks proposals (future enhancement).


🚨 Security Considerations

  1. SUDO Account Protection:

    • Use dedicated hardware wallet (Ledger recommended)
    • Only use for KYC approvals, nothing else
    • Consider multi-sig in production
  2. Signature Verification:

    • TODO: Implement Polkadot signature verification
    • Prevent vote spam from non-members
  3. Rate Limiting:

    • Add rate limiting to API endpoints
    • Prevent DoS attacks
  4. Audit Trail:

    • Log all votes to database (future enhancement)
    • Track council member changes

📝 TODO

  • Implement signature verification
  • Add database persistence (replace in-memory Maps)
  • Add rate limiting middleware
  • Add automated council sync cron job
  • Add multi-sig support for sudo account
  • Add audit logging
  • Add Prometheus metrics
  • Add Docker support

📞 Support

Backend Developer: [Your contact] Runtime Issues: Check /Pezkuwi-SDK/pezkuwi/pallets/identity-kyc Frontend Integration: See /pwap/ADMIN_KYC_GUIDE.md


Version: 1.0 (Backend Council MVP) Last Updated: 17 Kasım 2025