diff --git a/.env b/.env
new file mode 100644
index 00000000..6755eaab
--- /dev/null
+++ b/.env
@@ -0,0 +1,2 @@
+PI_SECRET=SXXXXXXXXXXXXXXXXXXXXXXXX
+CONTRACT_ID=TEST123
diff --git a/App.js b/App.js
new file mode 100644
index 00000000..85ec68c2
--- /dev/null
+++ b/App.js
@@ -0,0 +1,73 @@
+import React, { useState } from "react";
+import { connectWallet, signMessage } from "./wallet";
+
+function App() {
+ const [wallet, setWallet] = useState(null);
+ const [result, setResult] = useState(null);
+
+ const handleConnect = async () => {
+ const addr = await connectWallet();
+ setWallet(addr);
+ };
+
+ const sendData = async () => {
+ if (!wallet) {
+ alert("Connect wallet first");
+ return;
+ }
+
+ const user = {
+ attention: Math.random() * 10,
+ quality: Math.random(),
+ behavior: Math.random(),
+ session_time: Math.random() * 10,
+ interaction_rate: Math.random() * 5,
+ };
+
+ const message = JSON.stringify(user);
+ const signature = await signMessage(message);
+
+ const res = await fetch("http://localhost:8000/process", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ user,
+ address: wallet,
+ signature
+ }),
+ });
+
+ const data = await res.json();
+ setResult(data);
+ };
+
+ return (
+
+
PiRC-AI Wallet Dashboard
+
+ {!wallet ? (
+
+ ) : (
+
Wallet: {wallet}
+ )}
+
+
+
+ {result && (
+
+
Verification: {result.verification.toFixed(3)}
+
Reward: {result.reward.toFixed(3)}
+
Balance: {result.balance.toFixed(3)}
+
+ )}
+
+ );
+}
+
+export default App;
diff --git a/ReadMe.md b/ReadMe.md
index 4a9dfa39..5d53201b 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -1 +1,59 @@
-See [PiRC1: Pi Ecosystem Token Design](./PiRC1/ReadMe.md)
\ No newline at end of file
+See [PiRC1: Pi Ecosystem Token Design](./PiRC1/ReadMe.md)
+
+# PiRC-AI: Attention-Based Token Economy for Pi Network
+
+PiRC-AI is an extended implementation of the Pi Request for Comment (PiRC), introducing an attention-centered token economic model designed for the AI era.
+
+As automation reduces the role of traditional labor, this project explores a new paradigm where verified human attention becomes a core economic resource.
+
+## Core Innovations
+- Attention-based reward system (Attention Mining)
+- AI-powered human verification (anti-bot & Sybil resistance)
+- Token economy with revenue-backed sinks
+- Simulation-driven tokenomics validation
+
+## Vision
+Transitioning from a labor-centered economy to an attention-centered economy within the Pi ecosystem.
+
+## Status
+Experimental design + implementation layer (not official Pi Network code)
+## Architecture Overview
+
+PiRC-AI introduces a three-layer attention economy model:
+
+1. Attention Contribution
+ Users generate verifiable attention through interaction.
+
+2. Attention Verification
+ AI-based systems validate human authenticity and filter bots.
+
+3. Attention Monetization
+ Attention is converted into tokenized value backed by real economic sinks (ads, data, AI training).
+## Token Model
+
+The reward mechanism follows a simple but robust formula:
+
+R = A × Q × V
+
+Where:
+- A = Attention (time/engagement)
+- Q = Quality score (interaction depth)
+- V = Verification score (human authenticity)
+
+This ensures fair distribution and resistance to manipulation.
+## Simulation
+
+The project includes simulation tools to evaluate:
+- Token emission dynamics
+- Network effects
+- Inflation control
+
+Future work includes AI-driven optimization of token distribution.
+## Risks & Challenges
+
+- Sybil attacks (multi-account abuse)
+- Fake attention generation
+- Centralization of verification AI
+- Token inflation without sufficient sinks
+
+These risks are actively considered in the design.
diff --git a/app.js b/app.js
new file mode 100644
index 00000000..7f6ae575
--- /dev/null
+++ b/app.js
@@ -0,0 +1,13 @@
+import express from "express";
+import healthRoute from "./routes/healthRoute.js";
+
+const app = express();
+app.use(express.json());
+
+app.use("/api", healthRoute);
+
+const PORT = process.env.PORT || 3000;
+
+app.listen(PORT, () => {
+ console.log(`🚀 PiRC AI Oracle running on port ${PORT}`);
+});
diff --git a/backend/blockchain/piInvoke.js b/backend/blockchain/piInvoke.js
new file mode 100644
index 00000000..15e18c19
--- /dev/null
+++ b/backend/blockchain/piInvoke.js
@@ -0,0 +1,93 @@
+import {
+ SorobanRpc,
+ TransactionBuilder,
+ Networks,
+ BASE_FEE,
+ Keypair
+} from "@stellar/stellar-sdk";
+
+const server = new SorobanRpc.Server(
+ "https://rpc.testnet.minepi.com"
+);
+
+// ambil dari env (WAJIB)
+const SECRET = process.env.PI_SECRET;
+const CONTRACT_ID = process.env.CONTRACT_ID;
+
+if (!SECRET) {
+ throw new Error("❌ PI_SECRET belum diset di .env");
+}
+
+const source = Keypair.fromSecret(SECRET);
+
+// 🔍 cek koneksi + akun
+export async function checkAccount() {
+ try {
+ const account = await server.getAccount(source.publicKey());
+
+ return {
+ success: true,
+ publicKey: source.publicKey(),
+ sequence: account.sequence,
+ };
+ } catch (err) {
+ return {
+ success: false,
+ error: err.message,
+ };
+ }
+}
+
+// 🚀 invoke contract (core function)
+export async function invokePi(method, args = []) {
+ try {
+ if (!CONTRACT_ID) {
+ throw new Error("❌ CONTRACT_ID belum diset di .env");
+ }
+
+ const account = await server.getAccount(source.publicKey());
+
+ const tx = new TransactionBuilder(account, {
+ fee: BASE_FEE,
+ networkPassphrase: Networks.TESTNET,
+ })
+ .addOperation(
+ SorobanRpc.Operation.invokeContract({
+ contract: CONTRACT_ID,
+ function: method,
+ args: args,
+ })
+ )
+ .setTimeout(30)
+ .build();
+
+ tx.sign(source);
+
+ // 🔍 simulate dulu (WAJIB di Soroban)
+ const simulation = await server.simulateTransaction(tx);
+
+ if (simulation.error) {
+ return {
+ success: false,
+ stage: "SIMULATION",
+ error: simulation.error,
+ };
+ }
+
+ // 🚀 kirim transaksi
+ const send = await server.sendTransaction(tx);
+
+ return {
+ success: true,
+ hash: send.hash,
+ status: send.status,
+ };
+
+ } catch (err) {
+ return {
+ success: false,
+ stage: "EXECUTION",
+ error: err.message,
+ };
+ }
+}
diff --git a/backend/piClient.js b/backend/piClient.js
new file mode 100644
index 00000000..cb4976f2
--- /dev/null
+++ b/backend/piClient.js
@@ -0,0 +1,43 @@
+const axios = require("axios");
+
+const RPC_URL = "https://rpc.testnet.minepi.com";
+
+async function callRPC(method, params = {}) {
+ try {
+ const response = await axios.post(
+ RPC_URL,
+ {
+ jsonrpc: "2.0",
+ id: 1,
+ method,
+ params
+ },
+ {
+ headers: {
+ "Content-Type": "application/json"
+ }
+ }
+ );
+
+ return response.data;
+ } catch (error) {
+ console.error("RPC Error:", error.message);
+ throw error;
+ }
+}
+
+// ===== FUNCTIONS =====
+
+async function getHealth() {
+ return callRPC("getHealth");
+}
+
+async function getLatestLedger() {
+ const health = await getHealth();
+ return health.result.latestLedger;
+}
+
+module.exports = {
+ getHealth,
+ getLatestLedger
+};
diff --git a/backend/server.js b/backend/server.js
new file mode 100644
index 00000000..a9e4d283
--- /dev/null
+++ b/backend/server.js
@@ -0,0 +1,83 @@
+import express from "express";
+import PiRPC from "../sdk/piRpc.js";
+import AIOracle from "../oracle/aiOracle.js";
+
+const app = express();
+const rpc = new PiRPC();
+
+app.use(express.json());
+
+// HEALTH
+app.get("/health", async (req, res) => {
+ try {
+ const data = await rpc.getHealth();
+ res.json(data);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+// LEDGER
+app.get("/ledger", async (req, res) => {
+ try {
+ const data = await rpc.getLedger();
+ res.json(data);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+// AI INSIGHT
+app.get("/oracle/analysis", async (req, res) => {
+ try {
+ const data = await AIOracle.analyzeNetwork();
+ res.json(data);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+// SIMULASI TX
+app.post("/simulate", async (req, res) => {
+ try {
+ const { from, to, amount } = req.body;
+ const result = await AIOracle.simulateTransaction(from, to, amount);
+ res.json(result);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+// RPC HEALTH
+app.get("/rpc/health", async (req, res) => {
+ try {
+ const data = await rpc.getHealth();
+ res.json(data);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+// RPC NETWORK
+app.get("/rpc/network", async (req, res) => {
+ try {
+ const data = await rpc.getNetwork();
+ res.json(data);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+// RPC VERSION
+app.get("/rpc/version", async (req, res) => {
+ try {
+ const data = await rpc.getVersionInfo();
+ res.json(data);
+ } catch (err) {
+ res.status(500).json({ error: err.message });
+ }
+});
+
+app.listen(3000, () => {
+ console.log("🔥 PiRC API running on http://localhost:3000");
+});
diff --git a/backend/test.js b/backend/test.js
new file mode 100644
index 00000000..bbbd32ea
--- /dev/null
+++ b/backend/test.js
@@ -0,0 +1,42 @@
+import fetch from "node-fetch";
+
+const RPC_URL = "https://rpc.testnet.minepi.com";
+
+async function callRPC(method, params = []) {
+ try {
+ const res = await fetch(RPC_URL, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ jsonrpc: "2.0",
+ id: Date.now(),
+ method,
+ params,
+ }),
+ });
+
+ const data = await res.json();
+ return data.result;
+ } catch (err) {
+ console.error("Error:", err.message);
+ }
+}
+
+const methods = [
+ "getHealth",
+ "getLatestLedger",
+ "getVersion"
+];
+
+async function main() {
+ for (const m of methods) {
+ const res = await callRPC(m);
+ console.log("Method:", m);
+ console.log("Result:", res);
+ console.log("------------");
+ }
+}
+
+main();
diff --git a/contracts/reward_engine/Cargo.toml b/contracts/reward_engine/Cargo.toml
new file mode 100644
index 00000000..d1c18f6c
--- /dev/null
+++ b/contracts/reward_engine/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "reward_engine"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+soroban-sdk = "20.3.0"
diff --git a/contracts/reward_engine/lib.rs b/contracts/reward_engine/lib.rs
new file mode 100644
index 00000000..0bf01ef7
--- /dev/null
+++ b/contracts/reward_engine/lib.rs
@@ -0,0 +1,106 @@
+#![no_std]
+
+use soroban_sdk::{contract, contractimpl, Env, Symbol, symbol_short, Vec};
+
+#[contract]
+pub struct RewardEngine;
+
+#[contractimpl]
+impl RewardEngine {
+
+ // =========================
+ // Core Reward Calculation
+ // =========================
+ pub fn calculate_reward(
+ _env: Env,
+ attention: u64,
+ quality: u64,
+ verification: u64,
+ ) -> u64 {
+ // Simple multiplication model
+ attention * quality * verification
+ }
+
+ // =========================
+ // Batch Calculation (optional)
+ // =========================
+ pub fn batch_rewards(
+ env: Env,
+ attentions: Vec,
+ qualities: Vec,
+ verifications: Vec,
+ ) -> Vec {
+
+ let mut rewards = Vec::new(&env);
+
+ let len = attentions.len();
+
+ for i in 0..len {
+ let a = attentions.get(i).unwrap();
+ let q = qualities.get(i).unwrap();
+ let v = verifications.get(i).unwrap();
+
+ let r = a * q * v;
+ rewards.push_back(r);
+ }
+
+ rewards
+ }
+
+ // =========================
+ // Normalization (anti inflation)
+ // =========================
+ pub fn normalize_rewards(
+ env: Env,
+ rewards: Vec,
+ max_emission: u64,
+ ) -> Vec {
+
+ let mut total: u64 = 0;
+
+ for r in rewards.iter() {
+ total += r;
+ }
+
+ let mut normalized = Vec::new(&env);
+
+ if total == 0 {
+ return normalized;
+ }
+
+ for r in rewards.iter() {
+ let scaled = (r * max_emission) / total;
+ normalized.push_back(scaled);
+ }
+
+ normalized
+ }
+
+ // =========================
+ // Simple Anti-Bot Filter
+ // =========================
+ pub fn apply_verification_threshold(
+ env: Env,
+ rewards: Vec,
+ verifications: Vec,
+ threshold: u64,
+ ) -> Vec {
+
+ let mut filtered = Vec::new(&env);
+
+ let len = rewards.len();
+
+ for i in 0..len {
+ let r = rewards.get(i).unwrap();
+ let v = verifications.get(i).unwrap();
+
+ if v >= threshold {
+ filtered.push_back(r);
+ } else {
+ filtered.push_back(0);
+ }
+ }
+
+ filtered
+ }
+}
diff --git a/contracts/reward_engine/src/lib.rs b/contracts/reward_engine/src/lib.rs
new file mode 100644
index 00000000..c37aea9c
--- /dev/null
+++ b/contracts/reward_engine/src/lib.rs
@@ -0,0 +1,82 @@
+#![no_std]
+
+use soroban_sdk::{
+ contract, contractimpl, Env, Address, Vec, Map
+};
+
+#[contract]
+pub struct RewardEngine;
+
+#[contractimpl]
+impl RewardEngine {
+
+ // =========================
+ // Storage Keys
+ // =========================
+ fn balances(e: &Env) -> Map {
+ e.storage().instance().get(&"balances").unwrap_or(Map::new(e))
+ }
+
+ fn set_balances(e: &Env, map: Map) {
+ e.storage().instance().set(&"balances", &map);
+ }
+
+ // =========================
+ // Reward Formula
+ // =========================
+ pub fn calculate_reward(
+ _env: Env,
+ attention: u64,
+ quality: u64,
+ verification: u64,
+ ) -> u64 {
+ attention * quality * verification
+ }
+
+ // =========================
+ // Mint Token (core)
+ // =========================
+ pub fn mint(
+ env: Env,
+ user: Address,
+ reward: u64,
+ ) {
+ let mut balances = Self::balances(&env);
+
+ let current = balances.get(user.clone()).unwrap_or(0);
+ balances.set(user, current + reward);
+
+ Self::set_balances(&env, balances);
+ }
+
+ // =========================
+ // Batch Mint
+ // =========================
+ pub fn distribute_rewards(
+ env: Env,
+ users: Vec,
+ rewards: Vec,
+ ) {
+ let mut balances = Self::balances(&env);
+
+ let len = users.len();
+
+ for i in 0..len {
+ let user = users.get(i).unwrap();
+ let reward = rewards.get(i).unwrap();
+
+ let current = balances.get(user.clone()).unwrap_or(0);
+ balances.set(user, current + reward);
+ }
+
+ Self::set_balances(&env, balances);
+ }
+
+ // =========================
+ // View Balance
+ // =========================
+ pub fn get_balance(env: Env, user: Address) -> u64 {
+ let balances = Self::balances(&env);
+ balances.get(user).unwrap_or(0)
+ }
+}
diff --git a/dashboard/web-ui/src/App.js b/dashboard/web-ui/src/App.js
new file mode 100644
index 00000000..185e9f6e
--- /dev/null
+++ b/dashboard/web-ui/src/App.js
@@ -0,0 +1,48 @@
+import React, { useState } from "react";
+
+function App() {
+ const [result, setResult] = useState(null);
+
+ const sendData = async () => {
+ const user = {
+ attention: Math.random() * 10,
+ quality: Math.random(),
+ behavior: Math.random(),
+ session_time: Math.random() * 10,
+ interaction_rate: Math.random() * 5,
+ };
+
+ const res = await fetch("http://localhost:8000/process", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ user: user,
+ address: "USER_1",
+ }),
+ });
+
+ const data = await res.json();
+ setResult(data);
+ };
+
+ return (
+
+
PiRC-AI Live Dashboard
+
+
+
+ {result && (
+
+
Verification: {result.verification.toFixed(3)}
+
Reward: {result.reward.toFixed(3)}
+
+ )}
+
+ );
+}
+
+export default App;
diff --git a/dashboard/web-ui/src/wallet.js b/dashboard/web-ui/src/wallet.js
new file mode 100644
index 00000000..da19d352
--- /dev/null
+++ b/dashboard/web-ui/src/wallet.js
@@ -0,0 +1,9 @@
+export async function connectWallet() {
+ if (!window.freighterApi) {
+ alert("Install Freighter Wallet");
+ return null;
+ }
+
+ const publicKey = await window.freighterApi.getPublicKey();
+ return publicKey;
+}
diff --git a/design/attention-triad.md b/design/attention-triad.md
new file mode 100644
index 00000000..12fcf2e7
--- /dev/null
+++ b/design/attention-triad.md
@@ -0,0 +1,135 @@
+# Attention Triad
+
+## Overview
+
+The Attention Triad is a core conceptual framework in PiRC-AI that decomposes the attention economy into three distinct but interconnected layers:
+
+1. Attention Contribution
+2. Attention Verification
+3. Attention Monetization
+
+This separation makes visible the inefficiencies and value gaps in existing digital platforms, where user attention is often captured but not fairly rewarded.
+
+---
+
+## 1. Attention Contribution
+
+### Definition
+Attention Contribution refers to the measurable input of human attention within the ecosystem.
+
+### Examples
+- Time spent viewing content
+- User interactions (clicks, likes, comments)
+- Cognitive engagement (scroll depth, dwell time)
+
+### Key Insight
+In traditional platforms, users generate attention but do not directly receive proportional economic value.
+
+In PiRC-AI:
+> Attention becomes a measurable and rewardable resource.
+
+---
+
+## 2. Attention Verification
+
+### Definition
+Attention Verification ensures that contributed attention is authentic, human, and meaningful.
+
+### Purpose
+To prevent:
+- Bot activity
+- Fake engagement
+- Sybil attacks (multi-account abuse)
+
+### Methods
+- Behavioral analysis (interaction patterns)
+- AI-based anomaly detection
+- Reputation systems
+- Optional identity/KYC integration
+
+### Verification Score (V)
+Each attention event is assigned a verification score:
+
+V ∈ [0, 1]
+
+Where:
+- 0 = invalid (bot/fake)
+- 1 = fully verified human attention
+
+---
+
+## 3. Attention Monetization
+
+### Definition
+Attention Monetization converts verified attention into economic value.
+
+### Mechanisms
+- Advertising (attention sold to advertisers)
+- AI training data (human-labeled interaction)
+- Marketplace exposure
+- Data insights (aggregated, privacy-aware)
+
+### Token Integration
+Verified attention is rewarded via tokens:
+
+Reward ∝ Attention × Quality × Verification
+
+This ensures that only valuable and authentic attention is monetized.
+
+---
+
+## Attention Flow
+
+The full lifecycle of attention in PiRC-AI:
+
+User → Attention Contribution → Verification → Monetization → Token Reward
+
+---
+
+## Contribution Gap (Problem Statement)
+
+In current digital platforms:
+- Users contribute attention
+- Platforms monetize it
+- Users receive little or no direct compensation
+
+This creates a **value extraction imbalance**.
+
+PiRC-AI addresses this by:
+- Making attention measurable
+- Verifying authenticity
+- Redistributing value via token economics
+
+---
+
+## Design Principles
+
+1. Fairness
+ Users should receive proportional rewards for their attention.
+
+2. Verifiability
+ Only real human attention should be rewarded.
+
+3. Sustainability
+ Token rewards must be backed by real economic sinks.
+
+4. Scalability
+ The system must function across millions of users.
+
+---
+
+## Implications
+
+The Attention Triad enables:
+- A shift from labor-based to attention-based income
+- New forms of participation in digital economies
+- Alignment between users, platforms, and value creation
+
+---
+
+## Future Work
+
+- Advanced AI verification models
+- Cross-platform attention aggregation
+- Privacy-preserving attention tracking
+- Integration with decentralized identity systems
diff --git a/engine/actionEngine.js b/engine/actionEngine.js
new file mode 100644
index 00000000..3367e548
--- /dev/null
+++ b/engine/actionEngine.js
@@ -0,0 +1,20 @@
+export function takeAction(analysis) {
+ if (analysis.risk === "HIGH") {
+ return {
+ action: "SWITCH_RPC",
+ message: "Switching to backup node..."
+ };
+ }
+
+ if (analysis.risk === "MEDIUM") {
+ return {
+ action: "THROTTLE",
+ message: "Reducing request rate..."
+ };
+ }
+
+ return {
+ action: "NORMAL",
+ message: "All systems stable"
+ };
+}
diff --git a/oracle/aiOracle.js b/oracle/aiOracle.js
new file mode 100644
index 00000000..57c82c41
--- /dev/null
+++ b/oracle/aiOracle.js
@@ -0,0 +1,34 @@
+import PiRPC from "../sdk/piRpc.js";
+import detector from "./anomalyDetector.js";
+
+const rpc = new PiRPC();
+
+class AIOracle {
+
+ async analyzeNetwork() {
+ const health = await rpc.getHealth();
+ const ledger = await rpc.getLedger();
+
+ // fake tx counter (kalau RPC belum ada tx endpoint)
+ const txCount = Math.floor(Math.random() * 100);
+
+ const anomaly = detector.detect({
+ ledger: ledger || 0,
+ txCount
+ });
+
+ return {
+ status: health?.status || "unknown",
+ ledger,
+ txCount,
+ anomaly,
+ insight:
+ anomaly.risk === "HIGH"
+ ? "⚠️ Suspicious network activity detected"
+ : "✅ Network stable",
+ timestamp: Date.now()
+ };
+ }
+}
+
+export default new AIOracle();
diff --git a/oracle/ai_oracle_server.py b/oracle/ai_oracle_server.py
new file mode 100644
index 00000000..a172ac9a
--- /dev/null
+++ b/oracle/ai_oracle_server.py
@@ -0,0 +1,24 @@
+from fastapi import FastAPI
+import joblib
+import numpy as np
+
+app = FastAPI()
+
+model = joblib.load("simulations/ai_model/ai_verification_model.pkl")
+
+
+@app.post("/verify")
+def verify(user: dict):
+ features = np.array([[
+ user["attention"],
+ user["quality"],
+ user["behavior"],
+ user["session_time"],
+ user["interaction_rate"]
+ ]])
+
+ prob = model.predict_proba(features)[0][1]
+
+ return {
+ "verification_score": float(prob)
+ }
diff --git a/oracle/anomalyDetector.js b/oracle/anomalyDetector.js
new file mode 100644
index 00000000..2b29446d
--- /dev/null
+++ b/oracle/anomalyDetector.js
@@ -0,0 +1,64 @@
+class AnomalyDetector {
+ constructor() {
+ this.history = [];
+ this.maxHistory = 50;
+ }
+
+ // simpan data snapshot
+ addSample(sample) {
+ this.history.push(sample);
+
+ if (this.history.length > this.maxHistory) {
+ this.history.shift();
+ }
+ }
+
+ // hitung rata-rata sederhana
+ getAverage(key) {
+ const values = this.history.map(h => h[key] || 0);
+ const sum = values.reduce((a, b) => a + b, 0);
+ return values.length ? sum / values.length : 0;
+ }
+
+ // deteksi anomaly utama
+ detect(sample) {
+ this.addSample(sample);
+
+ const ledgerAvg = this.getAverage("ledger");
+ const txAvg = this.getAverage("txCount");
+
+ let risk = "LOW";
+ let score = 0;
+
+ // 🔥 RULE 1: spike ledger
+ if (sample.ledger > ledgerAvg * 1.8) {
+ risk = "HIGH";
+ score += 40;
+ }
+
+ // 🔥 RULE 2: spike transaksi
+ if (sample.txCount > txAvg * 2) {
+ risk = "HIGH";
+ score += 40;
+ }
+
+ // 🔥 RULE 3: empty / freeze pattern
+ if (sample.ledger === 0) {
+ risk = "MEDIUM";
+ score += 20;
+ }
+
+ // clamp score
+ if (score > 100) score = 100;
+
+ return {
+ risk,
+ score,
+ ledgerAvg,
+ txAvg,
+ sample
+ };
+ }
+}
+
+export default new AnomalyDetector();
diff --git a/oracle/api.py b/oracle/api.py
new file mode 100644
index 00000000..901b80d6
--- /dev/null
+++ b/oracle/api.py
@@ -0,0 +1,25 @@
+from fastapi import FastAPI
+from relayer import process_user
+
+app = FastAPI()
+
+@app.post("/process")
+def process(data: dict):
+ user = data["user"]
+ address = data["address"]
+
+ result = process_user(user, address)
+
+ return result
+
+
+from nacl.signing import VerifyKey
+import base64
+
+def verify_signature(address, message, signature):
+ try:
+ verify_key = VerifyKey(bytes.fromhex(address))
+ verify_key.verify(message.encode(), base64.b64decode(signature))
+ return True
+ except:
+ return False
diff --git a/oracle/client.py b/oracle/client.py
new file mode 100644
index 00000000..20e89fad
--- /dev/null
+++ b/oracle/client.py
@@ -0,0 +1,20 @@
+import requests
+
+def get_verification(user):
+ res = requests.post(
+ "http://localhost:8000/verify",
+ json=user
+ )
+ return res.json()["verification_score"]
+
+
+if __name__ == "__main__":
+ user = {
+ "attention": 8,
+ "quality": 0.9,
+ "behavior": 0.8,
+ "session_time": 10,
+ "interaction_rate": 3
+ }
+
+ print(get_verification(user))
diff --git a/oracle/relayer.py b/oracle/relayer.py
new file mode 100644
index 00000000..a8f7ad87
--- /dev/null
+++ b/oracle/relayer.py
@@ -0,0 +1,47 @@
+import requests
+
+# dummy contract interface (sementara)
+class ContractClient:
+ def mint(self, user_address, reward):
+ print(f"[CONTRACT] Mint {reward} to {user_address}")
+
+contract = ContractClient()
+
+
+def process_user(user, user_address):
+ # 1. Call AI Oracle
+ res = requests.post(
+ "http://localhost:8000/verify",
+ json=user
+ )
+
+ V = res.json()["verification_score"]
+
+ # 2. Calculate reward
+ reward = user["attention"] * user["quality"] * V
+
+ # 3. Send to contract
+ contract.mint(user_address, reward)
+
+ return {
+ "verification": V,
+ "reward": reward
+ }
+
+
+if __name__ == "__main__":
+ user = {
+ "attention": 8,
+ "quality": 0.9,
+ "behavior": 0.8,
+ "session_time": 10,
+ "interaction_rate": 3
+ }
+
+ result = process_user(user, "USER_1")
+ print(result)
+ balances = {}
+
+def update_balance(user_address, reward):
+ balances[user_address] = balances.get(user_address, 0) + reward
+ return balances[user_address]
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..63a1b1d1
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "pirc-core",
+ "version": "1.0.0",
+ "type": "module",
+ "main": "backend/server.js",
+ "scripts": {
+ "start": "node backend/server.js"
+ },
+ "dependencies": {
+ "express": "^4.18.2"
+ }
+}
diff --git a/routes/healthRoute.js b/routes/healthRoute.js
new file mode 100644
index 00000000..ef3194cf
--- /dev/null
+++ b/routes/healthRoute.js
@@ -0,0 +1,22 @@
+import express from "express";
+import { getPiHealth } from "../services/piHealth.js";
+import { analyzeHealth } from "../oracle/aiOracle.js";
+import { takeAction } from "../engine/actionEngine.js";
+
+const router = express.Router();
+
+router.get("/health-check", async (req, res) => {
+ try {
+ const health = await getPiHealth();
+ const analysis = analyzeHealth(health);
+ const action = takeAction(analysis);
+
+ res.json({ health, analysis, action });
+ } catch (err) {
+ res.status(500).json({
+ error: "Failed to fetch health"
+ });
+ }
+});
+
+export default router;
diff --git a/sdk/piRpc.js b/sdk/piRpc.js
new file mode 100644
index 00000000..70698013
--- /dev/null
+++ b/sdk/piRpc.js
@@ -0,0 +1,38 @@
+import fetch from "node-fetch";
+
+export default class PiRPC {
+ constructor(url = "https://rpc.testnet.minepi.com") {
+ this.url = url;
+ }
+
+ async call(method, params = []) {
+ const body = {
+ jsonrpc: "2.0",
+ id: 1,
+ method,
+ params
+ };
+
+ const res = await fetch(this.url, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(body)
+ });
+
+ return await res.json();
+ }
+
+ getNetwork() {
+ return this.call("getNetwork");
+ }
+
+ getHealth() {
+ return this.call("getHealth");
+ }
+
+ getVersionInfo() {
+ return this.call("getVersionInfo");
+ }
+}
diff --git a/server.js b/server.js
new file mode 100644
index 00000000..428e3e52
--- /dev/null
+++ b/server.js
@@ -0,0 +1,14 @@
+import express from "express";
+
+const app = express();
+const PORT = 3000;
+
+app.use(express.json());
+
+app.get("/", (req, res) => {
+ res.send("Backend aktif 🚀");
+});
+
+app.listen(PORT, () => {
+ console.log("Server jalan di port " + PORT);
+});
diff --git a/services/piHealth.js b/services/piHealth.js
new file mode 100644
index 00000000..2206332a
--- /dev/null
+++ b/services/piHealth.js
@@ -0,0 +1,18 @@
+import fetch from "node-fetch";
+
+export async function getPiHealth() {
+ const res = await fetch("https://rpc.testnet.minepi.com", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({
+ jsonrpc: "2.0",
+ id: 1,
+ method: "getHealth"
+ })
+ });
+
+ const data = await res.json();
+ return data.result || data;
+}
diff --git a/simulations/ai_model/features.py b/simulations/ai_model/features.py
new file mode 100644
index 00000000..9363f2e8
--- /dev/null
+++ b/simulations/ai_model/features.py
@@ -0,0 +1,8 @@
+def extract_features(user):
+ return [
+ user["attention"],
+ user["quality"],
+ user["behavior"],
+ user["session_time"],
+ user["interaction_rate"],
+ ]
diff --git a/simulations/ai_model/inference.py b/simulations/ai_model/inference.py
new file mode 100644
index 00000000..405e2a5e
--- /dev/null
+++ b/simulations/ai_model/inference.py
@@ -0,0 +1,17 @@
+import joblib
+import numpy as np
+
+model = joblib.load("ai_verification_model.pkl")
+
+def predict_verification(user):
+ features = np.array([[
+ user["attention"],
+ user["quality"],
+ user["behavior"],
+ user["session_time"],
+ user["interaction_rate"]
+ ]])
+
+ prob = model.predict_proba(features)[0][1] # probability human
+
+ return prob
diff --git a/simulations/ai_model/train_model.py b/simulations/ai_model/train_model.py
new file mode 100644
index 00000000..d81f93ac
--- /dev/null
+++ b/simulations/ai_model/train_model.py
@@ -0,0 +1,51 @@
+import random
+import numpy as np
+from sklearn.ensemble import RandomForestClassifier
+import joblib
+
+def generate_dataset(n=5000):
+ X = []
+ y = []
+
+ for _ in range(n):
+ is_bot = random.random() < 0.3
+
+ if is_bot:
+ attention = random.uniform(8, 15)
+ quality = random.uniform(0.1, 0.5)
+ behavior = random.uniform(0.1, 0.3)
+ session_time = random.uniform(1, 3)
+ interaction_rate = random.uniform(5, 10)
+ else:
+ attention = random.uniform(2, 10)
+ quality = random.uniform(0.6, 1.2)
+ behavior = random.uniform(0.6, 1.0)
+ session_time = random.uniform(5, 15)
+ interaction_rate = random.uniform(1, 5)
+
+ X.append([
+ attention,
+ quality,
+ behavior,
+ session_time,
+ interaction_rate
+ ])
+
+ y.append(0 if is_bot else 1)
+
+ return np.array(X), np.array(y)
+
+
+def train():
+ X, y = generate_dataset()
+
+ model = RandomForestClassifier(n_estimators=100)
+ model.fit(X, y)
+
+ joblib.dump(model, "ai_verification_model.pkl")
+
+ print("Model trained & saved!")
+
+
+if __name__ == "__main__":
+ train()
diff --git a/simulations/ai_verification.py b/simulations/ai_verification.py
new file mode 100644
index 00000000..5adcbeaf
--- /dev/null
+++ b/simulations/ai_verification.py
@@ -0,0 +1,44 @@
+import random
+
+def ai_verification_score(attention, quality, behavior_score):
+ """
+ Simulate AI-based human verification
+ """
+
+ # heuristic scoring
+ score = (
+ 0.4 * (attention / 10) +
+ 0.4 * quality +
+ 0.2 * behavior_score
+ )
+
+ # clamp 0–1
+ return max(0, min(1, score))
+
+
+def detect_bot_pattern(attention, quality):
+ if attention > 12 and quality < 0.4:
+ return True
+ return False
+
+
+def generate_user():
+ is_bot = random.random() < 0.3
+
+ if is_bot:
+ attention = random.uniform(8, 15)
+ quality = random.uniform(0.1, 0.5)
+ behavior = random.uniform(0.1, 0.3)
+ else:
+ attention = random.uniform(2, 10)
+ quality = random.uniform(0.6, 1.2)
+ behavior = random.uniform(0.6, 1.0)
+
+ verification = ai_verification_score(attention, quality, behavior)
+
+ return {
+ "attention": attention,
+ "quality": quality,
+ "verification": verification,
+ "is_bot": is_bot
+ }
diff --git a/simulations/attention_model.py b/simulations/attention_model.py
new file mode 100644
index 00000000..6af12edd
--- /dev/null
+++ b/simulations/attention_model.py
@@ -0,0 +1,102 @@
+# simulations/attention_model.py
+
+import random
+import statistics
+
+class User:
+ def __init__(self, is_bot=False):
+ self.is_bot = is_bot
+
+ def generate_attention(self):
+ if self.is_bot:
+ # bot: high activity but low quality
+ A = random.uniform(5, 15)
+ Q = random.uniform(0.1, 0.5)
+ V = random.uniform(0.0, 0.3)
+ else:
+ # human: moderate activity, higher quality
+ A = random.uniform(2, 10)
+ Q = random.uniform(0.5, 1.5)
+ V = random.uniform(0.7, 1.0)
+
+ return A, Q, V
+
+
+class AttentionEconomy:
+ def __init__(self, users=1000, bot_ratio=0.2, max_daily_emission=10000):
+ self.users = users
+ self.bot_ratio = bot_ratio
+ self.max_daily_emission = max_daily_emission
+ self.population = self._create_population()
+
+ def _create_population(self):
+ population = []
+ for _ in range(self.users):
+ if random.random() < self.bot_ratio:
+ population.append(User(is_bot=True))
+ else:
+ population.append(User(is_bot=False))
+ return population
+
+ def calculate_reward(self, A, Q, V):
+ return A * Q * V
+
+ def run_epoch(self):
+ rewards = []
+ raw_rewards = []
+
+ for user in self.population:
+ A, Q, V = user.generate_attention()
+ r = self.calculate_reward(A, Q, V)
+ raw_rewards.append(r)
+
+ total_raw = sum(raw_rewards)
+
+ # normalize to max emission (anti-inflation control)
+ if total_raw > 0:
+ scale = self.max_daily_emission / total_raw
+ else:
+ scale = 0
+
+ for r in raw_rewards:
+ rewards.append(r * scale)
+
+ return rewards
+
+ def simulate(self, days=30):
+ history = []
+
+ for day in range(days):
+ rewards = self.run_epoch()
+ total = sum(rewards)
+ avg = statistics.mean(rewards)
+ max_r = max(rewards)
+
+ history.append({
+ "day": day + 1,
+ "total_emission": total,
+ "avg_reward": avg,
+ "max_reward": max_r
+ })
+
+ return history
+
+
+if __name__ == "__main__":
+ sim = AttentionEconomy(
+ users=1000,
+ bot_ratio=0.3, # coba ubah untuk test ketahanan sistem
+ max_daily_emission=10000
+ )
+
+ results = sim.simulate(days=30)
+
+ print("=== Simulation Results ===\n")
+
+ for day in results:
+ print(
+ f"Day {day['day']}: "
+ f"Total={day['total_emission']:.2f}, "
+ f"Avg={day['avg_reward']:.4f}, "
+ f"Max={day['max_reward']:.2f}"
+ )
diff --git a/simulations/full_pipeline.py b/simulations/full_pipeline.py
new file mode 100644
index 00000000..d8a20f48
--- /dev/null
+++ b/simulations/full_pipeline.py
@@ -0,0 +1,27 @@
+from attention_model import AttentionEconomy
+from ai_verification import generate_user
+
+def run_full_simulation(users=1000):
+ rewards = []
+
+ for _ in range(users):
+ u = generate_user()
+
+ reward = (
+ u["attention"] *
+ u["quality"] *
+ u["verification"]
+ )
+
+ rewards.append(reward)
+
+ total = sum(rewards)
+
+ print("Total Rewards:", total)
+ print("Avg Reward:", total / users)
+
+ return rewards
+
+
+if __name__ == "__main__":
+ run_full_simulation()
diff --git a/simulations/full_pipeline_ai.py b/simulations/full_pipeline_ai.py
new file mode 100644
index 00000000..774992d3
--- /dev/null
+++ b/simulations/full_pipeline_ai.py
@@ -0,0 +1,34 @@
+from ai_model.inference import predict_verification
+import random
+
+def generate_user():
+ return {
+ "attention": random.uniform(1, 15),
+ "quality": random.uniform(0.1, 1.2),
+ "behavior": random.uniform(0.1, 1.0),
+ "session_time": random.uniform(1, 15),
+ "interaction_rate": random.uniform(1, 10),
+ }
+
+def run_simulation(n=1000):
+ rewards = []
+
+ for _ in range(n):
+ user = generate_user()
+
+ V = predict_verification(user)
+
+ reward = (
+ user["attention"] *
+ user["quality"] *
+ V
+ )
+
+ rewards.append(reward)
+
+ print("Total:", sum(rewards))
+ print("Avg:", sum(rewards) / n)
+
+
+if __name__ == "__main__":
+ run_simulation()