Logical Architecture
This section details the platform’s runtime responsibilities, object models, and interaction patterns. It describes what each logical component does, how components collaborate, and the invariants we maintain to keep the system safe, fast, and verifiable—without introducing a traditional web2 backend into the request path.
Frontend clients
The clients are statically built applications distributed via CDN and Walrus aggregator endpoints. They operate as the orchestration plane for user actions, directly coordinating with on‑chain modules and decentralized storage.
- Reader: content discovery, entitlement verification, retrieval from CDN/Walrus, payments/subscriptions, prediction market viewing and participation.
- Creator/Journalist: publishing workflow, Kiosk policy selection, royalty configuration, earnings views.
- Investigator: bounty creation and governance, encrypted source exchange, resolution actions.
Cross‑cutting client responsibilities
- Wallet & identity: connect wallets and zkLogin SSO; surface sponsored transactions when users lack gas.
- Entitlement checks: validate on‑chain access objects client‑side before content fetch; cache entitlements locally and invalidate deterministically on chain events.
- Network resilience: prefer CDN for speed; auto‑fallback to Walrus aggregator URLs; verify content integrity against expected hashes.
- Privacy & security: use end‑to‑end encryption for source media; never persist doxable PII on‑chain; minimize browser‑side secrets.
On‑chain modules (Sui / Move)
All economic and access state resides on Sui in Move modules. Each module emits events used for local caching and verification.
Content & Kiosk Module
module pml::content {
use sui::kiosk::{Self, Kiosk, KioskOwnerCap};
use sui::transfer_policy::{Self, TransferPolicy};
/// Content NFT with metadata and storage reference
struct ContentNFT has key, store {
id: UID,
title: String,
author: address,
walrus_blob_id: vector<u8>,
content_hash: vector<u8>,
created_at: u64
}
/// Transfer policy for royalties and restrictions
public fun create_content_policy(
publisher: &Publisher,
ctx: &mut TxContext
): (TransferPolicy<ContentNFT>, TransferPolicyCap<ContentNFT>) {
transfer_policy::new<ContentNFT>(publisher, ctx)
}
}
Entitlements Module
module pml::entitlements {
use sui::clock::Clock;
/// Access entitlement - owned by reader
struct Entitlement has key {
id: UID,
content_id: ID,
reader: address,
tier: u8, // 0: article, 1: basic sub, 2: premium
valid_from: u64,
valid_until: u64
}
/// Verify access (client-side callable)
public fun verify_access(
entitlement: &Entitlement,
content_id: ID,
clock: &Clock
): bool {
entitlement.content_id == content_id &&
clock.timestamp_ms() >= entitlement.valid_from &&
clock.timestamp_ms() <= entitlement.valid_until
}
}
Bounty Escrow Module
module pml::bounty {
use sui::balance::{Self, Balance};
use sui::table::{Self, Table};
/// Shared bounty pool
struct Bounty has key, store {
id: UID,
journalist: address,
reward: Balance<SUI>,
requirements_hash: vector<u8>,
deadline: u64,
submissions: Table<address, Submission>,
status: u8 // 0: active, 1: resolved, 2: expired
}
/// Hot potato for atomic resolution
struct BountyResolution {
bounty_id: ID,
winner: Option<address>,
decision: u8 // 0: accept, 1: reject, 2: expire
}
/// Event emitted for reputation updates
struct BountyResolved has copy, drop {
bounty_id: ID,
winner: Option<address>,
amount: u64,
timestamp: u64
}
}
Reputation Module
module pml::reputation {
/// Pseudonymous reputation - owned by contributor
struct Reputation has key {
id: UID,
score: u64,
verified_submissions: u64,
rejected_count: u64,
trust_level: u8 // 0: new, 1: trusted, 2: verified
}
/// Only bounty module can update reputation
public(friend) fun update_reputation(
rep: &mut Reputation,
accepted: bool
) {
if (accepted) {
rep.score = rep.score + 100;
rep.verified_submissions = rep.verified_submissions + 1;
if (rep.verified_submissions >= 10) {
rep.trust_level = 2; // Verified
} else if (rep.verified_submissions >= 3) {
rep.trust_level = 1; // Trusted
}
} else {
rep.rejected_count = rep.rejected_count + 1;
if (rep.score >= 10) {
rep.score = rep.score - 10;
}
}
}
}
Key invariants
- No entitlement grants access unless the object owner matches the requesting principal and the validity window holds.
- Bounty payouts/slashing are idempotent and single‑shot; attempts to re‑settle fail deterministically.
- Reputation changes only occur as a consequence of finalized outcomes.
#### Client-Side Verification Pattern
```typescript
// Client-side entitlement verification
async function verifyAccess(
userAddress: string,
contentId: string
): Promise<boolean> {
// Fetch user's entitlements
const entitlements = await sui.getOwnedObjects({
owner: userAddress,
filter: { StructType: `${PACKAGE_ID}::entitlements::Entitlement` }
});
// Check each entitlement
for (const obj of entitlements.data) {
const entitlement = obj.data.content;
if (
entitlement.content_id === contentId &&
Date.now() >= entitlement.valid_from &&
Date.now() <= entitlement.valid_until
) {
return true;
}
}
return false;
}
Storage & delivery
Media is stored via Walrus using the Quilt SDK and fetched through aggregator endpoints; the CDN serves as the primary distribution path with Walrus as an embedded fallback. Quilt provides optimized batching, progress tracking, and error recovery for large media uploads.
- Addressing & integrity: content hashes and Walrus blob IDs are referenced in on‑chain objects; clients verify integrity on retrieval.
- Caching: CDN provides low‑latency distribution; cache headers are tuned for immutability of published assets; aggregator URLs are embedded for resilience.
- Dual‑hosting: static clients are available from both CDN and Walrus; DNS provides domain resolution without requiring a mutable web origin.
Identity & UX
Users authenticate with wallets or via zkLogin. Sponsored transactions enable gas‑less operations when appropriate, with client‑side rate limiting and proof‑of‑person safeguards to mitigate abuse.
- Wallets: standard Sui wallet integrations for signing and account management.
- zkLogin: federated SSO mapped to Sui addresses; reduces first‑time friction while retaining cryptographic assurances.
- Sponsored tx: gas station pattern that sponsors tx for eligible actions; clients surface sponsorship when balances are low.
AI oracles (confidential + verifiable)
The oracle layer produces verifiable receipts for decisions that require confidential compute or external verification.
- Trusted Execution Environments: AWS Nitro Enclaves (Nautilus‑style) run enclave code and produce attestations; receipts are signed and include measurement hashes.
- Verifiable web evidence: zkTLS can prove properties of TLS sessions without revealing payloads; proofs are included in receipts.
- Privacy‑preserving access control: MystenLabs Seal enables threshold encryption requiring multiple key servers to cooperate for decryption, protecting sensitive source materials and editorial content.
- On‑chain anchoring: receipts are hashed and anchored on Sui; market/reputation modules can require receipt references to finalize outcomes.
User-Specific Critical Flows
The platform implements distinct logical flows for each user type, optimized for their specific needs and security requirements.
Reader Flow: Discovery to Consumption
Readers experience a streamlined journey from content discovery through consumption:
Journalist Flow: Publishing and Monetization
Journalists manage content creation, publishing, and revenue collection:
Source Flow: Anonymous Submission
Sources submit sensitive materials with maximum privacy protection:
Cross-User Interaction: Bounty Lifecycle
The complete bounty flow showing journalist-source interaction:
Error handling and resilience
- Idempotency: client operations include deterministic nonces where needed; on‑chain modules reject duplicate settlement.
- Retries & backoff: content fetches attempt CDN first, then Walrus; on‑chain reads are retried with bounded backoff.
- Graceful degradation: when identity providers are unavailable, wallet‑only flows remain; when CDN is degraded, Walrus aggregators serve directly.
Security boundaries and trust
- Clients trust only what can be verified: on‑chain state, content hashes, and attested oracle receipts.
- Identity providers and sponsors are integration points, not authorities for access checks—clients always verify entitlements on‑chain.
- Sensitive materials never traverse the chain; only hashes and receipts are recorded.