<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AGON</title>
    <description>The latest articles on DEV Community by AGON (@agon_markets).</description>
    <link>https://dev.to/agon_markets</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972617%2F9cb60d3b-7e2e-48f8-b1f7-ac049b6c588c.png</url>
      <title>DEV Community: AGON</title>
      <link>https://dev.to/agon_markets</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agon_markets"/>
    <language>en</language>
    <item>
      <title>AGON — CPMM binary markets</title>
      <dc:creator>AGON</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:29:20 +0000</pubDate>
      <link>https://dev.to/agon_markets/agon-cpmm-binary-markets-421e</link>
      <guid>https://dev.to/agon_markets/agon-cpmm-binary-markets-421e</guid>
      <description>&lt;p&gt;A binary prediction market asks one question — &lt;em&gt;will X happen, yes or no?&lt;/em&gt; — and lets people trade two outcome tokens, &lt;strong&gt;YES&lt;/strong&gt; and &lt;strong&gt;NO&lt;/strong&gt;, against a pool of collateral. The interesting engineering question is: with no order book and no human market maker, &lt;strong&gt;how does the price get set, and why does that price behave like a probability?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer most on-chain prediction markets reach for is the same automated-market-maker (AMM) math that powers token swaps: the &lt;strong&gt;constant-product&lt;/strong&gt; rule, &lt;code&gt;x · y = k&lt;/code&gt;. This post walks the full path — pricing, the YES + NO ≈ 1 identity, slippage, the ERC-1155 conditional-token plumbing underneath, USDC's 6-decimal accounting, and settlement — with code you can actually run. I'm building this stack on &lt;a href="https://agon.markets" rel="noopener noreferrer"&gt;AGON&lt;/a&gt;, a permissionless prediction-market app on Base (currently public testnet on Base Sepolia), so the conventions below mirror a real deployment rather than a toy.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The invariant: &lt;code&gt;x · y = k&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Uniswap v2 formalized the constant-product market maker: a pool holds reserves &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; of two tokens, and every trade must keep their product &lt;code&gt;k = x · y&lt;/code&gt; constant (it only grows from fees). The reference &lt;code&gt;getAmountOut&lt;/code&gt; from the v2 periphery library is the canonical statement of the rule, fee included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Uniswap v2 — UniswapV2Library.getAmountOut
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
    internal pure returns (uint amountOut)
{
    uint amountInWithFee = amountIn * 997;                 // 0.30% fee: 997/1000
    uint numerator       = amountInWithFee * reserveOut;
    uint denominator     = reserveIn * 1000 + amountInWithFee;
    amountOut = numerator / denominator;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;997/1000&lt;/code&gt; is a 0.30% fee skimmed off the input before the swap. Set the fee aside (&lt;code&gt;997 → 1000&lt;/code&gt;) and you get the clean invariant: &lt;code&gt;(reserveIn + amountIn) · (reserveOut − amountOut) = reserveIn · reserveOut&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A naive way to build a binary market is one such pool — YES against NO — but prediction markets have a cleaner construction.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. From two reserves to a probability
&lt;/h2&gt;

&lt;p&gt;Gnosis adapted the constant-product idea specifically for prediction markets in its &lt;strong&gt;Fixed Product Market Maker (FPMM)&lt;/strong&gt;. Instead of pricing one token against another, it holds an inventory of &lt;em&gt;every&lt;/em&gt; outcome token and keeps the &lt;strong&gt;product of all outcome balances constant&lt;/strong&gt;. The neat consequence is the pricing formula (straight from the Gnosis docs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oddsWeightForOutcome_i = product( balance_j  for every j ≠ i )
price_i                = oddsWeightForOutcome_i / Σ_k oddsWeightForOutcome_k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a &lt;strong&gt;binary&lt;/strong&gt; market with just YES and NO balances, the products collapse to a single term each, and the price of an outcome is simply the &lt;em&gt;other&lt;/em&gt; side's balance over the total:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;price(YES) = balance(NO) / ( balance(YES) + balance(NO) )
price(NO)  = balance(YES) / ( balance(YES) + balance(NO) )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things fall out immediately, and they are the whole point:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;price(YES) + price(NO) = 1&lt;/code&gt;&lt;/strong&gt; by construction — the prices are a normalized probability distribution.&lt;/li&gt;
&lt;li&gt;Each price is the market's &lt;strong&gt;implied probability&lt;/strong&gt; of that outcome. A YES trading at 0.65 USDC is the crowd saying "≈ 65% likely."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here it is in TypeScript, with prices and the implied probability derived from raw on-chain balances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Wei&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BinaryPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Wei&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// outcome-token balance held by the AMM&lt;/span&gt;
  &lt;span class="nl"&gt;no&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Wei&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Spot prices for a binary FPMM. price(YES)+price(NO) === 1. */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;spotPrices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BinaryPool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;no&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty pool&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// price(YES) = balanceNO / total ; price(NO) = balanceYES / total&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;no&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Inventory: more NO than YES held =&amp;gt; YES is the scarcer, pricier side.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BinaryPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000_000n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;no&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="nx"&gt;_000_000n&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spotPrices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0.7000 0.3000&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Implied P(YES) = &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 70.0%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the inversion: the AMM is &lt;em&gt;long&lt;/em&gt; the outcome it holds more of, so a large NO inventory makes YES the scarcer, more expensive side. That is the mechanism by which buying pushes a price up — you remove tokens from the side you buy, shrinking its balance and raising its price toward 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Slippage and price impact
&lt;/h2&gt;

&lt;p&gt;Spot price is the marginal price for an infinitesimal trade. Real fills move along the curve, so the &lt;strong&gt;average&lt;/strong&gt; price you pay is worse than spot — that gap is price impact. Because the FPMM keeps the product of balances invariant, you can compute the exact tokens received for a given USDC stake. For a binary market, buying YES adds your (post-fee) collateral to &lt;em&gt;both&lt;/em&gt; outcome pools (the collateral is split into a complete set), then drains YES until the product is restored:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ONE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// fixed-point scale used by Gnosis FPMM math&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Outcome tokens received when buying YES with `investment` of collateral.
 * Mirrors Gnosis FixedProductMarketMaker.calcBuyAmount for the 2-outcome case.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calcBuyYes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BinaryPool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;investment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Wei&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;feeBps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Wei&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;investment&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;feeBps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// e.g. 200 bps = 2%&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;investment&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;fee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                       &lt;span class="c1"&gt;// collateral after fee&lt;/span&gt;

  &lt;span class="c1"&gt;// A complete set adds `dx` to every outcome pool; YES is then sold down.&lt;/span&gt;
  &lt;span class="c1"&gt;// ending = yes' such that  yes' * (no + dx) == yes * no   (product preserved&lt;/span&gt;
  &lt;span class="c1"&gt;// across the other outcome). Scaled by ONE for precision, as in the contract.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ONE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;ONE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Tokens out = collateral you put into the YES pool, minus what's left.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;ending&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;_000_000n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 50 USDC (6 decimals) — see §4&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calcBuyYes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;avgPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`bought &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; YES shares, avg price &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;avgPrice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; USDC`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The takeaway is structural: &lt;strong&gt;price impact scales inversely with pool depth.&lt;/strong&gt; A market seeded with deep liquidity moves little on a 50-USDC trade; a thin one lurches. Anyone sizing a position — human or bot — has to read depth, not just the headline price.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. USDC and 6-decimal accounting
&lt;/h2&gt;

&lt;p&gt;The collateral is USDC, which has &lt;strong&gt;6 decimals&lt;/strong&gt;, not 18. This is the single most common footgun in this codebase, so it's worth being explicit: &lt;code&gt;1 USDC == 1_000_000&lt;/code&gt; base units. Outcome-token "shares" are denominated to redeem 1:1 against collateral, so one winning share pays out exactly &lt;code&gt;1_000_000&lt;/code&gt; USDC base units.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usdc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;human&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;human&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nf"&gt;usdc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// 50_000_000n&lt;/span&gt;
&lt;span class="nf"&gt;usdc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// 700_000n  → the cost of one YES share at price 0.70&lt;/span&gt;

&lt;span class="c1"&gt;// A winning ticket: shares * 1 USDC each.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="nx"&gt;_400_000n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                 &lt;span class="c1"&gt;// ~71.4 shares (6dp)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shares&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                       &lt;span class="c1"&gt;// 1 share -&amp;gt; 1 USDC base unit&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`redeems for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDC`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 71.4 USDC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mixing 18-decimal AMM scaling (the &lt;code&gt;ONE&lt;/code&gt; factor) with 6-decimal collateral is exactly why production code keeps the fixed-point math in &lt;code&gt;1e18&lt;/code&gt; space and only converts at the collateral boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The tokens: ERC-1155 conditional tokens
&lt;/h2&gt;

&lt;p&gt;YES and NO aren't bespoke ERC-20s. The clean construction is &lt;strong&gt;Gnosis Conditional Tokens (CTF)&lt;/strong&gt; on top of &lt;strong&gt;ERC-1155&lt;/strong&gt;. EIP-1155 is the multi-token standard whose whole premise is that "a single deployed contract may include any combination of fungible tokens, non-fungible tokens or other configurations" — so every outcome of every market is just another token ID in one contract, instead of a fresh ERC-20 deploy per market. (A common convention, used on AGON, is &lt;code&gt;tokenId(YES) = marketId·2&lt;/code&gt;, &lt;code&gt;tokenId(NO) = marketId·2 + 1&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;The CTF gives you three operations, with these signatures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Gnosis ConditionalTokens (abbreviated)
function splitPosition(IERC20 collateral, bytes32 parentCollectionId,
    bytes32 conditionId, uint[] calldata partition, uint amount) external;

function mergePositions(IERC20 collateral, bytes32 parentCollectionId,
    bytes32 conditionId, uint[] calldata partition, uint amount) external;

function redeemPositions(IERC20 collateral, bytes32 parentCollectionId,
    bytes32 conditionId, uint[] calldata indexSets) external;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;splitPosition&lt;/code&gt;&lt;/strong&gt; — deposit &lt;code&gt;amount&lt;/code&gt; of USDC, mint &lt;code&gt;amount&lt;/code&gt; of &lt;em&gt;each&lt;/em&gt; outcome token (a "complete set"). A complete set always costs face value because YES + NO together are guaranteed to pay 1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;mergePositions&lt;/code&gt;&lt;/strong&gt; — the inverse: burn one of each outcome token, get your collateral back. This is the no-arbitrage anchor that pins &lt;code&gt;price(YES) + price(NO)&lt;/code&gt; to 1: if the pair ever traded above 1, you'd mint sets and sell; below 1, you'd buy and merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;redeemPositions&lt;/code&gt;&lt;/strong&gt; — settlement. After the oracle calls &lt;code&gt;reportPayouts&lt;/code&gt; to write the result vector, holders of the winning outcome convert tokens to collateral; the losing tokens are worth 0.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Settlement
&lt;/h2&gt;

&lt;p&gt;Resolution is the moment the probabilistic price snaps to a binary truth. The oracle reports a payout vector — &lt;code&gt;[1, 0]&lt;/code&gt; for YES, &lt;code&gt;[0, 1]&lt;/code&gt; for NO — and &lt;code&gt;redeemPositions&lt;/code&gt; pays each winning share exactly 1 USDC while losing shares go to zero.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/** Payout (USDC base units) for a holder at resolution. */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shares&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;held&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;held&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;winner&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;shares&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1 share -&amp;gt; 1 USDC base unit, else 0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;usdc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;71.4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 71_400_000n  -&amp;gt; 71.4 USDC&lt;/span&gt;
&lt;span class="nf"&gt;redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;usdc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;71.4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire lifecycle: collateral splits into a complete set, the CPMM curve prices the two sides so they sum to one, traders push the implied probability around, and at resolution the winner redeems 1-for-1 while the loser zeroes out. No order book, no spread desk — the curve &lt;em&gt;is&lt;/em&gt; the order book, and the math is small enough to fit in one file.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uniswap v2 &lt;code&gt;getAmountOut&lt;/code&gt; (constant-product + 0.30% fee), &lt;code&gt;UniswapV2Library.sol&lt;/code&gt; — &lt;a href="https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol" rel="noopener noreferrer"&gt;https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Uniswap v2 protocol overview (the &lt;code&gt;x · y = k&lt;/code&gt; invariant) — &lt;a href="https://docs.uniswap.org/contracts/v2/concepts/protocol-overview/how-uniswap-works" rel="noopener noreferrer"&gt;https://docs.uniswap.org/contracts/v2/concepts/protocol-overview/how-uniswap-works&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Uniswap v2 whitepaper — &lt;a href="https://uniswap.org/whitepaper.pdf" rel="noopener noreferrer"&gt;https://uniswap.org/whitepaper.pdf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gnosis "Automated Market Makers for Prediction Markets" (FPMM odds formula, prices sum to 1) — &lt;a href="https://conditionaltokens-docs.dev.gnosisdev.com/conditionaltokens/docs/introduction3/" rel="noopener noreferrer"&gt;https://conditionaltokens-docs.dev.gnosisdev.com/conditionaltokens/docs/introduction3/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gnosis &lt;code&gt;FixedProductMarketMaker.sol&lt;/code&gt; (&lt;code&gt;calcBuyAmount&lt;/code&gt; / &lt;code&gt;calcSellAmount&lt;/code&gt;) — &lt;a href="https://github.com/gnosis/conditional-tokens-market-makers/blob/master/contracts/FixedProductMarketMaker.sol" rel="noopener noreferrer"&gt;https://github.com/gnosis/conditional-tokens-market-makers/blob/master/contracts/FixedProductMarketMaker.sol&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gnosis Conditional Tokens developer guide (&lt;code&gt;splitPosition&lt;/code&gt; / &lt;code&gt;mergePositions&lt;/code&gt; / &lt;code&gt;redeemPositions&lt;/code&gt;) — &lt;a href="https://conditional-tokens.readthedocs.io/en/latest/developer-guide.html" rel="noopener noreferrer"&gt;https://conditional-tokens.readthedocs.io/en/latest/developer-guide.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;EIP-1155: Multi Token Standard — &lt;a href="https://eips.ethereum.org/EIPS/eip-1155" rel="noopener noreferrer"&gt;https://eips.ethereum.org/EIPS/eip-1155&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Building this on AGON, a permissionless prediction-market app on Base — currently public testnet on Base Sepolia. No live token, no mainnet real-money betting yet; forward-looking features are planned. Nothing here is financial advice. &lt;a href="https://agon.markets" rel="noopener noreferrer"&gt;agon.markets&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uniswap v2 periphery — &lt;code&gt;UniswapV2Library.getAmountOut&lt;/code&gt; (verified source): &lt;a href="https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol" rel="noopener noreferrer"&gt;https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Uniswap v2 docs — "How Uniswap works" (&lt;code&gt;x · y = k&lt;/code&gt;): &lt;a href="https://docs.uniswap.org/contracts/v2/concepts/protocol-overview/how-uniswap-works" rel="noopener noreferrer"&gt;https://docs.uniswap.org/contracts/v2/concepts/protocol-overview/how-uniswap-works&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Uniswap v2 whitepaper: &lt;a href="https://uniswap.org/whitepaper.pdf" rel="noopener noreferrer"&gt;https://uniswap.org/whitepaper.pdf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gnosis Developer Portal — "Automated Market Makers for Prediction Markets" (FPMM odds = product of other balances / sum; prices sum to 1): &lt;a href="https://conditionaltokens-docs.dev.gnosisdev.com/conditionaltokens/docs/introduction3/" rel="noopener noreferrer"&gt;https://conditionaltokens-docs.dev.gnosisdev.com/conditionaltokens/docs/introduction3/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gnosis &lt;code&gt;FixedProductMarketMaker.sol&lt;/code&gt; (constant-product &lt;code&gt;calcBuyAmount&lt;/code&gt;/&lt;code&gt;calcSellAmount&lt;/code&gt;): &lt;a href="https://github.com/gnosis/conditional-tokens-market-makers/blob/master/contracts/FixedProductMarketMaker.sol" rel="noopener noreferrer"&gt;https://github.com/gnosis/conditional-tokens-market-makers/blob/master/contracts/FixedProductMarketMaker.sol&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gnosis Conditional Tokens — developer guide (split/merge/redeem signatures + &lt;code&gt;reportPayouts&lt;/code&gt; settlement): &lt;a href="https://conditional-tokens.readthedocs.io/en/latest/developer-guide.html" rel="noopener noreferrer"&gt;https://conditional-tokens.readthedocs.io/en/latest/developer-guide.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;EIP-1155 Multi Token Standard (official spec): &lt;a href="https://eips.ethereum.org/EIPS/eip-1155" rel="noopener noreferrer"&gt;https://eips.ethereum.org/EIPS/eip-1155&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blockchain</category>
      <category>solidity</category>
      <category>defi</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
