Skip to main content

Two Conditions, Both Required

Weighted Approval ≥ 60%
        AND
Participation Quorum ≥ 5% of total eligible weighted supply
        WITHIN
72-hour voting window
If quorum is not reached, the Capsule is automatically rejected - regardless of how many votes were cast or how they split. This prevents low-attention approvals.

Weight Formula

Voting Weight = Base Role Weight × Reputation Multiplier × Bond Stability Factor

Base Role Weights

RoleWeight
Citizen1
Contributor2
Reporter3
Verified Author4
Media Validator4

Reputation Multiplier - 0.5 → 2.0

Driven by: participation rate, alignment with final court outcomes, spam flags, inactivity.

Bond Stability Factor - 1.0 → 1.15

Bond DurationFactor
0–30 days1.00
30–90 days1.03
90–180 days1.07
180–365 days1.11
365+ days1.15
Prevents stake-and-vote manipulation. Short-term bonders earn no stability premium.

Effective Weight Example

// Reporter, 1.7 reputation, 1.10 stability (6 months bonded)
const effective = 3 * 1.7 * 1.10; // = 5.61

Vote State Query

import { Contract, JsonRpcProvider } from "ethers";

const ABI = [
  "function isVotingOpen(uint256 capsuleId) view returns (bool)",
  "function getVoteState(uint256 capsuleId) view returns (uint256, uint256, uint256, uint256, uint256, bool, bool)",
];

const acceptance = new Contract(
  "0x63D0c0b51a3856a539b36a909517a18BddDb4a32",
  ABI,
  new JsonRpcProvider("https://rpc.presschain.io")
);

const open = await acceptance.isVotingOpen(capsuleId);
const [yesVotes, noVotes, weightedYes, weightedNo, participation, finalized, accepted]
  = await acceptance.getVoteState(capsuleId);

const approvalRate = Number(weightedYes) / (Number(weightedYes) + Number(weightedNo));
Or via Bridge (recommended):
GET https://bridge.presschain.io/capsules/:id
{
  "status": "pending",
  "weightedYes": 3750,
  "weightedNo": 500,
  "weightedParticipation": 4250,
  "opensAt": "1704153600",
  "closesAt": "1704412800"
}

Voting Flow (Integration)

// 1. Request PressKey signature
const { signature, sessionToken } = await window.presskey.request({
  action: "SUBMIT_VOTE",
  capsuleId: "247",
  support: true,
});

// 2. Submit to Bridge
const res = await fetch("https://bridge.presschain.io/capsules/247/accept", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${sessionToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ capsuleId: "247", support: true, signature }),
});

Finalization

After the 72-hour window closes, finalization can be triggered:
POST https://bridge.presschain.io/capsules/:id/accept
Authorization: Bearer <token>
{ "capsuleId": "247" }
Finalization records acceptance on-chain and activates distribution. If both thresholds were met, the capsule becomes canonical. If not, it’s rejected.

Anti-Spam Controls

ControlBehavior
Daily vote cap (Citizen)Strict limit per day per account
Per-topic throttleAuto-reduced rate during coordinated attacks
PressKey requiredNo anonymous voting - every vote is signed
Reputation gateExpanded privileges require earned reputation
Bond stabilityFlash-stake-and-vote earns no weight bonus

Rejection Handling

# Query rejection reason
GET https://bridge.presschain.io/capsules/:id

# capsule.status === "rejected"
# Check weightedYes, weightedNo, weightedParticipation
# Low participation → quorum failure
# Low weightedYes → approval failure
Rejected Capsules can be revised and resubmitted. The revision goes through acceptance fresh with its own 72-hour window.