Onur SolmazWritings on math and crypto
https://solmaz.io/
Fri, 14 Jun 2019 09:49:22 +0000Fri, 14 Jun 2019 09:49:22 +0000Jekyll v3.8.5Analyzing the Proposed Validator Economics of Ethereum 2.0<p>In its next iteration dubbed Ethereum 2.0 or Serenity,
Ethereum will move on from ProofofWork to ProofofStake, implementing a
major change with how the network nodes are incentivized to participate.
This is an analysis of the proposal that’s going to be implemented as a part of
Phase 0. It’s based on the following work that’s been published:</p>
<ol>
<li><a href="https://github.com/ethereum/eth2.0specs/blob/b61963fc4cc57d7f62604f9cdc1c84dbc4452c59/specs/core/0_beaconchain.md">Beacon Chain Specification</a>
which started on HackMD, later migrated to GitHub.</li>
<li><a href="https://github.com/ethereum/beacon_chain/blob/eaf14825fd9bd95bafaf5d3457d173a33e84c65e/beacon_chain/state/state_transition.py">Beacon Chain PoC</a>
implemented in Python.</li>
<li><a href="https://github.com/ethhubio/ethhub/blob/3ca7115bffd861ab85e1df644e7172f291e6b250/ethereum101/monetarypolicy/eth2.0economics.md">Initial version of validator economics</a>
by Eric Conner.</li>
<li><a href="https://github.com/ethhubio/ethhub/blob/5a8882190969f0e063ce25961d01fb2b7f0c13e9/docs/ethereumroadmap/ethereum2.0/eth2.0economics.md">A more recent version</a>.</li>
<li><a href="https://ethresear.ch/t/theeconomicincentivesofstakinginserenity/4157">A discussion</a>
at ETH Research.</li>
<li><a href="https://twitter.com/econoar/status/1053311930885197825">A twitter thread</a> by Eric Conner.</li>
</ol>
<p>This is work in progress and will most probably change
in the following months.
I won’t be concentrating on the profit & loss of validators, but rather
capture the definition of the underlying model. I hope this will clarify how
validator deposits, total deposits, total supply, issuance rate and validator
interest relate to each other.</p>
<hr />
<p>As the first globally successful cryptocurrency, Bitcoin’s economics was a
starting point for the design of PoS systems to come. It was really simple:
rewards are issued at a constant rate and distributed randomly to miners.
Bitcoin’s creators aimed to minimize nontechnical governance from the very
beginning, so they designed it to have a supply cap by having the rewards halve
every 4 years.</p>
<p>Ethereum has a different approach to monetary policy. Issuance of ETH is not
decided by a priori consensus,
but <a href="https://en.wikipedia.org/wiki/Benevolent_dictator_for_life">BDFL governance</a>
by the core devs, like other aspects of the project. When you buy ETH, you
implicitly agree that the core
devs—whose livelihoods depend on ETH—are
going to act in their best interest and take the decisions that will maximize
ETH’s value, that is, until a more efficient and democratic method of
governance is developed.</p>
<p>In Ethereum 1.0, the issuance rate started as a constant 5 ETH per block, and
was reduced first to 3 ETH, and then 2 ETH in subsequent hard forks. In Ethereum
2.0, the protocol will be able to keep track of the total stake.
This makes it possible to implement different mechanisms. Rewards minted per
epoch will change with total staked ETH. I will refrain from making absolute
statements about the numbers, because
<a href="https://github.com/ethereum/eth2.0specs/pull/971">they changed even while I was writing this</a>.
The general idea is to target a reference validator return rate A% for B ETH staked. If
less than B ETH is staked, the return rate will be greater than A%, and vice
versa. This is to give the validators an extra incentive to stake following
the launch, and also to ensure that total stake never becomes too low.</p>
<p>The rule of thumb the core devs seem to be using is to target roughly 2.5~3% annual
return rate at optimal amount of ETH staked.
This was previously thought of as 10%, but seems to have increased to 30% with
<a href="https://twitter.com/econoar/status/1120069977841623040">recent feedback from the community</a>.
Notice how the projected return rates more than doubled since the first proposal
(current ETH supply is 105m):</p>
<table>
<thead>
<tr>
<th>ETH validating</th>
<th>Max annual issuance % (first)</th>
<th>Max annual issuance % (current)</th>
<th>Max annual return rate (first)</th>
<th>Max annual return rate (current)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1,000,000</td>
<td>0.08%</td>
<td>0.17%</td>
<td>8.02%</td>
<td>18.10%</td>
</tr>
<tr>
<td>3,000,000</td>
<td>0.13%</td>
<td>0.30%</td>
<td>4.63%</td>
<td>10.45%</td>
</tr>
<tr>
<td>10,000,000</td>
<td>0.24%</td>
<td>0.54%</td>
<td>2.54%</td>
<td>5.72%</td>
</tr>
<tr>
<td>30,000,000</td>
<td>0.42%</td>
<td>0.94%</td>
<td>1.46%</td>
<td>3.30%</td>
</tr>
<tr>
<td>100,000,000</td>
<td>0.77%</td>
<td>1.71%</td>
<td>0.80%</td>
<td>1.81%</td>
</tr>
</tbody>
</table>
<p>What is more interesting is the “sliding scale” model of reward issuance seen above.
A look at the <a href="https://github.com/ethereum/eth2.0specs/blob/b61963fc4cc57d7f62604f9cdc1c84dbc4452c59/specs/core/0_beaconchain.md#rewardsandpenalties">Beacon chain spec</a>
reveals how this is achieved:</p>
<div class="languagepython highlighterrouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_base_reward_from_total_balance</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">BeaconState</span><span class="p">,</span> <span class="n">total_balance</span><span class="p">:</span> <span class="n">Gwei</span><span class="p">,</span> <span class="n">index</span><span class="p">:</span> <span class="n">ValidatorIndex</span><span class="p">)</span> <span class="o">></span> <span class="n">Gwei</span><span class="p">:</span>
<span class="k">if</span> <span class="n">total_balance</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="n">adjusted_quotient</span> <span class="o">=</span> <span class="n">integer_squareroot</span><span class="p">(</span><span class="n">total_balance</span><span class="p">)</span> <span class="o">//</span> <span class="n">BASE_REWARD_QUOTIENT</span>
<span class="k">return</span> <span class="n">get_effective_balance</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span> <span class="o">//</span> <span class="n">adjusted_quotient</span> <span class="o">//</span> <span class="mi">5</span>
</code></pre></div></div>
<p>Rewards are scaled with the square root of the total ETH staked. Specifically,
per validator reward has the form</p>
<script type="math/tex; mode=display">r = \frac{c}{\sqrt{S}}</script>
<p>for a single epoch, where $c$ is a constant and $S$ is the total ETH staked.
This results in a system where validator return rate decreases with increasing
ETH staked, but the issuance rate increases:</p>
<figure>
<p><a href="/img/eth2_phase0_economics/fig3.svg" target="blank_"><img src="/img/eth2_phase0_economics/fig3.svg" /></a>
ETH staked versus annual issuance rate and validator return rate.</p>
</figure>
<p>In fact, this behavior holds for every reward function $r = c S^{\alpha}$ where
$0<\alpha<1$.
See my
<a href="/2019/04/20/equilibriumcryptoeconomicnetworks/">previous blog post</a> for more
details on such models, and how different parameters affect the economic
equilibrium.</p>
<p>One of the reasons for choosing such a model is to mitigate the
chicken and egg problem every nascent network faces. Another one is to minimize
the profit that can be obtained from censoring minorities, as demonstrated by
Buterin<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>.</p>
<h2 id="economicsofcontinuousgriefing">Economics of Continuous Griefing</h2>
<p>Continuous griefing by a majority coalition is one of the worst types of attacks,
where messages from a minority are continuously ignored by the coalition, effectively
censoring them. The fault in this case is nonattributable, since the protocol
can’t observe whether the minority is being censored or simply offline.
Since it’s not possible for the protocol to determine the attacker,
the only remaining option is to penalize everyone collectively.
Therefore in Ethereum 2.0, rewards will be
scaled down linearly with decreased participation as observed by the protocol.</p>
<p>The metric to take into account here is the griefing factor, defined by
Buterin<sup id="fnref:1:1"><a href="#fn:1" class="footnote">1</a></sup> as follows:
A factor of n means that the attacker can sacrifice \$1 of their own funds to
cause \$n losses to the victim. For a linear scaling of the rewards, he
calculates the griefing factors as 3 for the smallest minority and 2 for the
biggest minority.</p>
<p>Although griefing is penalized by the protocol, there is a side effect to the attack:
since there are now fewer validators, per validator rewards actually increase a
bit (recovery). If that increase is higher than the cost of the attack, then it’s still
possible to make a profit.</p>
<p>Let us now formulate the economics in terms of number of validators $N$ instead of
staked ETH, which are roughly analogous to the protocol. Let the per validator
reward have the form</p>
<script type="math/tex; mode=display">r = c_1 N^{\alpha}</script>
<p>which is analogous to a demand curve. Then let the number of validators that
would <em>economically</em> exist for a given per validator reward have the form</p>
<script type="math/tex; mode=display">N = (r/c_2)^{1/k}</script>
<p>which yields the inverse relation $r = c_2 N^k$. This is analogous to a supply
curve. Here, $c_1$ and $c_2$ are constants and $k$ is an external parameter
governing the economics of the network.</p>
<p>Griefing will cause rewards to decrease for everyone, pushing down the demand
curve. Given that the demand curve is pushed down by $\epsilon$, the figure
below demonstrates how to calculate the recovery as a fraction of $\epsilon$:</p>
<figure>
<p><a href="/img/eth2_phase0_economics/fig2.svg" target="blank_"><img src="/img/eth2_phase0_economics/fig2.svg" /></a>
Two functions $f(x)$ and $g(x)$ representing demand and supply respectively
(left). For small perturbations $\epsilon$ pushing down the demand curve, the
recovery, depicted by the second arrow, is calculated as $\frac{f’(x^\ast)}{g’(x^\ast)f’(x^\ast)}\epsilon$.</p>
</figure>
<p>Some simplifications done by Buterin<sup id="fnref:1:2"><a href="#fn:1" class="footnote">1</a></sup> do not actually hold, but for the given
relations, the recovery indeed simplifies to</p>
<script type="math/tex; mode=display">\frac{\alpha}{\alpha + k} \epsilon</script>
<p>locally at the intersection point $N^\ast = (c_1/c_2)^{1/(\alpha+k)}$.</p>
<p>Assuming the worst case scenario allows us to further simplify:</p>
<blockquote>
<p>Griefing factors are highest when the attacker has exactly half of the
validators. This is convenient, because it means that the size of the attacker
and victim sets are the same, so the griefing factor is also the ratio of the
losses of average rewards of <em>each validator</em>.</p>
</blockquote>
<p>Then we assume that the victims lose $\epsilon$ and the attacker loses
$\epsilon/F$ where $F$ is the griefing factor. To ensure unprofitability of
griefing, recovery should be smaller than losses for the attacker
$\epsilon\frac{\alpha}{\alpha + k} \leq \epsilon\frac{1}{F}$
yielding the condition</p>
<script type="math/tex; mode=display">\alpha \leq \frac{k}{F1}.</script>
<p>The griefing factor for 51% censoring the rest was 2, but Buterin<sup id="fnref:1:3"><a href="#fn:1" class="footnote">1</a></sup> assumes a
factor of 3—presumably for additional safety. The parameter $k$ is determined
partly by
external factors and partly by design choices; Buterin<sup id="fnref:1:4"><a href="#fn:1" class="footnote">1</a></sup> assumes a linear
relationship $k=1$. This is interpreted as “a $1/c_2$ increase in per validator
reward will always result in one more validator joining the validator set”.
Substituting these values, we obtain the condition</p>
<script type="math/tex; mode=display">\alpha \leq \frac{1}{2}.</script>
<p>This provides additional justification for the choice of $\alpha = 1/2$ for
Ethereum 2.0. Furthermore, it shows that PoS networks with $\alpha = 1$ are more
susceptible to censorship.</p>
<p><em>This research is being conducted on behalf of
<a href="https://casperlabs.io">CasperLabs</a>, where we are building the
truly decentralized, scalable, next generation ProofofStake network.</em></p>
<hr />
<h3 id="reference">Reference</h3>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Buterin V., <a href="https://github.com/ethereum/research/blob/master/papers/discouragement/discouragement.pdf">Discouragement Attacks</a>, 16.12.2018. <a href="#fnref:1" class="reversefootnote">↩</a> <a href="#fnref:1:1" class="reversefootnote">↩<sup>2</sup></a> <a href="#fnref:1:2" class="reversefootnote">↩<sup>3</sup></a> <a href="#fnref:1:3" class="reversefootnote">↩<sup>4</sup></a> <a href="#fnref:1:4" class="reversefootnote">↩<sup>5</sup></a></p>
</li>
</ol>
</div>
Wed, 24 Apr 2019 00:00:00 +0000
https://solmaz.io/2019/04/24/eth2phase0economics/
https://solmaz.io/2019/04/24/eth2phase0economics/mathcryptoeconomicsEquilibrium in Cryptoeconomic Networks<p>A cryptoeconomic network is a network where</p>
<ul>
<li>nodes perform tasks that are useful to the network,</li>
<li>incur costs while doing so,</li>
<li>and get compensated through fees paid by the network users, or rewards
generated by the network’s protocol (usually in the form of a currency native
to the network).</li>
</ul>
<p>Reward generation causes the supply of network currency to increase,
resulting in inflation. Potential nodes are incentivized to join the network
because they see there is profit to be made, especially if they are one of the
early adopters. This brings the notion of a “cake” being shared among nodes,
where the shares get smaller as the number of nodes increases.</p>
<p>Since one of the basic properties of a currency is finite supply, a sane
protocol cannot have the rewards increase arbitrarily with more nodes. Thus the
possible number of nodes is finite, and can be
calculated using costs and rewards, given that <strong>transaction fees are negligible</strong>.
The rate by which
rewards are generated determines the sensitivity of network
size to changes in costs and other factors.</p>
<p>Let $N$ be the number of nodes in a network, which perform the same work during
a given period. Then we can define a generalized reward per node, introduced by Buterin<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>:</p>
<script type="math/tex; mode=display">r = R_0 N^{\alpha}
\tag{1}</script>
<p>where $R_0$ is a constant and $\alpha$ is a parameter adjusting how the
rewards scale with $N$.</p>
<p>Then the total reward issued is equal to</p>
<script type="math/tex; mode=display">R = N r = R_0 N^{1\alpha}.</script>
<p>The value of $\alpha$ determines how the rewards scale with $N$:</p>
<table>
<thead>
<tr>
<th>Range</th>
<th>Per node reward $r$</th>
<th>Total reward $R$</th>
</tr>
</thead>
<tbody>
<tr>
<td>$\alpha < 0$</td>
<td>Increase with increasing $N$</td>
<td>Increase with increasing $N$</td>
</tr>
<tr>
<td>$ 0 < \alpha < 1$</td>
<td>Decrease with increasing $N$</td>
<td>Increase with increasing $N$</td>
</tr>
<tr>
<td>$\alpha > 1$</td>
<td>Decrease with increasing $N$</td>
<td>Decrease with increasing $N$</td>
</tr>
</tbody>
</table>
<! Since $\alpha\leq 0$ would result in runaway inflation, an >
<! economically sound system must have $\alpha > 0$ to ensure equilibrium. >
<p>Below is a table showing how different values of $\alpha$
corresponds to different rewarding schemes, given full participation.</p>
<table>
<thead>
<tr>
<th>$\alpha$</th>
<th>$r$</th>
<th>$R$</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>$0$</td>
<td>$R_0$</td>
<td>$R_0 N$</td>
<td>Constant interest rate</td>
</tr>
<tr>
<td>$1/2$</td>
<td>$R_0/\sqrt{N}$</td>
<td>$R_0 \sqrt{N}$</td>
<td>Middle ground between 0 and 1 (Ethereum 2.0)</td>
</tr>
<tr>
<td>$1$</td>
<td>$R_0/N$</td>
<td>$R_0$</td>
<td>Constant total reward (Ethereum 1.0, Bitcoin in the short run)</td>
</tr>
<tr>
<td>$\infty$</td>
<td>$0$</td>
<td>$0$</td>
<td>No reward (Bitcoin in the long run)</td>
</tr>
</tbody>
</table>
<p>The case $\alpha \leq 0$ results in unlimited network growth, causes runaway
inflation and is not feasible. The case $\alpha > 1$ is also not feasible due to
drastic reduction in rewards. The sensible range is $0 < \alpha \leq 1$, and we
will explore the reasons below.</p>
<h2 id="estimatingnetworksize">Estimating Network Size</h2>
<p>We relax momentarily the assumption that nodes perform the same amount of work.
The work mentioned here can be the hashing power contributed by a node in a PoW
network, the amount staked in a PoS network, or the measure of dedication in any
analogous system.</p>
<p>Let $w_i$ be the work performed by node $i$. Assuming that costs are incurred in
a currency other than the network’s—e.g. USD—we have to take the price of
the network currency $P$ into account. The expected value of $i$’s reward is
calculated analogous to (1)</p>
<script type="math/tex; mode=display">E(r_i) = \left[\frac{w_i}{\sum_{j} w_j}\right]^\alpha P R_0</script>
<p>Introducing variable costs $c_v$ and fixed costs $c_f$, we can calculate
$i$’s profit as</p>
<script type="math/tex; mode=display">E(\pi_i) = \left[\frac{w_i}{\sum_{j} w_j}\right]^\alpha P R_0  c_v w_i  c_f</script>
<p>Assuming every node will perform work in a way to maximize profit, we can
estimate $w_i$ given others’ effort:</p>
<script type="math/tex; mode=display">\frac{\partial}{\partial w_i} E(\pi_i)
= \frac{\alpha \,w_i^{\alpha1}\sum_{j\neq i}w_j}{(\sum_{j}w_j)^{\alpha+1}}
 c_v = 0</script>
<p>In a network where nodes have identical costs and capacities to work, all $w_j$
$j=1,\dots,N$ converge to the same equilibrium value $w^\ast$. Equating
$w_i=w_j$, we can solve for that value:</p>
<script type="math/tex; mode=display">w^\ast = \frac{\alpha(N1)}{N^{\alpha+1}} \frac{P R_0}{c_v}.</script>
<p>Plugging $w^\ast$ back above, we can calculate $N$ for the case of economic
equilibrium where profits are reduced to zero due to perfect competition:</p>
<script type="math/tex; mode=display">E(\pi_i)\bigg_{w^\ast} = \left[\frac{1}{N}\right]^\alpha P R_0
\frac{\alpha(N1)}{N^{\alpha+1}} P R_0  c_f = 0</script>
<p>which yields the following implicit equation</p>
<! $$ >
<! \frac{N^{\alpha+1}}{\alpha + N  \alpha N} = \frac{P R_0}{c_f} >
<! $$ >
<script type="math/tex; mode=display">\boxed{
\frac{\alpha}{N^{\alpha+1}} + \frac{1\alpha}{N^\alpha} = \frac{c_f}{P R_0}
}</script>
<p>It is a curious result that for the idealized model above,
network size does not depend on variable
costs. In reality, however, we have an uneven
distribution of all costs and work capacities. Nevertheless, the idealized model
can still yield rules of thumb that are useful in protocol design.</p>
<p>An explicit form for $N$ is not possible, but we can calculate it for different
values of $\alpha$. For $\alpha=1$, we have</p>
<script type="math/tex; mode=display">N = \sqrt{\frac{P R_0}{c_f}}.</script>
<p>as demonstrated by Thum<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>.</p>
<p>For $0<\alpha<1$, the explicit forms would take too much space. For brevity’s
sake, we can approximate $N$ by</p>
<script type="math/tex; mode=display">N \approx \left[ (1\alpha)\frac{P R_0}{c_f}\right]^{1/\alpha}</script>
<p>given $N \gg 1$. The closer $\alpha$ to zero, the better the approximation.</p>
<p>We also have</p>
<script type="math/tex; mode=display">\lim_{\alpha\to 0^+} N = \infty.</script>
<p>which shows that for $\alpha\leq 0$, the network grows without bounds and
render the network currency worthless by inflating it indefinitely.
Therefore there is no equilibrium.</p>
<p>For $\alpha > 1$, rewards and number of nodes decrease with increasing
$\alpha$. Finally, we have</p>
<script type="math/tex; mode=display">\lim_{\alpha\to\infty} N = 0</script>
<p>given that transaction fees are negligible.</p>
<figure>
<p><a href="/img/equilibrium_cryptoeconomic_networks/fig1.svg" target="blank_"><img src="/img/equilibrium_cryptoeconomic_networks/fig1.svg" /></a>
Number of nodes $N$ versus $P R_0/c_f$, on a log scale. The
straight lines were
solved for numerically, and corresponding approximations were overlaid with
markers, except for $\alpha=1$ and $2$.</p>
</figure>
<p>For $0 <\alpha \ll 1$, a $C$x change in underlying factors will result in
$C^{1/\alpha}$x change in network size. For $\alpha=1$, the change will be
$\sqrt{C}$x.</p>
<p>Let $\alpha=1$. Then a
$2$x increase in price or rewards will result in a $\sqrt{2}$x increase in network
size. Conversely, a $2$x increase in fixed costs will result in $\sqrt{2}$x
decrease in network size. If we let $\alpha = 1/2$,
a $2$x change to the factors result in $4$x change in network size, and so on.</p>
<p><em>This research is being conducted on behalf of
<a href="https://casperlabs.io">CasperLabs</a>, where we are building the
truly decentralized, scalable, next generation ProofofStake network.</em></p>
<h3 id="references">References</h3>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Buterin V., <a href="https://github.com/ethereum/research/blob/master/papers/discouragement/discouragement.pdf">Discouragement Attacks</a>, 16.12.2018. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>Thum M., <a href="https://www.cesifogroup.de/DocDL/CESifoForum20181thumbitcoinmarch.pdf">The Economic Cost of Bitcoin Mining</a>,
2018. <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Sat, 20 Apr 2019 00:00:00 +0000
https://solmaz.io/2019/04/20/equilibriumcryptoeconomicnetworks/
https://solmaz.io/2019/04/20/equilibriumcryptoeconomicnetworks/mathcryptoeconomicsScalable Reward Distribution with Changing Stake Sizes<p>This post is an addendum to the excellent paper
<em>Scalable Reward Distribution on the Ethereum Blockchain</em> by Batog et al.<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>
The outlined algorithm describes a pullbased approach to distributing rewards
proportionally in a staking pool. In other words, instead of pushing
rewards to each stakeholder in a forloop with $O(n)$ complexity, a
mathematical trick enables keeping account of the rewards with $O(1)$
complexity and distributing only when the stakeholders decide to pull them. This
allows the distribution of things like rewards, dividends, Universal Basic
Income, etc. with minimal resources and huge scalability.</p>
<p>The paper by Bogdan et al. assumes a model where stake size doesn’t change once
it is deposited, presumably to explain the concept in the simplest way possible.
After the deposit, a stakeholder can wait to collect rewards and then withdraw both
the deposit and the accumulated rewards.
This would rarely be the case in real applications, as participants would want
to increase or decrease their stakes between reward distributions. To make this
possible, we need to make modifications to the original formulation and
algorithm. Note that the algorithm given below is already implemented in
<a href="https://etherscan.io/address/0xb3775fb83f7d12a36e0475abdd1fca35c091efbe">PoWH3D</a>.</p>
<p>In the paper, the a $reward_t$ is distributed to a participant $j$ with an
associated $stake_j$ as</p>
<script type="math/tex; mode=display">reward_{j,t} = stake_{j} \frac{reward_t}{T_t}</script>
<p>where subscript $t$ denotes the values of quantities at distribution of reward
$t$ and $T$ is
the sum of all active stake deposits.</p>
<p>Since we relax the assumption of constant stake, we rewrite it for
participant $j$’s stake at reward $t$:</p>
<script type="math/tex; mode=display">reward_{j,t} = stake_{j, t} \frac{reward_t}{T_t}</script>
<p>Then the total reward participant $j$ receives is calculated as</p>
<script type="math/tex; mode=display">total\_reward_j
= \sum_{t} reward_{j,t}
= \sum_{t} stake_{j, t} \frac{reward_t}{T_t}</script>
<p>Note that we can’t take stake out of the sum as the authors did, because
it’s not constant.
Instead, we introduce the following identity:</p>
<p>For two sequences $(a_0, a_1, \dots,a_n)$ and $(b_0, b_1, \dots,b_n)$, we have</p>
<script type="math/tex; mode=display">\boxed{
\sum_{i=0}^{n}a_i b_i
=
a_n \sum_{j=0}^{n} b_j

\sum_{i=1}^{n}
\left(
(a_ia_{i1})
\sum_{j=0}^{i1} b_j
\right)
}</script>
<p><strong>Proof:</strong> Substitute $b_i = \sum_{j=0}^{i}b_j  \sum_{j=0}^{i1}b_j$ on the
LHS, distribute the multiplication, modify the index $i \leftarrow i1$ on the
first term, separate the last element of the sum from the first term and
combine the remaining sums since they have the same bounds.</p>
<p>We assume $n+1$ rewards represented by the indices $t=0,\dots,n$, and
apply the identity to total reward to obtain</p>
<script type="math/tex; mode=display">total\_reward_j
= stake_{j, n} \sum_{t=0}^{n} \frac{reward_t}{T_t}
 \sum_{t=1}^{n}
\left(
(stake_{j,t}stake_{j,t1})
\sum_{t=0}^{t1} \frac{reward_t}{T_t}
\right)</script>
<p>Recalling the authors’ definition of the sum</p>
<script type="math/tex; mode=display">S_t = \sum_{k=0}^{t} \frac{reward_k}{T_k}</script>
<p>and defining the change in stake between rewards $t1$ and $t$</p>
<script type="math/tex; mode=display">\Delta stake_{j,t} = stake_{j,t}stake_{j,t1}</script>
<p>we can write</p>
<script type="math/tex; mode=display">total\_reward_j
= stake_{j, n} S_n
 \sum_{t=1}^{n}
\left(
\Delta stake_{j,t}
S_{t1}
\right)</script>
<p>This result is similar to the one obtained by the authors in Equation 5. However,
instead of keeping track of $S$ at times of deposit for each participant as
is the case with $S_0$ from the paper, we keep track of</p>
<script type="math/tex; mode=display">P_{j,n}
:= \sum_{t=1}^{n}
\left(
\Delta stake_{j,t}
S_{t1}
\right)</script>
<p>In this case, positive $\Delta stake$ corresponds to a deposit and negative
corresponds to a withdrawal. $\Delta stake_{j,t}$ is zero if the stake of
participant $j$ remains constant between $t1$ and $t$. We have</p>
<script type="math/tex; mode=display">total\_reward_j
= stake_{j, n} S_n  P_{j,n}</script>
<p>The modified algorithm requires the same amount of memory, but has the
advantage of participants being able to increase or decrease their stakes
without withdrawing everything and depositing again.</p>
<p>Furthermore, a practical implementation should take into account that a
participant can withdraw rewards at any time.
Assuming $P_{j,n}$ is represented by a mapping <code class="highlighterrouge">P[]</code> which is
updated with each change in stake size</p>
<div class="highlighterrouge"><div class="highlight"><pre class="highlight"><code>P[address] = P[address] + change*S
</code></pre></div></div>
<p>we can update <code class="highlighterrouge">P[]</code> upon a complete withdrawal of $j$’s total accumulated
rewards:</p>
<div class="highlighterrouge"><div class="highlight"><pre class="highlight"><code>P[address] = stake[address]*S
</code></pre></div></div>
<p>which sets $j$’s rewards to zero.</p>
<p>The pseudocode for the modified algorithm is given below. The following methods
are exposed:</p>
<ul>
<li><code class="highlighterrouge">DepositStake</code> to deposit or increase a participant stake.</li>
<li><code class="highlighterrouge">Distribute</code> to fan out reward to all participants.</li>
<li><code class="highlighterrouge">WithdrawStake</code> to withdraw a participant’s stake partly or completely.</li>
<li><code class="highlighterrouge">WithdrawReward</code> to withdraw all of a participant’s accumulated rewards.</li>
</ul>
<div class="highlighterrouge"><div class="highlight"><pre class="highlight"><code>Algorithm 1: Constant Time Reward Distribution with Changing Stake Sizes
function Initialization();
begin
T = 0;
S = 0;
stake = {};
P = {};
end
function DepositStake(address, amount);
Input: increase the stake of _address_ by _amount_
begin
if address not in stake then
stake[address] = 0;
P[address] = 0;
end
stake[address] = stake[address] + amount;
P[address] = P[address] + S*amount;
T = T + amount;
end
function Distribute(r);
Input: Reward _r_ to be distributed proportionally to active stakes
begin
if T != 0 then
S = S + r/T;
else
revert();
end
end
function WithdrawStake(address, amount)
Input: decrease the stake of _address_ by _amount_
Output: returns the withdrawn _amount_
begin
if address not in stake then
revert();
end
if amount > stake[address] then
revert();
end
stake[address] = stake[address]  amount;
P[address] = P[address]  S*amount;
T = T  amount;
return amount
end
function WithdrawReward(address)
Input: withdraw the rewards of _address_
Output: _amount_ withdrawn
begin
if address not in stake then
revert();
end
reward = stake[address]*S  P[address]
P[address] = stake[address]*S
return reward
end
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>With a minor modification, we improved the user experience of the Constant Time
Reward Distribution Algorithm
first outlined in Batog et al., without changing the memory requirements.</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Batog B., Boca L., Johnson N., <a href="http://batog.info/papers/scalablerewarddistribution.pdf">Scalable Reward Distribution on the Ethereum Blockchain</a>, 2018. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Sun, 24 Feb 2019 00:00:00 +0000
https://solmaz.io/2019/02/24/scalablerewardchanging/
https://solmaz.io/2019/02/24/scalablerewardchanging/mathcryptoeconomicsInflation Curvature in Bitcoin Supply<p>New bitcoins are minted with every new block in the Bitcoin blockchain, called “block
rewards”, in order to incentivize mining by making it more profitable. This
inflates Bitcoin’s supply in a predictable manner.
Imagine that the inflation rate were constant and the transactions between
miners and users stopped at some point:
miners’ share of the total Bitcoin supply would approach 100% as the number
of blocks goes to infinity.</p>
<p>But that’s not the case, and said boost is valid only in the short term. In
fact, inflation rate decreases geometrically and there will come a time when
it’s effectively negligible. Whereas block rewards constituted the majority of
what a miner receives from a block, these will in time converge to zero and only
transaction fees will remain. The effect will be increased transaction fees, assuming
the mining market is already saturated enough.</p>
<p>There have been some confusion of the terminology, like people calling Bitcoin
deflationary. Bitcoin is in fact not deflationary—that implies negative
inflation rate. Bitcoin rather has negative <strong>inflation curvature</strong>: Bitcoin’s
inflation rate decreases monotonically.</p>
<p>An analogy from elementary physics should clear things up: Speaking strictly in
terms of monetary inflation,</p>
<ul>
<li><em>displacement</em> is analogous to <em>inflation/deflation</em>, as in total money
minted/burned, without considering a time period. Dimensions: $[M]$.</li>
<li><em>Velocity</em> is analogous to <em>inflation rate</em>, which defines total money minted/burned
in a given period. Dimensions: $[M/T]$.</li>
<li><em>Acceleration</em> is analogous to <em>inflation curvature</em>, which defines the total
change in inflation rate in a given period. Dimensions: $[M/T^2]$.</li>
</ul>
<p>Given a supply function $S$ as a function of time, block height, or any variable
signifying progress,</p>
<ul>
<li>inflation is a positive change in supply, $\Delta S$, and deflation, $\Delta S$.</li>
<li>Inflation rate is the first derivative of supply, $S’$.</li>
<li>Inflation curvature is the second derivative of supply, $S’’$.</li>
</ul>
<p>In Bitcoin, we have the supply as a function of block height:
$S:\mathbb{Z}_{\geq 0} \to \mathbb{R}_+$.
But the function itself is defined by the arithmetic<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> initial value problem</p>
<script type="math/tex; mode=display">S'(h) = \alpha^{\lfloor h/\beta\rfloor} R_0
,\quad
S(0) = 0
\tag{1}</script>
<p>where $R_0$ is the initial inflation rate, $\alpha$ is the rate by which the
inflation rate will decrease, $\beta$ is the milestone number of blocks at
which the decrease will take place, and $\lfloor \cdot \rfloor$ is the floor
function. In Bitcoin, we have $R_0 = 50\text{ BTC}$,
$\alpha=1/2$ and $\beta=210,000\text{ blocks}$. Here is what it looks like:</p>
<figure>
<p><a href="/img/inflation_curvature_bitcoin_supply/fig2.svg" target="blank_"><img src="/img/inflation_curvature_bitcoin_supply/fig2.svg" /></a>
Bitcoin inflation rate versus block height.</p>
</figure>
<p>We can directly compute inflation curvature:</p>
<script type="math/tex; mode=display">% <![CDATA[
S''(h) =
\begin{cases}
\frac{\ln(\alpha)}{\beta} \alpha^{h/\beta} & \text{if}\quad
h\ \mathrm{mod}\ \beta = 0 \quad\text{and}\quad h > 0\\
0 & \text{otherwise}.
\end{cases} %]]></script>
<p>$S’’$ is nonzero only when $h$ is a multiple of $\beta$. For $0 < \alpha < 1$,
$S’’$ is either zero or negative, which is the case for Bitcoin.</p>
<p>Finally, we can come up with a closedform $S$ by solving the initial value
problem (1):</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{aligned}
S(h) &= \sum_{i=0}^{\lfloor h/\beta\rfloor 1} \alpha^{i} \beta R_0
+ \alpha^{\lfloor h/\beta\rfloor} (h\ \mathrm{mod}\ \beta) R_0 \\
&= R_0 \left(\beta\frac{1\alpha^{\lfloor h/\beta\rfloor}}{1\alpha}
+\alpha^{\lfloor h/\beta\rfloor} (h\ \mathrm{mod}\ \beta) \right)
\end{aligned} %]]></script>
<p>Here is what the supply function looks like for Bitcoin:</p>
<figure>
<p><a href="/img/inflation_curvature_bitcoin_supply/fig1.svg" target="blank_"><img src="/img/inflation_curvature_bitcoin_supply/fig1.svg" /></a>
Bitcoin supply versus block height.</p>
</figure>
<p>And the maximum number of Bitcoins to ever exist are calculated by taking the
limit</p>
<script type="math/tex; mode=display">\lim_{h\to\infty} S(h)
= \sum_{i=0}^{\infty} \alpha^{i} \beta R_0
= \frac{\beta R_0}{1\alpha}
= 21,000,000\text{ BTC}.</script>
<h1 id="summary">Summary</h1>
<p>The concept of inflation curvature was introduced. The confusion regarding
Bitcoin’s inflation mechanism was cleared with an analogy. The IVP defining
Bitcoin’s supply was introduced and solved to get a closedform
expression. Inflation curvature for Bitcoin was derived.
The maximum number of Bitcoins to ever exist was derived and computed.</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Because $S$ is defined over positive integers. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Sat, 09 Feb 2019 00:00:00 +0000
https://solmaz.io/2019/02/09/inflationcurvaturebitcoinsupply/
https://solmaz.io/2019/02/09/inflationcurvaturebitcoinsupply/mathcryptoeconomicsPyramid or Stump? Bonding Curve Parameters Matter<p>A bonding curve is a mechanism that enables bootstrapping a new currency based
on another currency, called the base currency.
It’s like a fixedexchange rate system in terms of control over the currency;
but instead of having a fixedexchange rate, an authority increases the exchange
rate with increasing supply of the minted currency. The rate of increase is
determined by the bonding curve which strictly defines the relationship between
the exchange rate and the supply. Conversely, the exchange rate drops when the
supply decreases.</p>
<p>The total amount of base currency the authority keeps at any time is called
“reserve”.
Since the mechanism described mints the new currency, we use the term “price”
instead of exchange rate, as in minting price.</p>
<p>When designing such a system, it’s not just the type of the bonding curve that
matters, but also the parameters it uses. These parameters determine the
distribution of wealth among early and late buyers of the bonding curve.
In other words, a linear bonding curve’s initial price and slope determine
whether the distribution is a <em>pyramid</em> or a <em>stump</em>.</p>
<figure>
<p><a href="/img/pyramid_or_stump/fig1.svg" target="blank_"><img src="/img/pyramid_or_stump/fig1.svg" /></a></p>
</figure>
<p>Pyramid means a distribution
where early buyers can mint for much cheaper and have a lot more of the new
currency than late buyers, whereas stump means a comparatively more even
distribution, although early buyers still enjoy some advantage.
The steeper the bonding curve, the more pyramidlike the distribution.</p>
<h3 id="preliminaries">Preliminaries</h3>
<p>In a linear bonding curve, the price is a linear function of the supply:</p>
<script type="math/tex; mode=display">P(S) = P_0 + \Delta_p S</script>
<p>where $P$ is price, $S$ is supply, $P_0$ is the initial price and $\Delta_p$ is the price increment.</p>
<p>Were the price constant, we would have had the following relationship
between the amount of base currency $B$, minted currency $M$ and price $P$</p>
<script type="math/tex; mode=display">P = \frac{B}{M}</script>
<p>But since we have a changing price, we have the following differential equation instead:</p>
<script type="math/tex; mode=display">P = \frac{d B}{d M}</script>
<p>That’s why the area under the bonding curve equals total reserve for a given price.
Thus we calculate total reserve $R$ as a function of the total supply as</p>
<script type="math/tex; mode=display">R(S) = \int_0^S P(\tilde{S}) \, d\tilde{S} = P_0 S + \frac{1}{2} \Delta_p S^2</script>
<p>Inverting the function, we get</p>
<script type="math/tex; mode=display">S(R) = \frac{\sqrt{P_0^2+2 \Delta_p R}P_0}{\Delta_p}</script>
<p>Plugging this into the pricesupply function, we can get price as a function
of reserve</p>
<script type="math/tex; mode=display">P(R) = \sqrt{P_0^2+2\Delta_p R}</script>
<p>While choosing parameters, expressing price in terms of the underlying reserve
is more useful because we have a better feeling of the base currency compared to
the newly minted one. If we can come up with projections of market attributes, we
can reason better about how steep the price should
increase. Below are three metrics that can aid in this decision.</p>
<h3 id="metric1priceincreaseafteracertainreserveamount">Metric 1: Price increase after a certain reserve amount</h3>
<p>The first metric that comes to mind is the increase in price after the
investment of a certain amount $B$ of the base currency. The founder of the
bonding curve may design it according to a principle, e.g.</p>
<blockquote>
<p>The price should increase 2x with R reserve.</p>
</blockquote>
<p>Below is a graph that demonstrates this:</p>
<figure>
<p><a href="/img/pyramid_or_stump/fig3.svg" target="blank_"><img src="/img/pyramid_or_stump/fig3.svg" /></a>
Price versus reserve for different price increments, plotted using the formula above.</p>
</figure>
<p>For example, if the founder wants a 2x price increase for 3000 base currency
invested in the bonding curve, then
they should choose $\Delta_p \approx 0.0005$.</p>
<h3 id="metric2initialslope">Metric 2: Initial slope</h3>
<p>The initial slope of the pricereserve curve is good for comparing
different sets of parameters. It’s equal to</p>
<script type="math/tex; mode=display">\frac{dP}{dR}\bigg\rvert_{R=0} = \frac{\Delta_p}{P_0}</script>
<p>which is a straightforward metric that uses both parameters.</p>
<h3 id="metric3weakhandreturn">Metric 3: Weak hand return</h3>
<p>Another metric is the return obtained when</p>
<ol>
<li>the first ever buyer mints $M_0$ with $B$ base currency,</li>
<li>another buyer mints $M_1 < M_0$ (since price has increased) with $B$ base currency,</li>
<li>and the first buyer burns $M_0$ for profit.</li>
</ol>
<p>The return is calculated as</p>
<script type="math/tex; mode=display">return = \frac{\int_{M_1M_0}^{M_1} P(S)\,dS }{\underbrace{\int_0^{M_0} P(S)\,dS}_{=B}}</script>
<p>where $M_0 = S(B)$ and $M_1 = S(2B)$. It eventually yields</p>
<script type="math/tex; mode=display">return = \frac{1}{\Delta_p B} \left(\sqrt{P_0^4 + 6P_0^2\Delta_p B + 8\Delta_p^2B^2}
+ P_0\left(\sqrt{P_0^2+2\Delta_p B}\sqrt{P_0^2+4\Delta_p B}\right)
 P_0^2
\right)1</script>
<p>One interesting result is</p>
<script type="math/tex; mode=display">\lim_{B\to 0} return = 1
\quad\text{and}\quad
\lim_{B\to\infty} return = 2\sqrt{2}  1 \approx 1.8284\dots</script>
<p>For all positive values of $B$, the return is between 1 and 1.8284.
$B$ is supposed to be a purchase made by an
average buyer. In other words, it’s the expected value of an investment to the
bonding curve.</p>
<p>For a given B, the closer the return is to 1.8284, the more pyramidlike the
distribution. The closer it is to 1, the more stumplike the distribution.</p>
<figure>
<p><a href="/img/pyramid_or_stump/fig2.svg" target="blank_"><img src="/img/pyramid_or_stump/fig2.svg" /></a>
Weak hand return versus B. Price increment’s relationship to the
initial price is a determining factor, and returns have been plotted for
different price increments. For $B=5000$, we can say that around $\Delta_p=0.01$ is
roughly where the distribution stops looking less like a pyramid and more like a stump.</p>
</figure>
<h3 id="example">Example</h3>
<p>As of the beginning of 2019, the most sizeable deployment of a bonding curve ever was
the
<a href="https://etherscan.io/address/0xb3775fb83f7d12a36e0475abdd1fca35c091efbe">PoWH3D contract</a>
on Ethereum. Here is my
<a href="/2018/08/03/tokenbonding1/">previous analysis</a> of it.
At it’s height on July 27, 2018, the contract had more than 82,000 ETH, then
equal to ~$35 million of value.</p>
<p>Is PoWH3D a pyramid or a stump? The parameters are $P_0$ = 1e7 ETH and
$\Delta_p$ = 1e8 ETH. Let’s plug them in and see.</p>
<figure>
<p><a href="/img/pyramid_or_stump/fig4.svg" target="blank_"><img src="/img/pyramid_or_stump/fig4.svg" /></a>
Price versus reserve for PoWH3D, plotted up to reserve alltime high.</p>
</figure>
<p>It seems like the price starts at 0, but in reality, it has
increased so much that one can’t tell the difference. After 1 ETH in the
contract, the price increases ~1400x; after 10 ETH, ~4400x; after 100 ETH, ~14,000x;
after 1000 ETH, ~44,000x; after 10,000 ETH, ~140,000x and so on.
The price triples with each increase in the order of magnitude.
Someone who invested when there was only ~100 ETH in the contract could have
sold it for 28x profit at its height, not taking dividends into account.</p>
<p>Initial slope of the pricereserve curve is equal to 0.1, for the record.</p>
<p>What about the weak hand return? Below is a graph that shows for up to 1 ETH:</p>
<figure>
<p><a href="/img/pyramid_or_stump/fig5.svg" target="blank_"><img src="/img/pyramid_or_stump/fig5.svg" /></a>
Weak hand return versus investment size for PoWH3D. $B$ is in ETH.</p>
</figure>
<p>As you can see, it shoots up to the maximum value really quickly.</p>
<p>Interpreting these results, we can arrive at the conclusion that PoWH3D is a
pyramid rather than a stump, and the price increase is very steep.</p>
<h3 id="summary">Summary</h3>
<p>The pricereserve relationship, derived from the pricesupply relationship,
is more useful in determining linear bonding
curve parameters. More informed decisions can be made based on this curve, using
metrics such as initial slope and price increase at a certain amount of
reserve.
Another metric has been introduced, which calculates the returns after
selling when an investment of size equal to one’s own is made to the bonding
curve. A reallife example has been analyzed.</p>
Sun, 27 Jan 2019 00:00:00 +0000
https://solmaz.io/2019/01/27/pyramidorstump/
https://solmaz.io/2019/01/27/pyramidorstump/matheconomicscryptoThe Anatomy of a Block Stuffing Attack<p><em>Block stuffing</em> is a type of attack in blockchains where an attacker submits
transactions that deliberately fill up the block’s gas limit and stall other
transactions. To ensure inclusion of their transactions by miners, the
attacker can choose to pay higher transaction fees. By controlling the
amount of gas spent by their transactions, the attacker can influence the number
of transactions that get to be included in the block.</p>
<p>To control
the amount of gas spent by the transaction, the attacker utilizes a special
contract. There is a function in the contract which takes as input the amount of
gas that the attacker wants to burn. The function runs meaningless
instructions in a loop, and either returns or throws an error when the desired
amount is burned.</p>
<p>For example let’s say that the average gas price has been 5 Gwei in the last
10 blocks. In order to exert influence over the next block, the attacker needs to
submit transactions with gas prices higher than that, say 100 Gwei. The higher
the gas price, the higher the chance of inclusion by miners.
The attacker can choose to divide the task of using 8,000,000 gas—current
gas limit for blocks—into as
many transactions as they want. This could be 80 transactions with
100,000 gas expenditure, or 4 transactions with 2,000,000 gas expenditure.</p>
<p>Deciding on how to divide the task is a matter of maximizing the chance of
inclusion, and depends on the factors outline below.</p>
<h2 id="minersstrategyforselectingtransactions">Miners’ strategy for selecting transactions</h2>
<p>Miners want to maximize their
profit by including transactions with highest fees. In the current PoW
implementation of Ethereum, mining the block takes significantly more time
than executing the transactions. So let’s assume
all transactions in the pool are trivially executed as soon as they arrive
and miners know the amount of gas each one uses.</p>
<p>For miners, maximizing profit is an
<a href="https://en.wikipedia.org/wiki/Packing_problems">optimum packing problem</a>.
Miners want to choose a subset of the transaction pool that gives them
maximum profit per block. Since there are at least tens of thousands of
transactions in the pool at any given time, the problem can’t be solved by
bruteforcing every combination. Miners use algorithms that test a
feasible number of combinations and select the one giving the highest reward.</p>
<p>A block stuffer’s main goal is to target the selection process by
crafting a set of transactions that has the highest chance of being picked
up by miners in a way that will deplete blocks’ gas limits.
They can’t devise a 100% guaranteed strategy since each miner
can use a different algorithm, but they can find a sweet spot by testing out the
whole network.</p>
<p>(In a PoS system, our assumptions would be wrong since executing
transactions is not trivial compared to validating blocks. Validators would
need to develop more complex strategies depending on the PoS implementation.)</p>
<h2 id="thetransactionstheattackerwantstostall">The transactions the attacker wants to stall:</h2>
<p>It could be so that the
attacker wants to stall transactions with a specific contract. If the
function calls to that contract use a distinctively high amount of gas, say
between 300,000 and 500,000, then the attacker has to stuff the block in a
way that targets that range.</p>
<p>For example, the attacker can periodically submit $n$ transactions
$\{T_1, T_2,\dots, T_{n1}, T_n\}$ with very high prices where</p>
<script type="math/tex; mode=display">\sum\limits_{i=1}^{n} T_i^{\text{gas}} \approx 8,000,000.</script>
<p>If the attacker is targeting transactions within a range of
$(R_\text{lower}, R_\text{upper})$, they can choose
the first $n1$ transactions to deplete $8,000,000  R_\text{upper}$ gas
in short steps, and submit $T_n$ to deplete the remaining $R_\text{upper}$
gas with a relatively higher price. Note that the revenue from including a
single transaction is</p>
<script type="math/tex; mode=display">\text{tx_fee} = \text{gas_price} \times \text{gas_usage}.</script>
<p>As gas usage decreases, the
probability of being picked up by miners decreases, so prices should increase
to compensate.</p>
<h1 id="examplefomo3d">Example: Fomo3D</h1>
<p><a href="https://fomo3d.hostedwiki.co/">Fomo3D</a>
is a gambling game where players buy keys from a contract and their money
goes into a pot. At the beginning of each round, a time counter is initiated
which starts counting back from 24 hours. Each bought key adds 30 seconds to the
counter. When the counter hits 0, the last player to have bought a key wins the
majority of the pot and the rest is distributed to others. The
way the pot is distributed depends on the team that the winner belongs to.</p>
<p>Key price increases with increasing key supply, which makes it harder and harder
to buy a key and ensures the round will end after some point. In time, the stakes
increase and the counter reduces to a minimum, like 2 minutes. At this
point, the players pay both high gas and key prices to be “it” and win the game.
Players program bots to buy keys for them, and winning becomes a matter of coding the
right strategy. As you can understand from the subject, the
first round was won through a block stuffing attack.</p>
<p>On August 22 2018, the address
<a class="hex" href="https://etherscan.io/address/0xa169df5ed3363cfc4c92ac96c6c5f2a42fccbf85">0xa16…f85</a>
won
10,469 ETH from the first round by following the strategy I outlined above. The
winner managed to be the last buyer in
block <a href="https://etherscan.io/block/6191896">6191896</a>
and managed to stall
transactions with Fomo3D until block <a href="https://etherscan.io/block/6191909">6191909</a>
for 175 seconds,
ending the round. Some details:</p>
<ul>
<li>
<p>Fomo3D Long contract address:
<a class="hex" href="https://etherscan.io/address/0xA62142888ABa8370742bE823c1782D17A0389Da1">0xA62…Da1</a></p>
</li>
<li>
<p>Last transaction by the winner before the attack starts:
<a class="hex" href="https://etherscan.io/tx/0x7a06d9f11e650fbb2061b320442e26b4a704e1277547e943d73e5b67eb49c349">0x7a0…349</a></p>
</li>
<li>
<p>Transaction ending the round and firing the <code class="highlighterrouge">onBuyAndDistribute</code> event which
distributes the pot:
<a class="hex" href="https://etherscan.io/tx/0xa143a1ee36e1065c3388440ef7e7b38ed41925ca4799c8a4d429fa3ee1966012">0xa14…012</a></p>
</li>
<li>
<p>Transaction where winner withdraws the prize:
<a class="hex" href="https://etherscan.io/tx/0xe08a519c03cb0aed0e04b33104112d65fa1d3a48cd3aeab65f047b2abce9d508">0xe08…508</a></p>
</li>
<li>
<p>Contract used for block stuffing:
<a class="hex" href="https://etherscan.io/address/0x18e1b664c6a2e88b93c1b71f61cbf76a726b7801">0x18e…801</a></p>
</li>
<li>
<p>Other addresses possibly belonging to the winner:
<a class="hex" href="https://etherscan.io/address/0x3c316def240b1c5ab5e0be027cb91e8ae850ff27">0x3c3…f27</a>
, <a class="hex" href="https://etherscan.io/address/0xc6a4f7f08300a614756f20d823f08417f3ba43e2">0xc6a…3e2</a>
, <a class="hex" href="https://etherscan.io/address/0x81eff1f7a6bf826d550e9503f31e4f2d1973a0ac">0x81e…0ac</a>
, <a class="hex" href="https://etherscan.io/address/0xc96b8de929aea89eb242ed50412da0e4a6e7e590">0xc96…590</a>
, <a class="hex" href="https://etherscan.io/address/0xd27d2afdd35650629c63d4d702eb5f5d2d893642">0xd27…642</a>
, <a class="hex" href="https://etherscan.io/address/0x18da94903de79c18eb0f4f6e6327a4266ef60a9a">0x18d…a9a</a>
, <a class="hex" href="https://etherscan.io/address/0x87c7babe2a9bf81c622a346ffbe57671545854ef">0x87c…4ef</a>
, <a class="hex" href="https://etherscan.io/address/0x9dab207b6c366bb7e1a5d930b865ebda410af0cf">0x9da…0cf</a>
, <a class="hex" href="https://etherscan.io/address/0x7ddae8209776f2c0c94840e3e11c9f3862e2fc4c">0x7dd…c4c</a>
, <a class="hex" href="https://etherscan.io/address/0xb1d4abb185305aad9cda4e3c78fe0faaa9b95aef">0xb1d…aef</a>
, <a class="hex" href="https://etherscan.io/address/0x1a6d5dbb20fd44f04acbaf32712c2dcaaa2bad56">0x1a6…d56</a>
, <a class="hex" href="https://etherscan.io/address/0xf6e89c15731d611a33ddcbf3274cfaaae26e1059">0xf6e…059</a>
, <a class="hex" href="https://etherscan.io/address/0x1dd63481f86b47aa0d429581f1e59db97aa1fa69">0x1dd…a69</a>
, <a class="hex" href="https://etherscan.io/address/0x061d8d0fbceb6754d27eaf0da8facc2f42b0363b">0x061…63b</a>
, <a class="hex" href="https://etherscan.io/address/0x00c463d9e9d276e5689f6bbea54ef248e831e776">0x00c…776</a>
, <a class="hex" href="https://etherscan.io/address/0xa9413093002b8c7139eb6929f53ae760cf397eb8">0xa94…eb8</a>
, <a class="hex" href="https://etherscan.io/address/0xf033ad4b1d63687efc24620be89afd07b21b01f2">0xf03…1f2</a></p>
</li>
<li>
<p>Other contracts possibly deployed by the winner for testing prior to the attack:
<a class="hex" href="https://etherscan.io/address/0xaf1fca749a6625801bb28c93eee763ec346a4eae">0xaf1…eae</a>
, <a class="hex" href="https://etherscan.io/address/0x0c0cee774f02b2f05ad230f1292d8846070255ad">0x0c0…5ad</a>
, <a class="hex" href="https://etherscan.io/address/0x88ef961497f8205d36a53c2e81574fbeae15ed04">0x88e…d04</a>
, <a class="hex" href="https://etherscan.io/address/0x4f427bc21334102943c082ace86b5f3974ab76f8">0x4f4…6f8</a>
, <a class="hex" href="https://etherscan.io/address/0x4870580c874e13b050109c5111e30b06cdc864e5">0x487…4e5</a></p>
</li>
</ul>
<p>The user addresses above were scraped from the Ethereum transaction graph as being
linked to a primary account which supplied them with funds. The contract
addresses were scraped from 0valued transactions sent from user addresses.
These have a <a href="https://en.wikipedia.org/wiki/Distance_(graph_theory)">distance</a>
of 1, there may be other addresses involved with greater distances.</p>
<style>
table {
fontfamily: monospace;
fontsize: small;
}
.highlighted > td {
backgroundcolor: #f6e58d !important;
}
.failed {
textdecoration: linethrough;
}
</style>
<p>Below are details of the last 4 blocks preceding the end of the round. The rows
highlighted with yellow are transactions submitted by the attacker. The crossed
out rows are failed transactions. All transactions by the attacker were
submitted with a 501 Gwei gas price, and stuffing a single block costed around 4
ETH. The calls to buy keys generally spend around 300,000~500,000 gas, depending
on which function was called.
Below, you see the successfully stuffed
block 6191906.</p>
<table>
<caption><a href="https://etherscan.io/block/6191906">Block 6191906</a></caption>
<tr>
<th>Idx</th>
<th>From</th>
<th>To</th>
<th>Hash</th>
<th>ETH sent</th>
<th>Gas Price<br />[Gwei]</th>
<th>Gas Limit</th>
<th>Gas Used</th>
<th>ETH spent<br />on gas</th>
</tr>
<tr class="failed highlighted">
<td>0</td>
<td><a href="https://etherscan.io/address/0xF033ad4b1D63687efc24620be89aFD07b21B01f2">0xF03…1f2</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xb97d8e39db0fab5bc75c72e2fbbf3f1e2651b1e4c3fde5e2db02ee02db3fb8e4">0xb97…8e4</a></td>
<td>0</td>
<td>501.0</td>
<td>4,200,000</td>
<td>4,200,000</td>
<td>2.1042</td>
</tr>
<tr class="failed highlighted">
<td>1</td>
<td><a href="https://etherscan.io/address/0x87C7BABE2A9Bf81C622a346fFbE57671545854eF">0x87C…4eF</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0x96f3038119dcc786820008751380184988e067a3f01c6fbefa177565cc0881b0">0x96f…1b0</a></td>
<td>0</td>
<td>501.0</td>
<td>3,600,000</td>
<td>3,600,000</td>
<td>1.8036</td>
</tr>
<tr class="failed highlighted">
<td>2</td>
<td><a href="https://etherscan.io/address/0xf6E89C15731D611A33DdcbF3274CfAAAe26E1059">0xf6E…059</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0x897fc02810f6bbae8d8bc1a32e1e16f442a4c69fa6f77031e86fe546d6e002b3">0x897…2b3</a></td>
<td>0</td>
<td>501.0</td>
<td>200,000</td>
<td>200,000</td>
<td>0.1002</td>
</tr>
<tr>
<th>Sum</th>
<th></th>
<th></th>
<th></th>
<th>0</th>
<th>1503.01</th>
<th>8,000,000</th>
<th>8,000,000</th>
<th>4.0080</th>
</tr>
</table>
<p>Block 6191907 was a close call for the winner, because their transactions picked
up for the block did not amount up to 8,000,000 and the other transaction was a
call to Fomo3D by an opponent to buy keys. Note that it has a gas price of 5559
Gwei, which means either the bot or person who submitted the transaction was
presumably aware of the attack.
The transaction failed due to low gas limit, presumably due to a miscalculation
by the bot or the person.</p>
<table>
<caption><a href="https://etherscan.io/block/6191907">Block 6191907</a></caption>
<tr>
<th>Idx</th>
<th>From</th>
<th>To</th>
<th>Hash</th>
<th>ETH sent</th>
<th>Gas Price<br />[Gwei]</th>
<th>Gas Limit</th>
<th>Gas Used</th>
<th>ETH spent<br />on gas</th>
</tr>
<tr class="failed">
<td>0</td>
<td><a href="https://etherscan.io/address/0x32AD247B94E46bB75caC37B81e6CB53173002370">0x32A…370</a></td>
<td><a href="https://etherscan.io/address/0xA62142888ABa8370742bE823c1782D17A0389Da1">0xA62…Da1</a></td>
<td><a href="https://etherscan.io/tx/0x5e7309de3aab2a36286fc04aebcfadec627bcb4aa89af4dad82001a5993d1be1">0x5e7…be1</a></td>
<td>0.0056</td>
<td>5559.7</td>
<td>379,000</td>
<td>379,000</td>
<td>2.1071</td>
</tr>
<tr class="failed highlighted">
<td>1</td>
<td><a href="https://etherscan.io/address/0xC6A4F7f08300a614756f20D823f08417F3BA43E2">0xC6A…3E2</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xb8b11c23da4a4b4600be92fb445868af911836db57e235747e28cbb265f6340c">0xb8b…40c</a></td>
<td>0</td>
<td>501.0</td>
<td>3,900,000</td>
<td>3,900,000</td>
<td>1.9539</td>
</tr>
<tr class="failed highlighted">
<td>2</td>
<td><a href="https://etherscan.io/address/0xD27d2aFdD35650629c63d4D702eb5F5D2d893642">0xD27…642</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xbcf63a44632366a063ad4d37f7a17c19a95662ebf571d02cfa180d7309032c62">0xbcf…c62</a></td>
<td>0</td>
<td>501.0</td>
<td>3,300,000</td>
<td>3,300,000</td>
<td>1.6533</td>
</tr>
<tr class="failed highlighted">
<td>3</td>
<td><a href="https://etherscan.io/address/0x00c463D9E9D276e5689F6BbeA54eF248e831e776">0x00c…776</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xf30cc8510c58d34a96e43536e2e1e956f56d3320f8ad16c70a80ec6ac476d337">0xf30…337</a></td>
<td>0</td>
<td>501.0</td>
<td>400,000</td>
<td>400,000</td>
<td>0.2004</td>
</tr>
<tr>
<th>Sum</th>
<th></th>
<th></th>
<th></th>
<th>0.0056</th>
<th>7062.71</th>
<th>7,979,000</th>
<th>7,979,000</th>
<th>5.9147</th>
</tr>
</table>
<p>Transactions in block 6191908 belonged to the attacker except for one irrelevant
transfer. This block is also considered successfully stuffed, since the
7,970,000 gas usage by the attacker leaves no space for a call to buy keys.</p>
<table>
<caption><a href="https://etherscan.io/block/6191908">Block 6191908</a></caption>
<tr>
<th>Idx</th>
<th>From</th>
<th>To</th>
<th>Hash</th>
<th>ETH sent</th>
<th>Gas Price<br />[Gwei]</th>
<th>Gas Limit</th>
<th>Gas Used</th>
<th>ETH spent<br />on gas</th>
</tr>
<tr class="failed highlighted">
<td>0</td>
<td><a href="https://etherscan.io/address/0xD27d2aFdD35650629c63d4D702eb5F5D2d893642">0xD27…642</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0x74acf9d7bb35b8abc2bc3a3bbcd150d59ba5fdbd7303ea657b208ced9138b9b1">0x74a…9b1</a></td>
<td>0</td>
<td>501.0</td>
<td>3,300,000</td>
<td>3,300,000</td>
<td>1.6533</td>
</tr>
<tr class="failed highlighted">
<td>1</td>
<td><a href="https://etherscan.io/address/0x7Ddae8209776F2c0C94840E3E11c9f3862E2fc4c">0x7Dd…c4c</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0x48c720208f47a2d6cd49cc2d539a334ad802732a11233ce1fad61ee686fd2222">0x48c…222</a></td>
<td>0</td>
<td>501.0</td>
<td>2,700,000</td>
<td>2,700,000</td>
<td>1.3527</td>
</tr>
<tr class="failed highlighted">
<td>2</td>
<td><a href="https://etherscan.io/address/0x3C316DEF240b1C5aB5e0be027cb91E8aE850Ff27">0x3C3…f27</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0x01b9d5f0b4b33d47631c1008e5efd296dbe986f1e916f2559253992c430bb4aa">0x01b…4aa</a></td>
<td>0</td>
<td>501.0</td>
<td>1,800,000</td>
<td>1,800,000</td>
<td>0.9018</td>
</tr>
<tr class="failed highlighted">
<td>3</td>
<td><a href="https://etherscan.io/address/0xa9413093002B8C7139EB6929F53aE760CF397eb8">0xa94…eb8</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0x7765ee98603e32ccaef198fc7c495eb360a2a61853d554c55939bd329a947d43">0x776…d43</a></td>
<td>0</td>
<td>501.0</td>
<td>170,000</td>
<td>170,000</td>
<td>0.0851</td>
</tr>
<tr>
<td>4</td>
<td><a href="https://etherscan.io/address/0xbFd35dB76E747C8ed0737954f98B22490F2B31b4">0xbFd…1b4</a></td>
<td><a href="https://etherscan.io/address/0x663C9E9bBF5282bb7485f9D0Cc8Dbc21a0531d31">0x663…d31</a></td>
<td><a href="https://etherscan.io/tx/0x3a650d96b958a2953bfcac0cff9d7aad09463129bb404814e8d42d8e44351ba1">0x3a6…ba1</a></td>
<td>0.05</td>
<td>100.0</td>
<td>21,000</td>
<td>21,000</td>
<td>0.0021</td>
</tr>
<tr>
<th>Sum</th>
<th></th>
<th></th>
<th></th>
<th>0.05</th>
<th>2104.01</th>
<th>7,991,000</th>
<th>7,991,000</th>
<th>3.9950</th>
</tr>
</table>
<p>By block 6191909, the counter has struck zero—more like current UTC time
surpassed the round end variable stored in the contract—and any call to Fomo3D
would be the one to end the round and distribute the pot. And the first transaction
in the block is—wait for it—a call to Fomo3D to buy keys by the opponent
whose transaction failed a few blocks earlier, submitted with 5562 Gwei. So the
guy basically paid 1.7 ETH to declare the attacker the winner!</p>
<table>
<caption><a href="https://etherscan.io/block/6191909">Block 6191909</a></caption>
<tr>
<th>Idx</th>
<th>From</th>
<th>To</th>
<th>Hash</th>
<th>ETH sent</th>
<th>Gas Price<br />[Gwei]</th>
<th>Gas Limit</th>
<th>Gas Used</th>
<th>ETH spent<br />on gas</th>
</tr>
<tr>
<td>0</td>
<td><a href="https://etherscan.io/address/0x32AD247B94E46bB75caC37B81e6CB53173002370">0x32A…370</a></td>
<td><a href="https://etherscan.io/address/0xA62142888ABa8370742bE823c1782D17A0389Da1">0xA62…Da1</a></td>
<td><a href="https://etherscan.io/tx/0xa143a1ee36e1065c3388440ef7e7b38ed41925ca4799c8a4d429fa3ee1966012">0xa14…012</a></td>
<td>0.0056</td>
<td>5562.2</td>
<td>379,000</td>
<td>304,750</td>
<td>1.6950</td>
</tr>
<tr class="highlighted">
<td>1</td>
<td><a href="https://etherscan.io/address/0xC96b8de929aeA89EB242Ed50412da0E4a6e7E590">0xC96…590</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xf4703d5edf02f2b6fc33c6bdbc442b35f91abf0105132e8bafa9f922d18a59ca">0xf47…9ca</a></td>
<td>0</td>
<td>501.0</td>
<td>2,200,000</td>
<td>37,633</td>
<td>0.0188</td>
</tr>
<tr class="highlighted">
<td>2</td>
<td><a href="https://etherscan.io/address/0xb1D4Abb185305aAd9CDa4e3c78FE0FaaA9b95aEF">0xb1D…aEF</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xe4c71f694ae2a0b144bd4db938e20b5597d51cbefd3acb643f63abd3e55feedb">0xe4c…edb</a></td>
<td>0</td>
<td>501.0</td>
<td>1,400,000</td>
<td>37,633</td>
<td>0.0188</td>
</tr>
<tr class="highlighted">
<td>3</td>
<td><a href="https://etherscan.io/address/0x18Da94903De79c18Eb0F4F6e6327A4266ef60A9A">0x18D…A9A</a></td>
<td><a href="https://etherscan.io/address/0x18e1B664C6a2E88b93C1b71F61Cbf76a726B7801">0x18e…801</a></td>
<td><a href="https://etherscan.io/tx/0xf3a1a38d631034010ae5449ce14480bad932028bfc34309fb6030b2c31ed8995">0xf3a…995</a></td>
<td>0</td>
<td>501.0</td>
<td>800,000</td>
<td>37,633</td>
<td>0.0188</td>
</tr>
<tr class="">
<td>…</td>
<td>…</td>
<td>…</td>
<td>…</td>
<td>…</td>
<td>…</td>
<td>…</td>
<td>…</td>
<td>…</td>
</tr>
</table>
<p>Another thing to note is that the attacker probably crafted the spender contract
to stop the attack when the round has ended, presumably to cut costs. So the 37,633
gas used by the contract are probably to call the Fomo3D contract to check
round status. All these point out to the fact that the attacker is an
experienced programmer who knows their way around Ethereum.</p>
<p><a href="/assets/fomo3d_round1_tx_details.html">Here</a>, you can see the details of the 100
blocks preceding the end of the round, with the additional information of ABI
calls and events fired in transactions.</p>
<p>Since the end of the first round, 2 more rounds ended with attacks similar to
this one. I didn’t analyze all of them because it’s too much for this post, but
here are some details if you want to do it yourselves.</p>
<div style="overflowx: scroll;">
<table>
<thead>
<tr>
<th>Round</th>
<th>Address winning the pot</th>
<th>Winner’s last tx before the end of the round</th>
<th>Block containing that tx</th>
<th>Tx ending the round</th>
<th>Block containing that tx</th>
<th>Tx where winner withdraws prize</th>
<th>Amount won [ETH]</th>
<th>Contract used for block stuffing</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>0xa169df5ed3363cfc4c92ac96c6c5f2a42fccbf85</td>
<td>0x7a06d9f11e650fbb2061b320442e26b4a704e1277547e943d73e5b67eb49c349</td>
<td>6191896</td>
<td>0xa143a1ee36e1065c3388440ef7e7b38ed41925ca4799c8a4d429fa3ee1966012</td>
<td>6191909</td>
<td>0xe08a519c03cb0aed0e04b33104112d65fa1d3a48cd3aeab65f047b2abce9d508</td>
<td>10,469</td>
<td>0x18e1b664c6a2e88b93c1b71f61cbf76a726b7801</td>
</tr>
<tr>
<td>2</td>
<td>0x18a0451ea56fd4ff58f59837e9ec30f346ffdca5</td>
<td>0x0437885fa741f93acfdcda9f5a2e673bb16d26dd22dfc4890775efb8a94fb583</td>
<td>6391537</td>
<td>0x87bf726bc60540c6b91cc013b48024a5b8c1431e0847aadecf0e92c56f8f46fd</td>
<td>6391548</td>
<td>0x4da4052d2baffdc9c0b82d628b87d2c76368914e33799032c6966ee8a3c216a0</td>
<td>3,264</td>
<td>0x705203fc06027379681AEf47c08fe679bc4A58e1</td>
</tr>
<tr>
<td>3</td>
<td>0xaf492045962428a15903625B1a9ECF438890eF92</td>
<td>0x88452b56e9aa58b70321ee8d5c9ac762a62509c98d9a29a4d64d6caae49ae757</td>
<td>6507761</td>
<td>0xe6a5a10ec91d12e3fec7e17b0dfbb983e00ffe93d61225735af2e1a8eabde003</td>
<td>6507774</td>
<td>0xd7e70fdf58aca40139246a324e871c84d988cfaff673c9e5f384315c91afa5e4</td>
<td>376</td>
<td>0xdcC655B2665A675B90ED2527354C18596276B0de</td>
</tr>
</tbody>
</table>
</div>
<p>A thing to note in the following rounds is that participation in the game
and amount of pot gradually decreased, presumably owing to the fact that
the way of beating the game has been systematized. Although anyone can attempt
such an attack, knowing how it will be won takes the “fun” factor out of it.</p>
<p>Credit: Although I’ve found previous instances of the term “block stuffing”
online, Nic Carter is the first
one to <a href="https://twitter.com/nic__carter/status/1032262665668894721">use it</a> in
this context.</p>
Thu, 18 Oct 2018 00:00:00 +0000
https://solmaz.io/2018/10/18/anatomyblockstuffing/
https://solmaz.io/2018/10/18/anatomyblockstuffing/cryptoEnsuring Exactness in CurveBonded Dividend Token Systems<p>I have <a href="/math/2018/08/03/tokenbonding1/">written recently</a> on the math
behind curved token bonding, and done some derivations on a recent
dividend token implementation that utilizes it, called PoWH3D. First of all, here is a
<a href="https://medium.com/@optimumregret/thesurrealmadnessofethereumspyramidschemesda705fe7d92e">nice post</a>
documenting the failure of its previous iteration.</p>
<p>Despite its creators’ marketing it as a gambling ecosystem, the math behind
PoWH3D might prove to be a significant contribution to creating a reliable
dividendbased <a href="https://en.wikipedia.org/wiki/Basic_income">UBI</a> system. Because
unlike its predecessor which failed miserably due to math and implementation
errors, it works (at least as of writing this). Like clockwork, 10% of every
buy, sell and transfer goes to token holders.
More than 70,000 ETH (~$30m)
were deposited to the contract at the all time high.</p>
<p><em>But the contract is not perfect.</em> Let’s entertain the following scenario:</p>
<blockquote>
<p>Nobody has bought P3D yet, and you send 10,000 ETH to the contract. 9000 ETH
worth of P3D are minted, and 1000 ETH is distributed to the only token holder,
you. Then you decide to sell the tokens you have just bought. Their worth in
ETH is computed, and you receive 9/10th of it. The dividends from the sale go
to the only token holder—again, you. So after the purchase and sale, you only
have a fraction of your original 10,000 ETH, and the rest is stored in the
contract as dividends, belonging to you. So withdrawing the dividends, you
should end up with 10,000 ETH, right?</p>
</blockquote>
<p>I tested the scenario and,
<a href="https://github.com/osolmaz/powh3dstudy/blob/master/test_exact_dividends.py">here is the code</a>
to replicate the results. Below is the output.</p>
<div class="highlighterrouge"><div class="highlight"><pre class="highlight"><code>Change in own ETH balance: 885.0215718635744
P3D balance: 0.0
Contract ETH balance: 900.0215718635744
Contract P3D supply: 0.0
</code></pre></div></div>
<p>All P3D has been burned and dividends withdrawn, but 900 ETH remain in the
contract, essentially bricked. This corresponds to ~9% of the initial
investment. Why is that?</p>
<p>In a purchase or sale, the relationship between minted/burned tokens and
spent/reimbursed ethers is nonlinear, expressed by a nonconstant supplyprice
relationship:</p>
<figure>
<p><img src="/img/token_bonding/supply_price.svg" /></p>
</figure>
<p>And the dividends correspond to 9/10th of that area. The problem is how the
dividends are distributed. Your share is computed from your token balance
<em>after</em> the transaction. So if you sell all your tokens at once, your share of the
dividends from that sale is zero.</p>
<p>If one intends to sell large amount of tokens, this can be mitigated by dividing
the sale into installments. The amount of bricked ETH decreases exponentially
with increasing number of installments, as tested
<a href="https://github.com/osolmaz/powh3dstudy/blob/master/installment_sale.py">in this code</a>.</p>
<figure>
<p><img src="/img/exact_dividends/bricked_eth_installments.svg" />
Percentage of bricked ETH for the scenario above, for token sales consisting of
different number of installments.</p>
</figure>
<p>The computation of the contract becomes exact for an infinite number of
installments, given the transactions are costless. The same problem exists for
purchases. <em>Buyers are overpaid and sellers are underpaid in dividends,
and the effects don’t cancel out for large sums, as demonstrated above.</em></p>
<p>So how can we design this system to be exact? The computation of dividends needs
to account for the varying supplyprice relationship.</p>
<h1 id="purchasedividends">Purchase Dividends</h1>
<p>Let $S_0$ be the initial token supply, $\bar{T}_0$ our initial token balance,
and $R_d$ the dividend ratio of the system, e.g. 1/10 for PoWH3D.
Let us send $E$ ETH to the contract and received $T$ tokens in return, where
$D=R_d E$ is supposed to be
distributed as dividends. In PoWH3D, our dividends $\bar{D}$ from this purchase
is computed as</p>
<script type="math/tex; mode=display">\bar{D} = \frac{\bar{T}_0+\delta T}{S_0+\delta T} D.</script>
<p>Let us define the varying supply $S$ a function of the initial supply $S_0$ and
token increment $\delta T$:</p>
<script type="math/tex; mode=display">S := S_0 + \delta T.</script>
<p>Using this, we can formulate the equation above in terms of $S$ instead of
$\delta T$:</p>
<script type="math/tex; mode=display">\bar{D} = \left[1\frac{S_0T_0}{S}\right]D \tag{$\ast$}</script>
<p>and the sum of dividends distributed to everyone else can be computed as</p>
<script type="math/tex; mode=display">\tilde{D} := D\bar{D} = \frac{S_0T_0}{S}D.\tag{$\ast\ast$}</script>
<p>However, as demonstrated above, this computation yields inexact results. To
achieve exact results, we have to integrate over the $S$$P$ curve. The
relationship between spent ether and received tokens is</p>
<script type="math/tex; mode=display">E = \int_{S_0}^{S_0+T} P\, dS</script>
<p>For a linear bonding curve</p>
<script type="math/tex; mode=display">P(S) = P_0 + S I_p,</script>
<p>we have $E$ and $T$ in terms of each other:</p>
<script type="math/tex; mode=display">E(S, T) = T P_0 + T I_p S + \frac{1}{2} T^2 I_p</script>
<p>and</p>
<script type="math/tex; mode=display">T(S, E) = \frac{\sqrt{S^2I_p^2 + 2E I_p + 2 S P_0 I_p + P_0^2}P_0}{I_p}  S.\tag{$\dagger$}</script>
<p>Deriving from $(\ast)$, our <em>exact</em> dividend from the sale is calculated as</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{aligned}
\bar{D} &= \int_{S_0}^{S_0+T} P R_d \left[1\frac{S_0T_0}{S}\right] \, dS \\
&= \frac{R_d}{2}\left[
I_pT^2+2I_pTT_0+2P_0T + 2P_0(S_0+T_0)\ln\left(\frac{S_0}{S_0+T}\right)
\right]
.
\end{aligned} %]]></script>
<p>Calculation of the <em>exact</em> dividend of everyone else follows similarly
using $(\ast\ast)$</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{aligned}
\tilde{D} &= \int_{S_0}^{S_0+T} P R_d \left[\frac{S_0T_0}{S}\right] \, dS \\
&= R_d (S_0T_0) \left[I_p T  P_0 \ln\left(\frac{S_0}{S_0+T}\right)\right].
\end{aligned} %]]></script>
<p>Summing these up and substituting $(\dagger)$, we see</p>
<script type="math/tex; mode=display">\bar{D}+\tilde{D} = R_d E = D</script>
<p>which verifies the results.</p>
<p>Similar to PoWH3D, $\tilde{D}$ (sum of the dividends of everyone except the
purchaser) is distributed using token balances as weights. The difference is
that the dividends of the purchaser and the rest are computed separately.</p>
<h1 id="saledividends">Sale Dividends</h1>
<p>For a sale, the relationship between reimbursed ether and received tokens is</p>
<script type="math/tex; mode=display">E = \int_{S_0T}^{S_0} P\, dS</script>
<p>For a linear curve, we have the following relationships of $E$ and $T$:</p>
<script type="math/tex; mode=display">E(S, T) = T P_0 + T I_p S  \frac{1}{2} T^2 I_p</script>
<p>and</p>
<script type="math/tex; mode=display">T(S, E) = \frac{P_0\sqrt{S^2I_p^2  2E I_p + 2 S P_0 I_p + P_0^2}}{I_p} + S.</script>
<p>This time, the dividends are calculated according to</p>
<script type="math/tex; mode=display">\bar{D} = \frac{\bar{T}_0  \delta T}{S_0  \delta T} D</script>
<p>and the varying supply is calculated as</p>
<script type="math/tex; mode=display">S := S_0  \delta T.</script>
<p>Substituting, we see that $(\ast)$ and $(\ast\ast)$ also hold for sale.
For our dividends, we have</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{aligned}
\bar{D} &= \int_{S_0T}^{S_0} P R_d \left[1\frac{S_0T_0}{S}\right] \, dS \\
&= \frac{R_d}{2}\left[
I_pT^2+2I_pTT_0+2P_0T  2P_0(S_0T_0)\ln\left(\frac{S_0}{S_0T}\right)
\right]
.
\end{aligned}
. %]]></script>
<p>For the rest, we have</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{aligned}
\tilde{D} &= \int_{S_0T}^{S_0} P R_d \left[\frac{S_0T_0}{S}\right] \, dS \\
&= R_d (S_0T_0) \left[I_p T + P_0 \ln\left(\frac{S_0}{S_0T}\right)\right]
.
\end{aligned} %]]></script>
<h1 id="conclusion">Conclusion</h1>
<p>I discovered an inconsistency in a smart contract worth $30m while
playing with it. Although it may not be critical, the case proves that people
are OK with pouring money into a project that hasn’t even released a whitepaper,
as long as they are halfsure that they will profit from it. My intuition
makes me doubt that this can allow someone to exploit the contract. But who
knows; if someone manages to hack it, the prize is at least 10 times bigger than
it was in PoWH.</p>
<p>PoWH3D aside, the formulation above can be used to achieve exactness in any
dividend token. I didn’t go into how it can be integrated into a smart contract,
because it is out of the scope of this study. The right way of keeping account
of dividends is not having a map of addresses to dividends and iterating that
map in every transaction, but keeping track of profits per token, which achieves
the same result implicitly. This is how PoWH3D does it, but since my concerns are
theoretical, I didn’t delve into how this might be implemented.</p>
Thu, 16 Aug 2018 00:00:00 +0000
https://solmaz.io/2018/08/16/exactdividends/
https://solmaz.io/2018/08/16/exactdividends/matheconomicscryptoBreaking Even in PoWH3D and the Math Behind Curved Token Bonding<p>Curved Token Bonding is a set of protocol designs first documented by
<a href="http://simondlr.com">Simon de la Rouviere</a>
in his
<a href="https://medium.com/@simondlr/tokens20curvedtokenbondingincurationmarkets1764a2e0bee5">Medium</a>
<a href="https://medium.com/@simondlr/curationmarketscurvedbondingupdate02april201887c593d629c2">articles</a>.
Ethers are bonded to tokens, which are minted or burned by the smart contract on
buy and sell demands respectively.
Every buy and sell changes the price of the token according to a
predefined formula. The “curves” here represent the relationship between the
price of a single token and the token supply, as defined by said formula.
The result is an etherbacked token that rewards early adopters.</p>
<figure>
<p><img src="/img/token_bonding/supply_price.svg" />
An example supply versus price graph. The area below the curve is equal to the
amount of ethers E that must be spent to increase the supply from $S_0$ to $S_1$,
or that is going to be received when $S_1S_0$ tokens are sold.</p>
</figure>
<p>Inside a transaction, <strong>the price paid/received per token is not constant</strong> and
depends on the amount that is bought or sold. This complicates the calculations.</p>
<p>Let’s say for an initial supply of $S_0$, we want to buy $T$ tokens which are
added to the new supply $S_1=S_0+T$. The ether E that must be spent for this
purchase is defined as</p>
<script type="math/tex; mode=display">E = \int_{S_0}^{S_1} P\, dS</script>
<p>which is illustrated in the figure above. If one wanted to sell $T$ tokens, the
upper limit for the integral would be $S_0$ and the lower $S_0T$, with E
corresponding to the amount of ether received for the sale.</p>
<h1 id="linearcurves">Linear Curves</h1>
<p>A linear relationship for the bonding curves are defined as</p>
<script type="math/tex; mode=display">P(S) = P_0 + S I_p</script>
<p>where $P_0$ is the initial price of the token and $I_p$ is the price increment
per token.</p>
<h2 id="buyingtokens">Buying Tokens</h2>
<p>Let us have E ethers which we want to buy tokens with. Substituting $P$ into the
integral above with the limits $S_0\to S_0+T$, we obtain $E$ in terms of the
tokens $T$ that we want to buy:</p>
<script type="math/tex; mode=display">E(S, T) = T P_0 + T I_p S + \frac{1}{2} T^2 I_p</script>
<p>where $S$ is the supply before the purchase. Solving this for $T$, we obtain the
tokens received in a purchase as a function of the supply and ethers spent:</p>
<script type="math/tex; mode=display">\boxed{T(S, E) = \frac{\sqrt{S^2I_p^2 + 2E I_p + 2 S P_0 I_p + P_0^2}P_0}{I_p}  S.}</script>
<h2 id="sellingtokens">Selling Tokens</h2>
<p>Let us have T tokens which we want to sell for ethers. Selling $T$ tokens
decreases the supply from $S_0$ to $S_0T$, which we apply as limits for the
above integral and obtain:</p>
<script type="math/tex; mode=display">\boxed{E(S, T) = T P_0 + T I_p S  \frac{1}{2} T^2 I_p.}</script>
<h1 id="breakingeveninpowh3d">Breaking Even in PoWH3D</h1>
<p><a href="https://powh.io/">PoWH3D</a> is one of the applications of curved token bonding
with a twist: 1/10th of every transaction is distributed among token holders as
dividends. When you buy tokens with $E$ ethers, you receive $9/10 E$ worth of
tokens and $1/10 E$ is distributed to everybody else in proportion to the amount
they hold.</p>
<p>This means you are at a loss when you buy P3D (the token used by PoWH3D).
If you were to sell immediately,
you would only receive 81% of your money. Given the situation, one wonders when
exactly one can break even with their investment. The activity in PoWH3D isn’t
deterministic; nonetheless we can deduce <strong>sufficient but not
necessary conditions</strong> for breaking even in PoWH3D.</p>
<p>See <a href="https://bitses.org/analyses/powh3ddemiculus/">Bitses.org</a> for a report on PoWH3D.</p>
<h2 id="sufficientpurchase">Sufficient Purchase</h2>
<p>Let us spend $E_1$ ethers to buy tokens at supply $S_0$. The following calculations are
done with the assumption that the tokens received</p>
<script type="math/tex; mode=display">T_1 = T(S_0, 9E_1/10)</script>
<p>are small enough to be
neglected, that is $T_1 \ll S_0$ and $S_1 \approx S_0$. In other words, <em>this only
holds for nonwhale purchases</em>.</p>
<p>Then let others spend $E_2$ ethers to buy tokens and raise the supply to $S_2$.
The objective is to find an $E_2$ large enough to earn us dividends and make us
break even when we sell our tokens at $S_2$.
We have</p>
<script type="math/tex; mode=display">S_2 = S_0 + T(S_0, E_2).</script>
<p>Our new share of the P3D pool is $T_1/S_2$ and the dividends we earn from
the purchase is equal to</p>
<script type="math/tex; mode=display">\frac{1}{10}\frac{T_1}{S_2}E_2.</script>
<p>Then the condition for breaking even is</p>
<script type="math/tex; mode=display">\boxed{\frac{9}{10} E(S_2, T_1) + \frac{1}{10}\frac{T_1}{S_2}E_2 \geq E_1.}</script>
<p>This inequality has a lengthy analytic solution which is impractical to
typeset. The definition should be enough:</p>
<script type="math/tex; mode=display">E^{\text{suff}}_2(S_0, E_1) := \text{solve for $E_2$}\left\{\frac{9}{10} E(S_2, T_1) + \frac{1}{10}\frac{T_1}{S_2}E_2 = E_1\right\}</script>
<p>and</p>
<script type="math/tex; mode=display">E_2 \geq E^{\text{suff}}_2.</script>
<p>$E^{\text{suff}}_2$ can be obtained from the source of this page in JavaScript from
the function <code class="highlighterrouge">sufficient_purchase</code>. <em>Note that the function involves many power
and square operations and may yield inexact results for too high values of
$S_0$ or too small values off $E_1$, due to insufficient precision of the
underlying math functions.</em> For this reason, the calculator below is disabled
for sensitive input.</p>
<figure>
<p><img src="/img/token_bonding/limit_buy_single.svg" />
$S_0$ versus $E^{\text{suff}}_2$ for $E_1 = 100$.</p>
</figure>
<p>The relationship between the initial supply and sufficient purchase is roughly
quadratic, as seen from the graph above. This means that the difficulty of
breaking even increases quadratically as more people buy into P3D. As interest in
PoWH3D saturates, dividends received from the supply increase decreases
quadratically.</p>
<figure>
<p><img src="/img/token_bonding/limit_buy_log.svg" />
Logarithmic plot of $S_0$ versus $E^{\text{suff}}_2$ for changing values of $E_1$.</p>
</figure>
<p>The relationship is not exactly quadratic, as seen from the graph above. The
function is sensitive to $E_1$ for small values of $S_0$.</p>
<h2 id="sufficientsale">Sufficient Sale</h2>
<p>Let us spend $E_1$ ethers to buy tokens at supply $S_0$ and receive $T_1$ tokens.</p>
<p>Then let others sell $T_2$ P3D to lower the supply to $S_2$.
The objective is to find a $T_2$ large enough to earn us dividends and make us
break even when we sell our tokens at $S_2$.
We have</p>
<script type="math/tex; mode=display">S_2 = S_0  T_2.</script>
<p>Our new share of the P3D pool is $T_1/S_2$ and the dividends we earn from
the purchase is equal to</p>
<script type="math/tex; mode=display">\frac{1}{10}\frac{T_1}{S_2} E(S_2, T_2)</script>
<p>Then the condition for breaking even is</p>
<script type="math/tex; mode=display">\boxed{\frac{9}{10} E(S_2, T_1) + \frac{1}{10}\frac{T_1}{S_2} E(S_2, T_2) \geq E_1.}</script>
<p>Similar to the previous section, we have</p>
<script type="math/tex; mode=display">T^{\text{suff}}_2(S_0, E_1) := \text{solve for $T_2$}\left\{\frac{9}{10} E(S_2, T_1) + \frac{1}{10}\frac{T_1}{S_2} E(S_2, T_2) = E_1\right\}</script>
<p>and</p>
<script type="math/tex; mode=display">T_2 \geq T^{\text{suff}}_2.</script>
<p>$T^{\text{suff}}_2$ can be obtained from the function <code class="highlighterrouge">sufficient_sale</code>.</p>
<figure>
<p><img src="/img/token_bonding/limit_sell.svg" />
$S_0$ versus $T^{\text{suff}}_2$ for $E_1 = 100$.</p>
</figure>
<p>The relationship between $S_0$ and $T^{\text{suff}}_2$ is linear and
insensitive to $E_1$. Regardless of the ethers you invest, the
amount of tokens that need to be sold to guarantee your breakeven is roughly
the same, depending on your entry point.</p>
<h2 id="calculator">Calculator</h2>
<p>Below is a calculator you can input $S_0$ and $E_1$ to calculate
$E^{\text{suff}}_2$ and $T^{\text{suff}}_2$.</p>
<table>
<tr><th>$S_0$</th> <th><input type="text" id="s0input" value="3500000" /></th></tr>
<tr><th>$E_1$ </th> <th><input type="text" id="e1input" value="100" /></th></tr>
<tr><th>$E^{\text{suff}}_2 $ </th> <th><input type="text" id="e2suffinput" readonly="" /></th></tr>
<tr><th>$T^{\text{suff}}_2 $ </th> <th><input type="text" id="t2suffinput" readonly="" /></th></tr>
</table>
<p>For the default values above, we read this as:</p>
<blockquote>
<p>For 100 ETH worth of P3D bought
at 3,500,000 supply, either a purchase of ~31715 ETH
or a sale of ~3336785 P3D
made by other people is sufficient to
break even.</p>
</blockquote>
<p>In order to follow these statistics, you can follow
<a href="https://powh3d.eu/">this site</a>.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Calculations with curved token bonding contracts can get complicated because the
price paid per token depends on the amount of intended purchase/sale.
With this work, I aimed to clarify the logic behind PoWH3D.
Use the formulation and calculator at your own risk.</p>
<p>The above conditions are only sufficient and not necessary for a breakeven.
As PoWH3D becomes more popular, it gets quadratically more difficult to break
even from a supply increase.
Thus PoWH3D by itself doesn’t offer any value that is enough to make a profit
for its holders.
However every buy, sell and transfer deliver dividends.
According to its creators, P3D is intended to become the base token for a number
of games that will be built upon PoWH3D, like <a href="https://exitscam.me/">FOMO3D</a>.
With utilization of P3D in other games, sustained profit may become a possibility.
PoWH3D might become the foundation of a gaming/gambling ecosystem the likes of
which the world has never seen.</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.slim.js"></script>
<script>
var P_0 = 0.0000001;
var Delta_p = 0.00000001;
function sufficient_purchase(S_0, X){
return (20475*Delta_p**4*S_0**4/7396  42075*Delta_p**3*P_0*S_0**3/3698 + 4095*Delta_p**3*S_0**3*Math.sqrt(25*Delta_p**2*S_0**2 + 50*Delta_p*P_0*S_0 + 45*Delta_p*X + 25*P_0**2)/7396  22275*Delta_p**3*S_0**2*X/7396  111375*Delta_p**2*P_0**2*S_0**2/7396 + 12735*Delta_p**2*P_0*S_0**2*Math.sqrt(25*Delta_p**2*S_0**2 + 50*Delta_p*P_0*S_0 + 45*Delta_p*X + 25*P_0**2)/7396  92675*Delta_p**2*P_0*S_0*X/14792 + 1539*Delta_p**2*S_0*X*Math.sqrt(25*Delta_p**2*S_0**2 + 50*Delta_p*P_0*S_0 + 45*Delta_p*X + 25*P_0**2)/14792 + 3249*Delta_p**2*X**2/59168  13050*Delta_p*P_0**3*S_0/1849 + 2385*Delta_p*P_0**2*S_0*Math.sqrt(25*Delta_p**2*S_0**2 + 50*Delta_p*P_0*S_0 + 45*Delta_p*X + 25*P_0**2)/1849  1915*Delta_p*P_0**2*X/1849 + 361*Delta_p*P_0*X*Math.sqrt(25*Delta_p**2*S_0**2 + 50*Delta_p*P_0*S_0 + 45*Delta_p*X + 25*P_0**2)/3698  1125*P_0**4/1849 + 225*P_0**3*Math.sqrt(25*Delta_p**2*S_0**2 + 50*Delta_p*P_0*S_0 + 45*Delta_p*X + 25*P_0**2)/1849 + Math.sqrt(53660880000*Delta_p**8*S_0**8 + 441080640000*Delta_p**7*P_0*S_0**7  10732176000*Math.sqrt(5)*Delta_p**7*S_0**7*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 76285728000*Delta_p**7*S_0**6*X + 1490179680000*Delta_p**6*P_0**2*S_0**6  77483952000*Math.sqrt(5)*Delta_p**6*P_0*S_0**6*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 479914128000*Delta_p**6*P_0*S_0**5*X  5598187200*Math.sqrt(5)*Delta_p**6*S_0**5*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)  2711140000*Delta_p**6*S_0**4*X**2 + 2672896320000*Delta_p**5*P_0**3*S_0**5  220551984000*Math.sqrt(5)*Delta_p**5*P_0**2*S_0**5*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 1106883648000*Delta_p**5*P_0**2*S_0**4*X  30308040000*Math.sqrt(5)*Delta_p**5*P_0*S_0**4*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)  5107816000*Delta_p**5*P_0*S_0**3*X**2 + 1234065200*Math.sqrt(5)*Delta_p**5*S_0**3*X**2*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 2469759840*Delta_p**5*S_0**2*X**3 + 2735862480000*Delta_p**4*P_0**4*S_0**4  314027280000*Math.sqrt(5)*Delta_p**4*P_0**3*S_0**4*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 1136320272000*Delta_p**4*P_0**3*S_0**3*X  52648502400*Math.sqrt(5)*Delta_p**4*P_0**2*S_0**3*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)  8447067600*Delta_p**4*P_0**2*S_0**2*X**2 + 3684958800*Math.sqrt(5)*Delta_p**4*P_0*S_0**2*X**2*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 4636063080*Delta_p**4*P_0*S_0*X**3 + 40001688*Math.sqrt(5)*Delta_p**4*S_0*X**3*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 10556001*Delta_p**4*X**4 + 1585267200000*Delta_p**3*P_0**5*S_0**3  233145216000*Math.sqrt(5)*Delta_p**3*P_0**4*S_0**3*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 499041792000*Delta_p**3*P_0**4*S_0**2*X  30411187200*Math.sqrt(5)*Delta_p**3*P_0**3*S_0**2*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)  15170867200*Delta_p**3*P_0**3*S_0*X**2 + 1889499840*Math.sqrt(5)*Delta_p**3*P_0**2*S_0*X**2*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 1103100480*Delta_p**3*P_0**2*X**3 + 37532448*Math.sqrt(5)*Delta_p**3*P_0*X**3*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 477083520000*Delta_p**2*P_0**6*S_0**2  83908224000*Math.sqrt(5)*Delta_p**2*P_0**5*S_0**2*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 74801088000*Delta_p**2*P_0**5*S_0*X  3770841600*Math.sqrt(5)*Delta_p**2*P_0**4*S_0*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 8098212800*Delta_p**2*P_0**4*X**2  661120960*Math.sqrt(5)*Delta_p**2*P_0**3*X**2*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 60134400000*Delta_p*P_0**7*S_0  11508480000*Math.sqrt(5)*Delta_p*P_0**6*S_0*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 8824320000*Delta_p*P_0**6*X  1298304000*Math.sqrt(5)*Delta_p*P_0**5*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 2592000000*P_0**8  518400000*Math.sqrt(5)*P_0**7*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2))/59168)/(Delta_p*(10*Delta_p**2*S_0**2 + 20*Delta_p*P_0*S_0  2*Math.sqrt(5)*Delta_p*S_0*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 9*Delta_p*X + 10*P_0**2  2*Math.sqrt(5)*P_0*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)));
}
function sufficient_sale(S_0, X){
return (26*Math.sqrt(5)*Delta_p**2*S_0**2/17 + 43*Math.sqrt(5)*Delta_p*P_0*S_0/17  26*Delta_p*S_0*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)/17 + 181*Math.sqrt(5)*Delta_p*X/170 + Math.sqrt(5)*P_0**2  P_0*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)  Math.sqrt(64000*Delta_p**4*S_0**4 + 400000*Delta_p**3*P_0*S_0**3  12800*Math.sqrt(5)*Delta_p**3*S_0**3*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 220500*Delta_p**3*S_0**2*X + 897000*Delta_p**2*P_0**2*S_0**2  67200*Math.sqrt(5)*Delta_p**2*P_0*S_0**2*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 715400*Delta_p**2*P_0*S_0*X  32580*Math.sqrt(5)*Delta_p**2*S_0*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 163805*Delta_p**2*X**2 + 850000*Delta_p*P_0**3*S_0  112200*Math.sqrt(5)*Delta_p*P_0**2*S_0*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 567800*Delta_p*P_0**2*X  61540*Math.sqrt(5)*Delta_p*P_0*X*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2) + 289000*P_0**4  57800*Math.sqrt(5)*P_0**3*Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2))/170)/(Delta_p*(Math.sqrt(5)*Delta_p*S_0 + Math.sqrt(5)*P_0  Math.sqrt(5*Delta_p**2*S_0**2 + 10*Delta_p*P_0*S_0 + 9*Delta_p*X + 5*P_0**2)));
}
function update_boxes() {
var s0 = Number($("#s0input").val());
var e1 = Number($("#e1input").val());
var t2suff = sufficient_sale(s0, e1).toFixed(0);
var e2suff = sufficient_purchase(s0, e1).toFixed(2);
var e2_sensitivity = Math.abs((sufficient_purchase(s0, e1*1.0001)
 sufficient_purchase(s0, e1))/sufficient_purchase(s0, e1));
if (isNaN(e2_sensitivity)  e2_sensitivity > 1e3) {
e2suff = 'Precision Error';
}
if (s0 <= 0  e1 <= 0  e1 > s0/1000) {
e2suff = 'Invalid Range';
t2suff = 'Invalid Range';
}
$("#e2suffinput").val(e2suff);
$("#t2suffinput").val(t2suff);
}
$("#s0input").on("keyup change load", function() {update_boxes();});
$("#e1input").on("keyup change load", function() {update_boxes();});
$(document).ready(function(){
update_boxes();
});
</script>
Fri, 03 Aug 2018 00:00:00 +0000
https://solmaz.io/2018/08/03/tokenbonding1/
https://solmaz.io/2018/08/03/tokenbonding1/matheconomicscryptoLumped L2 Projection<div style="display:none">
<p>$
\newcommand{\rowsum}{\mathop{\rm rowsum}\nolimits}
\newcommand{\nnode}{n}
\newcommand{\suml}[2]{\sum\limits_{#1}^{#2}}
$</p>
</div>
<p>When utilizing Galerkintype solutions for
<a href="https://en.wikipedia.org/wiki/Boundary_value_problem">IBVP</a>s, we often
have to compute integrals using numerical methods such as
<a href="https://en.wikipedia.org/wiki/Gaussian_quadrature">Gauss quadrature</a>. In
such a solution, we solve for the values of a function at <em>mesh nodes</em>, whereas
the integration takes place at the <em>quadrature points</em>. Depending on the case,
we may need to compute the values of a function at mesh nodes, given their
values at quadrature points, e.g. stress recovery for mechanical problems.</p>
<p>There are many ways of achieving this, such as
<a href="https://www.sciencedirect.com/science/article/pii/004578259290023D">superconvergent patch recovery</a>.
In this post, I wanted to document a widely used solution which is easy to
implement, and which is used in research oriented codebases such as
<a href="http://projects.ce.berkeley.edu/feap/">FEAP</a>.</p>
<h1 id="l2projection">L2 Projection</h1>
<p>Given a function $u \in L^2(\Omega)$, its projection into a finite element space
$V_h\subset L^2(\Omega)$ is defined through the following optimization
problem:</p>
<p>Find $u_h\in V_h$ such that</p>
<script type="math/tex; mode=display">\begin{equation}
\Pi(u_h) := \frac{1}{2}\lVert u_hu \rVert^2_{L^2(\Omega)}
\quad\rightarrow\quad
\text{min}
\end{equation}</script>
<p>There is a unique solution to the problem since $\Pi(\cdot)$ is convex. Taking
its variation, we have
<script type="math/tex">\begin{equation}
D \Pi(u_h) \cdot v_h = \langle u_hu, v_h \rangle = 0
\end{equation}</script></p>
<p>for all $v_h\in V_h$. Thus we have the following variational formulation</p>
<blockquote>
<p>Find $u_h\in V_h$ such that</p>
<script type="math/tex; mode=display">\begin{equation}
\langle u_h,v_h\rangle = \langle u, v_h\rangle
\end{equation}</script>
<p>for all $v_h\in V_h$.</p>
</blockquote>
<p>Here,</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{equation}
\begin{alignedat}{3}
m(u_h,v_h) &= \langle u_h,v_h\rangle && = \int_\Omega u_hv_h \,dx \quad\text{and} \\
b(v_h) &= \langle u, v_h\rangle && = \int_\Omega u v_h \,dx
\end{alignedat}
\end{equation} %]]></script>
<p>are our bilinear and linear forms respectively. Substituting FE
discretizations $u_h = \sum_{J=1}^{\nnode} u^JN^J$ and
$v_h = \sum_{I=1}^{\nnode} v^IN^I$, we have</p>
<script type="math/tex; mode=display">\begin{equation}
\suml{J=1}{\nnode} M^{I\!J} u^J = b^I
\label{eq:projectionsystem1}
\end{equation}</script>
<p>for $I=1,\dots,\nnode$,
where the FE matrix and vector are defined as</p>
<script type="math/tex; mode=display">% <![CDATA[
\begin{equation}
\begin{alignedat}{3}
M^{I\!J} &= m(N^J,N^I) &&= \int_\Omega N^JN^I \,dx \quad\text{and} \\
b^{I} &= b(N^I) &&= \int_\Omega u N^I \,dx
\end{alignedat}
\end{equation} %]]></script>
<p>Thus L2 projection requires the solution of a linear system</p>
<script type="math/tex; mode=display">\boldsymbol{M}\boldsymbol{u}=\boldsymbol{b}</script>
<p>which depending on the algorithm used, can have a complexity of at least
$O(n^2)$ and at most $O(n^3)$.</p>
<h1 id="lumpedl2projection">Lumped L2 Projection</h1>
<p>The L2 projection requires the solution of a system which can be
computationally expensive. It is possible to convert the
matrix—called the mass matrix in literature—to a diagonal
form through a procedure called <strong>lumping</strong>.</p>
<p>The operator for row summation is defined as</p>
<script type="math/tex; mode=display">\begin{equation}
\rowsum{(\cdot)}_i := \suml{j=1}{\nnode} (\cdot)_{ij}
\end{equation}</script>
<p>For the mass matrix, we have</p>
<script type="math/tex; mode=display">\begin{equation}
\rowsum M^{I} =
\suml{J=1}{\nnode} \int_\Omega N^JN^I \,dx
= \int_\Omega N^I \,dx
=: m^I
\end{equation}</script>
<p>since $\sum_{J=1}^{\nnode} N^J = 1$.
Substituting the lumped mass matrix allows us to decouple the linear system of
equations in \eqref{eq:projectionsystem1} and instead write</p>
<script type="math/tex; mode=display">\begin{equation}
m^I u^I = b^I
\end{equation}</script>
<p>for $I=1,\dots,\nnode$. The lumped L2 projection is then as simple as</p>
<script type="math/tex; mode=display">\begin{equation}
u^I = \frac{b^I}{m^I} = \frac{\displaystyle\int_\Omega u N^I\,dx}{\displaystyle\int_\Omega N^I \,dx}
\end{equation}</script>
<p>This results in a very efficient algorithm with $O(n)$ complexity.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Lumped L2 projection is a faster working approximation to L2 projection that is
easy to implement for quick results. You can use it when developing a solution
for an IBVP, and don’t want to wait too long when debugging, while not
forgetting that it introduces some error.</p>
Tue, 24 Apr 2018 00:00:00 +0000
https://solmaz.io/2018/04/24/lumpedl2projection/
https://solmaz.io/2018/04/24/lumpedl2projection/mathfiniteelementsDisadvantages of Engineering Notation in Finite Elements<p>Suppose we have the following stiffness matrix of linear elasticity:</p>
<script type="math/tex; mode=display">\begin{equation}
A^{I\!J}_{ij} = \int_\Omega B^I_k \, C_{ikjl} \, B^J_l \,dv \label{eq:engnot1}
\end{equation}</script>
<p>where $\boldsymbol{B}^I = \nabla N^I$ are the gradients of the shape
functions $N^I$ and $\mathbb{C}$ is the linear elasticity tensor (you see the
contraction of their components in the equation).</p>
<p>Despite being of the most explicit form, these types of indicial expressions are
avoided in most texts on finite elements. There are two reasons for this:</p>
<ul>
<li>Engineers are not taught the Einstein summation convention.</li>
<li>The presence of indices result in a seemingly cluttered expression.</li>
</ul>
<p>They avoid the indicial expression by reshaping it into matrix multiplications.
In engineering notation, the left and righthand sides are reshaped as</p>
<script type="math/tex; mode=display">\begin{equation}
A_{\alpha\beta} = \int_\Omega B_{\gamma\alpha}C_{\gamma\delta}B_{\delta\beta}
\,dv \label{eq:engnot2}
\end{equation}</script>
<p>which allows us to write</p>
<script type="math/tex; mode=display">\begin{equation}
\boldsymbol{A} = \int_\Omega \tilde{\boldsymbol{B}}^T\tilde{\boldsymbol{C}}\tilde{\boldsymbol{B}} \,dv
\label{eq:engnot3}
\end{equation}</script>
<p>The matrices $\tilde{\boldsymbol{B}}$ and $\tilde{\boldsymbol{C}}$ are set on with tildes in order to
differentiate them from the boldface symbols used in the previous sections.
Here,</p>
<ul>
<li>$\tilde{\boldsymbol{C}}$ is a matrix containing the unique components of the elasticity
tensor $\mathbb{C}$, according to the Voigt notation.
In this reshaping, only the minor symmetries are taken into account.
If the dimension of the vectorial problem is $d$, then $\tilde{\boldsymbol{C}}$ is of the size
$d(d+1)/2 \times d(d+1)/2$. For example, if the problem is 3 dimensional, $\tilde{\boldsymbol{C}}$
is of the size $6\times 6$:</li>
</ul>
<script type="math/tex; mode=display">% <![CDATA[
\begin{equation}
[\tilde{\boldsymbol{C}}] =
\begin{bmatrix}
C_{1111} & C_{1122} & C_{1133} & C_{1112} & C_{1123} & C_{1113} \\
C_{2211} & C_{2222} & C_{2233} & C_{2212} & C_{2223} & C_{2213} \\
C_{3311} & C_{3322} & C_{3333} & C_{3312} & C_{3323} & C_{3313} \\
C_{1211} & C_{1222} & C_{1233} & C_{1212} & C_{1223} & C_{1213} \\
C_{2311} & C_{2322} & C_{2333} & C_{2312} & C_{2323} & C_{2313} \\
C_{1311} & C_{1322} & C_{1333} & C_{1312} & C_{1323} & C_{1313} \\
\end{bmatrix}
\label{eq:engnotC}
\end{equation} %]]></script>
<ul>
<li>$\tilde{\boldsymbol{B}}$ is a $nd\times d(d+1)/2$ matrix whose components are
adjusted so that \eqref{eq:engnot2} is equivalent to \eqref{eq:engnot1}. It
has the components of $\boldsymbol{B}^I$ for $I=1,\dots,n$ where $n$ is the number of
basis functions. Since $\tilde{\boldsymbol{B}}$ is adjusted to account for the reshaping
of $\mathbb{C}$, it has many zero components. A 3d example:</li>
</ul>
<script type="math/tex; mode=display">% <![CDATA[
\begin{equation}
[\tilde{\boldsymbol{B}}] =
\begin{bmatrix}
B^1_1 & 0 & 0 & B^2_1 & 0 & 0 & \cdots & B^n_1 & 0 & 0 \\
0 & B^1_2 & 0 & 0 & B^2_2 & 0 & \cdots & 0 & B^n_2 & 0 \\
0 & 0 & B^1_3 & 0 & 0 & B^2_3 & \cdots & 0 & 0 & B^n_3 \\
B^1_2 & B^1_1 & 0 & B^2_2 & B^2_1 & 0 & \cdots & B^n_2 & B^n_1 & 0 \\
0 & B^1_3 & B^1_2 & 0 & B^2_3 & B^2_2 & \cdots & 0 & B^n_3 & B^n_2 \\
B^1_3 & 0 & B^1_1 & B^2_3 & 0 & B^2_1 & \cdots & B^n_3 & 0 & B^n_1 \\
\end{bmatrix}
\label{eq:engnotB}
\end{equation} %]]></script>
<p>Although \eqref{eq:engnot3} looks nice on paper, it is much less optimal for
implementation. Implementing it requires the implementation of
\eqref{eq:engnotB}, which adds another layer of complexity to the algorithm.
The same cannot be said for \eqref{eq:engnotC}, because using Voigt
notation might be more efficient in inelastic problems. In the most complex
problems, the most efficient method is to implement \eqref{eq:engnot1} in
conjunction with Voigt notation.</p>
<p>To prove the inefficiency of \eqref{eq:engnot3} we can readily compare it with
\eqref{eq:engnot1} in terms of required number of iterations. Indices in
\eqref{eq:engnot1} have the following ranges:</p>
<script type="math/tex; mode=display">\begin{equation}
I,J = 1,\dots,n
\quad\text{and}\quad
i,j,k,l = 1,\dots,d
\end{equation}</script>
<p>so $n^2d^4$ iterations are required. Indices in
\eqref{eq:engnot2} have the following ranges:</p>
<script type="math/tex; mode=display">\begin{equation}
\alpha,\beta=1,\dots,nd
\quad\text{and}\quad
\gamma,\delta=1,\dots,d(d+1)/2
\end{equation}</script>
<p>so</p>
<script type="math/tex; mode=display">\begin{equation}
(nd)^2\left(\frac{d(d+1)}{2}\right)^2 = n^2d^4\frac{(d+1)^2}{4}
\end{equation}</script>
<p>iterations are required. So engineering notation requires $(d+1)^2/4$ times more
equations than index notation. For $d=2$, engineering notation is $2.25$
times slower and for $d=3$ it is $4$ times slower. For example, calculation of a
stiffness matrix for $n=8$ and $d=3$ requires $20736$ iterations for
engineering notation, whereas it only requires $5184$ iterations for index notation.</p>
<p>Although \eqref{eq:engnot3} seems less cluttered, what actually happens is
that one
trades off complexity in one expression for a much increased complexity in
another one, in this case \eqref{eq:engnotB}.
And to make it worse, it results in a slower algorithm.</p>
<p>The only obstacle to the widespread adoption of
index notation seems to be its lack in undergraduate engineering curricula.
If engineers were taught the index notation and summation convention as well
as the formal notation, such expressions would not be as confusing at first
sight. A good place would be in elementary calculus and physics courses, where
one heavily uses vector calculus.</p>
Fri, 13 Apr 2018 00:00:00 +0000
https://solmaz.io/2018/04/13/engineeringnotationdisadvantages/
https://solmaz.io/2018/04/13/engineeringnotationdisadvantages/mathfiniteelements