Skip to content

API 參考

CloudBank 預測市場的全面 API 文檔,涵蓋 REST APIs、智能合約介面、GraphQL 查詢和 WebSocket 通道。


Authentication

使用者身份驗證(EIP-191 簽章)

1. POST /api/v1/auth/nonce        → get challenge nonce
2. sign message with wallet                → EIP-191 personal_sign
3. POST /api/v1/auth/login         → submit signature and obtain JWT
4. Authorization: Bearer {token}   → include in subsequent requests

JWT 與 HS256 簽署。聲明包括 JWT(錢包位址)、HS256 和 Subject

管理員認證

  • JWT 承載:JWT 取得存取權限 + 刷新令牌
  • 基本驗證:在引導階段 Authorization: Basic base64(user:pass) 期間使用
  • RBAC:RBAC(完全權限)/superadmin(有限權限)

REST API

基礎 URL: URL

快速 cURL 範例(身份驗證/市場/交易/錢包)

bash
export HOST="https://docs-test.cloudbank.to"
export API="$HOST/api/v1"
export ADDRESS="0xYourWalletAddress"

1)驗證:隨機數+登入

bash
curl -sS -X POST "$API/auth/nonce" \
  -H "Content-Type: application/json" \
  -d "{\"address\":\"$ADDRESS\"}"
json
{
  "nonce": "7fa3f1d9",
  "message": "CloudBank login nonce: 7fa3f1d9",
  "expiresAt": "2026-03-06T00:00:00Z"
}

簽署後,提交登入($SIGNATURE$MESSAGE必須替換為實際的錢包簽署資料):

bash
export MESSAGE="CloudBank login nonce: 7fa3f1d9"
export SIGNATURE="0xYourEIP191Signature"

curl -sS -X POST "$API/auth/login" \
  -H "Content-Type: application/json" \
  -d "{\"address\":\"$ADDRESS\",\"message\":\"$MESSAGE\",\"signature\":\"$SIGNATURE\"}"
json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "custodialWalletAddress": "0x4D7E...A9f2",
  "expiresAt": "2026-03-06T12:00:00Z"
}
bash
export TOKEN="eyJhbGciOi..."

2)市場:查詢市場列表

bash
curl -sS "$API/markets?state=TRADING&limit=20&offset=0" \
  -H "Authorization: Bearer $TOKEN"
json
{
  "items": [
    {
      "id": "0x2E79B7190c463CD11793520d23F63A3d035A94c2",
      "question": "Will BTC close above $80k on Friday?",
      "state": "TRADING",
      "closeTime": "2026-03-08T12:00:00Z"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

3)交易:提交訂單

bash
curl -sS -X POST "$API/orderbook/orders" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "marketId":"0x2E79B7190c463CD11793520d23F63A3d035A94c2",
    "outcome":"YES",
    "side":"BUY",
    "orderType":"LIMIT",
    "price":"0.62",
    "amount":"100"
  }'
json
{
  "orderHash": "0x8f7b...c31d",
  "status": "open",
  "filledAmount": "0",
  "createdAt": "2026-03-05T10:00:00Z"
}

4)皮夾:獲取資訊+提現

bash
curl -sS "$API/wallet/info" \
  -H "Authorization: Bearer $TOKEN"
json
{
  "walletAddress": "0x4D7E...A9f2",
  "balances": {
    "BNB": "0.132",
    "USDC": "1250.50"
  },
  "chainId": 97
}
bash
curl -sS -X POST "$API/wallet/withdraw" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "asset":"USDC",
    "toAddress":"0xReceiverAddress",
    "amount":"25.0"
  }'
json
{
  "txHash": "0x4b17...9f25",
  "asset": "USDC",
  "amount": "25.0",
  "status": "pending"
}

Auth

MethodPathAuth速率限制Description
POSTPOST-100/min/IP產生 EIP-191 挑戰(位址 -> 隨機數 + 訊息)
POSTPOST-5/min/IP驗證簽名並傳回 JWT + custodialWalletAddress

POST POST

json
// Request
{ "address": "0x..." }
// Response
{ "nonce": "abc123", "message": "Sign this message...", "expiresAt": "2026-01-01T00:00:00Z" }

POST POST

json
// Request
{ "address": "0x...", "signature": "0x...", "message": "Sign this message..." }
// Response
{ "token": "eyJ...", "custodialWalletAddress": "0x...", "expiresAt": "2026-01-01T00:00:00Z" }

Wallet

MethodPathAuth速率限制Description
GETGETJWT100/min獲取託管錢包信息
DELETEDELETEJWT100/min刪除託管錢包(需要非功能狀態)
POSTPOSTJWT20/min代簽交易(白名單合約)
POSTPOSTJWT3/min提現BNB/USDC(每日限額)

POST POST

json
// Request
{ "to": "0x...", "data": "0x...", "value": "0", "product": "predict" }
// Response
{ "txHash": "0x...", "gasMode": "paymaster", "status": "pending", "createdAt": "..." }

POST POST

json
// Request
{ "asset": "USDC", "toAddress": "0x...", "amount": "100.5" }
// Response
{ "txHash": "0x...", "asset": "USDC", "amount": "100.5", "fee": "0", "gasMode": "user", "status": "pending" }

Orderbook

MethodPathAuth速率限制Description
GETGET-120/min/IP取得訂單深度
POSTPOSTJWT30/min提交訂單
POSTPOSTJWT30/min混合路線(AMM + 訂單簿)
DELETEDELETEJWT30/min取消訂單
GETGETJWT30/min取得心跳狀態
GETGETJWT-WebSocket 心跳通道

GET GET

?marketId={id}&outcomeTokenId={tokenId}&depth=20
json
// Response
{ "market": "0x...", "bids": [{"price": "0.65", "size": "100"}], "asks": [...] }

邀請關係

MethodPathAuth速率限制Description
GETGET-120/min/IP按邀請人查詢關係
POSTPOSTJWT60/min綁定邀請關係
GETGETJWT60/min獲得自己的邀請關係

管理員——授權

MethodPathAuth速率限制Description
POSTPOST-30/min/IP管理員登入
POSTPOST-30/min/IP刷新令牌

管理員 — 使用者(超級管理員)

MethodPathAuthDescription
GETGET管理員+SA列出所有管理員
GETGET管理員+SA獲取管理員詳細信息
POSTPOST管理員+SA建立管理員
PATCHPATCH管理員+SA更新管理員
POSTPOST管理員+SA重設密碼
POSTPOST管理員+SA綁定操作錢包
POSTPOST管理員+SA解綁操作錢包

管理員 — 保管用戶

MethodPathAuthDescription
GETGETAdmin託管使用者的分頁查詢
GETGETAdmin取得用戶詳細資訊+錢包
DELETEDELETESA永久刪除用戶錢包

管理員 — 操作錢包(超級管理員)

MethodPathAuthDescription
GETGETSA列出操作錢包
GETGETSA獲取錢包詳細信息
POSTPOSTSA創建操作錢包
PATCHPATCHSA更新操作錢包
POSTPOSTAdmin操作錢包代簽交易

管理員 — 白名單

MethodPathAuthDescription
POSTPOSTAdmin新增合約白名單
GETGETAdmin查詢白名單(可依產品過濾)
PATCHPATCHAdmin更新白名單條目
DELETEDELETEAdmin刪除白名單條目

管理員 — 邀請關係(超級管理員)

MethodPathAuthDescription
GETGETSA分頁查詢(支援CSV匯出)
POSTPOSTSA批次匯入(每批 <=500 行)

System

MethodPathAuthDescription
GETGET-健康檢查(SQL/Redis/BSC 狀態)
GETGET-普羅米修斯指標

錯誤代碼

所有錯誤回應都遵循以下格式:

json
{ "code": "error_code", "message": "Human-readable message", "details": {} }
CodeHTTP 狀態Description
invalid_request400請求參數無效
invalid_signature401EIP-191 簽章驗證失敗
invalid_nonce401Nonce 無效或已過期
unauthorized401未經過身份驗證或令牌已過期
forbidden403Forbidden
contract_not_whitelisted403合約未列入白名單
insufficient_bnb400BNB 餘額不足
insufficient_balance400餘額不足
daily_limit_exceeded429超出每日提款限額
not_found404找不到資源
rate_limited429超出速率限制
invite_binding_conflict409邀請關係衝突
invite_request_replayed409重複的綁定請求
invite_self_not_allowed400不允許自行邀請
internal_error500伺服器內部錯誤
service_unavailable503暫停服務

WebSocket

訂單心跳

URL:URL Auth:承載 JWT (查詢參數或標頭)

伺服器→客戶端

json
{ "type": "heartbeat_connected", "status": { ... } }
{ "type": "heartbeat_ack",       "status": { ... } }
{ "type": "error",               "message": "Error description" }

客戶端→伺服器

  • 任何訊息都可以觸發心跳保活
  • 支持標準 WebSocket ping/pong

智能合約介面

OptimisticController

管理生命週期狀態的二元預測市場控制器:TRADING -> PROPOSED -> DISPUTED -> RESOLVED / CANCELLED。

solidity
// Read methods
function getQuestion() external view returns (string memory);
function getMetadata() external view returns (string memory);
function getState() external view returns (MarketState);
function getConditionId() external view returns (bytes32);
function getPositionIds() external view returns (uint256[] memory);
function isActive() external view returns (bool);
function canSettle() external view returns (bool);
function getFeatureFlags() external pure returns (uint256);

// Market management (onlyOwner)
function setMetadata(string calldata metadata) external;
function setOracleAskAfter(uint256 newAskAfter) external;
function depositStake() external;
function proposeOutcome(uint8 outcome, bytes calldata data) external;
function settle(bytes calldata data) external;
function cancelAsInvalid() external;

// Open operations
function disputeOutcome(bytes calldata data) external;
function requestOracleQuestion(bytes calldata data) external payable;
function refundOracleQuestion() external;
function proposeOutcomeFromOracle(bytes calldata data) external;

活動

  • OutcomeProposed(uint8 indexed outcome, address indexed proposer, uint256 timestamp, bytes32 dataHash)
  • OutcomeDisputed(address indexed disputer, uint256 timestamp, bytes32 dataHash)
  • OracleQuestionRequested(bytes32 indexed oracleQuestionId, uint256 deadline, address indexed requester, uint256 value, bytes32 dataHash)
  • StakeProcessed(address indexed creator, address indexed token, uint256 amount, bool refunded)
  • StateTransition(MarketState indexed from, MarketState indexed to)
  • MarketResolved(uint8 indexed outcome, uint256 timestamp)

BinaryCPMM

恆定乘積做市商 (x*y=k),0% 費用,基於 Gnosis CTF ERC-1155 持倉代幣。

solidity
// Read methods
function getReserves() external view returns (uint256 yesReserves, uint256 noReserves);
function getPrice(uint256 tokenId) external view returns (uint256 price1e18);
function quote(uint256 tokenIn, uint256 amountIn) public view returns (uint256 amountOut);

// Liquidity
function addLiquidity(uint256 collateralAmount) external returns (uint256 lpOut);
function removeLiquidity(uint256 lpIn) external returns (uint256 yesOut, uint256 noOut);

// Trading
function swap(uint256 tokenIn, uint256 amountIn, uint256 minOut) external returns (uint256 amountOut);
function swapCollateralForOutcome(uint256 outcomeTokenId, uint256 collateralAmount, uint256 minOutcomeOut) external returns (uint256 outcomeOut);
function sellOutcomeForCollateral(uint256 outcomeTokenId, uint256 outcomeIn, uint256 minCollateralOut) external returns (uint256 collateralOut);
function sellAllOutcomeForCollateral(uint256 outcomeTokenId, uint256 minCollateralOut) external returns (uint256 collateralOut);

活動

  • LiquidityAdded(address indexed provider, uint256 collateralIn, uint256 lpOut)
  • LiquidityRemoved(address indexed provider, uint256 lpIn, uint256 yesOut, uint256 noOut)
  • Swapped(address indexed trader, uint256 indexed tokenIn, uint256 amountIn, uint256 indexed tokenOut, uint256 amountOut)
  • CollateralSwappedForOutcome(address indexed trader, uint256 collateralIn, uint256 indexed outcomeTokenId, uint256 outcomeOut)
  • OutcomeSoldForCollateral(address indexed trader, uint256 indexed outcomeTokenId, uint256 outcomeIn, uint256 collateralOut)

DCPPFactory

透過 EIP-1167 最小代理部署市場 + AMM 的市場工廠。

solidity
// Create market
function createOptimisticMarket(string calldata question, uint256 livenessPeriod, address, uint256, uint8 outcomeSlots) external returns (address market);
function createOptimisticMarket_V2(string calldata question, uint256 livenessPeriod, address, uint256, uint8 outcomeSlots) external returns (address market);
function createOptimisticMarketWithInitialLiquidity(...) external returns (address market, address amm);
function createOptimisticMarketWithInitialLiquidity_V2(...) external returns (address market, address amm);
function createOptimisticMarket_V3(string calldata question, string calldata metadata, ...) public returns (address market, address amm);
function createOptimisticMarket_V4(..., bytes32 key) external returns (address market, address amm);

// Read methods
function getMarketCount() external view returns (uint256);
function getMarketByIndex(uint256 idx) external view returns (address);

// Management (onlyOwner)
function setOracleAdapter(IYesNoOracleAdapter newAdapter) external;
function setMultiOutcomeFactory(address newFactory) external;

MultiOutcomeMarket

組成 N 個獨立二元市場的多選項市場包裝器(一對一模式)。

solidity
function optionCount() external view returns (uint256);
function getOption(uint256 index) external view returns (string label, address market, address amm, uint256 yesTokenId, uint256 noTokenId);
function proposeWinner(uint8 winnerIndex, bytes calldata data) external;  // onlyOwner
function settleWinner(uint8 winnerIndex) external;  // onlyOwner

// Oracle flow
function requestWinnerFromOracle(uint256 deadline, bytes calldata data) external payable returns (bytes32 qid);
function proposeWinnerFromOracle(bytes calldata data) external;
function settleWinnerFromOracle() external;

SoraOracle

最小 Yes/No 預言機,由指定提供者應答。

solidity
function askYesNoQuestion(string calldata question, uint256 deadline) external payable returns (uint256 questionId);
function provideAnswer(uint256 questionId, bool boolAnswer, uint8 confidenceScore, string calldata dataSource) external;  // onlyOracleProvider
function getQuestionWithAnswer(uint256 questionId) external view returns (string, uint256, string, bool, AnswerStatus, uint256);
function refundUnansweredQuestion(uint256 questionId) external;

CloudBankVerifyingPaymaster

ERC-4337 AA Paymaster 具有簽名驗證、每日配額和寄件者白名單。

solidity
function validatePaymasterUserOp(UserOperation calldata userOp, bytes32, uint256 maxCost) external returns (bytes memory context, uint256 validationData);
function postOp(PostOpMode, bytes calldata context, uint256 actualGasCost) external;
function getHash(UserOperation calldata userOp, uint48 validUntil, uint48 validAfter) public view returns (bytes32);

// Management (onlyOwner)
function setVerifyingSigner(address newSigner) external;
function setEnforceSenderAllowlist(bool enabled) external;
function setDailySponsorLimit(uint256 newLimit) external;
function setSenderAllowlist(address sender, bool allowed) external;
function batchSetSenderAllowlist(address[] calldata senders, bool allowed) external;
function deposit() external payable;

FactoryRegistry

工廠註冊表,提供指向目前工廠地址的穩定指針。

solidity
function factory() external view returns (address);
function setFactory(address newFactory) external;  // onlyOwner

關鍵介面

solidity
// IMarket
interface IMarket {
    function getQuestion() external view returns (string memory);
    function getState() external view returns (MarketState);
    function getConditionId() external view returns (bytes32);
    function isActive() external view returns (bool);
    function canSettle() external view returns (bool);
    function settle(bytes calldata data) external;
}

// IYesNoOracleAdapter
interface IYesNoOracleAdapter {
    function ask(string calldata question, uint256 deadline, bytes calldata data) external payable returns (bytes32);
    function getAnswer(bytes32 oracleQuestionId) external view returns (bool finalized, uint8 outcome);
    function refund(bytes32 oracleQuestionId) external returns (uint256 refunded);
}

// IConditionalTokens (Gnosis CTF)
interface IConditionalTokens {
    function prepareCondition(address oracle, bytes32 questionId, uint256 outcomeSlotCount) external;
    function reportPayouts(bytes32 questionId, uint256[] calldata payouts) external;
    function splitPosition(IERC20 collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint256[] calldata partition, uint256 amount) external;
    function mergePositions(IERC20 collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint256[] calldata partition, uint256 amount) external;
    function redeemPositions(IERC20 collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint256[] calldata indexSets) external;
}

GraphQL(圖表/Goldsky)

端點https://api.goldsky.com/api/public/project_{id}/subgraphs/cloudbank-bsc-testnet/{version}/gn

模式實體

Market

graphql
type Market @entity {
  id: ID!                        # Market contract address
  question: String!              # Market question
  conditionId: Bytes!            # CTF condition ID
  state: Int!                    # 0=TRADING, 1=PROPOSED, 2=RESOLVED
  amm: Bytes                     # AMM contract address
  yesTokenId: BigInt             # YES token ID (ERC-1155)
  noTokenId: BigInt              # NO token ID (ERC-1155)
  creator: Bytes!                # Creator address
  createdAtTimestamp: BigInt!
  totalVolume: BigDecimal!       # Total volume (USDC)
  metadataUri: String            # IPFS metadata URI
  category: String               # Market category (parsed from IPFS)
  isMultiOutcome: Boolean!       # Is multi-outcome market
  multiOutcomeMarket: MultiOutcomeMarket
  optionIndex: Int               # Multi-outcome option index
  optionLabel: String            # Multi-outcome option label
  trades: [Trade!]! @derivedFrom(field: "market")
}

Trade

graphql
type Trade @entity {
  id: ID!                        # txHash-logIndex
  market: Market!
  amm: Bytes!
  trader: Bytes!
  user: User!
  type: String!                  # "buy" | "sell"
  side: String!                  # "yes" | "no"
  amountIn: BigInt!
  amountOut: BigInt!
  price: BigDecimal!             # amountIn / amountOut
  outcomeTokenId: BigInt!
  timestamp: BigInt!
  blockNumber: BigInt!
  txHash: Bytes!
}

User

graphql
type User @entity {
  id: ID!                        # Address (lowercase)
  totalVolume: BigDecimal!
  realizedPnL: BigDecimal!
  totalTrades: Int!
  totalBuys: Int!
  totalSells: Int!
  totalProfitableSells: Int!
  firstTradeTimestamp: BigInt!
  lastTradeTimestamp: BigInt!
  trades: [Trade!]! @derivedFrom(field: "user")
  positions: [UserPosition!]! @derivedFrom(field: "user")
}

UserPosition

graphql
type UserPosition @entity {
  id: ID!                        # user-market-side
  user: User!
  market: Market!
  side: String!                  # "yes" | "no"
  shares: BigDecimal!            # Current holdings
  totalBought: BigDecimal!
  totalSold: BigDecimal!
  costBasis: BigDecimal!         # Cost basis
  proceeds: BigDecimal!          # Cumulative proceeds
  isOpen: Boolean!
  openedAtTimestamp: BigInt!
  lastTradeTimestamp: BigInt!
}

MultiOutcomeMarket

graphql
type MultiOutcomeMarket @entity {
  id: ID!
  question: String!
  metadataUri: String
  creator: Bytes!
  optionCount: Int!
  options: [Market!]! @derivedFrom(field: "multiOutcomeMarket")
  createdAtTimestamp: BigInt!
}

常見查詢

取得所有市場

graphql
query GetMarkets {
  markets(orderBy: createdAtTimestamp, orderDirection: desc) {
    id, question, state, amm, yesTokenId, noTokenId, totalVolume, category
    trades(first: 1, orderBy: timestamp, orderDirection: desc) { price, side }
  }
}

取得市場交易

graphql
query GetMarketTrades($marketId: ID!) {
  trades(where: { market: $marketId }, orderBy: timestamp, orderDirection: desc, first: 100) {
    id, trader, type, side, amountIn, amountOut, price, timestamp, txHash
  }
}

取得使用者位置

graphql
query GetUserPositions($user: ID!) {
  user(id: $user) {
    positions(where: { isOpen: true }) {
      side, shares, costBasis, proceeds
      market { id, question, state }
    }
  }
}

排行榜(按數量)

graphql
query GetTopTraders($first: Int!) {
  users(orderBy: totalVolume, orderDirection: desc, first: $first, where: { totalTrades_gt: 0 }) {
    id, totalVolume, realizedPnL, totalTrades, totalProfitableSells
  }
}

獲得多結果市場

graphql
query GetMultiOutcomeMarket($id: ID!) {
  multiOutcomeMarket(id: $id) {
    id, question, optionCount
    options(orderBy: optionIndex) {
      id, optionLabel, state, amm, yesTokenId, noTokenId, totalVolume
    }
  }
}

索引事件

Graph 子圖監聽以下鏈上事件:

ContractEventHandlerEntity
DCPPFactoryDCPPFactoryDCPPFactoryMarket
DCPPFactoryDCPPFactoryDCPPFactoryMarket
MultiOutcomeMarketFactoryMultiOutcomeMarketFactoryMultiOutcomeMarketFactoryMultiOutcomeMarket
MultiOutcomeMarketFactoryMultiOutcomeMarketFactoryMultiOutcomeMarketFactoryMarket
BinaryCPMM(模板)BinaryCPMMBinaryCPMM貿易,用戶,UserPosition
BinaryCPMM(模板)BinaryCPMMBinaryCPMM貿易,用戶,UserPosition
BinaryCPMM(模板)BinaryCPMMBinaryCPMM貿易,用戶,UserPosition

合約位址(BSC 測試網)

ContractAddress
FactoryRegistryFactoryRegistry
DCPPFactoryDCPPFactory
MultiOutcomeMarketFactoryMultiOutcomeMarketFactory
ConditionalTokens (CTF)ConditionalTokens
抵押代幣 (USDC)USDC

速率限制

基於 Redis 的令牌桶策略,具有滑動 1 分鐘窗口,按用戶 ID / 管理員 ID / IP 進行分段。

端點類別LimitIdentifier
驗證隨機數100/minIP
授權登入5/minIP
錢包資訊100/minUser
簽署交易20/minUser
Withdraw3/minUser
邀請綁定60/minUser
已讀訂單簿120/minIP
訂單簿寫入30/minUser
管理員授權30/minIP
管理員操作120/minAdmin
管理標誌30/minAdmin

超出時,返回 429 Too Many Requests + Retry-After 標頭。