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:
Parameter: the function call requires a CreateMarketParamsstruct
structCreateMarketParams { 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 outcomestring questionStart; // Used to build the Reality question on multi scalar marketsstring questionEnd; // Used to build the Reality question on multi scalar marketsstring outcomeType; // Used to build the Reality question on multi scalar marketsuint256 parentOutcome; // conditional outcome to use (optional)address parentMarket; // conditional market to use (optional)string category; // Reality question categorystring lang; // Reality question languageuint256 lowerBound; // Lower bound, only used for scalar marketsuint256 upperBound; // Upper bound, only user for scalar marketsuint256 minBond; // Min bond to use on Realityuint32 openingTime; // Reality question opening timestring[] 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
structRealityParams {bytes32[] questionsIds; // Reality questions idsuint256 templateId; // Reality templateIdstring[] encodedQuestions; // Encoded questions parameters, needed to create and reopen a question}structConditionalTokensParams {bytes32 conditionId; // Conditional Tokens conditionIdbytes32 parentCollectionId; // Conditional Tokens parentCollectionIduint256 parentOutcome; // conditional outcome to use (optional)address parentMarket; // conditional market to use (optional)bytes32 questionId; // Conditional Tokens questionId IERC20[] wrapped1155; //ERC20 tokens addressesbytes[] data; //ERC20 tokens data}stringpublic marketName; // The name of the marketstring[] public outcomes; // The market outcomes, doesn't include the INVALID_RESULT outcomeuint256public lowerBound; // Lower bound, only used for scalar marketsuint256public upperBound; // Upper bound, only user for scalar marketsConditionalTokensParams public conditionalTokensParams; // Conditional Tokens parametersRealityParams 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.
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.