ERC-XXXX: NFT-Bound Prediction Markets (LMSR pricing, on-chain state)
Abstract This proposes a standard for prediction markets bound one-to-one to NFTs. Each ERC-721 token represents ownership of a single binary (YES/NO) market. The market’s state — question text, current odds, pool balance, resolution status — is stored on-chain and rendered as the token’s tokenURI SVG, so the NFT is not a receipt for a market elsewhere; the NFT is the market. Pricing uses an on-chain Logarithmic Market Scoring Rule (LMSR) with fixed liquidity parameter b, settled in native chain currency. Market owners set the question once per cycle, earn a per-trade fee for the life of that token, and can reset the market on a new question after resolution. Resolution is oracle-driven with an optimistic dispute window. Motivation Existing prediction market designs treat markets as either (a) protocol-owned singletons (Augur, Polymarket) or (b) ephemeral rows in a database with a settled-on-chain payout. Both patterns give up the composability that makes tokens interesting: You can’t transfer a market, or list one for sale on an NFT marketplace. You can’t display a market’s live state in a wallet’s NFT view without off-chain metadata. The market’s economic upside (fees) can’t be sold or delegated separately from the market itself. Binding a market to an ERC-721 token solves all three. The market has an owner (the token holder), can be traded, and renders self-contained state to any ERC-721-aware surface. Question ownership becomes a transferable right rather than a smart-contract permission list. Specification A conforming contract MUST implement ERC-721 and MUST expose the following interface. The pricing math, resolution flow, and rendering are specified below. interface IOFT /* is IERC721 */ { // ----- Market lifecycle ----- function setQuestion(uint256 tokenId, string calldata question, uint64 lockTime) external; function resetMarket(uint256 tokenId, string calldata newQuestion, uint64 lockTime) external; // ----- Trading ----- function buy(uint256 tokenId, bool outcome, uint256 minShares) external payable returns (uint256 shares); function sell(uint256 tokenId, bool outcome, uint256 shares, uint256 minReturn) external returns (uint256 payout); function redeem(uint256 tokenId) external returns (uint256 payout); function refund(uint256 tokenId) external returns (uint256 refunded); // ----- Resolution ----- function resolve(uint256 tokenId, bool outcome) external; function dispute(uint256 tokenId, bool proposedOutcome) external payable; // ----- Views ----- function marketState(uint256 tokenId) external view returns (MarketState memory); function priceOf(uint256 tokenId, bool outcome) external view returns (uint256 priceWad); function costToBuy(uint256 tokenId, bool outcome, uint256 shares) external view returns (uint256 cost); } LMSR pricing. Cost function C(q_yes, q_no) = b · ln(exp(q_yes/b) + exp(q_no/b)). Trade cost is C(q_new) − C(q_current). Price of an outcome is exp(q_i/b) / (exp(q_yes/b) + exp(q_no/b)). Implementations MUST use fixed-point math with at least 18 decimals of precision (PRBMath, ABDK, or equivalent). b is set at market creation and is immutable per cycle. Fees. A conforming implementation MUST support: ownerFeeBps — accrued to the NFT holder, paid on every buy and sell protocolFeeBps — accrued to a treasury address set at deploy Both are basis-point values. Fee accrual is per-market so a market transfer transfers the fee stream with the token. Resolution. Two-phase: Propose. After lockTime, an oracle or permitted resolver calls resolve(tokenId, outcome). Starts a dispute window (e.g. 24h). Dispute. During the window, anyone can dispute(tokenId, proposedOutcome) with a bonded challenge. Disputed markets fall back to a slower resolution (e.g. UMA, second oracle, or owner-signed). Rendering. tokenURI returns a data URI containing an SVG that renders question text, current YES/NO prices, pool balance, and resolution state. This MUST be self-contained (no external image URLs, no IPFS dependency) so the market is legible in a wallet even if the frontend is offline. Rationale Why one NFT per market instead of ERC-1155 or a market registry? ERC-721 is the only widely-supported “one owner per thing” primitive with existing marketplace liquidity, wallet display, and royalty enforcement. A market registry inside a single contract loses transfer semantics. Why LMSR over CPMM (Uniswap-style)? LMSR gives bounded loss for the market maker (bounded by b), guarantees a price is always quotable regardless of liquidity, and doesn’t require initial liquidity provision from an LP. For binary outcomes with unknown volume, this is well-studied and better than CPMM. Why native ETH instead of a wrapped stable? Removes one dependency and one approval step. Implementations MAY offer an ERC-20 variant; the base spec is native. Why owner-set questions rather than protocol-set? Makes the token productive — the holder decides what market their NFT represents each cycle. Combined with reset semantics, one NFT can serve many markets over its lifetime. Backwards Compatibility Fully compatible with ERC-721, ERC-2981 (royalties on secondary market sales), and ERC-165 (interface detection). Existing NFT marketplaces will display and trade these tokens without modification. Security Considerations LMSR precision. Naïve implementations of exp and ln in fixed-point can drift. Reference implementations should include invariant tests that price_yes + price_no ≈ 1 within tolerance across the full range of q. Reentrancy on payout. sell, redeem, and refund transfer native currency. Standard checks-effects-interactions and reentrancy guards apply. Fee accounting on transfer. Owner-fee accrual must be settled on NFT transfer to prevent buyers inheriting unclaimed fees or sellers losing them. Oracle capture. The proposal → dispute flow assumes an honest oracle at least most of the time. Implementations should document their fallback resolver and dispute bond sizing. Refund path. If a market never resolves (oracle silence beyond a timeout), a refund path returns all trader collateral pro rata. This must be permissionless. Open Questions Would appreciate feedback specifically on: Interface surface. Is resetMarket distinct enough from setQuestion to justify a separate function, or should question-setting on a resolved market implicitly reset? Multi-outcome extension. Should the spec accommodate N-ary outcomes (not just binary) at the interface level, or is binary the base and N-ary a separate ERC? Dispute bond currency. Native or ERC-20? Native keeps dependencies low but forces bond sizing to be denominated in a volatile asset. SVG rendering budget. Full on-chain SVG has a gas cost. Is tokenURI returning a base64 data URI acceptable, or should a lightweight thumbnail + separate marketMetadataURI be normative? b (liquidity depth) mutability. Fixed per cycle is simplest and safest. Some implementations want dynamic b for capital efficiency. Worth accommodating in the standard or leave to extension? A reference implementation is in progress and will be linked once the discussion has settled enough to freeze the interface. Feedback welcome from anyone who’s worked on LMSR precision, oracle escalation, or on-chain SVG rendering. Thanks for reading. twitter: oftrobinhood site: oftrh .xyz 1 post - 1 participant Read full topic
DeFi Intel is an entity-graph aggregator: we curate, tag and link crypto news to a typed knowledge graph of protocols, tokens, people and incidents. We do not republish the full article body. Use the link above to read the original report at Ethereum_magicians.
Want the full article?
Continue reading on Ethereum_magicians →