Smart Contracts

ChainPress uses five smart contracts deployed on Avalanche Fuji Testnet. Below is the architecture overview, contract details, and event reference.

Architecture Overview

The contracts are designed with a modular architecture. PRSubmission owns the state machine for press releases. ContentRegistry provides an immutable content-addressed storage layer. CurationEngine handles voting and curator management. Treasury manages fee distribution and staking rewards. NewsToken is the platform ERC-20 with staking hooks.

Key permission relationships:

  • PRSubmission calls ContentRegistry.register() on submission
  • CurationEngine calls PRSubmission.approvePR()/rejectPR()/removePR() after voting
  • PRSubmission forwards fees to Treasury.distributeNEWS() on approval
  • NewsToken.notifyTreasury() updates Treasury on stake/unstake changes

NewsToken

Symbol: NEWS

The platform ERC-20 token. Fixed supply of 1 billion tokens with built-in staking, unstaking cooldown, and treasury notification hooks.

Deployed Address

text
0xA2E099aCBCf1b85fA4D21dbfa5083fe65B83F9Ad

View on Snowtrace ↗

Key Functions

  • mint(address to, uint256 amount) — Owner-only, capped at MAX_SUPPLY
  • burn(uint256 amount) — Any holder can burn their tokens
  • stake(uint256 amount) — Stake tokens for rewards
  • requestUnstake(uint256 amount) — Start 7-day unstake cooldown
  • claimUnstake() — Claim tokens after cooldown
  • balanceOfStaked(address) — View staked balance
  • unstakeRequests(address) — View pending unstake request

Events

  • Transfer(address indexed from, address indexed to, uint256 value)
  • Approval(address indexed owner, address indexed spender, uint256 value)
  • Staked(address indexed user, uint256 amount)
  • UnstakeRequested(address indexed user, uint256 amount, uint256 releaseTime)
  • UnstakeClaimed(address indexed user, uint256 amount)

PRSubmission

Manages press release lifecycle: submission, state transitions, flagging, and fee handling. Three tiers (Free, Verified, Premium) with different fee/stake requirements.

Deployed Address

text
0x575731b0f3DA45fA9F0de75e886700DDcf440276

View on Snowtrace ↗

Key Functions

  • submitPR(string title, string category, string[] tags, bytes32 contentHash, string arweaveTxId, uint8 tier) — Submit a new PR
  • flagPR(uint256 prId) — Flag a PR for review (requires FLAG_STAKE)
  • approvePR(uint256 prId) — CurationEngine-only: approve a PR
  • rejectPR(uint256 prId) — CurationEngine-only: reject a PR
  • removePR(uint256 prId) — CurationEngine-only: remove a flagged PR
  • finalizeFlaggedPR(uint256 prId, bool approved) — Finalize flagged review
  • getPR(uint256 prId) — View PR details
  • getPendingPRs() — List PRs awaiting curation
  • isPending(uint256 prId) — Check if PR is pending

Events

  • PRSubmitted(uint256 indexed prId, address indexed submitter, string title, string category)
  • PRApproved(uint256 indexed prId)
  • PRRejected(uint256 indexed prId)
  • PRFlagged(uint256 indexed prId, address indexed flagger)
  • PRRemoved(uint256 indexed prId)
  • FeeDistributed(uint256 prId, uint256 amount)

ContentRegistry

Immutable mapping of content hash to Arweave transaction ID. Registered once per PR by PRSubmission — cannot be updated.

Deployed Address

text
0x64d7151DCDf97d8d6231Af538dd1c2Dc566F5c53

View on Snowtrace ↗

Key Functions

  • register(bytes32 contentHash, string arweaveTxId) — PRSubmission-only: register content
  • verify(bytes32 contentHash, string arweaveTxId) — Verify content matches Arweave ID
  • getContentLocation(bytes32 contentHash) — Get Arweave ID for a hash
  • isRegistered(bytes32 contentHash) — Check if hash is registered

CurationEngine

Multi-sig voting system for press release curation. Manages curator applications, voting, slashing, reputation, and reward tracking.

Deployed Address

text
0x3f1264C0a6AFb286DA39F082D7241944d9F96cCc

View on Snowtrace ↗

Key Functions

  • applyAsCurator() — Apply with 500 NEWS stake
  • approveCuratorApplication(address curator) — Owner-only: approve a curator
  • slashCurator(address curator) — Owner-only: slash a curator (50% burn, 50% refund)
  • voteOnPR(uint256 prId, bool approve, string memo) — Vote on a PR
  • finalizeCuration(uint256 prId) — Finalize when threshold met
  • claimRewards() — Claim curator rewards
  • setThresholds(uint256 requiredApprovals, uint256 requiredRejections) — Owner-only
  • getCurator(address) — View curator details
  • getCurationVote(uint256 prId) — View vote tally
  • hasVoted(uint256 prId, address voter) — Check if curator voted
  • getRewardsOwed(address) — View pending rewards

Events

  • CuratorApplied(address indexed curator, uint256 stakeAmount)
  • CuratorApproved(address indexed curator)
  • CuratorSlashed(address indexed curator)
  • VoteCast(uint256 indexed prId, address indexed curator, bool approve)
  • CurationFinalized(uint256 indexed prId, bool result, uint256 qualityScore)
  • RewardsClaimed(address indexed curator, uint256 amount)

Treasury

Manages protocol fees with 40/30/20/10 distribution: treasury reserve, curator rewards, staking rewards, and token burns. Includes Synthetix-style staking reward accumulator.

Deployed Address

text
0xd726D7a7eDB6eB049b2B2211A0f6506DF5A43327

View on Snowtrace ↗

Key Functions

  • getBalances() — View NEWS and AVAX balances
  • claimStakingRewards() — Claim proportional staking rewards
  • accruedStakingRewards(address) — View accrued rewards for a staker
  • withdrawTreasuryReserve(address to, uint256 amount) — Owner-only
  • rewardInitialized(address) — Check if staker received initial snapshot
  • totalBurned() — Total NEWS burned via fee distribution
  • totalStakingRewardsClaimed() — Total NEWS claimed as staking rewards

Events

  • NEWSDistributed(uint256 amount, uint256 treasuryAmount, uint256 curationAmount, uint256 stakingAmount, uint256 burnAmount)
  • StakingRewardsClaimed(address indexed staker, uint256 amount)
  • TreasuryReserveWithdrawn(address indexed to, uint256 amount)