Market example

Let's consider a question where only one out of multiple choices may be chosen:

Will war in Ukraine stop in 2024?

  • Yes

  • No

Prerequisites

Client-side code samples will be written in JavaScript assuming the presence of ethers library. We will also use a forked Gnosis chain. We will need sDai address from GnosisRouter:

IERC20 public constant sDAI =
        IERC20(0xaf204776c7245bF4147c2612BF6e5972Ee483701);
sDAI = await ethers.getContractAt("ISavingsXDai", GnosisAddress.S_DAI);

Before we begin, we still need to deploy multiple dependent contracts, namely ConditionalTokens, Realitio, RealityProxy, Wrapped1155Factory, Market.

const market = await ethers.deployContract("Market");
const realitio = await ethers.deployContract("RealityETH_v3_0");
const wrapped1155Factory = await ethers.deployContract("Wrapped1155Factory");
const conditionalTokens = await ethers.deployContract("ConditionalTokens");

We will also need an arbitrator, however, for demo purpose, we will use a zero address:

const arbitrator = "0x0000000000000000000000000000000000000000";

After deploying dependent contracts, we will deploy our main contracts, MarketFactory and GnosisRouter:

const [owner] = await ethers.getSigners();
const governor = owner.address;
// Deploy MarketFactory
const marketFactory = await (
  await ethers.getContractFactory("MarketFactory")
).deploy(
  market,
  arbitrator,
  realitio,
  wrapped1155Factory,
  conditionalTokens,
  await collateralToken.getAddress(),
  realityProxy,
  QUESTION_TIMEOUT //60 * 60 * 24 * 3.5;
);

//Deploy GnosisRouter
const gnosisRouter = await (
      await ethers.getContractFactory("GnosisRouter")
  ).deploy(conditionalTokens, wrappedERC20Factory);

Create market

To create this market, one can run the following code:

await marketFactory.createCategoricalMarket({
  marketName: "Will war in Ukraine stop in 2024?",
  category: "misc",
  lang: "en_US",
  parentOutcome: 0 // only used in conditional market,
  parentMarket: "0x0000000000000000000000000000000000000000", // only used in conditional market
  questionStart: "", // only used in multi-scalar
  questionEnd: "", // only used in multi-scalar
  outcomeType: "", // only used in multi-scalar
  outcomes: ["Yes", "No"],
  lowerBound: 0, // only used in scalar
  upperBound: 0, // only used in scalar
  minBond: "1000",
  openingTime: 1735603200, //2024-12-31T00:00:00.000Z
  tokenNames: ["YES", "NO"],
})

After the call, we will create a Market contract, which address is stored in MarketFactory.

Since this is the first market we created, we can access its address at index 0.

const marketAddress = (await marketFactory.allMarkets())[0];
const market = await ethers.getContractAt("Market", marketAddress);

Split position

We will then call splitFromBase to deposit our collateral token (sDai) and receive ERC20 outcome tokens. In this case, we will receive 3 sets of tokens: YES, NO, INVALID_RESULT (INVALID_RESULT is default for every market):

await gnosisRouter.splitFromBase(
      market,
      { value: "1000" }
);

Parameters:

market: The market to split.

After the call, we will have ERC20 outcome tokens, ready to be traded.

Answer Reality Question

After the opening time, Reality question can be answered. You can learn more about how Reality works here. Basically, it allows multiple players to provide answers for a question in a decentralized manner, and the final correct answer will be rewarded:

await realitio.submitAnswer(
  questionId,
  ethers.toBeHex(BigInt(0), 32), // answer slot. Yes: 0 | No: 1 | Invalid: 2. We choose 0 in this case.
  0, // max_previous. If specified, reverts if a bond higher than this was submitted after you sent your transaction.
  {
    value: "1000", //the bond for this answer, must be higher than the current bond
  }
);

Resolve the market

After the answer is finalized, we can resolve the market:

await realityProxy.resolve(market);

This will calculate payouts for every outcomes and send the result to ConditionalTokens. In this case, since the finalized answer is 0, the payouts will be [1,0,0]. It means that outcome tokens at index 0 can be redeemed for full amount collateral, while outcome tokens at index 1 and 2 will be redeemed for zero amount.

Redeem positions

A user with ERC20 outcome tokens can redeem their winning positions for collateral token (sDai in this case). For example, if you want to redeem YES tokens only, you can pass an array that contains only outcome index 0.

await gnosisRouter.redeemToBase(
    market,
    [0], // array of outcome indexes,
    [1000n], // array of redeem amounts
);

Parameters:

market: The market to split.

outcomeIndexes: An array of outcome indexes you want to redeem.

amounts: Amount to redeem of each outcome.

To learn more about how split, merge, and redeem work under the hood, visit Gnosis Conditional Tokens Documentation.

Last updated