Developer Reference
This page covers the contract interfaces, key function signatures, React hooks, and integration patterns for building on top of UnitFlow Predict.
Contract Addresses (Arc Testnet)
| Contract | Address | Type |
|---|---|---|
| PredictMarketFactory | 0x7Ec112983011db79f907285daBc759643A9D8304 | Proxy |
| PredictMarketFactory (impl) | 0x2EA73225038E9D8b9767B722425c1d69dB8EB748 | Implementation |
| PredictOracle | 0xc40E6653D3a76FAA8F3F68060f1D09AEB5153A15 | Proxy |
| PredictOracle (impl) | 0xbdB7FD8E6FB1a0F3976E46B49C2c92BC532450F1 | Implementation |
| FeeDistributor | 0x0d0425413284ebB4023913ef78Eb207241d3b2eC | Proxy |
| FeeDistributor (impl) | 0x7b528bC0AF9Cd45F3C37982987E99ADD43B9a49E | Implementation |
| USDC | 0x3600000000000000000000000000000000000000 | ERC-20 |
| EURC | 0x89b50855aa3be2f677cd6303cec089b5f319d72a | ERC-20 |
PredictMarketFactory — Key Functions
createMarket
function createMarket(MarketParams calldata params)
external
returns (address marketAddress)
struct MarketParams {
string question;
string description;
string category;
string[] tags;
address currency; // USDC or EURC
uint256 resolutionDate; // unix timestamp, must be future
address resolver; // oracle proxy or custom address
string oracleSource; // description of data source
uint256 initialLiquidity; // >= 10e6 (10 USDC/EURC)
}
// Caller must approve: initialLiquidity + marketCreationFee (5e6)getAllMarkets
function getAllMarkets() external view returns (address[] memory)
marketCreationFee
function marketCreationFee() external view returns (uint256) // Returns 5e6 (5 USDC/EURC)
PredictMarket — Key Functions
stakeYes / stakeNo
function stakeYes(uint256 amount) external function stakeNo(uint256 amount) external // Requirements: // amount >= MIN_STAKE (1e6) // amount <= min(pool × 10%, 100_000e6) // market must be seeded and not resolved // block.timestamp < resolutionDate // caller must have approved this contract for amount
claimReward
function claimReward() external // Requirements: // market must be resolved // caller must have a winning position // caller must not have already claimed
getUserPosition
function getUserPosition(address user)
external view
returns (
uint256 yesShares,
uint256 noShares,
uint256 totalStaked,
bool claimed
)estimatePayout
function estimatePayout(address user)
external view
returns (
uint256 grossPayout,
uint256 netPayout,
uint256 claimFee
)
// Returns (0,0,0) if market not resolved or user has no winning positiongetMarketInfo
function getMarketInfo()
external view
returns (
bytes32 marketId,
string question,
string description,
string category,
string[] tags,
address currency,
uint256 resolutionDate,
address resolver,
string oracleSource,
address creator,
uint256 createdAt
)getParticipants
function getParticipants() external view returns (address[] memory) function getParticipantCount() external view returns (uint256) function getParticipantsPaginated(uint256 offset, uint256 limit) external view returns (address[] memory page, uint256 total)
Pool state
function yesPool() external view returns (uint256) function noPool() external view returns (uint256) function totalStaked() external view returns (uint256) function resolved() external view returns (bool) function outcome() external view returns (bool) function seeded() external view returns (bool)
PredictOracle — Key Functions
// Propose outcome (owner or authorized resolver only) function proposeResolution(address market, bool outcome) external // Dispute during 24h window (anyone) function disputeResolution(address market) external // Finalize after window (anyone) function finalizeResolution(address market) external // Override disputed resolution (owner only) function overrideResolution(address market, bool outcome) external // Read resolution state function resolutions(address market) external view returns ( bool proposedOutcome, uint256 proposedAt, address proposedBy, uint8 status, // 0=None 1=Proposed 2=Disputed 3=Finalized address disputedBy ) uint256 public constant DISPUTE_WINDOW = 24 hours
React Hooks
All hooks live in src/hooks/predict/.
| Hook | Returns |
|---|---|
useOnChainMarkets() | All markets from factory via RPC. Refreshes every 20s. |
useMarkets() | Filtered/sorted market list for the UI. Falls back to mock if factory empty. |
useMarket(idOrAddress) | Single market with live pool state (15s refresh). |
useStake(marketAddress, currency) | stake(amount, isYes), balance, txState. Handles approve + stake in sequence. |
useClaim(marketAddress) | claim(), txState. Calls claimReward(). |
useUserPosition(marketAddress, ...) | Connected wallet's position on one market. Includes payout estimate. |
usePortfolio() | All positions for connected wallet across all markets. |
useOnChainLeaderboard() | Full leaderboard from getParticipants() + getUserPosition(). |
useProtocolStats() | Aggregate volume, market count, participants, fees. |
useResolveMarket(marketAddress) | propose(outcome), finalize(), oracle state. |
useCreateMarket() | createMarket(params), txState, creationFee. |
useAmmEstimate(amount, isYes, pool) | Live share estimate and updated odds for a given stake amount. |
AMM Math Utilities
Pure functions in src/lib/predict/amm.ts. All use BigInt.
import {
getOdds, // { yesOdds, noOdds } in basis points
estimateStakeYes, // { shares, newYesOdds, newNoOdds, fee }
estimateStakeNo,
estimateClaim, // { grossPayout, claimFee, netPayout }
formatTokenAmount,
parseTokenAmount,
} from '@/lib/predict/amm'
// Example: get current odds
const { yesOdds, noOdds } = getOdds({ yesPool, noPool })
// yesOdds = 5800 means 58% implied probability of YES
// Example: estimate a stake
const est = estimateStakeYes(parseTokenAmount('100'), { yesPool, noPool })
// est.shares → shares you receive
// est.newYesOdds → odds after your stake
// est.fee → protocol fee deductedIntegration Example
Reading all markets and a user's positions from a custom component:
import { useOnChainMarkets } from '@/hooks/predict/useOnChainMarkets'
import { usePortfolio } from '@/hooks/predict/usePortfolio'
function MyComponent() {
const { markets, isLoading } = useOnChainMarkets()
const { positions, stats } = usePortfolio()
return (
<div>
<p>{markets.length} markets, {stats.marketsParticipated} participated</p>
{positions.map(p => (
<div key={p.id}>
{p.market.question} — {p.isYes ? 'YES' : 'NO'} — {p.status}
</div>
))}
</div>
)
}Source Code
- predict-smart-contract — Solidity contracts, Hardhat config, deploy and seed scripts
- UnitFlow-dex-test — Next.js frontend, hooks in
src/hooks/predict/, components insrc/components/predict/