Skip to main content

Overview

This page documents all events emitted by the Proteus smart contracts. Events provide a way to track on-chain activity and can be efficiently queried using blockchain indexers.

PredictionMarketV2 Events

MarketCreated

Emitted when a new prediction market is created.
event MarketCreated(
    uint256 indexed marketId,
    string actorHandle,
    uint256 endTime,
    address creator
)
marketId
uint256
The ID of the newly created market
actorHandle
string
Social media handle being predicted
endTime
uint256
Unix timestamp when the market ends
creator
address
Address that created the market
Emitted by: createMarket() Example Usage:
// Listen for new markets
predictionMarket.on("MarketCreated", (marketId, actorHandle, endTime, creator) => {
  console.log(`New market ${marketId} for ${actorHandle}`);
  console.log(`Ends at: ${new Date(endTime * 1000)}`);
});

SubmissionCreated

Emitted when a user submits a prediction to a market.
event SubmissionCreated(
    uint256 indexed submissionId,
    uint256 indexed marketId,
    address submitter,
    string predictedText,
    uint256 amount
)
submissionId
uint256
The ID of the newly created submission
marketId
uint256
The market this submission belongs to
submitter
address
Address that created the submission
predictedText
string
The predicted text
amount
uint256
ETH staked on this prediction (in wei)
Emitted by: createSubmission() Example Usage:
// Listen for submissions on a specific market
const marketFilter = predictionMarket.filters.SubmissionCreated(null, marketId);
predictionMarket.on(marketFilter, (submissionId, marketId, submitter, predictedText, amount) => {
  console.log(`New submission ${submissionId}: "${predictedText}"`);
  console.log(`Stake: ${ethers.formatEther(amount)} ETH`);
});

MarketResolved

Emitted when a market is resolved with the actual text.
event MarketResolved(
    uint256 indexed marketId,
    uint256 winningSubmissionId,
    string actualText,
    uint256 winningDistance
)
marketId
uint256
The market that was resolved
winningSubmissionId
uint256
The ID of the winning submission
actualText
string
The actual text the actor posted
winningDistance
uint256
Levenshtein distance of the winning prediction
Emitted by: resolveMarket() Example Usage:
// Listen for market resolutions
predictionMarket.on("MarketResolved", (marketId, winningSubmissionId, actualText, winningDistance) => {
  console.log(`Market ${marketId} resolved!`);
  console.log(`Winner: Submission #${winningSubmissionId}`);
  console.log(`Actual text: "${actualText}"`);
  console.log(`Edit distance: ${winningDistance}`);
});

PayoutClaimed

Emitted when a winner claims their payout.
event PayoutClaimed(
    uint256 indexed submissionId,
    address indexed claimer,
    uint256 amount
)
submissionId
uint256
The winning submission being claimed
claimer
address
Address claiming the payout
amount
uint256
Amount paid out (in wei)
Emitted by: claimPayout() Example Usage:
// Listen for payout claims
predictionMarket.on("PayoutClaimed", (submissionId, claimer, amount) => {
  console.log(`Submission ${submissionId} claimed!`);
  console.log(`Winner: ${claimer}`);
  console.log(`Payout: ${ethers.formatEther(amount)} ETH`);
});

SingleSubmissionRefunded

Emitted when a market with only one submission is refunded.
event SingleSubmissionRefunded(
    uint256 indexed marketId,
    uint256 indexed submissionId,
    address submitter,
    uint256 amount
)
marketId
uint256
The market with single submission
submissionId
uint256
The submission being refunded
submitter
address
Address receiving the refund
amount
uint256
Amount refunded (in wei)
Emitted by: refundSingleSubmission() and emergencyWithdraw() Example Usage:
// Listen for single submission refunds
predictionMarket.on("SingleSubmissionRefunded", (marketId, submissionId, submitter, amount) => {
  console.log(`Market ${marketId} had only one submission`);
  console.log(`Refunded ${ethers.formatEther(amount)} ETH to ${submitter}`);
});

FeesWithdrawn

Emitted when accumulated fees are withdrawn.
event FeesWithdrawn(
    address indexed recipient,
    uint256 amount
)
recipient
address
Address withdrawing fees
amount
uint256
Amount withdrawn (in wei)
Emitted by: withdrawFees() Example Usage:
// Listen for fee withdrawals
predictionMarket.on("FeesWithdrawn", (recipient, amount) => {
  console.log(`${recipient} withdrew ${ethers.formatEther(amount)} ETH in fees`);
});

GenesisNFT Events

GenesisNFTMinted

Emitted when a Genesis NFT is minted.
event GenesisNFTMinted(
    address indexed to,
    uint256 tokenId
)
to
address
Address receiving the NFT
tokenId
uint256
The token ID that was minted
Emitted by: mint() Example Usage:
// Listen for Genesis NFT mints
genesisNFT.on("GenesisNFTMinted", (to, tokenId) => {
  console.log(`Genesis #${tokenId} minted to ${to}`);
});

MintingFinalized

Emitted when minting is finalized.
event MintingFinalized(
    uint256 totalMinted
)
totalMinted
uint256
Total number of NFTs that were minted
Emitted by: finalizeMinting() and automatically by mint() when max supply is reached Example Usage:
// Listen for minting finalization
genesisNFT.on("MintingFinalized", (totalMinted) => {
  console.log(`Minting finalized with ${totalMinted} Genesis NFTs`);
});

Standard ERC721 Events

The GenesisNFT contract also emits standard ERC721 events:

Transfer

Emitted when an NFT is transferred.
event Transfer(
    address indexed from,
    address indexed to,
    uint256 indexed tokenId
)
from
address
Address transferring the NFT (zero address for minting)
to
address
Address receiving the NFT
tokenId
uint256
The token ID being transferred
Emitted by: transferFrom(), safeTransferFrom(), and mint()

Approval

Emitted when an NFT is approved for transfer.
event Approval(
    address indexed owner,
    address indexed approved,
    uint256 indexed tokenId
)
owner
address
Current owner of the NFT
approved
address
Address approved to transfer the NFT
tokenId
uint256
The token ID being approved
Emitted by: approve()

ApprovalForAll

Emitted when an operator is approved/revoked for all of an owner’s NFTs.
event ApprovalForAll(
    address indexed owner,
    address indexed operator,
    bool approved
)
owner
address
Owner of the NFTs
operator
address
Address being approved/revoked as operator
approved
bool
True if operator is approved, false if revoked
Emitted by: setApprovalForAll()

Event Querying Examples

Query Past Events

// Get all markets created in the last 24 hours
const currentBlock = await provider.getBlockNumber();
const blocksPerDay = 7200; // ~12 second blocks
const fromBlock = currentBlock - blocksPerDay;

const marketEvents = await predictionMarket.queryFilter(
  predictionMarket.filters.MarketCreated(),
  fromBlock
);

marketEvents.forEach(event => {
  console.log(`Market ${event.args.marketId}: ${event.args.actorHandle}`);
});

Track User Activity

// Get all submissions by a specific user
const userAddress = "0x...";
const allSubmissions = await predictionMarket.queryFilter(
  predictionMarket.filters.SubmissionCreated(null, null, userAddress)
);

console.log(`User has made ${allSubmissions.length} predictions`);

Monitor Market Resolution

// Wait for a specific market to be resolved
const marketId = 42;
const resolvedEvent = await new Promise((resolve) => {
  predictionMarket.once(
    predictionMarket.filters.MarketResolved(marketId),
    resolve
  );
});

console.log(`Market ${marketId} resolved!`);
console.log(`Winner: ${resolvedEvent.args.winningSubmissionId}`);

Event Indexing

For production applications, consider using event indexing services:
  • The Graph: Create a subgraph to index and query events efficiently
  • Moralis: Real-time event streaming and historical queries
  • Alchemy Notify: Webhook notifications for specific events
  • Etherscan: View all events via the blockchain explorer

Example Subgraph Schema

type Market @entity {
  id: ID!
  marketId: BigInt!
  actorHandle: String!
  endTime: BigInt!
  creator: Bytes!
  submissions: [Submission!]! @derivedFrom(field: "market")
  resolved: Boolean!
  winningSubmission: Submission
  totalPool: BigInt!
}

type Submission @entity {
  id: ID!
  submissionId: BigInt!
  market: Market!
  submitter: Bytes!
  predictedText: String!
  amount: BigInt!
  claimed: Boolean!
}

Best Practices

  1. Use Indexed Parameters: Query events efficiently using indexed parameters (marked with indexed keyword)
  2. Block Range Limits: Most RPC providers limit event queries to 10,000 blocks at a time
  3. Event Confirmation: Wait for multiple block confirmations before considering events finalized
  4. Error Handling: Events may not be available immediately; implement retry logic
  5. Local Caching: Cache event data to reduce RPC calls and improve performance
  6. Websocket Subscriptions: Use websockets for real-time event monitoring instead of polling

Build docs developers (and LLMs) love