UNPKG

@gnosis.pm/pm-contracts

Version:

Collection of smart contracts for the Gnosis prediction market platform

602 lines (497 loc) 63 kB
<!DOCTYPE html> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Developer Guide &mdash; Gnosis Prediction Market Contracts 2.0.0-alpha.2 documentation</title> <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> <link rel="index" title="Index" href="genindex.html"/> <link rel="search" title="Search" href="search.html"/> <link rel="top" title="Gnosis Prediction Market Contracts 2.0.0-alpha.2 documentation" href="index.html"/> <link rel="next" title="Changes from Version 1.x" href="changes-from-v1.html"/> <link rel="prev" title="Gnosis Prediction Market Contracts" href="index.html"/> <script src="_static/js/modernizr.min.js"></script> </head> <body class="wy-body-for-nav" role="document"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search"> <a href="index.html" class="icon icon-home"> Gnosis Prediction Market Contracts </a> <div class="version"> 2.0 </div> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div> <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation"> <p class="caption"><span class="caption-text">Contents:</span></p> <ul class="current"> <li class="toctree-l1 current"><a class="current reference internal" href="#">Developer Guide</a><ul> <li class="toctree-l2"><a class="reference internal" href="#prerequisites">Prerequisites</a></li> <li class="toctree-l2"><a class="reference internal" href="#installation">Installation</a><ul> <li class="toctree-l3"><a class="reference internal" href="#via-npm">Via NPM</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#preparing-a-condition">Preparing a Condition</a><ul> <li class="toctree-l3"><a class="reference internal" href="#a-categorical-example">A Categorical Example</a></li> <li class="toctree-l3"><a class="reference internal" href="#a-scalar-example">A Scalar Example</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#outcome-collections">Outcome Collections</a><ul> <li class="toctree-l3"><a class="reference internal" href="#categorical-example-featuring-alice-bob-and-carol">Categorical Example Featuring Alice, Bob, and Carol</a></li> <li class="toctree-l3"><a class="reference internal" href="#index-set-representation-and-identifier-derivation">Index Set Representation and Identifier Derivation</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#defining-positions">Defining Positions</a></li> <li class="toctree-l2"><a class="reference internal" href="#splitting-and-merging-positions">Splitting and Merging Positions</a><ul> <li class="toctree-l3"><a class="reference internal" href="#basic-splits">Basic Splits</a></li> <li class="toctree-l3"><a class="reference internal" href="#splits-to-deeper-positions">Splits to Deeper Positions</a></li> <li class="toctree-l3"><a class="reference internal" href="#splits-on-partial-partitions">Splits on Partial Partitions</a></li> <li class="toctree-l3"><a class="reference internal" href="#merging-positions">Merging Positions</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="#querying-and-transferring-stake">Querying and Transferring Stake</a></li> <li class="toctree-l2"><a class="reference internal" href="#redeeming-positions">Redeeming Positions</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="changes-from-v1.html">Changes from Version 1.x</a></li> <li class="toctree-l1"><a class="reference internal" href="contributing.html">Contributing</a></li> <li class="toctree-l1"><a class="reference internal" href="glossary.html">Glossary</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"> <nav class="wy-nav-top" role="navigation" aria-label="top navigation"> <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">Gnosis Prediction Market Contracts</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="breadcrumbs navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html">Docs</a> &raquo;</li> <li>Developer Guide</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/developer-guide.rst.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <div class="section" id="developer-guide"> <h1>Developer Guide<a class="headerlink" href="#developer-guide" title="Permalink to this headline">¶</a></h1> <div class="admonition warning"> <p class="first admonition-title">Warning</p> <p class="last">This document refers to a version of the framework which is under development. Some things may change. You may also be interested in <a class="reference external" href="https://gnosis-pm-contracts.readthedocs.io/en/v1/">v1</a> of this framework.</p> </div> <div class="section" id="prerequisites"> <h2>Prerequisites<a class="headerlink" href="#prerequisites" title="Permalink to this headline">¶</a></h2> <p>Usage of this smart contract system requires some proficiency in <a class="reference external" href="https://solidity.readthedocs.io">Solidity</a>.</p> <p>Additionally, this guide will assume a <a class="reference external" href="https://truffleframework.com">Truffle</a> based setup. Client-side code samples will be written in JavaScript assuming the presence of a <a class="reference external" href="https://web3js.readthedocs.io/en/1.0/">web3.js</a> instance and various <a class="reference external" href="https://github.com/trufflesuite/truffle/tree/next/packages/truffle-contract#truffle-contract">TruffleContract</a> wrappers.</p> <p>The current state of this smart contract system may be found on <a class="reference external" href="https://github.com/gnosis/pm-contracts">Github</a>.</p> </div> <div class="section" id="installation"> <h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2> <div class="section" id="via-npm"> <h3>Via NPM<a class="headerlink" href="#via-npm" title="Permalink to this headline">¶</a></h3> <p>This developmental framework may be installed from Github through NPM by running the following:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">npm</span> <span class="n">i</span> <span class="n">gnosis</span><span class="o">/</span><span class="n">pm</span><span class="o">-</span><span class="n">contracts</span> </pre></div> </div> </div> </div> <div class="section" id="preparing-a-condition"> <h2>Preparing a Condition<a class="headerlink" href="#preparing-a-condition" title="Permalink to this headline">¶</a></h2> <p>Before predictive assets can exist in the system, a <em>condition</em> must be prepared. A condition is a question to be answered in the future by a specific oracle in a particular manner. The following function may be used to prepare a condition:</p> <dl class="function"> <dt id="prepareCondition(address,bytes32,uint)"> <em>function </em><code class="descname">prepareCondition</code><span class="sig-paren">(</span><em>address oracle</em>, <em>bytes32 questionId</em>, <em>uint outcomeSlotCount</em><span class="sig-paren">)</span><a class="headerlink" href="#prepareCondition(address,bytes32,uint)" title="Permalink to this definition">¶</a><br /> <em>external</em><br /><a class="headerlink" href="#prepareCondition(address,bytes32,uint)" title="Permalink to this definition">¶</a></dt> <dd><p>This function prepares a condition by initializing a payout vector associated with the condition.</p> <table class="docutils field-list" frame="void" rules="none"> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple"> <li><strong>oracle</strong> – The account assigned to report the result for the prepared condition.</li> <li><strong>questionId</strong> – An identifier for the question to be answered by the oracle.</li> <li><strong>outcomeSlotCount</strong> – The number of outcome slots which should be used for this condition. Must not exceed 256.</li> </ul> </td> </tr> </tbody> </table> </dd></dl> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">It is up to the consumer of the contract to interpret the question ID correctly. For example, a client may interpret the question ID as an IPFS hash which can be used to retrieve a document specifying the question more fully. The meaning of the question ID is left up to clients.</p> </div> <p>If the function succeeds, the following event will be emitted, signifying the preparation of a condition:</p> <dl class="event"> <dt id="ConditionPreparation(bytes32,address,bytes32,uint)"> <em>event </em><code class="descname">ConditionPreparation</code><span class="sig-paren">(</span><em>bytes32 indexed conditionId</em>, <em>address indexed oracle</em>, <em>bytes32 indexed questionId</em>, <em>uint outcomeSlotCount</em><span class="sig-paren">)</span><a class="headerlink" href="#ConditionPreparation(bytes32,address,bytes32,uint)" title="Permalink to this definition">¶</a><br /><a class="headerlink" href="#ConditionPreparation(bytes32,address,bytes32,uint)" title="Permalink to this definition">¶</a></dt> <dd><p>Emitted upon the successful preparation of a condition.</p> <table class="docutils field-list" frame="void" rules="none"> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple"> <li><strong>conditionId</strong> – The condition’s ID. This ID may be derived from the other three parameters via <code class="docutils literal notranslate"><span class="pre">keccak256(abi.encodePacked(oracle,</span> <span class="pre">questionId,</span> <span class="pre">outcomeSlotCount))</span></code>.</li> <li><strong>oracle</strong> – The account assigned to report the result for the prepared condition.</li> <li><strong>questionId</strong> – An identifier for the question to be answered by the oracle.</li> <li><strong>outcomeSlotCount</strong> – The number of outcome slots which should be used for this condition. Must not exceed 256.</li> </ul> </td> </tr> </tbody> </table> </dd></dl> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">The condition ID is different from the question ID, and their distinction is important.</p> </div> <p>The successful preparation of a condition also initializes the following state variable:</p> <dl class="statevar"> <dt id="payoutNumerators"> mapping (bytes32 =&gt; uint[]) <em>public </em><code class="descname">payoutNumerators</code><a class="headerlink" href="#payoutNumerators" title="Permalink to this definition">¶</a></dt> <dd><p>Mapping key is an condition ID. Value represents numerators of the payout vector associated with the condition. This array is initialized with a length equal to the outcome slot count.</p> </dd></dl> <p>To determine if, given a condition’s ID, a condition has been prepared, or to find out a condition’s outcome slot count, use the following accessor:</p> <dl class="function"> <dt id="getOutcomeSlotCount(bytes32)"> <em>function </em><code class="descname">getOutcomeSlotCount</code><span class="sig-paren">(</span><em>bytes32 conditionId</em><span class="sig-paren">)</span><a class="headerlink" href="#getOutcomeSlotCount(bytes32)" title="Permalink to this definition">¶</a><br /> <em>external</em><br /> <em>view</em><br /> <em>returns </em><span class="sig-paren">(</span><em>uint</em><span class="sig-paren">)</span><br /><a class="headerlink" href="#getOutcomeSlotCount(bytes32)" title="Permalink to this definition">¶</a></dt> <dd><p>Gets the outcome slot count of a condition.</p> <table class="docutils field-list" frame="void" rules="none"> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple"> <li><strong>conditionId</strong> – ID of the condition.</li> </ul> </td> </tr> <tr class="field-even field"><th class="field-name">Return:</th><td class="field-body"><p class="first last">Number of outcome slots associated with a condition, or zero if condition has not been prepared yet.</p> </td> </tr> </tbody> </table> </dd></dl> <p>The resultant payout vector of a condition contains a predetermined number of <em>outcome slots</em>. The entries of this vector are reported by the oracle, and their values sum up to one. This payout vector may be interpreted as the oracle’s answer to the question posed in the condition.</p> <div class="section" id="a-categorical-example"> <h3>A Categorical Example<a class="headerlink" href="#a-categorical-example" title="Permalink to this headline">¶</a></h3> <p>Let’s consider a question where only one out of multiple choices may be chosen:</p> <blockquote> <div><p>Who out of the following will be chosen?</p> <ul class="simple"> <li>Alice</li> <li>Bob</li> <li>Carol</li> </ul> </div></blockquote> <p>Through some commonly agreed upon mechanism, the detailed description for this question becomes strongly associated with a 32 byte question ID: <code class="docutils literal notranslate"><span class="pre">0xabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc1234</span></code></p> <p>Let’s also suppose we trust the oracle with address <code class="docutils literal notranslate"><span class="pre">0x1337aBcdef1337abCdEf1337ABcDeF1337AbcDeF</span></code> to deliver the answer for this question.</p> <p>To prepare this condition, the following code gets run:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">await</span> <span class="nx">predictionMarketSystem</span><span class="p">.</span><span class="nx">prepareCondition</span><span class="p">(</span> <span class="s1">&#39;0x1337aBcdef1337abCdEf1337ABcDeF1337AbcDeF&#39;</span><span class="p">,</span> <span class="s1">&#39;0xabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc1234&#39;</span><span class="p">,</span> <span class="mi">3</span> <span class="p">)</span> </pre></div> </div> <p>The condition ID may also be determined from the parameters via:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">web3</span><span class="p">.</span><span class="nx">utils</span><span class="p">.</span><span class="nx">soliditySha3</span><span class="p">({</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;address&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="s1">&#39;0x1337aBcdef1337abCdEf1337ABcDeF1337AbcDeF&#39;</span> <span class="p">},</span> <span class="p">{</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;bytes32&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="s1">&#39;0xabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc1234&#39;</span> <span class="p">},</span> <span class="p">{</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;uint&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="mi">3</span> <span class="p">})</span> </pre></div> </div> <p>This yields a condition ID of <code class="docutils literal notranslate"><span class="pre">0x67eb23e8932765c1d7a094838c928476df8c50d1d3898f278ef1fb2a62afab63</span></code>.</p> <p>Later, if the oracle <code class="docutils literal notranslate"><span class="pre">0x1337aBcdef1337abCdEf1337ABcDeF1337AbcDeF</span></code> makes a report that the payout vector for the condition is <code class="docutils literal notranslate"><span class="pre">[0,</span> <span class="pre">1,</span> <span class="pre">0]</span></code>, the oracle essentially states that Bob was chosen, as the outcome slot associated with Bob would receive all of the payout.</p> </div> <div class="section" id="a-scalar-example"> <h3>A Scalar Example<a class="headerlink" href="#a-scalar-example" title="Permalink to this headline">¶</a></h3> <p>Let us now consider a question where the answer may lie in a range:</p> <blockquote> <div>What will the score be? [0, 1000]</div></blockquote> <p>Let’s say the question ID for this question is <code class="docutils literal notranslate"><span class="pre">0x777def777def777def777def777def777def777def777def777def777def7890</span></code>, and that we trust the oracle <code class="docutils literal notranslate"><span class="pre">0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe</span></code> to deliver the results for this question.</p> <p>To prepare this condition, the following code gets run:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">await</span> <span class="nx">predictionMarketSystem</span><span class="p">.</span><span class="nx">prepareCondition</span><span class="p">(</span> <span class="s1">&#39;0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe&#39;</span><span class="p">,</span> <span class="s1">&#39;0x777def777def777def777def777def777def777def777def777def777def7890&#39;</span><span class="p">,</span> <span class="mi">2</span> <span class="p">)</span> </pre></div> </div> <p>The condition ID for this condition can be calculated as <code class="docutils literal notranslate"><span class="pre">0x3bdb7de3d0860745c0cac9c1dcc8e0d9cb7d33e6a899c2c298343ccedf1d66cf</span></code>.</p> <p>In this case, the condition was created with two slots: one which represents the low end of the range (0) and another which represents the high end (1000). The slots’ reported payout values should indicate how close the answer was to these endpoints. For example, if the oracle <code class="docutils literal notranslate"><span class="pre">0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe</span></code> makes a report that the payout vector is <code class="docutils literal notranslate"><span class="pre">[9/10,</span> <span class="pre">1/10]</span></code>, then the oracle essentially states that the score was 100, as the slot corresponding to the low end is worth nine times what the slot corresponding with the high end is worth, meaning the score should be nine times closer to 0 than it is close to 1000. Likewise, if the payout vector is reported to be <code class="docutils literal notranslate"><span class="pre">[0,</span> <span class="pre">1]</span></code>, then the oracle is saying that the score was <em>at least</em> 1000.</p> </div> </div> <div class="section" id="outcome-collections"> <h2>Outcome Collections<a class="headerlink" href="#outcome-collections" title="Permalink to this headline">¶</a></h2> <p>The main concept for understanding the mechanics of this system is that of a <em>position</em>. We will build to this concept from conditions and outcome slots, and then demonstrate the use of this concept.</p> <p>However, before we can talk about positions, we first have to talk about <em>outcome collections</em>, which may be defined like so:</p> <blockquote> <div>A nonempty proper subset of a condition’s outcome slots which represents the sum total of all the contained slots’ payout values.</div></blockquote> <div class="section" id="categorical-example-featuring-alice-bob-and-carol"> <h3>Categorical Example Featuring Alice, Bob, and Carol<a class="headerlink" href="#categorical-example-featuring-alice-bob-and-carol" title="Permalink to this headline">¶</a></h3> <p>We’ll denote the outcome slots for Alice, Bob, and Carol as <code class="docutils literal notranslate"><span class="pre">A</span></code>, <code class="docutils literal notranslate"><span class="pre">B</span></code>, and <code class="docutils literal notranslate"><span class="pre">C</span></code> respectively.</p> <p>A valid outcome collection may be <code class="docutils literal notranslate"><span class="pre">(A|B)</span></code>. In this example, this outcome collection represents the eventuality in which either Alice or Bob is chosen. Note that for a categorical condition, the payout vector which the oracle reports will eventually contain a one in exactly one of the three slots, so the sum of the values in Alice’s and Bob’s slots is one precisely when either Alice or Bob is chosen, and zero otherwise.</p> <p><code class="docutils literal notranslate"><span class="pre">(C)</span></code> by itself is also a valid outcome collection, and this simply represents the case where Carol is chosen.</p> <p><code class="docutils literal notranslate"><span class="pre">()</span></code> is an invalid outcome collection, as it is empty. Empty outcome collections do not make sense, as they would essentially represent no eventuality and have no value no matter what happens.</p> <p>Conversely, <code class="docutils literal notranslate"><span class="pre">(A|B|C)</span></code> is also an invalid outcome collection, as it is not a proper subset. Outcome collections consisting of all the outcome slots for a condition also do not make sense, as they would simply represent any eventuality, and should be equivalent to whatever was used to collateralize these outcome collections.</p> <p>Finally, outcome slots from different conditions (e.g. <code class="docutils literal notranslate"><span class="pre">(A|X)</span></code>) cannot be composed in a single outcome collection.</p> </div> <div class="section" id="index-set-representation-and-identifier-derivation"> <h3>Index Set Representation and Identifier Derivation<a class="headerlink" href="#index-set-representation-and-identifier-derivation" title="Permalink to this headline">¶</a></h3> <p>A outcome collection may be represented by an a condition and an <em>index set</em>. This is a 256 bit array which denotes which outcome slots are present in a outcome collection. For example, the value <code class="docutils literal notranslate"><span class="pre">3</span> <span class="pre">==</span> <span class="pre">0b011</span></code> corresponds to the outcome collection <code class="docutils literal notranslate"><span class="pre">(A|B)</span></code>, whereas the value <code class="docutils literal notranslate"><span class="pre">4</span> <span class="pre">==</span> <span class="pre">0b100</span></code> corresponds to <code class="docutils literal notranslate"><span class="pre">(C)</span></code>. Note that the indices start at the lowest bit in a <code class="docutils literal notranslate"><span class="pre">uint</span></code>.</p> <p>A outcome collection may be identified with a 32 byte value called a <em>collection identifier</em>. In order to calculate the collection ID for <code class="docutils literal notranslate"><span class="pre">(A|B)</span></code>, simply hash the condition ID and the index set:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">web3</span><span class="p">.</span><span class="nx">utils</span><span class="p">.</span><span class="nx">soliditySha3</span><span class="p">({</span> <span class="c1">// See section &quot;A Categorical Example&quot; for derivation of this condition ID</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;bytes32&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="s1">&#39;0x67eb23e8932765c1d7a094838c928476df8c50d1d3898f278ef1fb2a62afab63&#39;</span> <span class="p">},</span> <span class="p">{</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;uint&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="mb">0b011</span> <span class="c1">// Binary Number literals supported in newer versions of JavaScript</span> <span class="p">})</span> </pre></div> </div> <p>This results in a collection ID of <code class="docutils literal notranslate"><span class="pre">0x52ff54f0f5616e34a2d4f56fb68ab4cc636bf0d92111de74d1ec99040a8da118</span></code>.</p> <p>We may also combine collection IDs for outcome collections for different conditions by adding their values modulo 2^256 (equivalently, by adding their values and then taking the lowest 256 bits).</p> <p>To illustrate, let’s denote the slots for range ends 0 and 1000 from our scalar condition example as <code class="docutils literal notranslate"><span class="pre">LO</span></code> and <code class="docutils literal notranslate"><span class="pre">HI</span></code>. We can find the collection ID for <code class="docutils literal notranslate"><span class="pre">(LO)</span></code> to be <code class="docutils literal notranslate"><span class="pre">0xd79c1d3f71f6c9d998353ba2a848e596f0c6c1a9f6fa633f2c9ec65aaa097cdc</span></code>.</p> <p>The combined collection ID for <code class="docutils literal notranslate"><span class="pre">(A|B)&amp;(LO)</span></code> can be calculated via:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;0x&#39;</span> <span class="o">+</span> <span class="nx">BigInt</span><span class="p">.</span><span class="nx">asUintN</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span> <span class="mh">0x52ff54f0f5616e34a2d4f56fb68ab4cc636bf0d92111de74d1ec99040a8da118</span><span class="nx">n</span> <span class="o">+</span> <span class="mh">0xd79c1d3f71f6c9d998353ba2a848e596f0c6c1a9f6fa633f2c9ec65aaa097cdc</span><span class="nx">n</span> <span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span> </pre></div> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last"><a class="reference external" href="https://tc39.github.io/proposal-bigint/">BigInt</a> is used here for the calculation, though <a class="reference external" href="https://github.com/indutny/bn.js/">BN.js</a> or <a class="reference external" href="https://github.com/MikeMcl/bignumber.js/">BigNumber.js</a> should both also suffice.</p> </div> <p>This calculation yields the value <code class="docutils literal notranslate"><span class="pre">0x2a9b72306758380e3b0a31125ed39a635432b283180c41b3fe8b5f5eb4971df4</span></code>.</p> </div> </div> <div class="section" id="defining-positions"> <h2>Defining Positions<a class="headerlink" href="#defining-positions" title="Permalink to this headline">¶</a></h2> <p>In order to define a position, we first need to designate a collateral token. This token must be an <a class="reference external" href="https://theethereum.wiki/w/index.php/ERC20_Token_Standard">ERC20</a> token which exists on the same chain as the PredictionMarketSystem instance.</p> <p>Then we need at least one condition with a outcome collection, though a position may refer to multiple conditions each with an associated outcome collection. Positions become valuable precisely when <em>all</em> of its constituent outcome collections are valuable. More explicitly, the value of a position is a <em>product</em> of the values of those outcome collections composing the position.</p> <p>With these ingredients, position identifiers can also be calculated by hashing the address of the collateral token and the combined collection ID of all the outcome collections in the position. We say positions are <em>deeper</em> if they contain more conditions and outcome collections, and <em>shallower</em> if they contain less.</p> <p>As an example, let’s suppose that there is an ERC20 token called DollaCoin which exists at the address <code class="docutils literal notranslate"><span class="pre">0xD011ad011ad011AD011ad011Ad011Ad011Ad011A</span></code>, and it is used as collateral for some positions. We will denote this token with <code class="docutils literal notranslate"><span class="pre">$</span></code>.</p> <p>We may calculate the position ID for the position <code class="docutils literal notranslate"><span class="pre">$:(A|B)</span></code> via:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">web3</span><span class="p">.</span><span class="nx">utils</span><span class="p">.</span><span class="nx">soliditySha3</span><span class="p">({</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;address&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="s1">&#39;0xD011ad011ad011AD011ad011Ad011Ad011Ad011A&#39;</span> <span class="p">},</span> <span class="p">{</span> <span class="nx">t</span><span class="o">:</span> <span class="s1">&#39;bytes32&#39;</span><span class="p">,</span> <span class="nx">v</span><span class="o">:</span> <span class="s1">&#39;0x52ff54f0f5616e34a2d4f56fb68ab4cc636bf0d92111de74d1ec99040a8da118&#39;</span> <span class="p">})</span> </pre></div> </div> <p>The ID for <code class="docutils literal notranslate"><span class="pre">$:(A|B)</span></code> turns out to be <code class="docutils literal notranslate"><span class="pre">0x6147e75d1048cea497aeee64d1a4777e286764ded497e545e88efc165c9fc4f0</span></code>.</p> <p>Similarly, the ID for <code class="docutils literal notranslate"><span class="pre">$:(LO)</span></code> can be found to be <code class="docutils literal notranslate"><span class="pre">0xfdad82d898904026ae6c01a5800c0a8ee9ada7e7862f9bb6428b6f81e06f53bb</span></code>, and <code class="docutils literal notranslate"><span class="pre">$:(A|B)&amp;(LO)</span></code> has an ID of <code class="docutils literal notranslate"><span class="pre">0xcc77e750b61d29e158aa3193faa3673b2686ba9f6a16f51b5cdbea2a4f694be0</span></code>.</p> <p>All the positions backed by DollaCoin which depend on the example categorical condition and the example scalar condition form a DAG (directed acyclic graph):</p> <div class="figure align-center" id="id1"> <img alt="DAG of every position which can be made from DollaCoin and the two example conditions, where the nodes are positions, edges are colored by condition, and directionality is implied with vertical spacing." src="_images/all-positions-from-two-conditions.png" /> <p class="caption"><span class="caption-text">Graph of all positions backed by <code class="docutils literal notranslate"><span class="pre">$</span></code> which are contingent on either or both of the example conditions.</span></p> </div> </div> <div class="section" id="splitting-and-merging-positions"> <h2>Splitting and Merging Positions<a class="headerlink" href="#splitting-and-merging-positions" title="Permalink to this headline">¶</a></h2> <p>Once conditions have been prepared, stake in positions contingent on these conditions may be obtained. Furthermore, this stake must be backed by collateral held by the system. In order to ensure this is the case, stake in shallow positions may only be created directly by sending collateral to the system for the system to hold, and stake in deeper positions may only be created by destroying stake in shallower positions. Any of these is referred to as <em>splitting a position</em>, and is done through the following function:</p> <dl class="function"> <dt id="splitPosition(IERC20,bytes32,bytes32,uint[],uint)"> <em>function </em><code class="descname">splitPosition</code><span class="sig-paren">(</span><em>IERC20 collateralToken</em>, <em>bytes32 parentCollectionId</em>, <em>bytes32 conditionId</em>, <em>uint[] partition</em>, <em>uint amount</em><span class="sig-paren">)</span><a class="headerlink" href="#splitPosition(IERC20,bytes32,bytes32,uint[],uint)" title="Permalink to this definition">¶</a><br /> <em>external</em><br /><a class="headerlink" href="#splitPosition(IERC20,bytes32,bytes32,uint[],uint)" title="Permalink to this definition">¶</a></dt> <dd><p>This function splits a position. If splitting from the collateral, this contract will attempt to transfer <cite>amount</cite> collateral from the message sender to itself. Otherwise, this contract will burn <cite>amount</cite> stake held by the message sender in the position being split. Regardless, if successful, <cite>amount</cite> stake will be minted in the split target positions. If any of the transfers, mints, or burns fail, the transaction will revert. The transaction will also revert if the given partition is trivial, invalid, or refers to more slots than the condition is prepared with.</p> <table class="docutils field-list" frame="void" rules="none"> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple"> <li><strong>collateralToken</strong> – The address of the positions’ backing collateral token.</li> <li><strong>parentCollectionId</strong> – The ID of the outcome collections common to the position being split and the split target positions. May be null, in which only the collateral is shared.</li> <li><strong>conditionId</strong> – The ID of the condition to split on.</li> <li><strong>partition</strong> – An array of disjoint index sets representing a nontrivial partition of the outcome slots of the given condition.</li> <li><strong>amount</strong> – The amount of collateral or stake to split.</li> </ul> </td> </tr> </tbody> </table> </dd></dl> <p>If this transaction does not revert, the following event will be emitted:</p> <dl class="event"> <dt id="PositionSplit(address,IERC20,bytes32,bytes32,uint[],uint)"> <em>event </em><code class="descname">PositionSplit</code><span class="sig-paren">(</span><em>address indexed stakeholder</em>, <em>IERC20 collateralToken</em>, <em>bytes32 indexed parentCollectionId</em>, <em>bytes32 indexed conditionId</em>, <em>uint[] partition</em>, <em>uint amount</em><span class="sig-paren">)</span><a class="headerlink" href="#PositionSplit(address,IERC20,bytes32,bytes32,uint[],uint)" title="Permalink to this definition">¶</a><br /><a class="headerlink" href="#PositionSplit(address,IERC20,bytes32,bytes32,uint[],uint)" title="Permalink to this definition">¶</a></dt> <dd><p>Emitted when a position is successfully split.</p> </dd></dl> <p>To decipher this function, let’s consider what would be considered a valid split, and what would be invalid:</p> <div class="figure align-center" id="id2"> <img alt="Various valid and invalid splits of positions." src="_images/valid-vs-invalid-splits.png" /> <p class="caption"><span class="caption-text">Details for some of these scenarios will follow</span></p> </div> <div class="section" id="basic-splits"> <h3>Basic Splits<a class="headerlink" href="#basic-splits" title="Permalink to this headline">¶</a></h3> <p>Collateral <code class="docutils literal notranslate"><span class="pre">$</span></code> can be split into outcome tokens in positions <code class="docutils literal notranslate"><span class="pre">$:(A)</span></code>, <code class="docutils literal notranslate"><span class="pre">$:(B)</span></code>, and <code class="docutils literal notranslate"><span class="pre">$:(C)</span></code>. To do so, use the following code:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="kr">const</span> <span class="nx">amount</span> <span class="o">=</span> <span class="mi">1</span><span class="nx">e18</span> <span class="c1">// could be any amount</span> <span class="c1">// user must allow predictionMarketSystem to</span> <span class="c1">// spend amount of DollaCoin, e.g. through</span> <span class="c1">// await dollaCoin.approve(predictionMarketSystem.address, amount)</span> <span class="nx">await</span> <span class="nx">predictionMarketSystem</span><span class="p">.</span><span class="nx">splitPosition</span><span class="p">(</span> <span class="c1">// This is just DollaCoin&#39;s address</span> <span class="s1">&#39;0xD011ad011ad011AD011ad011Ad011Ad011Ad011A&#39;</span><span class="p">,</span> <span class="c1">// For splitting from collateral, pass bytes32(0)</span> <span class="s1">&#39;0x00&#39;</span><span class="p">,</span> <span class="c1">// &quot;Choice&quot; condition ID:</span> <span class="c1">// see A Categorical Example for derivation</span> <span class="s1">&#39;0x67eb23e8932765c1d7a094838c928476df8c50d1d3898f278ef1fb2a62afab63&#39;</span><span class="p">,</span> <span class="c1">// Each element of this partition is an index set:</span> <span class="c1">// see Outcome Collections for explanation</span> <span class="p">[</span><span class="mb">0b001</span><span class="p">,</span> <span class="mb">0b010</span><span class="p">,</span> <span class="mb">0b100</span><span class="p">],</span> <span class="c1">// Amount of collateral token to submit for holding</span> <span class="c1">// in exchange for minting the same amount of</span> <span class="c1">// outcome token in each of the target positions</span> <span class="nx">amount</span><span class="p">,</span> <span class="p">)</span> </pre></div> </div> <p>The effect of this transaction is to transfer <code class="docutils literal notranslate"><span class="pre">amount</span></code> DollaCoin from the message sender to the <code class="docutils literal notranslate"><span class="pre">predictionMarketSystem</span></code> to hold, and to mint <code class="docutils literal notranslate"><span class="pre">amount</span></code> of outcome token for the following positions:</p> <table border="1" class="docutils"> <colgroup> <col width="11%" /> <col width="89%" /> </colgroup> <thead valign="bottom"> <tr class="row-odd"><th class="head">Symbol</th> <th class="head">Position ID</th> </tr> </thead> <tbody valign="top"> <tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">$:(A)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0x8c12fa3bb72c9c455acd4d6034989ec0ce9188afd7c89c8c42d064ed7fe5a9d8</span></code></td> </tr> <tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">$:(B)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0x21aec03d8dfd8b5f0a2750718fe491e439f3625816e383b66a05cabd56624b4c</span></code></td> </tr> <tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">$:(C)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0x8085f7c500098412ff2fc701a74174527e7b39a2b923cd0bca6ad2d5f7fa348d</span></code></td> </tr> </tbody> </table> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">The previous example, where collateral was split into shallow positions containing collections with one slot each, is similar to <code class="docutils literal notranslate"><span class="pre">Event.buyAllOutcomes</span></code> from v1.</p> </div> <p>The set of <code class="docutils literal notranslate"><span class="pre">(A)</span></code>, <code class="docutils literal notranslate"><span class="pre">(B)</span></code>, and <code class="docutils literal notranslate"><span class="pre">(C)</span></code> is not the only nontrivial partition of outcome slots for the example categorical condition. For example, the set <code class="docutils literal notranslate"><span class="pre">(B)</span></code> (with index set <code class="docutils literal notranslate"><span class="pre">0b010</span></code>) and <code class="docutils literal notranslate"><span class="pre">(A|C)</span></code> (with index set <code class="docutils literal notranslate"><span class="pre">0b101</span></code>) also partitions these outcome slots, and consequently, splitting from <code class="docutils literal notranslate"><span class="pre">$</span></code> to <code class="docutils literal notranslate"><span class="pre">$:(B)</span></code> and <code class="docutils literal notranslate"><span class="pre">$:(A|C)</span></code> is also valid and can be done with the following code:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">await</span> <span class="nx">predictionMarketSystem</span><span class="p">.</span><span class="nx">splitPosition</span><span class="p">(</span> <span class="s1">&#39;0xD011ad011ad011AD011ad011Ad011Ad011Ad011A&#39;</span><span class="p">,</span> <span class="s1">&#39;0x00&#39;</span><span class="p">,</span> <span class="s1">&#39;0x67eb23e8932765c1d7a094838c928476df8c50d1d3898f278ef1fb2a62afab63&#39;</span><span class="p">,</span> <span class="c1">// This partition differs from the previous example</span> <span class="p">[</span><span class="mb">0b010</span><span class="p">,</span> <span class="mb">0b101</span><span class="p">],</span> <span class="nx">amount</span><span class="p">,</span> <span class="p">)</span> </pre></div> </div> <p>This transaction also transfers <code class="docutils literal notranslate"><span class="pre">amount</span></code> DollaCoin from the message sender to the <code class="docutils literal notranslate"><span class="pre">predictionMarketSystem</span></code> to hold, but it mints <code class="docutils literal notranslate"><span class="pre">amount</span></code> of outcome token for the following positions instead:</p> <table border="1" class="docutils"> <colgroup> <col width="14%" /> <col width="86%" /> </colgroup> <thead valign="bottom"> <tr class="row-odd"><th class="head">Symbol</th> <th class="head">Position ID</th> </tr> </thead> <tbody valign="top"> <tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">$:(B)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0x21aec03d8dfd8b5f0a2750718fe491e439f3625816e383b66a05cabd56624b4c</span></code></td> </tr> <tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">$:(A|C)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0xb33b3d0035913315b76e85842f682920f78b32c43c7175768c4c67e3f31e6413</span></code></td> </tr> </tbody> </table> <div class="admonition warning"> <p class="first admonition-title">Warning</p> <p>If non-disjoint index sets are supplied to <code class="docutils literal notranslate"><span class="pre">splitPosition</span></code>, the transaction will revert.</p> <p class="last">Partitions must be valid partitions. For example, you can’t split <code class="docutils literal notranslate"><span class="pre">$</span></code> to <code class="docutils literal notranslate"><span class="pre">$:(A|B)</span></code> and <code class="docutils literal notranslate"><span class="pre">$:(B|C)</span></code> because <code class="docutils literal notranslate"><span class="pre">(A|B)</span></code> (<code class="docutils literal notranslate"><span class="pre">0b011</span></code>) and <code class="docutils literal notranslate"><span class="pre">(B|C)</span></code> (<code class="docutils literal notranslate"><span class="pre">0b110</span></code>) share outcome slot <code class="docutils literal notranslate"><span class="pre">B</span></code> (<code class="docutils literal notranslate"><span class="pre">0b010</span></code>).</p> </div> </div> <div class="section" id="splits-to-deeper-positions"> <h3>Splits to Deeper Positions<a class="headerlink" href="#splits-to-deeper-positions" title="Permalink to this headline">¶</a></h3> <p>It’s also possible to split from a position, burning outcome tokens in that position in order to acquire outcome tokens in deeper positions. For example, you can split <code class="docutils literal notranslate"><span class="pre">$:(A|B)</span></code> to target <code class="docutils literal notranslate"><span class="pre">$:(A|B)&amp;(LO)</span></code> and <code class="docutils literal notranslate"><span class="pre">$:(A|B)&amp;(HI)</span></code>:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">await</span> <span class="nx">predictionMarketSystem</span><span class="p">.</span><span class="nx">splitPosition</span><span class="p">(</span> <span class="c1">// Note that we&#39;re still supplying the same collateral token</span> <span class="c1">// even though we&#39;re going two levels deep.</span> <span class="s1">&#39;0xD011ad011ad011AD011ad011Ad011Ad011Ad011A&#39;</span><span class="p">,</span> <span class="c1">// Here, instead of just supplying 32 zero bytes, we supply</span> <span class="c1">// the collection ID for (A|B).</span> <span class="c1">// This is NOT the position ID for $:(A|B)!</span> <span class="s1">&#39;0x52ff54f0f5616e34a2d4f56fb68ab4cc636bf0d92111de74d1ec99040a8da118&#39;</span><span class="p">,</span> <span class="c1">// This is the condition ID for the example scalar condition</span> <span class="s1">&#39;0x3bdb7de3d0860745c0cac9c1dcc8e0d9cb7d33e6a899c2c298343ccedf1d66cf&#39;</span><span class="p">,</span> <span class="c1">// This is the only partition that makes sense</span> <span class="c1">// for conditions with only two outcome slots</span> <span class="p">[</span><span class="mb">0b01</span><span class="p">,</span> <span class="mb">0b10</span><span class="p">],</span> <span class="nx">amount</span><span class="p">,</span> <span class="p">)</span> </pre></div> </div> <p>This transaction burns <code class="docutils literal notranslate"><span class="pre">amount</span></code> of outcome token in position <code class="docutils literal notranslate"><span class="pre">$:(A|B)</span></code> (position ID <code class="docutils literal notranslate"><span class="pre">0x6147e75d1048cea497aeee64d1a4777e286764ded497e545e88efc165c9fc4f0</span></code>) in order to mint <code class="docutils literal notranslate"><span class="pre">amount</span></code> of outcome token in the following positions:</p> <table border="1" class="docutils"> <colgroup> <col width="19%" /> <col width="81%" /> </colgroup> <thead valign="bottom"> <tr class="row-odd"><th class="head">Symbol</th> <th class="head">Position ID</th> </tr> </thead> <tbody valign="top"> <tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">$:(A|B)&amp;(LO)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0xcc77e750b61d29e158aa3193faa3673b2686ba9f6a16f51b5cdbea2a4f694be0</span></code></td> </tr> <tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">$:(A|B)&amp;(HI)</span></code></td> <td><code class="docutils literal notranslate"><span class="pre">0xbacf3ddf0474d567cd254ea0674fe52ab20a3e2ebca00ec71a846f3c48c5de9d</span></code></td> </tr> </tbody> </table> </div> <div class="section" id="splits-on-partial-partitions"> <h3>Splits on Partial Partitions<a class="headerlink" href="#splits-on-partial-partitions" title="Permalink to this headline">¶</a></h3> <p>Supplying a partition which does not cover the set of all outcome slots for a condition, but instead some outcome collection, is also possible. For example, it is possible to split <code class="docutils literal notranslate"><span class="pre">$:(B|C)</span></code> (position ID <code class="docutils literal notranslate"><span class="pre">0x5d06cd85e2ff915efab0e7881432b1c93b3e543c5538d952591197b3893f5ce3</span></code>) to <code class="docutils literal notranslate"><span class="pre">$:(B)</span></code> and <code class="docutils literal notranslate"><span class="pre">$:(C)</span></code>:</p> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">await</span> <span class="nx">predictionMarketSystem</span><span class="p">.</span><span class="nx">splitPosition</span><span class="p">(</span> <span class="s1">&#39;0xD011ad011ad011AD011ad011Ad011Ad011Ad011A&#39;</span><span class="p">,</span> <span class="c1">// Note that we also supply zeroes here, as the only aspect shared</span> <span class="c1">// between $:(B|C), $:(B) and $:(C) is the collateral token</span> <span class="s1">&#39;0x00&#39;</span><span class="p">,</span> <span class="s1">&#39;0x67eb23e8932765c1d7a094838c928476df8c50d1d3898f278ef1fb2a62afab63&#39;</span><span class="p">,</span> <span class="c1">// This partition does not cover the first outcome slot</span> <span class="p">[</span><span class="mb">0b010</span><span class="p">,</span> <span class="mb">0b100</span><span class="p">],</span> <span class="nx">amount</span><span class="p">,</span> <span class="p">)</span> </pre></div> </div> </div> <div class="section" id="merging-positions"> <h3>Merging Positions<a class="headerlink" href="#merging-positions" title="Permalink to this headline">¶</a></h3> <p>Merging positions does