To create a market, the user calls one of the market creation functions inside the MarketFactory contract. The steps to create a prediction market are quite similar among different market types.
For example, the following function may be used to create a categorical market:
function createCategoricalMarket(CreateMarketParams calldata params) external returns (address)
Parameter: the function call requires a CreateMarketParamsstruct
struct CreateMarketParams {
string marketName; // Used only in categorical, multi categorical, and scalar markets. In multi scalar markets, the market name is formed using questionStart + outcomeType + questionEnd.
string[] outcomes; // The market outcomes, doesn't include the INVALID_RESULT outcome
string questionStart; // Used to build the Reality question on multi scalar markets
string questionEnd; // Used to build the Reality question on multi scalar markets
string outcomeType; // Used to build the Reality question on multi scalar markets
uint256 parentOutcome; // conditional outcome to use (optional)
address parentMarket; // conditional market to use (optional)
string category; // Reality question category
string lang; // Reality question language
uint256 lowerBound; // Lower bound, only used for scalar markets
uint256 upperBound; // Upper bound, only user for scalar markets
uint256 minBond; // Min bond to use on Reality
uint32 openingTime; // Reality question opening time
string[] tokenNames; // Name of the ERC20 tokens associated to each outcome
}
If the function succeeds, the newly created market address will be stored in a state variable:
address[] public markets; // Markets created by this factory
while the actual market information will be stored in a separate Market contract:
Market.sol
struct RealityParams {
bytes32[] questionsIds; // Reality questions ids
uint256 templateId; // Reality templateId
string[] encodedQuestions; // Encoded questions parameters, needed to create and reopen a question
}
struct ConditionalTokensParams {
bytes32 conditionId; // Conditional Tokens conditionId
bytes32 parentCollectionId; // Conditional Tokens parentCollectionId
uint256 parentOutcome; // conditional outcome to use (optional)
address parentMarket; // conditional market to use (optional)
bytes32 questionId; // Conditional Tokens questionId
IERC20[] wrapped1155; //ERC20 tokens addresses
bytes[] data; //ERC20 tokens data
}
string public marketName; // The name of the market
string[] public outcomes; // The market outcomes, doesn't include the INVALID_RESULT outcome
uint256 public lowerBound; // Lower bound, only used for scalar markets
uint256 public upperBound; // Upper bound, only user for scalar markets
ConditionalTokensParams public conditionalTokensParams; // Conditional Tokens parameters
RealityParams public realityParams; // Reality parameters
questionId is a hash of all the values that RealityProxy.resolve() uses to resolve a market, this way if an attacker tries to resolve a fake market by changing some value its questionId will not match the id of a valid market
bytes32 questionId = keccak256(
abi.encode(
questionsIds,
params.outcomes.length,
config.templateId,
params.lowerBound,
params.upperBound
)
);
For multi-scalar markets, marketName is questionStart + outcomeType + questionEnd
Setup one or multiple Reality questions. A market may contain one or multiple questions waiting to be resolved by an oracle. Reality is chosen for this task.
Prepare a Condition. Each market corresponds to a conditionId. This conditionId will be used in the ConditionalTokens contract to resolve the market.
function prepareCondition(
bytes32 questionId,
uint outcomeSlotCount
) internal returns (bytes32)
ERC20 Position Tokens Creation. For each possible outcome (including an "Invalid" outcome), the contract creates a wrapped ERC20 token representing this position using Wrapped1155Factory. The tokens addresses and data will be saved in the Market contract.