Appearance
L3-6: Prediction Market(予測市場)
1. 問題
予測市場は、参加者が将来の出来事(例:「2024年の大統領選で誰が勝つか」)について取引することを可能にし、価格はその出来事の発生確率に対する市場の集合的判断を反映します。オンチェーン実装には3つの中核的課題があります。(1) 「はい」と「いいえ」の結果を表す金融商品をいかに作成するか;(2) 市場作成者と参加者が最終結果を操作できないことをいかに保証するか;(3) 勝者の賞金分配をいかに公正に確保するか、です。
Polymarketのような大規模予測市場とは異なり、このチャレンジでは簡略化されたバージョンを構築します。固定価格でYES/NOシェアペアを購入し、結果は(分散型オラクルではなく)誰でも提出できます。これにより信頼の前提が導入されますが、二元結果+シェア償還という予測市場の中核的メカニズムは保持されています。
2. 理由
Polymarketの成功(月間取引高数十億ドル)は、Web3における予測市場のプロダクトマーケットフィットを検証しました。ブロックチェーンは、パーミッションレスな市場作成、透明な価格設定、信頼不要の決済を提供します。従来の予測市場では法的・地域的制限が主な障壁でしたが、Polymarketは暗号資産を通じてこれらの制限の一部を回避しています。
開発者にとって、予測市場は「条件付きトークン」(conditional tokens)の概念を理解するための優れた入り口です。条件付きトークンフレームワーク(CTF)は、予測市場における各可能な結果を取引可能なERC-1155トークンとしてカプセル化します。この簡略化された実装は、最も本質的な二元市場メカニズム(シェアの購入、市場の決済、賞金の償還)に焦点を当てています。
3. 解決策
PredictionMarket.solはETHベースの二元予測市場を実装しています。
市場の作成:createMarket()は質問の説明と期間を受け取ります。市場構造体には、question(質問)、endTime(終了時間)、resolved(決済済みかどうか)、isYes(結果)、totalYesShares/totalNoShares(総シェア量)が含まれます。
シェアの購入:buyShares()はユーザーがYESとNOの両方のシェアを同時に購入することを許可します。簡略化された価格モデル:各シェアペア(1 YES + 1 NO)= SHARE_PRICE = 0.01 ETH。ユーザーは(yesAmount + noAmount) * SHARE_PRICE ETHを支払い、過剰支払い分は返金されます。これは本質的に「市場全体のエクスポージャーを購入する」モデルであり、ユーザーは両方向のシェアを保有し、不要な方向のシェアを市場で売却できます。
市場の決済:resolveMarket()は誰でも呼び出せます(テスト/教育環境において)。isYesフラグとresolved = trueを設定します。本番環境では、決済は分散型オラクル(UMAのOptimistic OracleやChainlink Functionsなど)によって実行されるべきです。
賞金の償還:redeem()は勝者シェアの保有者が比例配分で賞金を引き出すことを許可します。総賞金プール = 全シェアの総購入コスト (totalYes + totalNo) * SHARE_PRICE。YESが勝利した場合、YESシェア保有者は(myYesShares * totalPool) / totalYesSharesを受け取ります。
参考ソースファイル:src/level3/PredictionMarket.sol
4. 遭遇した落とし穴
- 決済者の信頼性:誰でも
resolveMarket()を呼び出せます。権限制御がない場合、悪意のある行為者が誤った結果を提出する可能性があります - シェアペア価格設定の流動性問題:現在のモデルではユーザーにYESとNOの両方のシェアを同時に購入することを強制しており、単一方向を個別に購入できず、価格発見が制限されます
- 償還後のシェア状態:
redeem()は賞金支払い後にシェアをバーンせず、totalYesShares/totalNoSharesも減少させないため、後続の償還計算に混乱が生じる可能性があります - 賞金プールとコントラクト残高の乖離:賞金プールは
totalShares * SHARE_PRICEに基づいて計算されますが、実際のコントラクト残高は他のエラーや直接転送により一致しない可能性があります - 手数料の欠如:市場作成者は取引手数料などの経済的インセンティブを一切受け取れず、持続可能性に欠けます
5. 落とし穴の原因
決済者の信頼性は、分散型予測市場の中核的問題である「オラクル問題」です。PredictionMarket.solでは、resolveMarket()に権限制御がなく、誰でも呼び出せます。これは教育目的の設計で権限管理が省略されているためです(テスト駆動開発では、テストの便宜上誰でも決済できるべきです)。しかし本番環境では、これが深刻な操作リスクにつながります。
より深層的な問題は、多くの出来事の真の結果が主観的であるか、オフチェーン検証が必要であることです。例えば「ビットコインが2025年に$200Kまで高騰する」— いつ高騰したと見なすのか、どの価格データソースに基づくのか。これらはすべてオラクルによる橋渡しが必要です。UMAのOptimistic Oracleは経済的インセンティブ(チャレンジメカニズム)を通じてこの問題を解決します。決済者はトークンをステークする必要があり、結果が正常にチャレンジされた場合、ステークは没収されます。
シェアペア価格設定モデルも議論に値します。現在のYES+NO同時購入の強制モデルは「簡略化されたバイナリCLOB」として知られています。Polymarketの実際の実装では、CLOB(中央指値オーダーブック)+CTF(条件付きトークンフレームワーク)を使用し、ユーザーがYESまたはNOシェアを個別に売買できるようになっています。価格はオーダーブックの買い板・売り板を通じて自然に発見されます。YESシェアの価格は$0から$1の間で変動し、市場の出来事発生確率に対する判断を反映します。
6. 落とし穴の解決方法
オラクル統合:本番環境では、UMA Optimistic OracleやChainlink Functionsを使用して市場を決済します:
solidity
function resolveMarket(uint256 _marketId) external {
// UMAオラクルから結果を取得
bool outcome = umaOracle.getOutcome(market.question);
// またはChainlink Functionsでオフチェーンデータをリクエスト
// ... 以降のロジック
}
個別シェア購入:buyShares()を独立したbuyYes()とbuyNo()に変更します:
solidity
function buyYes(uint256 _marketId, uint256 _amount) external payable {
uint256 cost = _amount * currentYesPrice; // AMM価格モデルが必要
positions[_marketId][msg.sender].yesShares += _amount;
market.totalYesShares += _amount;
}
価格発見はAMMのx*y=k曲線やCLOBのオーダーブックマッチングを通じて実現できます。
経済的インセンティブ:市場作成者に手数料分配を追加します:
solidity
uint256 public constant CREATOR_FEE_BPS = 100; // 1%
// buySharesで手数料を差し引き、marketCreatorに転送
残高の一貫性:redeem()で式で計算されたtotalPoolではなく、コントラクトの実際の残高から差し引きます:
solidity
uint256 payout = (winningShares * address(this).balance) / totalWinningShares;
7. 技術ポイント
| 技術ポイント | 説明 |
|---|---|
| 二元市場 | YES/NO、2つの相互排他的な結果 |
| シェアペア価格設定 | 1 YES + 1 NO = 0.01 ETH(簡略化モデル) |
| 償還アルゴリズム | 比例配分:(myShares * totalPool) / winningShares |
| 状態機械 | 作成 → 取引中 → 決済 → 償還 |
| リエントランシー保護 | buySharesとredeemにnonReentrantを使用 |
| 過剰支払い返金 | 過剰支払いは自動返金され、UXが向上 |
| オラクル依存 | 決済結果には外部データ入力が必要 |